Gestione degli errori
Tutte le risposte di errore seguono una singola struttura JSON. Usa i codici di stato HTTP per instradare la logica di gestione degli errori e il campo error per il contesto leggibile dall'utente.
// Every non-2xx response returns:
{
"error": "human-readable description of what went wrong"
}Codici di errore
La tabella seguente copre tutti i codici di stato restituiti dal Connect Hub. La colonna Riprova indica se è sicuro riprovare automaticamente.
| Codice | Nome | Riprova | Descrizione |
|---|---|---|---|
400 | Bad Request | NO | Campi mancanti o non validi (es. telefono non in formato E.164, parametro obbligatorio del corpo mancante). Correggi il payload. |
401 | Unauthorized | NO | Header x-api-key mancante o non valido. Controlla la tua chiave API — non riprovare automaticamente. |
402 | Payment Required | NO | Saldo dell'account insufficiente. Ricarica il tuo account Novauth prima di riprovare. |
403 | Forbidden | NO | La chiave API non dispone dei permessi per eseguire questa azione. |
404 | Not Found | NO | La risorsa non esiste (es. UUID sconosciuto su /call/flash/{uuid}/cdr). Non riprovare. |
409 | Conflict | NO | È stata rilevata un'operazione duplicata o in conflitto (es. segnalazione webhook due volte per lo stesso UUID). |
422 | Unprocessable Entity | NO | Specifico di Telegram: richiesta semanticamente non valida (es. request_id scaduto su check-verification-status). |
429 | Too Many Requests | YES | Limite di frequenza superato. Rispetta l'header Retry-After e implementa il backoff esponenziale. |
480 | Temporarily Unavailable | YES | Destinatario temporaneamente non raggiungibile (derivato da SIP). Si può riprovare dopo un breve ritardo. |
482 | Loop Detected | NO | Rilevato loop di instradamento della richiesta. Non riprovare — esamina la tua integrazione. |
486 | Busy Here | YES | Il destinatario è occupato. Riprova dopo un ritardo o passa a un altro canale. |
488 | Not Acceptable Here | NO | Parametri della richiesta non accettabili (es. codec o formato non supportato). Correggi la richiesta. |
500 | Internal Server Error | YES | Errore imprevisto lato server. Riprova con backoff esponenziale (max 3 tentativi). |
502 | Bad Gateway | YES | Il servizio upstream (operatore, gateway) ha restituito una risposta non valida. Riprova dopo una breve attesa. |
503 | Service Unavailable | YES | Servizio temporaneamente sovraccarico o in manutenzione. Rispetta Retry-After se presente. |
603 | Decline | NO | Il destinatario ha rifiutato esplicitamente (derivato da SIP). Non riprovare — l'utente ha rifiutato attivamente la chiamata. |
Logica di ripetizione
Riprova solo per i codici 429, 480, 486, 500, 502, 503. Usa il backoff esponenziale partendo da 500 ms (raddoppia a ogni tentativo). Non riprovare mai automaticamente gli errori client 4xx — risolvi prima la causa principale.
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' })
})
);Le operazioni idempotenti (controlli di stato GET) possono essere ripetute liberamente. Per le operazioni POST che creano risorse, verifica sempre se la risorsa è già stata creata prima di riprovare — usa l'UUID restituito per interrogare prima lo stato.
Cascata di fallback
Verify Call funziona nella maggior parte delle regioni ma non è universale. Implementa una cascata in modo che gli utenti ricevano sempre il loro OTP anche quando il canale primario fallisce.
Success entro una finestra di timeout configurabile (consigliato: 15 s per 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()) };
}Per disabilitare la cascata per un flusso specifico, ometti semplicemente i blocchi try/catch di fallback e mostra l'errore direttamente all'utente. Non esiste un'impostazione di cascata lato server — la logica risiede interamente nel codice di integrazione.
Limitazione della frequenza
I limiti di frequenza vengono applicati a livello di gateway API. Quando viene raggiunto un limite, ricevi una risposta 429 Too Many Requests. Controlla l'header Retry-After per il tempo di attesa esatto.
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
}Errori di integrazione comuni
Questi sono i problemi più frequenti segnalati durante l'integrazione. Controlla questo elenco prima di aprire un ticket di supporto.