LogiLL ESIR

LogiLL ESIR — Primeri integracije (API i fajlovi)

LogiLL ESIR je u postupku odobrenja kod Poreske uprave Republike Srbije. Do odobrenja koristi se samo na probnom (sandbox) okruženju.

LogiLL ESIR — primeri integracije (REST API i fajlovi)

Ovaj dokument dopunjuje poglavlje 13. Integracije korisničkog uputstva. Ovde su gotovi primeri koji se mogu kopirati: svaki poziv REST API-ja, svaka vrsta računa i svaki oblik fajla za razmenu (JSON, TXT, XML), sa očekivanim odgovorom.

LogiLL ESIR i LogiLL LPFR su u postupku odobrenja Poreske uprave. Primeri važe za sandbox okruženje i probne račune dok proizvod nije odobren.

Pregled svih mogućnosti

Preuzmite gotove primere: primeri-integracije.zip. U njemu su folderi json, txt i xml sa istim artiklima i komitentima, i 27 gotovih računa (json/racuni/) koji pokrivaju svaki način plaćanja i svaku vrstu računa iz ovog pregleda. Fajl README.txt u arhivi objašnjava šta je koji.

Šta se šalje JSON TXT XML
Artikli da da da
Komitenti (kupci) da — —
Računi (svih vrsta) da — —

Vrste računa (vrsta) i tip transakcije (tip)

vrsta Šta je tip Posebna polja
Promet običan fiskalni račun Prodaja, Refundacija referenca kod refundacije; storno: true za poništavanje
Avans uplata unapred Prodaja stavke su uplate po poreskoj oznaci; datum_uplate; referenca na prethodni avans
Promet + zatvara_avans konačni račun koji zatvara avans Prodaja zatvara_avans (PFR broj avansa); ESIR sam izdaje i Avans-Refundaciju
Predračun predračun (nije promet) Prodaja
Promet + referenca promet na osnovu predračuna Prodaja referenca na predračun
Obuka račun za obuku kasira (nije promet) Prodaja
Kopija ponovni primerak izdatog računa isti tip kao original referenca je obavezna, stavke se prepisuju
Promet + bez_naknade promet bez naknade (poklon) Prodaja bez_naknade: true, bez plaćanja
Promet + jednonamenski_vaucer prodaja jednonamenskog vaučera Prodaja jednonamenski_vaucer: true, jedna stavka (oznaka i iznos)
Promet + korporacijska kartica plaćanje korporacijskom karticom Prodaja kupac.opciono: "50:…", plaćanje Voucher

Načini plaćanja (placanja[].nacin)

nacin Naziv na računu Napomene
Cash Готовина jedini koji dozvoljava primljeno (kusur); jednom po računu
Card Платна картица može više puta na istom računu; povraćaj na karticu samo istog dana
Check Чек može više puta
WireTransfer Пренос на рачун
Voucher Ваучер uz korporacijsku karticu je propisan
MobileMoney Инстант плаћање može više puta
Other Други безготовински начин плаћања uz promet bez naknade je propisan

Pravila za sva plaćanja:

  • Zbir placanja[].iznos mora biti tačno jednak iznosu računa. Kusur nije plaćanje: kod gotovine se upisuje iznos koji zatvara račun, a primljeno služi samo za izračunavanje kusura.
  • Podešavanja kase mogu isključiti neke načine (Podešavanja → Načini plaćanja). Ako je režim „ograničen", nema Card, Check i MobileMoney (unose se kao gotovina); „Prikaži na kasi" bira koje načine radnja koristi. Račun sa isključenim načinom se odbija.
  • Kod refundacije novac ide kupcu, pa nema kusura (primljeno se ignoriše).

Polja računa

Polje Obavezno Šta je
radnja samo za fajlove uvek "racun" (kod REST API-ja se ne šalje)
spoljni_id da vaš jedinstven broj dokumenta (zaštita od duple fiskalizacije)
vrsta, tip da v. tabelu iznad
kasir da ime i prezime kasira (štampa se na računu)
stavke da v. ispod; kod avansa i vaučera samo pfr_oznaka i cena
placanja da v. iznad; izostavlja se samo kod prometa bez naknade
kupac ne (obavezan kod refundacije prometa) v. ispod
referenca kod refundacije, kopije, storna, novog avansa, prometa iz predračuna broj i vreme originalnog računa (PFR broj i PFR vreme)
izlaz ne ["TERMALNI"], ["A4"], ["PDF"] ili kombinacija; [] = bez štampe; izostavljeno = kao na kasi. Izlaz mora biti uključen u podešavanjima ESIR-a
reklama ne tekst ispod kraja fiskalnog računa (ne ide Poreskoj upravi)
datum_uplate ne (samo avans) kad je uplata starija, npr. "2026-10-06 14:00"; ne sme biti u budućnosti
zatvara_avans ne PFR broj avansa koji se zatvara konačnim računom
bez_naknade ne true za poklon
jednonamenski_vaucer ne true za prodaju jednonamenskog vaučera
storno ne true uz tip: "Refundacija" za poništavanje celog računa

