Aller au contenu

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.

{
"error": {
"code": "insufficient_scope",
"message": "This API key is missing the \"messages:send\" scope."
}
}
  • code est stable : fais tes branchements dessus.
  • message est 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" } }.
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 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: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 2026-09-19T10:01:00.000Z

Quand 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 Requests
Retry-After: 23

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: 150
X-Quota-Remaining: 149
X-Quota-Reset: 2026-09-20T00:00:00.000Z

Les 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.

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.

Terminal window
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épond 409 tant que ça se stabilise. Il n’envoie jamais deux fois.
  • Les clés sont propres à ton espace et mémorisées 15 minutes.

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.

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.