twilio

Enable OpenClaw to operate Twilio “root” production workflows end-to-end: account and subaccount management, API keys and auth, console/billing/rate limits, and the operational patterns that sit on top (Messaging/Voice/Verify/SendGrid/Studio). This skill is for engineers who need to:

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "twilio" with this command: npx skills add alphaonedev/openclaw-graph/alphaonedev-openclaw-graph-twilio

twilio

Purpose

Enable OpenClaw to operate Twilio “root” production workflows end-to-end: account and subaccount management, API keys and auth, console/billing/rate limits, and the operational patterns that sit on top (Messaging/Voice/Verify/SendGrid/Studio). This skill is for engineers who need to:

  • Provision and rotate credentials safely (API Keys, Auth Tokens, SendGrid keys), including per-environment isolation.

  • Debug and remediate production incidents (webhook failures, carrier errors, rate limits, invalid numbers, auth errors).

  • Implement production-grade Messaging/Voice/Verify flows with correct compliance (STOP handling, 10DLC, toll-free verification).

  • Control cost and performance (messaging services with geo-matching, concurrency, retry/backoff, recording/transcription costs).

  • Automate Twilio operations via CLI + REST APIs + IaC patterns.

Prerequisites

Accounts and access

  • Twilio account with Console access: https://console.twilio.com/

  • For Messaging in US:

  • A2P 10DLC brand + campaign registration (required for most US long-code messaging).

  • Toll-free verification if using toll-free numbers for A2P.

  • Short code approval if using short codes.

  • For WhatsApp:

  • WhatsApp Business Account (WABA) and Twilio WhatsApp sender configured.

  • For Voice:

  • A Twilio phone number with Voice capability.

  • If using SIP trunking: Twilio Elastic SIP Trunking enabled.

  • For Verify:

  • Verify service created (Verify V2).

  • For SendGrid:

  • SendGrid account (can be separate from Twilio login), API key with appropriate scopes.

Local tooling (exact versions)

  • Node.js 20.11.1 (LTS) or 18.19.1 (LTS)

  • Python 3.11.8 or 3.12.2

  • curl 8.5.0+

  • jq 1.7+

  • OpenSSL 3.0.13+ (for signature verification tooling)

  • Docker 25.0.3+ (optional, for local webhook receivers and integration tests)

Twilio SDKs (recommended pinned versions)

  • Node: twilio 4.23.0

  • Python: twilio 9.0.5

  • SendGrid Node: @sendgrid/mail 8.1.1

  • SendGrid Python: sendgrid 6.11.0

Auth setup (Twilio)

Twilio supports:

  • Account SID (starts with AC... )

  • Auth Token (secret)

  • API Key SID (starts with SK... ) + API Key Secret (preferred over Auth Token for apps/CI)

  • Subaccounts (each has its own Account SID/Auth Token; API Keys can be created per account)

Minimum recommended production posture:

  • Use API Key + Secret in apps/CI.

  • Keep Auth Token only for break-glass and console use; rotate if exposed.

  • Separate subaccounts per environment (prod/stage/dev) and/or per tenant.

Twilio CLI (optional but strongly recommended)

Twilio CLI is useful for interactive operations; for automation prefer REST + IaC, but CLI is still valuable for incident response.

  • Twilio CLI: twilio-cli 5.17.0

  • Plugins:

  • @twilio-labs/plugin-serverless 3.0.2 (for Twilio Functions/Assets)

  • @twilio-labs/plugin-flex 6.0.6 (if using Flex)

Install via npm (see Installation & Setup).

Core Concepts

Accounts, subaccounts, projects

  • Account: top-level billing entity. Identified by AccountSid (AC... ).

  • Subaccount: child account with its own credentials, numbers, messaging services, etc. Useful for environment isolation and tenant isolation.

  • Project: Twilio Console UI grouping; not a separate security boundary. Don’t confuse with subaccounts.

Production pattern:

  • One parent account for billing.

  • Subaccounts per environment: prod , staging , dev .

  • Optionally subaccounts per customer/tenant if you need strict isolation and separate phone number pools.

