Skip to main content

Discover the template

Templates are listed as Meta holds them, with the placeholders each one expects, so your code can discover what to send without opening WhatsApp Manager. The list is cached for five minutes.
id is Meta’s id of that language of the template: GET /v1/whatsapp/templates/{template_id} reads it in full. managed is false for a key you create.

Send

Every placeholder the template declares is required, extra keys are refused, and values are strings of 1 to 1024 characters without newlines or control characters. Give lang when the template exists in more than one language.
The answer is 202 Accepted. Meta has taken the message; the status arrives afterwards.
Send an Idempotency-Key per business event and retry a 502 or a network error with the same key. A replay returns the original 202 with Idempotent-Replayed: true and sends nothing. See Reliability and limits.

Text headers

A template whose text header has a placeholder lists it under placeholders.header:
Its value goes in header.text, not in params. A header has one placeholder at most, and its value follows the same rules as a body value: 1 to 1024 characters, no newline.
A header for a template without a header placeholder answers 422 invalid_params, and so does a missing one for a template that has it.

Image headers

A template can open with an image (its header is an image Meta reviewed with the template). Each message carries its own: give the image’s public link in header.image.link. Meta fetches it when it sends, so it must answer at once with a JPG or a PNG of at most 5 MB.
The link must be https, at most 2048 characters, without spaces. A template that opens with an image and a send without header.image.link answers 422 invalid_params (`header.image.link` is required: this template opens with an image); an image for a template that does not open with one answers 422 invalid_params too. The field is optional for every other template, so existing integrations are unchanged.

Document headers

A template can open with a document, a PDF attachment: an invoice, a contract, an attendance sheet, a ticket (see Send a PDF attachment). Each message carries its own file: give its link in header.document.link and, optionally, the name the customer sees in header.document.filename. Meta downloads the file from the link when it sends, so the link must open without a sign-in at that moment; for a file that holds personal data, a signed link that lives a few minutes is enough.
A template that opens with a document and a send without header.document.link answers 422 invalid_params, and so does a link that is not https or is too long, a document for a template that does not open with one, or an image for a template that opens with a document. A header of another shape (document that is not an object, a link that is not a string, extra keys, text beside document) answers 400 invalid_request. The message is charged and recorded like any other send, with the link and the file name it carried. The whole flow, from the template to the send, is in Send a PDF attachment. Video and location headers are not sent yet: such a template answers 422 unsupported_template with message media_header. A named placeholder is at most 20 characters at send time: Meta approves a template with a longer name, such as {{subscription_start_date}}, then refuses every message from it. Such a template answers 422 unsupported_template with message long_placeholder_name, and nothing is sent or charged. Rename the placeholder ({{start_date}}) in a new template or an edit.

Marketing and opt-outs

A customer who turns off your offers inside WhatsApp is opted out the first time Meta refuses a marketing message to them (Meta’s error 131050). From then on a template whose category is MARKETING to that number answers 422 consent_opted_out, and nothing is sent or charged. Utility and authentication templates still go: order news and codes are the service the customer asked for.

Authentication templates

An authentication template sends a one-time code from your own number (see Templates). It takes exactly one value, params.code: 4 to 15 letters or digits. Tawked puts the code in Meta’s text and on the button, so send no buttons and no header. The listing shows the template as "placeholders": { "kind": "named", "header": [], "body": ["code"], "buttons": [] }.
The answer is the same 202 Accepted as any send:
A code outside 4 to 15 letters or digits, any other key in params, buttons or header answers 422 invalid_params with message naming the field. Tawked does not check the code: comparing what the customer types is your code’s job. Only Meta receives the code; Notifications → Messages and its Tawked Chat conversation show •••••• in its place. For codes by SMS, with the check done for you, use Tawked Verify.

Statuses and webhooks

accepted then sent, delivered, read, or failed from any of the first three. Statuses arrive from Meta within about a minute, are applied in order and never go backwards. A message stops being tracked 48 hours after the send and keeps its last status. Read the current state with GET /v1/whatsapp/messages/{id}:
Or receive one webhook per status change, at each of the application’s webhook endpoints that chose the message.* events, signed and retried exactly like verification.* events. Only the status reached is announced: a message that jumps straight to read gets one message.read. to is masked in webhooks the way the console shows it, so keep your own copy of the destination next to the returned id or your reference.
Signature verification is the same as for verification events: see Webhooks.
Last modified on October 18, 2026