Aller au contenu
WbizTool

API v2 (bêta)

Messages

Envoyez un message maintenant ou à une heure fixée, à un numéro de téléphone, un groupe WhatsApp, un contact enregistré ou un nom d'utilisateur Telegram. Envoyez le même message jusqu'à 1 000 destinataires en une seule requête, lisez l'historique, suivez le statut d'un message et annulez-le tant qu'il attend.

OpérationEndpointScope
Envoyer un messagePOST /api/v2/messagesmessages:send
Envoyer à plusieurs destinatairesPOST /api/v2/messages/batchmessages:send
Lister les messagesGET /api/v2/messagesmessages:read
Obtenir un messageGET /api/v2/messages/{id}messages:read
Annuler un messageDELETE /api/v2/messages/{id}messages:send

Les clés, les erreurs, Idempotency-Key et les limites fonctionnent comme décrit dans la présentation de l'API v2. Pour savoir quand un message est envoyé ou échoue sans interroger l'API en boucle, ajoutez un endpoint de webhook.

Envoyer un message#

POSThttps://wbiztool.com/api/v2/messages

Corps: JSON (application/json)

Le message est mis en file d'attente et la réponse arrive avant son départ, avec le code HTTP 202 et le Message au statut queued (ou scheduled avec un send_at futur). Suivez-le avec Obtenir un message ou un webhook.

curl -X POST https://wbiztool.com/api/v2/messages \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1042-ready" \
  -d '{
    "from": 101,
    "to": { "phone": "+919876543210" },
    "text": "Hi Asha, your order #1042 is ready."
  }'

Réponse (202) :

{
  "id": 9817263,
  "status": "queued",
  "from": { "id": 101, "phone": "919800000000", "platform": "whatsapp" },
  "to": { "phone": "+919876543210", "contact_id": 991 },
  "text": "Hi Asha, your order #1042 is ready.",
  "media": null,
  "send_at": null,
  "expires_at": null,
  "created_at": "2026-10-18T10:15:02.311Z",
  "sent_at": null,
  "error": null
}

Corps

toobjectobligatoire

Qui le reçoit : exactement un des champs phone, group, contact_id ou username. Voir Destinataires.

frominteger or nullObligatoire sauf si l'espace de travail a un seul numéro connecté

L'id du numéro qui l'envoie, obtenu avec Lister les numéros. S'il est omis, le seul numéro connecté l'envoie : un seul numéro WhatsApp connecté est utilisé même si un compte Telegram est aussi connecté, et un compte Telegram seulement quand aucun numéro WhatsApp n'est connecté. Un numéro déconnecté est accepté : ses messages attendent qu'il se reconnecte.

textstringObligatoire sauf si un média est envoyé

Le message, jusqu'à 3 000 caractères. Avec media, c'est la légende et il peut être omis. La mise en forme WhatsApp fonctionne : *bold*, _italic_, ~strikethrough~. En JSON, écrivez les retours à la ligne sous la forme \n.

mediaobject or nullfacultatif

Une image ou un fichier à envoyer. Voir Médias.

send_atstring or nullfacultatif

Envoyer à cette heure plutôt que maintenant : ISO 8601 avec son décalage, comme 2026-10-20T09:30:00+05:30. Elle doit être dans le futur. Voir Planification et expiration.

expires_atstring or nullfacultatif

Ne pas envoyer après cette heure : le message devient alors expired. ISO 8601 avec son décalage, dans le futur et après send_at.

En-têtes

Authorizationheaderobligatoire

Bearer wbz_live_…, une clé avec le scope messages:send.

Idempotency-Keyheaderfacultatif

N'importe quelle chaîne unique, pour qu'une nouvelle tentative n'envoie jamais un deuxième message. Voir Idempotency-Key.

Erreurs à l'envoi#

