Templates API - V2
Looking to manage templates (create, update, delete)? See the Template Management API.
WhatsApp allows you to send pre-approved message templates to users without them having to interact with your WhatsApp Business number first.
Overview
- Your template must be approved by WhatsApp before you can use it. Our team can help you with this.
- Each template must be categorised as either
MARKETING,UTILITYorAUTHENTICATION. - Templates can include:
- parameters for personalisation (e.g. name, order number or anything else)
- a text, image, video, document or location header
- up to three buttons (Quick Reply, Link or Call)
- a carousel of cards, each with its own media header, body text, and buttons
See the authentication page for how to obtain a bearer token.
Send a Template Message
V2 uses a flat, intuitive structure with body_variables as an ordered list of values, header as a single object, and typed buttons[]/cards[] arrays.
POST https://api.cuedesk.com/v2/messages/whatsapp
Authorization: Bearer <token>
Content-Type: application/json
Examples
- Basic
- Media Header
- Document Header
- Buttons
- Authentication (OTP)
- Carousel
{
"to": "447592850122",
"from": "447576209857",
"client_reference": "order-confirmation-123",
"template": {
"name": "order_confirmation",
"locale": "en",
"body_variables": ["Alex", "ORD-12345", "25 Jan 2025"]
}
}
{
"to": "447592850122",
"from": "447576209857",
"template": {
"name": "shipping_update",
"locale": "en",
"header": {
"type": "image",
"link": "https://www.example.com/tracking-map.jpg"
},
"body_variables": ["Alex", "ORD-12345", "Wed 26 July"]
}
}
{
"to": "447592850122",
"from": "447576209857",
"template": {
"name": "invoice_template",
"locale": "en",
"header": {
"type": "document",
"link": "https://www.example.com/invoices/INV-001.pdf",
"filename": "Invoice-001.pdf"
},
"body_variables": ["Alex", "INV-001", "$150.00"]
}
}
{
"to": "447592850122",
"from": "447576209857",
"template": {
"name": "delivery_update",
"locale": "en",
"body_variables": ["Alex", "ORD-12345"],
"buttons": [
{
"index": 0,
"type": "URL",
"url": "ORD-12345"
},
{
"index": 1,
"type": "QUICK_REPLY",
"title": "Confirm"
}
]
}
}
{
"to": "447592850122",
"from": "447576209857",
"template": {
"name": "otp_verification",
"locale": "en",
"body_variables": ["123456"],
"buttons": [
{
"index": 0,
"type": "OTP",
"otp_code": "123456"
}
]
}
}
{
"to": "447592850122",
"from": "447576209857",
"template": {
"name": "product_showcase",
"locale": "en",
"body_variables": ["Alex"],
"cards": [
{
"index": 0,
"header": {
"type": "image",
"link": "https://example.com/product1.jpg"
},
"body_variables": ["Running Shoes", "$99.00"],
"buttons": [
{
"index": 0,
"type": "URL",
"url": "running-shoes-123"
}
]
},
{
"index": 1,
"header": {
"type": "image",
"link": "https://example.com/product2.jpg"
},
"body_variables": ["Casual Sneakers", "$79.00"],
"buttons": [
{
"index": 0,
"type": "URL",
"url": "casual-sneakers-456"
}
]
}
]
}
}
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
to | string | Yes | Recipient WhatsApp number with country code (no leading +) |
from | string | Yes | Your WhatsApp Business number (channel identifier) |
client_reference | string | No | Custom reference ID returned in webhook status updates (max 255 chars) |
template | object | Yes | Template definition (see below) |
Template Object
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Name of the approved WhatsApp template |
locale | string | Yes | Language code (e.g. en, pt_BR) |
header | object | No | Header media or text |
body_variables | array[string] | No | Ordered values for body placeholders. Position 0 replaces {{1}}, position 1 replaces {{2}}, etc. |
buttons | array | No | Button parameters |
cards | array | No | Card definitions for carousel templates |
Header
| Field | Type | Required | Description |
|---|---|---|---|
type | string | No | Media type: image, video, document |
link | string | No | URL of the media file |
filename | string | No | Display filename for document type headers |
You cannot override your template's header with a different media type. If the template has an image header, only provide an image URL.
Buttons
| Field | Type | Required | Description |
|---|---|---|---|
index | integer | Yes | Zero-based position of the button in the template |
type | string | Yes | Button type: URL, QUICK_REPLY, or OTP |
title | string | No | Quick-reply button payload text. Required for QUICK_REPLY |
url | string | No | Dynamic URL suffix. Required for URL type |
otp_code | string | No | One-time password code. Required for OTP type |
Cards
| Field | Type | Required | Description |
|---|---|---|---|
index | integer | Yes | Zero-based position of the card |
header | object | No | Card media header (same structure as above) |
body_variables | array[string] | No | Ordered values for this card's body placeholders |
buttons | array | No | Card button parameters (same structure as above) |
You can include both top-level body_variables (for the template greeting above the carousel) and per-card body_variables in the same request. Top-level header is not supported on carousel templates — headers are defined per card only.
Response
202 Accepted
{
"id": "msg-a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
| Field | Type | Description |
|---|---|---|
id | string | Unique message identifier. Use to correlate with webhook status updates |
Error Responses
400 Bad Request:
{
"message": "Template 'order_confirmation' not found or not approved for locale 'en'"
}
403 Forbidden:
{
"detail": "Could not send message. Invalid channel."
}
429 Too Many Requests — Channel rate limit exceeded. Retry after a brief delay.