Messages WhatsApp
Ces quatre endpoints ouvrent l'addon WhatsApp Sender à l'API : les modèles de messages de commande validés pour la plateforme, le solde WhatsApp de la boutique, l'historique des messages envoyés aux acheteurs, et un appel qui envoie un modèle à l'acheteur d'une commande. Un message envoyé par l'API suit les mêmes règles que les messages automatiques. Il coûte un message du solde, un message refusé par WhatsApp est recrédité, et un message jamais envoyé n'est jamais débité.
Le texte libre n'est pas possible. Chaque message est l'un des six modèles listés plus bas, rempli à partir de la commande (prénom de l'acheteur, numéro de commande, nom de la boutique, transporteur, point de retrait, montant), en arabe ou en français, avec le bouton « Suivre ma commande ».
Avant de commencer
- L'addon WhatsApp Sender doit être activé sur la boutique (page Extensions du dashboard). Les trois endpoints de lecture fonctionnent sans lui ; l'envoi répond
403 addon_not_active. - Le solde se recharge depuis la page de l'addon dans le dashboard (
/dashboard/whatsapp-sender, bouton Recharger). L'API lit le solde mais ne peut pas le recharger. - Les messages ne partent que vers des numéros mobiles algériens (05, 06 ou 07). Tout autre numéro est ignoré avec
invalid_number, sans débit. - La clé a besoin des portées WhatsApp. Les nouvelles clés plateforme ont les deux par défaut. Les portées sont figées à la création de la clé : une clé créée avant la v1.6 ne les a pas. Créez une nouvelle clé pour utiliser ces endpoints.
| Portée | Description |
|---|---|
whatsapp:read | Consulter les modèles de messages WhatsApp, votre solde et l'historique des messages envoyés |
whatsapp:send | Envoyer des messages WhatsApp à vos acheteurs au sujet de leurs commandes (chaque message est débité de votre solde WhatsApp) |
GET /v1/whatsapp/templates
Le catalogue des modèles : le texte arabe et français, des valeurs d'exemple pour chaque champ, et le statut de validation de chaque langue.
Auth : clé plateforme avec whatsapp:read.
Le statut est le dernier lu par la plateforme auprès de WhatsApp. Il est rafraîchi au plus une fois toutes les 10 minutes tant que des messages partent, et UNKNOWN veut dire qu'il n'a pas encore été lu. Cet appel ne contacte jamais WhatsApp lui-même. Seuls les modèles APPROVED sont envoyés : un envoi dans une langue dont le modèle n'est pas validé est ignoré avec template_not_approved, sans débit.
Requête
curl 'https://api.dzbuild.app/v1/whatsapp/templates' \
-H "Authorization: Bearer $DZ_KEY"
Réponse 200
Un seul des six éléments est montré.
{
"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"
}
}
}
]
}
}
Les six modèles
key | toggle | Ce que lit l'acheteur |
|---|---|---|
received | received | Sa commande est arrivée et la boutique va l'appeler pour la confirmer. |
confirmed | confirmed | Sa commande est confirmée et en préparation, avec le montant à payer. |
shipped_home | shipped | Sa commande est en route vers son adresse, avec le délai de livraison réglé dans l'addon. |
shipped_desk | shipped | Sa commande est en route vers un point de retrait, que le message nomme. |
delivery_failed | delivery_failed | Le livreur n'a pas pu le joindre aujourd'hui et réessaiera demain. |
desk_ready | desk_ready | Le colis l'attend au point de retrait. |
toggle est l'interrupteur de message automatique, dans les réglages de l'addon, dont dépend le modèle. Il ne contrôle que les messages automatiques ; un envoi par l'API l'ignore.
GET /v1/whatsapp/balance
Le solde, l'état de l'addon et les compteurs de messages affichés sur la page de l'addon.
Auth : clé plateforme avec whatsapp:read.
Requête
curl 'https://api.dzbuild.app/v1/whatsapp/balance' \
-H "Authorization: Bearer $DZ_KEY"
Réponse 200
{
"data": {
"balance": 412,
"low_balance": false,
"addon_active": true,
"stats": {
"sent": 12,
"delivered": 230,
"read": 158,
"failed": 4,
"used_month": 96
}
}
}
| Champ | Signification |
|---|---|
balance | Messages restants dans le solde. Une boutique qui n'a jamais rechargé a 0. |
low_balance | true sous 50 messages. |
addon_active | L'addon WhatsApp Sender est-il activé sur la boutique. |
stats.sent, stats.delivered, stats.read, stats.failed | Messages des 30 derniers jours, comptés selon leur statut actuel. Un message lu par l'acheteur compte seulement dans read. |
stats.used_month | Messages débités du solde depuis le 1er du mois, y compris ceux recrédités ensuite. |
GET /v1/whatsapp/messages
Les messages de la boutique, du plus récent au plus ancien : les messages automatiques (source vaut auto) et ceux envoyés par l'API (source vaut api). Le numéro de téléphone de l'acheteur n'est jamais renvoyé.
Auth : clé plateforme avec whatsapp:read.
Paramètres de requête
| Param | Type | Défaut | Notes |
|---|---|---|---|
order_id | chiffres | aucun | Seulement les messages de cette commande. Toute valeur qui n'est pas composée de chiffres renvoie 400 bad_request. |
limit | int | 50 | De 1 à 200. |
cursor | string | aucun | Le next_cursor de la page précédente. Voir Pagination. |
Requête
curl 'https://api.dzbuild.app/v1/whatsapp/messages?order_id=6894' \
-H "Authorization: Bearer $DZ_KEY"
Réponse 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
}
}
| Champ | Signification |
|---|---|
event | Pour un message automatique, l'événement de commande qui l'a déclenché (received, confirmed, shipped, delivery_failed, desk_ready). Pour un message API, la clé du modèle envoyé. |
source | auto ou api. |
status | Voir le tableau ci-dessous. |
language | ar ou fr. |
template_name | Le nom du modèle enregistré chez WhatsApp. |
error_title | Pourquoi un message a été ignoré ou a échoué, sinon null. |
refunded | true une fois le message d'un envoi échoué recrédité. |
created_at | YYYY-MM-DD HH:MM:SS, heure du serveur. |
status | Signification |
|---|---|
queued | Payé, en attente. La plateforme l'envoie en une minute environ. |
sending | Envoi en cours vers WhatsApp. |
sent | Envoyé : accepté par WhatsApp. |
delivered | Livré sur le téléphone de l'acheteur. |
read | Lu par l'acheteur. |
failed | Échoué : WhatsApp n'a pas pu le délivrer. Le message est recrédité en quelques minutes et refunded passe à true. |
skipped | Non envoyé et non débité. error_title donne la raison. |
Un message ignoré porte l'une de ces raisons dans error_title :
error_title | Signification |
|---|---|
invalid_number | Numéro invalide : ce n'est pas un mobile algérien. |
suppressed | Numéro sans WhatsApp. |
template_not_approved | Modèle en attente de validation dans cette langue. |
empty_param | Données manquantes : il manque à la commande une valeur dont le modèle a besoin. |
POST /v1/orders/{id}/whatsapp
Met en file un modèle pour l'acheteur d'une commande et débite un message du solde. La plateforme l'envoie en une minute environ.
Auth : clé plateforme avec whatsapp:send. Nécessite Idempotency-Key.
Corps
| Champ | Type | Requis | Notes |
|---|---|---|---|
template | string | oui | Une key de GET /v1/whatsapp/templates, ou shipped, qui choisit shipped_home, shipped_desk ou desk_ready selon le type de livraison de la commande (domicile, bureau ou retrait). |
language | ar ou fr | non | Par défaut, la langue des messages choisie dans les réglages de l'addon, ou la langue de la boutique si aucune n'a été choisie. |
Ce que fait l'appel
- Il vérifie que l'addon est activé et que la commande appartient à la boutique. Une commande d'une autre boutique répond
404, comme une commande qui n'existe pas. - Il ignore les interrupteurs de messages automatiques de l'addon : vous pouvez envoyer un modèle que le marchand a désactivé pour les messages automatiques.
- Chaque modèle ne peut être envoyé qu'une fois par commande via l'API. Un second appel répond
409 already_sentavec l'idet lestatusdu message précédent. Seule exception : une tentative précédente ignorée, par exemple parce que le numéro était invalide et a été corrigé depuis sur la commande. L'appel réessaie alors. - Il vérifie le numéro, la validation du modèle et les données de la commande. Un problème répond
422avec la raison comme code d'erreur, enregistre un message ignoré et ne débite rien. - Il débite un message du solde. Un solde vide répond
402 no_creditet n'enregistre rien. - Il répond
202. Suivez le message avecGET /v1/whatsapp/messages?order_id=suivi de l'id de la commande. Un message refusé par WhatsApp passe àfailedet est recrédité.
Les messages API sont comptés à part des messages automatiques. Envoyer shipped_home par l'API n'empêche pas le message automatique « Commande en route » pour la même commande, et le message automatique ne bloque pas l'envoi par l'API. Chacun est payé.
Requête
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"}'
Réponse 202
template est la clé mise en file, avec shipped déjà résolu.
{
"data": {
"message_id": 4181,
"status": "queued",
"template": "shipped_home",
"language": "fr"
}
}
Erreurs
| HTTP | Code | Cause |
|---|---|---|
| 400 | bad_request | L'id de commande n'est pas composé de chiffres, le corps n'est pas un JSON valide, ou Idempotency-Key manque ou est mal formé. |
| 402 | no_credit | Le solde WhatsApp est vide. Rien n'a été enregistré. |
| 403 | forbidden | « Missing scope: whatsapp:send » |
| 403 | addon_not_active | L'addon WhatsApp Sender n'est pas activé sur la boutique. |
| 404 | not_found | Aucune commande avec cet id dans la boutique. |
| 409 | already_sent | Ce modèle a déjà été envoyé pour cette commande via l'API. |
| 422 | unknown_template | template n'est ni shipped ni une clé du catalogue. |
| 422 | invalid_language | language n'est ni ar ni fr. |
| 422 | invalid_number | Le téléphone de la commande n'est pas un mobile algérien. |
| 422 | suppressed | Le téléphone de la commande n'a pas de compte WhatsApp. |
| 422 | template_not_approved | Le modèle n'est pas encore validé dans cette langue. |
| 422 | empty_param | Il manque à la commande une valeur dont le modèle a besoin. |
| 422 | idempotency_key_reuse | La même Idempotency-Key a servi avec un autre corps. |
| 500 | send_failed | Le message n'a pas pu être mis en file. Réessayez avec la même clé. |
Voici un 409 already_sent.
{
"error": {
"code": "already_sent",
"message": "This template was already sent for this order",
"id": 4181,
"status": "delivered"
}
}
Réessais et Idempotency-Key
La première réponse à une clé est conservée 24 heures. Un réessai avec la même clé et le même corps renvoie cette réponse avec Idempotency-Replay: 1, y compris un 402, un 403 ou un 422. Après avoir rechargé le solde, activé l'addon ou corrigé la commande, réessayez avec une nouvelle Idempotency-Key : l'ancienne clé continue de renvoyer l'ancienne erreur. Un 202 rejoué veut dire qu'aucun second message n'a été mis en file.
La même clé avec un autre corps répond 422 idempotency_key_reuse. Une réponse 5xx ou 429 n'est jamais conservée : réessayez-la avec la même clé. Si le message avait en fait été mis en file avant l'erreur, le réessai répond 409 already_sent avec son id, et rien n'est débité deux fois. Voir Idempotence.
Limites connues
- Texte du délai de livraison.
shipped_homeporte le délai de livraison tel que le marchand l'a saisi dans les réglages de l'addon. Un message en français d'une boutique dont le délai est écrit en arabe affiche ce texte arabe au milieu du message français. Un délai écrit en chiffres, comme24-72h, se lit de la même façon dans les deux langues. - Envoi lent après une vérification de validation. Quand le statut de validation enregistré d'un modèle a plus de 10 minutes, l'envoi le relit auprès de WhatsApp avant de mettre le message en file. Cela arrive au plus une fois par modèle et par langue toutes les 10 minutes et peut retenir le
POSTjusqu'à 15 secondes : donnez à votre client HTTP un délai d'attente d'au moins 20 secondes.