メインコンテンツへスキップ
見出し画像
Photo bymirecat

【第450回】 Marketing Cloud Next : API を使ってフローから離脱させる方法

    Nobuyuki Watanabe

    Marketing Cloud Next Growth & Advanced Edition では、セグメントトリガーフロー、イベントトリガーフロー、オンデマンドフロー など、さまざまなフローを使ってリアルタイム施策や自動化を実現できます。

    しかし運用していると、こんなケースはありませんか?

    • ✅ 購入完了したのにリマインドメールが送られ続ける

    • ✅ すでに対応済みなのにフォローアップが止まらない

    • ✅ 外部システム側で処理完了したためフローを終了したい

    このような 「もうフローに残す必要がない個人」 を動的に離脱させるための仕組みが、Spring '26 の新機能リリースで登場した Exit Individuals from a Flow Action(REST API)です。

    この API を使うと、
    実行中のフローから特定の個人(Individual)を即座に退出させる
    ことができます。


    ユースケース例

    🛒 購入リマインドフロー

    1. カート放棄

    2. 1 日後リマインド

    3. 3 日後再通知

    4. 7 日後クーポン送付

    途中で、外部 EC サイトで購入完了

    このままだと
    ❌ 「まだ購入していませんか?」メールが送られる
    ⇒ そこで、Exit Individuals API でフローから離脱させる


    対応フロータイプ

    このアクションは、以下のフローで利用可能です。

    • セグメントトリガーフロー

    • イベントトリガーフロー

    • オンデマンドフロー


    API仕様

    この API は「API version 66.0」(Spring '26)以降で動きます。

    --- メソッド 
    POST 
    
    --- エンドポイント
    https://[私のドメイン名].my.salesforce.com/services/data/v66.0/actions/custom/exitIndividualsFromFlow/flow_API_name
    
    --- ヘッダー 
    Content-Type:application/json 
    Authorization:Bearer [アクセストークン] 
    
    --- ボディ
    {
      "inputs": [
        {
          "individualId": "003R000000ExAmPlE",
          "flowVersionId": "301R000000AbCdEfG",
          "description": "Customer completed purchase via external portal."
        }
      ]
    }
    • フローバージョン(flowVersionId)は任意です。指定がない場合は、すべてのバージョンから退出します。

    • 説明(description)も任意です。

    画像
    画像

    実装イメージ(活用パターン)

    パターン①:外部EC完了トリガー

    EC → Webhook → Lambda → REST API → Exit Flow

    パターン②:CRM更新トリガー

    Opportunity Closed Won → Apex → Callout → Exit Flow

    パターン③:サポート完了

    Case Closed → Event-Triggered Flow → Exit Flow


    取引先責任者のページに強制退出画面を作る

    最後に、画面フローを作成して連絡先の退出画面を作成してみます。
    具体的には、以下のような流れになります。

    Contact レコード
    ↓(クイックアクション)
    Screen Flow
    ↓
    Contact → IndividualId 取得
    ↓
    Flow API 名を手入力
    ↓
    Apex(Invocable)
    ↓
    POST /actions/custom/exitIndividualsFromFlow/{flowApiName}

    画像

    設定手順

    1. Named Credential の作成

    この作成方法については、以下の 2 つの記事をご確認ください。

    • 以下の記事で「コンシューマー鍵」と「コンシューマーの秘密」を取得するところまで進めてください。

    • 上で取得した「コンシューマー鍵」と「コンシューマーの秘密」を使って、Named Credential(指定ログイン情報)を作成してください。

    • 「データグラフのスケジュール実行」セクションの 手順 1 ~ 24 を実行してください。下の Apex をそのまま利用する場合は、Named Credential の Name(API 名)を「SelfOrg」と命名してください。


    2. Apex クラス を登録

    以下を登録してください。
    設定で登録されている Named Credential(指定ログイン情報)の Name(API 名)が「SelfOrg」であるか、再度確認してください。

    public with sharing class ExitIndividualsFromFlowAction {
    
        public class Request {
            @InvocableVariable(required=true)
            public String individualId;
    
            @InvocableVariable(required=true)
            public String flowApiName;
        }
    
        public class Result {
            @InvocableVariable public Boolean success;
            @InvocableVariable public Integer statusCode;
            @InvocableVariable public String message;
            @InvocableVariable public String responseBody;
        }
    
        @InvocableMethod(label='Exit Individual From Flow')
        public static List<Result> run(List<Request> requests) {
    
            List<Result> results = new List<Result>();
    
            for (Request req : requests) {
                Result r = new Result();
    
                try {
                    String apiName = (req.flowApiName == null) ? '' : req.flowApiName.trim();
    
                    HttpRequest httpReq = new HttpRequest();
                    httpReq.setMethod('POST');
                    httpReq.setEndpoint(
                        'callout:SelfOrg/services/data/v66.0/actions/custom/exitIndividualsFromFlow/' +
                        EncodingUtil.urlEncode(apiName, 'UTF-8')
                    );
                    httpReq.setHeader('Content-Type', 'application/json');
                    httpReq.setTimeout(120000);
    
                    Map<String,Object> body = new Map<String,Object>{
                        'inputs' => new List<Object>{
                            new Map<String,Object>{ 'individualId' => req.individualId }
                        }
                    };
                    httpReq.setBody(JSON.serialize(body));
    
                    HttpResponse res = new Http().send(httpReq);
    
                    r.statusCode = res.getStatusCode();
                    r.responseBody = res.getBody();
                    r.success = (r.statusCode >= 200 && r.statusCode < 300);
    
                    if (r.success) {
                        r.message = 'Successfully exited';
                    } else {
                        r.message = r.responseBody;
    
                        if (r.statusCode == 400 && !String.isBlank(r.responseBody)) {
                            String errCode = extractFirstErrorStatusCode(r.responseBody);
    
                            if (errCode == 'INDIVIDUAL_NOT_IN_FLOW') {
                                r.message = 'This individual is not currently in the flow (no exit required)';
                            }
                        }
                    }
    
                } catch (Exception e) {
                    r.success = false;
                    r.message = 'Exception: ' + e.getMessage();
                }
    
                results.add(r);
            }
    
            return results;
        }
    
        private static String extractFirstErrorStatusCode(String jsonText) {
            try {
                Object root = JSON.deserializeUntyped(jsonText);
    
                if (!(root instanceof List<Object>)) return null;
                List<Object> rootList = (List<Object>)root;
                if (rootList.isEmpty()) return null;
    
                Object first = rootList[0];
                if (!(first instanceof Map<String,Object>)) return null;
                Map<String,Object> firstMap = (Map<String,Object>)first;
    
                Object errorsObj = firstMap.get('errors');
                if (!(errorsObj instanceof List<Object>)) return null;
                List<Object> errors = (List<Object>)errorsObj;
                if (errors.isEmpty()) return null;
    
                Object e0 = errors[0];
                if (!(e0 instanceof Map<String,Object>)) return null;
                Map<String,Object> e0Map = (Map<String,Object>)e0;
    
                Object statusCodeObj = e0Map.get('statusCode');
                return (statusCodeObj == null) ? null : String.valueOf(statusCodeObj);
    
            } catch (Exception ignore) {
                return null;
            }
        }
    }
    画像

    3. 画面フローの作成

    1. 新規で「画面フロー」を作成します。

    画像

    2. 今回、以下の 5 つの「変数」を作ります。

    (1)recordId
    ・API Name:recordId
    ・Data Type:Text
    ・Available for input:ON

    (2)varIndividualId
    ・API Name:
    varIndividualId
    ・Data Type:Text

    (3)varMessage
    ・API Name:
    varMessage
    ・Data Type:Text

    (4)varStatusCode
    ・API Name:varStatusCode
    ・Data Type:Number
    ・Decimal Places:0

    (5)varSuccess
    ・API Name:
    varSuccess
    ・Data Type:Boolean

    画像

    3. 「レコードを取得」要素を設定します。

    • 表示名:Get Contact

    • API 名:Get_Contact

    • Object:Contact

    • Condition Requirements:All Conditions Are Met (AND)

    • Field:Contact Id

    • Operator:Equals

    • Value:{!recordId}(変数)

    • How Many Records to Store:Only the first record(デフォルト)

    • How to Store Record Data:Automatically store all fields(デフォルト)

    画像

    4. 「割り当て」を設定します。

    • 表示名:Set IndividualId

    • API 名:Set_IndividualId

    • Set Variable Values:varIndividualId(変数) = {!Get_Contact.Id}

    画像

    5. 「画面」要素を配置して、以下を入力します。

    • 表示名:Input Flow API Name

    • API 名:Input_Flow_API_Name

    画像

    6. 「テキスト」コンポーネントをドラッグアンドドロップして、以下を入力して、要素を保存します。

    • 表示名:Flow API Name

    • API 名:varFlowApiName(← 入力されたフローの API 名が、この変数に格納されます。)

    • 必須:ON

    画像

    4. Apex アクション

    1. Action を配置して、作成した Apex(ExitIndividualsFromFlowAction)を選択します。

    画像

    2. 表示名と API 名を決め、以下の 2 つをマッピングします。

    • 表示名:Exit Individual From Flow

    • API 名:Exit_Individual_From_Flow

    Set Input Values:

    • flowApiName = {!varFlowApiName}(画面上からの変数)

    • individualId = {!varIndividualId}(変数)

    画像

    一旦、ここまでで実装は成立していますが、以下に結果を表示するための画面を作成します。


    5. 出力応答の割り当て

    最初に作成した残り 3 つの変数に、Apex からの出力応答 を割り当てます。
    「割り当て」要素を配置してください。

    • 表示名:Set Result

    • API 名:Set_Result

    Set Variable Values:

    • varSuccess = {!Exit_Individual_From_Flow.success}

    • varStatusCode = {!Exit_Individual_From_Flow.statusCode}

    • ‎varMessage = {!Exit_Individual_From_Flow.message}

    画像

    6. 成功と失敗の分岐の作成

    「決定」要素を配置して

    • 表示名:Check Success

    • API 名:Check_Success

    • 左のパス名:Success

    • 右のパス名:Failure

    • 左の条件:{!Exit_Individual_From_Flow.success} = True

    画像

    7. 成功画面の作成

    左のパスに「画面」要素を配置して、設定画面を表示したら、表示名と API 名を設定します。

    • 表示名:Success Exit Completed

    • API 名:Success_Exit_Completed

    画像

    続いて、Display Text を配置して、以下を入力して「保存」します。

    • API 名:Success_Display

    • テキスト本文:
      ✅ Exit successful

      • Status: {!varStatusCode}

    画像

    8. 失敗画面の作成

    右のパスにも「画面」要素を配置して、以下を入力します。

    • 表示名:Error Exit Flow

    • API 名:Error_Exit_Flow

    画像

    こちらも、Display Text を配置して、以下を入力して「保存」します。

    • API 名:Failure_Display

    • テキスト本文:
      ❌ Exit failed

      • Status: {!varStatusCode}

      • Details: {!varMessage}

    画像

    9. フローの保存と有効化

    フローを保存して有効化してください。

    • フロー名:Exit Individual From Flow

    • API 名:Exit_Individual_From_Flow

    画像

    10. 取引先責任者のアクションに設定

    1. 設定 > オブジェクトマネージャーから「取引先責任者」の「Buttons, Links, and Actions」を選択して「新しいアクション」をクリックします。

    画像

    2. 以下で入力します。

    • アクションタイプ:Flow

    • フロー:Exit Individual From Flow

    • 表示名:Exit Flow

    • API 名:Exit_Flow

    画像

    3. 新しいアクションの保存後、取引先責任者の「ページレイアウト」に追加します。

    画像

    11. 動作確認

    1. フロー内に存在している「取引先責任者」のレコードを開いて、Exit Flow クイックアクションをクリックします。

    画像

    2. 「Exit Flow」の画面が開きますので、Flow API 名(❌ 表示名)を入力して先に進みます。(例:オンデマンドフロー の Order_Confirmation_Flow)

    画像

    3. 「退出されました」と表示されます。

    画像

    4. その後のフローでは、先に進まなくなります。成功です。

    画像

    5. フロー内に存在していない「取引先責任者」レコードの場合は、以下の通り「退出されませんでした」が表示されます。

    画像

    いかがでしたでしょうか。

    Marketing Cloud Next では、「開始する」だけでなく 「途中で止める」制御 も非常に重要です。

    Exit Individuals API は、Flow をよりインテリジェントに運用するための必須テクニック と言えます。

    リアルタイム施策や外部連携をしている方は、ぜひ活用してみてください。

    今回は以上です。


    次の記事はこちら

    前回の記事はこちら

    私の note のトップページはこちら

     
     
     
    Salesforce Marketing Cloud、Agentforce、Data Cloud、Salesforce 認定資格に関する実践的な情報を発信しています。これらの記事が、皆さまの学習や日々の業務に少しでもお役に立てば幸いです。