mcpField
T
twilio

twilio

github.com/alphaonedevクラウド・DevOps41 回インストール
リポジトリ

twilio について

twilioは、Twilioの本番ワークフローを運用するエンジニア向けのOpenClawスキルです。Twilio CLI、REST API、SDKを通じたアカウント管理、メッセージング、音声、認証、SendGrid、Studio、障害対応を扱います。

主な機能

  1. 01アカウントとサブアカウントの管理
  2. 02MessagingとVoiceフローの運用
  3. 03VerifyとSendGridワークフローの設定
  4. 04Studioフローの実行とバージョン管理
  5. 05エラー、再試行、レート制限への対応

活用シーン

  1. 01本番とステージングのアカウント分離
  2. 02Webhookや通信事業者の障害調査
  3. 03準拠したメッセージングと認証の実装
  4. 04CIでのTwilio運用自動化

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/alphaonedev/openclaw-graph --skill twilio

インストール後、Claude Code で/twilioを入力して読み込まれたか確認します。

詳細

twilio

目的

OpenClaw が Twilio の「ルート」本番ワークフローをエンドツーエンドで運用できるようにします。アカウントとサブアカウントの管理、API キーと認証、コンソール/請求/レート制限、およびその上に構築される運用パターン(Messaging/Voice/Verify/SendGrid/Studio)が含まれます。このスキルは、次のことを必要とするエンジニア向けです。

  • 環境ごとの分離を含め、認証情報(API キー、Auth Token、SendGrid キー)を安全にプロビジョニングし、ローテーションします。
  • 本番インシデント(Webhook の失敗、キャリアエラー、レート制限、無効な番号、認証エラー)をデバッグし、対処します。
  • 適切なコンプライアンス(STOP の処理、10DLC、フリーダイヤル番号の認証)に準拠した、本番品質の Messaging/Voice/Verify フローを実装します。
  • コストとパフォーマンスを制御します(地域マッチング機能付きメッセージングサービス、同時実行、リトライ/バックオフ、録音/文字起こしのコスト)。
  • CLI、REST API、IaC パターンを通じて Twilio の運用を自動化します。

前提条件

アカウントとアクセス
  • Console にアクセスできる Twilio アカウント:https://console.twilio.com/
  • 米国で Messaging を使用する場合:
    • A2P 10DLC ブランドとキャンペーンの登録(米国のロングコードメッセージングの大半で必須)。
    • A2P にフリーダイヤル番号を使用する場合は、フリーダイヤル番号の認証。
    • ショートコードを使用する場合は、ショートコードの承認。
  • WhatsApp の場合:
    • WhatsApp Business Account(WABA)と、設定済みの Twilio WhatsApp 送信者。
  • Voice の場合:
    • Voice 機能を備えた Twilio 電話番号。
    • SIP トランキングを使用する場合:Twilio Elastic SIP Trunking が有効であること。
  • Verify の場合:
    • Verify サービスが作成済みであること(Verify V2)。
  • SendGrid の場合:
    • SendGrid アカウント(Twilio のログインとは別でも構いません)、および適切なスコープを持つ API キー。
ローカルツール(正確なバージョン)
  • Node.js 20.11.1(LTS)または 18.19.1(LTS)
  • Python 3.11.8 または 3.12.2
  • curl 8.5.0+
  • jq 1.7+
  • OpenSSL 3.0.13+(署名検証ツール用)
  • Docker 25.0.3+(任意。ローカルの Webhook 受信先や統合テスト用)
Twilio SDK(推奨する固定バージョン)
  • Node:twilio 4.23.0
  • Python:twilio 9.0.5
  • SendGrid Node:@sendgrid/mail 8.1.1
  • SendGrid Python:sendgrid 6.11.0
認証の設定(Twilio)

Twilio がサポートする認証情報:

  • Account SID(AC... で始まります)
  • Auth Token(シークレット)
  • API Key SID(SK... で始まります)+ API Key Secret(アプリ/CI では Auth Token より推奨)
  • サブアカウント(それぞれが独自の Account SID/Auth Token を持ち、アカウントごとに API キーを作成できます)

本番環境で推奨される最低限の対策:

  • アプリ/CI では API キー+シークレットを使用します。
  • Auth Tokenは緊急時の使用とコンソールでの使用に限定し、漏えいした場合はローテーションします。
  • 環境(prod/stage/dev)ごと、および/またはテナントごとにサブアカウントを分けます。
Twilio CLI(任意ですが、強く推奨)

Twilio CLI は対話的な操作に便利です。自動化には REST と IaC を優先しますが、インシデント対応にも役立ちます。

  • Twilio CLI:twilio-cli 5.17.0
  • プラグイン:
    • @twilio-labs/plugin-serverless 3.0.2(Twilio Functions/Assets 用)
    • @twilio-labs/plugin-flex 6.0.6(Flex を使用する場合)

npm でインストールします(「インストールとセットアップ」を参照)。

基本概念

アカウント、サブアカウント、プロジェクト
  • アカウント:最上位の請求単位です。AccountSid(AC...)で識別されます。
  • サブアカウント:独自の認証情報、電話番号、メッセージングサービスなどを持つ子アカウントです。環境やテナントの分離に役立ちます。
  • プロジェクト:Twilio Console UI 上のグループです。独立したセキュリティ境界ではありません。サブアカウントと混同しないでください。

本番環境でのパターン:

  • 請求用に親アカウントを 1 つ用意します。
  • 環境ごとにサブアカウントを用意します:prod、staging、dev。
  • 厳密な分離と電話番号プールの分割が必要な場合は、顧客/テナントごとにサブアカウントを用意することもできます。
認証情報
  • Auth Token:アカウントのマスターシークレットです。漏えい時の影響範囲が大きくなります。
  • API Keys:アカウントにスコープが設定され、Auth Token をローテーションせずに取り消せます。
  • キーのローテーション:新しいキーを作成し、デプロイして、確認した後、古いキーを取り消します。
