service-de-channel-activate について
sf CLIでMessagingChannelUsageの状態を変更し、既存のメッセージチャネルを有効化するSalesforce向けスキルです。事前にルーティングや使用レコードを確認し、プロビジョニングの結果を報告します。
主な機能
- 01チャネル、ルーティング、使用レコードの確認
- 02REST PATCHによる有効化
- 03同期プロビジョニング結果の処理
- 04成功・失敗の構造化レポート
活用シーン
- 01設定済みメッセージチャネルの有効化
- 02プロビジョニング拒否の原因調査
- 03有効なチャネルへの再実行の回避
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill service-de-channel-activateインストール後、Claude Code で/service-de-channel-activateを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/gotchas.mdphone-verification.mdworked-examples.md詳細
メッセージングチャネルの有効化
このスキルの機能
{CHANNEL_ID} が指定されると、チャネルの MessagingChannelUsage.Id を読み取り、{"DeploymentStatus":"Provisioning"} を本文として PATCH /services/data/v{V}/sobjects/MessagingChannelUsage/{MCU_ID} を実行します。サーバー側では、次の処理が行われます。
MessagingChannelUsageFunctions.validateBeforeSaveがvalidateDeploymentStatus→validateChannelReadinessOnProvisioningを実行します。WhatsApp の場合、同意が設定されていることを確認します。書き込みが拒否されると、HTTP 400FIELD_INTEGRITY_EXCEPTIONが返されます。MessagingChannelUsageFunctions.saveHook_PostStmtExecuteOnceは UPDATE ステートメントの後、無条件に実行されます。MessagingChannelUsageFunctionsHelper.handlePostSaveを呼び出し、コミット後のTransactionObserverを登録します。- コミット時に、オブザーバーが(
AbstractChannelUsageDeploymentStatusServiceから継承した)ConversationChannelUsageDeploymentStatusService.handleProvisioningを呼び出します。このメソッドは次の処理を行います。runProvisioningを呼び出し、MessageTypeに応じてswitchで外部呼び出しを振り分けます。WHATS_APP→registerCsotWhatsAppNumber→LiveMessageSetupApi.registerWhatsAppNumber→ Meta/registerとステータス確認。所要時間は約 15~21 秒です。FACEBOOK→metaGraphApiService.subscribeFacebookPage。TEXT→registerCsotSms。AppleBusinessChat、Line、その他すべて →default分岐。外部呼び出しは行われず、ネットワーク待ちもありません。
- 成功時:PLSQL 経由で
DeploymentStatus = 'Active'を書き込みます。 - 失敗時:
DeploymentStatus = 'Error'とErrorReason/ErrorDetailsを書き込みます。
- 同じオブザーバー内の2回目の処理で、MCU が
ActiveになるとMessagingChannel.IsActive = trueに同期されます(ステータスがまだProvisioningの間は、isTransitioningStatusフラグによって切り替えがスキップされます)。
これらの処理はすべて PATCH リクエスト内で同期的に実行されます。204 レスポンスが返るのは、チェーン全体が完了した後です。WhatsApp:約15~21秒(Meta /register の往復時間)。Apple / Line:約1秒(外部呼び出しなし。ローカルの保存フック、オブザーバー、PLSQL 書き込みのみ)。wadtesting で 2026-04-30 に検証済みです。
参照ファイル一覧
| 参照ファイル | 読み込むタイミング |
|---|---|
references/phone-verification.md | ステージ3の結果が ErrorReason === "VERIFICATION_REQUIRED" の場合(WhatsApp のみ)。電話番号の OTP 確認サブフローを参照します。 |
references/worked-examples.md | WhatsApp の正常系、Apple の有効化、準備状態の確認失敗、または有効化済みの場合の何もしない動作の実行例を参照するとき。 |
references/gotchas.md | 想定外の結果をトラブルシューティングするとき、またはこのスキルを変更する前。既知の注意点11件を確認します。 |
なぜ Apex ではなく REST PATCH なのか?
REST PATCH を直接実行すると、旧 activateChannelUsage Apex メソッドと同一の保存フックチェーンが、仕組みを大幅に簡略化して実行されます。CSRF Cookie の取得、ブートストラップのフェッチ、Aura レスポンスの解析、二重にラップされた returnValue は不要です。REST のセマンティクスは明確です。204 は遷移の成功を、4xx は失敗を意味します。
コード上の根拠:MessagingChannelUsageFunctions.saveHook_PostStmtExecuteOnce は、REST、SOAP、Apex、Metadata API のいずれの DML 経路でも実行され、Apex 固有のゲートはありません。エンティティ XML(MessagingChannelUsage.entity.xml)では、DeploymentStatus が editAccess="always" と指定され、<readonly> 属性はありません。遷移バリデーター(getValidAPIStatusTransitions)では、Disabled → Provisioning(および New → Provisioning、Error → Provisioning | Deprovisioning、Active → Deprovisioning)が許可されています。DB 専用の遷移 Provisioning → Active | Error はオブザーバーの PLSQL 呼び出し用に予約されています。そのため、Provisioning を書き込み、最終状態はサーバーに決定させます。
このスキルを使用しない場合
- チャネルがすでに
IsActive=trueの場合。 API 遷移バリデーター(Active → ProvisioningはgetValidAPIStatusTransitions()に含まれていません)によって再実行がブロックされ、PATCH は 400 を返します。Stage 1 の事前条件チェックでこれを検出し、noop:trueを出力します。 - ルーティングが設定されていない場合。 以前は、
activateChannelUsageが Apex エントリーポイントでLiveMessageSetupException/nullQueueIdを発生させて失敗していました。REST パスでは、同じガードがvalidateChannelReadinessOnProvisioningにあります。SessionHandlerId=null && FallbackQueueId=nullの状態で書き込むと、400FIELD_INTEGRITY_EXCEPTIONが返されます。まずservice-de-channel-routing-configureを実行してください。Stage 1 のチェックも引き続き防御的に実行されます。 - MCU が存在しない場合。 存在しない行に PATCH はできません。先に挿入スキルを実行してください。これは
addChannelの副作用として常に MCU を作成します。
入力(呼び出し元から)
{CHANNEL_ID}— 15 文字または 18 文字のMessagingChannel.Id(プレフィックスは0Mj)。チャネルはすでに存在し、SessionHandlerIdまたはFallbackQueueIdが null でない必要があります。{ORG_ALIAS}— 任意。sfCLI のターゲット組織エイリアスです。デフォルトはsf config get target-orgの戻り値です。OAuth と SOQL の読み取りに使用します。{API_VERSION}— 任意。REST API バージョンです。デフォルトは68.0です。MessagingChannelUsageを標準 sobject としてアドレス指定できるバージョンであれば使用できます(v50 以降で動作するはずですが、網羅的にはテストされていません)。
このスキルの旧 Aura ベース版とは異なり、{POLL_TIMEOUT_S} / {POLL_INTERVAL_S} の入力はありません。PATCH はエンドツーエンドで同期的に実行されます。
出力(呼び出し元へ)
成功 — チャネルが稼働中:
{"ok": true, "channelId": "0Mj...", "mcuId": "0gL...", "deploymentStatus": "Active", "isActive": true, "messageType": "WhatsApp", "durationMs": 20934}
成功 — 何もしない(すでに有効):
{"ok": true, "noop": true, "channelId": "0Mj...", "message": "Channel already active"}
失敗 — 事前条件を満たしていない:
{"ok": false, "kind": "no-routing", "hint": "run service-de-channel-routing-configure first"}
{"ok": false, "kind": "no-mcu", "hint": "no MessagingChannelUsage row for this channel — run the insertion skill first"}
{"ok": false, "kind": "channel-missing","hint": "MessagingChannel id not found"}
失敗 — バリデーターまたはサーバー側のプロビジョニングエラー:
{"ok": false, "kind": "readiness-failed", "errorCode": "FIELD_INTEGRITY_EXCEPTION",
"message": "...", "hint": "validateChannelReadinessOnProvisioning rejected the write — most commonly missing consent; run service-de-channel-settings-configure first"}
{"ok": false, "kind": "provisioning-error", "mcuId": "0gL...", "errorReason": "MetaRegistrationFailed", "errorDetails": "..."}
{"ok": false, "kind": "verification-failed", "hint": "WhatsApp phone number verification failed or was declined by user"}
{"ok": false, "kind": "verification-request-failed", "errorCode": "...", "message": "...", "hint": "Could not request verification code from Meta"}
失敗 — 認証 / トランスポート:
{"ok": false, "kind": "auth", "hint": "OAuth token invalid / expired — run 'sf org login web'"}
{"ok": false, "kind": "transport", "status": 500, "message": "..."}
Stage 1:事前条件チェック
チャネルを読み取り、次に MCU を読み取ります。それぞれ別個の SOQL 呼び出しで行います。サブクエリーを組み合わせれば効率的ですが、子リレーションの名前を特定できない組織では失敗します(注意点 #4 を参照)。
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, DeveloperName, MessageType, IsActive, SessionHandlerId, FallbackQueueId, MessagingPlatformKey FROM MessagingChannel WHERE Id = '{CHANNEL_ID}'" \
--json > /tmp/amc-precheck-channel.json
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, DeploymentStatus, DeploymentType, ErrorReason, ErrorDetails FROM MessagingChannelUsage WHERE MessagingChannelId = '{CHANNEL_ID}'" \
--json > /tmp/amc-precheck-mcu.json
channel = /tmp/amc-precheck-channel.json records[0]、mcu = /tmp/amc-precheck-mcu.json records[0] とします。
| 条件 | 結果 |
|---|---|
| チャネルのクエリーが 0 件を返した | {ok:false, kind:"channel-missing", hint:"MessagingChannel id not found"} |
channel.IsActive === true | {ok:true, noop:true, channelId, message:"Channel already active"} — ここで終了 |
channel.SessionHandlerId == null && channel.FallbackQueueId == null | {ok:false, kind:"no-routing", hint:"run service-de-channel-routing-configure first"} |
| MCU のクエリーが 0 件を返した | {ok:false, kind:"no-mcu", hint:"no MessagingChannelUsage row for this channel — run the insertion skill first"} |
| それ以外 | {MCU_ID} = mcu.Id、{MESSAGE_TYPE} = channel.MessageType、{MESSAGING_PLATFORM_KEY} = channel.MessagingPlatformKey、{INITIAL_MCU_STATUS} = mcu.DeploymentStatus を記録し、Stage 2 に進みます。 |
最終結果で durationMs を報告できるよう、Stage 2 の開始時に {T0}(エポックミリ秒)も記録します。
Stage 1.1:すでにプロビジョニング中の MCU に対する高速パス
{INITIAL_MCU_STATUS} === "Provisioning" の場合、前回の呼び出しによって MCU はすでにこのトランザクション期間中に処理中です。Stage 2(PATCH の実行)を完全にスキップし、Stage 3(検証)に進みます。これはまれな競合状態に対するガードです。PATCH と監視処理は同期しているため、呼び出し元が 204 を確認する時点では、ステータスはすでに終端状態(Active または Error)になっています。外部から Provisioning が見えることはないはずです。事前チェックでこれが確認された場合、別の DML が Provisioning を書き込み、監視処理がまだ進行中です。2 回目の PATCH は実行しないでください。
ステージ 2:MessagingChannelUsage.DeploymentStatus = "Provisioning" を PATCH する
sf api request rest を使用して、認証情報を CLI のトランスポート内に保持します。OAuth トークンがシェルの状態に取り出されることはありません。
PATCH を実行します。この呼び出しには WhatsApp の場合、15~30 秒かかることがあります。オブザーバーは Meta の /register 往復を含めて同期的に実行されます。sf api request rest にはクライアント側で個別に設定できるタイムアウトがないため、基盤となる HTTP 呼び出しが完了するまで待機します。
sf api request rest \
"/services/data/v{API_VERSION}/sobjects/MessagingChannelUsage/{MCU_ID}" \
--method PATCH \
--target-org '{ORG_ALIAS}' \
--header 'Content-Type: application/json' \
--body '{"DeploymentStatus":"Provisioning"}' \
--include \
> /tmp/amc-patch-response.txt 2>&1
HTTP_CODE=$(head -1 /tmp/amc-patch-response.txt | grep -oE '[0-9]{3}')
--include は HTTP ステータス/ヘッダーのブロックを(通常、204 では空の)本文の前に出力します。-w 形式の末尾マーカーではなく、このブロックのステータス行を確認してください。
HTTP ステータスで分類します。
| ステータス | 本文 | 対応 |
|---|---|---|
| 204 | 空 | 成功です。オブザーバーの実行が完了し、MCU は Active または Error です。終端状態を読み取るため、ステージ 3 に進みます。 |
| 400 | [{errorCode:"FIELD_INTEGRITY_EXCEPTION", message:"..."}] | バリデーターによる拒否です。以下の表を参照してください。 |
| 400 | [{errorCode:"INVALID_FIELD_FOR_INSERT_UPDATE" or "MALFORMED_ID", ...}] | スキルの不具合です。ステージ 1 の MCU_ID が誤っているか、本文の形式が不正です。{ok:false, kind:"transport", status:400, message} を返します。 |
| 401 | (通常は空) | Bearer トークンが無効です。{ok:false, kind:"auth", hint:"OAuth token invalid / expired — run 'sf org login web'"} を返します。 |
| 403 | [{errorCode:"INSUFFICIENT_ACCESS"}] | ユーザーには DeploymentStatus を書き込む権限がありません。{ok:false, kind:"business", errorCode:"INSUFFICIENT_ACCESS", message} を返します。 |
| 5xx | さまざま | トランスポートエラーです。オブザーバーによるコミットが一部完了している可能性があります。ステージ 3 の SOQL を正とします。MCU の状態を読み取り、Active なら警告付きで成功を報告します。Error または引き続き Disabled の場合は、{ok:false, kind:"transport", status, message} として分類します。 |
既知の 400 FIELD_INTEGRITY_EXCEPTION メッセージ:
| メッセージの一部 | 意味 | 応答形式 |
|---|---|---|
| "invalid deployment status transition" | 現在のステータスでは → Provisioning への遷移が許可されていません(例:MCU がすでに Active です。ステージ 1 で検出されるはずですが、競合が発生する可能性があります)。 | MCU を再読み込みします。すでに Active なら、何もせず成功として返します。Provisioning なら、ステージ 3 でポーリングします。それ以外は {ok:false, kind:"readiness-failed", ...} を返します。 |
| "consent" / "keyword" / STOP/HELP に言及 | validateChannelReadinessOnProvisioning による拒否です。チャネルに必要な同意設定がありません。 | {ok:false, kind:"readiness-failed", errorCode:"FIELD_INTEGRITY_EXCEPTION", message, hint:"チャネルを有効化する前に、ConsentType と一致する MsgChannelLanguageKeyword レコード(オプトアウトキーワードと確認メッセージ)が必要です。service-de-channel-settings-configure を実行してください"}。 |
| "routing" / "queue" / "SessionHandler" | ルーティングの前提条件を満たしていません(ステージ 1 で検出されるはずですが、バリデーターが再確認します)。 | {ok:false, kind:"no-routing", message, hint:"最初に service-de-channel-routing-configure を実行してください"}。 |
| その他 | 認識できないバリデーターエラーです。 | {ok:false, kind:"readiness-failed", errorCode, message}。 |
ステージ 3:MCU の終端状態を読み取る
PATCH は同期的に実行されるため、ここに到達した時点で MCU は Active または Error です。ポーリングは不要です。一度だけ読み取ります。
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, DeploymentStatus, ErrorReason, ErrorDetails FROM MessagingChannelUsage WHERE Id = '{MCU_ID}'" \
--json > /tmp/amc-poststate-mcu.json
| ステータス | 対応 |
|---|---|
Active | ステージ 4 に進みます。 |
Error かつ ErrorReason === "VERIFICATION_REQUIRED" | WhatsApp チャネルの場合のみ、電話番号の OTP 認証が必要です。ステージ 3.2(WhatsApp 認証フロー)に進みます。 |
Error(その他) | {ok:false, kind:"provisioning-error", mcuId, errorReason, errorDetails} を返します。 |
Provisioning | 想定外です。PATCH が 204 を返す前にオブザーバーが終了するはずでした。防御的なポーリングに進みます(ステージ 3.1 を参照)。 |
Disabled | PATCH は 204 を返しましたが、書き込みが反映されていません。{ok:false, kind:"transport", message:"PATCH は 204 を返しましたが、MCU はまだ Disabled です。オブザーバーがコミットしませんでした"} を返します。 |
ステージ 3.2:WhatsApp の電話番号認証(ErrorReason === "VERIFICATION_REQUIRED" の場合のみ)
このサブフローは、WhatsApp チャネルの有効化が ErrorReason === "VERIFICATION_REQUIRED" で失敗した場合にのみ実行されます。この場合、登録前に Meta で電話番号を OTP 認証する必要があります。MCU が ErrorReason === "VERIFICATION_REQUIRED" を返した場合(WhatsApp のみ)、references/phone-verification.md を読み込み、その手順に従って電話番号認証のサブフロー(認証コードをリクエスト → ユーザーに入力を促す → コードを検証 → 有効化を一度だけ再試行)を進めてください。
ステージ 3.1:防御的ポーリング(ステージ 3 で Provisioning が確認された場合のみ)
オブザーバーの外部呼び出しブロック(WhatsApp/Facebook/SMS)は PATCH リクエスト内で同期的に実行されます。すべてのメッセージタイプで、runProvisioning に非同期キューを介した処理はありません(ConversationChannelUsageDeploymentStatusService の switch/case で確認済みです)。そのため、ステージ 3 で Provisioning ステータスが返ることは、通常の状態では起こらないはずです。発生する場合に考えられる原因は、外部呼び出しの成功後、PLSQL の終端書き込み前に例外が発生したこと、非同期オブザーバー実行を使う特殊なインスタンス構成、またはディスパッチ動作が未確認の将来の MessageType です。ステージ 3 が Provisioning を返した場合は、次のループを実行します。
for i in 1 2 3 4 5 6 7 8 9 10; do
sleep 3
STATUS=$(sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT DeploymentStatus FROM MessagingChannelUsage WHERE Id='{MCU_ID}'" --json \
| node -e 'console.log(JSON.parse(require("fs").readFileSync(0,"utf8")).result.records[0].DeploymentStatus)')
case "$STATUS" in
Provisioning) continue ;;
Active|Error) break ;;
esac
done
最大待機時間:30 秒。ループ後も Provisioning の場合は、{ok:false, kind:"timeout", mcuId, lastStatus:"Provisioning", elapsedS:30} を出力します。2026-04-30 に WhatsApp/wadtesting で確認済み:このループが実際に反復されることはないはずです。
ステージ 4:MessagingChannel.IsActive を確認する
オブザーバーはステータスの終端書き込みと同じコールバック内で IsActive を切り替えます。原則として、PATCH の応答が返るまでに設定されます。確認してください。
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, IsActive FROM MessagingChannel WHERE Id = '{CHANNEL_ID}'" --json > /tmp/amc-verify-channel.json
IsActive === true の場合は、durationMs = Date.now() - T0 を計算して成功を出力します。MCU が Active であるにもかかわらず IsActive !== true の場合は、IsActive の同期処理がスキップされています(たとえば、オブザーバーの実行時に isTransitioningStatus が true だった場合です。終端状態になった後に発生するはずはありません)。次を出力します。
{"ok": false, "kind": "provisioning-error", "mcuId": "...", "errorReason": "mcu-active-but-channel-inactive",
"errorDetails": "MCU DeploymentStatus=Active but MessagingChannel.IsActive=false — observer's IsActive sync pass didn't run. Inspect MessagingChannelUsageFunctionsHelper.handlePostSave."}
ステージ 5:呼び出し元に結果を返す
成功時のエンベロープを作成します。
{"ok": true, "channelId": "{CHANNEL_ID}", "mcuId": "{MCU_ID}", "deploymentStatus": "Active",
"isActive": true, "messageType": "{MESSAGE_TYPE}", "durationMs": 20934}
このスキルがリーフ(ユーザーが直接呼び出したスキル)の場合は、次の内容を表示します。
Success — Activated — MessagingChannel {CHANNEL_ID} ({messageType}) is now live. MCU DeploymentStatus=Active, IsActive=true. (~{durationMs/1000}s)(有効化に成功)Info: Already active — MessagingChannel {CHANNEL_ID} is IsActive=true. No changes.(変更なしのパス)Error: Routing not configured — run 'service-de-channel-routing-configure' skill first.(ルーティング未設定)Error: No MessagingChannelUsage row — run the insertion skill first.(MCU なし)Error: Readiness check failed: {message} — if it mentions consent/keywords, run 'service-de-channel-settings-configure' first.(準備状態の確認に失敗)Error: Activation failed: {errorReason} — {errorDetails}(プロビジョニングエラー)Error: WhatsApp phone number verification failed: {hint}(認証失敗)Error: Could not request verification code: {message}(認証コードのリクエスト失敗)Timeout: Activation timed out after {elapsedS}s with MCU.DeploymentStatus={lastStatus}. Defensive-poll limit hit; this is unusual. Check MCU {mcuId} in Setup.(タイムアウト)
実行例
エンドツーエンドの有効化のトレース(WhatsApp の正常系、Apple の有効化、準備状態バリデーターの失敗、すでに有効な場合の変更なし)については、references/worked-examples.md を参照してください。
注意点
既知の注意点が 11 個あります。WhatsApp の同期 PATCH のタイミング、有効な API ステータス遷移、IsActive の同期処理、組織間でのリレーション名の違い、同意に関する前提条件、DeploymentStatus ピックリストの大文字・小文字、REST と Apex の同等性、ErrorReason の値、VERIFICATION_REQUIRED の処理、OAuth トークンの抽出、Status-code-409 による Admin API の競合です。予期しない結果のトラブルシューティングやこのスキルの変更を行う前に、references/gotchas.md を読み込み、その手順に従ってください。