Skip to main content

WhatsApp messages

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 costs one message from the wallet, a message WhatsApp rejects is credited back, and 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_number and costs nothing.
  • The key needs the WhatsApp scopes. New platform keys get both by default. Scopes are frozen when a key is created, so a key created before v1.6 does not have them: create a new key to use these endpoints.
ScopeDescription
whatsapp:readRead 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.
whatsapp:sendSend 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​

keytoggleWhat the buyer reads
receivedreceivedThe order has arrived and the store will call to confirm it.
confirmedconfirmedThe order is confirmed and being prepared, with the amount to pay.
shipped_homeshippedThe order is on its way to the buyer's address, with the delivery delay set in the addon.
shipped_deskshippedThe order is on its way to a pickup desk, which the message names.
delivery_faileddelivery_failedThe courier could not reach the buyer today and will try again tomorrow.
desk_readydesk_readyThe 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,
"used_month": 96
}
}
}
FieldMeaning
balanceMessages left in the wallet. A store that never topped up has 0.
low_balancetrue under 50 messages.
addon_activeWhether the WhatsApp Sender addon is active on the store.
stats.sent, stats.delivered, stats.read, stats.failedMessages of the last 30 days, counted by their current status. A message the buyer read counts under read only.
stats.used_monthMessages taken from the wallet since the 1st of the month, including the ones credited back later.

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​

ParamTypeDefaultNotes
order_iddigitsnoneOnly the messages of this order. Anything other than digits returns 400 bad_request.
limitint501 to 200.
cursorstringnonenext_cursor of the previous page. See Pagination.

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,
"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": false,
"created_at": "2026-09-25 18:02:41"
}
],
"next_cursor": null,
"has_more": false
}
}
FieldMeaning
eventFor an automatic message, the order event that triggered it (received, confirmed, shipped, delivery_failed, desk_ready). For an API message, the template key that was sent.
sourceauto or api.
statusSee the table below.
languagear or fr.
template_nameThe template name registered with WhatsApp.
error_titleWhy a message was skipped or failed, otherwise null.
refundedtrue once the message of a failed send is back in the wallet.
created_atYYYY-MM-DD HH:MM:SS, server time.
statusMeaning
queuedPaid and waiting. The platform sends it within about a minute.
sendingBeing handed to WhatsApp.
sentAccepted by WhatsApp.
deliveredReached the buyer's phone.
readThe buyer opened it.
failedWhatsApp could not deliver it. The message goes back to the wallet within a few minutes and refunded turns true.
skippedNever sent and never charged. error_title gives the reason.

A skipped message carries one of these reasons in error_title:

error_titleMeaning
invalid_numberThe phone is not an Algerian mobile number.
suppressedThe number has no WhatsApp account.
template_not_approvedThe template is still waiting for approval in that language.
empty_paramThe 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​

FieldTypeRequiredNotes
templatestringyesA key from GET /v1/whatsapp/templates, or shipped, which picks shipped_home, shipped_desk or desk_ready from the order's delivery type (home, desk or pickup).
languagear or frnoDefaults to the message language chosen in the addon settings, or the store language when none was chosen.

What the call does​

  1. 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.
  2. It ignores the addon's automatic-message switches: you can send a template the merchant turned off for automatic messages.
  3. Each template can be sent once per order through the API. A second call answers 409 already_sent with the earlier message's id and status. 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.
  4. It checks the phone, the template approval and the order data. A problem answers 422 with the reason as the error code, records a skipped message and charges nothing.
  5. It takes one message from the wallet. An empty wallet answers 402 no_credit and records nothing.
  6. It answers 202. Follow the message with GET /v1/whatsapp/messages?order_id= and the order id. A message WhatsApp rejects turns failed and 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​

HTTPCodeCause
400bad_requestThe order id is not all digits, the body is not valid JSON, or Idempotency-Key is missing or malformed.
402no_creditThe WhatsApp wallet is empty. Nothing was recorded.
403forbidden"Missing scope: whatsapp:send"
403addon_not_activeThe WhatsApp Sender addon is not active on the store.
404not_foundNo order with this id in the store.
409already_sentThis template was already sent for this order through the API.
422unknown_templatetemplate is not shipped or a key from the catalogue.
422invalid_languagelanguage is not ar or fr.
422invalid_numberThe order's phone is not an Algerian mobile number.
422suppressedThe order's phone has no WhatsApp account.
422template_not_approvedThe template is not approved yet in that language.
422empty_paramThe order is missing a value the template needs.
422idempotency_key_reuseThe same Idempotency-Key was used with a different body.
500send_failedThe 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 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_home carries the delivery delay the merchant typed in the addon settings, as typed. A French message from a store whose delay text is in Arabic shows that Arabic text inside the French message. A delay written with digits only, such as 24-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 POST for up to 15 seconds, so give your HTTP client a timeout of at least 20 seconds.