メッセージングアーキテクチャ
  • 送信元には、次のいずれかを指定できます。
    • 電話番号(10DLC ロングコード、フリーダイヤル番号、ショートコード)
    • 適切な送信元を選択する Messaging Service SID(MG...)(プール、地域マッチング、スティッキー送信元)
  • ステータスコールバック:Webhook を介したメッセージのライフサイクルイベント:
    • queued、sent、delivered、undelivered、failed(および、WhatsApp など、対応しているチャネルでは read の場合もあります)
  • STOP の処理:
    • Twilio には多くのチャネル向けにオプトアウト処理が組み込まれています。これを誤って上書きしてはいけません。
    • アプリでは STOP をコンプライアンスイベントとして扱い、受信者が再度オプトイン(例:START)するまで、その受信者への今後の送信を抑制してください。
音声アーキテクチャ
  • TwiML:Webhook が返す、通話を制御するための XML 命令です。
    • IVR 用の <Dial>、<Conference>、<Record>、<Say>(Polly 音声を使用)、<Gather>。
  • 通話ステータスコールバック:通話イベント用の Webhook です。
  • 録音:通話ごと、またはカンファレンスごとに有効化できます。文字起こしは別の機能であり、コストと遅延が発生します。
  • SIP トランキング:PBX/SBC を Twilio に接続します。認証と IP ACL の慎重な設定が必要です。
Verify V2
  • Verify Service(VA...)でチャネル構成とポリシーを定義します。
  • Verify のチェックにはレート制限と不正利用対策が適用されます。429 と Verify 固有のエラーコードを処理する必要があります。
  • カスタムチャネル:メール/プッシュ/TOTP を統合できます。それぞれを個別の信頼性および到達性のドメインとして扱ってください。
SendGrid
  • トランザクション用とマーケティング用:
    • トランザクション用:API 主導、低遅延、テンプレート対応です。
    • マーケティング用:キャンペーン、リスト管理、コンプライアンスに対応します。
  • 動的テンプレートでは Handlebars を使用します。
  • Inbound Parse:受信メールを HTTP POST に変換する Webhook です。
Studio
  • Studio Flow は、Twilio で管理されるステートマシンです。
  • REST Trigger API でフローの実行を開始できます。
  • バージョン管理のためにフローをエクスポート/インポートできます。Split ウィジェットを使用して A/B テストを実施できます。
レート制限と再試行
  • Twilio ではアカウント単位およびリソース単位のレート制限が適用されます。20429 と HTTP 429 が返されます。
  • Twilio は 2xx 以外のレスポンスに対して Webhook を再試行します。エンドポイントは冪等でなければなりません。

インストールとセットアップ

公式 Python SDK

リポジトリ: https://github.com/twilio/twilio-python
PyPI: https://pypi.org/project/twilio/ · 対応バージョン: Python 3.7–3.13

pip install twilio
from twilio.rest import Client
import os

# Environment variables (recommended)
client = Client()  # reads TWILIO_ACCOUNT_SID + TWILIO_AUTH_TOKEN

# API Key auth (preferred for production)
client = Client(
    os.environ["TWILIO_API_KEY"],
    os.environ["TWILIO_API_SECRET"],
    os.environ["TWILIO_ACCOUNT_SID"]
)

# Regional edge routing
client = Client(region='au1', edge='sydney')

出典:twilio/twilio-python — クライアント認証

Ubuntu 22.04 / 24.04 (x86_64)

依存関係をインストールします:

sudo apt-get update
sudo apt-get install -y curl jq ca-certificates gnupg lsb-release openssl

NodeSource 経由で Node.js 20.11.1 をインストールします:

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
node -v  # expect v20.11.x
npm -v

Twilio CLI 5.17.0:

sudo npm install -g [email protected]
twilio --version

オプションのプラグイン:

twilio plugins:install @twilio-labs/[email protected]
twilio plugins:install @twilio-labs/[email protected]
twilio plugins

Python 3.11(必要な場合):

sudo apt-get install -y python3 python3-venv python3-pip
python3 --version
Fedora 39 / 40 (x86_64)
sudo dnf install -y curl jq openssl nodejs npm python3 python3-pip
node -v
sudo npm install -g [email protected]
twilio --version
macOS 14 (Sonoma) Intel

Homebrew:

brew update
brew install node@20 jq openssl@3 [email protected]
brew link --force --overwrite node@20
node -v

Twilio CLI:

npm install -g [email protected]
twilio --version
macOS 14 (Sonoma) Apple Silicon (ARM64)

Intel と同じです。PATH が正しく設定されていることを確認してください:

brew install node@20 jq openssl@3 [email protected]
echo 'export PATH="/opt/homebrew/opt/node@20/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
node -v
npm install -g [email protected]
twilio --version
Twilio CLI の認証

対話型ログイン(トークンをローカル設定に保存します):

twilio login

環境変数を使用した非対話型認証(CI。推奨):

export TWILIO_ACCOUNT_SID="YOUR_ACCOUNT_SID"
export TWILIO_API_KEY="YOUR_API_KEY_SID"
export TWILIO_API_SECRET="your_api_key_secret_here"

Auth Token を使用する必要がある場合(CI では非推奨):

export TWILIO_AUTH_TOKEN="your_auth_token_here"

認証を確認します:

twilio api:core:accounts:fetch --sid "$TWILIO_ACCOUNT_SID"
SDK のインストール(Node)
mkdir -p twilio-app && cd twilio-app
npm init -y
npm install [email protected]
npm install @sendgrid/[email protected]
SDK のインストール(Python)
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install twilio==9.0.5 sendgrid==6.11.0

主な機能

アカウント管理(ルートアカウントとサブアカウント)
  • アカウント/サブアカウントの一覧表示、サブアカウントの作成/閉鎖。
  • API キーのローテーション。
  • 使用状況と請求に関する情報を取得します(API で取得可能な場合)。
  • サブアカウントを使用して環境を分離します。
Programmable Messaging(SMS/MMS/WhatsApp)
  • From 番号または Messaging Service(MessagingServiceSid)を使用してメッセージを送信します。
  • ステータスコールバックと Webhook の検証を実装します。
  • STOP/START によるオプトアウトを正しく処理します。
  • 米国のコンプライアンス要件に対応します:10DLC キャンペーン、フリーダイヤル番号の認証、ショートコード。
  • コストを最適化します:地域マッチング、スティッキー送信元、送信元プール。
