These four endpoints expose the WhatsApp Sender addon: the order message templates the platform has had approved, the store's WhatsApp wallet, the log of messages sent to buyers, and a call that sends one template to the buyer of one order. A message sent through the API follows the same rules as the automatic ones. It takes one message from the wallet when it is queued, and that credit comes back when WhatsApp does not bill the message: rejected, never delivered, or delivered without a charge. A message that is never sent is never charged.
You cannot send free text. Every message is one of the six templates listed below, filled from the order (buyer first name, order number, store name, courier, pickup desk, amount to pay), in Arabic or French, with a track-my-order button.
Before you start
The WhatsApp Sender addon must be active on the store (Add-ons page of the dashboard). The three read endpoints work without it; the send answers
403 addon_not_active.The wallet is topped up from the addon's page in the dashboard (
/dashboard/whatsapp-sender, Top up). The API reads the balance but cannot top it up.Messages go to Algerian mobile numbers only (05, 06 or 07). Any other number is skipped with
invalid_numberand costs nothing.The key needs the WhatsApp scopes. Keys created from the dashboard (Settings → API,
/dashboard/api) get both. Scopes are frozen when a key is created, so a key created before v1.6 does not have them: create a new key from the dashboard to use these endpoints. A key created throughPOST /v1/keysonly gets the scopes held by the key that created it.
Scope | Description |
| Read the WhatsApp order message templates, the WhatsApp wallet balance and the message log. Included in merchant keys created from v1.6 on; an older key needs a new key. |
| Send WhatsApp order messages to buyers, each paid from the store's WhatsApp wallet. Included in merchant keys created from v1.6 on; an older key needs a new key. |
GET /v1/whatsapp/templates
The template catalogue: the Arabic and French text, example values for each placeholder, and the approval status of each language.
Auth: platform key with whatsapp:read.
The status is the last one the platform read from WhatsApp. It is refreshed at most every 10 minutes while messages are being sent, and UNKNOWN means it has not been read yet. This call never contacts WhatsApp itself. Only APPROVED templates are sent: a send in a language whose template is not approved is skipped with template_not_approved and costs nothing.
Request
curl 'https://api.dzbuild.app/v1/whatsapp/templates' \ -H "Authorization: Bearer $DZ_KEY"
Response 200
One of the six items is shown.
{
"data": {
"items": [
{
"key": "shipped_home",
"name": "dz_order_shipped_home",
"toggle": "shipped",
"languages": {
"ar": {
"body": "أهلاً {{1}}، طلبك رقم {{2}} من {{3}} في الطريق مع {{4}}.\nسيصلك خلال {{5}}. سيتصل بك عامل التوصيل قبل الوصول، يرجى إبقاء هاتفك متاحاً وتجهيز المبلغ: {{6}} دج.\nاضغط على الزر لتتبع طلبك.",
"example": ["أحمد", "1024", "متجري", "Yalidine", "يوم إلى 3 أيام", "3500"],
"status": "APPROVED"
},
"fr": {
"body": "Bonjour {{1}}, votre commande n° {{2}} chez {{3}} est en route avec {{4}}.\nLivraison prévue sous {{5}}. Le livreur vous appellera avant d'arriver : restez joignable et préparez le montant de {{6}} DA.\nAppuyez sur le bouton pour suivre votre commande.",
"example": ["Ahmed", "1024", "Ma Boutique", "Yalidine", "1 à 3 jours", "3500"],
"status": "APPROVED"
}
}
}
]
}
}
The six templates
|
| What the buyer reads |
|
| The order has arrived and the store will call to confirm it. |
|
| The order is confirmed and being prepared, with the amount to pay. |
|
| The order is on its way to the buyer's address, with the delivery delay set in the addon. |
|
| The order is on its way to a pickup desk, which the message names. |
|
| The courier could not reach the buyer today and will try again tomorrow. |
|
| The parcel is waiting at the pickup desk. |
toggle is the automatic-message switch in the addon settings that owns the template. It controls the automatic messages only; a send through the API ignores it.
GET /v1/whatsapp/balance
The wallet balance, the addon state and the message counts shown on the addon's page.
Auth: platform key with whatsapp:read.
Request
curl 'https://api.dzbuild.app/v1/whatsapp/balance' \ -H "Authorization: Bearer $DZ_KEY"
Response 200
{
"data": {
"balance": 412,
"low_balance": false,
"addon_active": true,
"stats": {
"sent": 12,
"delivered": 230,
"read": 158,
"failed": 4,
"free": 9,
"used_month": 96
}
}
}
Field | Meaning |
| Messages left in the wallet. A store that never topped up has |
|
|
| Whether the WhatsApp Sender addon is active on the store. |
| Messages of the last 30 days, counted by their current status. |
| Messages of the last 30 days that reached the buyer but that WhatsApp did not bill. Their credit is back in the wallet. |
| Messages taken from the wallet since the 1st of the month and not credited back: the ones WhatsApp billed plus the ones whose outcome WhatsApp has not reported yet. |
GET /v1/whatsapp/messages
The store's messages, newest first: the automatic ones (source is auto) and the ones sent through the API (source is api). The buyer's phone number is never returned.
Auth: platform key with whatsapp:read.
Query parameters
Param | Type | Default | Notes |
| digits | none | Only the messages of this order. Anything other than digits returns |
| int | 50 | 1 to 200. |
| string | none |
|
Request
curl 'https://api.dzbuild.app/v1/whatsapp/messages?order_id=6894' \ -H "Authorization: Bearer $DZ_KEY"
Response 200
{
"data": {
"items": [
{
"id": 4181,
"order_id": 6894,
"event": "shipped_home",
"source": "api",
"status": "read",
"language": "fr",
"template_name": "dz_order_shipped_home",
"error_title": null,
"refunded": false,
"billing": "charged",
"created_at": "2026-09-26 10:14:03"
},
{
"id": 4180,
"order_id": 6894,
"event": "confirmed",
"source": "auto",
"status": "delivered",
"language": "ar",
"template_name": "dz_order_confirmed",
"error_title": null,
"refunded": true,
"billing": "free",
"created_at": "2026-09-25 18:02:41"
}
],
"next_cursor": null,
"has_more": false
}
}
Field | Meaning |
| For an automatic message, the order event that triggered it ( |
|
|
| See the table below. |
|
|
| The template name registered with WhatsApp. |
| Why a message was skipped or failed, otherwise |
|
|
|
|
|
|
| Meaning |
| Paid and waiting. The platform sends it within about a minute. |
| Being handed to WhatsApp. |
| Accepted by WhatsApp. |
| Reached the buyer's phone. |
| The buyer opened it. |
| WhatsApp could not deliver it. When the send to WhatsApp itself failed, the credit is back in the wallet within a few minutes. When WhatsApp reports the failure, the platform waits 24 hours before it credits the message back, because WhatsApp can still report it delivered on another of the buyer's devices, and the status then changes to |
| Never sent and never charged. |
A skipped message carries one of these reasons in error_title:
| Meaning |
| The phone is not an Algerian mobile number. |
| The number has no WhatsApp account. |
| The template is still waiting for approval in that language. |
| The order is missing a value the template needs. |
POST /v1/orders/{id}/whatsapp
Queues one template for the buyer of one order and takes one message from the wallet. The platform sends it within about a minute.
Auth: platform key with whatsapp:send. Requires Idempotency-Key.
Body
Field | Type | Required | Notes |
| string | yes | A |
|
| no | Defaults to the message language chosen in the addon settings, or the store language when none was chosen. |
What the call does
It checks that the addon is active and that the order belongs to the store. An order of another store answers
404, like an order that does not exist.It ignores the addon's automatic-message switches: you can send a template the merchant turned off for automatic messages.
Each template can be sent once per order through the API. A second call answers
409 already_sentwith the earlier message'sidandstatus. The one exception is an earlier attempt that was skipped, for example because the phone was invalid and has since been corrected on the order: then the call tries again.It checks the phone, the template approval and the order data. A problem answers
422with the reason as the error code, records a skipped message and charges nothing.It takes one message from the wallet. An empty wallet answers
402 no_creditand records nothing.It answers
202. Follow the message withGET /v1/whatsapp/messages?order_id=and the order id. A message WhatsApp rejects turnsfailedand goes back to the wallet.
API messages are counted apart from the automatic ones. Sending shipped_home through the API does not stop the automatic on-its-way message for the same order, and the automatic message does not block the API send. Each is paid.
Request
curl -X POST 'https://api.dzbuild.app/v1/orders/6894/whatsapp' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: wa-6894-shipped-1" \
-d '{"template": "shipped", "language": "fr"}'
Response 202
template is the key that was queued, with shipped already resolved.
{
"data": {
"message_id": 4181,
"status": "queued",
"template": "shipped_home",
"language": "fr"
}
}
Errors
HTTP | Code | Cause |
400 |
| The order id is not all digits, the body is not valid JSON, or |
402 |
| The WhatsApp wallet is empty. Nothing was recorded. |
403 |
| "Missing scope: whatsapp:send" |
403 |
| The WhatsApp Sender addon is not active on the store. |
404 |
| No order with this id in the store. |
409 |
| This template was already sent for this order through the API. |
422 |
|
|
422 |
|
|
422 |
| The order's phone is not an Algerian mobile number. |
422 |
| The order's phone has no WhatsApp account. |
422 |
| The template is not approved yet in that language. |
422 |
| The order is missing a value the template needs. |
422 |
| The same |
500 |
| The message could not be queued. Retry with the same key. |
A 409 already_sent looks like this.
{
"error": {
"code": "already_sent",
"message": "This template was already sent for this order",
"id": 4181,
"status": "delivered"
}
}
Retries and Idempotency-Key
The first answer to a key is stored for 24 hours. A retry with the same key and the same body gets that answer back with Idempotency-Replay: 1, including a 402, 403 or 422. So after you top up the wallet, activate the addon or fix the order, retry with a new Idempotency-Key: the old key keeps returning the old error. A replayed 202 means no second message was queued.
The same key with a different body or for another order answers 422 idempotency_key_reuse. A 5xx or 429 answer is never stored, so retry it with the same key. If the message was in fact queued before the error, the retry answers 409 already_sent with its id, and nothing is charged twice. See Idempotency.
Known limits
Delivery delay text.
shipped_homecarries the delivery delay the merchant typed in the addon settings, as typed. When that field is empty, it carries the addon's default delay, written in the message language chosen in the addon settings (the store language when none was chosen). A French message from a store whose delay text is in Arabic, typed or default, shows that Arabic text inside the French message. A delay written with digits only, such as24-72h, reads the same in both languages.Slow first send after an approval check. When the stored approval status of a template is older than 10 minutes, the send reads it again from WhatsApp before queuing. That happens at most once per template and language every 10 minutes and can hold the
POSTfor up to 15 seconds, so give your HTTP client a timeout of at least 20 seconds.