Référence

Gestion des erreurs

Toutes les réponses d'erreur suivent une structure JSON unique. Utilisez les codes de statut HTTP pour orienter votre logique de gestion des erreurs, et le champ error pour le contexte lisible par l'humain.

Format de réponse d'erreur
json
// Every non-2xx response returns:
{
  "error": "human-readable description of what went wrong"
}

Codes d'erreur

Le tableau ci-dessous couvre tous les codes de statut retournés par le Connect Hub. La colonne Réessayer indique si une nouvelle tentative automatique est sans risque.

CodeNomRéessayerDescription
400Bad RequestNOChamps manquants ou invalides (par ex. téléphone non E.164, paramètre de corps obligatoire manquant). Corrigez votre charge utile.
401UnauthorizedNOEn-tête x-api-key manquant ou invalide. Vérifiez votre clé API — ne réessayez pas automatiquement.
402Payment RequiredNOSolde de compte insuffisant. Rechargez votre compte Novauth avant de réessayer.
403ForbiddenNOLa clé API n'a pas la permission d'effectuer cette action.
404Not FoundNOLa ressource n'existe pas (par ex. UUID inconnu sur /call/flash/{uuid}/cdr). Ne réessayez pas.
409ConflictNOUne opération dupliquée ou conflictuelle a été détectée (par ex. signalement webhook deux fois pour le même UUID).
422Unprocessable EntityNOSpécifique à Telegram : requête sémantiquement invalide (par ex. request_id expiré sur check-verification-status).
429Too Many RequestsYESLimite de débit dépassée. Respectez l'en-tête Retry-After et implémentez un recul exponentiel.
480Temporarily UnavailableYESDestinataire temporairement inaccessible (dérivé de SIP). Sûr à relancer après un court délai.
482Loop DetectedNOBoucle de routage de requête détectée. Ne réessayez pas — investiguez votre intégration.
486Busy HereYESLe destinataire est occupé. Réessayez après un délai ou basculez sur un autre canal.
488Not Acceptable HereNOParamètres de requête non acceptables (par ex. codec ou format non pris en charge). Corrigez la requête.
500Internal Server ErrorYESÉchec inattendu côté serveur. Réessayez avec un recul exponentiel (max 3 tentatives).
502Bad GatewayYESLe service en amont (opérateur, passerelle) a retourné une réponse invalide. Réessayez après une courte attente.
503Service UnavailableYESService temporairement surchargé ou en maintenance. Respectez Retry-After si présent.
603DeclineNOLe destinataire a explicitement refusé (dérivé de SIP). Ne réessayez pas — l'utilisateur a activement rejeté l'appel.

Logique de nouvelle tentative

Ne réessayez que sur les codes 429, 480, 486, 500, 502, 503. Utilisez un recul exponentiel en commençant à 500 ms (doublez à chaque tentative). Ne réessayez jamais automatiquement les erreurs client 4xx — corrigez d'abord la cause racine.

javascript
async function callWithRetry(fn, { maxAttempts = 3, baseDelay = 500 } = {}) {
  // Safe codes to retry: 429, 500, 502, 503
  const RETRYABLE = new Set([429, 500, 502, 503]);

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const res = await fn();

    if (res.ok) return res;

    const { status } = res;

    // Non-retryable — surface error immediately
    if (!RETRYABLE.has(status)) {
      const body = await res.json().catch(() => ({}));
      throw Object.assign(new Error(body.error ?? 'API error'), { status, body });
    }

    if (attempt === maxAttempts) {
      throw Object.assign(new Error('Max retries reached'), { status });
    }

    // Exponential backoff: 500ms, 1000ms, 2000ms …
    const delay = baseDelay * 2 ** (attempt - 1);
    await new Promise(r => setTimeout(r, delay));
  }
}

// Usage
const res = await callWithRetry(() =>
  fetch('https://api.novauth.com/api/v1/connect-hub/call/flash', {
    method: 'POST',
    headers: {
      'x-api-key':    process.env.BETATEL_API_KEY,
      'x-account-id': process.env.BETATEL_ACCOUNT_ID,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ callee: '+14155552671' })
  })
);

Les opérations idempotentes (vérifications GET de statut) peuvent être relancées librement. Pour les opérations POST qui créent des ressources, vérifiez toujours si la ressource a déjà été créée avant de réessayer — utilisez l'UUID retourné pour interroger le statut d'abord.