音声(TwiML + SDK + SIP + IVR)
  • 着信/発信通話を制御する TwiML エンドポイント。
  • カンファレンス、録音、文字起こし。
  • <Gather> とサーバー側のセッション状態を使用する IVR ステートマシン。
  • SIP トランキングの統合パターンとセキュリティ。
Verify V2
  • Verify サービスを作成し、認証コードを送信して、コードを確認します。
  • カスタムチャネル(メール/プッシュ/TOTP)のパターン。
  • 不正利用対策とレート制限の処理。
SendGrid
  • 動的テンプレートを使ったトランザクションメール。
  • Inbound Parse webhook の取り込み。
  • バウンス/スパム処理と抑制管理。
  • IP ウォーミングと配信到達性の監視パターン。
Studio
  • REST 経由でフローをトリガーします。
  • バージョン管理のためにフローをエクスポート/インポートします。
  • 分岐ベースの A/B テストのパターン。
エラー処理と運用の卓越性
  • 一般的な Twilio エラーコードを修正手順に対応付けます。
  • Webhook の再試行に安全なエンドポイントを実装します。
  • レート制限時のバックオフと冪等性キー。

コマンドリファレンス

注:

  • Twilio CLI のコマンドグループは、CLI のバージョンやインストール済みプラグインによって多少異なる場合があります。以下のコマンドは、デフォルトのプラグインを使用した [email protected] で検証済みです。
  • 自動化には、直接 REST を呼び出すことをおすすめします。CLI は対話型の運用に最適です。
Twilio CLI のグローバルフラグ

ほとんどの twilio ... コマンドに適用されます:

  • -h, --help:ヘルプを表示
  • -v, --version:CLI のバージョンを表示
  • -l, --log-level <level>:debug|info|warn|error
  • -o, --output <format>:json|tsv(コマンドによって異なります)
  • --profile <name>:~/.twilio-cli/config.json の名前付きプロファイルを使用

例:

twilio -l debug api:core:accounts:fetch --sid "$TWILIO_ACCOUNT_SID"
twilio --profile prod api:core:messages:list --limit 20 -o json
認証とプロファイル

ログイン:

twilio login

プロファイルの一覧表示:

twilio profiles:list

プロファイルを使用:

twilio --profile prod api:core:accounts:fetch --sid YOUR_ACCOUNT_SID
アカウント(Core API)

アカウントを取得:

twilio api:core:accounts:fetch --sid YOUR_ACCOUNT_SID

アカウントを一覧表示(サブアカウントを含む):

twilio api:core:accounts:list --limit 50

フラグ:

  • --limit <n>:返すレコードの最大数
  • --page-size <n>:API ページネーションのページサイズ
  • --friendly-name <name>:フレンドリー名でフィルター(対応している場合)

サブアカウントを作成:

twilio api:core:accounts:create --friendly-name "prod-messaging"

アカウントのステータスを更新(サブアカウントを閉鎖):

twilio api:core:accounts:update --sid YOUR_ACCOUNT_SID --status closed

フラグ:

  • --friendly-name <name>
  • --status <status>:active|suspended|closed
API キー(Core API)

API キーを一覧表示:

twilio api:core:keys:list --limit 50

API キーを作成:

twilio api:core:keys:create --friendly-name "ci-prod-2026-02" --key-type standard

フラグ:

  • --friendly-name <name>
  • --key-type <type>:standard|restricted(restricted には追加設定が必要です。明確なポリシーモデルがない場合は standard をおすすめします)

キーを取得:

twilio api:core:keys:fetch --sid YOUR_API_KEY_SID

キーを削除(失効):

twilio api:core:keys:remove --sid YOUR_API_KEY_SID
メッセージング(Core API)

From を使って SMS を送信:

twilio api:core:messages:create \
  --from "+14155550100" \
  --to "+14155550199" \
  --body "prod smoke test 2026-02-21T18:42Z" \
  --status-callback "https://api.example.com/twilio/sms/status"

Messaging Service 経由で送信:

twilio api:core:messages:create \
  --messaging-service-sid YOUR_MG_SID \
  --to "+14155550199" \
  --body "geo-match send via MG"

重要なフラグ:

  • --from <E.164>:送信者の番号
  • --to <E.164>:宛先
  • --body <text>:本文
  • --media-url <url>:MMS 用。複数回指定できます
  • --messaging-service-sid <MG...>:--from の代わりにメッセージングサービスを使用
  • --status-callback <url>:メッセージステータスの Webhook
  • --max-price <decimal>:料金の上限(チャネルによって異なります)
  • --provide-feedback <boolean>:配信フィードバックを要求(対応している場合)
  • --validity-period <seconds>:メッセージの TTL
  • --force-delivery <boolean>:配信を強制的に試行(適用範囲は限定的です)
  • --application-sid <AP...>:メッセージングアプリケーション(レガシーパターン)
  • --smart-encoded <boolean>:スマートエンコーディングを有効化

メッセージを一覧表示:

twilio api:core:messages:list --limit 20

一覧をフィルター:

twilio api:core:messages:list --to "+14155550199" --date-sent 2026-02-21 --limit 50

メッセージを取得:

twilio api:core:messages:fetch --sid SM0123456789abcdef0123456789abcdef
着信電話番号

番号を一覧表示:

twilio api:core:incoming-phone-numbers:list --limit 50

番号を購入(利用可能状況は異なります):

twilio api:core:available-phone-numbers:us:local:list --area-code 415 --limit 5
twilio api:core:incoming-phone-numbers:create --phone-number "+14155550100" --friendly-name "prod-sms-415-0100"

番号に Webhook URL を設定:

twilio api:core:incoming-phone-numbers:update \
  --sid PN0123456789abcdef0123456789abcdef \
  --sms-url "https://api.example.com/twilio/sms/inbound" \
  --sms-method POST \
  --voice-url "https://api.example.com/twilio/voice/inbound" \
  --voice-method POST

フラグ(よく使われるもの):

  • --sms-url <url>、--sms-method <GET|POST>
  • --voice-url <url>、--voice-method <GET|POST>
  • --status-callback <url>(リソースによって、番号の音声通話ステータスコールバックに使用)
  • --friendly-name <name>
音声通話

発信通話を作成:

