Referenca

Rukovanje greškama

Svi odgovori sa greškom prate jedinstvenu JSON strukturu. Koristite HTTP statusne kodove za usmeravanje 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 bezbedno.

KodNazivPonovni pokušajOpis
400Bad RequestNONedostajuća ili nevažeća polja (npr. telefon nije u E.164 formatu, nedostaje obavezan parametar tela). Ispravite svoj payload.
401UnauthorizedNONedostajuće ili nevažeće x-api-key zaglavlje. Proverite svoj API ključ — ne ponavljajte automatski.
402Payment RequiredNONedovoljno stanje na nalogu. Dopunite svoj Novauth nalog pre 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: zahtev je semantički nevažeći (npr. istekao request_id na check-verification-status).
429Too Many RequestsYESPrekoračen limit broja zahteva. Poštujte zaglavlje Retry-After i implementirajte eksponencijalno odlaganje.
480Temporarily UnavailableYESPrimalac je privremeno nedostupan (izvedeno iz SIP-a). Bezbedno je pokušati ponovo nakon kraće pauze.
482Loop DetectedNOOtkrivena je petlja u rutiranju zahteva. 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 zahteva nisu prihvatljivi (npr. nepodržan kodek ili format). Ispravite zahtev.
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 provere statusa) mogu se slobodno ponavljati. Za POST operacije koje kreiraju resurse, uvek proverite da li je resurs već kreiran pre ponavljanja — koristite vraćeni UUID da prvo proverite status.

Rezervna kaskada

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

Preporučeni rezervni redosled
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 zahteva

Ograničenja broja zahteva primenjuju se na sloju API gateway-a. Kada se dostigne limit, dobijate odgovor 429 Too Many Requests. Proverite zaglavlje Retry-After za tačno vreme čekanja.

Retry-After
Broj sekundi čekanja pre nego što je sledeći zahtev dozvoljen.
X-RateLimit-Limit
Maksimalan broj zahteva dozvoljen u trenutnom prozoru.
X-RateLimit-Remaining
Preostali zahtevi 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. Proverite ovu listu pre 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č biće izložen u kodu na klijentskoj strani. Uvek prosleđujte pozive kroz svoj backend server.
3
Neobrađivanje greške 402 Payment Required
Stanje se u produkciji troši neprimetno. 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, dobićete 422.
6
Parsiranje tela Telegram Gateway-a pre verifikacije potpisa
Uvek verifikujte HMAC nad sirovim bajtovima pre JSON.parse(). Ponovna serijalizacija menja redosled bajtova.
7
Neopozivanje Telegram kodova nakon uspeha
Pozovite POST /revoke-verification nakon uspešnog code_valid odgovora da biste sprečili replay napade.
8
Korišćenje Verify Call-a kao jedinog kanala bez rezerve
Verify Call zakaže u nekim mrežama. Uvek implementirajte rezervu na SMS ili Telegram za kritične tokove.