Aller au contenu
WbizTool

API v2 (bêta)

API v2

L'API v2 est la nouvelle API REST de WbizTool : une clé par application avec uniquement l'accès dont elle a besoin, des URL orientées ressources, de vrais codes de statut HTTP, des webhooks JSON signés et des nouvelles tentatives sans risque. Cette page décrit ce que toutes les requêtes ont en commun. Les pages des ressources décrivent chaque endpoint.

URL de base#

https://wbiztool.com/api/v2

Les chemins n'ont pas de barre oblique finale (/api/v2/messages), mais elle est acceptée aussi. Une adresse qui n'existe pas répond 404 avec le code not_found.

Exemple rapide#

Vérifiez votre clé avec GET /me. Cela fonctionne avec n'importe quel scope et n'envoie rien :

curl https://wbiztool.com/api/v2/me \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY"
{
  "workspace": { "id": 5012, "name": "Acme Bakery" },
  "key": {
    "id": 7,
    "name": "Order system",
    "mode": "live",
    "scopes": ["messages:send", "messages:read"],
    "limited_to_numbers": false,
    "number_ids": [],
    "expires_at": null
  },
  "plan": { "name": "Starter" },
  "limits": {
    "requests_per_minute": 60,
    "requests_per_day": 10000,
    "messages_per_number_per_day": 1000,
    "messages_remaining": null
  }
}

messages_remaining vaut null lorsque le forfait envoie des messages illimités. plan vaut null lorsque l'espace de travail n'a pas de forfait actif.

Clés#

Envoyez votre clé dans l'en-tête Authorization de chaque requête :

Authorization: Bearer wbz_live_…

Il n'y a pas de client_id : la clé désigne son espace de travail. Une clé v2 commence par wbz_live_ ou wbz_test_, suivi de 38 lettres et chiffres. Les clés v1 ne fonctionnent pas sur la v2 (elles reçoivent v1_key_on_v2), et les clés v2 ne fonctionnent pas sur la v1.

Créer une clé#

Les propriétaires créent les clés sur Paramètres → Clés API, dans la carte Clés API v2 : cliquez sur Créer une clé v2, puis choisissez :

  • Nom : l'application qui l'utilisera, jusqu'à 50 caractères.
  • Type de clé : Réelle envoie de vrais messages ; Test vérifie tout et n'envoie rien (voir Mode test).
  • Ce qu'elle peut faire : les scopes, ou Tout.
  • Numéros qu'elle peut utiliser : tous les numéros, y compris ceux ajoutés plus tard, ou seulement certains (voir Clés limitées à certains numéros).
  • Expiration : jamais, ou dans 30 jours, 90 jours ou 1 an.

La clé n'est affichée qu'une fois. Copiez-la tout de suite et conservez-la sur votre serveur, par exemple dans une variable d'environnement. WbizTool n'en garde qu'une empreinte (hash) et ses quatre derniers caractères : une clé perdue ne peut donc pas être réaffichée. Révoquez-la et créez-en une nouvelle.

Un espace de travail peut avoir jusqu'à 10 clés v2 non révoquées. La carte affiche pour chaque clé ses quatre derniers caractères, ses scopes, ses numéros, son expiration, ainsi que la date et l'adresse IP de sa dernière utilisation. Révoquer arrête une clé immédiatement, et avec elle les endpoints de webhook qu'elle a créés. Une clé dont la date d'expiration est passée reçoit api_key_expired.

Scopes#

Chaque clé ne peut faire que ce que ses scopes autorisent. Une requête en dehors de ceux-ci répond 403 avec missing_scope, et required_scope dans l'erreur indique celui qu'il faut.