twilio api:core:calls:create \
  --from "+14155550100" \
  --to "+14155550199" \
  --url "https://api.example.com/twilio/voice/twiml/outbound"

フラグ:

  • --from、--to
  • --url <twiml-webhook-url>:TwiML 指示のエンドポイント
  • --method <GET|POST>
  • --status-callback <url>
  • --status-callback-event <initiated|ringing|answered|completed>(複数回指定できます)
  • --status-callback-method <GET|POST>
  • --timeout <seconds>
  • --record <boolean>
  • --recording-status-callback <url>
  • --recording-status-callback-method <GET|POST>

通話を取得:

twilio api:core:calls:fetch --sid YOUR_CA_SID

通話を一覧表示:

twilio api:core:calls:list --from "+14155550100" --start-time 2026-02-21 --limit 50
Verify V2(REST 優先。CLI の対応範囲は異なります)

Verify は通常、REST 呼び出しを使うのが最も簡単です。curl を使った例:

認証を送信:

curl -sS -X POST "https://verify.twilio.com/v2/Services/YOUR_VERIFY_SERVICE_SID/Verifications" \
  -u "$TWILIO_API_KEY:$TWILIO_API_SECRET" \
  --data-urlencode "To=+14155550199" \
  --data-urlencode "Channel=sms"

認証を確認:

curl -sS -X POST "https://verify.twilio.com/v2/Services/YOUR_VERIFY_SERVICE_SID/VerificationCheck" \
  -u "$TWILIO_API_KEY:$TWILIO_API_SECRET" \
  --data-urlencode "To=+14155550199" \
  --data-urlencode "Code=123456"
Studio(REST Trigger API)

Studio Flow の実行をトリガーします:

curl -sS -X POST "https://studio.twilio.com/v2/Flows/FW0123456789abcdef0123456789abcdef/Executions" \
  -u "$TWILIO_API_KEY:$TWILIO_API_SECRET" \
  --data-urlencode "To=+14155550199" \
  --data-urlencode "From=+14155550100" \
  --data-urlencode "Parameters={\"experiment\":\"B\",\"locale\":\"en-US\"}"
プラグイン経由の Serverless(Twilio Functions)

初期化:

mkdir -p twilio-functions && cd twilio-functions
twilio serverless:init twilio-prod-webhooks --template blank

デプロイ:

twilio serverless:deploy --environment production --force

フラグ:

  • --environment <name>:Twilio Serverless の環境
  • --force:プロンプトをスキップ
  • --service-name <name>:サービス名を上書き
  • --functions-folder <path>
  • --assets-folder <path>

設定リファレンス

Twilio CLI の設定

パス:

  • macOS/Linux:~/.twilio-cli/config.json
  • Windows(該当する場合):%USERPROFILE%\.twilio-cli\config.json

~/.twilio-cli/config.json の例:

{
  "profiles": {
    "prod": {
      "accountSid": "YOUR_ACCOUNT_SID",
      "apiKeySid": "YOUR_API_KEY_SID",
      "apiKeySecret": "ENV:TWILIO_API_SECRET",
      "region": "us1",
      "edge": "ashburn"
    },
    "staging": {
      "accountSid": "YOUR_ACCOUNT_SID",
      "authToken": "ENV:TWILIO_AUTH_TOKEN_STAGING",
      "region": "us1"
    }
  },
  "activeProfile": "prod"
}

注意事項:

  • 平文ではなく、環境変数(ENV:...)から取得した apiKeySecret を使用してください。
  • region/edge によってレイテンシーを低減できます。ご利用の Twilio デプロイ環境で有効か確認してください。
アプリケーションの環境変数

推奨ファイル:

  • /etc/twilio/twilio.env(Linux サーバー)
  • または Kubernetes Secret と環境変数の注入

/etc/twilio/twilio.env の例:

TWILIO_ACCOUNT_SID=YOUR_ACCOUNT_SID
TWILIO_API_KEY=YOUR_API_KEY_SID
TWILIO_API_SECRET=supersecret_api_key_secret
TWILIO_MESSAGING_SERVICE_SID=YOUR_MG_SID
TWILIO_VERIFY_SERVICE_SID=YOUR_VERIFY_SERVICE_SID
TWILIO_WEBHOOK_AUTH_TOKEN=your_auth_token_for_signature_validation
TWILIO_REGION=us1
TWILIO_EDGE=ashburn
SENDGRID_API_KEY=SG.xxxxxx.yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

TWILIO_WEBHOOK_AUTH_TOKEN:

  • Twilio のリクエスト署名の検証には、Webhook 設定を所有するアカウントの Auth Token を使用します。
  • REST 呼び出しに API Keys を使用する場合でも、Webhook 署名の検証には Auth Token が必要になることがあります。別途保管し、アクセスを制限してください。
NGINX リバースプロキシ(Webhook エンドポイント)

パス:

  • /etc/nginx/conf.d/twilio-webhooks.conf

例:

server {
  listen 443 ssl http2;
  server_name api.example.com;

  ssl_certificate     /etc/letsencrypt/live/api.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;

  location /twilio/ {
    proxy_pass http://127.0.0.1:8080/;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Request-Id $request_id;

    proxy_read_timeout 10s;
    proxy_connect_timeout 2s;
  }
}
Systemd サービス(Linux)

パス:

  • /etc/systemd/system/twilio-webhooks.service

例:

[Unit]
Description=Twilio Webhook Service
After=network-online.target

[Service]
User=twilio
Group=twilio
EnvironmentFile=/etc/twilio/twilio.env
WorkingDirectory=/opt/twilio-webhooks
ExecStart=/usr/bin/node /opt/twilio-webhooks/server.js
Restart=always
RestartSec=2
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/twilio-webhooks /var/log/twilio-webhooks

[Install]
WantedBy=multi-user.target

統合パターン

シークレット管理(Vault/AWS/GCP)との連携

パターン:

  • TWILIO_API_SECRET、TWILIO_WEBHOOK_AUTH_TOKEN、SENDGRID_API_KEY をシークレットマネージャーに保管します。
  • 実行環境に環境変数として注入します。
  • 四半期ごと、またはインシデント発生時にキーをローテーションします。

