Pagination, idempotence et gestion des erreurs
L'API Ody utilise une pagination par curseur opaque sur ses points de terminaison de liste, un en-tête Idempotency-Key pour des tentatives d'envoi de messages sécurisées, et une enveloppe d'erreur uniforme avec un ID de requête sur chaque réponse — ce guide couvre les trois.
Pagination par curseur
GET /v1/api/contacts et GET /v1/api/conversations paginent avec ?limit= et ?cursor= :
curl "https://api.ody.co/v1/api/contacts?limit=100" \
-H "Authorization: Bearer ody_live_…"
La réponse inclut un nextCursor — repassez-le comme ?cursor= pour récupérer la page suivante, et arrêtez-vous quand il est null :
{ "contacts": [ … ], "nextCursor": "eyJ…" }
- Les curseurs sont opaques — passez-les toujours tels quels ; un curseur modifié ou périmé renvoie
400 invalid_argument. - Limites de taille de page : contacts par défaut 50, max 200 ; conversations par défaut 50, max 100.
GET /v1/api/messages/search(par défaut 25, max 100) etGET /v1/api/calls(par défaut 50, max 200) prennent?limit=uniquement, sans curseurs. - Les SDK officiels suivent
nextCursorpour vous aveclistAll()/list_all()— voir Démarrage rapide des SDK : TypeScript et Python.
Envois de messages idempotents
Une défaillance réseau après un POST /v1/api/messages vous laisse sans savoir si le message a été envoyé — retenter aveuglément risque un double envoi. Envoyez un en-tête Idempotency-Key (toute chaîne de caractères jusqu'à 200 caractères, unique par envoi logique) et les tentatives deviennent sûres :
curl https://api.ody.co/v1/api/messages \
-H "Authorization: Bearer ody_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042-shipped" \
-d '{"to":"+15125550123","body":"Your order shipped!"}'
- La première réponse réussie est stockée pendant 24 heures ; toute nouvelle tentative avec la même clé dans cette fenêtre la rejoue textuellement au lieu de l'envoyer à nouveau, avec un en-tête de réponse
Idempotency-Replayed: true. - Dérivez la clé de votre propre événement commercial ("order-1042-shipped"), et non d'une valeur aléatoire par tentative — l'objectif est que les tentatives la partagent.
L'enveloppe d'erreur
Chaque réponse d'erreur utilise la même forme :
{ "error": { "code": "permission_denied", "message": "This API key is missing the 'messages:send' scope", "requestId": "req_…" } }
| Statut | Code | Que faire |
|---|---|---|
400 |
invalid_argument |
Corrigez la requête — le message indique ce qui ne va pas |
401 |
unauthenticated |
La clé est manquante, invalide ou révoquée. Ne réessayez pas ; alertez le propriétaire de l'intégration |
403 |
permission_denied |
Le message nomme la portée manquante — créez une clé qui la possède |
404 |
not_found |
La ressource n'existe pas dans cet espace de travail |
409 |
failed_precondition |
L'espace de travail ne peut pas encore faire cela (par exemple, pas de numéro actif pour envoyer). Affichez-le, ne réessayez pas |
429 |
resource_exhausted |
Limite de débit atteinte — attendez Retry-After secondes, puis réessayez avec un délai exponentiel |
500 |
internal |
Réessayez avec un délai exponentiel et un jitter ; limitez les tentatives |
ID de requête
Chaque réponse — succès ou erreur — contient un en-tête X-Request-Id, répercuté comme requestId dans les corps d'erreur. Enregistrez-le avec vos propres journaux de requêtes, et citez-le lorsque vous contactez le support : il permet de localiser la requête exacte de notre côté. Vous pouvez également fournir votre propre X-Request-Id (jusqu'à 64 caractères, lettres/chiffres/_/-) et Ody le renverra, ce qui facilite la corrélation des tentatives.
Articles connexes
Questions fréquemment posées
Comment obtenir la page de résultats suivante ?
Passez le nextCursor de la réponse précédente comme ?cursor= sur la requête suivante. Un nextCursor nul signifie que vous avez atteint la fin.
Que se passe-t-il si je réessaie un envoi avec la même Idempotency-Key ?
Dans les 24 heures, Ody rejoue la première réponse stockée au lieu de l'envoyer à nouveau, et ajoute un en-tête Idempotency-Replayed: true.
Que dois-je envoyer au support en cas d'échec ?
Le requestId du corps de l'erreur (également l'en-tête de réponse X-Request-Id) — il nous permet de trouver la requête exacte dans nos journaux.