Stavka (stavke[]): sifra i naziv (obavezni), jm (neobavezno, podrazumevano kom), pfr_oznaka (obavezno, poreska oznaka od PFR-a), kolicina (do 3 decimale, veća od 0), cena (do 2 decimale, veća od 0), gtin (neobavezno; ispravan 8/12/13/14-cifreni).

Kupac (kupac):

Polje Obavezno Šta je
dokument da ID kupca u obliku šifra:broj, npr. 10:101234569
opciono ne opciono polje, npr. 20:SNPDV-2026-15 ili 50:broj korporacijske kartice
naziv, adresa, mesto ne štampaju se ispod fiskalnog dela
sifra, tip ne ako je sifra upisana, kupac se čuva u komitente (tip PRAVNO ili FIZICKO)

Šifre ID kupca (dokument): 10 PIB · 11 JMBG (preduzetnik) · 12 PIB:JBKJS · 13 penzionerska kartica · 14 PIB poljoprivrednog gazdinstva · 15 JMBG poljoprivrednog gazdinstva · 16 BPG · 20 lična karta · 21 izbeglička legitimacija · 22 EBS · 23 pasoš · 30 strani pasoš · 31 diplomatska legitimacija · 32–35 lična karta MKD/MNE/ALB/BIH · 36 lična karta EU/CH/NO/IS · 40 strani poreski broj. Opciono polje: 20 broj SNPDV · 21 LNPDV · 30–33 PPO/ZPPO/MPPO/IPPO-PDV · 50 broj korporacijske kartice · 60 period storna korporacijskih kartica.

Artikli i komitenti

Artikal (artikli[]) Obavezno Šta je
sifra da ključ artikla
naziv da
jm ne podrazumevano kom
mp_cena da maloprodajna cena
pfr_oznaka da poreska oznaka od PFR-a
gtin (u TXT/XML barkod) ne ispravan GTIN
aktivan ne false isključuje artikal (brisanja nema)
Komitent (kupci[]) Obavezno Šta je
sifra da ključ komitenta u vašem programu
tip da PRAVNO ili FIZICKO
naziv, adresa, mesto naziv da
dokumenti da {"10": "101234569"} (šifra vrste ID-a → broj)
aktivan ne false isključuje komitenta

Spisak primera u arhivi

Fajl Šta pokazuje
racuni/01–09 svih 7 načina plaćanja, mešovito (kartica + gotovina) i dve kartice na istom računu
racuni/10–12 kupac bez šifre (uz opciono polje), kupac sa šifrom, fizičko lice
racuni/13, 14 reklama i izbor štampe, račun bez štampe
racuni/20–22 predračun, promet iz predračuna, obuka
racuni/30–32 avans: prva uplata, naredna uplata, konačni račun
racuni/40–42 bez naknade, jednonamenski vaučer, korporacijska kartica
racuni/50–53 refundacija (gotovina, kartica), kopija, storno

Računi koji se pozivaju na prethodni račun (21, 31, 32, 50–53) imaju primer broja i vremena u referenca: zamenite ih stvarnim PFR brojem i vremenom. Kopija, storno i zatvaranje avansa rade samo za račune koji su izdati na ovom ESIR-u, a refundacija na karticu samo istog dana kad je original izdat.

Pre prvog primera

  1. U LogiLL ESIR otvorite Podešavanja → Integracije → Nova integracija i sačuvajte prikazani API ključ (prikazuje se samo jednom).
  2. Saznajte port: LogiLL ESIR sluša na 127.0.0.1, na portu 8625 (ili sledećem slobodnom do 8635). U primerima je 8625.
  3. Poreske oznake (Ђ, Е, …) nisu iste u sandboxu i produkciji i ne zadajete ih sami. Prvo pozovite GET /poreske-stope (primer 2) i koristite oznake koje vrati.
  4. Primeri koriste ćirilična slova poreskih oznaka (Ђ, Е). Šaljite ih u UTF-8.

Sadržaj

  • A. REST API — A1 status · A2 poreske stope · A3 sinhronizacija · A4 artikli · A5 kupci · A6 računi (promet, više plaćanja, kupac, bez štampe, avans, predračun, bez naknade, vaučer, korporacijska kartica) · A7 refundacija, kopija, storno · A8 pitanje po spoljni_id, usklađivanje, PDF · A9 greške · A10 redosled koraka koji ne gubi račune
  • B. Fajlovi — B1 kako se upisuje zahtev · B2 račun · B3 artikli (JSON, TXT, XML) · B4 kupci · B5 odgovori · B6 kad PFR nije dostupan · B7 čitanje odgovora

A. REST API

U primerima su prikazani samo metod i adresa (i telo, gde ga ima). Isto važi za svaki poziv:

  • zaglavlje Authorization: Bearer VAS_API_KLJUC (osim za GET /status);
  • zaglavlje Content-Type: application/json; charset=utf-8 kad se šalje telo;
  • telo je JSON u UTF-8.

