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
| Polje | Opis |
|---|
code | Mašinski čitljiv kod greške |
message | Ljudski čitljiv opis na hrvatskom |
param | Koji parametar je uzrokovao grešku (ako je primjenjivo) |
doc_url | Link na dokumentaciju za ovu grešku |
request_id | ID zahtjeva za debugging (uvijek navesti u support ticketu) |
HTTP status kodovi
2xx — Uspjeh
| Status | Značenje |
|---|
200 OK | Zahtjev uspješan |
201 Created | Resurs kreiran (npr. fiskaliziran račun) |
202 Accepted | Zahtjev prihvaćen, procesira se async (npr. eRačun) |
204 No Content | Uspješno, bez sadržaja (npr. DELETE) |
4xx — Greška klijenta
| Status | Značenje |
|---|
400 Bad Request | Neispravan zahtjev (krivi JSON, nedostaju parametri) |
401 Unauthorized | Nedostaje ili neispravan API ključ |
403 Forbidden | Nemate dozvolu za ovu akciju |
404 Not Found | Resurs ne postoji |
409 Conflict | Konflikt (npr. duplikat računa) |
422 Unprocessable Entity | Validacija prošla, ali poslovna logika odbila |
429 Too Many Requests | Rate limit prekoračen |
5xx — Greška servera
| Status | Značenje |
|---|
500 Internal Server Error | Naša greška — kontaktirajte podršku |
502 Bad Gateway | Problem s upstream servisom (FINA/Porezna) |
503 Service Unavailable | Servis privremeno nedostupan |
504 Gateway Timeout | Timeout od Porezne/FINA-e |
Popis error kodova
Autentifikacija
| Kod | HTTP | Opis |
|---|
authentication_required | 401 | Nedostaje Authorization header |
invalid_api_key | 401 | API ključ nije valjan |
api_key_revoked | 401 | API ključ je opozvan |
api_key_expired | 401 | API ključ je istekao |
insufficient_permissions | 403 | Ključ nema dozvolu za ovu akciju |
Validacija
| Kod | HTTP | Opis |
|---|
invalid_request | 400 | Neispravan JSON ili struktura zahtjeva |
missing_parameter | 400 | Obavezan parametar nedostaje |
invalid_parameter | 400 | Parametar ima neispravnu vrijednost |
invalid_oib | 400 | OIB nije valjan (kriva kontrolna znamenka ili format) |
invalid_iban | 400 | IBAN nije valjan |
invalid_kpd | 400 | KPD šifra ne postoji |
invalid_date | 400 | Datum nije u ispravnom formatu (ISO 8601) |
Fiskalizacija (F1)
| Kod | HTTP | Opis |
|---|
duplicate_invoice | 409 | Račun s tim brojem već postoji |
fiscalization_failed | 422 | Porezna odbila račun (detalji u message) |
invalid_invoice_number | 400 | Broj računa nije u formatu X/Y/Z |
invalid_business_unit | 400 | Poslovni prostor nije registriran |
certificate_error | 500 | Problem s FINA certifikatom |
eRačuni (F2)
| Kod | HTTP | Opis |
|---|
einvoice_delivery_failed | 422 | Nije moguće dostaviti eRačun |
recipient_not_found | 422 | Primatelj nije pronađen u FINA registru |
einvoice_rejected | 422 | Primatelj odbio eRačun |
invalid_ubl | 400 | Generirani UBL nije validan (naša greška) |
Eksterni servisi
| Kod | HTTP | Opis |
|---|
porezna_unavailable | 503 | Porezna uprava trenutno nedostupna |
porezna_timeout | 504 | Timeout od Porezne (pokušajte ponovno) |
fina_unavailable | 503 | FINA eRačun servis nedostupan |
fina_timeout | 504 | Timeout od FINA-e |
Rate limiting
| Kod | HTTP | Opis |
|---|
rate_limit_exceeded | 429 | Prekorač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]