Apexから指定ログイン設定でPardot APIを利用


この投稿はSalesforce Advent Calendar 2022の５日目の記事です
https://qiita.com/advent-calendar/2022/salesforce

## はじめに

SalesforceのApexクラスからPardotのプロスペクト項目をPardot APIで更新してみよう。
せっかくだから『指定ログイン』も使ってみよう・・という内容になります。


## Pardot連携済みSalesforceユーザの準備
Pardot APIを利用するための、Pardotと連携済みのSalesforceユーザを準備しましょう。
ここでは詳細は割愛させていただきます。

※当方はidentityライセンスのユーザで試しました。


## 自己署名証明書を作成

`設定 - セキュリティ - 証明書と鍵の管理`
から、[自己署名証明書の作成]ボタンを押して、作成しちゃいましょう。

![自己署名証明書.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956449/a62eeb3c-1da8-b8db-d764-99e0c93e0250.png)

後で、指定ログインの設定で利用します。

::: note warn
 有効期限が１年なので注意しましょう！
:::

## ＜接続アプリケーション＞ 新規作成
毎度おなじみ、「接続アプリケーション」です。

`設定 - アプリケーション - アプリケーションマネージャ`
から、[新規接続アプリケーション]ボタンを押して作成します。

![接続アプリケーション_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956449/f60b55a1-bbab-50ad-6176-60e679b14587.png)

| 設定内容 | 値（または例） |
|:-----------|:------------|
| 接続アプリケーション名       | （良い感じで付けましょう）        |
| API参照名     | （良い感じで付けましょう）    |
| 取引先責任者 メール       | （システム管理者さんのアドレスが良いと思います）       |
| OAuth設定の有効化       | ON        |
| コールバックURL     | https://login.salesforce.com/services/oauth2/callback <br>（Sandbox環境なら）https://test.salesforce.com/services/oauth2/callback  |
| デジタル署名を使用       | ON<br>※先ほど作成した「自己署名証明書」を添付しましょう。<br>添付忘れると、指定ログイン設定での認証時、JWTトークンの交換が出来ずにコールアウト時にエラーになります |
| 選択したOAuth 範囲       | いつでも要求を実行(refresh_token, offiline_access) <br>Pardotサービスを管理(pardot_api)       |
| Webサーバーフローの秘密が必要     | ON   |

## ＜接続アプリケーション＞ コンシューマ鍵・コンシューマの秘密を確認
コンシューマ鍵とコンシューマの秘密を確認しましょう。（後で使用します）

`設定 - アプリケーション - アプリケーションマネージャ`
から、作成した接続アプリケーションを"参照"後、[コンシューマの詳細を管理]ボタンから確認できます。

![コンシューマーキー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956449/1d2b78f9-6a59-a31c-cbc4-9ead416bf74a.png)

## ＜接続アプリケーション＞ OAuthポリシーと対象ユーザ設定
`設定 - アプリケーション - アプリケーションマネージャ`
から、作成した接続アプリケーションを`Manage`後、[ポリシーを編集]ボタンを押します。