HTTPCodeQuand
400validation_failedUn champ manque, a le mauvais type ou est inconnu ; to n'a aucun de ses champs ou en a plusieurs ; media a à la fois url et media_id, ou aucun des deux ; expires_at n'est pas après send_at
400text_requiredNi text ni media
400text_too_longtext dépasse 3 000 caractères
400invalid_datetimesend_at ou expires_at n'est pas au format ISO 8601 avec un décalage
402no_creditsL'espace de travail n'a plus de messages sur son forfait
403number_not_allowedLa clé est limitée à d'autres numéros
403account_disabledLe compte du propriétaire de l'espace de travail est désactivé
422invalid_phoneto.phone n'est pas un numéro de téléphone au format international avec +
422invalid_usernameto.username n'est pas un nom d'utilisateur Telegram, un lien ou un identifiant tg:
422username_needs_telegramto.username avec un numéro WhatsApp comme from
422contact_not_foundAucun contact avec ce to.contact_id
422media_not_foundAucun fichier avec ce media.media_id
422invalid_media_urlmedia.url n'est pas un lien http(s) public
422time_in_pastsend_at ou expires_at est déjà passé
422number_not_foundfrom n'est pas un numéro de cet espace de travail
422from_requiredPas de from, et l'espace de travail n'a aucun numéro connecté ou en a plusieurs
422message_rejectedLe message n'a pas pu être mis en file d'attente ; message indique pourquoi
429number_daily_cap_reachedLe numéro a envoyé 1 000 messages au cours des dernières 24 heures

Un envoi refusé ne laisse aucune trace : aucun message n'est enregistré, il n'y a donc rien à annuler. Les erreurs possibles sur n'importe quelle requête (clés, scopes, limites de débit, Idempotency-Key) se trouvent sur la page des erreurs.

Envoyer à plusieurs destinataires#

POSThttps://wbiztool.com/api/v2/messages/batch

Corps: JSON (application/json)

Envoie le même message jusqu'à 1 000 destinataires. Le corps est le même que pour Envoyer un message, sauf que to est une liste de destinataires.

  • Tout ou rien. Chaque destinataire est vérifié avant que quoi que ce soit ne soit mis en file d'attente, et toute la liste doit tenir dans les messages restants du forfait et dans la marge du numéro d'envoi pour les prochaines 24 heures. Si un destinataire est incorrect, rien n'est mis en file d'attente, et field l'indique, par exemple to[3].phone.
  • Le même destinataire indiqué deux fois reçoit un seul message.
  • La réponse est 202 avec data : un Message par destinataire, dans l'ordre de to.
curl -X POST https://wbiztool.com/api/v2/messages/batch \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: opening-hours-2026-10-20" \
  -d '{
    "from": 101,
    "to": [
      { "phone": "+919876543210" },
      { "phone": "+447700900123" },
      { "group": "Bakery staff" }
    ],
    "text": "We open at 10 tomorrow."
  }'

Réponse (202), un Message par destinataire ; le deuxième et le troisième ressemblent au premier, avec to égal à {"phone": "+447700900123", …} et {"group": "Bakery staff", …} :

{
  "data": [
    {
      "id": 9817264,
      "status": "queued",
      "from": { "id": 101, "phone": "919800000000", "platform": "whatsapp" },
      "to": { "phone": "+919876543210", "contact_id": 991 },
      "text": "We open at 10 tomorrow.",
      "media": null,
      "send_at": null,
      "expires_at": null,
      "created_at": "2026-10-19T16:02:40.118Z",
      "sent_at": null,
      "error": null
    }
  ]
}

Erreurs à l'envoi d'un lot#

Les mêmes que pour l'envoi d'un message, avec la position du destinataire dans field (to[0].phone), et en plus :

HTTPCodeQuand
400too_many_recipientsto a plus de 1 000 entrées
400validation_failedto est vide ou n'est pas une liste
402no_creditsLa liste ne tient pas dans les messages restants : requested et remaining indiquent de combien
429number_daily_cap_reachedLa liste ne tient pas dans la marge du numéro pour les prochaines 24 heures : requested et room indiquent combien

Lister les messages#

GEThttps://wbiztool.com/api/v2/messages

Les messages de l'espace de travail des 90 derniers jours, les plus récents d'abord, par pages. Cela inclut les messages envoyés depuis le tableau de bord, les campagnes, les rappels, les intégrations et l'API v1, pas seulement ceux de l'API v2. Une clé limitée à certains numéros ne voit que leurs messages.

Paramètres de requête

numberintegerfacultatif

Uniquement les messages de cet id de numéro.

statusstringfacultatif

Uniquement les messages avec ce statut : queued, scheduled, sent, delivered, read, failed, cancelled ou expired.

sincestringfacultatif

Uniquement les messages créés à cette heure ou après (ISO 8601 avec décalage).

untilstringfacultatif

Uniquement les messages créés avant cette heure (ISO 8601 avec décalage).

