Templates
List WhatsApp templates and send approved ones, including outside the 24-hour window.
A template is a pre-written WhatsApp message that Meta has reviewed and approved, with
numbered placeholders ({{1}}, {{2}}, …) for your values. It is the only kind of message you may
send a customer on the WhatsApp Cloud API outside the
24-hour window: use one to start a conversation
with someone who has never written to you, or to pick one back up after the customer has gone
quiet.
Templates are written and submitted for approval in the console (Templates), where you can see Meta's review status, rejection reasons and quality rating. The API reads them; it does not create them.
| Endpoint | Scope | |
|---|---|---|
GET /v2/templates | templates:read | Templates, filtered by connectionId, status, language, category |
GET /v2/templates/{id} | templates:read | One template |
Test keys may read templates; App-pinned keys may not.
The template object
{
"id": "6a0e2c4d-8f1b-4d3a-9e5c-7b9d1f3a5c7e",
"connectionId": "9b2f6c1e-3d4a-4e5b-8f70-1a2b3c4d5e6f",
"name": "appointment_reminder",
"language": "en_GB",
"category": "UTILITY",
"status": "approved",
"body": "Hi {{1}}, a reminder of your appointment on {{2}} at {{3}}.",
"components": [],
"variables": ["1", "2", "3"],
"rejectionReason": null,
"qualityRating": "GREEN",
"createdAt": "2026-09-30T12:00:00.000Z",
"updatedAt": "2026-10-01T08:15:00.000Z"
}status is draft, pending, approved, rejected, paused or disabled; only an approved
template can be sent. variables lists the placeholders a send must fill.
Send a template
Pass template to POST /v2/messages: the template's id, or its
name and language on that connection, and variables keyed by placeholder number:
{
"connectionId": "9b2f6c1e-3d4a-4e5b-8f70-1a2b3c4d5e6f",
"conversationId": "c41e7b2a-5d6f-4e8a-9b1c-3d5e7f9a1b2c",
"template": {
"name": "appointment_reminder",
"language": "en_GB",
"variables": { "1": "Layla", "2": "Tuesday 22 October", "3": "10:30" }
}
}Start a conversation with a template
Address the send with to (an E.164 phone number) or contactId instead of conversationId, and
the template opens the conversation:
{
"connectionId": "9b2f6c1e-3d4a-4e5b-8f70-1a2b3c4d5e6f",
"to": "+447700900123",
"template": {
"name": "appointment_reminder",
"language": "en_GB",
"variables": { "1": "Layla", "2": "Tuesday 22 October", "3": "10:30" }
}
}- A new number: Gauge creates the contact, its WhatsApp identity and the conversation, then sends the template.
- A known contact or number: Gauge uses that contact's conversation on this connection, reopening it if it was resolved, so the history stays in one place.
- The answer is
202withstatus: queued(or201withstatus: sentwhen delivery is immediate) and theconversationId. Watchmessage.status_updatedfor delivery. - Send an
Idempotency-Key: a retry with the same key answers the same message and sends nothing.
The connection's capabilities.startConversations is true when templates are enabled for your
workspace. Free text to someone who has no conversation answers 422 unsupported_channel_action
with reason outside_24h_window: WhatsApp allows only a template as the first message.
Errors
Every template check runs before anything is written, so a refused send never creates a contact or an empty conversation.
| Status | reason | When |
|---|---|---|
400 validation_failed | No template with that id, or that name, on this connection | |
422 unsupported_channel_action | template_language_not_found | The template exists but not in that language; details.languages lists the ones it has |
422 unsupported_channel_action | template_not_approved | The template is pending, rejected, paused, disabled or a draft |
422 unsupported_channel_action | template_variable_mismatch | variables is not exactly {{1}}..{{n}} of the template body; details.expected lists them |
422 unsupported_channel_action | templates_not_supported | The connection cannot send templates |
422 unsupported_channel_action | consent_opted_out | A marketing template to a contact who opted out of marketing (utility templates still send) |
Header parameters (an image, document or video header, or a header variable) and button parameters (a quick-reply payload or a URL suffix) are not supported over the API yet. Body variables are.
Meta may charge for template messages, depending on their category and the recipient's country. Gauge passes these fees through at cost.