When to use
Use this to build channel-portable message templates once and reuse them everywhere: a
single Content resource (ContentSid) renders as SMS text, an MMS media message, a WhatsApp
interactive template, or an RCS card/carousel depending on the destination channel. Use it
whenever you need approved WhatsApp templates, variable substitution ({{1}}, {{2}}), or
rich interactive content (quick replies, call-to-action buttons, list pickers, cards,
carousels, catalogs) that the send-time APIs reference by SID.
Not for: the act of delivering messages (see twilio-rcs-messaging for RCS/SMS sends and
twilio-whatsapp-messaging for WhatsApp sends); free-form one-off messages that never repeat
(just pass Body); voice prompts (see twilio-voice-twiml).
Method
- Choose a content type for the primary variant. Add channel-specific variants in the same
Content resource so one SID serves multiple channels.
- Author variables as
{{1}}, {{2}}, ... (or named). Provide sample values in variables
so approval reviewers and previews render correctly.
- Create the template: POST to the Content API. Capture the returned
sid (starts HX).
- Decision point: does the destination channel require approval? WhatsApp templates must be
approved by Meta before use; SMS and RCS do not require Content-level approval (RCS still
needs a verified RBM agent — see twilio-rcs-messaging).
- For WhatsApp, submit an ApprovalRequest with category (utility/marketing/authentication)
and name; poll approval status until
approved or rejected.
- Send by SID: pass
ContentSid plus ContentVariables (JSON map of index→value) to the
Messages API. Twilio substitutes variables and picks the right channel variant for the
destination.
- Decision point: variable count mismatch? Every
{{n}} in the body must have a key in
ContentVariables or the send errors; unused keys are ignored.
Example
# Create a quick-reply template with one variable.
curl -X POST https://content.twilio.com/v1/Content \
-u "$ACCOUNT_SID:$AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"friendly_name": "order_status_qr",
"language": "en",
"variables": {"1": "Ada"},
"types": {
"twilio/quick-reply": {
"body": "Hi {{1}}, your order shipped. Track it?",
"actions": [
{"id": "track", "title": "Track order"},
{"id": "help", "title": "Talk to support"}
]
},
"twilio/text": {"body": "Hi {{1}}, your order shipped."}
}
}'
# Send it later by SID with runtime variables.
client.messages.create(
messaging_service_sid="MGxxxx",
to="+15551234567",
content_sid="HXxxxx",
content_variables='{"1": "Ada"}',
)
Pitfalls
- WhatsApp approval is Meta-side and can be rejected for policy/formatting; marketing
templates face stricter review than utility. Fix and resubmit under a new ApprovalRequest.
ContentVariables must be a JSON string, not a nested object, when sent as form params.
- Variable indices are 1-based and must be contiguous as authored; a body with
{{2}} but no
{{1}} confuses substitution.
- A channel that lacks a matching variant falls back to
twilio/text if present; without a
text variant, sends to that channel fail. Always include a text variant for SMS reach.
- Editing an approved WhatsApp template can invalidate approval; create a new template for
substantive changes.
- Catalog/authentication types have channel-specific required fields; validate against the
content-type schema before POST.
Output format
A Content resource with sid (HX...), types map, and variables. WhatsApp
ApprovalRequests return a status: received/pending → approved or rejected with a
rejection reason. At send time the ContentSid + ContentVariables produce a rendered Message.
Reference
- Create:
POST https://content.twilio.com/v1/Content; list GET /v1/Content; fetch
GET /v1/Content/{Sid}; delete DELETE /v1/Content/{Sid}.
- WhatsApp approval:
POST https://content.twilio.com/v1/Content/{Sid}/ApprovalRequests/whatsapp;
fetch status GET /v1/Content/{Sid}/ApprovalRequests.
- Content types:
twilio/text, twilio/media, twilio/quick-reply,
twilio/call-to-action, twilio/list-picker, twilio/card, twilio/carousel,
twilio/catalog, whatsapp/card, whatsapp/authentication.
- Variables:
{{1}}-style placeholders substituted at send via ContentVariables (JSON).
- WhatsApp limits: quick-reply up to 3 buttons; call-to-action up to 2 buttons (1 URL +
1 phone); list-picker up to 10 items; body text limits per WhatsApp template policy.
- Content template creation/storage has no per-template fee; delivery bills at the
destination channel's message rate (WhatsApp conversation pricing, SMS segment, RCS RBM).
1---2name: twilio-content-template-builder3description: Author reusable Twilio Content API templates with typed content, variable placeholders, and channel approval, then send them by ContentSid across SMS, WhatsApp, and RCS.4---56## When to use78Use this to build channel-portable message templates once and reuse them everywhere: a9single Content resource (ContentSid) renders as SMS text, an MMS media message, a WhatsApp10interactive template, or an RCS card/carousel depending on the destination channel. Use it11whenever you need approved WhatsApp templates, variable substitution ({{1}}, {{2}}), or12rich interactive content (quick replies, call-to-action buttons, list pickers, cards,13carousels, catalogs) that the send-time APIs reference by SID.1415**Not for:** the act of delivering messages (see twilio-rcs-messaging for RCS/SMS sends and16twilio-whatsapp-messaging for WhatsApp sends); free-form one-off messages that never repeat17(just pass `Body`); voice prompts (see twilio-voice-twiml).1819## Method20211. Choose a content type for the primary variant. Add channel-specific variants in the same22 Content resource so one SID serves multiple channels.232. Author variables as `{{1}}`, `{{2}}`, ... (or named). Provide sample values in `variables`24 so approval reviewers and previews render correctly.253. Create the template: POST to the Content API. Capture the returned `sid` (starts `HX`).264. Decision point: does the destination channel require approval? WhatsApp templates must be27 approved by Meta before use; SMS and RCS do not require Content-level approval (RCS still28 needs a verified RBM agent — see twilio-rcs-messaging).295. For WhatsApp, submit an ApprovalRequest with category (utility/marketing/authentication)30 and name; poll approval status until `approved` or `rejected`.316. Send by SID: pass `ContentSid` plus `ContentVariables` (JSON map of index→value) to the32 Messages API. Twilio substitutes variables and picks the right channel variant for the33 destination.347. Decision point: variable count mismatch? Every `{{n}}` in the body must have a key in35 ContentVariables or the send errors; unused keys are ignored.3637## Example3839```bash40# Create a quick-reply template with one variable.41curl -X POST https://content.twilio.com/v1/Content \42 -u "$ACCOUNT_SID:$AUTH_TOKEN" \43 -H "Content-Type: application/json" \44 -d '{45 "friendly_name": "order_status_qr",46 "language": "en",47 "variables": {"1": "Ada"},48 "types": {49 "twilio/quick-reply": {50 "body": "Hi {{1}}, your order shipped. Track it?",51 "actions": [52 {"id": "track", "title": "Track order"},53 {"id": "help", "title": "Talk to support"}54 ]55 },56 "twilio/text": {"body": "Hi {{1}}, your order shipped."}57 }58 }'59```6061```python62# Send it later by SID with runtime variables.63client.messages.create(64 messaging_service_sid="MGxxxx",65 to="+15551234567",66 content_sid="HXxxxx",67 content_variables='{"1": "Ada"}',68)69```7071## Pitfalls7273- WhatsApp approval is Meta-side and can be rejected for policy/formatting; marketing74 templates face stricter review than utility. Fix and resubmit under a new ApprovalRequest.75- `ContentVariables` must be a JSON string, not a nested object, when sent as form params.76- Variable indices are 1-based and must be contiguous as authored; a body with `{{2}}` but no77 `{{1}}` confuses substitution.78- A channel that lacks a matching variant falls back to `twilio/text` if present; without a79 text variant, sends to that channel fail. Always include a text variant for SMS reach.80- Editing an approved WhatsApp template can invalidate approval; create a new template for81 substantive changes.82- Catalog/authentication types have channel-specific required fields; validate against the83 content-type schema before POST.8485## Output format8687A Content resource with `sid` (`HX...`), `types` map, and `variables`. WhatsApp88ApprovalRequests return a status: `received`/`pending` → `approved` or `rejected` with a89rejection reason. At send time the ContentSid + ContentVariables produce a rendered Message.9091## Reference9293- Create: `POST https://content.twilio.com/v1/Content`; list `GET /v1/Content`; fetch94 `GET /v1/Content/{Sid}`; delete `DELETE /v1/Content/{Sid}`.95- WhatsApp approval: `POST https://content.twilio.com/v1/Content/{Sid}/ApprovalRequests/whatsapp`;96 fetch status `GET /v1/Content/{Sid}/ApprovalRequests`.97- Content types: `twilio/text`, `twilio/media`, `twilio/quick-reply`,98 `twilio/call-to-action`, `twilio/list-picker`, `twilio/card`, `twilio/carousel`,99 `twilio/catalog`, `whatsapp/card`, `whatsapp/authentication`.100- Variables: `{{1}}`-style placeholders substituted at send via `ContentVariables` (JSON).101- WhatsApp limits: quick-reply up to 3 buttons; call-to-action up to 2 buttons (1 URL +102 1 phone); list-picker up to 10 items; body text limits per WhatsApp template policy.103- Content template creation/storage has no per-template fee; delivery bills at the104 destination channel's message rate (WhatsApp conversation pricing, SMS segment, RCS RBM).