Kao orijentir, ceo HTTP zahtev za izdavanje računa izgleda ovako (alat ili programski jezik kojim ga šaljete nije bitan):

POST /api/v1/racuni HTTP/1.1
Host: 127.0.0.1:8625
Authorization: Bearer VAS_API_KLJUC
Content-Type: application/json; charset=utf-8

{ ...telo računa iz primera... }

U ostalim primerima se ovaj omot ne ponavlja. Telo (racun.json, artikli.json, kupci.json) je JSON iz primera.

U svim primerima: spoljni_id je vaš broj dokumenta, obavezan je i jedinstven (zaštita od duple fiskalizacije, v. A8 i A10). Primeri se šalju na adresu:

POST http://127.0.0.1:8625/api/v1/racuni
telo: racun.json

Poziv je sinhron: čekajte odgovor najmanje 45 sekundi (L-PFR obično odgovara za 1–3 s).

Odgovor (200, i kad je PFR odbio račun — tada je status: "GRESKA" i greska kaže razlog):

{
  "id": 128, "spoljni_id": "DOK-58231", "status": "FISKALIZOVAN",
  "vrsta": "Promet", "tip": "Prodaja", "iznos": 379.98, "kusur": 20.02,
  "pfr": {"broj": "DENJ4FJH-DENJ4FJH-33", "vreme": "2026-10-08T08:07:43+02:00",
          "brojac": "19/33ПП", "url": "https://suf.purs.gov.rs/v/?vl=…",
          "tekst": "============ ФИСКАЛНИ РАЧУН ============\n…", "qr_gif": "R0lGOD…"},
  "stampa": [{"izlaz": "TERMALNI", "ok": true, "poruka": ""}],
  "greska": ""
}

Zapamtite pfr.broj i pfr.vreme: potrebni su za refundaciju, kopiju, storno i avans.

A6.1 Prodaja gotovinom (najčešći slučaj)

{
  "spoljni_id": "DOK-58231",
  "vrsta": "Promet",
  "tip": "Prodaja",
  "kasir": "Jovan Jović",
  "stavke": [
    {"sifra": "1001", "naziv": "Sok narandža 1l", "jm": "kom", "pfr_oznaka": "Ђ", "kolicina": 2, "cena": 189.99}
  ],
  "placanja": [{"nacin": "Cash", "iznos": 379.98, "primljeno": 400}]
}

primljeno (neobavezno, samo gotovina) služi za izračunavanje kusura (kusur u odgovoru). Zbir placanja[].iznos mora biti jednak iznosu računa.

Načini plaćanja: Cash, Card, Check, WireTransfer, Voucher, MobileMoney, Other.

A6.2 Više stavki i dva načina plaćanja, uz GTIN

{
  "spoljni_id": "DOK-58232",
  "vrsta": "Promet",
  "tip": "Prodaja",
  "kasir": "Jovan Jović",
  "stavke": [
    {"sifra": "1001", "naziv": "Sok narandža 1l", "jm": "kom", "gtin": "8601234567899", "pfr_oznaka": "Ђ", "kolicina": 2, "cena": 189.99},
    {"sifra": "1002", "naziv": "Hleb beli 500g", "jm": "kom", "pfr_oznaka": "Е", "kolicina": 1, "cena": 79.90},
    {"sifra": "2001", "naziv": "Mleko 1l", "jm": "l", "pfr_oznaka": "Е", "kolicina": 1.5, "cena": 120.00}
  ],
  "placanja": [
    {"nacin": "Card", "iznos": 300},
    {"nacin": "Cash", "iznos": 339.88, "primljeno": 400}
  ]
}

Količine mogu imati do 3 decimale, iznosi do 2. Artikli iz stavki se čuvaju u šifarniku ESIR-a; cena u stavci važi samo za taj račun, a cena u šifarniku se menja samo preko PUT /artikli (ili kad artikal ne postoji).

A6.3 Račun sa kupcem — dve varijante

Varijanta A: bez sifra. Kupac se ne čuva u komitente; njegov ID ide samo na račun. Koristi se za jednokratne kupce, fizička lica i firme koje ne vodite u šifarniku.

{
  "spoljni_id": "DOK-58233", "vrsta": "Promet", "tip": "Prodaja", "kasir": "Jovan Jović",
  "stavke": [{"sifra": "1001", "naziv": "Sok narandža 1l", "jm": "kom", "pfr_oznaka": "Ђ", "kolicina": 10, "cena": 189.99}],
  "placanja": [{"nacin": "WireTransfer", "iznos": 1899.90}],
  "kupac": {"dokument": "10:101234569", "opciono": "20:SNPDV-2026-15",
            "naziv": "Kupac DOO", "adresa": "Bulevar 1", "mesto": "Beograd"}
}

dokument je u obliku šifra:broj (10: PIB, 11: JMBG, 20: lična karta…). opciono je neobavezno (npr. 20: broj SNPDV obrasca). Naziv, adresa i mesto se štampaju ispod fiskalnog dela.