Credentials

  • Auth Token: master secret for an account. High blast radius.

  • API Keys: scoped to an account; can be revoked without rotating Auth Token.

  • Key rotation: create new key, deploy, verify, revoke old key.

Messaging architecture

  • From can be:

  • A phone number (10DLC long code, toll-free, short code)

  • A Messaging Service SID (MG... ) which selects an appropriate sender (pooling, geo-match, sticky sender)

  • Status callbacks: message lifecycle events via webhook:

  • queued , sent , delivered , undelivered , failed (and sometimes read for channels that support it, e.g., WhatsApp)

  • STOP handling:

  • Twilio has built-in opt-out handling for many channels; you must not override it incorrectly.

  • Your app should treat STOP as a compliance event and suppress future sends to that recipient unless they opt back in (e.g., START).

Voice architecture

  • TwiML: XML instructions returned by your webhook to control calls.

  • <Dial> , <Conference> , <Record> , <Say> (with Polly voices), <Gather> for IVR.

  • Call status callbacks: webhooks for call events.

  • Recording: can be enabled per call or per conference; transcription is separate and has cost/latency.

  • SIP trunking: connect PBX/SBC to Twilio; requires careful auth and IP ACLs.

Verify V2

  • Verify Service (VA... ) defines channel configuration and policies.

  • Verify checks are rate-limited and fraud-protected; you must handle 429 and Verify-specific error codes.

  • Custom channels: email/push/TOTP can be integrated; treat as separate trust and deliverability domains.

SendGrid

  • Transactional vs marketing:

  • Transactional: API-driven, low latency, templated.

  • Marketing: campaigns, list management, compliance.

  • Dynamic templates use Handlebars.

  • Inbound Parse: webhook that turns inbound email into HTTP POST.

Studio

  • Studio Flows are state machines managed in Twilio.

  • REST Trigger API can start a flow execution.

  • Export/import flows for version control; A/B testing via Split widgets.

Rate limits and retries

  • Twilio enforces per-account and per-resource rate limits; you will see 20429 and HTTP 429 .

  • Webhooks are retried by Twilio on non-2xx responses; your endpoints must be idempotent.

Installation & Setup

Official Python SDK

Repository: https://github.com/twilio/twilio-python

PyPI: https://pypi.org/project/twilio/ · Supported: 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')

Source: twilio/twilio-python — client auth

Ubuntu 22.04 / 24.04 (x86_64)

Install dependencies:

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

Node.js 20.11.1 via NodeSource:

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 twilio-cli@5.17.0 twilio --version

Optional plugins:

twilio plugins:install @twilio-labs/plugin-serverless@3.0.2 twilio plugins:install @twilio-labs/plugin-flex@6.0.6 twilio plugins

Python 3.11 (if needed):

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 twilio-cli@5.17.0 twilio --version

macOS 14 (Sonoma) Intel

Homebrew:

brew update brew install node@20 jq openssl@3 python@3.12 brew link --force --overwrite node@20 node -v

Twilio CLI:

npm install -g twilio-cli@5.17.0 twilio --version

macOS 14 (Sonoma) Apple Silicon (ARM64)

Same as Intel; ensure correct PATH:

brew install node@20 jq openssl@3 python@3.12 echo 'export PATH="/opt/homebrew/opt/node@20/bin:$PATH"' >> ~/.zshrc source ~/.zshrc node -v npm install -g twilio-cli@5.17.0 twilio --version

Twilio CLI authentication

Interactive login (stores token in local config):

twilio login

Non-interactive (CI) using env vars (preferred):

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

If you must use Auth Token (not recommended for CI):

export TWILIO_AUTH_TOKEN="your_auth_token_here"

Verify auth:

twilio api:core:accounts:fetch --sid "$TWILIO_ACCOUNT_SID"

SDK installation (Node)

mkdir -p twilio-app && cd twilio-app npm init -y npm install twilio@4.23.0 npm install @sendgrid/mail@8.1.1

SDK installation (Python)

python3 -m venv .venv source .venv/bin/activate pip install --upgrade pip pip install twilio==9.0.5 sendgrid==6.11.0

Key Capabilities

