REST API za izdavanje fiskalnih računa u Srbiji (e-fiskalizacija Poreske uprave). Ovo je cela površina API-ja — jedan poziv za račun, po jedan za avans i refundaciju.
| Bazni URL | https://api.fiskalapi.rs |
|---|---|
| Format | JSON (Content-Type: application/json) |
| Autentikacija | Authorization: Bearer <API_KLJUC> |
Dobijaš dva ključa. fapi_test_… radi u sandbox režimu — pravi tok, probni računi, ne naplaćuje se i ne troši limit. fapi_live_… izdaje prave fiskalne račune. Isti pozivi, samo zameniš ključ.
POST /api/racuni — promet prodaja (fiskalni račun)
curl https://api.fiskalapi.rs/api/racuni \
-H "Authorization: Bearer fapi_live_…" \
-H "Content-Type: application/json" \
-d '{
"paymentType": "Card",
"items": [
{ "name": "Pretplata Pro/kom", "quantity": 1, "unitPrice": 2400, "labels": ["А"] }
],
"kupac": { "email": "kupac@primer.rs" }
}'
{
"mode": "live",
"brojRacuna": "NRXJ2JLE-XXXXXXXX-1",
"qrKod": "data:image/png;base64,…",
"verifikacija": "https://suf.purs.gov.rs/v/?vl=…",
"zurnal": "…tekstualni fiskalni isečak…",
"brojaci": { "invoiceCounter": 1, "totalCounter": 1 },
"sdcDateTime": "2026-08-28T12:41:05+02:00"
}
sdcDateTime je vreme koje je računu dodelila Poreska uprava. Sačuvaj ga — ide kao referentDocumentDT kad taj račun budeš refundirao. Vraća se i u sandbox režimu.
| Polje | Opis |
|---|---|
items[] | Stavke: name, quantity, unitPrice (RSD), labels (poreske oznake), opciono gtin. Umesto stavki može i amountRsd + description. |
payments[] / paymentType | Način plaćanja: Cash, Card, WireTransfer, Voucher, MobileMoney, Check, Other. |
labels | Poreske oznake iz GET /api/status. Npr. А = Nije u PDV (0%), Ђ = opšta (20%), Е = posebna (10%). |
buyerId | Opciono — identifikacija kupca (npr. "10:PIB") za račun na firmu. |
transactionId | Opciono, ali preporučeno — tvoj ID; idempotency ključ. Ponovljen poziv sa istim ID-em vraća isti račun i "ponovljen": true, ne izdaje novi. |
occurredAt | Opciono — vreme uplate (ЕСИР време), samo kad je novac primljen pre izdavanja računa. Šalji apsolutan trenutak u ISO 8601 sa zonom: 2026-08-04T15:20:00+02:00 ili 2026-08-04T13:20:00Z. Zapis bez zone se čita kao beogradsko vreme. |
POST /api/racuni/avans — za pretplate i uplate unapred. Ista struktura tela kao promet prodaja.
Račun svom kupcu šalješ ti, svojim mejlom i sa svog domena: uzmi qrKod i verifikacija iz odgovora i ubaci ih u svoju potvrdu porudžbine. Polje "kupac": { "email": "…" } se podrazumevano zanemaruje (u odgovoru tada stiže napomena, a mejlPoslat je null) — mejl bi išao sa našeg domena, pa bi tuđi odbijeni mejlovi trošili reputaciju sa koje isporučujemo API ključeve i alarme.
POST /api/racuni/obuka — račun tipa Обука na tvom pravom bezbednosnom elementu. Prolazi ceo lanac do Poreske uprave, ali nije promet: nema poreske obaveze, ne ulazi u tvoju evidenciju prodaje i ne naplaćujemo ga. Koristi ga da proveriš da kasa radi pre prve prave kupovine. Ista struktura tela kao promet prodaja.
POST /api/racuni/refundacija — zahteva referentDocumentNumber (PFR broj originalnog računa) i referentDocumentDT.
Obe vrednosti stižu u odgovoru na račun koji storniraš: brojRacuna → referentDocumentNumber, sdcDateTime → referentDocumentDT. Isto važi i u sandboxu, pa se refundacija može ispratiti od početka do kraja test ključem.
Delimične refundacije: refundacija sme da nosi isti transactionId kao prodaja koju storniraš — to su za nas dva različita računa. Ali druga delimična refundacija iste porudžbine mora imati drugačiji transactionId (npr. 1284-ref-1, 1284-ref-2). Ako pošalješ isti, dobićeš nazad prvu refundaciju uz "ponovljen": true — to nije greška, nego zaštita: sa iste strane ne razlikujemo „ponovi drugu ratu" od „webhook se ponovio".
Pošalji svoj transactionId uz svaki poziv. Ponovljen poziv sa istim ID-em vraća isti račun i "ponovljen": true (HTTP 200, isti oblik odgovora) — ne izdaje se drugi. To pokriva ponovljene webhookove, duple klikove i istovremene pozive.
Bez transactionId te zaštite NEMA. Svaki poziv je tada nov račun: ako procesor ponovi webhook, izdaće se drugi pravi fiskalni račun za istu kupovinu — a to se ispravlja jedino refundacijom, na teret tvoje firme. Zato u odgovoru na takav poziv stiže i napomena koja na to podseća. Polje je formalno opciono samo zbog starijih integracija; tretiraj ga kao obavezno.
Ključ je klijent + tip računa + smer + transactionId, pa isti ID sme da se koristi za promet, avans i obuku — to su različiti računi i ne poništavaju se međusobno.
GET /api/racuni/{id} — vraća već izdat račun, po tvom transactionId ili po PFR broju računa. Za slučaj da izgubiš odgovor sa izdavanja: dokument je već prijavljen Poreskoj upravi i mora da postoji način da se pročita nazad.
Vraćaju se brojRacuna, iznos, sdcDateTime i verifikacija, a qrKod, zurnal i brojaci dok god je zapis o izdavanju kod nas (35 dana). Ako isti transactionId nosi više dokumenata (prodaja pa refundacija), racun je najnoviji, a ceo lanac stoji u racuni.
Vide se samo tvoji i samo pravi (live) računi — test računi se ne pamte. Nepoznat ID vraća 404. U sandboxu je zato odgovor na POST jedini izvor — sadrži sva polja, sdcDateTime uključujući.
GET /api/status — podaci obveznika, ESIR i aktuelne poreske stope (oznake i procenti). Uvek povlači stope od Poreske uprave — nikad ih ne kucaj ručno.
GET /api/usage — broj računa, mesečni trošak i iskorišćenost limita za tekući mesec (opciono ?month=YYYY-MM).
| Kod | Značenje |
|---|---|
401 | Nevalidan API ključ. |
403 | Nalog nije aktivan ili je suspendovan (neizmirena obaveza). |
402 | Dostignut mesečni limit računa. |
400 | Neispravno telo zahteva (npr. zbir plaćanja ≠ iznos, nepoznata oznaka). |
409 | Prethodni pokušaj sa istim transactionId nije razrešen — račun je možda već izdat, pa drugi ne izdajemo. Javi nam transactionId; proveravamo kod Poreske uprave. |
502 | Greška prema V-PFR-u Poreske uprave. Ako odgovor nosi "statusRacuna": "nepoznato", veza je pukla posle slanja i račun je možda izdat — ne ponavljaj automatski. |
Ako zahtev ode Poreskoj upravi, a odgovor ne stigne (timeout, prekid veze), niko na našoj strani ne zna da li je račun izdat. Tada dobijaš 502 sa "statusRacuna": "nepoznato".
Automatsko ponavljanje bi u tom slučaju moglo da napravi drugi pravi fiskalni račun za istu kupovinu — greška koja se ispravlja jedino refundacijom. Zato ponovljen poziv sa istim transactionId vraća 409 dok se ne proveri šta se stvarno desilo. Ako se račun u međuvremenu nađe u evidenciji, sve se razrešava samo i dobijaš ga nazad sa "ponovljen": true.
| Datum | Šta se promenilo |
|---|---|
2026-08-28 |
Sandbox vraća sdcDateTime i brojaci — odgovor sa test ključem sada ima ista polja kao live. Refundacija traži referentDocumentDT, a test računi se ne pamte, pa se to vreme uzima iz odgovora na sam POST.
|
2026-08-22 |
Novo: GET /api/racuni/{id} — izdat račun se sada može pročitati nazad, po transactionId ili po PFR broju. Ranije je odgovor na POST bio jedini primerak.
Ispravljeno u ovoj dokumentaciji: kupac.email se podrazumevano zanemaruje — mejl kupcu šalje prodavac. Ranije je ovde pisalo da račun „odmah stiže kupcu na mejl".
|
2026-08-09 |
occurredAt se čita kao apsolutan trenutak. Ranije se vrednost prosleđivala Poreskoj upravi doslovno, a V-PFR cifre štampa neizmenjene — pa je vreme na računu izlazilo pomereno za pomak zone, i integracije koje su to primetile slale su beogradski sat sa oznakom Z da bi ispis bio tačan.
Od ovog datuma vreme prevodimo mi: pošalji stvaran trenutak ( 2026-08-04T13:27:37Z ili 2026-08-04T15:27:37+02:00) i na računu piše 15:27:37. Zapis bez zone se čita kao beogradsko vreme.
Ako je tvoja integracija ranije dodavala sat/dva da bi ispis bio tačan — ukloni to, inače će račun sada nositi vreme pomereno unapred. Prepoznajemo taj obrazac i upozorenje ti stoji u „Moj nalog". |
2026-08-09 |
Zaštita od duplog računa i kod 409. Ponovljen transactionId vraća isti račun umesto novog; prekid veze posle slanja daje 502 sa "statusRacuna": "nepoznato", a naredni pokušaj 409 dok se ne razreši. |
2026-08-09 |
Vremena u prikazima i obračunu su beogradska. Dan i mesec se seku na beogradskoj ponoći — račun izdat 1. u 00:30 pripada novom mesecu (fakture, KPO knjiga). |
Pitanja? Kontakt · Početna · English version