limitintegerfacultatif

Messages par page, de 1 à 100 (25 par défaut).

cursorstringfacultatif

Le next_cursor de la page précédente, avec les mêmes filtres.

Les filtres se combinent. Dans une chaîne de requête, écrivez le + d'un décalage sous la forme %2B (un + simple arrive comme une espace, qui est aussi lue comme +), ou utilisez Z.

curl -G https://wbiztool.com/api/v2/messages \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY" \
  --data-urlencode "status=failed" \
  --data-urlencode "since=2026-10-01T00:00:00+05:30" \
  --data-urlencode "limit=100"

La réponse est {"data": [Message, …], "next_cursor": "…" or null}.

Erreurs de la liste#

HTTPCodeQuand
400validation_failednumber n'est pas un identifiant de numéro, status n'est pas l'un des statuts, ou limit n'est pas entre 1 et 100
400invalid_datetimesince ou until n'est pas au format ISO 8601 avec un décalage
400invalid_cursorLe curseur est endommagé ou a été créé avec d'autres filtres

Obtenir un message#

GEThttps://wbiztool.com/api/v2/messages/{id}

Un message et son statut actuel.

curl https://wbiztool.com/api/v2/messages/9817263 \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY"

Réponse (200), un message qui a été distribué :

{
  "id": 9817263,
  "status": "delivered",
  "from": { "id": 101, "phone": "919800000000", "platform": "whatsapp" },
  "to": { "phone": "+919876543210", "contact_id": 991 },
  "text": "Hi Asha, your order #1042 is ready.",
  "media": null,
  "send_at": null,
  "expires_at": null,
  "created_at": "2026-10-18T10:15:02.311Z",
  "sent_at": "2026-10-18T10:15:09.870Z",
  "error": null
}

Un message qui n'existe pas, qui appartient à un autre espace de travail ou (pour une clé limitée à certains numéros) qui a été envoyé depuis un autre numéro répond 404 message_not_found.

Annuler un message#

DELETEhttps://wbiztool.com/api/v2/messages/{id}

Annule un message qui attend encore (queued ou scheduled), quelle que soit son origine. La réponse est 200 avec le Message, désormais au statut cancelled. Un endpoint de webhook reçoit message.cancelled.

Un message déjà parti ne peut pas être rappelé. Un message que le numéro d'envoi est en train de prendre en charge à ce moment-là peut encore partir : vérifiez donc son statut ensuite si cela compte.

curl -X DELETE https://wbiztool.com/api/v2/messages/9817263 \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY"

Erreurs à l'annulation#

HTTPCodeQuand
404message_not_foundAucun message de ce type pour cette clé
409not_cancellableIl n'attend plus ; status dans l'erreur indique son état actuel, par exemple sent

L'objet Message#

Chaque opération de cette page répond avec des objets Message, et les événements webhook en contiennent un dans data.message.

ChampTypeDescription
idintegerL'identifiant du message. Utilisez-le pour obtenir ou annuler le message.
statusstringOù il en est. Voir Statuts.
fromobjectLe numéro d'envoi : id, phone (ses chiffres avec l'indicatif du pays, sans +) et platform (whatsapp ou telegram).
toobjectLe destinataire : phone (avec +), group ou username, et contact_id, le contact enregistré auquel il a été envoyé. Un numéro de téléphone ou un groupe qui reçoit un message pour la première fois est enregistré comme contact. (contact_id ne vaut null que pour un message de test vers un numéro non enregistré.)
textstringLe texte ou la légende ; "" s'il n'y en a pas.
mediaobject or nulltype (image ou file), url et file_name (null pour les images). L'url peut être un lien valable pendant une durée limitée ; ne le conservez pas.
send_atstring or nullL'heure pour laquelle il est planifié, ou null pour « maintenant ».
expires_atstring or nullL'heure après laquelle il n'est plus envoyé, ou null.
created_atstringQuand il a été créé.
sent_atstring or nullQuand il est parti, une fois parti (sent, delivered ou read).
errorobject or nullPour un message failed ou expired, message indique pourquoi, par exemple File exceeds WhatsApp size limit (16MB max). null sinon.

Statuts#