Cascade de repli

Verify Call fonctionne dans la plupart des régions mais n'est pas universel. Implémentez une cascade afin que les utilisateurs reçoivent toujours leur OTP même en cas d'échec du canal principal.

Ordre de repli recommandé
Verify Call
le plus rapide
Telegram OTP
si l'utilisateur a TG
SMS
universel
Conditions de déclenchement : Basculez en repli lorsque le canal principal retourne une erreur non-relançable (400, 402, 488, 603) ou lorsque la session de vérification n'est pas signalée comme Success dans une fenêtre de délai configurable (recommandé : 15 s pour Verify Call).
javascript
async function sendWithFallback(phone, otp) {
  // 1. Try Verify Call first
  try {
    const flash = await fetch('.../call/flash', {
      method: 'POST',
      headers,
      body: JSON.stringify({ callee: phone })
    });
    if (flash.ok) return { channel: 'flash', ...(await flash.json()) };
  } catch {}

  // 2. Flash failed — fall back to Telegram if user has it
  try {
    const tg = await fetch('.../telegram', {
      method: 'POST',
      headers,
      body: JSON.stringify({ to: phone, code: otp, ttl: 120 })
    });
    if (tg.ok) return { channel: 'telegram', ...(await tg.json()) };
  } catch {}

  // 3. Final fallback: SMS (widest global reach)
  const sms = await fetch('.../sms', {
    method: 'POST',
    headers,
    body: JSON.stringify({ to: phone, text: `Your code: ${otp}` })
  });
  if (!sms.ok) throw new Error('All channels failed');
  return { channel: 'sms', ...(await sms.json()) };
}

Pour désactiver la cascade pour un flux spécifique, omettez simplement les blocs try/catch de repli et affichez l'erreur directement à l'utilisateur. Il n'y a pas de paramètre de cascade côté serveur — la logique réside entièrement dans votre code d'intégration.

Limitation de débit

Les limites de débit sont appliquées au niveau de la passerelle API. Lorsqu'une limite est atteinte, vous recevez une réponse 429 Too Many Requests. Consultez l'en-tête Retry-After pour le temps d'attente exact.

Retry-After
Secondes à attendre avant que la prochaine requête soit autorisée.
X-RateLimit-Limit
Nombre maximum de requêtes autorisées dans la fenêtre en cours.
X-RateLimit-Remaining
Requêtes restantes dans la fenêtre en cours.
X-RateLimit-Reset
Époque Unix de réinitialisation de la fenêtre en cours.
javascript
const res = await fetch(url, { method: 'POST', headers, body });

if (res.status === 429) {
  const retryAfter = Number(res.headers.get('Retry-After') ?? 1);
  console.warn(`Rate limited — waiting ${retryAfter}s`);
  await new Promise(r => setTimeout(r, retryAfter * 1000));
  // retry the request
}

Erreurs d'intégration courantes

Ce sont les problèmes les plus fréquemment signalés lors de l'intégration. Consultez cette liste avant d'ouvrir un ticket de support.

1
Envoi de numéros de téléphone sans indicatif pays
Utilisez le format E.164. "+14155552671" et non "4155552671" ou "014155552671".
2
Appel de l'API depuis le navigateur
Votre clé API sera exposée dans le code côté client. Passez toujours par votre serveur backend.
3
Non-gestion de l'erreur 402 Payment Required
Le solde s'épuise silencieusement en production. Surveillez votre solde de compte Novauth et configurez des alertes.
4
Nouvelle tentative sur les erreurs 400 et 401
Ce sont des erreurs client — relancer gaspille le budget et ajoute de la latence. Corrigez d'abord la cause racine.
5
Ignorer le TTL Telegram
Les codes expirent après le ttl que vous spécifiez. Si vous appelez check-verification-status après expiration, vous obtiendrez un 422.
6
Analyse du corps du Telegram Gateway avant vérification de la signature
Vérifiez toujours le HMAC sur les octets bruts avant JSON.parse(). La re-sérialisation modifie l'ordre des octets.
7
Non-révocation des codes Telegram après succès
Appelez POST /revoke-verification après une réponse code_valid réussie pour prévenir les attaques par rejeu.
8
Utilisation de Verify Call comme seul canal sans repli
Verify Call échoue sur certains réseaux. Implémentez toujours un repli vers SMS ou Telegram pour les flux critiques.