WhatsApp API
Your app can send WhatsApp messages to a store's buyers through four endpoints. The messages use the order templates that Meta approved for DZBuild, and each one is paid from the store's WhatsApp wallet, exactly like the messages the WhatsApp Sender addon sends on its own. You cannot send free text or your own templates.
The full request and response reference is in the OpenAPI description, linked from the API reference page. This page explains how the pieces fit together.
Scopes
| Scope | Allows |
|---|---|
whatsapp:read | GET /v1/whatsapp/templates, GET /v1/whatsapp/balance, GET /v1/whatsapp/messages |
whatsapp:send | POST /v1/orders/{id}/whatsapp |
Request only the scopes you need in the authorize URL. A call without the scope answers 403 with the code forbidden and the message Missing scope: whatsapp:send (or whatsapp:read). See Scopes.
Templates
GET /v1/whatsapp/templates lists the six templates. It reads the approval status DZBuild keeps and never calls Meta.
| Key | Sent for |
|---|---|
received | The order was received. |
confirmed | The order was confirmed. |
shipped_home | The parcel is on its way to the buyer's address. |
shipped_desk | The parcel is on its way to a courier desk. |
delivery_failed | The delivery attempt failed. |
desk_ready | The parcel is ready for pickup. |
Each item carries key, name (the template name at Meta, for example dz_order_confirmed), toggle (the merchant's matching switch in the addon) and languages. languages.ar and languages.fr each hold the body with its placeholders, an example, and the status. A template can only be sent in a language whose status is APPROVED. UNKNOWN means DZBuild has no status stored yet.
Wallet
GET /v1/whatsapp/balance returns:
| Field | Meaning |
|---|---|
balance | Messages left in the store's wallet. One message costs one credit. |
low_balance | true when fewer than 50 messages are left. |
addon_active | Whether the merchant has the WhatsApp Sender addon turned on. |
stats | Counts for the last 30 days by status (sent, delivered, read, failed) and used_month, the credits used since the first day of this month. |
The merchant tops up the wallet in the DZBuild dashboard. Your app cannot add credit.
Send a message
POST /v1/orders/{id}/whatsapp queues one template for one order of the store. It is a write, so it needs an Idempotency-Key header (see Rate limits).
POST /v1/orders/98765/whatsapp HTTP/1.1
Host: api.dzbuild.app
Authorization: Bearer dzpk_live_xxxxxxxx
Idempotency-Key: wa-98765-confirmed
Content-Type: application/json
{"template": "confirmed", "language": "fr"}
| Body field | Required | Meaning |
|---|---|---|
template | Yes | One of the six keys, or shipped. shipped picks the right template from the order's delivery type: shipped_home for home delivery, shipped_desk for a desk, desk_ready for pickup. |
language | No | ar or fr. Without it, the language set in the store's WhatsApp Sender is used, or the store's language when the addon has none. When that fallback is neither ar nor fr, the message goes in Arabic. |
A manual send ignores the merchant's automatic switches in the addon. The addon itself must be active on the store.
The call answers 202 when the message is queued and the credit is taken:
{
"data": { "message_id": 4411, "status": "queued", "template": "confirmed", "language": "fr" },
"meta": { "request_id": "8f2c1a9d4b7e6035", "api_version": "v1" }
}
DZBuild sends queued messages in the background. Follow the result with GET /v1/whatsapp/messages.
Answers and error codes
| Status | Code | Meaning |
|---|---|---|
202 | Queued, one credit taken. | |
400 | bad_request | The order id is not numeric, or the body is not valid JSON. |
402 | no_credit | The store's wallet is empty. Nothing was queued and nothing was charged. |
403 | addon_not_active | The merchant has not turned on the WhatsApp Sender addon. |
403 | forbidden | The token lacks whatsapp:send. |
404 | not_found | No order with this id on this store. |
409 | already_sent | This template was already sent for this order. The error object carries the existing message id and status. |
422 | unknown_template | template is not one of the accepted keys. |
422 | invalid_language | language is not ar or fr. |
422 | invalid_number | The buyer's phone is not a valid Algerian mobile number. |
422 | suppressed | The buyer's number is blocked for WhatsApp messages on the platform. |
422 | template_not_approved | The template is not approved in that language. |
422 | empty_param | A value the template needs is empty on the order. |
500 | send_failed | The message could not be queued. Retry later. |
Each template can be sent once per order through the API. A later call for the same template and order answers 409, even if the first message failed. The 422 answers from invalid_number to empty_param are different: nothing was charged, and the next call for that template and order tries again, so fix the cause (for example the phone number on the order) and call again with a new Idempotency-Key.
Message log
GET /v1/whatsapp/messages lists the store's messages, newest first. Query parameters: order_id to filter one order, limit (default 50, maximum 200) and cursor (the next_cursor of the previous page). The buyer's phone number is never returned.
| Field | Meaning |
|---|---|
id | The message id, the same as message_id in the send answer. |
order_id | The order. |
event | The template key for API messages, or the addon event (received, confirmed, shipped, delivery_failed, desk_ready) for automatic ones. |
source | api for messages sent through the API, auto for the addon's automatic messages. |
status | queued, sending, sent, delivered, read, failed or skipped. |
language | ar or fr. |
template_name | The template name at Meta. |
error_title | Why the message failed or was skipped, or null. |
refunded | true when the credit was given back. |
billing | charged once WhatsApp billed the message, free once the credit came back, null while WhatsApp has not reported the outcome. |
created_at | When the message was queued. |
A message that fails, expires undelivered after 30 days, or is delivered without a charge from WhatsApp gets its credit back once: refunded turns true and billing becomes free. A message WhatsApp bills settles as charged.