例:Kubernetes External Secrets(AWS Secrets Manager)のスニペット:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: twilio-secrets
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets
    kind: ClusterSecretStore
  target:
    name: twilio-secrets
  data:
    - secretKey: TWILIO_API_SECRET
      remoteRef:
        key: prod/twilio
        property: api_secret
    - secretKey: TWILIO_WEBHOOK_AUTH_TOKEN
      remoteRef:
        key: prod/twilio
        property: auth_token
    - secretKey: SENDGRID_API_KEY
      remoteRef:
        key: prod/sendgrid
        property: api_key
CI/CD パイプライン:キーのローテーションとスモークテスト

パイプラインの手順:

  1. Twilio で新しい API キーを作成します(手動承認を行うか、ロックされたジョブで Auth Token を使って自動化します)。
  2. シークレットストアを更新します。
  3. デプロイします。
  4. スモークテスト:テスト用デバイスに SMS を送信し、ステータスコールバックを受信したことを確認します。
  5. 古いキーを無効にします。

スモークテストの例(Node):

node scripts/smoke_sms.js

scripts/smoke_sms.js:

import twilio from "twilio";

const accountSid = process.env.TWILIO_ACCOUNT_SID;
const apiKey = process.env.TWILIO_API_KEY;
const apiSecret = process.env.TWILIO_API_SECRET;
const mg = process.env.TWILIO_MESSAGING_SERVICE_SID;

const client = twilio(apiKey, apiSecret, { accountSid });

const to = "+14155550199";

const msg = await client.messages.create({
  messagingServiceSid: mg,
  to,
  body: `smoke ${new Date().toISOString()}`
});

console.log({ sid: msg.sid, status: msg.status });
イベント駆動型のステータス処理(Webhook → キュー → ワーカー)

パターン:

  • Twilio のステータスコールバックが /twilio/sms/status に届きます。
  • エンドポイントで署名を検証してペイロードを正規化し、Kafka/SQS/PubSub にエンキューします。
  • ワーカーが DB のメッセージステートマシンを更新します。MessageSid によって冪等性を確保します。

メリット:

  • Webhook のタイムアウトを回避できます。
  • リトライを安全に処理できます。
  • キャリアエラーの分析を一元化できます。
IVR ステートマシン(Voice Webhook とセッションの永続化)

パターン:

  • <Gather> を使用し、action がアプリを指すように設定します。
  • CallSid をキーにして状態を永続化します。
  • 冪等性を確保してください。エンドポイントがタイムアウトすると、Twilio が Webhook を再試行する場合があります。
Studio とバックエンドのオーケストレーション

パターン:

  • Studio で会話の分岐とチャネルの選択を処理します。
  • バックエンドからパラメーターを指定して Studio Flow をトリガーし、コールバックを受け取ります。
  • A/B テストには Split ウィジェットを使用し、experiment パラメーターを DB に保存します。

エラー処理とトラブルシューティング

1) エラー 21211(無効な To 番号)

症状(Twilio API の応答):

  • コード:21211
  • メッセージ:The 'To' number +1415555 is not a valid phone number.

根本原因:

  • E.164 形式ではありません。
  • 国番号がありません。
  • 許可されていない数字以外の文字やスペースが含まれています。

対処方法:

  • E.164 形式に正規化します(+14155550199)。
  • Twilio を呼び出す前に libphonenumber で検証します。
  • WhatsApp の場合は、whatsapp:+E164 になっていることを確認します。
2) エラー 20003(認証)

症状:

  • コード:20003
  • メッセージ:Authenticate

または HTTP 401:

  • HTTP 401 Unauthorized

根本原因:

  • API キー/シークレットが間違っています。
  • API Key SID を Auth Token とともに使用しており、API Key Secret を使用していません。
  • API キー認証を使用する際のアカウント SID が一致していません(SDK クライアントのオプションで accountSid を渡す必要があります)。

解決方法:

  • シークレットストアの認証情報を確認します。
  • Node SDK の場合:twilio(apiKey, apiSecret, { accountSid })。
  • キーが、対象としているアカウント/サブアカウントと同じアカウントに属していることを確認します。
3) エラー 20429(レート制限)

症状:

  • コード:20429
  • メッセージ:Too Many Requests

または HTTP 429。

根本原因:

  • アカウント/番号/チャネルの制限を超えるバースト送信。
  • Verify の確認頻度が高すぎます。
  • Studio のトリガー頻度が高すぎます。

解決方法:

  • ジッターを加えた指数バックオフを実装します。
  • アカウントごと、送信先ごとにクライアント側でレート制限(トークンバケット)を追加します。
  • 適切なスループット設定(10DLC/ショートコード)で Messaging Services を使用します。
  • Verify の場合:ユーザーごとのクールダウンと最大試行回数を設定します。
4) エラー 30003(到達不能/キャリアによる拒否)

症状:

  • コード:30003
  • メッセージ:Unreachable destination handset

根本原因:

  • キャリアによる拒否(無効な番号、ローミング制限、ブロック)。
  • 送信先が SMS を受信できません。

解決方法:

  • その試行では終端エラーとして扱い、積極的に再試行しないでください。
  • 重要な場合は、音声通話またはメールに切り替えます。
  • キャリアごとの失敗率を追跡し、番号検証/HLR の利用を検討します(合法かつ利用可能な場合)。
5) Webhook 署名の検証失敗

ログに表示される症状:

  • Error: Twilio Request Validation Failed. Expected signature ...

根本原因:

  • Auth Token が間違っています(別のアカウント/サブアカウントのもの)。
  • URL が一致していません(http と https の違い、パスの欠落、プロキシによる書き換え)。
  • POST パラメーターを受信時と完全に同じ形で含めていません(順序/エンコードの問題)。

解決方法:

  • Twilio Console で設定した正確な公開 URL に対して検証していることを確認します。
  • フレームワークによってパラメーターが変更される場合は、検証用に生のボディを保持します。
  • 電話番号/メッセージングサービスを所有するアカウントを確認し、そのアカウントの Auth Token を使用します。
6) メッセージのステータスコールバックが実行されない

症状:

  • Console ではメッセージが配信済みと表示されますが、システムにはコールバックが届きません。
  • または Twilio Debugger に Webhook エラーが表示されます。

