Templates
List templates and send them to a phone number via the API.
List templates
Query parameters
| Param | Description |
|---|---|
status | Filter by status (APPROVED, PENDING, REJECTED) |
channel | business or personal |
Each template includes its status, rejection_reason, updated_at, the full WhatsApp components, and a ready-to-use summary β enough to show and send a template without parsing WhatsApp's format:
variable_count is how many values to pass in variables; send_requires lists any extra fields a send needs.
Send a template
Send an approved template to a phone number, with variable substitution. :id is the template's id from GET /api/v1/templates, or its name (e.g. /api/v1/templates/order_update/send). If a name exists in more than one language, also pass language (e.g. "en") or use the id.
Request body
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
to | string | β | Recipient phone number with country code |
variables | string[] | β | Values for {{1}}, {{2}}, etc. in order |
language | string | β | Only when sending by name and the template exists in several languages, e.g. "en" or "hi". |
contact_name | string | β | Sets/updates the recipient contact's name, used to resolve {{name}}. Omit to leave the existing name untouched. |
contact_company | string | β | Sets/updates the recipient contact's company, used to resolve {{company}}. Omit to leave untouched. |
custom_fields | object | β | Sets/updates custom field values on the recipient contact, used to resolve a matching {{field_key}} placeholder (e.g. {{bni_date}}). Keys must match the field_key values defined in your workspace's Custom Fields settings β not the field's display label. Merged into the contact's existing custom fields; omitted keys are left untouched. |
connection_id | string | β | Which number to send from (alias: from), from GET /api/v1/connections. Personal templates need a Personal number and Business templates a Business number. If omitted, a Personal template uses your API key's account (or the only connected one), and a Business template uses the number it was created on. |
header_url | string | β | Business templates with a photo, video or PDF header. Public URL of the file to show for this send. Omit to use the sample file saved with the template. |
header_filename | string | β | Business templates with a PDF header. The file name the customer sees. |
button_values | string[] | β | Business templates with a link button whose URL ends in {{1}} (e.g. https://example.com/track/{{1}}): the value for each such button, in order β e.g. ["order/1234"]. |
Business WhatsApp templates
Templates approved for Business WhatsApp (source: "meta" in GET /api/v1/templates) are sent from your Business number and can be sent at any time β unlike free-form messages, they aren't limited to the 24 hours after the customer's last message.
- Pass exactly one value in
variablesfor each{{1}},{{2}}β¦ in the template body. - For a template with a photo, video or PDF header, pass the file in
header_url(andheader_filenamefor a PDF) β for example a different invoice for each customer. - Buttons defined on the template are sent automatically.
- Each send is charged to your wallet at the template's category rate (marketing, utilityβ¦).
The response also includes "channel": "business" and the connection_id it was sent from.
Login / OTP (authentication) templates: pass the code as the first value in variables. It fills both the message and the Copy code (or one-tap) button β you don't send it twice.
Link button with a per-customer URL: if the template's button URL ends in {{1}} (for example https://example.com/track/{{1}}), pass the ending in button_values β one value per such button, in order:
The customer's button then opens https://example.com/track/order/1234. If a required value is missing, the API returns 400 naming the button.
Named and custom-field placeholders
A template body can contain named placeholders like {{name}}, {{company}}, {{address_as}}, and any workspace custom field by its field_key, e.g. {{bni_date}}. These resolve from the recipient's contact record. See Variables & Personalisation for the full placeholder syntax, including fallback text ({{bni_date|TBD}}).
To set a custom field's value as part of the same send β rather than requiring it to already be on the contact β pass it in custom_fields:
Example
Response
text is the fully resolved message as sent β useful for confirming your variables and custom fields resolved as expected while testing.
Create a template
Personal WhatsApp template
Ready to use immediately (no review). Supports a body and an optional media header.
Business WhatsApp template
Pass "channel": "business". The template is submitted to WhatsApp for approval and returns status PENDING; approval usually arrives within minutes to a few hours.
| Field | Description |
|---|---|
name | Lowercase letters, numbers and underscores |
body | The message. Use {{1}}, {{2}}β¦ for values filled at send time |
category | MARKETING (default), UTILITY or AUTHENTICATION |
language | e.g. en (default), hi |
variables | A sample for each {{n}}, for WhatsApp's review: [{ "name": "1", "sample": "Rahul" }] |
header_type | TEXT, IMAGE, VIDEO or DOCUMENT |
header_text / header_media_url | The header text, or a sample file for a media header |
footer_text | Small text at the bottom (max 60 characters) |
buttons | Up to 10: QUICK_REPLY, URL (max 2) or PHONE_NUMBER (max 1) β see below |
connection_id | Which Business number, if you have more than one |
Link button with a per-customer URL: end the button's url with {{1}} and give an example β you'll pass the actual ending with button_values when sending.
Login / OTP (authentication) template
WhatsApp writes the message itself β "<code> is your verification code." β with a Copy code button, so you don't pass a body, header, footer or buttons. Optional settings:
| Field | Description |
|---|---|
add_security_recommendation | Adds "For your security, do not share this code." Default true |
code_expiration_minutes | Adds "This code expires in N minutes." (1β90) |
otp_button_text | Button label, default Copy code |
Once approved, send it with POST /api/v1/templates/:id/send and "variables": ["482913"] β the code fills both the message and the Copy code button.