Fehlerbehandlung
Alle Fehlerantworten folgen einer einzigen JSON-Struktur. Verwende HTTP-Statuscodes zur Steuerung deiner Fehlerbehandlungslogik und das Feld error für menschenlesbaren Kontext.
// 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.
| Code | Name | Wiederholen | Beschreibung |
|---|---|---|---|
400 | Bad Request | NO | Fehlende oder ungültige Felder (z. B. Telefon nicht im E.164-Format, fehlendes Pflichtfeld im Body). Payload korrigieren. |
401 | Unauthorized | NO | Fehlender oder ungültiger x-api-key-Header. API-Schlüssel prüfen – nicht automatisch wiederholen. |
402 | Payment Required | NO | Unzureichendes Kontoguthaben. Novauth-Konto aufladen, bevor erneut versucht wird. |
403 | Forbidden | NO | Der API-Schlüssel hat keine Berechtigung für diese Aktion. |
404 | Not Found | NO | Ressource existiert nicht (z. B. unbekannte UUID bei /call/flash/{uuid}/cdr). Nicht wiederholen. |
409 | Conflict | NO | Eine doppelte oder widersprüchliche Operation wurde erkannt (z. B. zweimaliges Melden des Webhooks für dieselbe UUID). |
422 | Unprocessable Entity | NO | Telegram-spezifisch: Anfrage semantisch ungültig (z. B. abgelaufene request_id bei check-verification-status). |
429 | Too Many Requests | YES | Rate Limit überschritten. Den Retry-After-Header beachten und exponentielles Backoff implementieren. |
480 | Temporarily Unavailable | YES | Empfänger vorübergehend nicht erreichbar (SIP-abgeleitet). Nach kurzer Verzögerung sicher wiederholbar. |
482 | Loop Detected | NO | Anfrage-Routing-Schleife erkannt. Nicht wiederholen – Integration untersuchen. |
486 | Busy Here | YES | Empfänger ist besetzt. Nach einer Verzögerung erneut versuchen oder auf einen anderen Kanal zurückfallen. |
488 | Not Acceptable Here | NO | Anfrageparameter nicht akzeptabel (z. B. nicht unterstützter Codec oder Format). Anfrage korrigieren. |
500 | Internal Server Error | YES | Unerwarteter serverseitiger Fehler. Mit exponentiellem Backoff wiederholen (max. 3 Versuche). |
502 | Bad Gateway | YES | Upstream-Dienst (Carrier, Gateway) hat eine ungültige Antwort zurückgegeben. Nach kurzer Wartezeit wiederholen. |
503 | Service Unavailable | YES | Dienst vorübergehend überlastet oder in Wartung. Retry-After beachten, falls vorhanden. |
603 | Decline | NO | Empfä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.
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.
Success gemeldet wird (empfohlen: 15 s für Verify Call).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-AfterX-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-Resetconst 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.