Skip to main content
A template is a message pre-approved by Meta. It is the only message type you can send when the 24-hour window is closed — that is, when the contact hasn’t written to you in the last 24 hours. While the window is open you can send free text; once it closes, only a template will reach the customer.
Templates are created and approved in the dashboard. The public API only consumes them to send — it does not create or edit them.

How a template is resolved

1

Identify the template by name

A template is identified by its template_name — the same name you see in the dashboard and report to Meta.
2

Specify the language

Language is required on every send: add language in Meta format lower_UPPER (e.g. en_US) to pick which template to send.
3

Verify it is approved

Only templates with status APPROVED can be sent. One in PENDING or REJECTED is not sendable.

Template components

A template is designed and approved in the dashboard with fixed parts and dynamic slots. When you send it from the API you only fill in those slots: you can’t add a header or buttons the template doesn’t have.

body_variables

The body placeholders ({{1}}, {{2}}, …). Array of { index, value }, index from 1, up to 30 variables.

header

The header: text, or media (image, video, or document) via file_uuid.

button_parameters

The parameter for a dynamic button (e.g. the suffix of a URL button). Up to 3.
It’s a union by type — the type must match how the template was designed: The file_uuid comes from the Upload media flow. The transcription (up to 4000 characters) is required when vision can’t transcribe the file (unsupported MIME or larger than 20 MB); if it’s missing in that case, the action fails with TEMPLATE_HEADER_TRANSCRIPTION_MISSING.

button_parameters

Array of { subType, index, text }, up to 3 buttons:
  • subType — today only "url" (dynamic URL button).
  • index — the position of the dynamic button within the template, from 0.
  • text — the value appended to the button’s base URL (e.g. a resource identifier), up to 1024 characters.
When writing, the key is subType (camelCase). The read endpoint Template detail returns the same field as sub_type (snake_case): do not copy the key verbatim from the read response — on send, sub_type is silently dropped and the action fails with INVALID_REQUEST.

Sending a template

You fill in the template object based on the slots it has. These are the most common cases:
You’ll find template names in the dashboard, which is where templates get approved. To see what variables, header, and buttons a specific one expects, see Template detail.
To send text or media while the window is open and have the template arrive if it’s closed, include the template alongside the primary content in the same send_message.

Payment details in variables (markers)

A payment marker is a token shaped ==name== that gets replaced with that conversation’s real payment details at send time. In a template it goes inside a body variable’s value, never in the template text itself. Meta approves the body with its placeholders (Hi {{1}}, your CLABE is {{2}} ({{3}})), not the values — those travel with each send. That’s why the marker can be resolved there, and Meta never sees the token.
Available markers: clabe_spei, clabe_bank and account_national_link.
They only work in body_variables. In the text header and in button parameters they are rejected with PAYMENT_MARKER_UNSUPPORTED_FIELD (422).The reason is that those fields’ length is validated against the text you send — measuring the marker, not the value replacing it — so a substitution could turn a value that was valid on save into a Meta rejection on delivery. And a button parameter is the suffix of an already-approved URL, so a payment link there would produce a nested URL. Move the marker to a body variable.A template footer accepts no variables at all; that is Meta’s rule.
If the conversation has no payment account yet, one is generated at that moment — the marker is the trigger. That is why a campaign whose templates carry markers creates one account per recipient: it is what lets you attribute who paid.
The whole send is blocked, delivering nothing, when the marker cannot be resolved or its result does not fit: misspelled name (PAYMENT_MARKER_UNKNOWN, 422), the conversation lacks that value (PAYMENT_MARKER_DATA_UNAVAILABLE, 422), the interpolated body exceeds Meta’s 1024 characters (TEMPLATE_BODY_TOO_LONG, 422), or the payment account could not be generated (PAYMENT_PROFILE_GENERATION_FAILED, 500). A half-written message is never delivered in a money flow.

Test templates for tester conversations

The dashboard lets you create test templates (status: FAKE) from the Tester module without going through Meta’s approval. They exist so operators and integrators can test flows against tester conversations without waiting for Meta review. Sending rules via the public API:
  • Tester conversation (is_tester: true in GET /conversation) — you can send both APPROVED templates and FAKE templates. The send replicates the real flow but does not hit Meta (wamid returns "").
  • Real conversation (is_tester: false) — only APPROVED templates. If you try to send a FAKE template or a template with is_tester: true to a real conversation, the API responds with TEMPLATE_FAKE_REQUIRES_TESTER_CONVERSATION (422).
The public template catalog does not include FAKE templates — only real APPROVED ones. If you need the name of a FAKE template to send it, ask the operator.

Next steps

Send messages

Sending templates, text, media, and quick replies.

Conversations

The 24-hour window and the state of a conversation.