Referenca

Rukovanje greškama

Svi odgovori s greškom prate jedinstvenu JSON strukturu. Koristite HTTP statusne kodove za usmjeravanje logike obrade grešaka, a polje error za kontekst čitljiv ljudima.

Format odgovora s greškom
json
// Every non-2xx response returns:
{
  "error": "human-readable description of what went wrong"
}

Kodovi grešaka

Tablica u nastavku pokriva sve statusne kodove koje vraća Connect Hub. Stupac Ponovni pokušaj pokazuje je li automatsko ponavljanje sigurno.

KodNazivPonovni pokušajOpis
400Bad RequestNONedostajuća ili nevažeća polja (npr. telefon nije u E.164 formatu, nedostaje obvezan parametar tijela). Ispravite svoj payload.
401UnauthorizedNONedostajuće ili nevažeće x-api-key zaglavlje. Provjerite svoj API ključ — ne ponavljajte automatski.
402Payment RequiredNONedovoljno stanje na računu. Nadoplatite svoj Novauth račun prije ponovnog pokušaja.
403ForbiddenNOAPI ključ nema dopuštenje za izvršavanje ove radnje.
404Not FoundNOResurs ne postoji (npr. nepoznat UUID na /call/flash/{uuid}/cdr). Ne pokušavajte ponovno.
409ConflictNOOtkrivena je duplicirana ili konfliktna operacija (npr. dvostruko prijavljivanje webhooka za isti UUID).
422Unprocessable EntityNOSpecifično za Telegram: zahtjev je semantički nevažeći (npr. istekao request_id na check-verification-status).
429Too Many RequestsYESPrekoračen limit broja zahtjeva. Poštujte zaglavlje Retry-After i implementirajte eksponencijalno odgađanje.
480Temporarily UnavailableYESPrimatelj je privremeno nedostupan (izvedeno iz SIP-a). Sigurno je pokušati ponovno nakon kraće pauze.
482Loop DetectedNOOtkrivena je petlja u usmjeravanju zahtjeva. Ne pokušavajte ponovno — istražite svoju integraciju.
486Busy HereYESPrimatelj je zauzet. Pokušajte ponovno nakon pauze ili prijeđite na drugi kanal.
488Not Acceptable HereNOParametri zahtjeva nisu prihvatljivi (npr. nepodržan kodek ili format). Ispravite zahtjev.
500Internal Server ErrorYESNeočekivani otkaz na poslužiteljskoj strani. Pokušajte ponovno uz eksponencijalno odgađanje (maks. 3 pokušaja).
502Bad GatewayYESUzvodni servis (operator, gateway) vratio je nevažeći odgovor. Pokušajte ponovno nakon kraćeg čekanja.
503Service UnavailableYESServis je privremeno preopterećen ili na održavanju. Poštujte Retry-After ako je prisutan.
603DeclineNOPrimatelj je izričito odbio poziv (izvedeno iz SIP-a). Ne pokušavajte ponovno — korisnik je aktivno odbio poziv.

Logika ponavljanja

Ponavljajte samo kodove 429, 480, 486, 500, 502, 503. Koristite eksponencijalno odgađanje počevši od 500 ms (udvostručite pri svakom pokušaju). Nikada ne ponavljajte automatski 4xx klijentske greške — prvo otklonite osnovni uzrok.

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

Idempotentne operacije (GET provjere statusa) mogu se slobodno ponavljati. Za POST operacije koje kreiraju resurse, uvijek provjerite je li resurs već kreiran prije ponavljanja — koristite vraćeni UUID da prvo provjerite status.

Rezervna kaskada

Verify Call radi u većini regija, ali nije univerzalan. Implementirajte kaskadu tako da korisnici uvijek dobiju svoj OTP čak i kada primarni kanal zakaže.

Preporučeni rezervni redoslijed
Verify Call
najbrži
Telegram OTP
ako korisnik ima TG
SMS
univerzalan
Uvjeti aktiviranja: Prijeđite na rezervni kanal kada primarni kanal vrati grešku koja se ne ponavlja (400, 402, 488, 603) ili kada sesija verifikacije nije prijavljena kao Success u podesivom vremenskom okviru (preporučeno: 15 s za 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()) };
}

Da biste onemogućili kaskadu za određeni tijek, jednostavno izostavite rezervne try/catch blokove i prikažite grešku izravno korisniku. Ne postoji postavka kaskade na poslužiteljskoj strani — logika u potpunosti živi u vašem integracijskom kodu.

Ograničavanje broja zahtjeva

Ograničenja broja zahtjeva primjenjuju se na sloju API gatewaya. Kada se dosegne limit, dobivate odgovor 429 Too Many Requests. Provjerite zaglavlje Retry-After za točno vrijeme čekanja.

Retry-After
Broj sekundi čekanja prije nego što je sljedeći zahtjev dopušten.
X-RateLimit-Limit
Maksimalan broj zahtjeva dopušten u trenutnom prozoru.
X-RateLimit-Remaining
Preostali zahtjevi u trenutnom prozoru.
X-RateLimit-Reset
Unix epoha kada se trenutni prozor resetira.
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
}

Česte greške pri integraciji

Ovo su najčešći problemi prijavljeni tijekom integracije. Provjerite ovaj popis prije otvaranja zahtjeva za podršku.

1
Slanje telefonskih brojeva bez pozivnog broja zemlje
Koristite E.164 format. "+14155552671", a ne "4155552671" ni "014155552671".
2
Pozivanje API-ja iz preglednika
Vaš API ključ bit će izložen u kodu na klijentskoj strani. Uvijek prosljeđujte pozive kroz svoj backend poslužitelj.
3
Neobrađivanje greške 402 Payment Required
Stanje se u produkciji troši neprimjetno. Pratite stanje svog Novauth računa i postavite upozorenja.
4
Ponavljanje grešaka 400 i 401
Ovo su klijentske greške — ponavljanje troši budžet i dodaje kašnjenje. Prvo otklonite osnovni uzrok.
5
Ignoriranje Telegram TTL-a
Kodovi istječu nakon ttl-a koji navedete. Ako pozovete check-verification-status nakon isteka, dobit ćete 422.
6
Parsiranje tijela Telegram Gatewaya prije verifikacije potpisa
Uvijek verificirajte HMAC nad sirovim bajtovima prije JSON.parse(). Ponovna serijalizacija mijenja redoslijed bajtova.
7
Neopozivanje Telegram kodova nakon uspjeha
Pozovite POST /revoke-verification nakon uspješnog code_valid odgovora da biste spriječili replay napade.
8
Korištenje Verify Calla kao jedinog kanala bez rezerve
Verify Call zakaže u nekim mrežama. Uvijek implementirajte rezervu na SMS ili Telegram za kritične tijekove.