![接続アプリ(1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956449/89463f3f-10f3-bffb-eaf6-8caa471cb4b0.png)

| 設定内容 | 値 |
|:-----------|:------------|
| 許可されているユーザ       | 管理者が承認したユーザは事前承認済み       |

その後、`接続アプリケーションの画面下部のプロファイル関連リスト`に、
`今回のユーザに割り当てているプロファイルを追加`しましょう。
（専用の権限セットを作って、権限セットで割り当てでも良さそうです）


## 指定ログイン情報を作成
指定ログイン情報を設定し、コールアウトエンドポイントとして指定することで、Apexコード内での認証処理を直接書かないで済むようにします。

![指定ログイン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956449/1086efaf-6764-a7c5-d4b0-cc0c62dba9ed.png)


| 設定内容 | 値 |
|:-----------|:------------|
| URL       | https://pi.pardot.com/api<br>（Pardotデモ環境なら）https://pi.demo.pardot.com/api       |
| ID種別       | 指定ユーザ      |
| 認証プロトコル       | JWTトークンの交換      |
| トークンエンドポイント       | https://login.salesforce.com/services/oauth2/token <br> （Sandboxなら）https://test.salesforce.com/services/oauth2/token    |
| 発行者      | （接続アプリケーションのコンシューマ鍵を登録します）      |
| 利用者       | （認証に使用するユーザID）    |
| JWT署名証明書       | 先ほど作成した自己署名証明書を紐づけます     |



これで準備は完了です。
早速、Apexクラスから呼び出して使ってみましょう！
（ここでは、プロスペクトのopted_outを更新する処理にしています）


## サンプルApexクラス

```Apex:Pardotにコールアウトするクラス

public class CalloutToPardot {

    @future(callout=true)
    public static void postOptedOutFromFID(String targetId, Boolean opted_out){

        String endpoint = '';

        Http http = new Http();
        HttpRequest request = new HttpRequest();

        // callout:XXXXXXXXXにて、指定ログイン情報（APEX_Pardot_Credential）を差し込み
        endpoint += 'callout:APEX_Pardot_Credential/prospect/version/4/do/update/fid/';
        endpoint += targetId;
        endpoint += '?opted_out=';
        endpoint += opted_out;
        endpoint += '&format=json';
        request.setEndpoint(endpoint);

        request.setMethod('POST');

        // ビジネスユニットをカスタム表示ラベル(PARDOT_BUSINESS_UNIT_ID)で指定
        request.setHeader('Pardot-Business-Unit-Id',System.Label.PARDOT_BUSINESS_UNIT_ID);

        HttpResponse response = http.send(request);
        system.debug(response);

        if (response.getStatusCode() == 200 || response.getStatusCode() == 201) {
            System.debug('API Successful: ' +
                         response.getStatusCode() + ' ' + response.getStatus()+ ' ' + response.getBody());
        } else {
            System.debug('API Error: ' +
                         response.getStatusCode() + ' ' + response.getStatus()+ ' ' + response.getBody());
        }
    }
}
```
**開発者コンソールで直接呼び出して確認**

NAMED_CREDENTIAL_RESPONSEで、StatusCodeが200でOKとなっており、認証が問題ない事が確認できます。

![開発者コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956449/c0dabedf-baf8-422c-fff7-9de62c35ed00.png)






**上記クラスをフローから呼び出したい時**

```Apex:フローから呼び出す用のApexクラス
public class CalloutToPardotForFlow {

    public class CalloutInfos {
        @InvocableVariable(required=true label='FID')
        public string fid;

        @InvocableVariable(required=true label='Opted_out')
        public boolean opted_out;
    }

    // フローからは"Update Padot Opted_Out"というアクション名で指定できます
    @InvocableMethod(label='Update Pardot Opted_Out' description='Update Opted_out of Pardot prospect')
    public static void updatePardotProspectOptedOut(CalloutInfos[] infos) {
        CalloutToPardot.postOptedOutFromFID(infos[0].fid,infos[0].opted_out);
    }

}

```

フロー側はこんな感じで、Apexのアクションを追加してみましょう。

![フロー0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956449/361a9b5f-167b-f3dd-70c9-76c233a3fd0e.png)

その際、フロー側からApexクラスに渡すパラメータ値をセットします。
（ここではプロスペクトを特定するための取引先責任者の18桁IDと、オプトアウト値（Boolean値）を渡しています）

![フロー05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956449/08758fa6-f614-dd22-4148-7e9b25cf6870.png)

上記アクションを非同期のルートにセットします。

![フロー1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956449/f21a3008-ca32-04f6-fd6c-e140a08f24ff.png)






ちなみに処理が実行されると、プロスペクトの[監査]からはこんな感じで表示されますね。

![更新されると・・.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956449/81918a52-80fa-b293-e83a-b2d151c1a747.png)

## 最後に ##
Salesforceと連携中の項目で同期挙動が"Pardotの値を利用する"、もしくは未連携だけど、
Salesforce側のトリガーで即座に更新させたい時がある・・なんて時に使えるかなと思います。
ちょいとマニアックな内容かなと思いつつ・・
よろしければ、ご参考までに・・