Template Definition
A template definition is the JSON document that describes a template's content. It is the required definition field of the Create Template (POST /v3/templates) and Update Template (PUT /v3/templates/{id}) requests. The dashboard template builder displays the same JSON via its View JSON action.
Top-level request fields use snake_case (submit_for_review); field names inside definition use camelCase (multiChannel, variableType).
Create template request
| Field | Type | Required | Description |
|---|---|---|---|
category | string | No | MARKETING, UTILITY, or AUTHENTICATION. Auto-detected from the template content when omitted |
language | string | No | Language code (for example, en_US). Auto-detected from the template content when omitted |
definition | object | Yes | The definition object |
creation_source | string | No | Source label for the template. Default: from-api |
submit_for_review | boolean | No | true submits the template for review immediately after creation. Default: false, which saves the template with status DRAFT |
Definition object
| Field | Type | Required | Description |
|---|---|---|---|
header | object | No | Header object |
body | object | Yes | Body object |
footer | object | No | Footer object |
buttons | array | No | Array of button objects |
definitionVersion | string | No | Version of the template definition format |
authenticationConfig | object | No | Authentication configuration, used only by AUTHENTICATION templates |
Channel support
| Component | SMS | RCS | |
|---|---|---|---|
| Header | Not supported | Native header | Prepended to message text |
| Body | Supported | Supported | Supported |
| Footer | Not supported | Native footer | Appended to message text |
| Buttons | Not supported | Interactive buttons | First four shown as suggestion chips |
Header object
| Field | Type | Required | Description |
|---|---|---|---|
type | string | No | Header type: text, image, video, or document |
template | string | Yes | Header text with optional variable placeholders. Maximum 60 characters |
variables | array | No | Variable objects used in the header. Maximum 1 |
Text headers must not contain newlines, emojis, or formatting markup (*, _, ~). AUTHENTICATION templates do not use headers; Sent excludes any header from them automatically.
Body object
The body carries channel-specific content. multiChannel applies to every channel unless a channel-specific override is present.
| Field | Type | Required | Description |
|---|---|---|---|
multiChannel | object | No | Body content used for all channels without an override |
sms | object | No | Body content that overrides multiChannel for SMS |
whatsapp | object | No | Body content that overrides multiChannel for WhatsApp |
rcs | object | No | Body content that overrides multiChannel for RCS |
Body content object
| Field | Type | Required | Description |
|---|---|---|---|
type | string | No | Body type: body |
template | string | Yes | Body text with variable placeholders. Maximum 1024 characters |
variables | array | No | Variable objects used in the body. IDs must be unique within the body |
Footer object
| Field | Type | Required | Description |
|---|---|---|---|
type | string | No | Footer type: text |
template | string | Yes | Footer text. Maximum 60 characters |
variables | array | No | Must be empty; footers cannot contain variables |
Footers must not contain variables, newlines, emojis, or formatting markup (*, _, ~).
Buttons array
A template holds a maximum of 10 buttons. Button IDs must be unique. Per-type limits: maximum 1 COPY_CODE, 1 PHONE_NUMBER, 2 URL, and 10 QUICK_REPLY buttons.
| Field | Type | Required | Description |
|---|---|---|---|
id | number | No | Button identifier (1-based index). Must be unique within the template |
type | string | Yes | QUICK_REPLY, URL, VOICE_CALL, PHONE_NUMBER, or COPY_CODE |
props | object | Yes | Type-specific button properties |
Button props object
| Field | Type | Applies to | Description |
|---|---|---|---|
text | string | All types | Button label. Maximum 25 characters |
quickReplyType | string | QUICK_REPLY | custom or pre-configured |
urlType | string | URL | static or dynamic |
url | string | URL | Destination URL. Maximum 2000 characters |
variables | array | URL (dynamic) | Exactly 1 variable object; its placeholder must appear at the end of url |
activeFor | number | VOICE_CALL | Integer greater than 0 |
countryCode | string | PHONE_NUMBER | Country code (for example, US) |
phoneNumber | string | PHONE_NUMBER | Phone number in international format |
offerCode | string | COPY_CODE | Code copied to the clipboard on tap |
otpType | string | AUTHENTICATION OTP buttons | COPY_CODE or ONE_TAP |
Variable object
Variables use a numbered placeholder syntax in template text: {{0:variable}} for text variables and {{4:link}} for links, where the number is the variable's id.
| Field | Type | Required | Description |
|---|---|---|---|
id | number | No | Sequential ID starting from 0, unique within its section |
name | string | Yes | Readable identifier for the variable (for example, orderNumber) |
type | string | Yes | variable, link, or media |
props | object | Yes | Variable properties |
Variable props object
| Field | Type | Applies to | Description |
|---|---|---|---|
variableType | string | variable | Required. text, link, image, or file |
sample | string | variable | Required. Example value shown in previews and used during review |
regex | string | variable | Optional validation pattern for the variable value |
url | string | link, media | Required. Full HTTP or HTTPS URL |
shortUrl | string | link | Optional shortened URL |
alt | string | link, media | Alternative text |
mediaType | string | media | Required. image, video, or document |
Authentication configuration
AUTHENTICATION templates accept an authenticationConfig object:
| Field | Type | Description |
|---|---|---|
addSecurityRecommendation | boolean | Adds the text "For your security, do not share this code." |
codeExpirationMinutes | number | 1–90. When set, adds the footer "This code expires in X minutes." |
An AUTHENTICATION body must declare exactly one text variable (the code) and must not contain links or emojis.
Content rules and limits
| Rule | Limit |
|---|---|
| Body length | 1024 characters per channel body |
| Header and footer length | 60 characters each |
| Header variables | 1 |
| Buttons per template | 10 |
| Button label length | 25 characters |
| Button URL length | 2000 characters |
| Variables in a dynamic URL button | Exactly 1, at the end of the URL |
Emojis in a MARKETING body | 10 |
Length limits are validated at save time against the stored text, with {{...}} placeholders unsubstituted. Counting is encoding-blind: each UTF-16 code unit counts as one character (the behavior of .NET's string.Length and JavaScript's String.prototype.length), so characters in the Basic Multilingual Plane count as 1 and most emoji count as 2. There is no post-substitution validation; a body within the limit can render into a longer message once variables expand. For how rendered length maps to SMS segments, see SMS Encoding & Message Length.
Body text must additionally satisfy these rules:
- Must not start or end with a newline, and must not contain more than two consecutive line breaks or more than four consecutive spaces.
- Must contain at least one letter before the first variable and after the last variable; variables cannot be adjacent without text between them.
- Word count must be at least (2 × variable count) + 1.
Template statuses
| Status | Meaning |
|---|---|
DRAFT | Created but not submitted. Editable and testable; cannot be sent on any channel |
PENDING | Submitted for review; awaiting a decision |
APPROVED | Approved; available for sending |
REJECTED | Declined by the reviewer. A rejected template must be revised and resubmitted before it can send |
PAUSED | Paused by Meta; sends against the template are blocked until it is reinstated |
Review routing depends on your account:
- With a connected WhatsApp Business Account, Meta reviews the template. A Meta
APPROVEDorPENDINGverdict applies to every channel (SMS, WhatsApp, and RCS); aREJECTEDverdict applies to the WhatsApp channel only. - Without a connected WhatsApp Business Account, Sent's compliance team reviews the template, and each channel is approved or rejected individually.
Approval is tracked per channel. A message sends on a channel only when the template is approved for that channel; sends against unapproved templates return status BLOCKED. Status changes are delivered as templates webhook events carrying the template ID, channel, status, and reason.
Example
A complete POST /v3/templates request body with a header, a multi-channel body using text variables and a dynamic link, a footer, and two buttons:
{
"category": "UTILITY",
"language": "en_US",
"submit_for_review": false,
"definition": {
"header": {
"type": "text",
"template": "Order {{0:variable}}: Delivery Update",
"variables": [
{
"id": 0,
"name": "orderNumber",
"type": "variable",
"props": {
"variableType": "text",
"sample": "12345"
}
}
]
},
"body": {
"multiChannel": {
"type": "body",
"template": "Hi {{0:variable}},\nYour Acme order {{1:variable}} has been shipped and is expected to arrive {{2:variable}} between {{3:variable}}.\nYou can track your package or update your delivery preferences at {{4:link}} before the driver arrives.",
"variables": [
{
"id": 0,
"name": "customerName",
"type": "variable",
"props": {
"variableType": "text",
"sample": "Lucas"
}
},
{
"id": 1,
"name": "orderNumber",
"type": "variable",
"props": {
"variableType": "text",
"sample": "#12345"
}
},
{
"id": 2,
"name": "arrivalDate",
"type": "variable",
"props": {
"variableType": "text",
"sample": "tomorrow (Oct 11)"
}
},
{
"id": 3,
"name": "arrivalTime",
"type": "variable",
"props": {
"variableType": "text",
"sample": "2 PM – 4 PM"
}
},
{
"id": 4,
"name": "orderLink",
"type": "link",
"props": {
"url": "https://example.com",
"shortUrl": "",
"alt": "Tracking Page"
}
}
]
}
},
"footer": {
"type": "text",
"template": "Thank you for shopping with Acme.",
"variables": []
},
"buttons": [
{
"id": 1,
"type": "URL",
"props": {
"text": "Track your order",
"urlType": "static",
"url": "https://www.example.com/track"
}
},
{
"id": 2,
"type": "PHONE_NUMBER",
"props": {
"text": "Acme customer support",
"countryCode": "US",
"phoneNumber": "+112345678"
}
}
]
}
}The endpoint responds with the standard response envelope; the created template's fields are documented on the Create Template endpoint page.