Greške i error kodovi

FiskalAPI koristi standardne HTTP status kodove i vraća strukturirane error objekte s detaljnim porukama i linkovima na dokumentaciju.

Format error responsa

4xx / 5xx Response
{
  "error": {
    "code": "invalid_oib",
    "message": "OIB '1234567890' nije valjan. Kontrolna znamenka ne odgovara.",
    "param": "buyer.oib",
    "doc_url": "https://fiskalapi.hr/docs/reference/greske#invalid_oib"
  },
  "request_id": "req_abc123xyz789"
}

Error objekt

PoljeOpis
codeMašinski čitljiv kod greške
messageLjudski čitljiv opis na hrvatskom
paramKoji parametar je uzrokovao grešku (ako je primjenjivo)
doc_urlLink na dokumentaciju za ovu grešku
request_idID zahtjeva za debugging (uvijek navesti u support ticketu)

HTTP status kodovi

2xx — Uspjeh

StatusZnačenje
200 OKZahtjev uspješan
201 CreatedResurs kreiran (npr. fiskaliziran račun)
202 AcceptedZahtjev prihvaćen, procesira se async (npr. eRačun)
204 No ContentUspješno, bez sadržaja (npr. DELETE)

4xx — Greška klijenta

StatusZnačenje
400 Bad RequestNeispravan zahtjev (krivi JSON, nedostaju parametri)
401 UnauthorizedNedostaje ili neispravan API ključ
403 ForbiddenNemate dozvolu za ovu akciju
404 Not FoundResurs ne postoji
409 ConflictKonflikt (npr. duplikat računa)
422 Unprocessable EntityValidacija prošla, ali poslovna logika odbila
429 Too Many RequestsRate limit prekoračen

5xx — Greška servera

StatusZnačenje
500 Internal Server ErrorNaša greška — kontaktirajte podršku
502 Bad GatewayProblem s upstream servisom (FINA/Porezna)
503 Service UnavailableServis privremeno nedostupan
504 Gateway TimeoutTimeout od Porezne/FINA-e

Popis error kodova

Autentifikacija

KodHTTPOpis
authentication_required401Nedostaje Authorization header
invalid_api_key401API ključ nije valjan
api_key_revoked401API ključ je opozvan
api_key_expired401API ključ je istekao
insufficient_permissions403Ključ nema dozvolu za ovu akciju

Validacija

KodHTTPOpis
invalid_request400Neispravan JSON ili struktura zahtjeva
missing_parameter400Obavezan parametar nedostaje
invalid_parameter400Parametar ima neispravnu vrijednost
invalid_oib400OIB nije valjan (kriva kontrolna znamenka ili format)
invalid_iban400IBAN nije valjan
invalid_kpd400KPD šifra ne postoji
invalid_date400Datum nije u ispravnom formatu (ISO 8601)

Fiskalizacija (F1)

KodHTTPOpis
duplicate_invoice409Račun s tim brojem već postoji
fiscalization_failed422Porezna odbila račun (detalji u message)
invalid_invoice_number400Broj računa nije u formatu X/Y/Z
invalid_business_unit400Poslovni prostor nije registriran
certificate_error500Problem s FINA certifikatom

eRačuni (F2)

KodHTTPOpis
einvoice_delivery_failed422Nije moguće dostaviti eRačun
recipient_not_found422Primatelj nije pronađen u FINA registru
einvoice_rejected422Primatelj odbio eRačun
invalid_ubl400Generirani UBL nije validan (naša greška)

Eksterni servisi

KodHTTPOpis
porezna_unavailable503Porezna uprava trenutno nedostupna
porezna_timeout504Timeout od Porezne (pokušajte ponovno)
fina_unavailable503FINA eRačun servis nedostupan
fina_timeout504Timeout od FINA-e

Rate limiting

KodHTTPOpis
rate_limit_exceeded429Prekoračen broj zahtjeva (vidi Retry-After header)

Handling grešaka

Primjer (Node.js)

import FiskalAPI, { FiskalAPIError } from '@fiskalapi/node';

const fiskal = new FiskalAPI(process.env.FISKALAPI_KEY);

try {
  const invoice = await fiskal.invoices.fiscalize({ ... });
} catch (error) {
  if (error instanceof FiskalAPIError) {
    switch (error.code) {
      case 'invalid_oib':
        console.error('Neispravan OIB:', error.param);
        break;
      case 'duplicate_invoice':
        console.error('Račun već postoji');
        break;
      case 'porezna_unavailable':
        console.error('Porezna nedostupna, pokušaj kasnije');
        // Implementiraj retry logiku
        break;
      case 'rate_limit_exceeded':
        const retryAfter = error.headers['retry-after'];
        console.error(`Rate limit, pokušaj za ${retryAfter}s`);
        break;
      default:
        console.error('Nepoznata greška:', error.message);
    }
    
    // Za support ticket
    console.error('Request ID:', error.requestId);
  }
}

Retry strategija

Za 5xx greške i timeoutove, preporučamo exponential backoff:

async function fiscalizeWithRetry(data, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fiskal.invoices.fiscalize(data);
    } catch (error) {
      const isRetryable = 
        error.code === 'porezna_unavailable' ||
        error.code === 'porezna_timeout' ||
        error.statusCode >= 500;
      
      if (!isRetryable || attempt === maxRetries - 1) {
        throw error;
      }
      
      // Exponential backoff: 1s, 2s, 4s
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(r => setTimeout(r, delay));
    }
  }
}

Kontakt podrške

Ako ne možete riješiti grešku, kontaktirajte nas s:

  • request_id iz error responsa
  • Timestamp kada se greška dogodila
  • Endpoint koji ste pozivali
  • Request body (bez API ključa!)

Email: [email protected]