Account management (root + subaccounts)

  • List accounts/subaccounts, create/close subaccounts.

  • Rotate API keys.

  • Fetch usage and billing signals (where available via API).

  • Enforce environment isolation via subaccounts.

Programmable Messaging (SMS/MMS/WhatsApp)

  • Send messages via From number or Messaging Service (MessagingServiceSid ).

  • Implement status callbacks and webhook verification.

  • Handle STOP/START opt-out correctly.

  • Support US compliance: 10DLC campaigns, toll-free verification, short codes.

  • Cost optimization: geo-matching, sticky sender, sender pools.

Voice (TwiML + SDK + SIP + IVR)

  • TwiML endpoints for inbound/outbound call control.

  • Conferences, recordings, transcription.

  • IVR state machines with <Gather> and server-side session state.

  • SIP trunking integration patterns and security.

Verify V2

  • Create Verify services, send verification codes, check codes.

  • Custom channels (email/push/TOTP) patterns.

  • Fraud guard and rate limiting handling.

SendGrid

  • Transactional email with dynamic templates.

  • Inbound Parse webhook ingestion.

  • Bounce/spam handling and suppression management.

  • IP warming and deliverability monitoring patterns.

Studio

  • Trigger flows via REST.

  • Export/import flows for version control.

  • Split-based A/B testing patterns.

Error handling and operational excellence

  • Map common Twilio error codes to remediation steps.

  • Implement webhook retry-safe endpoints.

  • Rate limit backoff and idempotency keys.

Command Reference

Notes:

  • Twilio CLI command groups can vary slightly by CLI version and installed plugins. The commands below are validated against twilio-cli@5.17.0 with default plugins.

  • For automation, prefer direct REST calls; CLI is best for interactive ops.

Global Twilio CLI flags

Applies to most twilio ... commands:

  • -h, --help : show help

  • -v, --version : show CLI version

  • -l, --log-level <level> : debug|info|warn|error

  • -o, --output <format> : json|tsv (varies by command)

  • --profile <name> : use a named profile from ~/.twilio-cli/config.json

Examples:

twilio -l debug api:core:accounts:fetch --sid "$TWILIO_ACCOUNT_SID" twilio --profile prod api:core:messages:list --limit 20 -o json

Auth and profiles

Login:

twilio login

List profiles:

twilio profiles:list

Use a profile:

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

Accounts (Core API)

Fetch account:

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

List accounts (includes subaccounts):

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

Flags:

  • --limit <n> : max records to return

  • --page-size <n> : page size for API pagination

  • --friendly-name <name> : filter by friendly name (where supported)

Create subaccount:

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

Update account status (close subaccount):

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

Flags:

  • --friendly-name <name>

  • --status <status> : active|suspended|closed

API Keys (Core API)

List API keys:

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

Create API key:

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

Flags:

  • --friendly-name <name>

  • --key-type <type> : standard|restricted (restricted requires additional configuration; prefer standard unless you have a clear policy model)

Fetch key:

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

Delete key (revoke):

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

Messaging (Core API)

Send SMS via From :

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"

Send via Messaging Service:

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

Important flags:

  • --from <E.164> : sender number

  • --to <E.164> : recipient

  • --body <text>

  • --media-url <url> : repeatable for MMS

  • --messaging-service-sid <MG...> : use messaging service instead of --from

  • --status-callback <url> : message status webhook

  • --max-price <decimal> : cap price (channel-dependent)

  • --provide-feedback <boolean> : request delivery feedback (where supported)

  • --validity-period <seconds> : TTL for message

  • --force-delivery <boolean> : attempt to force delivery (limited applicability)

  • --application-sid <AP...> : messaging application (legacy patterns)

  • --smart-encoded <boolean> : enable smart encoding

List messages:

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

Filter list:

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

Fetch message:

twilio api:core:messages:fetch --sid SM0123456789abcdef0123456789abcdef

Incoming phone numbers

List numbers:

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

Purchase a number (availability varies):

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"

Configure webhook URLs on a number:

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

Flags (commonly used):

  • --sms-url <url> , --sms-method <GET|POST>

  • --voice-url <url> , --voice-method <GET|POST>

  • --status-callback <url> (voice call status callback for the number, depending on resource)

  • --friendly-name <name>