Varijanta B: sa sifra. Kupac se čuva ili osvežava u komitentima (kao A5) i ide na račun.

{
  "spoljni_id": "DOK-58234", "vrsta": "Promet", "tip": "Prodaja", "kasir": "Jovan Jović",
  "stavke": [{"sifra": "1001", "naziv": "Sok narandža 1l", "jm": "kom", "pfr_oznaka": "Ђ", "kolicina": 1, "cena": 189.99}],
  "placanja": [{"nacin": "Card", "iznos": 189.99}],
  "kupac": {"sifra": "K-245", "tip": "PRAVNO", "naziv": "Kupac DOO", "dokument": "10:101234569",
            "adresa": "Bulevar 1", "mesto": "Beograd"}
}

U obe varijante ESIR proverava oblik ID-a i kontrolnu cifru PIB-a/JMBG-a (loš ID vraća 400).

A6.4 Bez štampe (samo elektronski račun)

Ako sami štampate ili prikazujete račun, isključite štampu u LogiLL ESIR-u:

{
  "spoljni_id": "DOK-58235", "vrsta": "Promet", "tip": "Prodaja", "kasir": "Jovan Jović",
  "stavke": [{"sifra": "1001", "naziv": "Sok narandža 1l", "jm": "kom", "pfr_oznaka": "Ђ", "kolicina": 1, "cena": 189.99}],
  "placanja": [{"nacin": "Cash", "iznos": 189.99}],
  "izlaz": []
}

izlaz može biti ["TERMALNI"], ["A4"], ["PDF"] ili kombinacija; izostavljeno = kao na kasi (prvi uključeni izlaz). Izabrani izlaz mora biti uključen u podešavanjima ESIR-a. Tekst računa i QR su uvek u odgovoru (pfr.tekst, pfr.qr_gif).

A6.5 Avans — uplata, nastavak i zatvaranje

Prva uplata avansa. Stavke nisu artikli nego uplate po poreskoj oznaci (bez šifre i naziva):

{
  "spoljni_id": "AV-1001-1", "vrsta": "Avans", "tip": "Prodaja", "kasir": "Jovan Jović",
  "stavke": [{"pfr_oznaka": "Ђ", "cena": 12000}],
  "placanja": [{"nacin": "Card", "iznos": 12000}],
  "datum_uplate": "2026-10-06 14:00"
}

datum_uplate je neobavezan: koristi se samo kad je uplata starija (ne sme biti u budućnosti).

Naredna uplata poziva se na prethodni avans (mora biti poslednji u lancu i otvoren):

{
  "spoljni_id": "AV-1001-2", "vrsta": "Avans", "tip": "Prodaja", "kasir": "Jovan Jović",
  "stavke": [{"pfr_oznaka": "Ђ", "cena": 8000}],
  "placanja": [{"nacin": "Cash", "iznos": 8000}],
  "referenca": {"broj": "DENJ4FJH-DENJ4FJH-41", "vreme": "2026-10-06T14:02:11+02:00"}
}

Konačni račun koji zatvara avans (prodaja stvarne robe; avans se obračunava, placanja pokrivaju samo ostatak, a ako je avans pokrio sve, mogu biti prazna):

{
  "spoljni_id": "AV-1001-KONACNI", "vrsta": "Promet", "tip": "Prodaja", "kasir": "Jovan Jović",
  "zatvara_avans": "DENJ4FJH-DENJ4FJH-42",
  "stavke": [{"sifra": "S-77", "naziv": "Radovi na montaži", "jm": "kom", "pfr_oznaka": "Ђ", "kolicina": 1, "cena": 20500}],
  "placanja": [{"nacin": "Cash", "iznos": 500}],
  "kupac": {"dokument": "10:101234569"}
}

zatvara_avans je PFR broj avansa iz lanca (obično poslednje uplate). Iznos stavki konačnog računa mora biti najmanje jednak ukupno uplaćenom avansu, a placanja je ostatak koji kupac još plaća. ESIR sam izdaje i prateću Avans-Refundaciju, pa odgovor nosi i polje prateci.

A6.6 Predračun i promet iz predračuna

{
  "spoljni_id": "PRED-77", "vrsta": "Predračun", "tip": "Prodaja", "kasir": "Jovan Jović",
  "stavke": [{"sifra": "1001", "naziv": "Sok narandža 1l", "jm": "kom", "pfr_oznaka": "Ђ", "kolicina": 5, "cena": 189.99}],
  "placanja": [{"nacin": "Cash", "iznos": 949.95}]
}

Kad kupac prihvati, izdajete običan Promet sa istim stavkama i referenca koja pokazuje na predračun:

{
  "spoljni_id": "DOK-58240", "vrsta": "Promet", "tip": "Prodaja", "kasir": "Jovan Jović",
  "stavke": [{"sifra": "1001", "naziv": "Sok narandža 1l", "jm": "kom", "pfr_oznaka": "Ђ", "kolicina": 5, "cena": 189.99}],
  "placanja": [{"nacin": "Card", "iznos": 949.95}],
  "referenca": {"broj": "DENJ4FJH-DENJ4FJH-50", "vreme": "2026-10-12T09:15:00+02:00"}
}

