ZevSend Docs
Sign up

API Reference

Send WhatsApp

POST /v1/whatsapp — send a transactional WhatsApp message using a pre-approved template.

Send a transactional WhatsApp message to a phone number in international format.

POST /v1/whatsapp

Request

curl https://api.zevsend.com/v1/whatsapp \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+2348012345678",
    "template_id": "tpl_01HXYZ...",
    "variables": {
      "first_name": "Ada",
      "order_id": "ORD-1234"
    }
  }'

Body parameters

FieldTypeRequiredDescription
tostringyesRecipient phone in E.164.
template_idstringyesTemplate public id (tpl_…). Must be a whatsapp template.
variablesobjectsometimesValues for the template’s declared customer.* variables.
brand_domain_idstringnoPin the send to a specific verified domain (dom_…) for brand variables like {{brand.name}}.

Response

HTTP/1.1 202 Accepted
Content-Type: application/json

{
  "id": "wam_01HXYZ...",
  "to": "+2348012345678",
  "status": "sending",
  "sandbox": false,
  "created_at": "2025-05-24T12:34:56.789Z"
}

Lifecycle

WhatsApp has one more terminal state than email or SMS — a read event fires when the recipient opens the conversation.

StateMeaning
queuedPersisted but not yet handed off.
sendingHanded off; awaiting accept.
sentAccepted and in transit.
deliveredConfirmed at the recipient’s device.
readRecipient opened the conversation.
failedRejected at submit or permanent delivery failure.

The read state is best-effort. WhatsApp only fires read receipts when the recipient has read-receipts enabled in their own settings, so a message that’s been read may never visibly transition past delivered. Don’t treat the absence of read as a signal that the message wasn’t seen.

Templates only

Every WhatsApp send must reference a pre-approved template. Raw text isn’t accepted — the upstream network would reject it anyway, so we reject it at the API.

The variable manifest on the template encodes the positional order of placeholders in the approved template body. You pass named variables; we map them to positions at send time. The upstream network renders the message body from the approved template using your variable values.

Pricing

WhatsApp templates carry a per-send price, set on the template in your team’s billing currency. Templates can also have per-country overrides that take precedence over the default rate when sending to those countries. The price you see on the template is what you pay. We never expose which upstream provider handled the send.

See the Pricing guide for the full charge cascade and how Zev Credit is debited.

Errors

StatusCodeCause
400invalid_phoneto isn’t a valid E.164 number.
400template_id_requiredtemplate_id was missing.
404template_not_foundNo such template on this team.
409wrong_template_channelThe template is for email or SMS.
422missing_variableA required variable was missing.
422unknown_variableYou passed a variable the template doesn’t declare.
403no_approved_brand_domainYou’re live but no approved domain exists for the team.
403recipient_not_allowedSandbox-only: recipient hasn’t been verified on this team.
503no_carrier_availableNo enabled WhatsApp provider is currently online.

Conversation windows

WhatsApp enforces 24-hour conversation windows: once a recipient last messaged you, you have 24 hours to send free-form messages back. Outside that window only pre-approved templates of the right category can be delivered. ZevSend is template-only, so this is enforced by design.

Template categories (set when the template is registered):

CategoryUsed for
AUTHENTICATIONOTPs, login codes, verification messages.
UTILITYAccount updates, order confirmations, shipping notifications.
MARKETINGPromotional content. Limited per recipient per day.

Pick the right category when you author the template — picking wrong is the most common reason templates get rejected.

Updated at, Thursday, October 1, 2026