ScopeCe qu'il autorise
messages:sendEnvoyer des messages et des lots, et annuler des messages en attente : POST /messages, POST /messages/batch, DELETE /messages/{id}
messages:readLire les messages et leur statut (GET /messages, GET /messages/{id}), et gérer les endpoints de webhook
remindersCréer, lister, modifier, mettre en pause et supprimer des rappels
numbersLister les numéros, voir leur connexion et connecter des numéros WhatsApp
mediaTéléverser, lister et supprimer des fichiers du Répertoire média
contactsVérifications de numéros (les endpoints de contacts viendront plus tard)

GET /me ne demande aucun scope particulier. Envoyer à un contact enregistré avec to.contact_id ne demande que messages:send.

Clés limitées à certains numéros#

Une clé limitée à certains numéros ne fonctionne qu'avec eux :

  • Elle n'envoie que depuis ces numéros, et ne liste, ne lit et n'annule que leurs messages. Un autre numéro dans from reçoit number_not_allowed.
  • GET /numbers ne liste que ces numéros. Elle peut les reconnecter, mais ne peut pas ajouter de nouveau numéro.
  • Elle ne voit et ne modifie que les rappels qui envoient depuis ces numéros, et un nouveau rappel doit indiquer l'un d'eux comme from.
  • Elle ne peut pas du tout gérer les endpoints de webhook, car ceux-ci reçoivent les événements de tout l'espace de travail.

GET /me indique limited_to_numbers et les number_ids que la clé peut utiliser.

Requêtes#

  • JSON en entrée et en sortie. Envoyez les corps en Content-Type: application/json. La seule exception est le téléversement d'un fichier, en multipart/form-data. Chaque réponse est en JSON, erreurs comprises.
  • Les noms de champs sont en snake_case, et les champs inconnus sont refusés : une faute de frappe comme txt répond validation_failed au lieu d'être ignorée.
  • Les numéros de téléphone sont au format international avec + (E.164), par exemple +919876543210. Les espaces et les tirets sont acceptés ; un numéro sans + est refusé avec invalid_phone.
  • Les heures sont au format ISO 8601 avec un décalage, par exemple 2026-10-20T09:30:00+05:30 ou 2026-10-20T04:00:00Z. Une heure sans décalage est refusée avec invalid_datetime. Les heures des réponses sont en UTC et se terminent par Z, sauf le next_run_at d'un rappel, qui est dans le fuseau horaire du rappel.
  • Les identifiants sont des entiers, comme l'id d'un numéro (from lors d'un envoi) ou l'id d'un message.
  • Les codes de statut disent ce qu'ils veulent dire : 200 OK, 201 créé, 202 accepté (mis en file d'attente), 400 la requête est incorrecte, 401 la clé est incorrecte, 402 plus de messages, 403 non autorisé, 404 introuvable, 409 conflit, 413 trop volumineux, 415 mauvais type de contenu, 422 une valeur est inutilisable, 429 trop de requêtes, 5xx problème de notre côté.

Les réponses portent Cache-Control: no-store.

Erreurs#

Toutes les erreurs ont la même forme :

{
  "error": {
    "code": "invalid_phone",
    "message": "This is not a valid phone number. Write it in international format with +, e.g. +919876543210.",
    "field": "to.phone",
    "docs": "https://wbiztool.com/docs/api/v2/errors/#invalid_phone",
    "request_id": "req_4f1c2a9b8e7d6c5b4a392817"
  }
}
  • code est stable : c'est sur lui que votre code doit se baser. message est un texte en anglais destiné au développeur et peut changer.
  • field nomme le champ concerné par l'erreur (to.phone, to[3].phone, schedule.cron), ou vaut null.
  • docs renvoie vers le code sur la page des erreurs.
  • request_id est identique à l'en-tête X-Request-Id. Indiquez-le si vous nous contactez.
  • Certaines erreurs ajoutent des détails, par exemple status pour not_cancellable ou used et limit pour storage_full. Lorsqu'une requête a plusieurs problèmes, errors liste les autres, chacun avec field et message.

Chaque code, son statut HTTP et la marche à suivre se trouvent sur la page des erreurs.

Idempotency-Key#