A6.7 Promet bez naknade (poklon)

Bez placanja:

{
  "spoljni_id": "DOK-58250", "vrsta": "Promet", "tip": "Prodaja", "kasir": "Jovan Jović",
  "bez_naknade": true,
  "stavke": [{"sifra": "1001", "naziv": "Sok narandža 1l", "jm": "kom", "pfr_oznaka": "Ђ", "kolicina": 1, "cena": 189.99}]
}

A6.8 Jednonamenski vaučer

Jedna stavka, samo oznaka i iznos:

{
  "spoljni_id": "VAU-300", "vrsta": "Promet", "tip": "Prodaja", "kasir": "Jovan Jović",
  "jednonamenski_vaucer": true,
  "stavke": [{"pfr_oznaka": "Ђ", "cena": 3000}],
  "placanja": [{"nacin": "Cash", "iznos": 3000}]
}

A6.9 Korporacijska kartica

Plaćanje je uvek Voucher, a broj kartice ide u opciono polje kupca uz 50::

{
  "spoljni_id": "DOK-58260", "vrsta": "Promet", "tip": "Prodaja", "kasir": "Jovan Jović",
  "stavke": [{"sifra": "1001", "naziv": "Sok narandža 1l", "jm": "kom", "pfr_oznaka": "Ђ", "kolicina": 1, "cena": 189.99}],
  "placanja": [{"nacin": "Voucher", "iznos": 189.99}],
  "kupac": {"dokument": "10:101234569", "opciono": "50:1234-5678-9012"}
}

A7. Refundacija, kopija i storno

Sve je isti POST /racuni, sa referencom na original (referenca.broj i referenca.vreme — PFR broj i vreme originalnog računa) i svojim novim spoljni_id. ESIR proverava da original postoji, da je fiskalizovan i nije storniran, da svaka stavka postoji na originalu (ista šifra, cena i oznaka) i da količina ne prelazi „kupljeno minus već vraćeno".

Refundacija (cela ili deo). kupac je obavezan kod refundacije prometa:

{
  "spoljni_id": "REF-58231-1", "vrsta": "Promet", "tip": "Refundacija", "kasir": "Jovan Jović",
  "referenca": {"broj": "DENJ4FJH-DENJ4FJH-33", "vreme": "2026-10-08T08:07:43+02:00"},
  "stavke": [{"sifra": "1001", "naziv": "Sok narandža 1l", "jm": "kom", "pfr_oznaka": "Ђ", "kolicina": 1, "cena": 189.99}],
  "placanja": [{"nacin": "Cash", "iznos": 189.99}],
  "kupac": {"dokument": "20:009876543"}
}

Kod povraćaja gotovinom ESIR sam izdaje i Kopiju refundacije; odgovor tada nosi oba računa ("prateci": [ … ]).

Kopija (ponovni primerak originalnog računa). Stavke možete izostaviti, ESIR ih prepisuje sa originala:

{
  "spoljni_id": "KOP-58231-1", "vrsta": "Kopija", "tip": "Prodaja", "kasir": "Jovan Jović",
  "referenca": {"broj": "DENJ4FJH-DENJ4FJH-33", "vreme": "2026-10-08T08:07:43+02:00"}
}

Ne pravi se kopija kopije: kopija se uvek radi od originalnog računa.

Storno (poništavanje pogrešnog računa u celini). Stavke izostavite ili pošaljite identične originalu; ID kupca (10:PIB prodavca) stavlja ESIR:

{
  "spoljni_id": "STO-58231", "vrsta": "Promet", "tip": "Refundacija", "storno": true, "kasir": "Jovan Jović",
  "referenca": {"broj": "DENJ4FJH-DENJ4FJH-33"}
}

Kopija i storno rade samo za račune koji su izdati na ovoj kasi (original mora biti u žurnalu LogiLL ESIR-a).

A8. Pitanje po spoljni_id, usklađivanje i PDF

Šta je sa računom ako odgovor nije stigao? Prvo pitajte, pa tek onda ponovo šaljite:

GET http://127.0.0.1:8625/api/v1/racuni?spoljni_id=DOK-58231

Odgovor je isti kao pri izdavanju. Ako račun sa tim spoljni_id nije stigao do ESIR-a, vraća se 404:

{"kod": "NEPOZNAT", "poruka": "račun sa ovim spoljni_id nije stigao do ESIR-a — bezbedno je poslati ga ponovo", "polje": "spoljni_id"}

Tada smete ponovo da šaljete isti račun.

Usklađivanje — svi računi posle zadatog ESIR id (redom, sa izvorom KASA / API / FAJL). Služi za račune izdate ručno na kasi, koje vaš program samo prikazuje:

GET http://127.0.0.1:8625/api/v1/racuni?posle_id=120&limit=200

