service-de-headless-channel-configure について
Salesforce Enhanced Messaging チャネルを作成から有効化まで進めるエンドツーエンドのスキルです。規約への同意、挿入、ルーティング、同意設定、有効化を連携し、既存状態を確認して処理を再開できます。
主な機能
- 01挿入から有効化までの4段階を実行
- 02組織操作の前に規約同意を必須化
- 03種別別のチャネル挿入を振り分け
- 04ルーティングと同意設定
- 05現在の状態に基づく完了済み手順のスキップ
活用シーン
- 01メッセージチャネルの新規設定と有効化
- 02中断したチャネル設定の再開
- 03複数のメッセージ種別に共通の設定フローを適用
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill service-de-headless-channel-configureインストール後、Claude Code で/service-de-headless-channel-configureを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/gotchas.mdinputs.mdoutput-envelopes.mdpartial-success.mdterms-and-conditions.mdworked-examples.md詳細
ヘッドレスチャネルのセットアップ(タイプ非依存)
このスキルでできること
チャネルタイプ(WhatsApp | Line | AppleBusinessChat | Facebook | Text)とタイプ固有の入力を受け取り、有効化済みのMessagingChannelに設定します。まずEnhanced Messagingの利用規約への同意を確認し、その後、次の4つのステップを実行します。
- 利用規約への同意 — Enhanced Messagingの免責事項を表示し、ユーザーに組織を拘束する権限があることを証明するよう求めます。これは組織内の「チャネルを追加」ウィザードに準じています。ブロッキング処理です。同意しない場合、組織に対する処理を開始する前に実行を終了します。(ステージ0.5、このスキル内)
- チャネルの挿入 —
service-de-channel-createを呼び出します。この処理では、タイプごとに必要なサードパーティの前提条件も内部で処理します(例:WhatsAppのservice-de-waba-integrateはservice-de-channel-create内で実行されます)。(スキル:service-de-channel-create) - ルーティングの設定 —
SessionHandlerIdにOmni-Channelキューを設定します(既存のキューを選択するか、新規作成します)。メッセージタイプには依存しません。(スキル:service-de-channel-routing-configure) - 同意の設定 — 有効な
ConsentTypeと、それに対応するMsgChannelLanguageKeywordレコードが存在することを確認します。Connectの挿入時に、デフォルトのConsentType=ImplicitOptInとオプトアウトキーワードが自動的に作成されるため、新規チャネルではこのステップが不要なことがよくあります。また、呼び出し側がExplicitOptInまたはDoubleOptInを希望する場合は、アップグレードします。有効化の準備状況チェックではルーティングと同意の両方が必須となるため、この処理は有効化の前に実行します。(スキル:service-de-channel-settings-configure) - 有効化 — REST経由で
MessagingChannelUsage.DeploymentStatusをProvisioningにPATCHします。サーバー側の保存フックがオブザーバーチェーン全体を同期的に実行し、MCUがActiveに達してMessagingChannel.IsActive=trueになると204を返します。メッセージタイプには依存しません。(スキル:service-de-channel-activate)
デフォルトで再開します。 各ステップは冪等です。失敗後に再実行すると、オーケストレーターが既存の状態を検出し、すでに成功したステップをスキップします。
処理の途中でプロンプトを表示します。 最初のリクエストに{MESSAGE_TYPE}が含まれていない場合、オーケストレーターは最初に確認します。ルーティングの選択(キューを選択/新規作成)は、事前ではなくステップ2の実行時にプロンプトで確認します。これにより、個々のスキルを自己完結型に保てます。
リファレンスファイル一覧
| リファレンスファイル | 読み込むタイミング |
|---|---|
references/inputs.md | 入力フィールドの一覧が必要な場合。MESSAGE_TYPE/ORG_ALIASに加え、WhatsApp、LINE、AppleBusinessChat、Facebook、Text(SMS)のタイプ別フィールドが記載されています。 |
references/terms-and-conditions.md | ステージ0.5の免責事項と同意プロンプトを表示する場合。原文のテキストと、タイプごとのラベル/サードパーティ対応表が記載されています。 |
references/output-envelopes.md | エラー処理を組み込む場合、または標準的な成功/失敗/利用規約への不同意を示すJSONエンベロープの形式を解析する場合。 |
references/partial-success.md | オーケストレーターが途中で失敗し、部分成功/再開レポートを表示する必要がある場合。 |
references/gotchas.md | 想定外の動作をデバッグする場合。重複キーエラー、再開/冪等性に関する質問、事前チェックのSOQL形式、無人実行/CIでの使用について記載されています。 |
references/worked-examples.md | 具体的なエンベロープ形式を確認するため、参照用の実行トレース(新規WhatsAppの実行、失敗後の再開、Appleのディスパッチ、未対応タイプの拒否)が必要な場合。 |
重要な実行ルール
このオーケストレーターは、すべてのステージ(0~5)を、ステージ間で停止することなく、1 回の応答で実行する必要があります。
リーフスキル(service-de-channel-create、service-de-channel-routing-configure、service-de-channel-settings-configure、service-de-channel-activate)を呼び出し、function_results 経由で結果が返された場合:
- 必ず行うこと: function_results の戻り値を直ちに解析し、次のステージに進んでください
- 必ず行うこと: ステージ 0.5 → ステージ 1 → ステージ 2 → ステージ 3 → ステージ 3.5 → ステージ 4 → ステージ 5 を、1 回の応答内で続けて実行してください
- 行ってはいけないこと: ステージ間で停止してユーザーに報告すること
- 行ってはいけないこと: ステージ間でユーザーの確認を待つこと
- 行ってはいけないこと: 各ステージを会話の別々のターンとして扱うこと
重要な理由: ユーザーは、エンドツーエンドで有効化されたチャネルを取得するために、このオーケストレータースキルを呼び出しました。個別のリーフスキルを呼び出したわけではありません。あなたの役割は、パイプライン全体を自律的に実行し、最終結果を報告することです。途中で停止するとオーケストレーターのパターンが崩れ、ユーザーが各ステージを手動で再開しなければならなくなります。
例外: リーフスキルが ok: false と回復不能なエラー(続行可能なプロンプトではない)を返した場合、またはユーザーがステージ 0.5 の利用規約への同意を拒否した場合(terms-not-accepted を出力して停止)に限り、処理を途中で停止します。その場合は、失敗したステージと到達した状態を示して、直ちに失敗を報告してください。
ステージ 0.5 は必須のブロッキングプロンプトです。 利用規約への同意ゲートは、組織に関する処理を開始する前に肯定的な回答が必要な唯一のプロンプトです。省略できず、自動的に同意してはいけません。no/拒否の場合は上記の例外に従って実行を終了し、yes の場合は同じ応答内でステージ 1 に進みます。
リーフスキルのプロンプト: 一部のリーフスキル(service-de-waba-integrate や service-de-channel-routing-configure など)は、実行中にユーザーへ入力を求める場合があります。それ自体は問題ありません。プロンプトにはその都度回答し、回答後すぐに次のステージへ進んでください。プロンプトがあったというだけで停止してはいけません。
このスキルを使わない場合
- 1 つのステップだけを実行したい場合。 リーフスキル(service-de-channel-create、service-de-channel-routing-configure、service-de-channel-activate)を直接呼び出してください。このオーケストレーターは、何もない状態からチャネルの有効化までを自動で実行するためのものです。
- ステージを別々の会話ターンで個別に実行したい場合。 このオーケストレーターは、すべてのステージを 1 回の応答内で続けて実行します。ステージ間で手動制御が必要な場合は、リーフスキルを個別に呼び出してください。
WhatsApp/Line/AppleBusinessChat/Facebook/Text以外のメッセージタイプを使いたい場合。 ディスパッチャーはunsupported-typeを返します。WeChat / MsCopilot / Alexa を使うには、それぞれのリーフスキルとディスパッチャーの更新が必要です。- 前提条件が満たされていない場合(WABA が共有されていない、LINE チャネルが作成されていない、Apple アカウントが登録されていない、SMS 番号がプロビジョニングされていない)。 タイプごとの挿入スキルにおけるステージ 2 相当の処理で明確に通知され、戻ります。オーケストレーションで解決することはできません。(SMS/Text では挿入時に番号のプロビジョニング要件は確認されません。プロビジョニングされていない番号は、後の有効化時に
provisioning-errorとして表面化します。)
入力(ユーザーから)
{MESSAGE_TYPE}(省略された場合はプロンプトで確認)と、任意の {ORG_ALIAS}、および WhatsApp、LINE、AppleBusinessChat、Facebook、Text(SMS)用のタイプ固有フィールドがディスパッチャーに転送されます。すべてのフィールドと、タイプが省略された場合に表示するプロンプトの文面については、references/inputs.md を読み、その指示に従ってください。
出力(ユーザー向け)
最上位の結果は、成功、ステップ注釈付きの失敗、利用規約への同意拒否の 3 種類です。正確な JSON 形式については、references/output-envelopes.md を読み、その指示に従ってください。
Stage 0: {MESSAGE_TYPE} とタイプ固有のキーを解決する
{MESSAGE_TYPE} が省略されている場合は、ユーザーに確認します(上記の「Inputs」を参照)。適切なデフォルト値はないため、指定されない限り先に進まないでください。
判明したら、事前チェックキーを決定します。これは、既存の状態を検出するために MessagingChannel の SOQL で絞り込むフィールドです。常に MessagingPlatformKey ですが、その値はタイプによって異なります。
{MESSAGE_TYPE} | 事前チェックキーの値 {PLATFORM_KEY} | 備考 |
|---|---|---|
WhatsApp | {PHONE_NUMBER_ID} | 事前に必須 |
Line | {LINE_CHANNEL_ID} | 事前に必須 |
AppleBusinessChat | {APPLE_BC_ID} | 事前に必須 |
Facebook | {PAGE_ID} | 任意。OAuth → ページを取得 → 未指定の場合はユーザーに確認 |
Text | {SMS_NUMBER} | 事前に必須(電話番号/ショートコードそのもの) |
Facebook は特殊です。 {PAGE_ID} が指定されていない場合、オーケストレーターは独自の Stage 1 事前チェックを実行できません。その場合は Stage 1 をスキップし、service-de-channel-create に OAuth → ページ選択 → 事前チェック → 作成のフロー全体を処理させます。挿入スキルには独自の Stage 1 事前チェックがあり、ページ選択後に実行されます。
Facebook 以外のタイプでは、呼び出し元から {MESSAGE_TYPE} に必要なタイプ固有の入力が提供されていることを検証します(上記の「Inputs」を参照)。不足している場合は、ユーザーに確認するか処理を停止してください。ディスパッチャーを呼び出してはいけません。再検証されて missing-input が返され、余分な往復が発生します。
Stage 0.5: Enhanced Messaging Terms and Conditions(ブロッキングゲート)
組織へのクエリやチャネルに関する処理を行う前に、必ず実行してください。 組織内の「Add a Channel」ウィザードでは、管理者が Enhanced Messaging Terms and Conditions に同意しないと、チャネル設定に進めません。ヘッドレスフローでも同じゲートを適用してください。スキップしたり、ユーザーに代わって同意したりしてはいけません。この処理は、{MESSAGE_TYPE} が判明した後(免責事項でチャネル名を明示するため)、Stage 1 の前に、オーケストレーターの呼び出しごとに一度実行します。
references/terms-and-conditions.md から免責事項と同意確認プロンプトを取得し(チャネルラベルを置き換えたうえで、原文どおりに)表示してください。正確な文言とタイプごとのラベル/サードパーティの対応関係については、同ファイルを読み込み、その指示に従ってください。
ゲートの動作:
- ユーザーがはいと回答した場合(肯定的な同意)、
{TC_ACCEPTED} = trueを記録し、Stage 1 に進みます。 - ユーザーがいいえと回答した場合、拒否した場合、または明確な同意を示さなかった場合は、直ちに停止します。Stage 1 や後続のステージを実行してはいけません。次を出力します。
{"ok": false, "kind": "terms-not-accepted", "hint": "user did not accept the Enhanced Messaging Terms and Conditions — channel setup cannot proceed. Re-run when ready to accept."} - 再開時の実行を含め、オーケストレーターを呼び出すたびに同意が必要です。同意はセッション単位のゲートであり、永続化されません。永続的に記録する場所がなく、再確認のコストもプロンプト1回分だからです。
ステージ 1:事前状態の検出(再開のサポート)
MESSAGE_TYPE=Facebook かつ {PAGE_ID} が指定されていない場合は、このステージ全体をスキップしてください。 Facebook 挿入スキルでは、確認対象の PAGE_ID を特定する前に OAuth を実行する必要があります。ページを選択した後、ステージ 1 で挿入スキルに独自の事前確認を処理させてください。
それ以外の場合は、組織にクエリを実行して、前回の実行がどこまで進んだかを確認します。これにより、再開時に後続のステップから処理できます。サブクエリではなく、2 回クエリを実行してください — (SELECT ... FROM MessagingChannelUsages) サブクエリは、子リレーションに名前を付けられない一部の組織で失敗します。代わりに、外部キーをキーにした 2 回目のクエリを使用してください(注意点 #9 を参照)。
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, DeveloperName, MessageType, IsActive, SessionHandlerId, FallbackQueueId FROM MessagingChannel WHERE MessagingPlatformKey = '{PLATFORM_KEY}' AND MessageType = '{MESSAGE_TYPE}'" \
--json > /tmp/hcs-preflight.json
チャネルクエリで行が返された場合は、2 回目のクエリを実行してその MCU を特定します。
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, DeploymentStatus FROM MessagingChannelUsage WHERE MessagingChannelId = '{CHANNEL_ID}'" \
--json > /tmp/hcs-preflight-mcu.json
結合した結果を解析して、{CURRENT_STATE} を判定します。
| 事前確認の結果 | CURRENT_STATE | 実行する最初のステップ |
|---|---|---|
| レコードなし | fresh | ステップ 1(挿入) |
レコードあり、IsActive=false、SessionHandlerId=null、かつ FallbackQueueId=null | inserted-no-routing | ステップ 2(ルーティングの設定) |
レコードあり、IsActive=false、ルーティング設定済み | routed-not-active | ステップ 3(同意の設定)、次にステップ 4(有効化) |
レコードあり、IsActive=true | already-active | 何もしない成功エンベロープを出力して返します。 |
既存の {CHANNEL_ID} と {MCU_ID} がある場合は記録してください。後続のステップで必要になります。
{STEPS_RUN} = []、{STEPS_SKIPPED} = []、{T0} = Date.now() を初期化します。
ステージ 2:チャネルの挿入(4 ステップ中のステップ 1)
CURRENT_STATE が {inserted-no-routing, routed-not-active, already-active} に含まれる場合、このステージをスキップしてください — チャネルはすでに存在します。その場合は、"insert" を STEPS_SKIPPED に追加します。
それ以外の場合は、次の値を指定して service-de-channel-create を呼び出します。
{MESSAGE_TYPE}=(ステージ 0 から取得)- タイプ固有のすべての入力(そのまま転送 — ディスパッチャーが適切なリーフに振り分けます)
{ORG_ALIAS}
挿入スキルは、タイプごとの前提条件を内部で処理します(例:WhatsApp の場合、service-de-channel-create がステージ 2 として service-de-waba-integrate を呼び出します)。このオーケストレーターは、WABA の連携、LINE のトークン検証、Apple の登録について把握する必要はありません — service-de-channel-create が、実行するタイプに応じた前提条件の処理を担います。
エンベロープを次のように処理します。
| リーフのエンベロープ | オーケストレーターのアクション |
|---|---|
{ok: true, channelId, mcuId, ...} | {CHANNEL_ID} と {MCU_ID} を記録します。"insert" を STEPS_RUN に追加し、続行します。 |
{ok: false, kind: "partnership-blocked" | "user-declined" | "apple-registration-pending" | "line-prereq-missing"} | これらはタイプごとの前提条件ステージから返されます。failedStep: "insert"、failedStepIndex: 1 としてそのまま渡し、返します。 |
{ok: false, kind: "missing-input" | "unsupported-type"} | ステージ 0 で検出されているはずです — 呼び出し元の入力が不完全だったことを示す注記を添えて、failedStep: "insert" の失敗を出力します。 |
{ok: false, kind: <anything else>} | failedStep: "insert"、failedStepIndex: 1 の失敗エンベロープを出力し、返します。 |
この時点で、ステップ 1 を実行したかスキップしたかにかかわらず、{CHANNEL_ID} と {MCU_ID} が取得されています。
→ 同じレスポンス内ですぐにステージ 3 に進んでください。停止しないでください。
ステージ 3:ルーティングの設定(4 ステップ中 2 番目)
CURRENT_STATE === "routed-not-active" の場合は、このステージをスキップしてください。ルーティングはすでに設定されています。STEPS_SKIPPED に "route" を追加してください。
それ以外の場合は、service-de-channel-routing-configure を呼び出してください。
{CHANNEL_ID}= 上記で記録した値{ORG_ALIAS}
このステップでは、キューの選択(既存のものを選択/新規作成/エスケープハッチ)をユーザーにプロンプトで確認します。プロンプトを先回りして対応しないでください。ユーザーの回答をそのまま渡してください。
エンベロープを処理します。
| リーフエンベロープ | オーケストレーターのアクション |
|---|---|
{ok: true, sessionHandlerId, queueName, ...}(noop: true を含む) | {SESSION_HANDLER_ID} と {QUEUE_NAME} を記録します。STEPS_RUN に "route" を追加します。続行します。 |
{ok: false, kind: "unsupported-routing-type", ...} | ユーザーが flow/user/asa/aea を選択しました。failedStep: "route" を含む部分成功を出力し、UI を示す再開ヒントを渡します。返ります。 |
{ok: false, kind: "metadata-deploy-failed" | "patch-failed" | "verify-failed"} | failedStep: "route" を含む失敗エンベロープを出力します。返ります。 |
→ 同じ応答内ですぐにステージ 3.5 に進んでください。停止しないでください。
ステージ 3.5:同意の設定(有効化の前)
有効化の準備状況チェックでは同意とルーティングの両方が必要です。ルーティングが完全に設定されたチャネルでも、同意が設定されていなければ有効化に失敗します。service-de-channel-settings-configure を呼び出してください。
{CHANNEL_ID}= 上記で記録した値{CONSENT_TYPE}、{LANGUAGE}、キーワード/プロンプトの値:ユーザーが指定した値をそのまま渡し、指定されていないものは省略します{ORG_ALIAS}
このステージでは同意が有効化の準備を整えていることを確認します。必ずしも書き込みを行うわけではありません。Connect の挿入処理では、ConsentType=ImplicitOptIn と、デフォルトのオプトアウト用 MsgChannelLanguageKeyword が自動的にシードされます。これらは準備状況チェックをすでに満たすため、リーフのステージ 1 ではチャネルの準備がすでに整っていると判断され、noop: true が返されることがよくあります。これは新しい ImplicitOptIn チャネルでは想定どおりの結果であり、バグではありません。実際に書き込みを行うのは、アップグレード(ExplicitOptIn/DoubleOptIn)する場合、またはシードされたキーワード/プロンプトを上書きする場合のみです。ユーザーがアップグレードを求める入力を事前に指定していた場合は、書き込みが行われることを想定し、不足している値についてリーフがプロンプトを表示できるようにしてください。プロンプトを抑制しないでください。
エンベロープを処理します。
| リーフエンベロープ | オーケストレーターのアクション |
|---|---|
{ok: true, ...}(noop: true を含む) | STEPS_RUN に "consent" を追加します(noop の場合は STEPS_SKIPPED に追加します)。続行します。 |
{ok: false, kind: "not-enhanced"} | 発生するはずはありません。このスキルでは Enhanced チャネルのみを作成します。failedStep: "consent" を含む失敗を出力します。返ります。 |
{ok: false, kind: "missing-consent-input", hint} | 選択された ConsentType に必要なキーワード/プロンプトがユーザーから提供されていません。failedStep: "consent" を含む失敗を出力し、hint をそのまま渡します。返ります。 |
{ok: false, ...}(その他のすべての種類:channel-patch-failed、keyword-record-failed、verify-failed、または認識できないエンベロープ) | failedStep: "consent" を含む失敗を出力し、リーフの kind とメッセージをそのまま渡します。返ります。 |
→ 同じ応答内ですぐにステージ 4 に進んでください。停止しないでください。
ステージ 4:有効化(全 4 ステップ中のステップ 4)
(CURRENT_STATE === "already-active" の場合はステージ 1 で早期終了するため、それ以外の場合は)必ず実行します。
service-de-channel-activate を呼び出します。
{CHANNEL_ID}= 上で記録した値{ORG_ALIAS}
タイムアウト設定はありません。有効化は同期 PATCH 1 回で完了します。サーバーが遷移の途中で応答した場合、リーフは安全のためポーリングしますが、想定される経路では 1 往復です。
エンベロープを処理します。
| リーフのエンベロープ | オーケストレーターのアクション |
|---|---|
{ok: true, isActive: true, ...}(noop: true を含む) | 結果を記録します。"activate" を STEPS_RUN に追加します。ステージ 5 に進みます。 |
{ok: false, kind: "no-routing"} | 想定外です(今しがた設定したばかりです)。競合状態か権限の問題が考えられます。権限の確認を促すヒントを付けて失敗を出力します。終了します。 |
{ok: false, kind: "no-mcu" | "channel-missing"} | 挿入が成功した後に発生するはずはありません。リーフのエンベロープとともに失敗を出力します。終了します。 |
{ok: false, kind: "readiness-failed", errorMessage} | validateChannelReadinessOnProvisioning により PATCH が拒否されました。必要な同意(STOP/HELP キーワードのレコード)がありません。ステージ 3.5 で検出されるはずですが、再び発生した場合は、そのチャネルに対して service-de-channel-settings-configure を再実行します。失敗を出力し、再開用ヒントをそのまま渡します。終了します。 |
{ok: false, kind: "provisioning-error", errorReason, errorDetails} | サードパーティ側で拒否されました(Meta の /register が失敗した場合など)。MCU は Error 状態になっています。失敗を出力し、errorReason/errorDetails をそのまま渡します。終了します。 |
{ok: false, kind: "auth" | "transport"} | HTTP レイヤーで REST 呼び出しが失敗しました(sf 認証による 401、インスタンスによる 5xx など)。そのまま渡します。終了します。 |
ステージ 5:最終レポート
成功エンベロープを作成します。
{
"ok": true,
"messageType": "{MESSAGE_TYPE}",
"channelId": "{CHANNEL_ID}",
"mcuId": "{MCU_ID}",
"channelName": "{CHANNEL_NAME or inferred}",
"sessionHandlerId": "{SESSION_HANDLER_ID}",
"queueName": "{QUEUE_NAME}",
"isActive": true,
"stepsRun": [...],
"stepsSkipped": [...],
"totalDurationMs": Date.now() - T0
}
次のようにユーザーに表示します。
Success — {MESSAGE_TYPE} channel '{CHANNEL_NAME}' is live on {ORG_ALIAS}.
Channel ID: {CHANNEL_ID}
Routed to: {queueName} ({SESSION_HANDLER_ID})
Steps: ran {STEPS_RUN.join(", ")}{, skipped " + STEPS_SKIPPED.join(", ") if any}
Total time: {formatted from durationMs}
再開によってスキップされたステップがある場合は、レポートに明示します。
部分的な成功と再開に関するレポート
オーケストレーターが途中で失敗した場合、エンベロープには、どこまで反映されたかを示す stateSoFar が必ず含まれます。stateSoFar には、反映されたフィールドに加えて、必ず stepsRun と stepsSkipped の両方を含めてください(どちらも配列とし、反映またはスキップされたステップがまだない場合は空にします)。部分成功レンダラーは両方を読み取ります。失敗を表示する際は、references/partial-success.md を読み込み、その指示に従ってください。反映済みのステップと再試行方法を示す正確なテンプレートが記載されています。
実例
参考トレース(新規 WhatsApp 実行、ルーティング失敗後の再開、Apple のディスパッチ、非対応タイプの拒否)については、references/worked-examples.md を参照してください。
注意点
既知の注意点が 9 つあります。前提条件の所有者、MessagingPlatformKey の一意性、再開のセマンティクス、CSOT のみのサポート、エラー分類の境界、プロンプトの配置、プラットフォームキーのマッピング、実時間の所要時間、2 クエリの事前確認による回避策です。予期しない動作をデバッグする際は、references/gotchas.md を読み込み、その指示に従ってください。