Skip to main content

WhatsApp messages

Read the WhatsApp order templates, the store's WhatsApp wallet and message log, and send a template to an order's buyer from your own code.

Written by Support

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_number and 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 through POST /v1/keys only gets the scopes held by the key that created it.

Scope

Description

whatsapp:read

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.

whatsapp:send

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

key

toggle

What the buyer reads

received

received

The order has arrived and the store will call to confirm it.

confirmed

confirmed

The order is confirmed and being prepared, with the amount to pay.

shipped_home

shipped

The order is on its way to the buyer's address, with the delivery delay set in the addon.

shipped_desk

shipped

The order is on its way to a pickup desk, which the message names.

delivery_failed

delivery_failed

The courier could not reach the buyer today and will try again tomorrow.

desk_ready

desk_ready

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

balance

Messages left in the wallet. A store that never topped up has 0.

low_balance

true under 50 messages.

addon_active

Whether the WhatsApp Sender addon is active on the store.

stats.sent, stats.delivered, stats.read, stats.failed

Messages of the last 30 days, counted by their current status. delivered includes the messages the buyer read, so do not add delivered and read together.

stats.free

Messages of the last 30 days that reached the buyer but that WhatsApp did not bill. Their credit is back in the wallet.

stats.used_month

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

order_id

digits

none

Only the messages of this order. Anything other than digits returns 400 bad_request.

limit

int

50

1 to 200.

cursor

string

none

next_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,
        "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

event

For 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.

source

auto or api.

status

See the table below.

language

ar or fr.

template_name

The template name registered with WhatsApp.

error_title

Why a message was skipped or failed, otherwise null.

refunded

true once the credit is back in the wallet.

billing

charged once WhatsApp billed the message, free once its credit is back in the wallet (failed, undelivered after 30 days, or delivered without a charge), null while WhatsApp has not reported the outcome.

created_at

YYYY-MM-DD HH:MM:SS, server time.

status

Meaning

queued

Paid and waiting. The platform sends it within about a minute.

sending

Being handed to WhatsApp.

sent

Accepted by WhatsApp.

delivered

Reached the buyer's phone.

read

The buyer opened it.

failed

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 delivered. refunded turns true once the credit is back.

skipped

Never sent and never charged. error_title gives the reason.

A skipped message carries one of these reasons in error_title:

error_title

Meaning

invalid_number

The phone is not an Algerian mobile number.

suppressed

The number has no WhatsApp account.

template_not_approved

The template is still waiting for approval in that language.

empty_param

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

template

string

yes

A 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).

language

ar or fr

no

Defaults 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

HTTP

Code

Cause

400

bad_request

The order id is not all digits, the body is not valid JSON, or Idempotency-Key is missing or malformed.

402

no_credit

The WhatsApp wallet is empty. Nothing was recorded.

403

forbidden

"Missing scope: whatsapp:send"

403

addon_not_active

The WhatsApp Sender addon is not active on the store.

404

not_found

No order with this id in the store.

409

already_sent

This template was already sent for this order through the API.

422

unknown_template

template is not shipped or a key from the catalogue.

422

invalid_language

language is not ar or fr.

422

invalid_number

The order's phone is not an Algerian mobile number.

422

suppressed

The order's phone has no WhatsApp account.

422

template_not_approved

The template is not approved yet in that language.

422

empty_param

The order is missing a value the template needs.

422

idempotency_key_reuse

The same Idempotency-Key was used with a different body or for another order.

500

send_failed

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_home carries 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 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.

Did this answer your question?