Voice calls

Create outbound call:

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

Flags:

  • --from , --to

  • --url <twiml-webhook-url> : TwiML instructions endpoint

  • --method <GET|POST>

  • --status-callback <url>

  • --status-callback-event <initiated|ringing|answered|completed> (repeatable)

  • --status-callback-method <GET|POST>

  • --timeout <seconds>

  • --record <boolean>

  • --recording-status-callback <url>

  • --recording-status-callback-method <GET|POST>

Fetch call:

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

List calls:

twilio api:core:calls:list --from "+14155550100" --start-time 2026-02-21 --limit 50

Verify V2 (REST-first; CLI coverage varies)

Verify is often easiest via REST calls. Example with curl:

Send verification:

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"

Check verification:

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)

Trigger a Studio Flow execution:

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) via plugin

Initialize:

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

Deploy:

twilio serverless:deploy --environment production --force

Flags:

  • --environment <name> : environment in Twilio Serverless

  • --force : skip prompts

  • --service-name <name> : override service name

  • --functions-folder <path>

  • --assets-folder <path>

Configuration Reference

Twilio CLI config

Path:

  • macOS/Linux: ~/.twilio-cli/config.json

  • Windows (if applicable): %USERPROFILE%.twilio-cli\config.json

Example ~/.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" }

Notes:

  • Prefer apiKeySecret sourced from environment (ENV:... ) rather than plaintext.

  • region /edge can reduce latency; validate against your Twilio deployment.

Application environment variables

Recommended file:

  • /etc/twilio/twilio.env (Linux servers)

  • Or Kubernetes Secret + env injection

Example /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 request signature validation uses the Auth Token for the account that owns the webhook configuration.

  • If you use API Keys for REST calls, you may still need the Auth Token for webhook signature validation. Store it separately and restrict access.

NGINX reverse proxy (webhook endpoints)

Path:

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

Example:

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 service (Linux)

Path:

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

Example:

[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

Integration Patterns

Compose with secrets management (Vault / AWS / GCP)

Pattern:

  • Store TWILIO_API_SECRET , TWILIO_WEBHOOK_AUTH_TOKEN , SENDGRID_API_KEY in a secret manager.

  • Inject into runtime as environment variables.

  • Rotate keys quarterly or on incident.

Example: Kubernetes External Secrets (AWS Secrets Manager) snippet:

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 pipeline: key rotation + smoke test

Pipeline steps:

  • Create new API key in Twilio (manual approval or automated with Auth Token in a locked job).

  • Update secret store.

  • Deploy.

  • Smoke test: send SMS to test device; verify status callback received.

  • Revoke old key.

Smoke test example (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 });

Event-driven status processing (webhooks → queue → worker)

Pattern:

  • Twilio status callbacks hit /twilio/sms/status .

  • Endpoint validates signature, normalizes payload, enqueues to Kafka/SQS/PubSub.

  • Worker updates message state machine in DB; idempotent by MessageSid .

Benefits:

  • Avoids webhook timeouts.

  • Handles retries safely.

  • Centralizes carrier error analytics.

IVR state machine (Voice webhooks + persisted session)

Pattern:

  • Use <Gather> with action pointing to your app.

  • Persist state keyed by CallSid .

  • Ensure idempotency: Twilio may retry webhook if your endpoint times out.

Studio + backend orchestration

Pattern:

  • Studio handles conversational branching and channel selection.

  • Backend triggers Studio Flow with parameters and receives callbacks.

  • Use Split widget for A/B tests; store experiment parameter in your DB.

Error Handling & Troubleshooting

  1. Error 21211 (invalid To number)

Symptom (Twilio API response):

  • Code: 21211

  • Message: The 'To' number +1415555 is not a valid phone number.

Root causes:

  • Not E.164 formatted.

  • Missing country code.

  • Contains non-digits/spaces not allowed.

Fix:

  • Normalize to E.164 (+14155550199 ).

  • Validate with libphonenumber before calling Twilio.

  • For WhatsApp, ensure whatsapp:+E164 .

  1. Error 20003 (authentication)

