Skip to main content
POST
Send WhatsApp Template
Sends an approved WhatsApp template to one recipient and records it in your Inbox, so the send appears in the conversation alongside everything your agent does.

Quick Example

Use Cases

  • Transactional notifications: order confirmations, shipping updates, appointment reminders
  • Re-opening a conversation: outside the 24-hour customer service window a template is the only thing WhatsApp allows
  • Campaign attribution: pass wa_campaign_id so the send, its delivery status and any follow-ups all roll up to one campaign
  • Enriching your CRM as you send: pass metadata and the data you already have about this person is saved onto their contact, instead of being discarded after the send

What happens on your account

1

Ownership is verified

The phone_number_id is checked against your WhatsApp Business Account. A number that is not yours returns 403, so a valid API key can never send from another customer’s number.
2

The language is resolved

If you omit language_code, the language the template is actually approved in is used. Pass it explicitly to override.
3

The message is recorded

The rendered template is stored and appears in your Inbox. A rejected send is stored too, with Meta’s reason attached, rather than disappearing into the API response.
4

A contact is created if needed

If this number is not yet a contact, one is created with lead direction outbound. An existing contact is never reclassified.
5

metadata is saved onto that contact

Any metadata keys matching your contact attributes are written in the same operation, so one call sends the template and populates the contact.

Saving contact attributes with metadata

The data you already have about a person — their plan, their city, an order number — is usually worth keeping after the send. Pass it as metadata and it is saved onto that recipient’s CRM contact, exactly the way extra columns in a campaign CSV are.
The response tells you what happened:
Limits: at most 50 keys, each value at most 1000 characters. Both are rejected with a 400 rather than truncated — silently shortening a value would put corrupted data in your CRM with no way to tell.
metadata vs components. components fills the template’s variables for this one message. metadata is saved on the contact and persists. They are separate on purpose: a value in components is not stored on the contact, and metadata is never sent to WhatsApp. Send a value in both if you want it to do both.
Check metadata_ignored the first time you integrate. A mistyped or undefined attribute name does not fail the request — the message still goes out and the response lists what was dropped. If you never look, a typo surfaces much later as an empty column, with the sends already made.

Delivery status

The response message_id is WhatsApp’s wamid. Delivery is asynchronous, and a 200 here does not mean the user received the message. A message starts at sent and only delivered or read confirms it arrived. To read the current status, use Get WhatsApp Messages, or subscribe to the message_status_updated webhook event.

Errors worth handling

Meta rejected the send. The message field carries Meta’s own reason, which is specific — a wrong template name, a variable count that does not match the approved template, or a field over its length limit (footer max 60 characters, body max 1024). Fix the payload rather than retrying.
The number is not on your WABA. Check the ID in WhatsApp → Phone Numbers.
The account has no wabaId. Complete WhatsApp onboarding first.
metadata has to be a JSON object of {attribute_name: value}, with at most 50 keys and values of at most 1000 characters. Note that an undefined attribute name is not an error — it is ignored and reported in metadata_ignored.
A rejected send is not retried for you, and a 400 will keep failing with the same payload. Only 5xx responses are worth retrying.

Authorizations

X-API-KEY
string
header
required

Body

application/json
phone_number_id
string
required

WhatsApp phone number ID you are sending from. Must belong to your WABA.

to_number
string
required

Recipient, digits only including country code.

template_name
string
required

Name of an approved WhatsApp template.

language_code
string
default:en

Defaults to the language the template is actually approved in when that can be resolved, otherwise "en".

components
object[]

Meta template components (variable values). Same shape Meta's own send API takes.

agent_id
string

Optional. Tags the stored message with one of your agents.

wa_campaign_id
string

Optional campaign to attribute this send to. 1-64 characters of letters, digits, '_' or '-'. Alias: waCampaignId. Follow-ups triggered by this message inherit it.

metadata
object

Optional. Contact attributes to save onto the recipient's CRM contact, as {attribute_name: value}. The attribute must already be defined on your account; keys matching no definition are ignored and listed in metadata_ignored. Name matching ignores case, spaces, underscores and hyphens. Blank values are skipped, and a value edited by hand in the CRM is never overwritten. Max 50 keys, each value max 1000 characters. Nothing is written if the send fails.

Example:
extra
object

Optional. Stored verbatim on the message row. Unlike metadata, this is not written to the contact.

Response

Template sent

status
string
Example:

"success"

message
string
Example:

"Template sent"

message_id
string

WhatsApp message ID (wamid) of the sent message.

contact_updated
string[]

Attribute names from metadata that were saved onto the contact.

Example:
metadata_ignored
string[]

metadata keys that matched no attribute definition and were dropped. The send still succeeded -- check this on first integration to catch a mistyped name.

Example: