Referenz

Fehlerbehandlung

Alle Fehlerantworten folgen einer einzigen JSON-Struktur. Verwende HTTP-Statuscodes zur Steuerung deiner Fehlerbehandlungslogik und das Feld error für menschenlesbaren Kontext.

Format der Fehlerantwort
json
// Every non-2xx response returns:
{
  "error": "human-readable description of what went wrong"
}

Fehlercodes

Die nachfolgende Tabelle deckt alle vom Connect Hub zurückgegebenen Statuscodes ab. Die Spalte Wiederholen gibt an, ob ein automatischer Wiederholungsversuch sicher ist.

CodeNameWiederholenBeschreibung
400Bad RequestNOFehlende oder ungültige Felder (z. B. Telefon nicht im E.164-Format, fehlendes Pflichtfeld im Body). Payload korrigieren.
401UnauthorizedNOFehlender oder ungültiger x-api-key-Header. API-Schlüssel prüfen – nicht automatisch wiederholen.
402Payment RequiredNOUnzureichendes Kontoguthaben. Novauth-Konto aufladen, bevor erneut versucht wird.
403ForbiddenNODer API-Schlüssel hat keine Berechtigung für diese Aktion.
404Not FoundNORessource existiert nicht (z. B. unbekannte UUID bei /call/flash/{uuid}/cdr). Nicht wiederholen.
409ConflictNOEine doppelte oder widersprüchliche Operation wurde erkannt (z. B. zweimaliges Melden des Webhooks für dieselbe UUID).
422Unprocessable EntityNOTelegram-spezifisch: Anfrage semantisch ungültig (z. B. abgelaufene request_id bei check-verification-status).
429Too Many RequestsYESRate Limit überschritten. Den Retry-After-Header beachten und exponentielles Backoff implementieren.
480Temporarily UnavailableYESEmpfänger vorübergehend nicht erreichbar (SIP-abgeleitet). Nach kurzer Verzögerung sicher wiederholbar.
482Loop DetectedNOAnfrage-Routing-Schleife erkannt. Nicht wiederholen – Integration untersuchen.
486Busy HereYESEmpfänger ist besetzt. Nach einer Verzögerung erneut versuchen oder auf einen anderen Kanal zurückfallen.
488Not Acceptable HereNOAnfrageparameter nicht akzeptabel (z. B. nicht unterstützter Codec oder Format). Anfrage korrigieren.
500Internal Server ErrorYESUnerwarteter serverseitiger Fehler. Mit exponentiellem Backoff wiederholen (max. 3 Versuche).
502Bad GatewayYESUpstream-Dienst (Carrier, Gateway) hat eine ungültige Antwort zurückgegeben. Nach kurzer Wartezeit wiederholen.
503Service UnavailableYESDienst vorübergehend überlastet oder in Wartung. Retry-After beachten, falls vorhanden.
603DeclineNOEmpfänger hat explizit abgelehnt (SIP-abgeleitet). Nicht wiederholen – Nutzer hat den Anruf aktiv zurückgewiesen.

Wiederholungslogik

Nur bei den Codes 429, 480, 486, 500, 502, 503 erneut versuchen. Exponentielles Backoff ab 500 ms verwenden (bei jedem Versuch verdoppeln). 4xx-Client-Fehler niemals automatisch wiederholen – zuerst die Ursache beheben.

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' })
  })
);

Idempotente Operationen (GET-Statusabfragen) können beliebig oft wiederholt werden. Bei POST-Operationen, die Ressourcen erstellen, immer prüfen, ob die Ressource bereits erstellt wurde, bevor ein erneuter Versuch unternommen wird – verwende die zurückgegebene UUID, um zuerst den Status abzufragen.

Fallback-Kaskade

Verify Call funktioniert in den meisten Regionen, ist aber nicht universell. Implementiere eine Kaskade, damit Nutzer ihren OTP immer erhalten, auch wenn der primäre Kanal ausfällt.

Empfohlene Fallback-Reihenfolge
Verify Call
schnellste
Telegram OTP
falls Nutzer TG hat
SMS
universell
Auslösebedingungen: Fallback, wenn der primäre Kanal einen nicht wiederholbaren Fehler zurückgibt (400, 402, 488, 603) oder wenn die Verifizierungssitzung nicht innerhalb eines konfigurierbaren Timeout-Fensters als Success gemeldet wird (empfohlen: 15 s für 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()) };
}

Um die Kaskade für einen bestimmten Flow zu deaktivieren, einfach die Fallback-try/catch-Blöcke weglassen und den Fehler direkt an den Nutzer weitergeben. Es gibt keine serverseitige Kaskaden-Einstellung – die Logik liegt vollständig in deinem Integrationscode.

Rate Limiting

Rate Limits werden auf der API-Gateway-Ebene durchgesetzt. Wenn ein Limit erreicht wird, erhältst du eine 429 Too Many Requests-Antwort. Prüfe den Header Retry-After für die genaue Wartezeit.

Retry-After
Sekunden bis die nächste Anfrage erlaubt ist.
X-RateLimit-Limit
Maximale Anfragen im aktuellen Zeitfenster.
X-RateLimit-Remaining
Verbleibende Anfragen im aktuellen Zeitfenster.
X-RateLimit-Reset
Unix-Epoch, wann das aktuelle Zeitfenster zurückgesetzt wird.
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
}

Häufige Integrationsfehler

Dies sind die häufigsten Probleme, die während der Integration gemeldet werden. Prüfe diese Liste, bevor du ein Support-Ticket öffnest.

1
Telefonnummern ohne Ländervorwahl senden
E.164-Format verwenden. "+14155552671" statt "4155552671" oder "014155552671".
2
Die API vom Browser aus aufrufen
Dein API-Schlüssel wird im clientseitigen Code exponiert. Immer über deinen Backend-Server proxyen.
3
402 Payment Required nicht behandeln
Das Guthaben läuft in der Produktion unbemerkt aus. Novauth-Kontoguthaben überwachen und Benachrichtigungen einrichten.
4
400- und 401-Fehler wiederholen
Das sind Client-Fehler – Wiederholen verschwendet Budget und erhöht die Latenz. Zuerst die Ursache beheben.
5
Den Telegram-TTL ignorieren
Codes laufen nach dem von dir angegebenen ttl ab. Wenn du check-verification-status nach dem Ablauf aufrufst, erhältst du eine 422.
6
Den Telegram-Gateway-Body vor der Signaturprüfung parsen
Immer den HMAC auf den rohen Bytes prüfen, bevor JSON.parse() aufgerufen wird. Re-Serialisierung verändert die Byte-Reihenfolge.
7
Telegram-Codes nach Erfolg nicht widerrufen
POST /revoke-verification nach einer erfolgreichen code_valid-Antwort aufrufen, um Replay-Angriffe zu verhindern.
8
Verify Call als einzigen Kanal ohne Fallback verwenden
Verify Call schlägt in manchen Netzwerken fehl. Für kritische Flows immer einen Fallback auf SMS oder Telegram implementieren.