Referenca

Rukovanje greškama

Svi odgovori sa 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 sa greškom
json
// Every non-2xx response returns:
{
  "error": "human-readable description of what went wrong"
}

Kodovi grešaka

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

KodNazivPonovni pokušajOpis
400Bad RequestNONedostajuća ili nevažeća polja (npr. telefon nije u E.164 formatu, nedostaje obavezan 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 nalogu. Dopunite svoj Novauth nalog prije ponovnog pokušaja.
403ForbiddenNOAPI ključ nema dozvolu za izvršavanje ove akcije.
404Not FoundNOResurs ne postoji (npr. nepoznat UUID na /call/flash/{uuid}/cdr). Ne pokušavajte ponovo.
409ConflictNOOtkrivena je duplirana ili konfliktna operacija (npr. dvostruko prijavljivanje webhook-a 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 odlaganje.
480Temporarily UnavailableYESPrimalac je privremeno nedostupan (izvedeno iz SIP-a). Sigurno je pokušati ponovo nakon kraće pauze.
482Loop DetectedNOOtkrivena je petlja u rutiranju zahtjeva. Ne pokušavajte ponovo — istražite svoju integraciju.
486Busy HereYESPrimalac je zauzet. Pokušajte ponovo nakon pauze ili pređite na drugi kanal.
488Not Acceptable HereNOParametri zahtjeva nisu prihvatljivi (npr. nepodržan kodek ili format). Ispravite zahtjev.
500Internal Server ErrorYESNeočekivani otkaz na serverskoj strani. Pokušajte ponovo uz eksponencijalno odlaganje (maks. 3 pokušaja).
502Bad GatewayYESUzvodni servis (operater, gateway) vratio je nevažeći odgovor. Pokušajte ponovo nakon kraćeg čekanja.
503Service UnavailableYESServis je privremeno preopterećen ili na održavanju. Poštujte Retry-After ako je prisutan.
603DeclineNOPrimalac je izričito odbio poziv (izvedeno iz SIP-a). Ne pokušavajte ponovo — korisnik je aktivno odbio poziv.

Logika ponavljanja

Ponavljajte samo kodove 429, 480, 486, 500, 502, 503. Koristite eksponencijalno odlaganje 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 da li je resurs već kreiran prije ponavljanja — koristite vraćeni UUID da prvo provjerite status.

Rezervna kaskada

Verify Call radi u većini regiona, 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
Uslovi aktiviranja: Pređ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 tok, jednostavno izostavite rezervne try/catch blokove i prikažite grešku direktno korisniku. Ne postoji podešavanje kaskade na serverskoj strani — logika u potpunosti živi u vašem integracionom kodu.

Ograničavanje broja zahtjeva

Ograničenja broja zahtjeva primjenjuju se na sloju API gateway-a. Kada se dostigne limit, dobijate odgovor 429 Too Many Requests. Provjerite zaglavlje Retry-After za tačno vrijeme čekanja.

Retry-After
Broj sekundi čekanja prije nego što je sljedeći zahtjev dozvoljen.
X-RateLimit-Limit
Maksimalan broj zahtjeva dozvoljen u trenutnom prozoru.
X-RateLimit-Remaining
Preostali zahtjevi u trenutnom prozoru.
X-RateLimit-Reset
Unix epoha kada se trenutni prozor resetuje.
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 tokom integracije. Provjerite ovu listu prije otvaranja tiketa podrške.

1
Slanje telefonskih brojeva bez pozivnog broja zemlje
Koristite E.164 format. "+14155552671", a ne "4155552671" ni "014155552671".
2
Pozivanje API-ja iz pregledača
Vaš API ključ bit će izložen u kodu na klijentskoj strani. Uvijek prosljeđujte pozive kroz svoj backend server.
3
Neobrađivanje greške 402 Payment Required
Stanje se u produkciji troši neprimjetno. Pratite stanje svog Novauth naloga i podesite 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
Ignorisanje Telegram TTL-a
Kodovi ističu nakon ttl-a koji navedete. Ako pozovete check-verification-status nakon isteka, dobit ćete 422.
6
Parsiranje tijela Telegram Gateway-a prije verifikacije potpisa
Uvijek verifikujte 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 Call-a kao jedinog kanala bez rezerve
Verify Call zakaže u nekim mrežama. Uvijek implementirajte rezervu na SMS ili Telegram za kritične tokove.