WhatsApp Template Variables: How to Send a WhatsApp Template Message With Parameters
WhatsApp template variables are placeholders you fill at send time. Named versus positional, the parameter_format default that breaks sends, both payload shapes, and the rules that get templates rejected.
A WhatsApp template variable is a placeholder you write into an approved template, wrapped in double curly brackets, that gets swapped for a real value at the moment you send. You define the placeholder once when you create the template, and you supply the value on every send. Meta calls them parameters; WhatsApp Manager calls them variables. They are the same thing, and getting them wrong is the most common reason a template is rejected on creation or fails on send.
Most guides stop at the creation half. This one covers both, because the two payloads are different shapes and the mismatch between them is where the errors live.
What a WhatsApp template variable actually is
When you submit a template for approval, the text you submit is fixed. Meta reviews that exact wording, and once it is approved you cannot change it without going back through review. Variables are the escape hatch: the parts you are allowed to change per recipient without re-approval.
So a body written like this:
Hi {{1}}, order {{2}} shipped today and should reach you by {{3}}.
is approved once, then sent thousands of times with a different name, order number and date each time. The wording around the placeholders is what Meta approved. The placeholders themselves are yours to fill.
You can build and check one against Meta's published limits with our WhatsApp message template generator, which flags the parameter faults described below before you submit anything.
Named or positional: pick a format, because the default may not be the one you want
Meta supports two parameter formats, and this is the detail that catches teams out. From Meta's template documentation: "Upon template creation, if a string includes one or more parameters, you can specify their format, either named or positional, and you must include an example value for each parameter. If you do not specify a format, the template uses positional format by default."
That default matters. If you leave parameter_format out of your creation payload and then try to send with named parameters, the send fails, because the template you actually created is positional.
Positional parameters
Positional parameters must be ordered array index numbers, starting from 1, wrapped in double curly brackets. On send, the values must appear in the order in which their corresponding placeholders appear in the text. There are no labels, just position.
Named parameters
Parameters using the named format must be unique, single strings, composed of lowercase characters and underscores, wrapped in double curly brackets, for example {{first_name}}. The payoff comes at send time: with named parameters, the real values can appear in any order, because each one carries its own parameter_name.
For a team that edits message copy often, named is the safer choice. Reword a positional template so the order number now comes before the customer name, and every send after that quietly puts the order number where the name should be. Nothing errors. The messages just go out wrong. Named parameters make that class of bug impossible.
The creation payload
This is what you POST to the message_templates edge on your WhatsApp Business Account. Note the parameter_format field and the example object, both of which are required once your text contains a parameter.
{
"name": "order_confirmation",
"language": "en_US",
"category": "utility",
"parameter_format": "named",
"components": [
{
"type": "body",
"text": "Thank you, {{first_name}}! Your order number is {{order_number}}.",
"example": {
"body_text_named_params": [
{ "param_name": "first_name", "example": "Pablo" },
{ "param_name": "order_number", "example": "860198-230332" }
]
}
}
]
}
The positional equivalent uses "parameter_format": "positional" and swaps the example object for "body_text": [["Pablo", "860198-230332"]]. That nested array is not a typo. body_text is an array of arrays, and passing a flat array is a common first-attempt failure.
The example values are not decoration. Meta's reviewer reads the template with your examples substituted in, so a template whose examples are "aaa" and "bbb" is being reviewed as a message that says "Thank you, aaa!" Give it realistic values and approval gets easier.
The send payload, which is a different shape
Here is where most of the confusion sits. The creation payload describes the template. The send payload fills it. They do not look alike.
Sending a template that uses named parameters:
{
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "+16505551234",
"type": "template",
"template": {
"name": "order_confirmation",
"language": { "code": "en_US" },
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "parameter_name": "first_name", "text": "Jessica" },
{ "type": "text", "parameter_name": "order_number", "text": "SKBUP2-4CPIG9" }
]
}
]
}
}
The positional version is identical except that each parameter drops parameter_name and relies on array order alone. Three things to notice, because each one is a separate way to break a send:
languageis a nested object here ("language": { "code": "en_US" }) but a plain string on creation. Copying the creation shape into a send call fails.- The
componentsarray on send only lists components that carry parameters. A footer with no variables is not mentioned at all. - The parameter count has to match what the approved template expects. Send two values into a three-parameter template and the message is rejected, not truncated.
The wider mechanics of the send endpoint, including authentication and the response shape, are covered on our WhatsApp API send message page.
The parameter rules that get templates rejected
Meta's template review guidance lists the mechanical faults directly, and every one of them is checkable before you submit:
- Dangling parameters. The message template cannot start or end with a parameter. A body that opens with a name placeholder is rejected. This is why so many approved templates begin with "Hi" or "Hello" before the variable.
- Non-sequential parameters. Positional parameters must run 1, 2, 3. Jump from {{1}} to {{3}}, usually because you deleted a sentence, and it fails.
- Mismatched curly braces. A single brace, or three, breaks the parse.
- Too many variables for the length. Meta flags templates with excessive variables relative to the message length. A six-word body with four placeholders reads as a spam shell, because that is what spam shells look like.
- Special characters inside the placeholder. Characters such as #, $ and % inside the brackets are rejected.
If you are already staring at a rejection, our walkthrough on what to do when a WhatsApp template is rejected covers the appeal path. Appeals are reviewed and decided within 24 hours, but appealing a template you have not actually fixed just spends a day.
Where the values come from, and why that is the real work
Writing the placeholder takes a minute. Reliably producing the value for every recipient at send time is the part that takes a sprint. An order confirmation needs the order number from your commerce platform, the delivery estimate from your fulfillment provider and the customer name from your CRM, joined per recipient and ready before the send fires.
Teams usually discover this after the template is approved. The template is fine, the send code is fine, and the campaign still stalls because the three systems holding the values do not talk to each other. That is a plumbing problem rather than a WhatsApp problem, and it is worth solving with something purpose-built for connecting your apps, APIs and databases rather than with a scheduled export that silently goes stale.
A practical guard: never send a parameter value you have not defaulted. An empty string in a required parameter is a failed send, and a null that stringifies to "null" is worse, because it delivers. Decide per field what happens when the value is missing, before the first send rather than after.
Frequently asked questions
How many variables can a WhatsApp template have?
Meta does not publish a hard number for the body, which accepts multiple parameters. A text header supports 1 parameter. The practical ceiling is the review rule rather than a count: templates with too many variables relative to the length of the message get rejected. Keep the ratio sane and you will not meet the limit.
Can a WhatsApp template start with a variable?
No. Meta's rule is explicit that the message template cannot start or end with a parameter, and dangling parameters are not allowed. Put a word in front of the placeholder. "Hi {{1}}" is approved; {{1}} alone at the start is not.
Can I change a variable in an approved template?
You can change the value you pass on every send, which is the whole point. You cannot change the surrounding text or add a new placeholder without editing the template, and editing sends it back through review. Plan the placeholders you will want later, because adding a fourth one in month three means a fresh approval cycle.
What happens if I send the wrong number of parameters?
The send is rejected rather than partially delivered. The approved template defines exactly how many values it expects, and the API validates the count against it. This is why parameter count belongs in your pre-send validation rather than in your error handling.
Do variables cost extra?
No. Meta bills per delivered template message by category and country, not by how many parameters the template carries. A five-variable utility template and a zero-variable utility template to the same country cost the same. The WhatsApp Business API pricing page has the category breakdown.
Are named parameters better than numbered ones?
For anything you expect to edit, yes. Named parameters carry a parameter_name on send, so values match by label instead of by position and reordering the copy cannot shuffle them. Numbered parameters are fine for a template you will write once and never touch. Just remember that omitting parameter_format gives you positional whether you wanted it or not.
The short version
Define placeholders in double curly brackets, declare parameter_format explicitly, include an example value for every parameter on creation, and remember that the send payload nests language as an object and lists only the components that carry values. Never start or end a body with a placeholder. Then check the template against the limits before you submit it, because a rejection costs a day and a validator costs a minute.