根本原因:

  • メッセージまたはメッセージングサービスに StatusCallback が設定されていません。
  • エンドポイントが 2xx 以外を返しています。Twilio は再試行した後、処理を断念します。
  • TLS/CA の問題、DNS の問題、ファイアウォールによるブロック。

解決方法:

  • メッセージごとに statusCallback を設定するか、メッセージングサービスのレベルで設定します。
  • エンドポイントが速やかに(5 秒未満で)200 を返し、非同期で処理するようにします。
  • Twilio Debugger とリクエストインスペクターを確認します。
7) Voice TwiML の取得エラー

症状:

  • 通話に失敗し、Twilio Debugger に次のエラーが表示されます:
    • 11200 HTTP retrieval failure
    • 11205 HTTP retrieval failure

根本原因:

  • TwiML URL に到達できない、応答が遅い、または 2xx 以外が返されます。
  • TLS チェーンが無効です。
  • リダイレクトが想定どおりに処理されていません。

解決方法:

  • TwiML エンドポイントに外部からアクセスでき、数秒以内に応答することを確認します。
  • 正しい Content-Type: text/xml を指定して、有効な TwiML を返します。
  • 長時間の同期依存処理を避け、事前計算するかキャッシュします。
8) Verify:最大試行回数/ブロック

よくある症状:

  • HTTP 429、または試行回数が多すぎることを示す Verify エラー。
  • ユーザーからコードが届かないという報告があります。

根本原因:

  • ユーザーごとの送信/確認回数が多すぎます。
  • 不審なパターンに対して不正利用対策のガードがブロックしています。
  • キャリアによるフィルタリング。

解決方法:

  • アプリでクールダウンと試行回数の上限を設定します。
  • 代替チャネル(音声通話/メール/TOTP)を使用します。
  • Verify イベントを監視してポリシーを調整し、テンプレートと送信者のレピュテーションを確認します。
9) SendGrid:403 Forbidden/無効な API キー

症状:

  • HTTP Error 403: Forbidden
  • またはレスポンスボディに permission denied, wrong scopes が含まれています。

根本原因:

  • API キーに Mail Send 権限がありません。
  • 失効したキーを使用しています。

解決方法:

  • Mail Send スコープを持つキーを作成します。
  • キーをローテーションし、シークレットストアを更新します。
10) Studio の実行を開始できない

症状:

  • executions エンドポイントの呼び出し時に HTTP 404/401 が発生します。

根本原因:

  • Flow SID(FW...)またはアカウントが間違っています。
  • 別のサブアカウントの API キーを使用しています。

対処方法:

  • Flow が認証情報と同じアカウント/サブアカウントに存在することを確認してください。
  • 正しいベース URL と認証情報を使用してください。

セキュリティの強化

認証情報の取り扱い
  • アプリケーション認証には、Auth Token より API Keys を優先してください。
  • シークレットマネージャーにシークレットを保管し、git にコミットしないでください。
  • API キーは少なくとも四半期ごとにローテーションし、漏えいの疑いがある場合は直ちにローテーションしてください。
  • 影響範囲を抑えるため、環境ごとに別のサブアカウントを使用してください。
Webhook エンドポイントの強化
  • すべての受信 Webhook(Messaging、Voice、Studio、SendGrid inbound parse)で Twilio 署名を検証してください。
  • HTTPS のみを許可し、HTTP から HTTPS にリダイレクトしてください。
  • 冪等性を実装してください:
    • Messaging:MessageSid をキーとして使用
    • Voice:CallSid とイベントタイプをキーとして使用
  • 速やかに 200 を返し、処理はキューに登録してください。
ネットワーク制御
  • 管理用エンドポイントへのアクセスを IP 許可リスト/VPN で制限してください。
  • SIP トランキングの場合:
    • IP ACL と強力な認証情報を使用してください。
    • サポートされている場合は TLS/SRTP を優先してください。
  • SendGrid inbound parse の場合:
    • 可能であれば送信元 IP を検証し、署名付きイベントも使用してください(SendGrid Event Webhook は署名検証をサポートしています)。
OS とランタイムの強化(CIS 準拠)
  • Linux:
    • 使用するディストリビューションの CIS Benchmarks(例:CIS Ubuntu Linux 22.04 LTS Benchmark)を適用してください。
    • Webhook サービスは root 以外のユーザーとして実行してください。
    • systemd の強化オプション(NoNewPrivileges=true、ProtectSystem=strict など)を使用してください。
  • Node/Python:
    • 依存関係のバージョンを固定し、ロックファイルを使用してください。
    • CI で SAST/DAST を有効にしてください。
    • 悪用を防ぐため、リクエストボディのサイズ制限を設定してください。
データの取り扱い
  • 電話番号を機微な個人データとして扱ってください。
  • 完全な E.164 番号のログ記録を最小限に抑え、可能な場合はマスキングしてください。
  • 録音/文字起こしデータの場合:
    • 保持ポリシーが法的要件に準拠していることを確認してください。
    • 録音 URL へのアクセスを制限してください。公開 URL を保存するのではなく、認証済み API 経由で取得することを推奨します。

パフォーマンスのチューニング

Messaging のスループットとレイテンシー
  • Messaging Services を使用し、次の機能を活用してください:
    • Geo-matching:リージョンをまたぐ通信事業者のペナルティを軽減し、到達率を向上させます。
    • Sticky sender:会話の継続性を高め、ユーザーの混乱を軽減します。
    • Sender pools:コンプライアンス要件とキャンペーンの上限の範囲内で、スループットを向上させます。

想定される効果(一般的な例):

  • 適切なローカル送信者を使用することで、配信レイテンシーのばらつきが減り、通信事業者によるフィルタリングの発生も減少します。
  • 単一の長いコードと比べて、持続可能なスループットが向上します。
Webhook の処理
  • Webhook の応答時間は p95 で < 200ms を目標にしてください。
  • キューにオフロードし、下流の依存先を同期的に呼び出さないでください。
  • コネクションプーリングと Keep-Alive を使用してください。

想定される効果:

  • Twilio の再試行と重複イベントが減り、急増時のシステム安定性が向上します。
