API v2 (bêta)
Passer de la v1 à la v2
L'API v2 fait tout ce que fait la v1, avec des clés plus sûres, un seul style d'URL, de vrais codes de statut HTTP et des webhooks JSON signés. Cette page fait correspondre chaque endpoint et champ v1 à son équivalent v2. Les nouveautés propres à la v2 sont décrites dans la présentation.
Ce qui change partout#
- Clés : le
client_id+api_keyde la v1 deviennent un seul en-tête,Authorization: Bearer wbz_live_…. Créez une clé v2 sur Paramètres → Clés API, dans la carte Clés API v2, avec uniquement les scopes dont l'application a besoin. Les clés v1 ne fonctionnent pas sur la v2, et les clés v2 ne fonctionnent pas sur la v1. - Uniquement du JSON : pas de champs de formulaire. Les téléversements de fichiers passent par
POST /media(multipart) et sont envoyés parmedia_id. - Méthodes et URL :
GETpour lire,POSTpour créer,PATCHpour modifier,DELETEpour annuler ou supprimer, soushttps://wbiztool.com/api/v2. - Des codes de statut HTTP au lieu de
"status": 0ou1(voir Réponses et erreurs). - Les numéros de téléphone au format international avec
+, sanscountry_code. - Les heures au format ISO 8601 avec un décalage, au lieu de champs séparés pour la date, l'heure et le fuseau horaire.
- Les webhooks sont des endpoints que vous ajoutez une fois pour l'espace de travail, avec des événements JSON signés, au lieu d'une URL
webhooksur chaque message.
Endpoint par endpoint#
Les chemins v2 sont relatifs à https://wbiztool.com/api/v2.
L'envoi, champ par champ#
| v1 | v2 | Remarques |
|---|---|---|
client_id + api_key (corps ou Authorization: Bearer) | Authorization: Bearer wbz_live_… | Une nouvelle clé v2 ; pas de client_id |
phone + country_code | to.phone | Un seul numéro au format E.164 avec + : "9876543210" avec "country_code": "91" devient {"phone": "+919876543210"}. Aucun indicatif de pays n'est ajouté à votre place |
phone avec un @username (Telegram) | to.username | @name, t.me/name ou tg: suivi d'un identifiant, depuis un compte Telegram |
group_name | to.group | Le nom exact du groupe |
| (absent de la v1) | to.contact_id | Un contact enregistré |
whatsapp_client | from | L'id du numéro ; facultatif lorsqu'un seul numéro est connecté, comme avant |
msg (ou message) | text | Jusqu'à 3 000 caractères, comme avant |
msg_type 0, 1, 2 | aucun | Un message avec media est un message média ; media.type (image ou file) lorsque le lien ne l'indique pas |
img_url / file_url | media.url | Un lien http(s) public |
file (téléversement dans la même requête) | media.media_id | Téléversez d'abord, puis envoyez l'identifiant aussi souvent que vous le souhaitez |
file_name | media.file_name | Pour les fichiers |
date + time + timezone de schedule_msg/ | send_at | Une seule heure avec son décalage : 24/12/2026, 10:30 et Asia/Kolkata deviennent "2026-12-24T10:30:00+05:30" |
expire_after_seconds | expires_at | Une heure, pas une durée : maintenant plus les secondes, avec son décalage |
webhook | endpoints de webhook | Ajoutés une seule fois avec POST /webhooks, pour tous les messages de l'espace de travail |
msg_id dans la réponse | id | Le Message lui-même est renvoyé, avec son status |
Le même envoi en v1 et en v2 :
# v1
curl -X POST https://wbiztool.com/api/v1/send_msg/ \
-H "Authorization: Bearer YOUR_V1_KEY" \
-H "Content-Type: application/json" \
-d '{"whatsapp_client": 101, "msg_type": 1, "country_code": "91", "phone": "9876543210",
"img_url": "https://example.com/offers/diwali-sale.jpg", "msg": "Our Diwali sale starts today",
"expire_after_seconds": 3600}'
# v2
curl -X POST https://wbiztool.com/api/v2/messages \
-H "Authorization: Bearer $WBIZTOOL_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: diwali-9876543210" \
-d '{"from": 101, "to": {"phone": "+919876543210"},
"media": {"url": "https://example.com/offers/diwali-sale.jpg"}, "text": "Our Diwali sale starts today",
"expires_at": "2026-10-20T11:30:00+05:30"}'
Quelques comportements de la v1 disparaissent volontairement :
- Plus de devinette de l'indicatif du pays. La v1 ajoutait
country_codedevant un numéro (avec91, toujours devant un numéro à 10 chiffres). La v2 prend le numéro exactement tel qu'il est écrit avec+. - Plus de téléchargement de fichier lors de l'appel. La v1 récupérait
img_urletfile_urlpendant la requête. La v2 vérifie que le lien est public et récupère le fichier au moment de l'envoi du message ; un mauvais lien apparaît comme un messagefailed. - Plus de ligne en échec lors d'un refus. Quand la v1 refuse un envoi au-delà des 1 000 quotidiens, elle enregistre quand même le message comme échoué. La v2 n'enregistre rien lorsqu'elle refuse un envoi.
- Les champs inconnus sont refusés au lieu d'être ignorés.
Statuts#
Les nombres et les mots de la v1 deviennent un seul champ status :
| v1 | status v2 |
|---|---|
0 Created / Pending | queued, ou scheduled tant que son send_at est à venir |
1 Sent | sent, delivered ou read (les coches WhatsApp) |
2 Failed | failed |
3 Cancelled | cancelled |
4 Expired | expired |
Les événements webhook sont message.sent, message.failed, message.cancelled et message.expired, correspondant aux SENT, FAILED, CANCELLED et EXPIRED de la v1.
Réponses et erreurs#
La v1 répond à de nombreuses erreurs avec le code HTTP 200 ou 400 et "status": 0, et au succès avec "status": 1. La v2 utilise le code de statut HTTP :
- Le succès est
200,201(créé) ou202(mis en file d'attente), et le corps est l'objet lui-même, comme le Message. Il n'y a pas d'enveloppestatus: 1. - Les erreurs sont des
4xxou5xxavec une seule forme :{"error": {"code", "message", "field", "docs", "request_id"}}. Basez-vous surcode, pas sur lemessageen anglais. Chaque code se trouve sur la page des erreurs.
# v1
result = response.json()
if result.get("status") == 1:
msg_id = result["msg_id"]
# v2
if response.status_code == 202:
message_id = response.json()["id"]
else:
error = response.json()["error"]
if error["code"] == "number_daily_cap_reached":
... # try again tomorrow
Quelques messages v1 et leurs codes v2 :
| Message v1 | Code v2 |
|---|---|
Auth Error: invalid api key | 401 invalid_api_key, api_key_revoked ou api_key_expired |
Invalid phone number / Invalid Contact Number "…" | 422 invalid_phone |
Msg cant be null | 400 text_required |
Message length is too long | 400 text_too_long |
Invalid whatsapp client | 422 number_not_found |
Invalid whatsapp client id. | 422 from_required |
Not enough credits | 402 no_credits |
Daily limit reached: … | 429 number_daily_cap_reached |
Demo Account can not access apis | 403 demo_account |
Account Disabled | 403 account_disabled |
Invalid JSON format: … | 400 invalid_json |
Webhooks#
En v1, chaque message peut porter une URL webhook qui reçoit un msg_id=…&status=SENT encodé comme un formulaire. En v2 :
- Ajoutez un endpoint une seule fois avec
POST /webhookset conservez sonsecret. - Il reçoit des événements JSON pour tous les messages de l'espace de travail, avec le Message complet dans
data.message. Rapprochez-les de vos données grâce àdata.message.id. - Vérifiez la signature : le même principe que pour la v1 (
WbizTool-Timestamp,WbizTool-Signature: v1=…), mais avec le secret propre à l'endpoint au lieu de celui de l'espace de travail. - Écartez les doublons avec
WbizTool-Event-Id. Les nouvelles tentatives se poursuivent pendant environ 23 heures, et non 4 essais en quelques minutes comme en v1, et les réponses4xxsont aussi retentées.
Les événements de connexion de la v1 (webhook_url sur whatsapp/connect/) n'ont pas encore d'événement v2 : interrogez plutôt GET /numbers/{id}.
Liste de contrôle#
Créez une clé v2 par application
Sur Paramètres → Clés API, avec uniquement les scopes dont elle a besoin. Essayez-la d'abord avec une clé de test, qui vérifie tout et n'envoie rien.
Modifiez les requêtes
Nouvelles URL et méthodes, corps JSON,
to/from/text/media, numéros de téléphone avec+, heures avec décalage. Ajoutez uneIdempotency-Keyà chaque envoi.Modifiez la gestion des erreurs
Vérifiez le statut HTTP, puis
error.code. Gérez429en attendant la durée deRetry-After.Migrez les webhooks
Ajoutez un endpoint, vérifiez les signatures avec son secret, et écartez les doublons grâce à l'identifiant de l'événement.
Basculez et révoquez
Une fois que l'application tourne sur la v2, supprimez sa clé v1 sur Paramètres → Clés API.
