Erreurs, limites et idempotence
Chaque erreur de l’API WhatSetter a la même forme et un code stable. Cette page les liste toutes, décrit les en-têtes qui traduisent tes limites, et dit quoi faire quand un appel échoue.
L’enveloppe d’erreur
Section intitulée « L’enveloppe d’erreur »{ "error": { "code": "insufficient_scope", "message": "This API key is missing the \"messages:send\" scope." }}codeest stable : fais tes branchements dessus.messageest pour les humains et peut changer. Logue-le, ne le parse pas.- Le statut HTTP correspond au code (voir le tableau). Les réponses de succès utilisent
{ "data": … }, et les listes ajoutent{ "pagination": { "has_more", "next_cursor" } }.
Les codes d’erreur
Section intitulée « Les codes d’erreur »| HTTP | code |
Quand ça arrive | Quoi faire |
|---|---|---|---|
| 400 | validation_error |
Le chemin contient un encodage d’URL invalide (par exemple %ZZ). |
Corrige l’URL. |
| 401 | missing_api_key |
Ni en-tête Authorization: Bearer, ni en-tête X-Api-Key. |
Envoie la clé. |
| 401 | invalid_api_key |
La clé est inconnue, révoquée, ou n’a pas le format ws_live_. |
Vérifie la clé, ou crées-en une nouvelle. |
| 402 | plan_limit_reached |
POST /campaigns/{id}/resume alors que le quota de campagnes actives de ton plan est plein. |
Mets une autre campagne en pause, ou change de plan. |
| 403 | insufficient_scope |
La clé n’a pas le scope que cet endpoint demande. Le message le nomme. | Crée une clé avec ce scope. |
| 404 | not_found |
Route inconnue, ou la ressource n’existe pas, ou elle appartient à un autre espace. | Vérifie l’identifiant et le chemin. |
| 409 | invalid_state |
Mettre en pause une campagne qui n’est pas active, relancer une campagne qui n’est pas en pause, ajouter un lead à une campagne qui n’est pas active, ou passer la main sur un lead sans conversation. | Lis le message et change l’état dans le dashboard. |
| 409 | lead_not_contacted |
POST /messages sur un lead à qui personne n’a encore écrit. |
Le premier contact passe par une liste et une campagne. |
| 409 | request_in_flight |
Une requête avec la même Idempotency-Key est encore en cours. |
Attends quelques secondes, puis réessaie avec la même clé. |
| 409 | already_blocked |
POST /blocked-contacts pour un numéro ou un indicatif déjà dans la liste. |
Rien : il est déjà bloqué. |
| 422 | validation_error |
Un paramètre ou un champ du corps manque ou est invalide : limit hors de 1 à 100, une date qui n’est pas en ISO 8601, un text vide, un id de membre inconnu dans assigned_to. |
Corrige la requête. Réessayer à l’identique échouera encore. |
| 429 | rate_limited |
Plus de requêtes par minute que ton plan n’en autorise. | Attends Retry-After secondes, puis réessaie. |
| 429 | quota_exceeded |
Le quota WhatsApp quotidien du numéro émetteur est atteint (il se remet à zéro à minuit UTC), ou un plafond de l’espace est atteint : 200 listes, 10 souscriptions webhook, 500 contacts bloqués. | Attends X-Quota-Reset, ou supprime ce qui ne sert plus. |
| 500 | internal_error |
Une erreur inattendue de notre côté, ou le backend de messagerie n’est pas configuré. | Réessaie plus tard. Contacte le support si ça persiste. |
| 500 | server_error |
Le contrôle de l’agent n’est pas configuré sur ce déploiement (handoff, resume). |
Contacte le support. |
| 502 | send_failed |
Le moteur WhatsApp n’a pas confirmé l’envoi. | Réessaie avec la même Idempotency-Key. Sans clé, relis la conversation avant de renvoyer. |
| 502 | upstream_error |
Le workflow derrière handoff, resume ou POST /campaigns/{id}/leads a refusé l’appel ou était injoignable. |
Réessaie dans un instant. |
| 503 | agent_disconnected |
Le numéro WhatsApp de la campagne est déconnecté, ou aucun numéro n’y est rattaché. | Reconnecte le numéro dans le dashboard. |
| 503 | service_unavailable |
Le backend d’authentification est indisponible. | Réessaie dans quelques secondes. |
Les en-têtes de débit
Section intitulée « Les en-têtes de débit »Les requêtes sont comptées par espace et par minute, toutes clés confondues, avec une limite fixée par ton plan (60 à 1000 par minute, voir Authentification et permissions). Chaque réponse porte :
X-RateLimit-Limit: 300X-RateLimit-Remaining: 287X-RateLimit-Reset: 2026-09-19T10:01:00.000ZQuand la limite est dépassée, la réponse est 429 rate_limited et ajoute Retry-After en secondes :
HTTP/1.1 429 Too Many RequestsRetry-After: 23Les en-têtes de quota
Section intitulée « Les en-têtes de quota »L’envoi de messages a un second budget, séparé : le quota quotidien du numéro WhatsApp, le même que celui du moteur de campagne (voir la protection anti-ban). Un POST /messages réussi le renvoie :
X-Quota-Limit: 150X-Quota-Remaining: 149X-Quota-Reset: 2026-09-20T00:00:00.000ZLes mêmes chiffres sont dans le corps sous data.quota (limit, used, remaining, resets_at). Quand le quota est atteint tu reçois 429 quota_exceeded. Il se remet à zéro à minuit UTC. quota_exceeded sert aussi pour les plafonds de l’espace listés dans le tableau ci-dessus.
L’idempotence
Section intitulée « L’idempotence »POST /messages peut être réessayé sans risque si tu envoies un en-tête Idempotency-Key : n’importe quelle chaîne unique de 200 caractères au plus, par exemple un UUID par intention d’envoi.
curl -X POST https://app.whatsetter.com/api/v1/messages \ -H "Authorization: Bearer $WHATSETTER_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 4d3f9b2a-7c1e-4a8b-9f0d-2e6c8a1b3d5f" \ -d '{"lead_id":"66f1a2b3c4d5e6f7a8b9c0d1","text":"On se confirme pour demain 14h ?"}'Ce que fait la clé :
- Une clé qui a déjà produit une réponse la rejoue avec l’en-tête
X-Idempotent-Replay: true. Aucun second message n’est envoyé. - Une nouvelle tentative lancée pendant que la première tourne encore reçoit
409 request_in_flight. Attends quelques secondes et réessaie avec la même clé. - Si un envoi expire ou répond
502 send_failed, réessayer avec la même clé est sûr : WhatSetter rejoue le résultat enregistré ou répond409tant que ça se stabilise. Il n’envoie jamais deux fois. - Les clés sont propres à ton espace et mémorisées 15 minutes.
L’en-tête de version
Section intitulée « L’en-tête de version »Chaque réponse porte X-Api-Version: 2026-07, la version du contrat REST. Les charges utiles des webhooks ont leur propre champ api_version (2026-06-01), décrit sur la page webhooks.
Conseils pour réessayer
Section intitulée « Conseils pour réessayer »| Réponse | Réessayer ? | Comment |
|---|---|---|
429 rate_limited |
Oui | Attends Retry-After secondes. |
429 quota_exceeded sur POST /messages |
Oui, demain | Attends X-Quota-Reset (minuit UTC). |
502 send_failed, 502 upstream_error, 503 * |
Oui | Backoff exponentiel, à partir de quelques secondes. Pour POST /messages, réutilise la même Idempotency-Key. |
500 internal_error |
Une fois, plus tard | Si ça persiste, contacte le support avec le chemin et l’heure de la requête. |
409 request_in_flight |
Oui | Attends quelques secondes, même Idempotency-Key. |
Tout autre 4xx |
Non | La requête elle-même est fausse. Corrige-la d’abord. |

