API and developers

Send a template message

post/v1/template-messages

Send an approved WhatsApp template to a customer.

A send that is taken answers 202 with status accepted as soon as the sending service has it — the reply carries no delivery outcome. Poll GET /template-messages/{event_id} for what became of it; no webhook reports a send outcome today.

Idempotent on event_id: repeating one returns the state of the first request and never produces a second message.

A 422 names the offending field: a phone outside strict E.164, a template that is not approved for this merchant in that language, or a missing template variable. It also covers the two account-level refusals that no payload can fix — an account that is not on the conversational rail this API sends from, and an account with no connected WhatsApp sender number — each carrying its own type. Neither is worth a retry.

An event older than the freshness window, or one whose conversation is paused, is not an error either: it answers 200 with status discarded and the reason in status_detail.

A 402 means the account cannot pay for the message and nothing was sent. insufficient_funds and wallet_sends_paused clear as soon as the account adds funds, and the same event_id may be sent again once it has; wallet_currency_mismatch needs us. Retrying without adding funds returns the same answer.

Example

curl -X POST "https://api.ya.onl/v1/template-messages" \
  -H "X-API-Key: yv_live_v1_…" \
  -H "Content-Type: application/json" \
  -d '{"event_id":"…","phone":"…","template":"…"}'

Request body

event_idstringrequired

Your identifier for the event. Idempotency key and lookup key for the status endpoint; must be stable across retries. The charset is bounded because this value travels in the status URL

phonestringrequired

Destination phone in strict E.164 (+ country code, 8-15 digits). A number outside the format is rejected with 422 — the country code is never inferred

templateTemplateRefrequired

Approved template to send, by name and language

variablesobject

Template variable values, keyed exactly as required_variables lists them in GET /v1/templates: by position on a positional template ("1" fills {{1}}), by name on a template authored with named placeholders ("name" fills {{name}}). A missing or unknown key is a 422

occurred_atstring | null

ISO 8601 UTC timestamp of the originating event. An event older than the freshness window is discarded instead of sent

metadataTemplateMessageMetadata | null

Optional attribution metadata

Responses

200
No new send was produced: the event_id had already been received and the stored state is returned, or the event settled without being sent
202
Accepted for delivery. The response does not carry the delivery outcome — poll GET /template-messages/{event_id} for it
401
Invalid or missing API key
402
The account cannot pay for this message. type says which: insufficient_funds (no funds left), wallet_sends_paused (sending stopped when the funds ran out) or wallet_currency_mismatch. The first two clear as soon as the account adds funds, and sending resumes on its own; the third does not and needs us. Retrying without adding funds returns the same answer
403
API key lacks the outbound:send scope
409
The event_id is bound to a different message, or it aged out of the idempotency window. Send the event under a new event_id
422
Validation Error
429
Rate limit exceeded
502
The outbound sending service is unavailable
Need help?