Pamtite poslednji viđeni id.

PDF računa za arhivu:

GET http://127.0.0.1:8625/api/v1/racuni/128/pdf

A9. Greške

Svaka greška ima oblik {"kod": "...", "poruka": "...", "polje": "..."}. kod je stabilan za mašinsku obradu, poruka je za čoveka (iste poruke kao na kasi).

HTTP Značenje Primer odgovora
400 Loš zahtev. PFR-u ništa nije poslato, ispravite i pošaljite ponovo. {"kod": "PLACANJE", "poruka": "nedostaje 10,00 — zbir plaćanja mora biti 250,00", "polje": "placanja"}
401 Nema ključa, ključ je pogrešan ili je integracija isključena. {"kod": "KLJUC", "poruka": "API ključ nije važeći ili je integracija isključena"}
402 Licenca nije aktivna (izdavanje je blokirano, ostalo radi). {"kod": "LICENCA", "poruka": "…"}
404 Samo za pitanje po spoljni_id: račun nije stigao do ESIR-a, bezbedno je poslati ga ponovo. {"kod": "NEPOZNAT", …}
409 Isti spoljni_id se upravo obrađuje (sačekajte i pitajte po spoljni_id), ili je avans već zatvoren/storniran (SUKOB). {"kod": "U_OBRADI", "poruka": "račun sa ovim spoljni_id se upravo obrađuje — sačekajte"}
503 PFR nije dostupan ili traži PIN. {"kod": "NIJE_SPREMNA", "poruka": "PFR traži PIN"}
200 + "status": "GRESKA" PFR je odbio račun; razlog je u greska. Ponovni pokušaj radite sa novim spoljni_id (npr. DOK-58231-2).

Vrednosti kod za loš zahtev (400) su: PLACANJE, STAVKE, KUPAC, REFERENCA, AVANS, JSON (neispravan JSON) i ZAHTEV (ostalo); polje polje pokazuje na deo zahteva. Ostali kodovi: KLJUC, LICENCA, U_OBRADI, SUKOB, NIJE_SPREMNA, NEPOZNAT, INTERNO. Za mašinsku obradu najpre gledajte HTTP status i status računa, a kod koristite za prikaz i evidenciju.

A10. Redosled koraka da se nijedan račun ne izgubi i ne udvostruči