Symptom:

  • Code: 20003

  • Message: Authenticate

Or HTTP 401 with:

  • HTTP 401 Unauthorized

Root causes:

  • Wrong API key/secret.

  • Using API Key SID with Auth Token instead of API Key Secret.

  • Account SID mismatch when using API key auth (must pass accountSid in SDK client options).

Fix:

  • Verify credentials in secret store.

  • For Node SDK: twilio(apiKey, apiSecret, { accountSid }) .

  • Confirm key belongs to the same account/subaccount you’re targeting.

  1. Error 20429 (rate limit)

Symptom:

  • Code: 20429

  • Message: Too Many Requests

Or HTTP 429.

Root causes:

  • Burst sending beyond account/number/channel limits.

  • Verify checks too frequent.

  • Studio triggers too frequent.

Fix:

  • Implement exponential backoff with jitter.

  • Add client-side rate limiting (token bucket) per account and per destination.

  • Use Messaging Services with proper throughput configuration (10DLC/short code).

  • For Verify: enforce per-user cooldown and max attempts.

  1. Error 30003 (unreachable / carrier violation)

Symptom:

  • Code: 30003

  • Message: Unreachable destination handset

Root causes:

  • Carrier rejected (inactive number, roaming restrictions, blocked).

  • Destination cannot receive SMS.

Fix:

  • Treat as terminal for that attempt; do not retry aggressively.

  • If critical, fall back to Voice or email.

  • Track per-carrier failure rates; consider number validation/HLR (where legal/available).

  1. Webhook signature validation failures

Symptom in your logs:

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

Root causes:

  • Using wrong Auth Token (wrong account/subaccount).

  • URL mismatch (http vs https, missing path, proxy rewriting).

  • Not including POST params exactly as received (order/encoding issues).

Fix:

  • Ensure you validate against the exact public URL configured in Twilio Console.

  • Preserve raw body for validation if your framework mutates params.

  • Confirm which account owns the phone number / messaging service; use that Auth Token.

  1. Messaging status callback not firing

Symptoms:

  • Message shows delivered in Console but your system never receives callback.

  • Or Twilio Debugger shows webhook errors.

Root causes:

  • StatusCallback not set on message or messaging service.

  • Endpoint returns non-2xx; Twilio retries then gives up.

  • TLS/CA issues, DNS issues, firewall blocks.

Fix:

  • Set statusCallback per message or configure at Messaging Service level.

  • Ensure endpoint returns 200 quickly (< 5s) and processes async.

  • Check Twilio Debugger and request inspector.

  1. Voice TwiML fetch errors

Symptom:

  • Call fails; Twilio Debugger shows:

  • 11200 HTTP retrieval failure

  • 11205 HTTP retrieval failure

Root causes:

  • TwiML URL unreachable, slow, or returns non-2xx.

  • Invalid TLS chain.

  • Redirects not handled as expected.

Fix:

  • Ensure TwiML endpoint is publicly reachable and responds within a few seconds.

  • Return valid TwiML with correct Content-Type: text/xml .

  • Avoid long synchronous dependencies; precompute or cache.

  1. Verify: max attempts / blocked

Common symptoms:

  • HTTP 429 or Verify error indicating too many attempts.

  • Users report never receiving codes.

Root causes:

  • Too many sends/checks per user.

  • Fraud guard blocking suspicious patterns.

  • Carrier filtering.

Fix:

  • Enforce cooldown and attempt limits in your app.

  • Use alternative channels (voice/email/TOTP).

  • Monitor Verify events and adjust policies; ensure templates and sender reputation.

  1. SendGrid: 403 Forbidden / invalid API key

Symptom:

  • HTTP Error 403: Forbidden

  • Or response body includes permission denied, wrong scopes

Root causes:

  • API key missing Mail Send permission.

  • Using a revoked key.

Fix:

  • Create a key with Mail Send scope.

  • Rotate and update secret store.

  1. Studio execution fails to start

Symptom:

  • HTTP 404/401 when calling executions endpoint.

Root causes:

  • Wrong Flow SID (FW... ) or wrong account.

  • Using API key from a different subaccount.

