Erreurs API Yasmine

Format RFC 7807 sur tout /v1/*. Chaque classe d'erreur a un type stable ; router dessus côté SDK, pas sur le code HTTP seul. Format URL : https://docs.yasmine.akidly.com/errors/<slug> → redirige vers la section ci-dessous.

invalid_api_key401

Ce que ça veut dire. Header Authorization absent, mal formé (pas de Bearer), ou clé invalide/révoquée. Le header WWW-Authenticate: Bearer est propagé.

Causes fréquentes

  • Clé copiée avec espace/newline en fin (le serveur hash la clé entière).
  • Clé révoquée via DELETE /v1/me/api-keys/{id}.
  • Bearer prefix manquant : Authorization: yk_... au lieu de Bearer yk_....

Comment corriger

  • Régénérer une clé via POST /v1/me/api-keys.
  • Vérifier l'état de vos clés : GET /v1/me/api-keys.
  • Consulter les events d'audit de la clé : GET /v1/me/api-keys/{id}/events.

Exemple de réponse

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/invalid_api_key",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Authorization: Bearer <reseller_api_key> requis",
  "instance": "/v1/calls",
  "request_id": "a1b2c3d4"
}
↑ Retour en haut

forbidden403

Ce que ça veut dire. Clé valide, mais sans droit sur cette ressource. Aucun endpoint /v1/* ne l'émet aujourd'hui — slug réservé pour une future séparation admin/reader.

Comment corriger

  • Contacter le support si vous êtes admin et voyez ce code.
↑ Retour en haut

validation_error422

Ce que ça veut dire. Le body du POST ne respecte pas le schéma attendu par l'endpoint. Inclut aussi les champs inconnus : les schémas de POST /v1/calls rejettent tout champ non déclaré — un typo comme custommer au lieu de customer, ou phonne_number au lieu de phone_number dans customer, est refusé. Le champ errors[] liste chaque violation avec son chemin exact.

Causes fréquentes

  • Typo sur le nom d'un champ (errors[].type === "extra_forbidden").
  • Type mauvais : amount envoyé en nombre au lieu de string.
  • Contrainte violée : customer.name vide, amount ≤ 0.
  • Enum : country hors MA/DZ/TN/FR.

Comment corriger

  • Parser errors[].loc et errors[].msg pour cibler le champ exact (loc peut avoir plusieurs segments pour les champs nested, ex. ["body", "customer", "phone_number"]).
  • Consulter les schémas CallCreate et CustomerInput dans la spec OpenAPI.
  • Pour un champ en trop : vérifier l'orthographe ou supprimer du body.

Exemple de réponse

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/validation_error",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "Un ou plusieurs champs du payload sont invalides.",
  "instance": "/v1/calls",
  "request_id": "a1b2c3d4",
  "errors": [
    { "loc": ["body", "customer", "phonne_number"], "msg": "Extra inputs are not permitted", "type": "extra_forbidden" },
    { "loc": ["body", "amount"], "msg": "Decimal input should be greater than 0", "type": "greater_than" }
  ]
}
↑ Retour en haut

invalid_key_id400

Ce que ça veut dire. DELETE /v1/me/api-keys/{key_id} ou GET /v1/me/api-keys/{key_id}/events avec UUID malformé. Distingué du 404 pour aider à diagnostiquer un bug de construction d'URL côté client.

Comment corriger

  • key_id doit être un UUID v4 strict (format 8-4-4-4-12).
  • Relire la valeur retournée par POST /v1/me/api-keys (id).
↑ Retour en haut

invalid_period_format400

Ce que ça veut dire. GET /v1/me/usage?period=... avec format non-YYYY-MM ou mois hors 01-12. Exemples de valeurs rejetées : ?period=abc, ?period=2026-13, ?period=2026-00.

Comment corriger

  • Format strict ^\d{4}-(0[1-9]|1[0-2])$.
  • Omettre period pour obtenir le mois courant UTC (défaut).
↑ Retour en haut

invalid_status_filter400

Ce que ça veut dire. GET /v1/me/webhooks/deliveries?status=... avec valeur hors delivered/failed/pending.

Comment corriger

  • Utiliser exactement delivered, failed, ou pending.
  • Le detail de la réponse liste les valeurs acceptées.
↑ Retour en haut

invalid_cursor400

Ce que ça veut dire. Curseur de pagination malformé, avec signature invalide, ou clé de signature tournée côté serveur. S'applique à tous les endpoints paginés : GET /v1/calls, GET /v1/me/transactions, GET /v1/me/webhooks/deliveries, GET /v1/me/api-keys/{id}/events.

Comment corriger

  • Refaire la 1re requête sans le paramètre cursor.
  • Ne pas stocker de curseurs en durable (TTL 24 h + rotation possible de la clé de signature).
↑ Retour en haut

cursor_expired400

Ce que ça veut dire. Curseur plus vieux que 24 h (TTL fixe). Yasmine ne propose pas de curseur « temps-indépendant » pour limiter la surface en cas de fuite de clé.

Comment corriger

  • Refaire la 1re requête sans cursor.
  • Reprendre la pagination depuis le début avec la page 1 fraîche.
↑ Retour en haut

missing_idempotency_key400

Ce que ça veut dire. Header Idempotency-Key absent sur POST /v1/calls. Obligatoire pour éviter un double appel en cas de retry réseau.

Comment corriger

  • Générer un UUID v4 par requête (uuidgen, crypto.randomUUID(), etc.).
  • Même valeur dans un retry automatique → la réponse cachée est servie (pas de double appel).
  • Fenêtre de dedup : 24 h.
↑ Retour en haut

idempotency_key_empty400

Ce que ça veut dire. Header Idempotency-Key présent mais vide. Doit faire au moins 1 caractère.

↑ Retour en haut

idempotency_key_too_long400

Ce que ça veut dire. Header Idempotency-Key > 255 caractères. Limite stricte serveur pour éviter un abus storage.

↑ Retour en haut

idempotency_key_conflict409

Ce que ça veut dire. La même Idempotency-Key a déjà été utilisée dans la fenêtre 24 h avec un body différent. Générer une nouvelle clé pour une nouvelle requête. Le body original n'est jamais ré-exposé (anti-BOPLA).

Comment corriger

  • Ne jamais réutiliser une Idempotency-Key pour 2 requêtes sémantiquement différentes.
  • Un retry légitime (même body) renvoie la réponse d'origine, pas une erreur.
↑ Retour en haut

order_external_id_already_exists409

Ce que ça veut dire. Un POST /v1/calls envoie une order.external_id déjà utilisée pour cette boutique. Les commandes sont créées en insertion stricte, sans écrasement — un second POST avec la même external_id est rejeté.

Causes fréquentes

  • Retry d'une commande sans réutiliser la même Idempotency-Key (qui aurait fait un replay).
  • Deux services du reseller qui partagent le même pool d'external_id sans coordination.
  • Collision involontaire (formats courts type CMD-001).

Comment corriger

  • Retenter sur la commande existante : nouveau POST avec nouvelle Idempotency-Key + order.previous_attempts incrémenté.
  • Créer une commande distincte : générer une external_id unique côté reseller.
  • Retry réseau pur : garder la même Idempotency-Key → replay bit-for-bit.

Exemple de réponse

HTTP/1.1 409 Conflict
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/order_external_id_already_exists",
  "title": "Order external_id already exists",
  "status": 409,
  "detail": "An order with this external_id already exists for this shop.",
  "instance": "/v1/calls",
  "request_id": "a1b2c3d4",
  "hint": "To retry reaching the customer on this existing order, submit a new POST with a fresh Idempotency-Key and increment order.previous_attempts. To create a distinct order, use a unique external_id."
}
↑ Retour en haut

shop_not_found404

Ce que ça veut dire. Aucune boutique active ne porte cet identifiant sur votre compte. Le corps de la réponse est identique dans trois cas — la boutique n'existe pas, elle a été archivée, ou elle appartient à un autre compte. C'est volontaire : une réponse différenciée permettrait de deviner quelles boutiques existent chez les autres.

Causes fréquentes

  • Faute de frappe dans l'identifiant, ou confusion entre external_id (la boutique) et merchant_external_id (son propriétaire).
  • Boutique archivée par un DELETE précédent — elle reste consultable via GET /v1/shops?status=archived.
  • Boutique créée sur un autre compte, ou avec une autre clé API.

Comment corriger

  • Vérifier l'identifiant avec GET /v1/shops, qui liste les boutiques du compte.
  • Chercher parmi les archivées : ?status=all.
  • La créer si elle n'existe pas encore : POST /v1/shops.

Exemple de réponse

HTTP/1.1 404 Not Found
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/shop_not_found",
  "title": "Not Found",
  "status": 404,
  "detail": "Aucune boutique active avec cet identifiant sur votre compte.",
  "instance": "/v1/shops/shop-4471",
  "request_id": "a1b2c3d4"
}
↑ Retour en haut

shop_external_id_already_exists409

Ce que ça veut dire. Une boutique existe déjà avec cet external_id sur votre compte. La création est stricte : elle ne se transforme jamais en mise à jour implicite. Créer deux fois la même boutique est une erreur d'intégration, pas une modification.

Causes fréquentes

  • Rejeu d'une création déjà passée — le premier appel a réussi.
  • Tentative de modifier une boutique via POST au lieu de PATCH.
  • Collision d'identifiants entre deux systèmes qui alimentent le même compte.

Comment corriger

  • Pour modifier la boutique existante : PATCH /v1/shops/{external_id}.
  • Pour en créer une distincte : choisir un external_id non utilisé.
  • Rejeu après un timeout réseau : ce 409 confirme que la création initiale a abouti. Un GET renvoie la fiche.

Exemple de réponse

HTTP/1.1 409 Conflict
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/shop_external_id_already_exists",
  "title": "Conflict",
  "status": 409,
  "detail": "Une boutique existe deja avec l'identifiant 'shop-4471' sur votre compte. Utiliser PATCH pour la modifier, ou un autre identifiant pour en creer une nouvelle.",
  "instance": "/v1/shops",
  "request_id": "a1b2c3d4"
}
↑ Retour en haut

product_not_found404

Ce que ça veut dire. Aucun produit actif ne porte cet identifiant dans cette boutique. Le corps est identique dans trois cas — le produit n'existe pas, il a été archivé, ou il appartient à une autre boutique. Une réponse différenciée permettrait de deviner ce qui existe ailleurs.

Causes fréquentes

  • Produit déclaré dans une autre boutique du même compte : l'identifiant n'est unique qu'à l'intérieur d'une boutique.
  • Produit archivé par un DELETE précédent — toujours visible via ?status=archived.
  • Confusion entre l'identifiant du produit et celui d'une de ses variantes.

Comment corriger

  • Lister le catalogue de la boutique : GET /v1/shops/{shop_external_id}/products.
  • Chercher parmi les archivés : ?status=all.
  • Le créer s'il n'existe pas encore.

Exemple de réponse

HTTP/1.1 404 Not Found
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/product_not_found",
  "title": "Not Found",
  "status": 404,
  "detail": "Aucun produit actif avec cet identifiant dans cette boutique.",
  "instance": "/v1/shops/shop-4471/products/TSHIRT-99",
  "request_id": "a1b2c3d4"
}
↑ Retour en haut

product_external_id_already_exists409

Ce que ça veut dire. Un produit porte déjà cet external_id dans cette boutique. La création est stricte : elle ne se transforme jamais en mise à jour implicite.

Causes fréquentes

  • Rejeu d'une création déjà passée — le premier appel a réussi.
  • Tentative de modifier un produit via POST au lieu de PATCH.
  • Import en masse relancé après une interruption.

Comment corriger

  • Pour modifier : PATCH /v1/shops/{shop_external_id}/products/{product_external_id}.
  • Pour en créer un distinct : choisir un external_id libre.
  • Rejeu après un timeout réseau : ce 409 confirme que la création initiale a abouti. Un GET renvoie la fiche.

Exemple de réponse

HTTP/1.1 409 Conflict
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/product_external_id_already_exists",
  "title": "Conflict",
  "status": 409,
  "detail": "Un produit existe deja avec l'identifiant 'TSHIRT-01' dans la boutique 'shop-4471'. Utiliser PATCH pour le modifier, ou un autre identifiant pour en creer un nouveau.",
  "instance": "/v1/shops/shop-4471/products",
  "request_id": "a1b2c3d4"
}
↑ Retour en haut

order_item_unknown_product422

Ce que ça veut dire. Une ligne de commande référence un product_external_id — ou un variant_external_id — qui n'existe pas dans la boutique de cet appel. L'appel n'a pas été créé, rien n'a été facturé.

Causes fréquentes

  • Produit déclaré dans une autre boutique : l'identifiant n'est unique qu'à l'intérieur d'une boutique.
  • Produit archivé depuis, ou jamais déclaré.
  • Commande envoyée avant que le catalogue ne soit synchronisé.

Comment corriger

  • Déclarer le produit : POST /v1/shops/{shop_external_id}/products.
  • Ou décrire l'article sur place : une ligne sans product_external_id mais avec name et unit_price reste parfaitement valide. C'est la voie pour un article sur mesure, un frais de port, un cadeau — un produit non déclaré ne doit jamais bloquer un appel.

Exemple de réponse

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/order_item_unknown_product",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "Le produit 'BOUGIE-99' n'existe pas dans la boutique 'shop-4471'.",
  "instance": "/v1/calls",
  "request_id": "a1b2c3d4"
}
↑ Retour en haut

order_item_variant_required422

Ce que ça veut dire. La ligne référence un produit qui a plusieurs déclinaisons — tailles, couleurs — sans préciser laquelle. Nous n'en choisissons jamais une au hasard : l'agent annoncerait au client un article qu'il n'a pas commandé.

Le detail liste les variantes existantes : vous n'avez pas à aller les chercher.

Comment corriger

  • Préciser variant_external_id sur la ligne, à côté de product_external_id.
  • Vérifier le catalogue : GET /v1/shops/{shop_external_id}/products/{product_external_id} renvoie toutes les variantes avec leur prix.

Un produit sans déclinaison n'est jamais concerné : sa variante unique est résolue automatiquement, et vous n'avez à parler que du produit.

Exemple de réponse

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/order_item_variant_required",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "Le produit 'TSHIRT-01' a 2 variantes : TSH-S, TSH-XL. Preciser laquelle via `variant_external_id`.",
  "instance": "/v1/calls",
  "request_id": "a1b2c3d4"
}
↑ Retour en haut

insufficient_balance402

Ce que ça veut dire. Solde strictement inférieur au minimum facturable (10 secondes) pour initier un appel. L'appel n'a pas été lancé.

Causes fréquentes

  • Recharge automatique non configurée ou échouée.
  • Consommation sur la période supérieure à l'attendu.
  • Clé API partagée dev/prod qui consomme le même crédit.

Comment corriger

  • Lire le solde : GET /v1/me/balance.
  • Vérifier la consommation : GET /v1/me/usage?period=YYYY-MM.
  • Recharger via le portail ou l'API facturation.

Exemple de réponse

HTTP/1.1 402 Payment Required
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/insufficient_balance",
  "title": "Payment Required",
  "status": 402,
  "detail": "Solde disponible 3s < minimum facturable 10s.",
  "instance": "/v1/calls",
  "request_id": "a1b2c3d4",
  "balance_seconds": 3,
  "required_seconds": 10
}
↑ Retour en haut

rate_limited429

Ce que ça veut dire. Slug fallback générique émis si un 429 est levé hors du compteur de rate limit (rare). En pratique vous verrez plutôt rate_limit_exceeded.

↑ Retour en haut

rate_limit_exceeded429

Ce que ça veut dire. Rate-limit par clé API dépassé. Le bucket est remis à zéro en glissant à la fin de la fenêtre.

Seuils actuels

  • POST /v1/calls : 60 / min / clé.
  • POST /v1/calls/{id}/cancel : 120 / min.
  • GET /v1/* (lectures) : 600 / min.
  • POST /v1/me/webhooks* : 10 / min.
  • POST /v1/me/api-keys : 5 / min.

Comment corriger

  • Respecter le header Retry-After (secondes) avant de retenter.
  • Exploiter X-RateLimit-Limit / -Remaining / -Reset sur les 2xx pour prévenir la saturation.
  • Chaque 429 est enregistré comme event rate_limited sur la clé — visible dans GET /v1/me/api-keys/{id}/events.

Exemple de réponse

HTTP/1.1 429 Too Many Requests
Retry-After: 38
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1745229338
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/rate_limit_exceeded",
  "title": "Too Many Requests",
  "status": 429,
  "detail": "Limite de frequence depassee (60 per 1 minute). Reessayer dans 38 seconde(s).",
  "instance": "/v1/calls",
  "request_id": "a1b2c3d4",
  "retry_after": 38
}
↑ Retour en haut

not_found404

Ce que ça veut dire. Ressource absente ou non accessible au reseller courant. Slug générique — certains endpoints utilisent un slug dédié (call_not_found, api_key_not_found, webhook_not_configured).

↑ Retour en haut

call_not_found404

Ce que ça veut dire. GET /v1/calls/{id}, GET /v1/calls/{id}/recording ou POST /v1/calls/{id}/cancel sur un call_id inexistant OU appartenant à un autre reseller (anti-énumération). Émis aussi par l'endpoint recording quand l'audio n'a pas (encore) été produit (call jamais finalisé). Body byte-identique dans tous les cas — pas de leak d'existence.

↑ Retour en haut

recording_gone410

Ce que ça veut dire. GET /v1/calls/{id}/recording sur un appel dont l'enregistrement audio a été purgé après la fenêtre de rétention (30 jours).

Pourquoi distinct de call_not_found

Pour permettre au reseller de différencier « jamais existé » (404) vs « a existé mais purgé après rétention » (410). Si vous stockez les recording_url côté reseller pour permettre aux opérateurs d'écouter les appels passés, traitez le 410 comme le signal de mettre à jour votre indexation locale (l'audio n'est plus disponible).

Correctif

Aucun retry possible — l'audio est définitivement supprimé. Si vous avez besoin d'archiver les enregistrements au-delà de 30 jours, téléchargez-les côté reseller et stockez-les chez vous.

↑ Retour en haut

api_key_not_found404

Ce que ça veut dire. DELETE /v1/me/api-keys/{id} ou GET /v1/me/api-keys/{id}/events sur une clé inexistante OU appartenant à un autre reseller . Body byte-identique — anti-énumération.

↑ Retour en haut

conflict409

Ce que ça veut dire. Slug générique 409. Les cas concrets utilisent un slug dédié : idempotency_key_conflict, webhook_already_configured.

↑ Retour en haut

webhook_url_rejected400

Ce que ça veut dire. POST /v1/me/webhooks avec URL refusée par le guard SSRF. Le body contient un champ reason explicite.

Valeurs possibles de reason

  • invalid_url — URL non parseable.
  • scheme_not_allowed — pas https (ou http en dev).
  • localhost_rejectedlocalhost/127.0.0.1 interdits.
  • dns_resolution_failed — le hostname ne résout pas.
  • private_ip_rejected — IP privée (RFC 1918) ou link-local interdite.
↑ Retour en haut

webhook_already_configured409

Ce que ça veut dire. POST /v1/me/webhooks sur un reseller qui a déjà un webhook actif. 1 webhook max par reseller.

Comment corriger

  • DELETE /v1/me/webhooks d'abord pour rotate.
  • Le nouveau POST retournera un secret HMAC frais.
↑ Retour en haut

webhook_not_configured404

Ce que ça veut dire. GET /v1/me/webhooks ou DELETE /v1/me/webhooks sans configuration active. Pas de webhook à lire/supprimer.

↑ Retour en haut

webhook_url_not_configured400

Ce que ça veut dire. POST /v1/me/webhooks/test sans webhook actif. Impossible de tester une URL qui n'existe pas.

Comment corriger

  • Configurer un webhook via POST /v1/me/webhooks avant de tester.
↑ Retour en haut

payload_too_large413

Ce que ça veut dire. Émis sur POST /webhooks/whatsapp quand le body dépasse 256 KiB. Vérification avant HMAC (défense en profondeur contre DoS et payloads falsifiés).

Contexte

  • Meta envoie ~50 KB en pratique — marge 5×.
  • Pas applicable aux endpoints /v1/* (leur validation coupe plus tôt).
  • Si vu côté Meta retry storm : contacter le support avec request_id.
↑ Retour en haut

bad_request400

Ce que ça veut dire. Slug fallback 400 générique. Les cas concrets utilisent un slug dédié (idempotency, cursor, period, key_id, webhook, validation). Un bad_request brut sans contexte indique un chemin d'erreur rare — contacter le support avec request_id.

↑ Retour en haut

service_unavailable503

Ce que ça veut dire. Dépendance externe indisponible ou config manquante côté Yasmine. Exemple concret : la clé de signature des curseurs non configurée → tous les endpoints paginés répondent 503 fail-closed plutôt que d'émettre des curseurs non signés.

Comment corriger (côté client)

  • Retenter après quelques secondes (backoff exponentiel recommandé).
  • Si persistant : contacter le support avec request_id.
↑ Retour en haut

internal_error500

Ce que ça veut dire. Erreur inattendue côté Yasmine (bug). La stack trace est loguée côté serveur avec le request_id — l'envoyer au support pour qu'il retrouve la trace exacte.

Exemple de réponse

HTTP/1.1 500 Internal Server Error
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/internal_error",
  "title": "Internal Server Error",
  "status": 500,
  "detail": "Une erreur interne est survenue. Contacter le support avec la valeur de request_id.",
  "instance": "/v1/calls",
  "request_id": "a1b2c3d4"
}
↑ Retour en haut

language_not_supported_for_country422

Ce que ça veut dire. POST /v1/calls avec une combinaison (country, language) non disponible. Aujourd'hui, seule la combinaison country=FR + language=ar est rejetée. Les autres combinaisons (MA/DZ/TN avec ar ou fr, FR avec fr) sont valides.

Exemple de réponse

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/language_not_supported_for_country",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "La langue 'ar' n'est pas disponible pour le pays 'FR'. Combinaisons supportees : MA/DZ/TN avec `ar` ou `fr`, FR uniquement avec `fr`.",
  "instance": "/v1/calls",
  "request_id": "a1b2c3d4"
}

Remédiation

  • Soit retirer le champ language du payload — la langue locale du pays sera appliquée par défaut (MA/DZ/TNar, FRfr).
  • Soit fournir une combinaison valide (FR + fr, ou un pays maghrébin avec ar/fr).
↑ Retour en haut

channel_not_available422

Ce que ça veut dire. POST /v1/calls demande un call_params.channel qui n'est pas ouvert sur cette installation. Le detail nomme les canaux disponibles ainsi que le canal par défaut.

Le refus est volontairement explicite : un appel discrètement re-routé vers un autre canal que celui demandé serait indétectable de votre côté. Mieux vaut une erreur claire qu'un comportement silencieux.

Exemple de réponse

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json

{
  "type": "https://docs.yasmine.akidly.com/errors/channel_not_available",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "Le canal `whatsapp` n'est pas ouvert sur cette installation. Canaux disponibles : gsm. Omettre `call_params.channel` sert le canal par defaut (`gsm`).",
  "instance": "/v1/calls",
  "request_id": "a1b2c3d4"
}

Remédiation

  • Retirer call_params.channel du payload — c'est le cas normal. Le canal par défaut s'applique, et il convient dans la quasi-totalité des intégrations.
  • Ou demander un canal nommé comme disponible dans le detail.
↑ Retour en haut

http_error4xx/5xx

Ce que ça veut dire. Slug fallback générique pour les codes HTTP non mappés explicitement (cas marginal). Le code HTTP réel est toujours dans le champ status du body. Ne pas dépendre de ce slug dans votre code — un code HTTP donné finira toujours par avoir un slug stable dédié.

Remédiation

  • Logger le request_id et contacter le support si vous voyez ce slug.
  • Côté SDK reseller : router sur le code HTTP en fallback quand type termine par /http_error.
↑ Retour en haut