

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# 動的フローのセットアップ
<a name="managing-flows-dynamic"></a>

動的フローは、実行時に独自の HTTPS エンドポイントを呼び出して、画面コンテンツを取得し、ナビゲーションを決定します。静的フローは、フロー JSON のすべての画面を定義します。動的フローは代わりに `data_exchange`アクションを使用して、ユーザーが画面間を移動するたびにエンドポイントにデータをリクエストします。これにより、オープンオーダーの表示、入力サーバー側の検証、バックエンドの決定に基づく分岐など、パーソナライズされたデータ駆動型のエクスペリエンスが可能になります。

ユーザーが動的フローとやり取りすると、Meta は暗号化されたリクエストでエンドポイントを直接呼び出します。エンドポイントはリクエストを復号し、ビジネスロジックを実行し、レスポンスを暗号化して、Meta に返します。暗号化されたリクエストとレスポンスは Meta とエンドポイントの間で直接渡されるため、 AWS End User Messaging Social はこれらの交換の復号されたコンテンツにアクセスできません。 AWS End User Messaging Social は、フローの作成と更新、暗号化パブリックキーのアップロード、フローヘルスウェブフックの配信のコントロールプレーンを管理します。

動的フローを設定するには、次の手順を実行します。

1. HTTPS エンドポイントをデプロイします。

1. 暗号化用のビジネスパブリックキーをアップロードします。

1. エンドポイント URI を使用してフローを作成します。

1. Meta アプリをアタッチしてリクエストを検証します。

1. フローを発行します。

## ステップ 1: HTTPS エンドポイントをデプロイする
<a name="managing-flows-dynamic-endpoint"></a>

エンドポイントは、次の要件を満たしている必要があります。
+ 有効な TLS 証明書を持つパブリックにアクセス可能な HTTPS URL。
+ 10 秒以内に応答します。メタはハードタイムアウトを適用し、p90 レイテンシーをモニタリングします。レイテンシーのしきい値を一貫して超えたり、エラーを返したりするエンドポイントは、スロットリングまたはブロックされる可能性があります。
+ 暗号化された JSON ペイロードを含む POST リクエストを受け入れます。
+ 暗号化されたレスポンスを `text/plain` (base64 エンコード) として返します。