Fix:

  • Confirm Flow exists in the same account/subaccount as credentials.

  • Use correct base URL and auth.

Security Hardening

Credential handling

  • Prefer API Keys over Auth Tokens for application auth.

  • Store secrets in a secret manager; never commit to git.

  • Rotate API keys at least quarterly; immediately on suspected exposure.

  • Use separate subaccounts per environment to reduce blast radius.

Webhook endpoint hardening

  • Validate Twilio signatures on all inbound webhooks (Messaging, Voice, Studio, SendGrid inbound parse).

  • Enforce HTTPS only; redirect HTTP to HTTPS.

  • Implement idempotency:

  • Messaging: key by MessageSid

  • Voice: key by CallSid

  • event type
  • Return 200 quickly; enqueue work.

Network controls

  • Restrict admin endpoints by IP allowlist/VPN.

  • For SIP trunking:

  • Use IP ACLs and strong credentials.

  • Prefer TLS/SRTP where supported.

  • For SendGrid inbound parse:

  • Validate source IPs where feasible and/or use signed events (SendGrid Event Webhook supports signature verification).

OS and runtime hardening (CIS-aligned)

  • Linux:

  • Apply CIS Benchmarks for your distro (e.g., CIS Ubuntu Linux 22.04 LTS Benchmark).

  • Run webhook services as non-root.

  • Use systemd hardening options (NoNewPrivileges=true , ProtectSystem=strict , etc.).

  • Node/Python:

  • Pin dependencies; use lockfiles.

  • Enable SAST/DAST in CI.

  • Set request body size limits to prevent abuse.

Data handling

  • Treat phone numbers as sensitive personal data.

  • Minimize logging of full E.164 numbers; mask where possible.

  • For recordings/transcriptions:

  • Ensure retention policies align with legal requirements.

  • Restrict access to recording URLs; prefer fetching via authenticated API rather than storing public URLs.

Performance Tuning

Messaging throughput and latency

  • Use Messaging Services with:

  • Geo-matching: reduces cross-region carrier penalties and improves deliverability.

  • Sticky sender: improves conversation continuity and reduces user confusion.

  • Sender pools: increases throughput (subject to compliance and campaign limits).

Expected impact (typical):

  • Reduced delivery latency variance and fewer carrier filtering events when using appropriate local senders.

  • Higher sustainable throughput vs single long code.

Webhook processing

  • Target p95 webhook response time < 200ms.

  • Offload to queue; do not call downstream dependencies synchronously.

  • Use connection pooling and keep-alives.

Expected impact:

  • Fewer Twilio retries, fewer duplicate events, improved system stability during spikes.

Rate limit handling

  • Implement exponential backoff with jitter for 20429 / HTTP 429.

  • Use concurrency limits per account and per destination prefix.

  • For bulk sends, batch and schedule.

Expected impact:

  • Reduced error rates during campaigns; smoother throughput.

Voice TwiML endpoints

  • Cache static TwiML responses where possible.

  • Avoid cold starts (serverless) for latency-sensitive call flows; if using serverless, keep functions warm via scheduled pings.

Expected impact:

  • Fewer 11200/11205 retrieval failures; faster call connect.

Advanced Topics

STOP/START compliance gotchas

  • Do not attempt to “override” STOP by auto-responding with marketing content.

  • Maintain your own suppression list even if Twilio blocks sends; you need suppression for multi-provider or future migrations.

  • For WhatsApp, opt-in rules differ; ensure you follow WhatsApp template and session rules.

10DLC operational realities

  • Campaign registration affects throughput and filtering.

  • Mismatched message content vs declared use case increases carrier filtering.

  • Ensure message templates align with campaign description; audit periodically.

Multi-region and edge selection

  • Twilio supports regions/edges; selecting an edge closer to your infra can reduce REST latency.

  • Do not assume region/edge changes are free of compliance implications; validate data residency requirements.

Recording and transcription costs

  • Recording every call can be expensive and increases data handling obligations.

  • Consider selective recording (only certain queues, only after consent).

  • Transcription adds latency; if you need real-time, consider streaming media (more complex).