レート制限への対応
  • 20429 / HTTP 429 に対して、ジッターを加えた指数バックオフを実装してください。
  • アカウントごと、および宛先のプレフィックスごとに同時実行数を制限してください。
  • 一括送信の場合は、バッチ処理とスケジュール設定を行ってください。

想定される効果:

  • キャンペーン中のエラー率が低下し、スループットがより安定します。
Voice TwiML エンドポイント
  • 可能な場合は静的な TwiML 応答をキャッシュしてください。
  • レイテンシーに敏感な通話フローではコールドスタートを避けてください。サーバーレスを使用する場合は、スケジュールされた ping で関数をウォーム状態に保ってください。

想定される効果:

  • 11200/11205 の取得失敗が減り、通話接続が速くなります。

高度なトピック

STOP/START コンプライアンスに関する注意点
  • マーケティングコンテンツを自動返信して STOP を「無効化」しようとしないでください。
  • Twilio が送信をブロックする場合でも、独自の抑止リストを維持してください。複数プロバイダーを利用する場合や将来移行する場合に必要です。
  • WhatsApp ではオプトインのルールが異なります。WhatsApp のテンプレートとセッションに関するルールに従ってください。
10DLC の運用上の実情
  • キャンペーンの登録は、スループットとフィルタリングに影響します。
  • メッセージの内容と申告したユースケースが一致しないと、キャリアによるフィルタリングが増加します。
  • メッセージテンプレートがキャンペーンの説明に沿っていることを確認し、定期的に監査してください。
マルチリージョンとエッジの選択
  • Twilio はリージョン/エッジに対応しています。インフラに近いエッジを選択すると、REST のレイテンシを低減できます。
  • リージョン/エッジの変更にコンプライアンス上の影響がないと決めつけないでください。データ所在地に関する要件を確認してください。
録音と文字起こしのコスト
  • すべての通話を録音すると高額になる場合があり、データ取り扱いに関する義務も増えます。
  • 選択的な録音を検討してください(一部のキューのみ、同意取得後のみなど)。
  • 文字起こしを行うとレイテンシが増加します。リアルタイム処理が必要な場合は、ストリーミングメディアを検討してください(より複雑になります)。
Webhook の再試行と重複
  • Twilio は、2xx 以外のレスポンスやタイムアウトが発生すると再試行します。
  • ネットワーク障害の状況によっては、2xx を返していても重複を受信することがあります。
  • 必ず冪等性を実装し、重複を排除してください。
サブアカウント分離に関する落とし穴
  • 電話番号とメッセージングサービスは、特定のアカウント/サブアカウントに属します。
  • Webhook の署名検証には、所有アカウントの Auth Token が使われます。
  • 複数のサブアカウントにまたがってリソースを混在させると、原因の分かりにくい 401/検証エラーにつながります。

使用例

1) メッセージングサービス + ステータスコールバック + 重複排除による本番 SMS(Node)

server.js(Express):

import express from "express";
import twilio from "twilio";
import crypto from "crypto";

const app = express();

// Twilio sends application/x-www-form-urlencoded by default
app.use(express.urlencoded({ extended: false }));

const {
  TWILIO_ACCOUNT_SID,
  TWILIO_API_KEY,
  TWILIO_API_SECRET,
  TWILIO_MESSAGING_SERVICE_SID,
  TWILIO_WEBHOOK_AUTH_TOKEN
} = process.env;

const client = twilio(TWILIO_API_KEY, TWILIO_API_SECRET, { accountSid: TWILIO_ACCOUNT_SID });

function validateTwilioSignature(req) {
  const signature = req.header("X-Twilio-Signature");
  const url = `https://${req.get("host")}${req.originalUrl}`;
  const params = req.body;

  const isValid = twilio.validateRequest(TWILIO_WEBHOOK_AUTH_TOKEN, signature, url, params);
  return isValid;
}

// naive in-memory dedupe for example; use Redis/DB in production
const seen = new Set();

app.post("/twilio/sms/status", (req, res) => {
  if (!validateTwilioSignature(req)) return res.status(403).send("invalid signature");

  const messageSid = req.body.MessageSid;
  const messageStatus = req.body.MessageStatus;

  const key = `${messageSid}:${messageStatus}`;
  if (seen.has(key)) return res.status(200).send("duplicate");
  seen.add(key);

  // enqueue to your queue here
  console.log({ messageSid, messageStatus, errorCode: req.body.ErrorCode, errorMessage: req.body.ErrorMessage });

  res.status(200).send("ok");
});

app.post("/send", async (req, res) => {
  const to = req.body.to;
  const body = req.body.body;

  const msg = await client.messages.create({
    messagingServiceSid: TWILIO_MESSAGING_SERVICE_SID,
    to,
    body,
    statusCallback: "https://api.example.com/twilio/sms/status"
  });

  res.json({ sid: msg.sid, status: msg.status });
});

app.listen(8080, () => console.log("listening on :8080"));

実行:

export TWILIO_ACCOUNT_SID="YOUR_ACCOUNT_SID"
export TWILIO_API_KEY="YOUR_API_KEY_SID"
export TWILIO_API_SECRET="supersecret_api_key_secret"
export TWILIO_MESSAGING_SERVICE_SID="YOUR_MG_SID"
export TWILIO_WEBHOOK_AUTH_TOKEN="your_auth_token_for_signature_validation"

node server.js
curl -sS -X POST http://localhost:8080/send -d 'to=+14155550199' -d 'body=hello from prod'
2) 受信 SMS の STOP 処理 + 配信抑止リスト(Python)

要点:

  • Twilio が STOP を自動処理する場合がありますが、配信抑止リストは引き続き管理してください。
  • 受信した Body は大文字と小文字を区別せずに扱い、前後の空白を削除してください。
from flask import Flask, request, abort
from twilio.request_validator import RequestValidator
import os

app = Flask(__name__)

validator = RequestValidator(os.environ["TWILIO_WEBHOOK_AUTH_TOKEN"])
suppressed = set()  # replace with DB table keyed by E.164

def valid(req):
    signature = req.headers.get("X-Twilio-Signature", "")
    url = "https://api.example.com" + req.path
    return validator.validate(url, req.form, signature)