パブリック HTTPS URL を提供する任意のコンピューティングオプションを使用できます。一般的なアプローチは次のとおりです。
+ **AWS Lambda 関数 URL** — HTTPS エンドポイントが組み込まれた単一の関数。Meta は を使用しない`NONE`ため、認可タイプを に設定します。で設定したビジネス暗号化キーペアを使用してリクエストを認証します[ステップ 2: ビジネスパブリックキーをアップロードする](#managing-flows-dynamic-encryption)。
+ **Lambda を使用した Amazon API Gateway ** — ソース IPs、 AWS WAF ルール、スロットリングを制限するリソースポリシーなどの追加のコントロールを提供します。
+ **Lambda ターゲットを使用した Elastic Load Balancing ** — 既存の負荷分散インフラストラクチャと組み合わせる場合に便利です。
+ その他の HTTPS サーバー (コンテナ、Amazon EC2 インスタンス、または外部サービス）。

エンドポイントは、次のリクエストタイプを処理する Meta のデータ交換契約を実装する必要があります。
+ **ヘルスチェック** — メタは定期的に`ping`リクエストを送信して、エンドポイントが使用可能であることを確認します。で応答します`{"data": {"status": "active"}}`。
+ **INIT** — ユーザーがフローを開いたときに送信されます。初期画面とそのデータを返します。
+ **data\_exchange** — ユーザーが画面を送信するたびに送信されます。次の画面とそのデータを返します。
+ **BACK** — ユーザーが前の画面に戻ったときに送信されます。

複数の言語での暗号化および復号コードサンプルを含むエンドポイント実装ガイドの詳細については、Meta for Developers ウェブサイトの[「フローエンドポイントの実装](https://developers.facebook.com/docs/whatsapp/flows/guides/implementingyourflowendpoint)」を参照してください。

## ステップ 2: ビジネスパブリックキーをアップロードする
<a name="managing-flows-dynamic-encryption"></a>

Meta は、RSA (Rivest-Shamir-Adleman) パブリックキーを使用して、すべてのデータ交換リクエストをend-to-endで暗号化します。エンドポイントは、対応するプライベートキーを使用してリクエストを復号します。 AWS End User Messaging Social は、ユーザーに代わってパブリックキーを Meta にアップロードしますが、プライベートキーにアクセスまたは保存することはありません。

`PutWhatsAppBusinessPublicKey` API を使用して、電話番号のパブリックキーをアップロードします。次のいずれかを指定する必要があります。
+ **PEM エンコードされた RSA パブリックキー** — キーを直接指定します。エンドポイントは、復号用の対応するプライベートキーを保持します。
+ **AWS Key Management Service キー ARN** — 非対称 RSA-2048 KMS キーの ARN を指定します。 AWS End User Messaging Social は、 を使用してパブリック半分のみを読み取り`kms:GetPublicKey`、Meta にアップロードします。プライベートキーが を離れることはありません AWS KMS。エンドポイントは を使用して、実行時にリクエスト`kms:Decrypt`を復号します。

両方を指定するか、どちらも を返します`InvalidParametersException`。

**PEM モード**

RSA キーペアを生成し、パブリックキーをアップロードします。

```
# Generate a key pair
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -pubout -out public.pem

# Upload the public key
aws social-messaging put-whatsapp-business-public-key \
    --origination-phone-number-id {{{PHONE_NUMBER_ID}}} \
    --business-public-key "$(cat public.pem)"
```

プライベートキーを安全に保存し、エンドポイントで復号化できるようにします。

**AWS KMS モード**

非対称 RSA KMS キーを作成し、その ARN をアップロードします。

```
# Create the KMS key
KMS_KEY_ARN=$(aws kms create-key \
    --key-spec RSA_2048 \
    --key-usage ENCRYPT_DECRYPT \
    --description "WhatsApp Dynamic Flow encryption key" \
    --query KeyMetadata.Arn --output text)

# Upload the KMS key ARN
aws social-messaging put-whatsapp-business-public-key \
    --origination-phone-number-id {{{PHONE_NUMBER_ID}}} \
    --kms-key-arn {{$KMS_KEY_ARN}}
```

KMS キーポリシーは、次のアクセス許可を付与する必要があります。
+ `kms:GetPublicKey` `social-messaging.amazonaws.com`をサービスプリンシパルに送信します。これにより、 AWS エンドユーザーメッセージングソーシャルはパブリックキーを読み取って Meta にアップロードできます。
+ `kms:Decrypt` エンドポイントの実行ロールに。これにより、エンドポイントは受信データ交換リクエストを復号できます。 AWS End User Messaging Social はこのキー`kms:Decrypt`を呼び出すことはありません。

**キーの検証**

`GetWhatsAppBusinessPublicKey` API を使用して、保存されたキーを確認し、Meta の署名ステータスを確認します。

```
aws social-messaging get-whatsapp-business-public-key \
    --origination-phone-number-id {{{PHONE_NUMBER_ID}}}
```

レスポンスには、保存された PEM と Meta の署名ステータス (`VALID` または ) が含まれます`MISMATCH`。`MISMATCH` ステータスは、保存されたキーが Meta の予想と一致していないことを示します。このステータスが表示された場合は、新しいキーをアップロードします。

## ステップ 3: エンドポイントを使用してフローを作成する
<a name="managing-flows-dynamic-create"></a>

動的フローを作成するときは、HTTPS エンドポイント URL で `--endpoint-uri`パラメータを指定します。フロー JSON も を宣言する必要があります。これにより`data_api_version`、フローセッション中にエンドポイントを呼び出すよう Meta に指示します。

```
aws social-messaging create-whatsapp-flow \
    --id {{{WABA_ID}}} \
    --flow-name "{{my_dynamic_flow}}" \
    --categories '["OTHER"]' \
    --flow-json fileb://{{flow.json}} \
    --endpoint-uri "{{https://your-endpoint.example.com/flow}}"
```

を使用して、既存のドラフトフローでエンドポイントを追加または変更することもできます`UpdateWhatsAppFlow`。

```
aws social-messaging update-whatsapp-flow \
    --id {{{WABA_ID}}} \
    --flow-id {{{FLOW_ID}}} \
    --endpoint-uri "{{https://your-endpoint.example.com/flow}}"
```

**注記**  
動的フローを発行すると、Meta はエンドポイントに対して同期ヘルスチェックを実行します。エンドポイントが応答しない場合、またはエラーを返す場合、パブリッシュオペレーションは失敗し、次のような Meta エラーが発生します `131000` (「エンドポイントが使用可能であり、ヘルスチェックを実装していることを確認します」）。ビジネスパブリックキーが欠落しているか無効である場合も、このエラーが発生する可能性があります。公開する前に、エンドポイントがデプロイされ、`ping`リクエストに応答していること、および有効なビジネスパブリックキーをアップロードしていることを確認します (「」を参照[ステップ 2: ビジネスパブリックキーをアップロードする](#managing-flows-dynamic-encryption))。

フロー用に設定されたエンドポイントとデータ API バージョンを確認するには、 を使用します`GetWhatsAppFlow`。

```
aws social-messaging get-whatsapp-flow \
    --id {{{WABA_ID}}} \
    --flow-id {{{FLOW_ID}}}
```

レスポンスには、Meta `endpointUri`が保持している 、Flow JSON で`dataApiVersion`宣言されている 、および現在アタッチされている が含まれます`application`。

## ステップ 4: Meta アプリをアタッチしてリクエストを検証する
<a name="managing-flows-dynamic-app"></a>

デフォルトでは、フロースルー AWS エンドユーザーメッセージングソーシャルを作成すると、サービスの Meta アプリに関連付けられます。エンドポイントへのデータ交換リクエストが Meta から発信されていることを確認するには、独自の Meta アプリを Flow にアタッチします。独自のアプリをアタッチしないと、リクエストオリジンの検証はできません。アプリをアタッチすると、Meta が各リクエストに含める `X-Hub-Signature-256` HMAC ヘッダーを検証するために必要なアプリシークレットにアクセスできます。

```
aws social-messaging update-whatsapp-flow \
    --id {{{WABA_ID}}} \
    --flow-id {{{FLOW_ID}}} \
    --meta-app-id "{{{YOUR_META_APP_ID}}}"
```

Meta アプリは、WhatsApp Business Account (WABA) を所有するのと同じビジネスによって所有されている必要があります。

**重要**  
独自の Meta アプリをアタッチすることは、一方向操作です。アプリをアタッチした後、サービスのアプリを再アタッチすることはできません。これはフロー機能には影響しません。新しいフローのみがアプリケーションの関連付けをリセットします。

`--endpoint-uri` と は、同じ呼び出し`--meta-app-id`または別々の呼び出しで設定できます。2 つのフィールドは独立しています。

アプリをアタッチしたら、 を呼び出し`GetWhatsAppFlow`てレスポンスの `application`フィールドを確認して設定を確認します。は、指定した Meta アプリ ID と一致する`application.id`必要があります。

## エンドポイントの保護
<a name="managing-flows-dynamic-security"></a>

Meta はエンドポイントを直接呼び出すため、次のセキュリティプラクティスを検討してください。
+ **リクエスト署名の検証** — 独自の Meta アプリをアタッチした場合 (ステップ 4)、アプリシークレットを使用して、各リクエストで `X-Hub-Signature-256` HMAC-SHA256 ヘッダーを検証します。これにより、リクエストが Meta から発信されたことが確認されます。検証が失敗した場合、HTTP ステータス 432 を返します。
+ **フロートークンの検証** — フローをユーザーに送信するときに、フローセッション`flow_token`ごとに一意の予測不可能な を生成します。エンドポイントは暗号化されたペイロード内でトークンを受け取り、アクティブなセッションに対して検証する必要があります。トークンが不明、期限切れ、または既に完了しているリクエストを拒否します。これにより、未承認または再生されたリクエストがビジネスロジックに到達するのを防ぎます。
+ **トークンの検証なしでヘルスチェックを処理する** — メタはエンドポイントのヘルスをモニタリングするための定期的な`ping`リクエストを送信します。これらのリクエストには は含まれません`flow_token`。拒否するとエンドポイントの可用性スコアが低下するため、トークンの検証を必要とせずにヘルスチェックに応答します。
+ **適切なステータスコードを返**す — エンドポイントがリクエストを復号できない場合 (メタはパブリックキーを再取得して再試行します）、421 を返します。が無効な場合は 427 を返します (メタ`flow_token`はそのセッションのフローボタンを無効にします）。

## 動的フロー JSON の記述
<a name="managing-flows-dynamic-flow-json"></a>

動的フロー JSON は、静的フロー JSON と 2 つの点で異なります。

1. 最上位`data_api_version`フィールドは必須です。これにより、 Meta はフローセッション中にエンドポイントを呼び出すように指示されます。サポートされている値は `"3.0"`と です `"4.0"` (推奨）。

1. 画面フッターは、 の代わりに `data_exchange`アクションを使用します`navigate`。各`data_exchange`アクションはフォームデータをエンドポイントに送信し、次の画面とそのコンテンツを返します。

次の例は、2 つの画面を持つ最小限の動的フロー JSON を示しています。最初の画面はユーザー名を収集し、エンドポイントに送信します。エンドポイントは、2 番目の画面でパーソナライズされた挨拶を返します。

```
{
    "version": "6.0",
    "data_api_version": "3.0",
    "routing_model": {
        "INPUT": ["RESULT"],
        "RESULT": []
    },
    "screens": [
        {
            "id": "INPUT",
            "title": "Welcome",
            "data": {
                "greeting": {
                    "type": "string",
                    "__example__": "Tell us your name"
                }
            },
            "layout": {
                "type": "SingleColumnLayout",
                "children": [
                    {
                        "type": "TextBody",
                        "text": "${data.greeting}"
                    },
                    {
                        "type": "Form",
                        "name": "input_form",
                        "children": [
                            {
                                "type": "TextInput",
                                "name": "user_name",
                                "label": "Your name",
                                "input-type": "text",
                                "required": true
                            },
                            {
                                "type": "Footer",
                                "label": "Submit",
                                "on-click-action": {
                                    "name": "data_exchange",
                                    "payload": {
                                        "user_name": "${form.user_name}"
                                    }
                                }
                            }
                        ]
                    }
                ]
            }
        },
        {
            "id": "RESULT",
            "title": "Hello",
            "terminal": true,
            "data": {
                "message": {
                    "type": "string",
                    "__example__": "Hello, World!"
                }
            },
            "layout": {
                "type": "SingleColumnLayout",
                "children": [
                    {
                        "type": "TextBody",
                        "text": "${data.message}"
                    },
                    {
                        "type": "Footer",
                        "label": "Done",
                        "on-click-action": {
                            "name": "complete",
                            "payload": {}
                        }
                    }
                ]
            }
        }
    ]
}
```

Flow JSON スキーマの完全なリファレンスについては、Meta for Developers ウェブサイトの[「Flow JSON](https://developers.facebook.com/docs/whatsapp/flows/reference/flowjson)」を参照してください。

## エンドツーエンドの例
<a name="managing-flows-dynamic-example"></a>

次の例は、動的フローを設定して公開するための API コールの完全なシーケンスを示しています。

```
# 1. Upload the business public key (KMS mode)
aws social-messaging put-whatsapp-business-public-key \
    --origination-phone-number-id {{{PHONE_NUMBER_ID}}} \
    --kms-key-arn {{{KMS_KEY_ARN}}}

# 2. Create the Dynamic Flow with an endpoint
FLOW_ID=$(aws social-messaging create-whatsapp-flow \
    --id {{{WABA_ID}}} \
    --flow-name "{{my_dynamic_flow}}" \
    --categories '["OTHER"]' \
    --flow-json fileb://{{flow.json}} \
    --endpoint-uri "{{https://your-endpoint.example.com/flow}}" \
    --query flowId --output text)

# 3. Attach your Meta app for signature verification
aws social-messaging update-whatsapp-flow \
    --id {{{WABA_ID}}} \
    --flow-id $FLOW_ID \
    --meta-app-id "{{{YOUR_META_APP_ID}}}"

# 4. Publish the Flow
aws social-messaging publish-whatsapp-flow \
    --id {{{WABA_ID}}} \
    --flow-id $FLOW_ID

# 5. Verify the configuration
aws social-messaging get-whatsapp-flow \
    --id {{{WABA_ID}}} \
    --flow-id $FLOW_ID
```

公開後、フローはテンプレートメッセージで使用できます。フローの送信の詳細については、「」を参照してください[WhatsApp フローをユーザーに送信する](managing-flows-send.md)。