Une erreur réseau ou un délai dépassé vous laisse dans le doute : la requête a-t-elle abouti ? Envoyez un en-tête Idempotency-Key avec un POST qui crée quelque chose, et vous pourrez le renvoyer sans risque :

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 '{"to": {"phone": "+919876543210"}, "text": "Hi Asha, your order #1042 is ready."}'
  • La valeur vous appartient : n'importe quelle chaîne unique de 1 à 255 caractères imprimables, comme un UUID ou votre propre numéro de commande. Créez-en une nouvelle pour chaque nouvelle requête, et ne la réutilisez que pour une nouvelle tentative de la même requête.
  • Une nouvelle tentative reçoit la première réponse avec l'en-tête Idempotent-Replayed: true. Rien n'est fait deux fois : pas de deuxième message, rappel, fichier ou endpoint.
  • Les clés durent 24 heures à partir de la première requête, et appartiennent à votre clé API : une autre clé API de l'espace de travail peut utiliser la même valeur sans conflit.
  • Même clé, requête différente : une requête avec une clé déjà utilisée pour une autre méthode, un autre chemin ou un autre corps répond 422 idempotency_key_reused.
  • Toujours en cours : tant que la première requête avec la clé est encore en traitement, une nouvelle tentative répond 409 idempotency_in_progress avec Retry-After: 1. Attendez un instant et renvoyez-la.
  • Les erreurs ne sont pas conservées. Si la première requête a répondu par une erreur, rien n'est enregistré : corrigez la requête et renvoyez-la avec la même clé.
  • Les secrets ne sont pas rejoués. Le rejeu d'un POST /webhooks omet le secret de l'endpoint, qui n'est affiché que dans la première réponse.

Cela fonctionne sur POST /messages, POST /messages/batch, POST /numbers, POST /reminders, POST /media, POST /number-checks et POST /webhooks, et reste facultatif sur chacun. Les autres requêtes ignorent l'en-tête. Une valeur vide ou trop longue répond 400 invalid_idempotency_key.

Limites de débit#

Chaque clé peut faire 60 requêtes par minute et 10 000 requêtes par jour. Ce sont des fenêtres fixes : la fenêtre d'une minute commence au début de chaque minute, celle d'un jour à 00:00 UTC. Au-delà d'une limite, la requête répond 429 rate_limited.

Les réponses aux requêtes avec une clé valide portent ces en-têtes :

En-têteSignification
RateLimit-LimitRequêtes autorisées dans la fenêtre en cours (60, ou 10000 une fois la limite journalière atteinte)
RateLimit-RemainingRequêtes restantes dans cette fenêtre
RateLimit-ResetSecondes avant que cette fenêtre ne recommence
RateLimit-PolicyLes deux limites : 60;w=60, 10000;w=86400
Retry-AfterSur un 429 : secondes à attendre avant de réessayer

En dehors de ces limites :

  • Clés incorrectes : plus de 30 requêtes par minute avec une clé incorrecte depuis une même adresse IP répondent 429 too_many_auth_failures avec Retry-After: 60.
  • Messages par numéro : un numéro envoie au plus 1 000 messages en 24 heures (usage raisonnable). Un envoi au-delà répond 429 number_daily_cap_reached.

Pagination#