Webhook retries and duplicates

  • Twilio retries on non-2xx and timeouts.

  • You will receive duplicates even with 2xx in some network failure modes.

  • Always implement idempotency and dedupe.

Subaccount isolation pitfalls

  • Phone numbers and messaging services are owned by a specific account/subaccount.

  • Webhook signature validation uses the Auth Token of the owning account.

  • Mixing resources across subaccounts leads to confusing 401/validation failures.

Usage Examples

  1. Production SMS with Messaging Service + status callbacks + dedupe (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"));

Run:

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'

  1. Inbound SMS STOP handling + suppression list (Python)

Key points:

  • Twilio may handle STOP automatically, but you still maintain suppression.

  • Treat inbound Body case-insensitively and trim.

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) Voice IVR with Polly voice + state machine (TwiML)

Inbound webhook returns 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>

Menu handler returns TwiML based on digit:

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

Production gotchas:

  • Always return valid XML quickly.

  • Use absolute URLs in action if behind proxies that rewrite paths.

  • Persist CallSid state if multi-step.

  1. Verify V2 with fallback channels + rate limiting

Pseudo-flow:

  • Attempt SMS verify.

  • If 429 or repeated failures, offer voice call or email.

  • Enforce cooldown: e.g., 60 seconds between sends, max 5 per hour.

Send SMS verify (curl shown earlier). Handle 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 .

  1. SendGrid transactional email with dynamic template (Node)

import sgMail from "@sendgrid/mail";

sgMail.setApiKey(process.env.SENDGRID_API_KEY);

const msg = { to: "oncall@example.com", from: "noreply@example.com", 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);

Operational notes:

  • Monitor bounces/spam reports; suppress accordingly.

  • Warm IPs if moving to dedicated IPs.

  1. Studio Flow trigger for A/B test

Trigger with parameter 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"}"

In Studio:

  • Use Split widget on {{flow.data.experiment}} .

  • Log outcomes to your backend via HTTP Request widget.

Quick Reference

Task Command / API Key flags / fields

Login CLI twilio login

n/a

Fetch account twilio api:core:accounts:fetch --sid AC...

--sid

Create subaccount twilio api:core:accounts:create

--friendly-name

Close subaccount twilio api:core:accounts:update

--sid , --status closed

List API keys twilio api:core:keys:list

--limit

Create API key twilio api:core:keys:create

--friendly-name , --key-type

Revoke API key twilio api:core:keys:remove

--sid

Send SMS (From) twilio api:core:messages:create

--from , --to , --body , --status-callback

Send SMS (MG) twilio api:core:messages:create

--messaging-service-sid , --to , --body

Fetch message twilio api:core:messages:fetch

--sid SM...

Configure number webhooks twilio api:core:incoming-phone-numbers:update

--sms-url , --voice-url , methods

Create outbound call twilio api:core:calls:create

--from , --to , --url , callbacks

Verify send POST /v2/Services/{VA}/Verifications

To , Channel

Verify check POST /v2/Services/{VA}/VerificationCheck

To , Code

Trigger Studio POST /v2/Flows/{FW}/Executions

To , From , Parameters

Graph Relationships

DEPENDS_ON

  • http (webhooks, REST APIs)

  • tls (HTTPS endpoints, certificate validation)

  • secrets-management (Vault/KMS/Secrets Manager)

  • dns (webhook reachability)

  • queueing (Kafka/SQS/PubSub for webhook processing)

COMPOSES

  • kubernetes (deploy webhook services, manage secrets, autoscaling)

  • terraform (manage Twilio resources where feasible; otherwise manage config + secrets)

  • observability (structured logs, tracing, alerting on error codes like 20429/30003)

  • incident-response (runbooks for auth rotation, webhook failures, carrier incidents)

SIMILAR_TO

  • nexmo-vonage (messaging/voice APIs, webhooks, compliance)

  • plivo (programmable communications)

  • aws-sns (messaging primitives; different compliance and feature set)

  • sendgrid (email delivery; overlaps with Twilio SendGrid component)

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

playwright-scraper

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

clawflows

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

tavily-web-search

No summary provided by upstream source.

Repository SourceNeeds Review