Skip to main content
POST
cURL
Guide: Sending messages

Authorizations

Authorization
string
header
required

Authorization: Bearer . An application key (tk_live_, tk_test_) has full access, which covers every product and any product added later, or custom access, chosen when the key is created: one or more of the scopes verify:check, verify:send (includes verify:check), notifications:read, notifications:send (includes notifications:read), email:read, email:send (includes email:read), email:manage (includes email:send), webhooks:manage, email:inbound, notifications:templates (includes notifications:read), chat:menus, chat:attendant. No key made on the API keys page holds notifications:templates, full access included: the three template writes answer such a key 403 insufficient_scope. A connected app's key holds it. Nor chat:menus: the five conversation menu operations answer such a key 403 insufficient_scope, and a connected app's key holds it once the client approved it. Nor chat:attendant: the five auto-attendant operations answer such a key 403 insufficient_scope too, and a connected app's key holds it once the client approved it. email:manage and webhooks:manage are held only by a key someone chose them for: a full-access key, old or new, never holds them. email:inbound, which reads, deletes and forwards received e-mail, is opt-in on every key, full access included: a key holds it only when it was turned on when the key was created. A call outside the key's access answers 403 insufficient_scope and names the scope it needs in the WWW-Authenticate response header. A partner key (tk_partner_) always has full access. Whatever its access, a key is a server-side secret.

Headers

Idempotency-Key
string

A 1 to 128 printable-ASCII-character key you generate, scoped to your API key. Replaying the same key returns the original 202 response unchanged, with the response header Idempotent-Replayed: true: nothing is sent or charged again. A send that fails with 502 releases the key. Use one key per business event (order-1042-received) and retry a 502 or a network error with the same key.

Body

application/json
to
string
required

The destination: a Saudi mobile in any of the accepted formats, stored as E.164.

template
string
required

The template name exactly as WhatsApp Manager lists it, 1 to 512 characters. It must be approved on the number's WhatsApp Business Account.

lang
string

The template language as Meta lists it (ar, en, en_US). Required when the template exists in more than one language.

params
object

Placeholder values for the body: the keys are the placeholder names of a named template ({{name}}), or "1", "2" for a positional one ({{1}}). Every placeholder is required, extra keys are refused, values are strings of 1 to 1024 characters. An authentication template takes exactly { "code": "…" }, 4 to 15 letters or digits, which fills its text and its button. GET /v1/whatsapp/templates lists the placeholders of each template.

header
object

{ "text": "…" }: the value of the text header's placeholder. Required when the template has one, refused otherwise; no newlines. For a template that opens with an image, { "image": { "link": "https://…" } }: the image's public https link, at most 2048 characters, a JPG or PNG of at most 5 MB that Meta fetches when it sends; required for such a template, refused for any other. For a template that opens with a document, { "document": { "link": "https://…/Contract-1042.pdf", "filename": "Contract-1042.pdf" } }: link is required, an https link of at most 2048 characters with no spaces to a PDF (Meta's limit for a document is 100 MB), which Meta downloads when it sends, so it must open without a sign-in at that moment (a signed link that lives a few minutes suits a file with personal data, such as an invoice or a contract); filename is optional, 1 to 240 characters with no control characters and no / or \, the name the customer sees on the document (without it WhatsApp shows a generic name). A document is required for such a template and refused for any other, and an image is refused for it. A header of another shape (document that is not an object, a link that is not a string, extra keys, text beside document) answers 400 invalid_request. Video and location headers are not supported yet.

buttons
array

[{ "index": 0, "parameter": "…" }]: the dynamic suffix of each URL button, one entry per button that has a placeholder; index is the button's position among the template's buttons. Refused for an authentication template: params.code fills its button.

reference
string

Your own reference (order id, event id), 1 to 64 printable characters. Echoed back, and searchable in the Messages log of the console.

Response

Accepted

id
string
status
string
to
string
template
string
lang
string
reference
string
price_halalas
integer
created_at
string<date-time>