Whatever the payload structure already states (character limits, accepted
types, counts) is declared in the API reference
schema: the playground shows it field by field. This page is for the rules the
schema cannot express.
Character limits
The name accepts lowercase letters, digits and underscore, and it does not
change after creation.
Line breaks
Only the message accepts line breaks. Header, footer and button text are single-line:\n, \r and tabs there are grounds for rejection, and so is more
than four spaces in a row.
In the message, avoid a blank line at the end and more than two breaks in a row.
Variables
By far the biggest source of rejections.A variable cannot open or close the text
2388299.
Every variable needs an example
Withoutexample, Meta rejects with missing expected field(s) (example),
code 2388043. The example is what the reviewer reads to understand the
template.
In positional format, numbering is sequential and starts at 1
The example travels as a list, and Meta matches each item by position. With{{1}} and {{3}}, the third one ends up without an example, and the rejection
talks about a missing field without mentioning numbering.
The header accepts one variable
Just one. The second comes back as “The Header field can only have up to 1 variable(s)”, code2388029.
The footer accepts no variables
Meta treats the footer as plain text: a variable there is not replaced and goes literally to the customer.Short text with many variables is rejected
Meta compares how many variables there are against the length of the text, and rejects what is out of proportion, with code2388293. It does not publish the
formula. From our measurements, with two variables or more, count three words
of text per variable, plus one.
Buttons
Quick replies stay together
Meta doesn’t require them to come first: it requires the buttons to sit in two groups, the quick replies and everything else. A quick reply in the middle of other types is rejected.URL and phone format
The URL needshttp or https. www.yourstore.com without the protocol is
rejected, and the error cites the button index in the payload.
The phone number goes in international format, with the country code:
+5511988881234. Without the + and the country, the rejection is
(#192) ... is not a valid phone number.
Variables in buttons
The URL button accepts one variable, and only at the end of the address:Labels Meta writes
On catalog, multi-product, single product, checkout, order and on the authentication code, the button text belongs to Meta. Thetext field is
still required: what changes is that the value isn’t yours. Sending a
different one is rejected with code 2388153, and the response says which one
was right.
The WhatsApp app translates the label into the recipient’s language, so the
value you send at creation is not what the customer reads.
Carousel
- 2 to 10 cards on the media carousel. On the product one, exactly 2 at creation, and up to 10 at send time.
- Every card with the same components. As a consequence: if one card has text, all of them need text; the set of buttons (type and order) is the same across cards. What changes from one card to the next is the button text and the destination.
- On the media carousel, every card needs media.
- The product card has a
{"format": "PRODUCT"}header and a single button, with no card text. Sending two buttons or a body comes back ascomponent of type BODY is required, code2388045, which does not describe the cause.
Media
In the header and in the cards, the media reference is the handle obtained
in Upload media, or the public link to the
file, which we convert to a handle before creating the template.
The link has to open for a server, not only in a browser. Stores and blogs
often block automated downloads, and then Meta answers
media download failed, code 380.
The header image is displayed at 1.91:1, landscape. Anything outside that
ratio is not rejected: WhatsApp crops the excess to fit, from the center. Worth
building the artwork at that size, or accepting that the edges disappear on the
customer’s phone.
Delivery window
message_send_ttl_seconds has a range per category:
The value
-1 is a shortcut for 30 days. On authentication, the delivery window
cannot be shorter than the code validity: if the message stops being delivered
first, the customer loses both.
How many templates fit in the account
The limits below belong to the account, not to the template you are creating. That is why their rejection is confusing: it does not mention anything that is in your payload.
The name is unique per WABA and language: the same name in
pt_BR and in
en_US are two templates, and both are accepted. Repeating name and language
in the same account comes back as already exists — including when the other
one was deleted less than 30 days ago, because deleting reserves the name for
that period.
Going over 100 creations per hour is not a payload error: it is a queue. If
you are migrating a whole catalog of templates at once, create them in
batches and wait between them, instead of retrying right away.
Editing and deleting
- An approved template accepts up to 10 edits in 30 days, and one every 24 hours. Rejected and paused have no such cap.
- Only approved, rejected and paused templates can be edited.
- Name and language do not change. Neither does the category of an approved template.
- An edit replaces all components: send the complete set, because whatever is left out is erased.
- After an edit, the template goes back into the review queue on its own.
- Deleting an approved template reserves its name for 30 days.
Meta errors, and what each one means
When the rejection comes from Meta, we return her original message along with
the
traceId. Keep both: they are what support uses to identify the case.