StatutSignification
queuedEn attente d'envoi.
scheduledEn attente de son send_at.
sentEnvoyé depuis votre numéro (une coche dans WhatsApp).
deliveredDistribué sur le téléphone du destinataire (deux coches).
readLu par le destinataire (coches bleues).
failedIl n'a pas pu être envoyé ; error.message indique pourquoi.
cancelledAnnulé avant son départ : avec Annuler un message, depuis le tableau de bord, ou parce que son numéro ou sa campagne a été supprimé.
expiredNon envoyé avant son expires_at.

queued et scheduled peuvent être annulés. sent peut encore devenir delivered puis read. failed, cancelled, expired et read sont définitifs. Les webhooks signalent sent, failed, cancelled et expired ; pour voir delivered et read, obtenez le message.

Destinataires#

to prend exactement un de ces champs :

ChampExempleQui le reçoit
phone{"phone": "+919876543210"}Un numéro de téléphone au format international avec + (E.164). Les espaces et les tirets sont acceptés.
group{"group": "Bakery staff"}Un groupe WhatsApp dont fait partie le numéro d'envoi, par son nom exact (jusqu'à 200 caractères).
contact_id{"contact_id": 991}Un contact enregistré dans l'espace de travail, par son identifiant (le contact_id d'un message précédent, par exemple). Le message part vers le numéro ou le groupe de ce contact.
username{"username": "@asha_bakes"}Un utilisateur Telegram : @name, un lien t.me/name, ou tg: suivi d'un identifiant d'utilisateur. Uniquement depuis un compte Telegram : indiquez-en un comme from (ou n'en ayez qu'un seul connecté).

Les envois vers un groupe ou sur Telegram exigent que le numéro d'envoi fasse partie de ce groupe ou puisse joindre cet utilisateur ; un problème à ce niveau apparaît comme un message failed, pas comme une erreur au moment de l'envoi.

Médias#

media envoie une image ou un fichier, avec text comme légende. Indiquez exactement un des champs url ou media_id :

media.urlstringurl ou media_id

Un lien public http ou https vers le fichier, jusqu'à 1 000 caractères. Les liens vers des adresses privées ou locales sont refusés avec invalid_media_url.

media.media_idintegerurl ou media_id

Un fichier du Répertoire média de l'espace de travail, obtenu avec Téléverser un fichier. Téléversez un fichier une fois et envoyez-le aussi souvent que vous le souhaitez.

media.typestringfacultatif

image ou file. S'il est omis, un lien se terminant par .jpg, .jpeg, .png, .gif ou .webp est envoyé comme image et tout le reste comme fichier ; un media_id utilise le type avec lequel le fichier a été téléversé.

media.file_namestringfacultatif

Pour un file : le nom que voit le destinataire, comme invoice-1042.pdf (jusqu'à 100 caractères). S'il est omis, le nom vient du lien ou du fichier téléversé. Son extension détermine la façon dont le fichier est envoyé : incluez-en donc une. Ignoré pour les images.

{
  "to": { "phone": "+919876543210" },
  "text": "Your invoice for order #1042",
  "media": { "url": "https://example.com/invoices/1042.pdf", "type": "file", "file_name": "invoice-1042.pdf" }
}

Le fichier est récupéré au moment de l'envoi du message, pas lors de l'appel à l'API : un lien cassé ou un fichier trop volumineux apparaît donc comme un message failed avec la raison dans error.message. Les règles de taille et de type sont celles de la v1 : voir Envoyer des images et des fichiers.

Planification et expiration#

  • send_at planifie le message. Il reste scheduled jusque-là et peut être annulé tant qu'il n'est pas parti. Écrivez l'heure avec son décalage : 2026-10-20T09:30:00+05:30 signifie 09:30 en Inde. Pour les messages qui se répètent, utilisez les rappels.
  • expires_at est une échéance : si le message n'est pas parti d'ici là (parce que le numéro était déconnecté, par exemple), il devient expired au lieu de partir en retard. Utilisez-le pour les codes à usage unique, les heures de livraison et les offres. Une tâche en arrière-plan le marque comme expiré au moins 30 secondes après l'échéance : ne comptez donc pas sur des échéances de moins d'une minute.
  • Les deux doivent être dans le futur, et expires_at doit être après send_at.

Voir aussi#

  • Webhooks : recevez message.sent et message.failed au lieu d'interroger l'API en boucle.
  • Médias : téléversez des fichiers à envoyer par media_id.
  • Numéros : l'id à utiliser comme from.
  • Erreurs