Les listes qui peuvent grandir (GET /messages, /reminders, /media, /number-checks et les /results d'une vérification) arrivent par pages, les plus récents d'abord :

{
  "data": [ … ],
  "next_cursor": "eyJpZCI6OTgxNzI2MywidCI6IjIwMjYtMTAtMThUMTA6MTU6MDIuMzExWiIsImYiOiI0NGIxMzZmYTM1NWIifQ"
}
  • limit fixe la taille de la page, de 1 à 100 (25 par défaut).
  • Pour obtenir la page suivante, envoyez la même requête avec cursor égal au next_cursor de la page précédente. next_cursor vaut null sur la dernière page.
  • Gardez les mêmes filtres : un curseur utilisé avec d'autres filtres répond 400 invalid_cursor. Recommencez sans curseur.
  • Traitez le curseur comme une chaîne opaque. Les éléments ajoutés pendant que vous parcourez les pages ne décalent pas les pages.
curl "https://wbiztool.com/api/v2/messages?limit=100&cursor=eyJpZCI6OTgxNzI2MywidCI6..." \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY"

GET /numbers et GET /webhooks renvoient tout dans une seule liste data.

Identifiants de requête#

Chaque réponse, erreurs comprises, a un en-tête X-Request-Id comme req_4f1c2a9b8e7d6c5b4a392817. Les erreurs portent la même valeur dans request_id. Enregistrez-le dans vos logs et indiquez-le si vous nous contactez : il nous permet de retrouver la requête dans nos logs, qui enregistrent l'identifiant de votre clé mais jamais la clé elle-même.

Si vous envoyez votre propre X-Request-Id (jusqu'à 100 caractères imprimables), il revient dans X-Client-Request-Id, pour que vous puissiez rapprocher les réponses de vos propres logs.

Mode test#

Une clé de test (wbz_test_…) vous permet de construire et de tester une intégration sans rien envoyer. Créez-en une sur Paramètres → Clés API avec Type de clé : Test. GET /me affiche "mode": "test".

Ce qu'une clé de test fait comme une clé réelle :

  • POST /messages et POST /messages/batch vérifient tout ce que vérifie un envoi réel : le destinataire, le texte, les médias, send_at et expires_at, le numéro d'envoi, ainsi que les scopes et les numéros de la clé. Les mêmes erreurs reçoivent les mêmes réponses.
  • Les scopes, les numéros, les limites de débit et Idempotency-Key fonctionnent de la même façon.
  • Chaque lecture du reste de l'espace de travail (GET /me, /numbers, /reminders, /media, /number-checks, /webhooks) montre ses vraies données, en lecture seule.

Ce qui change :

  • Rien n'est envoyé. Un envoi de test est conservé comme message de test, et ne consomme ni les messages du forfait ni les 1 000 messages quotidiens du numéro : il ne reçoit donc jamais no_credits ni number_daily_cap_reached.
  • Son statut avance tout seul : queued, puis sent 5 secondes plus tard et delivered 15 secondes après sa création (à compter de send_at pour un message planifié). Un message dont l'expires_at arrive avant son envoi devient expired. Les messages de test ne deviennent jamais read ni failed.
  • Une clé de test ne voit que ses propres messages de test. GET /messages et GET /messages/{id} les montrent, et rien d'autre, et DELETE /messages/{id} en annule un tant qu'il est queued ou scheduled. Les clés réelles ne voient jamais les messages de test. Le filtre status de GET /messages n'est pas pris en charge pour les clés de test et répond test_mode_unsupported ; number, since et until fonctionnent.
  • Les autres écritures sont refusées avec 403 test_mode_unsupported : connecter un numéro, créer, modifier ou supprimer des rappels, téléverser ou supprimer des médias, lancer une vérification de numéros, et ajouter, supprimer, renouveler ou tester des endpoints de webhook.
  • Aucun événement webhook n'est envoyé pour les messages de test.
  • Les messages de test sont conservés 30 jours.

Ressources#

  • Messages : envoyer maintenant ou plus tard, envoyer jusqu'à 1 000 destinataires, lire l'historique, annuler.
  • Numéros : lister vos numéros WhatsApp et vos comptes Telegram, et connecter un numéro WhatsApp par code QR ou code d'association.
  • Rappels : des messages récurrents selon un planning cron.
  • Médias : téléverser des fichiers une fois et les envoyer par media_id.
  • Vérifications de numéros : savoir quels numéros sont sur WhatsApp.
  • Webhooks : des événements signés quand un message est envoyé, échoue, est annulé ou expire.
  • Erreurs : tous les codes d'erreur.
  • Passer de la v1 à la v2 : chaque endpoint et champ v1, et son équivalent v2.