Redosled je isti u svakom programu i jeziku:

  1. Pre slanja u svojoj bazi zabeležite da je dokument „poslat" (sa njegovim spoljni_id).
  2. GET /api/v1/status: ako je spremna: false, ne šaljite; prikažite razlog (npr. „PFR traži PIN").
  3. POST /api/v1/racuni i čekajte odgovor najmanje 45 sekundi.
  4. Po odgovoru: - 200 i status: FISKALIZOVAN: upišite pfr.broj, pfr.vreme, pfr.url i pfr.tekst uz dokument; dokument je „izdat". - 200 i status: GRESKA: PFR je odbio račun (razlog u greska). Dokument je „odbijen"; novi pokušaj ide sa novim spoljni_id. - 400, 401, 402, 503: ništa nije poslato PFR-u. Ispravite uzrok (zahtev, ključ, licenca, PFR/PIN) i pošaljite ponovo isti spoljni_id. - 409 U_OBRADI: isti račun se upravo obrađuje. Sačekajte nekoliko sekundi i pitajte (korak 5).
  5. Nema odgovora (istek vremena, pad veze, restart programa): ne šaljite ponovo naslepo. Pitajte GET /api/v1/racuni?spoljni_id=…: - 200: račun je izdat (ili odbijen); postupite kao u koraku 4. - 404 NEPOZNAT: račun nije stigao do ESIR-a; bezbedno je poslati isti zahtev ponovo. - bez odgovora: pokušajte kasnije; ne smišljajte novi spoljni_id.

Čak i kad isti spoljni_id pošaljete ponovo, ESIR PFR-u ništa ne šalje, već vraća već izdat račun, pa udvostručenja nema; pitanje samo jasnije kaže šta se desilo.


B. Razmena preko fajlova

Za program koji ne može da pošalje HTTP zahtev, već samo upisuje fajlove u folder. Razmena se uključuje u LogiLL ESIR-u (Podešavanja → Integracije → Razmena preko fajlova) i ne traži API ključ: kontrola pristupa je pristup folderu.

Folder (podrazumevano C:\ProgramData\LogiLL ESIR\razmena\) ima:

ulaz\        ← vaš program upisuje zahteve
izlaz\       → LogiLL ESIR upisuje <ime>.odgovor.json i <ime>.status.json
obradjeno\   → zahtevi koji su uspeli (briše se posle 30 dana)
greska\      → odbijeni zahtevi

B1. Kako se upisuje zahtev

  1. Upišite fajl pod imenom <ime>.json.tmp (ili .txt.tmp, .xml.tmp).
  2. Kad je upis gotov, preimenujte ga u <ime>.json. Program čita samo fajlove sa pravom ekstenzijom, pa nikad ne pročita nedovršen fajl.
  3. Ime neka počinje datumom i vremenom, npr. 20261008-081500_DOK58231.json. Obrada ide po imenu, redom. Kodiranje je UTF-8 (BOM je dozvoljen), najviše 5 MB. Folder se proverava svake sekunde.

Isti postupak važi bez obzira na jezik ili alat kojim je napisan vaš program; potrebno je samo da program može da upiše fajl i da ga preimenuje. Ako vaš alat ne zna da preimenuje fajl, dovoljno je da upiše ceo fajl u drugi folder na istom disku pa ga premesti u ulaz\ pod pravim imenom (premeštanje na istom disku je trenutno).

Primer redosleda za jedan račun:

1. upiši  ulaz\20261008-081500_DOK58231.json.tmp   (ceo sadržaj, UTF-8)
2. zatvori fajl
3. preimenuj u  ulaz\20261008-081500_DOK58231.json

B2. Račun u fajlu

Sadržaj je isti JSON kao za POST /racuni, uz dodatno polje "radnja": "racun". Primeri A6 i A7 važe i ovde: dodajte samo "radnja": "racun". Isti oblik koristi i kopija, refundacija i storno.

20261008-081500_DOK58231.json:

{
  "radnja": "racun",
  "spoljni_id": "DOK-58231",
  "vrsta": "Promet",
  "tip": "Prodaja",
  "kasir": "Jovan Jović",
  "stavke": [
    {"sifra": "1001", "naziv": "Sok narandža 1l", "jm": "kom", "pfr_oznaka": "Ђ", "kolicina": 2, "cena": 189.99}
  ],
  "placanja": [{"nacin": "Cash", "iznos": 379.98, "primljeno": 400}]
}

Refundacija kroz fajl (isto kao A7):

{
  "radnja": "racun",
  "spoljni_id": "REF-58231-1", "vrsta": "Promet", "tip": "Refundacija", "kasir": "Jovan Jović",
  "referenca": {"broj": "DENJ4FJH-DENJ4FJH-33", "vreme": "2026-10-08T08:07:43+02:00"},
  "stavke": [{"sifra": "1001", "naziv": "Sok narandža 1l", "jm": "kom", "pfr_oznaka": "Ђ", "kolicina": 1, "cena": 189.99}],
  "placanja": [{"nacin": "Cash", "iznos": 189.99}],
  "kupac": {"dokument": "20:009876543"}
}

B3. Artikli u fajlu — JSON, TXT ili XML

Vrsta fajla se prepoznaje po ekstenziji: .json, .txt ili .xml. Pravila su ista kao za A4 (sve ili ništa, brisanje preko aktivan).

JSON — telo sa radnja i nizom artikli:

20261012-093000_artikli.json:

{
  "radnja": "artikli",
  "artikli": [
    {"sifra": "1001", "naziv": "Sok narandža 1l", "jm": "kom", "mp_cena": 189.99, "pfr_oznaka": "Ђ", "gtin": "8601234567899", "aktivan": true},
    {"sifra": "1002", "naziv": "Hleb beli 500g", "jm": "kom", "mp_cena": 79.90, "pfr_oznaka": "Е"}
  ]
}

TXT — kolone razdvojene tabulatorom (ili tačka-zarezom, kao CSV iz Excel-a). Prvi red je zaglavlje; kolone mogu biti u bilo kom redosledu. Bez zaglavlja važi redosled sifra, naziv, jm, mp_cena, pfr_oznaka, barkod, aktivan. Cena sme imati zarez ili tačku. aktivan je 1/0 (ili da/true). Napomena: u TXT i XML-u kolona GTIN-a se zove barkod, a u JSON-u gtin.

20261012-093000_artikli.txt (znak → je tabulator):

sifra→naziv→jm→mp_cena→pfr_oznaka→barkod→aktivan
1001→Sok narandža 1l→kom→189,99→Ђ→8601234567899→1
1002→Hleb beli 500g→kom→79,90→Е→→1
1003→Staro pakovanje→kom→10,00→Ђ→→0

Isti oblik koristi Uvoz na ekranu Artikli. Najlakši uzorak dobijate kad u programu izvezete postojeće artikle (Šifarnici → Artikli → Izvoz → TXT).

XML:

20261012-093000_artikli.xml:

<?xml version="1.0" encoding="UTF-8"?>
<artikli>
  <artikal>
    <sifra>1001</sifra>
    <naziv>Sok narandža 1l</naziv>
    <jm>kom</jm>
    <mp_cena>189.99</mp_cena>
    <pfr_oznaka>Ђ</pfr_oznaka>
    <barkod>8601234567899</barkod>
    <aktivan>true</aktivan>
  </artikal>
  <artikal>
    <sifra>1002</sifra>
    <naziv>Hleb beli 500g</naziv>
    <jm>kom</jm>
    <mp_cena>79.90</mp_cena>
    <pfr_oznaka>Е</pfr_oznaka>
  </artikal>
</artikli>

B4. Kupci u fajlu

Samo JSON, sa radnja i nizom kupci (oblik kupca isti kao u A5):

20261012-093500_kupci.json:

{
  "radnja": "kupci",
  "kupci": [
    {"sifra": "K-245", "tip": "PRAVNO", "naziv": "Kupac DOO", "adresa": "Bulevar 1", "mesto": "Beograd",
     "dokumenti": {"10": "101234569"}, "aktivan": true}
  ]
}

B5. Odgovori

Za svaki zahtev LogiLL ESIR upiše izlaz\<ime>.odgovor.json (isti JSON kao odgovor API-ja), pa tek onda premesti zahtev u obradjeno\ (uspeh) ili greska\ (odbijen). Odgovore vi brišete kad ih pročitate; program ih sam ne briše.

Uspešan račun (izlaz\20261008-081500_DOK58231.odgovor.json; zahtev je u obradjeno\):

{"id": 128, "spoljni_id": "DOK-58231", "status": "FISKALIZOVAN", "iznos": 379.98,
 "pfr": {"broj": "DENJ4FJH-DENJ4FJH-33", "vreme": "2026-10-08T08:07:43+02:00"}, "greska": ""}

Odbijen račun (zahtev je u greska\):

{"kod": "PLACANJE", "poruka": "nedostaje 10,00 — zbir plaćanja mora biti 250,00", "polje": "placanja"}

Šifarnik (artikli ili kupci):

{"dodato": 2, "izmenjeno": 0, "nepromenjeno": 0, "greske": []}

Nepoznata radnja (greška u radnja):

{"kod": "RADNJA", "poruka": "nepoznata radnja „racn“ (racun, artikli, kupci)", "polje": "radnja"}

B6. Kad PFR nije dostupan

Ako PFR traži PIN, nema veze ili licenca nije aktivna, zahtev za račun ostaje u ulaz\, a LogiLL ESIR upisuje izlaz\<ime>.status.json:

{"status": "CEKA", "razlog": "PFR traži PIN"}
  • Ako PFR proradi u roku od 2 minuta od pojave fajla, račun se izdaje sam, redom, a status.json se briše.
  • Ako je fajl stariji, ESIR ga ne izdaje sam (kupac verovatno više nije na kasi). Status postaje:

json {"status": "CEKA_ODLUKU", "razlog": "stariji od 2 min — kasir odlučuje"}

Kasir na ekranu bira Izdaj izabrane (izdaje se sa današnjim vremenom) ili Odbaci izabrane. Odbačen zahtev dobija odgovor {"spoljni_id": "…", "status": "ODBACENO", "poruka": "odbačeno na kasi — račun nije izdat"}. - Zahtev možete otkazati brisanjem fajla iz ulaz\, dok nije obrađen. - Ako se LogiLL ESIR ugasi usred obrade, fajl ostaje u ulaz\; pri ponovnoj obradi isti spoljni_id vraća već izdat račun, pa ne nastaje dupli fiskalni račun.

Zahtevi iza onog koji čeka takođe čekaju (obrada ide redom).

B7. Čitanje odgovora

Posle upisa zahteva postupak je ovakav:

  1. Svake sekunde (do npr. 60 s) proverite da li postoji izlaz\<ime>.odgovor.json sa istim imenom kao zahtev.
  2. Kad se pojavi, pročitajte ga (UTF-8) i uzmite polje status (FISKALIZOVAN ili greška), pfr.broj, pfr.url, pfr.tekst; kod greške poruka ili greska.
  3. Obrišite odgovor iz izlaz\ kad ga preuzmete (program ga sam ne briše).
  4. Ako odgovora nema, proverite postoji li izlaz\<ime>.status.json (CEKA ili CEKA_ODLUKU, v. B6), a zatim da li je zahtev prešao u obradjeno\ ili greska\.

Ako odgovor ne stigne, ne šaljite isti račun pod novim spoljni_id: proverite izlaz\<ime>.status.json i foldere obradjeno\ i greska\. Ponovljen isti spoljni_id je bezbedan: ESIR vraća već izdat račun.


Najčešće greške u integraciji

  • 400 zbog poreske oznake: oznaka mora biti iz GET /poreske-stope. Sandbox i produkcija imaju različite oznake.
  • Zbir plaćanja nije jednak iznosu računa: iznos računa je zbir kolicina × cena po stavkama, zaokružen na 2 decimale.
  • Refundacija bez kupca: za Promet + Refundacija obavezan je kupac.dokument.
  • Isti spoljni_id za dva različita računa: drugi neće biti izdat, već će vratiti prvi. Svaki dokument mora imati svoj broj.
  • Ponavljanje posle greške PFR-a (GRESKA): koristite novi spoljni_id.
  • Fajl se ne obrađuje: proverite da je preimenovan u pravu ekstenziju (ne .tmp), da je razmena uključena i da je ESIR pokrenut; dnevnik integracija (Podešavanja → Integracije) prikazuje svaki poziv.