@app.post("/twilio/sms/inbound")
def inbound_sms():
    if not valid(request):
        abort(403)

    from_ = request.form.get("From", "")
    body = (request.form.get("Body", "") or "").strip().upper()

    if body in {"STOP", "STOPALL", "UNSUBSCRIBE", "CANCEL", "END", "QUIT"}:
        suppressed.add(from_)
        return ("", 200)

    if body in {"START", "YES", "UNSTOP"}:
        suppressed.discard(from_)
        return ("", 200)

    # normal inbound processing
    return ("", 200)
3) Polly 音声 + ステートマシンによる音声 IVR(TwiML)

受信 Webhook は TwiML を返します:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say voice="Polly.Joanna">Welcome. Press 1 for sales. Press 2 for support.</Say>
  <Gather numDigits="1" action="/twilio/voice/menu" method="POST" timeout="5">
    <Say voice="Polly.Joanna">Make your selection now.</Say>
  </Gather>
  <Say voice="Polly.Joanna">No input received. Goodbye.</Say>
  <Hangup/>
</Response>

メニューハンドラーは、入力された数字に応じて TwiML を返します:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial>
    <Queue>support</Queue>
  </Dial>
</Response>

本番環境での注意点:

  • 常に有効な XML をすばやく返してください。
  • プロキシがパスを書き換える場合は、action に絶対 URL を使用してください。
  • 複数ステップの場合は、CallSid の状態を永続化してください。
4) フォールバックチャネル + レート制限による Verify V2

疑似フロー:

  1. SMS 認証を試みます。
  2. 429 または失敗が繰り返される場合は、音声通話またはメールを提示します。
  3. クールダウンを適用します。例:送信間隔は 60 秒、1 時間あたり最大 5 回。

SMS 認証を送信します(curl の例は前述)。429 を処理します:

resp="$(curl -sS -w "\n%{http_code}" -X POST \
  "https://verify.twilio.com/v2/Services/$TWILIO_VERIFY_SERVICE_SID/Verifications" \
  -u "$TWILIO_API_KEY:$TWILIO_API_SECRET" \
  --data-urlencode "To=+14155550199" \
  --data-urlencode "Channel=sms")"

body="$(echo "$resp" | head -n1)"
code="$(echo "$resp" | tail -n1)"

if [ "$code" = "429" ]; then
  echo "rate limited; offer voice/email fallback"
  exit 0
fi

echo "$body" | jq .
5) 動的テンプレートを使った SendGrid のトランザクションメール(Node)
import sgMail from "@sendgrid/mail";

sgMail.setApiKey(process.env.SENDGRID_API_KEY);

const msg = {
  to: "[email protected]",
  from: "[email protected]",
  templateId: "d-13b8f94f2f2c4c0f9a2d8b2d3b7a9c01",
  dynamicTemplateData: {
    incident_id: "INC-2026-021",
    service: "messaging-api",
    severity: "SEV2",
    started_at: "2026-02-21T18:42:00Z"
  }
};

const [resp] = await sgMail.send(msg);
console.log(resp.statusCode);

運用上の注意:

  • バウンス/スパム報告を監視し、適宜配信を抑止してください。
  • 専用 IP に移行する場合は、IP をウォームアップしてください。
6) A/B テスト用 Studio Flow トリガー

パラメーター experiment を指定してトリガーします:

curl -sS -X POST "https://studio.twilio.com/v2/Flows/FW0123456789abcdef0123456789abcdef/Executions" \
  -u "$TWILIO_API_KEY:$TWILIO_API_SECRET" \
  --data-urlencode "To=+14155550199" \
  --data-urlencode "From=+14155550100" \
  --data-urlencode "Parameters={\"experiment\":\"A\",\"user_id\":\"u_9f2c1\"}"

Studio で:

  • {{flow.data.experiment}} に Split ウィジェットを使用します。
  • HTTP Request ウィジェットを使って、結果をバックエンドに記録します。

クイックリファレンス

タスクコマンド/API主なフラグ/フィールド
CLI にログインtwilio loginn/a
アカウントを取得twilio api:core:accounts:fetch --sid AC...--sid
サブアカウントを作成twilio api:core:accounts:create--friendly-name
サブアカウントを閉鎖twilio api:core:accounts:update--sid、--status closed
API キーを一覧表示twilio api:core:keys:list--limit
API キーを作成twilio api:core:keys:create--friendly-name、--key-type
API キーを取り消しtwilio api:core:keys:remove--sid
SMS を送信(From)twilio api:core:messages:create--from、--to、--body、--status-callback
SMS を送信(MG)twilio api:core:messages:create--messaging-service-sid、--to、--body
メッセージを取得twilio api:core:messages:fetch--sid SM...
電話番号の Webhook を設定twilio api:core:incoming-phone-numbers:update--sms-url、--voice-url、メソッド
発信通話を作成twilio api:core:calls:create--from、--to、--url、コールバック
Verify を送信POST /v2/Services/{VA}/VerificationsTo、Channel
Verify を確認POST /v2/Services/{VA}/VerificationCheckTo、Code
Studio をトリガーPOST /v2/Flows/{FW}/ExecutionsTo、From、Parameters

グラフの関係性

DEPENDS_ON

  • http(Webhook、REST API)
  • tls(HTTPS エンドポイント、証明書の検証)
  • secrets-management(Vault/KMS/Secrets Manager)
  • dns(Webhook の到達性)
  • queueing(Webhook 処理用の Kafka/SQS/PubSub)

COMPOSES

  • kubernetes(Webhook サービスのデプロイ、シークレットの管理、自動スケーリング)
  • terraform(可能な場合は Twilio リソースを管理し、それ以外の場合は設定とシークレットを管理)
  • observability(構造化ログ、トレーシング、20429/30003 などのエラーコードに関するアラート)
  • incident-response(認証情報のローテーション、Webhook の障害、通信事業者のインシデントに関するランブック)

SIMILAR_TO

  • nexmo-vonage(メッセージング/音声 API、Webhook、コンプライアンス)
  • plivo(プログラム可能なコミュニケーション)
  • aws-sns(メッセージングの基本機能。コンプライアンスと機能セットは異なります)
  • sendgrid(メール配信。Twilio SendGrid コンポーネントと重複します)

コメント