Riferimento

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.

Formato della risposta di errore
json
// 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.

CodiceNomeRiprovaDescrizione
400Bad RequestNOCampi mancanti o non validi (es. telefono non in formato E.164, parametro obbligatorio del corpo mancante). Correggi il payload.
401UnauthorizedNOHeader x-api-key mancante o non valido. Controlla la tua chiave API — non riprovare automaticamente.
402Payment RequiredNOSaldo dell'account insufficiente. Ricarica il tuo account Novauth prima di riprovare.
403ForbiddenNOLa chiave API non dispone dei permessi per eseguire questa azione.
404Not FoundNOLa risorsa non esiste (es. UUID sconosciuto su /call/flash/{uuid}/cdr). Non riprovare.
409ConflictNOÈ stata rilevata un'operazione duplicata o in conflitto (es. segnalazione webhook due volte per lo stesso UUID).
422Unprocessable EntityNOSpecifico di Telegram: richiesta semanticamente non valida (es. request_id scaduto su check-verification-status).
429Too Many RequestsYESLimite di frequenza superato. Rispetta l'header Retry-After e implementa il backoff esponenziale.
480Temporarily UnavailableYESDestinatario temporaneamente non raggiungibile (derivato da SIP). Si può riprovare dopo un breve ritardo.
482Loop DetectedNORilevato loop di instradamento della richiesta. Non riprovare — esamina la tua integrazione.
486Busy HereYESIl destinatario è occupato. Riprova dopo un ritardo o passa a un altro canale.
488Not Acceptable HereNOParametri della richiesta non accettabili (es. codec o formato non supportato). Correggi la richiesta.
500Internal Server ErrorYESErrore imprevisto lato server. Riprova con backoff esponenziale (max 3 tentativi).
502Bad GatewayYESIl servizio upstream (operatore, gateway) ha restituito una risposta non valida. Riprova dopo una breve attesa.
503Service UnavailableYESServizio temporaneamente sovraccarico o in manutenzione. Rispetta Retry-After se presente.
603DeclineNOIl 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.

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

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.

Ordine di fallback consigliato
Verify Call
più veloce
Telegram OTP
se l'utente ha TG
SMS
universale
Condizioni di attivazione: Passa al canale di riserva quando il canale primario restituisce un errore non ripetibile (400, 402, 488, 603) o quando la sessione di verifica non risulta Success entro una finestra di timeout configurabile (consigliato: 15 s per 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()) };
}

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-After
Secondi da attendere prima che la prossima richiesta sia consentita.
X-RateLimit-Limit
Numero massimo di richieste consentite nella finestra corrente.
X-RateLimit-Remaining
Richieste rimanenti nella finestra corrente.
X-RateLimit-Reset
Epoch Unix in cui si azzera la finestra corrente.
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
}

Errori di integrazione comuni

Questi sono i problemi più frequenti segnalati durante l'integrazione. Controlla questo elenco prima di aprire un ticket di supporto.

1
Invio di numeri di telefono senza prefisso internazionale
Usa il formato E.164. "+14155552671" non "4155552671" o "014155552671".
2
Chiamata all'API dal browser
La tua chiave API verrà esposta nel codice lato client. Passa sempre attraverso il tuo server backend.
3
Mancata gestione del 402 Payment Required
Il saldo si esaurisce silenziosamente in produzione. Monitora il saldo del tuo account Novauth e configura avvisi.
4
Ripetizione degli errori 400 e 401
Questi sono errori client — riprovare spreca budget e aggiunge latenza. Risolvi prima la causa principale.
5
Ignorare il TTL di Telegram
I codici scadono dopo il ttl specificato. Se chiami check-verification-status dopo la scadenza riceverai un 422.
6
Analisi del corpo di Telegram Gateway prima della verifica della firma
Verifica sempre l'HMAC sui byte grezzi prima di JSON.parse(). La riseriazzazione modifica l'ordine dei byte.
7
Mancata revoca dei codici Telegram dopo il successo
Chiama POST /revoke-verification dopo una risposta code_valid riuscita per prevenire attacchi di replay.
8
Utilizzo di Verify Call come unico canale senza fallback
Verify Call fallisce su alcune reti. Implementa sempre un fallback a SMS o Telegram per i flussi critici.