name-regex
Template names are used as stable identifiers across Meta, webhooks, and our database. Meta enforces lowercase-only characters so names are URL-safe and diff-friendly across BSPs. Rule:^[a-z][a-z0-9_]{0,511}$ — lowercase letters, digits, and underscores only. No spaces, hyphens, uppercase, dots, or accented characters. Must be unique per WABA per language.
DO
leading-variable
Meta rejects body text that starts with a placeholder because it renders awkwardly on mobile and gives the model no anchor for category classification. A body that begins with a name or greeting reads like a message; one that begins with{{1}} reads like a template leak.
DO
trailing-variable
The mirror of the leading-variable rule. A body that ends on{{N}} — even with a trailing full stop — is rejected. Add at least one fixed word after the last placeholder, ideally a full sentence of context.
DO
adjacent-variables
Two placeholders with only whitespace or punctuation between them are rejected. Meta cannot render the boundary cleanly and cannot classify the intent when the body is effectively a parameter list. Put at least one real word between every pair. DOmissing-example
Every{{n}} in a HEADER, BODY, or dynamic URL button must have a matching realistic example. Meta uses examples to render the preview shown to reviewers and to classify the template’s category. A template with placeholders and no examples is rejected at submit time.
DO
example-count-mismatch
The length of the example array must equal the number of distinct placeholders. Three{{n}} tokens require exactly three example strings — not two, not four. This check runs per component (body, header text, URL button).
DO
numeric-only-example
Example values must be realistic — that is, they should contain alphabetic characters or a clearly meaningful alphanumeric token (currency amount with symbol, a date string, an order code). A bare number, a single symbol, or a code-like string with no context is rejected because it does not represent how a real recipient will see the message. DO"20%", not "20" with the % sitting adjacent in the body. That removes the “bare number” heuristic and renders identically.
Meta docs: Example values.
sequential-numbering
Placeholders must start at{{1}} and run sequentially with no gaps and no duplicates. {{1}}, {{2}}, {{3}} is valid; {{1}}, {{3}} is not; {{2}}, {{3}} is not (must start at 1). The validator extracts the unique indices, sorts them, and checks the resulting list equals [1..N].
DO
params-words-ratio
A template where placeholders dominate the fixed text reads like a raw data dump and is flagged during content review. The Switchbord linter warns when the ratio of variables to total words exceeds roughly 1 in 4 — a template with three{{n}} tokens should have at least twelve words of fixed copy around them.
DO
length-caps
Each component has a hard character limit. Count the raw template string including placeholders — the runtime expansion does not count against the limit.
DO
button-limits
Buttons have per-type hard caps. Exceeding any one cap rejects the whole template at submit.
Dynamic URL buttons must have
{{1}} as the only variable, appearing at the end of the URL path or query value — never in the hostname.
DO
component-ordering
A template’s components must appear in the orderHEADER → BODY → FOOTER → BUTTONS. Each component may appear at most once, except BODY which is required exactly once. Meta normalises the order in some cases but rejects duplicates and unknown types with code 100.
DO
footer-has-variables
Footers are for static, legally-important copy — the sender identity, the opt-out instruction, a disclosure. They cannot contain{{n}} placeholders. Put runtime data in the body.
DO
Quick-reference regex set
If you are writing your own validator or scripting bulk checks, the canonical regexes are:See also
- Your first template — end-to-end walkthrough.
- Marketing templates — category-specific rules and opt-out.
- Template API endpoints — programmatic submission.