# BokaPOS API dokumentacija > BokaPOS je ESIR u cloudu za prodaju na daljinu u Srbiji (BOKA GROUP DOO). Ovaj tekst je kompletna API dokumentacija u jednoj datoteci, generisana iz istog izvora kao https://bokapos.rs/api. Mašinski ugovor: https://api.bokapos.rs/openapi.yaml. Osnovna adresa: https://api.bokapos.rs. Token: https://auth.bokapos.rs/realms/boka/protocol/openid-connect/token. Verzija ugovora 1.0.0, ažurirano 2026-08-29. ## Sadržaj - [Početak](https://bokapos.rs/api) - [Autentifikacija](https://bokapos.rs/api/autentifikacija) - [Konvencije](https://bokapos.rs/api/konvencije) - [Račun za promet](https://bokapos.rs/api/prodaja) - [Prikazi i dostava](https://bokapos.rs/api/racuni) - [Refundacija](https://bokapos.rs/api/refundacija) - [Avans](https://bokapos.rs/api/avans) - [Predračun i obuka](https://bokapos.rs/api/predracun-i-obuka) - [Katalog i podešavanja](https://bokapos.rs/api/katalog) - [Dnevnik i izveštaji](https://bokapos.rs/api/dnevnik) - [Greške](https://bokapos.rs/api/greske) - [Produkcija](https://bokapos.rs/api/produkcija) - [Referenca operacija](https://bokapos.rs/api/referenca) --- # BokaPOS API Jedan HTTP poziv, jedan fiskalni račun. Vaš web shop, ERP ili platforma pošalje stavke i plaćanja, BokaPOS ih fiskalizuje preko V-PFR-a Poreske uprave i vrati broj računa, verifikacioni link, PDF i QR kod. Ovde je sve što integratoru treba: brzi start, pravila, tokovi i referenca svake operacije. - **Brzi start** (#brzi-start): Od pristupnih podataka do prvog fiskalizovanog računa u sandboxu, korak po korak. - **Autentifikacija i okruženja** (https://bokapos.rs/api/autentifikacija): OAuth 2.0 client credentials, jedna adresa za sandbox i produkciju, scope-ovi. - **Konvencije** (https://bokapos.rs/api/konvencije): Idempotencija, statusi dokumenta, iznosi, vreme, reference, načini plaćanja, kupac. - **Referenca operacija** (https://bokapos.rs/api/referenca): Svaka operacija sa parametrima, telom, odgovorima i primerom u pet jezika. ## Šta API radi - **Izdaje fiskalne račune za prodaju na daljinu**: promet (prodaja), refundacija, avans, predračun, obuka i kopija, sa svim referencama koje propisi traže. - **Vraća kompletan paket računa**: PFR broj, vreme i brojač, verifikacioni link Poreske uprave, zvanični tekst žurnala, PDF u A4, 80 mm i 58 mm, PNG pregled i QR kod. - **Čuva elektronski dnevnik** svake operacije, uključujući odbijene i nepoznate ishode, sa pretragom, izvozom i izveštajem o prometu. - **Vodi složene tokove umesto vas**: refundacija sa automatskom kopijom kod gotovine, lanac avansa sa zatvaranjem, predračun sa referencom. Vi šaljete poslovni zahtev, BokaPOS sastavlja fiskalne dokumente. - **Šalje račun kupcu e-poštom** sa platforme, ako je uključen modul E-mail. - **Ne izmišlja**: račun postoji tek kada V-PFR vrati potpisan odgovor i BokaPOS ga trajno sačuva. Nema lažnog uspeha, nema tihog ponavljanja. > **Kome je namenjen:** Prodaji na daljinu: web shop, marketplace, SaaS platforma, ERP koji izdaje račune za online porudžbine. Prodaja licem u lice traži L-PFR i nije deo ovog API-ja (za to postoji [BokaLPFR](https://bokalpfr.rs)). ## Brzi start: prvi račun u sandboxu 1. **Zatražite sandbox pristup** Javite se na [office@bokagroup.rs](mailto:office@bokagroup.rs) ili preko [kontakt stranice](https://bokapos.rs/kontakt). BokaPOS otvara organizaciju, dodeljuje sandbox bezbednosni element i izdaje **client id** (`boka-sbx-...`) i **tajnu**. Tajna se prikazuje jednom; sačuvajte je u tajnama servera, nikad u kodu ili pregledaču. Sandbox je besplatan. 2. **Uzmite token** OAuth 2.0 client credentials na `https://auth.bokapos.rs/realms/boka/protocol/openid-connect/token`. Token važi 300 sekundi; keširajte ga i obnovite pre isteka. 3. **Proverite pristup** `GET /v1/runtime` vraća vašu organizaciju, client id i da li je fiskalni adapter spreman. 4. **Pronađite obveznika i prodajno mesto** `GET /v1/taxpayers`, pa `GET /v1/taxpayers/{taxpayerId}/business-premises`. Ta dva identifikatora idu u svaki fiskalni zahtev; sačuvajte ih u konfiguraciji. 5. **Pročitajte poreske oznake** `GET /v1/tax-rates` sa oba identifikatora. Oznake iz odgovora su jedine koje račun sme da nosi. Sandbox i produkcija imaju različit skup, pa ih nikad ne ugrađujte u kod. 6. **Izdajte račun** `POST /v1/fiscal-documents` sa `Idempotency-Key` zaglavljem. Odgovor 201 sa `fiscalized: true` je fiskalni račun; sve ostalo nije. 7. **Preuzmite PDF i link** Iz odgovora uzmite `pfr.verificationUrl` i `receipt.pdfA4Url` i sačuvajte `id` dokumenta uz porudžbinu. ### 1. Token ```bash curl -X POST "https://auth.bokapos.rs/realms/boka/protocol/openid-connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=$BOKAPOS_CLIENT_ID" \ -d "client_secret=$BOKAPOS_CLIENT_SECRET" ``` Odgovor tokena: ```json { "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6...", "expires_in": 300, "token_type": "Bearer", "scope": "tenant:read operations:read catalogue:read catalogue:write fiscal:read fiscal:write refund:write proforma-training:write advance:write advance:close configuration:read security-elements:read" } ``` Svaki sledeći poziv nosi `Authorization: Bearer `. U primerima ispod token je u promenljivoj okruženja `BOKAPOS_TOKEN`. ### 2. Provera pristupa GET /v1/runtime: ```bash curl -X GET "https://api.bokapos.rs/v1/runtime" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "manufacturer": "BOKA GROUP DOO", "productName": "BokaPOS", "esirNumber": "", "softwareVersion": "1.0.0", "buildCommit": "1f0d454e8b2c9a7d6f5e4c3b2a1908f7e6d5c4b3", "instanceId": "api-bokapos-rs", "organizationId": "7c1e9a4b-2d3f-4e5a-b6c7-8d9e0f1a2b3c", "clientId": "boka-sbx-k7m2p9x4q1wz", "fiscalEndpointsEnabled": true, "pfrAdapter": "configured" } ``` ### 3. Obveznik i prodajno mesto GET /v1/taxpayers: ```bash curl -X GET "https://api.bokapos.rs/v1/taxpayers" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` GET /v1/taxpayers/{taxpayerId}/business-premises: ```bash curl -X GET "https://api.bokapos.rs/v1/taxpayers/3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11/business-premises" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "items": [ { "id": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "puIdentifier": "1234567", "name": "Web shop", "commerceMode": "distance", "environment": "sandbox", "paymentMode": "all", "status": "active", "createdAt": "2026-08-21T09:05:00.000Z", "updatedAt": "2026-08-21T09:05:00.000Z" } ] } ``` ### 4. Poreske oznake GET /v1/tax-rates: ```bash curl -X GET "https://api.bokapos.rs/v1/tax-rates?taxpayerId=3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11&businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "source": "PFR", "environment": "sandbox", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "currentTaxGroupId": 8, "validFrom": "2022-05-01T00:00:00", "fetchedAt": "2026-09-01T08:14:02.118Z", "labels": [ { "label": "F", "category": "ECAL", "categoryType": 0, "rate": 11, "activeFrom": "2022-05-01T00:00:00" }, { "label": "N", "category": "N-TAX", "categoryType": 0, "rate": 0, "activeFrom": "2022-05-01T00:00:00" }, { "label": "P", "category": "PBL", "categoryType": 2, "rate": 0.5, "activeFrom": "2022-05-01T00:00:00" }, { "label": "E", "category": "STT", "categoryType": 0, "rate": 6, "activeFrom": "2022-05-01T00:00:00" }, { "label": "T", "category": "TOTL", "categoryType": 1, "rate": 2, "activeFrom": "2022-05-01T00:00:00" }, { "label": "A", "category": "VAT", "categoryType": 0, "rate": 10, "activeFrom": "2022-05-01T00:00:00" }, { "label": "B", "category": "VAT", "categoryType": 0, "rate": 0, "activeFrom": "2022-05-01T00:00:00" }, { "label": "Ж", "category": "VAT", "categoryType": 0, "rate": 19, "activeFrom": "2022-05-01T00:00:00" }, { "label": "C", "category": "VAT-EXCL", "categoryType": 0, "rate": 0, "activeFrom": "2022-05-01T00:00:00" } ] } ``` Note: Sandbox Poreske uprave nosi generički test skup oznaka. U produkciji dobijate zvanične srpske oznake (na primer Ђ 20%, Е 10%, Г 0%, А bez PDV-a). Nikad ne ugrađujte oznake u kod. ### 5. Prvi račun POST /v1/fiscal-documents: ```bash curl -X POST "https://api.bokapos.rs/v1/fiscal-documents" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-4127-sale-1" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4127", "invoiceType": "NORMAL", "transactionType": "SALE", "cashier": { "id": "web-shop", "displayName": "Web shop" }, "items": [ { "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 8990, "gtin": "8606012345678", "taxLabels": [ "F" ] } ], "payments": [ { "type": "CARD", "amount": 8990 } ], "metadata": { "orderId": "4127", "channel": "web" } }' ``` Response 201: ```json { "id": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-sale-1", "clientReference": "ORDER-4127", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1042", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 897, "totalCounter": 1042, "invoiceCounterExtension": "ПП", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n115711881\nBOKA GROUP DOO\nBokaPOS sandbox\nРоза Луксембург 16\nБеоград-Раковица\nКасир: web-shop\nЕСИР број: 1656/1.0.0\n-------------ПРОМЕТ ПРОДАЈА-------------\nАртикли\n========================================\nНазив Цена Кол. Укупно\nBluetooth slušalice/kom (F)\n 8.990,00 1 8.990,00\n----------------------------------------\nУкупан износ: 8.990,00\nПлатна картица: 8.990,00\n========================================\nОзнака Име Стопа Порез\nF ECAL 11,00% 890,90\n----------------------------------------\nУкупан износ пореза: 890,90\n========================================\nПФР време: 01.09.2026. 10:15:32\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1042\nБројач рачуна: 897/1042ПП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/official-text", "jsonUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` > **Šta je u odgovoru:** `status: FISCALIZED` i `fiscalized: true` znače da račun postoji. `pfr.invoiceNumber` je zvanični broj računa, `pfr.verificationUrl` je link za proveru kod Poreske uprave (isti je u QR kodu), `pfr.journal` je zvanični tekst računa, a `receipt.*` su adrese prikaza. Sačuvajte `id`: on je ključ za kopije, refundacije i pretragu. ### 6. PDF računa GET /v1/fiscal-documents/{fiscalDocumentId}/representations/{representationFormat}: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-a4" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ --output racun-ORDER-4127.pdf ``` Isti dokument ima sedam prikaza (tekst, JSON, QR, PDF za tri formata papira, PNG). Pogledajte [Prikazi i dostava računa](https://bokapos.rs/api/racuni). ## Šta dalje - **Račun za promet** (https://bokapos.rs/api/prodaja): Sva polja zahteva, popusti, kupac (B2B), više načina plaćanja, kopija računa. - **Refundacija** (https://bokapos.rs/api/refundacija): Potpuna i delimična, po liniji izvornog računa, sa kopijom kod gotovine. - **Avans** (https://bokapos.rs/api/avans): Uplate pre isporuke, storno pogrešnog avansa, zatvaranje konačnim računom. - **Predračun i obuka** (https://bokapos.rs/api/predracun-i-obuka): Ponuda bez poreskog efekta i test računi, sa pravilima referenci. - **Dnevnik i izveštaji** (https://bokapos.rs/api/dnevnik): Pretraga, izvoz, izveštaj o prometu, stanje operacije, sertifikati, licenca. - **Prelazak u produkciju** (https://bokapos.rs/api/produkcija): Sertifikat, licenca, produkcioni kredencijal i kontrolna lista. ## Šta se radi u portalu, a ne kroz API API kredencijal ima fiksan skup ovlašćenja: fiskalizacija, katalog, čitanje obveznika, prodajnih mesta, sertifikata i licence. Sledeće radnje su namerno izvan API-ja i rade se u portalu [cloud.bokapos.rs](https://cloud.bokapos.rs) (vlasnik ili administrator organizacije) ili ih obavlja BokaPOS administracija: - kreiranje obveznika i prodajnih mesta (PIB i identifikator poslovnog prostora su nepromenljivi), - otpremanje i aktivacija produkcionog bezbednosnog elementa (sertifikata), - izdavanje i opoziv API kredencijala, - brendiranje računa (logo, kontakt, zahvalnica) i podešavanja dostave e-poštom, - korisnici i uloge, dnevnik aktivnosti, pretplata i fakture. --- # Autentifikacija i okruženja OAuth 2.0 client credentials preko običnog TLS-a. Jedna adresa za sve; sandbox i produkcija se razlikuju po kredencijalu, ne po URL-u. ## Adrese | Šta | Vrednost | | --- | --- | | API | `https://api.bokapos.rs` | | OpenAPI ugovor | `https://api.bokapos.rs/openapi.yaml` (javno, bez prijave) | | Token (client credentials) | `https://auth.bokapos.rs/realms/boka/protocol/openid-connect/token` | | Portal za ljude | `https://cloud.bokapos.rs` | Nema odvojenog sandbox hosta. Isti kod, iste adrese i isti pozivi rade u oba okruženja; menja se samo client id i tajna. ## Pristupni podaci API kredencijal (client id i tajnu) izdaje BokaPOS administracija na zahtev vlasnika organizacije, posebno za sandbox (`boka-sbx-...`) i za produkciju (`boka-prod-...`). Tajna se prikazuje jednom, pri izdavanju, i ne može se ponovo pročitati; ako se izgubi, kredencijal se opoziva i izdaje nov. Kredencijal je vezan za jednu organizaciju i jedno okruženje i nosi fiksan paket scope-ova opisan ispod. > **Tajna ostaje na serveru:** Kredencijal nikad ne sme u pregledač, mobilnu aplikaciju, javni repozitorijum ili log. Pozive ka BokaPOS-u uvek pravi vaš backend. Ako posumnjate da je tajna procurela, zatražite opoziv odmah; stari token važi najviše još 300 sekundi. ## Preuzimanje tokena Standardni `client_credentials` zahtev, `application/x-www-form-urlencoded`. Nije potrebno slati `scope`; token dobija sve scope-ove kredencijala. ```bash curl -X POST "https://auth.bokapos.rs/realms/boka/protocol/openid-connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=$BOKAPOS_CLIENT_ID" \ -d "client_secret=$BOKAPOS_CLIENT_SECRET" ``` Odgovor: ```json { "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6...", "expires_in": 300, "refresh_expires_in": 0, "token_type": "Bearer", "not-before-policy": 0, "scope": "tenant:read operations:read catalogue:read catalogue:write fiscal:read fiscal:write refund:write proforma-training:write advance:write advance:close configuration:read security-elements:read" } ``` - Token važi **300 sekundi**. Keširajte ga u memoriji procesa i obnovite kada mu ostane manje od, na primer, 30 sekundi. Ne tražite nov token za svaki poziv. - Odgovor `401` na bilo kom pozivu znači istekao ili nevažeći token: uzmite nov i ponovite isti zahtev (sa istim `Idempotency-Key`). - Token je JWT sa tvrdnjama `org_id` (vaša organizacija) i `boka_env` (`sandbox` ili `production`). Ne morate ih čitati; API ih primenjuje sam. - Pogrešan client id ili tajna vraćaju `401` sa `error: invalid_client` od servera za identitet. ## Zaglavlje svakog poziva Zaglavlja: ```http Authorization: Bearer Content-Type: application/json Idempotency-Key: order-4127-sale-1 (samo na fiskalnim izmenama) Accept: application/json ``` ## Scope-ovi kredencijala Svaki API kredencijal dobija isti paket od dvanaest scope-ova. Oni određuju koje operacije sme da pozove; sve ostale operacije iz ugovora pripadaju portalu i BokaPOS konzoli. | Scope | Dozvoljava | | --- | --- | | `fiscal:write` | izdavanje računa za promet, kopija i dostava e-poštom | | `fiscal:read` | čitanje dokumenata, prikaza, dnevnika, izveštaja, dostava, avansnih slučajeva | | `refund:write` | refundacija kroz `/v1/refund-workflows` | | `advance:write` | otvaranje avansnog slučaja, avansne uplate, storno | | `advance:close` | zatvaranje avansnog slučaja | | `proforma-training:write` | predračun i obuka | | `operations:read` | stanje operacije | | `catalogue:read`, `catalogue:write` | katalog proizvoda, uvoz i izvoz | | `configuration:read` | poreske stope | | `tenant:read` | obveznici, prodajna mesta, runtime, licenca | | `security-elements:read` | metapodaci sertifikata | ## Sandbox i produkcija - **Kredencijal nosi okruženje.** Sandbox kredencijal može da radi samo sa sandbox bezbednosnim elementom, produkcioni samo sa produkcionim. Ukrštanje vraća `403 CREDENTIAL_ENVIRONMENT_MISMATCH` pre bilo kakve rezervacije. - **Sandbox element dodeljuje BokaPOS** iz sopstvenog fonda; sandbox računi zato izlaze pod PIB-om BOKA GROUP DOO i verifikuju se na `sandbox.suf.purs.gov.rs`. Produkcioni element je sertifikat vaše firme koji vlasnik otprema u portalu. - **Sandbox je besplatan i nikad blokiran** licencom. Produkcija traži važeću licencu; `GET /v1/license` kaže unapred da li je fiskalizacija dozvoljena. - **Poreske oznake se razlikuju.** Sandbox Poreske uprave nosi generički test skup; produkcija zvanične srpske oznake. Zato se oznake uvek čitaju iz `GET /v1/tax-rates`. - **Kredencijal vidi samo svoje okruženje.** Svako čitanje je ograničeno: sandbox ključ lista samo sandbox obveznike, prodajna mesta, bezbednosne elemente i dokumente, produkcioni samo produkcione. Objekat drugog okruženja za vas ne postoji, pa čitanje po `id`-u vraća `404`, a podešavanje koje registrujete (`POST /v1/taxpayers`) pripada okruženju vašeg ključa. PIB je jedinstven po okruženju, pa vaša firma može da postoji jednom u sandboxu i jednom u produkciji. - **Idempotency ključevi su jedinstveni po organizaciji u oba okruženja.** Ponovna upotreba ključa iz sandbox testiranja u produkciji vraća `409 IDEMPOTENCY_KEY_REUSED_IN_OTHER_ENVIRONMENT`; izaberite nov ključ umesto ponavljanja. - **Ista organizacija, oba okruženja.** Vlasnik u portalu vidi sandbox i produkcione dokumente jedno pored drugog dok organizacija ne pređe u produkciju; od tada portal podrazumevano sakriva sandbox podatke (vlasnik ih može ponovo prikazati u Podešavanjima). Vaš sistem ih razlikuje po kredencijalu kojim je zvao. Prelazak u produkciju je opisan na stranici [Prelazak u produkciju](https://bokapos.rs/api/produkcija): sertifikat, aktivacija, licenca, produkcioni kredencijal, zamena u konfiguraciji. Kod se ne menja. ## Provera posle prijave GET /v1/runtime: ```bash curl -X GET "https://api.bokapos.rs/v1/runtime" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "manufacturer": "BOKA GROUP DOO", "productName": "BokaPOS", "esirNumber": "", "softwareVersion": "1.0.0", "buildCommit": "1f0d454e8b2c9a7d6f5e4c3b2a1908f7e6d5c4b3", "instanceId": "api-bokapos-rs", "organizationId": "7c1e9a4b-2d3f-4e5a-b6c7-8d9e0f1a2b3c", "clientId": "boka-sbx-k7m2p9x4q1wz", "fiscalEndpointsEnabled": true, "pfrAdapter": "configured" } ``` `pfrAdapter: configured` i `fiscalEndpointsEnabled: true` znače da je fiskalizacija moguća za vaše okruženje. `esirNumber` je prazan dok Poreska uprava ne dodeli broj odobrenja; kada ga dodeli, štampa se na svakom računu. --- # Konvencije Pravila koja važe za sve pozive: identifikatori, idempotencija, statusi dokumenta i kako ih tumačiti, iznosi, vreme, vrste računa, reference, načini plaćanja, kupac, paginacija i oblik grešaka. ## Identifikatori u svakom zahtevu | Polje | Šta je | Odakle | | --- | --- | --- | | `taxpayerId` | obveznik (pravno lice sa PIB-om) | `GET /v1/taxpayers` | | `businessPremiseId` | prodajno mesto (poslovni prostor Poreske uprave) sa svojim bezbednosnim elementom | `GET /v1/taxpayers/{taxpayerId}/business-premises` | | `clientReference` | vaša referenca: broj porudžbine, fakture ili transakcije; pretraživa u dnevniku | vaš sistem | | `cashier.id` | identifikator kasira ili sistema koji izdaje račun; štampa se na računu | vaš sistem (na primer `web-shop`) | | `Idempotency-Key` | zaglavlje koje sprečava dupli račun | vaš sistem, iz `clientReference` i vrste radnje | ## Idempotency-Key Svaka fiskalna izmena (`POST` na `/v1/fiscal-documents`, `/copies`, `/v1/refund-workflows`, `/v1/advance-cases*`, `/v1/proforma-training-workflows`, `/v1/receipt-deliveries`) zahteva zaglavlje `Idempotency-Key` dužine 16 do 200 znakova. Ključ je jedinstven unutar vaše organizacije i vezuje se za kanonski sadržaj zahteva: - **isti ključ, isti sadržaj**: API vraća originalnu operaciju (200 umesto 201) i ne izdaje drugi račun, ma koliko puta ponovili; - **isti ključ, drugačiji sadržaj**: `409 IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_REQUEST` sa `operationId` originala; - **nov ključ**: nova operacija, i potencijalno nov račun. > **Kako birati ključ:** Izvedite ga iz nečega što je već jedinstveno u vašem sistemu i opisuje radnju: `order-4127-sale-1`, `order-4127-refund-2`, `order-5001-advance-3`, `order-4127-email-1`. Ne koristite nasumične UUID-e koje ne čuvate: kada mreža pukne posle slanja, morate moći da ponovite tačno isti ključ. Response 409: ```json { "code": "IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_REQUEST", "operationId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761" } ``` ## Statusi dokumenta Svaki fiskalni zahtev postaje trajna operacija sa statusom. Status je istina; HTTP kod je samo njegov sažetak. | Status | Značenje | HTTP | `fiscalized` | `retryable` | | --- | --- | --- | --- | --- | | `FISCALIZED` | V-PFR je potpisao račun i odgovor je trajno sačuvan. **Jedini status koji znači račun.** | 201 (200 pri ponavljanju) | true | false | | `REJECTED` | V-PFR je odbio zahtev (validacija). Nije račun. `pfrRejection` na pojedinačnom čitanju kaže koje polje. | 422 | false | false | | `NOT_FISCALIZED` | V-PFR nije bio dostupan pre slanja; ništa nije poslato. | 503 | false | true | | `OUTCOME_UNKNOWN` | Zahtev je možda poslat, odgovor nije stigao. Nije račun, ali može da postane. **Ne ponavljati.** | 503 | false | false | | `RECONCILING` | BokaPOS proverava kod V-PFR-a da li nepoznat ishod postoji (samo čitanjem). Prelazno. | 503 | false | false | | `RECEIVED`, `VALIDATED`, `SUBMITTING` | Prelazni statusi tokom sinhronog poziva; vidite ih samo u dnevniku ako čitate u toku obrade. | n/a | false | false | ## Kako tumačiti odgovor 1. **201 i fiscalized: true** Račun postoji. Sačuvajte `id`, `pfr.invoiceNumber`, `pfr.sdcTime`, `pfr.verificationUrl` i, po potrebi, PDF. Porudžbina je fiskalizovana. 2. **503 i retryable: true** Ništa nije poslato (`NOT_FISCALIZED`, na primer `PFR_SUBMISSION_FAULT` ili `CURRENT_TAX_CONFIGURATION_UNAVAILABLE`). Sačekajte nekoliko sekundi i pošaljite **isti zahtev sa istim ključem**. Ograničite broj pokušaja i posle toga prepustite operateru. 3. **503 i status OUTCOME_UNKNOWN** Ne šaljite nov zahtev za istu prodaju. Zapamtite `id` i proveravajte `GET /v1/operations/{id}` (na primer na 30 sekundi, pa ređe). BokaPOS u pozadini razrešava ishod isključivo čitanjem kod V-PFR-a; kada ga nađe, status postaje `FISCALIZED`. Ako ishod ostane nepoznat, operater odlučuje u portalu. 4. **422** Zahtev krši pravilo (naše ili V-PFR-ovo). Ništa nije izdato. Ispravite zahtev i pošaljite ga sa **novim** ključem, jer je stari ključ vezan za pogrešan sadržaj. 5. **403** Okruženje ili licenca. Ništa nije izdato. Sandbox nikad ne dobija 403 zbog licence. 6. **409** Sukob: ključ ponovo upotrebljen sa drugim sadržajem, ili radnja koja nije dozvoljena u trenutnom stanju toka (avans, predračun). Pročitajte stanje i nastavite od njega. > **Nikad dva računa za jednu prodaju:** Jedino što sme da izda drugi račun za istu porudžbinu je nov ključ. Zato nov ključ generišite tek kada ste sigurni da prethodna operacija nije i neće postati račun (`REJECTED`, ili `NOT_FISCALIZED` koji ste odustali da ponavljate). `OUTCOME_UNKNOWN` nikad nije takav trenutak. ## Iznosi, količine i zaokruživanje - Sve cene i iznosi su **bruto, u dinarima, sa najviše dve decimale** (`8990.00`). Više decimala V-PFR odbija (šifra 2804). - `unitPrice` je konačna jedinična cena posle popusta. Porez ne šaljete: BokaPOS ga računa iz poreske oznake po zvaničnim pravilima i V-PFR ga potpisuje. - `unitPriceBeforeDiscount` je opciona cena pre popusta, samo za prikaz izvan fiskalnog dela računa; mora biti veća od `unitPrice`. - `quantity` ima do tri decimale (`1.5`), minimum `0.001`. - Zbir `quantity × unitPrice` po stavkama, zaokružen na dve decimale, mora biti jednak zbiru `payments`. Inače `422` sa greškom u polju `totals`. - Više načina plaćanja na istom računu je dozvoljeno (`payments` je lista). ## Vreme - Sva vremena su ISO 8601. `createdAt` i `updatedAt` su u UTC (`Z`). `pfr.sdcTime` je vreme potpisa V-PFR-a sa pomakom koji je V-PFR poslao (`+02:00` ili `+01:00`); to je zvanično vreme računa. - Filteri `pfrFrom`/`pfrTo` u dnevniku i izveštajima se odnose na `sdcTime`; `createdFrom`/`createdTo` na trenutak kada je BokaPOS primio zahtev. Donja granica je uključena, gornja isključena. - Ne šaljete vreme računa. Jedini izuzetak je avansna uplata virmanom primljena ranije (`paymentOccurredAt`), po zvaničnom pravilu; vidite [Avans](https://bokapos.rs/api/avans). ## Vrste računa i transakcija | `invoiceType` | `transactionType` | Zvanično | Operacija | | --- | --- | --- | --- | | `NORMAL` | `SALE` | Промет Продаја | `POST /v1/fiscal-documents` | | `NORMAL` | `REFUND` | Промет Рефундација | `POST /v1/refund-workflows` | | `COPY` | `SALE` / `REFUND` | Копија | `POST /v1/fiscal-documents/{id}/copies` (i automatski kod refundacije gotovinom) | | `ADVANCE` | `SALE` / `REFUND` | Аванс | `/v1/advance-cases/...` | | `PROFORMA` | `SALE` / `REFUND` | Предрачун | `POST /v1/proforma-training-workflows` | | `TRAINING` | `SALE` / `REFUND` | Обука | `POST /v1/proforma-training-workflows` | `POST /v1/fiscal-documents` prihvata samo `NORMAL SALE`; sve ostalo ima svoj tok koji BokaPOS vodi na serveru, sa ispravnim referencama i redosledom. ## Reference između dokumenata Refundacija, kopija i konačni račun posle avansa moraju da se pozovu na izvorni dokument (PFR broj i vreme). Kada je izvor dokument koji je BokaPOS izdao, šaljete samo njegov `fiscalDocumentId` (`{ "source": "BOKA", "fiscalDocumentId": "..." }`) i BokaPOS upisuje tačne PFR podatke; na istom obvezniku i prodajnom mestu. Referenca na dokument drugog ESIR-a (`source: EXTERNAL`) traži tačan PFR broj, vreme i vrstu i podržana je samo za kopiju kroz `POST /v1/fiscal-documents`; refundacija i avans spoljne dokumente ne prihvataju. | Novi dokument | Sme da se pozove na | | --- | --- | | Промет Рефундација | Промет Продаја (BokaPOS izvor) | | Копија | Промет ili Аванс, prodaja ili refundacija, koji je fiskalizovan | | Аванс Продаја (sledeća uplata) | prethodnu Аванс Продају istog slučaja (automatski) | | Аванс Рефундација | poslednju Аванс Продају (automatski) | | Промет Продаја (konačni račun) | Аванс Рефундацију zatvaranja (automatski) | | Предрачун Рефундација | Предрачун Продају (BokaPOS izvor) | | Обука Рефундација | Обука Продају (BokaPOS izvor) | ## Načini plaćanja | `type` | Zvanično | Tipična upotreba | | --- | --- | --- | | `CARD` | Платна картица | kartično plaćanje online | | `WIRE_TRANSFER` | Пренос на рачун | virman, uplatnica, e-banking | | `INSTANT_PAYMENT` | Инстант плаћање | IPS QR, instant transfer | | `CASH` | Готовина | pouzeće naplaćeno u gotovini; refundacija gotovinom traži kopiju sa potpisom | | `VOUCHER` | Ваучер | vaučer, poklon kartica, korporativna kartica (uz opciono polje kupca `50:`) | | `CHECK` | Чек | retko | | `OTHER` | Друго безготовинско плаћање | sve ostalo bezgotovinsko | Prodajno mesto može da radi u ograničenom režimu plaćanja (samo `OTHER`, `CASH`, `WIRE_TRANSFER`, `VOUCHER`); tada ostali načini vraćaju `422 PAYMENT_TYPE_NOT_ALLOWED_ON_PREMISE`. Režim se vidi u polju `paymentMode` prodajnog mesta. ## Identifikacija kupca `buyer.id` je zvanični `prefiks:vrednost`. Obavezan je na svakoj refundaciji, kod prodaje firmi koje traže PIB na računu, i u drugim slučajevima koje propisi nabrajaju. Za domaću firmu (`10:`, `12:` ili `14:` sa važećim PIB-om) BokaPOS automatski dodaje naziv i adresu kupca iz registra NBS ispod identifikacije, na svim prikazima; vraća ih i u `buyerDetails`. | Prefiks | Vrednost | | --- | --- | | `10:` | PIB domaćeg pravnog lica ili preduzetnika | | `11:` | JMBG domaćeg fizičkog lica koje obavlja samostalnu delatnost | | `12:` | PIB i JBKJS budžetskog korisnika, `PIB:JBKJS` | | `13:` | broj penzionerske kartice | | `14:` / `15:` / `16:` | PIB, JMBG odnosno BPG poljoprivrednog gazdinstva | | `20:` | broj lične karte | | `21:` | broj izbegličke legitimacije | | `22:` | EBS stranca sa boravkom u Srbiji | | `23:` | broj domaćeg pasoša | | `30:` | broj stranog pasoša | | `31:` do `36:` | diplomatske i strane lične karte prema zvaničnoj listi | | `40:` | strani poreski broj (TIN) | `buyer.optionalField` je opciono polje kupca, takođe `prefiks:vrednost`: `20:` SNPDV, `21:` LNPDV, `30:` do `33:` PPO-PDV obrasci, `50:` broj korporativne kartice (plaćanje je `VOUCHER`), `60:` period refundacije korporativne kartice `ddMMyyyy_ddMMyyyy`. Isti prefiks znači različite stvari u dva polja. ## Paginacija Liste dnevnika koriste stabilan keyset: odgovor nosi `nextCursor`, koji šaljete kao `cursor` za sledeću stranicu; `null` je kraj. `pageSize` je do 200 (podrazumevano 50). Lista proizvoda koristi isti obrazac sa UUID cursor-om. Redosled je po `createdAt` pa `id`, opadajuće, pa nova stranica nikad ne preskače i ne ponavlja zapis. ## Oblik grešaka | Oblik | Kada | Primer | | --- | --- | --- | | `{ "code": "...", "message"?: "..." }` | pravilo BokaPOS-a ili V-PFR-a, 4xx i 5xx | `{ "code": "TAX_LABEL_NOT_CURRENT", "invalidLabels": ["Ђ"] }` | | RFC 9457 problem (`application/problem+json`) | validacija polja, 422 | `{ "status": 422, "errors": { "items[0].unitOfMeasure": ["..."] } }` | | `{ "code": "IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_REQUEST", "operationId": "..." }` | 409 | vidite iznad | | fiskalni dokument sa `fiscalized: false` | 503 na fiskalnom pozivu | status i `failureCode` kažu šta se desilo | Potpun katalog kodova sa preporukom šta uraditi je na stranici [Greške](https://bokapos.rs/api/greske). --- # Račun za promet Glavni poziv integracije: kupac je platio, vi šaljete stavke i plaćanja, BokaPOS izdaje Промет Продаја. Ovde su sva polja zahteva, popust, kupac, više načina plaćanja i kopija računa. ## Kada se izdaje Račun za promet se izdaje u trenutku kada je promet ostvaren: kod prodaje na daljinu to je kada je roba isporučena ili usluga izvršena, odnosno kada je plaćanje primljeno, u skladu sa vašim poslovnim modelom i propisima. Ako kupac plaća pre isporuke, a isporuka je kasnije, to je [avans](https://bokapos.rs/api/avans). Ako samo šaljete ponudu, to je [predračun](https://bokapos.rs/api/predracun-i-obuka). ## Zahtev POST /v1/fiscal-documents: ```bash curl -X POST "https://api.bokapos.rs/v1/fiscal-documents" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-4127-sale-1" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4127", "invoiceType": "NORMAL", "transactionType": "SALE", "cashier": { "id": "web-shop", "displayName": "Web shop" }, "items": [ { "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 8990, "gtin": "8606012345678", "taxLabels": [ "F" ] } ], "payments": [ { "type": "CARD", "amount": 8990 } ], "metadata": { "orderId": "4127", "channel": "web" } }' ``` ### Polja | Polje | Obavezno | Pravilo | | --- | --- | --- | | `taxpayerId`, `businessPremiseId` | da | obveznik i aktivno prodajno mesto za prodaju na daljinu | | `clientReference` | da | vaš broj porudžbine; ne mora biti jedinstven, ali je pretraživ | | `invoiceType`, `transactionType` | da | ovde uvek `NORMAL` i `SALE` | | `cashier.id` | da | kasir ili sistem; `displayName` je opcion | | `items[]` | da, bar jedna | vidite ispod | | `payments[]` | da, bar jedno | zbir jednak zbiru stavki; više načina plaćanja je dozvoljeno | | `buyer` | ne | obavezan kada propis traži identifikaciju kupca (B2B sa PIB-om i drugi slučajevi) | | `commercialFooter` | ne | vaš tekst ispod fiskalnog dela (do 2000 znakova): zahvalnica, reklamacije, kontakt | | `metadata` | ne | vaši parovi ključ-vrednost; čuvaju se uz operaciju, nikad ne idu V-PFR-u i nisu na računu | | `reference` | ne | samo za kopiju spoljnog dokumenta (`source: EXTERNAL`); promet prodaja nema referencu | ### Stavka | Polje | Obavezno | Pravilo | | --- | --- | --- | | `name` | da | naziv artikla ili usluge, do 2048 znakova; na računu se štampa kao `naziv/jedinica` | | `unitOfMeasure` | da | jedinica mere (`kom`, `kg`, `h`, `m`...), do 50 znakova; izuzetak su samo propisane avansne stavke | | `quantity` | da | do tri decimale, najmanje 0.001 | | `unitPrice` | da | konačna bruto jedinična cena posle popusta, dve decimale | | `taxLabels` | da | jedna ili više oznaka iz `GET /v1/tax-rates`; obično jedna | | `gtin` | ne | GTIN/EAN 8 do 14 cifara; štampa se na računu | | `catalogProductId` | ne | `id` proizvoda iz kataloga, ako ga vodite u BokaPOS-u; stavke mogu biti i potpuno slobodne | | `unitPriceBeforeDiscount` | ne | cena pre popusta, mora biti veća od `unitPrice`; prikazuje se izvan fiskalnog dela | > **Poreske oznake:** Pre izdavanja pročitajte `GET /v1/tax-rates` za to prodajno mesto i koristite samo oznake iz odgovora. Sandbox nosi test skup (`F`, `A`, `Ж`...), produkcija zvanične srpske oznake (na primer `Ђ` za opštu stopu). Oznaka koje nema u svežoj konfiguraciji vraća `422 TAX_LABEL_NOT_CURRENT` i ništa se ne šalje. ## Odgovor Response 201: ```json { "id": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-sale-1", "clientReference": "ORDER-4127", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1042", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 897, "totalCounter": 1042, "invoiceCounterExtension": "ПП", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n115711881\nBOKA GROUP DOO\nBokaPOS sandbox\nРоза Луксембург 16\nБеоград-Раковица\nКасир: web-shop\nЕСИР број: 1656/1.0.0\n-------------ПРОМЕТ ПРОДАЈА-------------\nАртикли\n========================================\nНазив Цена Кол. Укупно\nBluetooth slušalice/kom (F)\n 8.990,00 1 8.990,00\n----------------------------------------\nУкупан износ: 8.990,00\nПлатна картица: 8.990,00\n========================================\nОзнака Име Стопа Порез\nF ECAL 11,00% 890,90\n----------------------------------------\nУкупан износ пореза: 890,90\n========================================\nПФР време: 01.09.2026. 10:15:32\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1042\nБројач рачуна: 897/1042ПП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/official-text", "jsonUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` Ako isti zahtev (isti sadržaj, isti `Idempotency-Key`) pošaljete ponovo posle `201`, dobijate `200` sa istim dokumentom i istim `id`: račun se ne izdaje drugi put. Novi račun postoji samo posle prvog `201` sa `fiscalized: true`; `200` samo potvrđuje već izdati. | Polje | Značenje | | --- | --- | | `id` | identifikator dokumenta u BokaPOS-u: sačuvajte ga uz porudžbinu; služi za kopije, refundacije, prikaze i dostavu | | `status`, `fiscalized` | `FISCALIZED` i `true` znače da račun postoji | | `pfr.invoiceNumber` | zvanični broj računa `JID-JID-brojač` | | `pfr.sdcTime` | zvanično vreme računa (potpis V-PFR-a) | | `pfr.verificationUrl` | link za proveru računa kod Poreske uprave; kupcu se prosleđuje u ovom obliku ili kao QR kod | | `pfr.journal` | zvanični tekst računa (žurnal); može se prikazati ili štampati kakav jeste | | `pfr.totalAmount` | ukupan iznos koji je V-PFR potpisao | | `pfr.totalTax` | ukupan porez koji je V-PFR potpisao (zbir poreza po oznakama); može biti `null` | | `pfr.totalCounter`, `pfr.transactionTypeCounter`, `pfr.invoiceCounterExtension` | potpisani brojači i zvanična oznaka vrste računa (`ПП`, `ПР`, `АП`, `АР`...); mogu biti `null`, pa ih tako i primite; brojač je uvek i u žurnalu | | `receipt.*` | adrese sedam prikaza; vidite [Prikazi i dostava računa](https://bokapos.rs/api/racuni) | | `buyerDetails` | naziv i adresa kupca iz registra NBS kada je kupac domaća firma; inače `null` | ## Kupac, popust i više načina plaćanja Isti poziv pokriva prodaju firmi sa PIB-om (`buyer.id` sa prefiksom `10:`), popust na stavku (`unitPriceBeforeDiscount` samo za prikaz, `unitPrice` je ono što se fiskalizuje), decimalne količine, više stavki i podelu plaćanja na virman i karticu. POST /v1/fiscal-documents: ```bash curl -X POST "https://api.bokapos.rs/v1/fiscal-documents" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-4128-sale-1" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4128", "invoiceType": "NORMAL", "transactionType": "SALE", "cashier": { "id": "web-shop" }, "buyer": { "id": "10:106952811" }, "items": [ { "name": "Godišnja licenca", "unitOfMeasure": "kom", "quantity": 2, "unitPrice": 12000, "taxLabels": [ "F" ] }, { "name": "Instalacija", "unitOfMeasure": "h", "quantity": 1.5, "unitPrice": 4000, "unitPriceBeforeDiscount": 5000, "taxLabels": [ "F" ] } ], "payments": [ { "type": "WIRE_TRANSFER", "amount": 20000 }, { "type": "CARD", "amount": 10000 } ], "commercialFooter": "Hvala na kupovini. Reklamacije: podrska@primer.rs" }' ``` Response 201: ```json { "id": "8e7d6c5b-4a39-4210-8765-fedcba987650", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4128-sale-1", "clientReference": "ORDER-4128", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": "10:106952811", "buyerDetails": { "legalName": "PRIMER DOO BEOGRAD", "taxIdentifier": "106952811", "registrationNumber": "20712345", "address": "Bulevar kralja Aleksandra 1", "city": "Beograd", "source": "nbs-jrr", "resolvedAt": "2026-09-01T08:20:11.004Z" }, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1043", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 898, "totalCounter": 1043, "invoiceCounterExtension": "ПП", "totalAmount": 30000, "totalTax": 2972.973, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1043\nБројач рачуна: 898/1043ПП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/official-text", "jsonUrl": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` Popust je uvek deo cene: V-PFR ne poznaje polje za popust, pa BokaPOS šalje `unitPrice` kao konačnu cenu, a razliku prikazuje samo izvan fiskalnog dela računa. Popust na ceo račun rasporedite po stavkama pre slanja. ## Šta sačuvati u svom sistemu - `id` dokumenta i `Idempotency-Key` koji ste upotrebili (da biste mogli da ponovite isti zahtev posle prekida); - `pfr.invoiceNumber`, `pfr.sdcTime` i `pfr.verificationUrl` (za prikaz kupcu, knjigovodstvo i reklamacije); - po potrebi PDF, ali ne morate: prikazi su trajno dostupni na `receipt.*` adresama i nose `ETag`. ## Kopija računa Копија je zvanični dokument koji ponavlja fiskalizovan račun (promet ili avans, prodaja ili refundacija) kad kupac traži novi primerak. BokaPOS je pravi iz sačuvanog originala; vi šaljete samo kasira. Kopija se potpisuje kao nov dokument, štampa `ОВО НИЈЕ ФИСКАЛНИ РАЧУН` i nosi referencu na original. Kopija refundacije ima liniju za potpis kupca. Predračun, obuka i kopija se ne kopiraju. POST /v1/fiscal-documents/{fiscalDocumentId}/copies: ```bash curl -X POST "https://api.bokapos.rs/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/copies" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-4127-copy-1" \ -H "Content-Type: application/json" \ -d '{ "cashier": { "id": "web-shop" } }' ``` Response 201: ```json { "id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-copy-1", "clientReference": "COPY-ORDER-4127", "invoiceType": "COPY", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1044", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 899, "totalCounter": 1044, "invoiceCounterExtension": "КП", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1044\nБројач рачуна: 899/1044КП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/official-text", "jsonUrl": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "pfrNumber": "JWX4K9PL-JWX4K9PL-1042", "pfrTime": "2026-09-01T10:15:32.483+02:00" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` Ponovljen isti zahtev sa istim `Idempotency-Key` vraća `200` sa već izdatom kopijom; nova kopija se ne potpisuje. ## Šta ne ide kroz ovaj poziv - **Refundacija**: `POST /v1/refund-workflows`, jer traži proveru izvornih linija i automatsku kopiju kod gotovine ([Refundacija](https://bokapos.rs/api/refundacija)). - **Avans**: `/v1/advance-cases`, jer je lanac dokumenata sa referencama ([Avans](https://bokapos.rs/api/avans)). - **Predračun i obuka**: `/v1/proforma-training-workflows` ([Predračun i obuka](https://bokapos.rs/api/predracun-i-obuka)). - **Prodaja licem u lice**: zahteva L-PFR; prodajno mesto koje nije za prodaju na daljinu vraća `422 LPFR_REQUIRED_FOR_IN_PERSON_SALES`. ## Greške kod prodaje | HTTP | Code | Meaning | What to do | Retry | | --- | --- | --- | --- | --- | | 422 | `LPFR_REQUIRED_FOR_IN_PERSON_SALES` | Prodajno mesto nije za prodaju na daljinu. BokaPOS fiskalizuje samo prodaju na daljinu preko V-PFR-a. | Za prodaju licem u lice potreban je L-PFR (na primer BokaLPFR). | never | | 422 | `BUSINESS_PREMISE_INACTIVE` | Prodajno mesto je suspendovano ili zatvoreno. | Aktivirajte ga u portalu ili koristite drugo. | later | | 422 | `PAYMENT_TYPE_NOT_ALLOWED_ON_PREMISE` | Prodajno mesto radi u ograničenom režimu plaćanja (OTHER, CASH, WIRE_TRANSFER, VOUCHER), a zahtev nosi drugi način. | Promenite način plaćanja ili režim prodajnog mesta u portalu. | fix-request | | 422 | `ACTIVE_SECURITY_ELEMENT_REQUIRED` | Prodajno mesto nema aktivan bezbednosni element. | U sandboxu BokaPOS dodeljuje element; u produkciji vlasnik ga otprema u portalu, BokaPOS ga aktivira. | later | | 422 | `TAX_LABEL_NOT_CURRENT` | Bar jedna poreska oznaka nije u svežoj konfiguraciji V-PFR-a (polje `invalidLabels`). | Pročitajte `GET /v1/tax-rates` i koristite samo oznake koje vrati; sandbox i produkcija imaju različit skup. | fix-request | | 422 | `TAX_LABEL_NOT_ALLOWED_OUTSIDE_VAT` | Obveznik je označen kao van sistema PDV-a, a stavka nosi PDV oznaku. | Koristite oznaku bez PDV-a ili ispravite PDV status obveznika u portalu. | fix-request | | 422 | `COPY_SOURCE_NOT_COPYABLE` | Kopija, predračun i obuka se ne mogu kopirati. | Kopirajte samo račun za promet ili avans. | never | | 422 | `COPY_SOURCE_NOT_FISCALIZED` | Izvor kopije nije fiskalizovan. | Kopija postoji samo za dokument sa statusom FISCALIZED. | never | | 503 | `PFR_SUBMISSION_FAULT` | V-PFR nije bio dostupan pre slanja; dokument je `NOT_FISCALIZED`, `retryable: true`. | Ponovite isti zahtev istim `Idempotency-Key` ključem posle kratke pauze. | same-key | | 503 | `OUTCOME_UNKNOWN` | Zahtev je možda stigao do V-PFR-a, ali odgovor nije stigao nazad. Status `OUTCOME_UNKNOWN`, `retryable: false`. Nije račun, ali može da postane. | Ne šaljite nov zahtev za istu prodaju. Proveravajte `GET /v1/operations/{id}`; BokaPOS sam razrešava ishod čitanjem, nikad ponovnim slanjem. | never | | 422 | `REJECTED` | V-PFR je odbio zahtev. Dokument ima status `REJECTED`, a `GET /v1/fiscal-documents/{id}` vraća `pfrRejection` sa putanjom polja i šifrom (2310 nepostojeća oznaka; 2800 do 2808 obavezno polje, dužina, opseg, vrednost, format, veličina liste). | Ispravite zahtev i pošaljite ga sa novim ključem. | fix-request | --- # Prikazi i dostava računa Jedan fiskalizovan dokument, sedam prikaza: zvanični tekst, JSON paket, QR kod, PDF za A4, 80 mm i 58 mm, PNG pregled. Plus dostava kupcu e-poštom sa platforme. ## Prikazi `GET /v1/fiscal-documents/{fiscalDocumentId}/representations/{representationFormat}`. Adrese svih prikaza su već u odgovoru na izdavanje (`receipt.*`). Svaki prikaz se generiše iz nepromenljivog paketa (kanonski zahtev plus originalni odgovor V-PFR-a) tek pošto se ponovo provere njihovi otisci, pa je uvek isti; odgovor nosi `ETag` i `Boka-Receipt-Representation-Version`. | `representationFormat` | Content-Type | Šta je | Kada | | --- | --- | --- | --- | | `official-text` | `text/plain` | tačan zvanični tekst žurnala V-PFR-a, bez ijednog dodatog znaka | termalni štampači, tekstualni prikaz u aplikaciji, arhiva | | `canonical-json` | `application/json` | ceo paket: zahtev, PFR podaci po stavkama poreza, žurnal, otisci | sopstveni prikaz računa, knjigovodstvo, provera | | `qr-svg` | `image/svg+xml` | QR kod sa verifikacionim linkom | vaš dizajn računa ili strane porudžbine | | `pdf-a4`, `pdf-80mm`, `pdf-58mm` | `application/pdf` | gotov PDF | štampa (iz pregledača ili direktno na štampač), prilog e-pošte, preuzimanje, arhiva | | `preview-png` | `image/png` | slika računa u formatu 80 mm | e-mail bez PDF-a, pregled u admin panelu | `receipt.preferredPaperFormat` (`a4`, `80mm`, `58mm`) je format koji je obveznik izabrao u portalu u trenutku izdavanja; koristite ga kada ne znate šta da ponudite. GET /v1/fiscal-documents/{fiscalDocumentId}/representations/{representationFormat}: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-a4" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ --output racun-ORDER-4127.pdf ``` GET /v1/fiscal-documents/{fiscalDocumentId}/representations/{representationFormat}: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/official-text" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200 (text/plain): ```text ============ ФИСКАЛНИ РАЧУН ============ 115711881 BOKA GROUP DOO BokaPOS sandbox Роза Луксембург 16 Београд-Раковица Касир: web-shop ЕСИР број: 1656/1.0.0 -------------ПРОМЕТ ПРОДАЈА------------- Артикли ======================================== Назив Цена Кол. Укупно Bluetooth slušalice/kom (F) 8.990,00 1 8.990,00 ---------------------------------------- Укупан износ: 8.990,00 Платна картица: 8.990,00 ======================================== Ознака Име Стопа Порез F ECAL 11,00% 890,90 ---------------------------------------- Укупан износ пореза: 890,90 ======================================== ПФР време: 01.09.2026. 10:15:32 ПФР број рачуна: JWX4K9PL-JWX4K9PL-1042 Бројач рачуна: 897/1042ПП ======================================== ======== КРАЈ ФИСКАЛНОГ РАЧУНА ========= ``` Kanonski JSON je koristan kada želite da sami iscrtate račun ili proknjižite porez po stavkama: sadrži `pfr.taxItems` (oznaka, stopa, porez i osnovica), `pfr.invoiceCounter`, brojače i `officialJournal`. Porez po oznaci potpisuje V-PFR; osnovicu (`taxableAmountPerLabel`) izračunava BokaPOS iz stavki računa (zbir stavki sa tom oznakom umanjen za porez te oznake), jer je odgovor V-PFR-a ne sadrži. GET /v1/fiscal-documents/{fiscalDocumentId}/representations/{representationFormat}: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/canonical-json" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "schemaVersion": "boka-receipt-representation-v21", "sourceSha256": "5d41402abc4b2a76b9719d911017c592e99f0d3b4a7c1e6f8b2d9a0c3e5f7a1b", "canonicalRequestSha256": "9b74c9897bac770ffc029102a200c5de3a4b1c6d7e8f9a0b1c2d3e4f5a6b7c8d", "originalPfrResponseSha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4127", "invoiceType": "NORMAL", "transactionType": "SALE", "request": { "cashierId": "web-shop", "cashierDisplayName": "Web shop", "buyer": null, "items": [ { "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 8990, "gtin": "8606012345678", "taxLabels": [ "F" ] } ], "payments": [ { "type": "CARD", "amount": 8990 } ], "reference": null, "transactionOccurredAt": null, "commercialFooter": null }, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1042", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "invoiceCounter": "897/1042ПП", "invoiceCounterExtension": "ПП", "totalCounter": 1042, "transactionTypeCounter": 897, "totalAmount": 8990, "taxGroupRevision": 8, "taxItems": [ { "categoryType": 0, "label": "F", "amount": 890.9009, "rate": 11, "categoryName": "ECAL", "taxableAmountPerLabel": 8099.0991 } ], "businessName": "BOKA GROUP DOO", "tin": "115711881", "locationName": "BokaPOS sandbox", "address": "Роза Луксембург 16", "district": "Београд-Раковица", "mrc": null, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "officialJournal": "============ ФИСКАЛНИ РАЧУН ============\n115711881\nBOKA GROUP DOO\nBokaPOS sandbox\nРоза Луксембург 16\nБеоград-Раковица\nКасир: web-shop\nЕСИР број: 1656/1.0.0\n-------------ПРОМЕТ ПРОДАЈА-------------\nАртикли\n========================================\nНазив Цена Кол. Укупно\nBluetooth slušalice/kom (F)\n 8.990,00 1 8.990,00\n----------------------------------------\nУкупан износ: 8.990,00\nПлатна картица: 8.990,00\n========================================\nОзнака Име Стопа Порез\nF ECAL 11,00% 890,90\n----------------------------------------\nУкупан износ пореза: 890,90\n========================================\nПФР време: 01.09.2026. 10:15:32\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1042\nБројач рачуна: 897/1042ПП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========", "officialJournalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "opaqueFiscalDataStored": true }, "branding": null } ``` ## Šta kupac mora da dobije - Kod prodaje na daljinu račun se dostavlja u elektronskom obliku: najmanje **verifikacioni link** (`pfr.verificationUrl`) ili QR kod, a u praksi PDF ili slika računa u e-pošti i na strani porudžbine. - Fiskalni deo računa se ne menja: ne sme se prepisivati, prevoditi ni skraćivati. Vaš logo, zahvalnica i kontakt idu izvan njega (brendiranje u portalu ili `commercialFooter`). - Kupcu prikazujte samo dokumente sa `fiscalized: true`. Prikaz za odbijen ili nepoznat ishod ne postoji (`404`/`409`). ## Keširanje Prikazi su nepromenljivi: možete ih trajno keširati po `ETag`-u. Ako ipak želite samo jedan poziv, sačuvajte PDF u trenutku izdavanja; svaki kasniji poziv vraća bajt-po-bajt isti sadržaj dokle god je verzija prikaza (`Boka-Receipt-Representation-Version`) ista. ## Dostava e-poštom sa platforme Umesto da sami šaljete poruku, možete zatražiti da BokaPOS pošalje račun kupcu: poruka na jeziku obveznika (`sr-Cyrl`, `sr-Latn` ili `en`), sa verifikacionim linkom kao aktivnim linkom i izabranim prilozima (`a4`, `80mm`, `58mm`, `png`). Uslovi: dokument je fiskalizovan, obveznik je uključio dostavu u portalu (Dokumenti, E-mail računi) i, u produkciji, organizacija ima **modul E-mail**. Dostava se stavlja u red i šalje u pozadini; njen status nikad nije dokaz fiskalizacije. Račun Avans-Refundacija se po Tehničkom uputstvu ne izdaje kupcu, pa se on i njegova kopija odbijaju sa `RECEIPT_DELIVERY_DOCUMENT_NOT_ISSUED_TO_BUYER`; kupcu šaljete završni račun avansnog slučaja. POST /v1/receipt-deliveries: ```bash curl -X POST "https://api.bokapos.rs/v1/receipt-deliveries" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-4127-email-1" \ -H "Content-Type: application/json" \ -d '{ "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "channel": "EMAIL", "recipient": "kupac@example.com", "language": "sr-Latn", "attachments": [ "a4" ] }' ``` Response 202: ```json { "id": "f6a7b8c9-d0e1-4f2a-9b3c-4d5e6f7a8b90", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "channel": "EMAIL", "recipient": "kupac@example.com", "language": "sr-Latn", "attachments": [ "a4" ], "status": "QUEUED", "attempts": 0, "failureCode": null, "createdAt": "2026-09-01T08:15:40.000Z", "deliveredAt": null, "updatedAt": "2026-09-01T08:15:40.000Z" } ``` GET /v1/receipt-deliveries/{receiptDeliveryId}: ```bash curl -X GET "https://api.bokapos.rs/v1/receipt-deliveries/f6a7b8c9-d0e1-4f2a-9b3c-4d5e6f7a8b90" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "f6a7b8c9-d0e1-4f2a-9b3c-4d5e6f7a8b90", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "channel": "EMAIL", "recipient": "kupac@example.com", "language": "sr-Latn", "attachments": [ "a4" ], "status": "DELIVERED", "attempts": 1, "failureCode": null, "createdAt": "2026-09-01T08:15:40.000Z", "deliveredAt": "2026-09-01T08:15:52.418Z", "updatedAt": "2026-09-01T08:15:52.418Z" } ``` | `status` | Značenje | | --- | --- | | `QUEUED` | primljeno, čeka slanje | | `SENDING` | u toku | | `DELIVERED` | predato mail serveru primaoca (`deliveredAt`) | | `FAILED` | odbijeno posle pokušaja; `failureCode` kaže zašto (na primer nevažeća adresa) | `language` i `attachments` su opcioni i podrazumevano prate podešavanja obveznika. Sadržaj i izgled poruke se podešavaju u portalu; za tim postoji pregled i test poruka. ## Greške kod prikaza i dostave | HTTP | Code | Meaning | What to do | Retry | | --- | --- | --- | --- | --- | | 403 | `MODULE_NOT_LICENSED` | Osnovna licenca važi, ali modul iz polja `module` (advance ili email) nije uključen. | Uključite modul preko BokaPOS administracije ili ne koristite tu funkciju u produkciji. | later | | 404 | `FISCAL_DOCUMENT_NOT_FOUND` | Dokument ne postoji u vašoj organizaciji i okruženju. | Proverite identifikator; dokumenti druge organizacije i drugog okruženja su nevidljivi. | fix-request | | 422 | `RECEIPT_DELIVERY_DISABLED` | Obveznik nije uključio dostavu e-poštom u podešavanjima portala. | Uključite dostavu u portalu (Dokumenti, E-mail računi) ili šaljite račun iz svog sistema. | later | | 422 | `RECEIPT_DELIVERY_DOCUMENT_NOT_FISCALIZED` | Dokument nije fiskalizovan, pa nema šta da se dostavi. | Šaljite samo dokumente sa `fiscalized: true`. | never | | 422 | `RECEIPT_DELIVERY_DOCUMENT_NOT_ISSUED_TO_BUYER` | Račun Avans-Refundacija se ne izdaje kupcu, pa ga BokaPOS ne šalje na adresu kupca. Isto važi i za njegovu kopiju. | Pošaljite završni račun avansnog slučaja (Promet-Prodaja). Avans-Refundacija ostaje dostupna za štampu i u elektronskom dnevniku. | never | | 503 | `RECEIPT_DELIVERY_UNAVAILABLE` | Platformski e-mail transport nije konfigurisan ili nije dostupan. Ništa nije stavljeno u red. | Ponovite kasnije istim ključem ili pošaljite račun iz svog sistema; fiskalizacija je već završena. | same-key | --- # Refundacija Потпуна или делимична Промет Рефундација računa koji je BokaPOS izdao. Vi navodite koje linije i koliko se vraća; BokaPOS proverava izvorni račun, upisuje referencu i, kod povraćaja gotovine, odmah izdaje i kopiju sa linijom za potpis. ## Pravila - Izvor je uvek račun koji je BokaPOS izdao (`original.source: BOKA`, `fiscalDocumentId`), tipa Промет Продаја, na istom obvezniku i prodajnom mestu. Refundacija računa drugog ESIR-a nije podržana, jer se ne može proveriti koliko je već vraćeno. - Svaka stavka refundacije pokazuje na liniju izvornog računa (`originalLineIndex`, od nule) i mora da ponovi njen naziv, jedinicu, cenu, oznake i GTIN. Količina može biti manja (delimična refundacija); zbir svih refundacija te linije nikad ne prelazi izvornu količinu. - `buyer.id` je **obavezan**: propis traži identifikaciju kupca na svakoj refundaciji (na primer `20:` broj lične karte ili `10:` PIB). - `payments` su vraćena sredstva; zbir mora biti jednak zbiru refundiranih stavki. Ako je bilo koje plaćanje `CASH`, BokaPOS odmah izdaje i **Копију Рефундације** sa linijom za potpis kupca, kao što propis traži. - Refundacija nikad nije blokirana licencom: već izdat račun uvek može da se poništi. ## Zahtev POST /v1/refund-workflows: ```bash curl -X POST "https://api.bokapos.rs/v1/refund-workflows" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-4127-refund-1" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4127-R1", "original": { "source": "BOKA", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761" }, "cashier": { "id": "web-shop" }, "buyer": { "id": "20:001234567" }, "items": [ { "originalLineIndex": 0, "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 8990, "gtin": "8606012345678", "taxLabels": [ "F" ] } ], "payments": [ { "type": "CARD", "amount": 8990 } ] }' ``` ## Odgovor Response 201: ```json { "id": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4127-R1", "status": "COMPLETED", "original": { "source": "BOKA", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "pfrNumber": "JWX4K9PL-JWX4K9PL-1042", "pfrTime": "2026-09-01T10:15:32.483+02:00", "invoiceType": "NORMAL", "transactionType": "SALE" }, "refund": { "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-refund-1", "clientReference": "ORDER-4127-R1", "invoiceType": "NORMAL", "transactionType": "REFUND", "cashierId": "web-shop", "buyerId": "20:001234567", "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1045", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 900, "totalCounter": 1045, "invoiceCounterExtension": "ПР", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1045\nБројач рачуна: 900/1045ПР\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/official-text", "jsonUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "pfrNumber": "JWX4K9PL-JWX4K9PL-1042", "pfrTime": "2026-09-01T10:15:32.483+02:00" }, "createdAt": "2026-09-01T14:40:04.310Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "cashRefundCopy": null, "failureCode": null, "createdAt": "2026-09-01T14:40:04.300Z", "updatedAt": "2026-09-01T14:40:05.120Z" } ``` | `status` | Značenje | Šta uraditi | | --- | --- | --- | | `COMPLETED` | refundacija (i kopija, ako je bila potrebna) je fiskalizovana | sačuvajte `refund.id` i `refund.pfr.*`; ako postoji `cashRefundCopy`, odštampajte je za potpis | | `REFUND_PENDING` | refundacija nije poslata (V-PFR nedostupan), HTTP 503 | ponovite isti zahtev istim ključem | | `REFUND_OUTCOME_UNKNOWN` | refundacija poslata, odgovor nije stigao, HTTP 503 | ne ponavljajte; pratite `GET /v1/operations/{refund.id}` | | `COPY_PENDING`, `COPY_OUTCOME_UNKNOWN` | refundacija postoji, kopija nije završena, HTTP 503 | ponovite istim ključem (pending) ili sačekajte (unknown); refundacija je već važeća | | `FAILED` | V-PFR odbio; `failureCode` i `refund.pfrRejection` kažu zašto | ispravite i pošaljite sa novim ključem | ## Refundacija gotovinom POST /v1/refund-workflows: ```bash curl -X POST "https://api.bokapos.rs/v1/refund-workflows" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-4127-refund-1" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4127-R1", "original": { "source": "BOKA", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761" }, "cashier": { "id": "web-shop" }, "buyer": { "id": "20:001234567" }, "items": [ { "originalLineIndex": 0, "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 8990, "gtin": "8606012345678", "taxLabels": [ "F" ] } ], "payments": [ { "type": "CASH", "amount": 8990 } ] }' ``` Response 201: ```json { "id": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4127-R1", "status": "COMPLETED", "original": { "source": "BOKA", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "pfrNumber": "JWX4K9PL-JWX4K9PL-1042", "pfrTime": "2026-09-01T10:15:32.483+02:00", "invoiceType": "NORMAL", "transactionType": "SALE" }, "refund": { "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-refund-1", "clientReference": "ORDER-4127-R1", "invoiceType": "NORMAL", "transactionType": "REFUND", "cashierId": "web-shop", "buyerId": "20:001234567", "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1045", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 900, "totalCounter": 1045, "invoiceCounterExtension": "ПР", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1045\nБројач рачуна: 900/1045ПР\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/official-text", "jsonUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "pfrNumber": "JWX4K9PL-JWX4K9PL-1042", "pfrTime": "2026-09-01T10:15:32.483+02:00" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "cashRefundCopy": { "id": "6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-refund-1:copy", "clientReference": "COPY-ORDER-4127-R1", "invoiceType": "COPY", "transactionType": "REFUND", "cashierId": "web-shop", "buyerId": "20:001234567", "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1046", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 901, "totalCounter": 1046, "invoiceCounterExtension": "КР", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1046\nБројач рачуна: 901/1046КР\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/official-text", "jsonUrl": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "pfrNumber": "JWX4K9PL-JWX4K9PL-1045", "pfrTime": "2026-09-01T16:40:05.120+02:00" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "failureCode": null, "createdAt": "2026-09-01T14:40:04.300Z", "updatedAt": "2026-09-01T14:40:06.902Z" } ``` Note: Kod povraćaja gotovine BokaPOS odmah izdaje i kopiju refundacije (`cashRefundCopy`) sa linijom za potpis kupca; odštampajte je i dajte kupcu na potpis. ## Delimična refundacija Za povraćaj dela porudžbine pošaljite samo linije koje se vraćaju, sa količinom koja se vraća. Ako je izvorni račun imao dve linije i kupac vraća jedan od dva komada prve, `items` sadrži jednu stavku sa `originalLineIndex: 0` i `quantity: 1`. Sledeća refundacija iste linije može da vrati najviše preostali komad. Cene i oznake se ne menjaju: refundira se ono što je bilo na računu. ## Refundacija ostalih vrsta - **Avans**: storno pogrešne avansne uplate i zatvaranje slučaja su Аванс Рефундација, kroz `/v1/advance-cases` ([Avans](https://bokapos.rs/api/avans)). - **Predračun i obuka**: refundacija mora da ponovi ceo izvorni dokument, kroz `/v1/proforma-training-workflows` ([Predračun i obuka](https://bokapos.rs/api/predracun-i-obuka)). - **Kopija** postojeće refundacije: `POST /v1/fiscal-documents/{refund.id}/copies`. ## Greške kod refundacije | HTTP | Code | Meaning | What to do | Retry | | --- | --- | --- | --- | --- | | 422 | `REFERENCE_DOCUMENT_NOT_FOUND` | Referentni dokument (`reference.fiscalDocumentId`) ne postoji. | Proverite identifikator iz odgovora originalnog računa. | fix-request | | 422 | `REFERENCE_DOCUMENT_NOT_FISCALIZED` | Referentni dokument nije fiskalizovan, pa ne može biti referenca. | Referenca sme da pokazuje samo na dokument sa statusom FISCALIZED. | fix-request | | 422 | `REFERENCE_DOCUMENT_SCOPE_MISMATCH` | Referentni dokument pripada drugom obvezniku ili prodajnom mestu. | Referenca mora biti na istom obvezniku i prodajnom mestu. | fix-request | | 422 | `REFERENCE_DOCUMENT_TYPE_NOT_ALLOWED` | Kombinacija vrste računa i transakcije ne sme da se poziva na tu vrstu izvornog dokumenta (zvanična matrica referenci). | Pogledajte tabelu referenci na stranici Konvencije. | fix-request | | 422 | `REFUND_QUANTITY_EXCEEDS_ORIGINAL` | Vraćena količina je veća od količine na izvornoj liniji. | Smanjite količinu; delimična refundacija je dozvoljena. | fix-request | | 422 | `REFUND_CUMULATIVE_QUANTITY_EXCEEDED` | Zbir svih dosadašnjih refundacija te linije premašio bi izvornu količinu. | Proverite ranije refundacije u dnevniku. | never | | 422 | `REFUND_ITEM_MUST_MATCH_ORIGINAL_LINE` | Naziv, cena, oznake ili GTIN se ne poklapaju sa izvornom linijom `originalLineIndex`. | Prepišite stavku iz izvornog računa (`GET /v1/fiscal-documents/{id}/representations/canonical-json`). | fix-request | | 422 | `REFUND_ORIGINAL_LINE_NOT_FOUND` | `originalLineIndex` ne postoji na izvornom računu. | Indeksi su od nule, po redosledu stavki originala. | fix-request | --- # Avans Kupac plaća pre isporuke, ponekad u više rata. Propis traži Аванс Продају za svaku uplatu, Аванс Рефундацију celog avansa pri isporuci i konačni Промет Продаја račun sa referencom. BokaPOS vodi ceo lanac kao jedan slučaj; vi šaljete uplate i, na kraju, isporuku. > **Modul Avans:** U produkciji otvaranje slučaja i avansne uplate traže uključen modul Avans (`403 MODULE_NOT_LICENSED` inače). Zatvaranje i storno rade i bez modula, da bi svaki započet lanac mogao da se završi. U sandboxu sve radi. ## Tok 1. **Otvorite slučaj** `POST /v1/advance-cases` sa `clientReference` porudžbine. Slučaj ne izdaje račun; on drži lanac. 2. **Fiskalizujte svaku uplatu** `POST /v1/advance-cases/{id}/payments` za svaku primljenu uplatu. Prva Аванс Продаја nema referencu; svaka sledeća automatski referencira prethodnu. 3. **Stornirajte pogrešnu uplatu (po potrebi)** `POST /v1/advance-cases/{id}/cancellations` izdaje Аванс Рефундацију koja poništava poslednju avansnu prodaju u celosti; slučaj ostaje otvoren. 4. **Zatvorite pri isporuci** `POST /v1/advance-cases/{id}/close` sa stavkama isporuke i doplatom. BokaPOS izdaje Аванс Рефундацију ukupnog avansa, pa konačni Промет Продаја račun sa referencom na nju. ## Otvaranje slučaja POST /v1/advance-cases: ```bash curl -X POST "https://api.bokapos.rs/v1/advance-cases" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-5001-advance-case" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-5001" }' ``` Response 201: ```json { "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-5001", "externalAdvance": null, "state": "OPEN", "advanceSales": [], "cancellations": [], "cancelledAdvanceSaleIds": [], "advanceRefund": null, "finalSale": null, "failureCode": null, "createdAt": "2026-09-03T09:00:00.000Z", "updatedAt": "2026-09-03T09:00:00.000Z" } ``` Slučaj može da preuzme i avanse naplaćene pre eFiskalizacije (`externalAdvance`: ukupan iznos, oznaka, način plaćanja, broj poslednjeg pre-fiskalnog dokumenta, samo cifre, i njegov datum). Tada prva avansna prodaja referencira taj dokument, a zatvaranje refundira i stari i nove avanse zajedno. ## Avansna uplata Stavke avansne prodaje nisu roba nego **propisani avansni artikli**: naziv `10: Аванс (Ђ)` za oznaku Ђ, `11: Аванс (Е)`, `12: Аванс (Г)`, `13: Аванс (А)`, tačno tako, bez jedinice mere, sa `taxLabels` iste oznake i `unitPrice` jednakim iznosu uplate za tu stopu. Ako porudžbina ima stavke po dve stope, avans se deli na dve avansne stavke. `commercialFooter` je obavezan: tu ide opis šta se plaća. POST /v1/advance-cases/{advanceCaseId}/payments: ```bash curl -X POST "https://api.bokapos.rs/v1/advance-cases/c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f/payments" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-5001-advance-1" \ -H "Content-Type: application/json" \ -d '{ "cashier": { "id": "web-shop" }, "items": [ { "name": "10: Аванс (F)", "quantity": 1, "unitPrice": 3000, "taxLabels": [ "F" ] } ], "payments": [ { "type": "WIRE_TRANSFER", "amount": 3000 } ], "paymentOccurredAt": "2026-09-02T11:30:00+02:00", "commercialFooter": "Avans za porudžbinu ORDER-5001. Isporuka po uplati ostatka." }' ``` Response 201: ```json { "id": "d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-5001-advance-1", "clientReference": "ORDER-5001", "invoiceType": "ADVANCE", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1049", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 904, "totalCounter": 1049, "invoiceCounterExtension": "АП", "totalAmount": 3000, "totalTax": 297.2973, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1049\nБројач рачуна: 904/1049АП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/official-text", "jsonUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-03T09:01:00.000Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` Note: U produkciji naziv stavke je propisani `10: Аванс (Ђ)` (ili 11/12/13 za Е, Г, А) sa istom oznakom. Sandbox nema te oznake, pa prima `10: Аванс (X)` za bilo koju oznaku iz sveže konfiguracije. > **Virman primljen ranije:** Kada je uplata virmanom stigla pre nego što ste za nju saznali, zvanično pravilo dozvoljava da avansna prodaja nosi stvarno vreme uplate: pošaljite `paymentOccurredAt` (mora biti pre trenutka fiskalizacije) i bar jedno plaćanje tipa `WIRE_TRANSFER`. Za sve druge slučajeve polje izostavite. ## Storno pogrešne uplate Zvanični postupak za pogrešno izdat avans je Аванс Рефундација koja ponavlja ceo taj avansni račun, referencira ga i kao kupca nosi PIB samog prodavca (`10:`). BokaPOS to radi sam: vi šaljete `id` poslednje avansne prodaje. Lanac se nastavlja od prethodne uplate; stornirane prodaje ostaju vidljive u `advanceSales`, a `cancelledAdvanceSaleIds` kaže koje su poništene. POST /v1/advance-cases/{advanceCaseId}/cancellations: ```bash curl -X POST "https://api.bokapos.rs/v1/advance-cases/c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f/cancellations" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-5001-advance-1-cancel" \ -H "Content-Type: application/json" \ -d '{ "cashier": { "id": "web-shop" }, "advanceSaleFiscalDocumentId": "d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80" }' ``` Response 201: ```json { "id": "a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-5001-advance-1-cancel", "clientReference": "ORDER-5001", "invoiceType": "ADVANCE", "transactionType": "REFUND", "cashierId": "web-shop", "buyerId": "10:115711881", "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1050", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 905, "totalCounter": 1050, "invoiceCounterExtension": "АР", "totalAmount": 3000, "totalTax": 297.2973, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1050\nБројач рачуна: 905/1050АР\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/official-text", "jsonUrl": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80", "pfrNumber": "JWX4K9PL-JWX4K9PL-1049", "pfrTime": "2026-09-03T11:01:00.500+02:00" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` ## Zatvaranje `finalItems` su stavke isporuke sa punom vrednošću (kao da se izdaje običan račun). `remainingPayments` je samo doplata: konačni iznos umanjen za ukupan fiskalizovan avans. Kada doplate nema, pošaljite jedno plaćanje sa iznosom `0` (V-PFR traži bar jedan element). BokaPOS izdaje dva dokumenta redom: Аванс Рефундацију ukupnog avansa, pa Промет Продаја sa referencom na nju. Delimična isporuka iz avansa nije podržana u ovom toku. POST /v1/advance-cases/{advanceCaseId}/close: ```bash curl -X POST "https://api.bokapos.rs/v1/advance-cases/c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f/close" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-5001-close" \ -H "Content-Type: application/json" \ -d '{ "cashier": { "id": "web-shop" }, "finalItems": [ { "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 8990, "gtin": "8606012345678", "taxLabels": [ "F" ] } ], "remainingPayments": [ { "type": "CARD", "amount": 5990 } ], "commercialFooter": "Hvala na kupovini." }' ``` Response 201: ```json { "case": { "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-5001", "externalAdvance": null, "state": "CLOSED", "advanceSales": [ { "id": "d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-5001-advance-1", "clientReference": "ORDER-5001", "invoiceType": "ADVANCE", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1049", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 904, "totalCounter": 1049, "invoiceCounterExtension": "АП", "totalAmount": 3000, "totalTax": 297.2973, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1049\nБројач рачуна: 904/1049АП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/official-text", "jsonUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ], "cancellations": [], "cancelledAdvanceSaleIds": [], "advanceRefund": { "id": "e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-5001-close:refund", "clientReference": "ORDER-5001", "invoiceType": "ADVANCE", "transactionType": "REFUND", "cashierId": "web-shop", "buyerId": "10:115711881", "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1051", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 906, "totalCounter": 1051, "invoiceCounterExtension": "АР", "totalAmount": 3000, "totalTax": 297.2973, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1051\nБројач рачуна: 906/1051АР\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/official-text", "jsonUrl": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80", "pfrNumber": "JWX4K9PL-JWX4K9PL-1049", "pfrTime": "2026-09-03T11:01:00.500+02:00" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "finalSale": { "id": "f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-5001-close:sale", "clientReference": "ORDER-5001", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1052", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 907, "totalCounter": 1052, "invoiceCounterExtension": "ПП", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1052\nБројач рачуна: 907/1052ПП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/official-text", "jsonUrl": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091", "pfrNumber": "JWX4K9PL-JWX4K9PL-1051", "pfrTime": "2026-09-05T13:20:44.010+02:00" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "failureCode": null, "createdAt": "2026-09-03T09:00:00.000Z", "updatedAt": "2026-09-05T11:20:45.300Z" } } ``` Note: Konačni račun nosi ukupnu vrednost isporuke (8.990) i referencu na avansnu refundaciju; `remainingPayments` je samo doplata (5.990). > **202: refundacija prošla, konačni račun nije:** Zatvaranje je dva dokumenta. Ako je Аванс Рефундација fiskalizovana, a konačni račun potvrđeno nije poslat, odgovor je `202` sa stanjem `ADVANCE_REFUND_FISCALIZED_SALE_PENDING`. Ponovite **isti zahtev istim ključem**: BokaPOS šalje samo konačni račun. Nepoznat ishod bilo kog koraka blokira umesto da ponavlja. ## Stanja slučaja | `state` | Značenje | Dozvoljeno | | --- | --- | --- | | `OPEN` | lanac u toku | uplata, storno, zatvaranje | | `ADVANCE_SALE_OUTCOME_UNKNOWN` | poslednja uplata ima nepoznat ishod | čekanje; `GET` slučaja dok se ne razreši | | `CLOSING` | zatvaranje u toku | ponavljanje istim ključem | | `ADVANCE_REFUND_OUTCOME_UNKNOWN` | avansna refundacija zatvaranja ima nepoznat ishod | čekanje | | `ADVANCE_REFUND_FISCALIZED_SALE_PENDING` | refundacija prošla, konačni račun nije poslat | ponavljanje zatvaranja istim ključem | | `FINAL_SALE_OUTCOME_UNKNOWN` | konačni račun ima nepoznat ishod | čekanje | | `CLOSED` | sve fiskalizovano | ništa; čitanje | | `FAILED` | V-PFR odbio korak; `failureCode` | nov slučaj sa ispravljenim podacima | GET /v1/advance-cases/{advanceCaseId}: ```bash curl -X GET "https://api.bokapos.rs/v1/advance-cases/c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` GET /v1/advance-cases: ```bash curl -X GET "https://api.bokapos.rs/v1/advance-cases?businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22&state=OPEN&search=ORDER-5001" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` ## Sandbox i produkcija Sandbox Poreske uprave nema oznake Ђ, Е, Г, А, pa BokaPOS u sandboxu prihvata naziv `10: Аванс (X)` za bilo koju oznaku iz sveže konfiguracije (u primerima `F`). U produkciji važe isključivo četiri propisana naziva; svaki drugi naziv se odbija. Kod se ne menja: naziv sastavite iz oznake koju ste pročitali iz `GET /v1/tax-rates`. ## Greške kod avansa | HTTP | Code | Meaning | What to do | Retry | | --- | --- | --- | --- | --- | | 403 | `MODULE_NOT_LICENSED` | Osnovna licenca važi, ali modul iz polja `module` (advance ili email) nije uključen. | Uključite modul preko BokaPOS administracije ili ne koristite tu funkciju u produkciji. | later | | 409 | `ADVANCE_CASE_NOT_OPEN` | Slučaj je zatvoren, neuspešan ili čeka razrešenje ishoda. | Pročitajte `GET /v1/advance-cases/{id}` i polje `state`. | never | | 422 | `ADVANCE_CANCELLATION_TARGET_NOT_LATEST` | Može se stornirati samo poslednja fiskalizovana avansna prodaja. | Pošaljite `id` poslednje stavke iz `advanceSales` koja nije u `cancelledAdvanceSaleIds`. | fix-request | | 422 | `ADVANCE_CLOSE_TOTAL_MISMATCH` | `remainingPayments` nije jednako konačnom iznosu umanjenom za ukupan avans. | Izračunajte razliku iz `advanceSales` i pošaljite je; kad je nula, jedan element sa iznosom 0. | fix-request | | 422 | `ADVANCE_CASE_HAS_NO_FISCALIZED_SALE` | Ne može se zatvoriti slučaj bez ijedne fiskalizovane avansne prodaje (osim kad postoji `externalAdvance`). | Prvo fiskalizujte uplatu. | never | | 409 | `ADVANCE_PAYMENT_SUPERSEDED` | Ponovljeni zahtev cilja uplatu koja više nije poslednja u lancu. | Pročitajte slučaj i nastavite od aktuelnog stanja. | never | | 409 | `ADVANCE_CASE_CLOSE_ALREADY_RESERVED` | Zatvaranje je već rezervisano drugim ključem. | Ponovite zatvaranje istim `Idempotency-Key` ključem kojim je započeto. | same-key | | 503 | `ADVANCE_REFUND_NOT_FISCALIZED` | Poreska uprava je odbila avansnu refundaciju pri zatvaranju: slučaj je `FAILED` sa šifrom odbijanja, a rezervisani konačni račun nikad nije poslat i ima ovaj `failureCode`, `NOT_FISCALIZED`, `retryable: false`. | Pročitajte `failureCode` slučaja i `advanceRefund.pfrRejection`, ispravite podatke i otvorite nov slučaj. Ponavljanje istog zatvaranja ne šalje ništa. | never | --- # Predračun i obuka Предрачун je ponuda koja izgleda kao račun, ali nema poreski efekat; Обука je vežba za operatere i testove. Oba idu kroz jedan ograničeni tok sa jasnim pravilima referenci. ## Kada se koriste - **Predračun** (`PROFORMA`): ponuda ili profaktura kupcu pre plaćanja, na primer za B2B porudžbinu koja se plaća virmanom. Štampa `ОВО НИЈЕ ФИСКАЛНИ РАЧУН`. Kada kupac plati i roba se isporuči, izdaje se pravi račun za promet (koji se ne poziva na predračun). - **Obuka** (`TRAINING`): probni dokument za obuku operatera ili testiranje toka. Nema poreski efekat i takođe štampa `ОВО НИЈЕ ФИСКАЛНИ РАЧУН`. U produkciji je to dokument kojim BokaPOS dokazuje aktivaciju vašeg sertifikata. ## Pravila | Dokument | Referenca (`original`) | | --- | --- | | Предрачун Продаја | bez reference, ili na BokaPOS predračun (prodaju ili refundaciju) | | Предрачун Рефундација | obavezno na BokaPOS Предрачун Продају; ponavlja sve stavke i plaćanja i identifikuje kupca | | Обука Продаја | bez reference | | Обука Рефундација | obavezno na BokaPOS Обука Продају; ponavlja ceo izvorni dokument | Izvor može biti refundiran samo jednom u celosti; drugi pokušaj vraća `409`. Spoljni dokumenti nisu podržani. Poreske oznake, iznosi i plaćanja prate ista pravila kao račun za promet. ## Predračun POST /v1/proforma-training-workflows: ```bash curl -X POST "https://api.bokapos.rs/v1/proforma-training-workflows" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: quote-2210-proforma-1" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "QUOTE-2210", "invoiceType": "PROFORMA", "transactionType": "SALE", "cashier": { "id": "web-shop" }, "buyer": { "id": "10:106952811" }, "items": [ { "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 8990, "gtin": "8606012345678", "taxLabels": [ "F" ] } ], "payments": [ { "type": "WIRE_TRANSFER", "amount": 8990 } ], "commercialFooter": "Ponuda važi 7 dana." }' ``` Response 201: ```json { "id": "0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "QUOTE-2210", "invoiceType": "PROFORMA", "transactionType": "SALE", "state": "COMPLETED", "original": null, "document": { "id": "1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "quote-2210-proforma-1", "clientReference": "QUOTE-2210", "invoiceType": "PROFORMA", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": "10:106952811", "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1047", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 902, "totalCounter": 1047, "invoiceCounterExtension": "ПрП", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1047\nБројач рачуна: 902/1047ПрП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/official-text", "jsonUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "failureCode": null, "createdAt": "2026-09-02T07:02:10.000Z", "updatedAt": "2026-09-02T07:02:11.204Z" } ``` ## Obuka POST /v1/proforma-training-workflows: ```bash curl -X POST "https://api.bokapos.rs/v1/proforma-training-workflows" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: training-2026-09-02-1" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "TRAINING-1", "invoiceType": "TRAINING", "transactionType": "SALE", "cashier": { "id": "operater-1" }, "items": [ { "name": "Test artikal", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 100, "taxLabels": [ "F" ] } ], "payments": [ { "type": "CASH", "amount": 100 } ] }' ``` ## Stanja toka | `state` | HTTP | Značenje | | --- | --- | --- | | `COMPLETED` | 201 (200 pri ponavljanju) | dokument je potpisan; `document` nosi PFR podatke i prikaze | | `PENDING` | 202 ili 503 | rezervisano, nije poslato; ponovite istim ključem | | `OUTCOME_UNKNOWN` | 503 | poslato, odgovor nije stigao; ne ponavljajte, čitajte `GET /v1/proforma-training-workflows/{id}` | | `REJECTED` | 422 | V-PFR odbio; ispravite i pošaljite sa novim ključem | | `FAILED` | 503 | greška pre slanja; `failureCode` | GET /v1/proforma-training-workflows/{proformaTrainingWorkflowId}: ```bash curl -X GET "https://api.bokapos.rs/v1/proforma-training-workflows/0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` ## Greške kod predračuna i obuke | HTTP | Code | Meaning | What to do | Retry | | --- | --- | --- | --- | --- | | 403 | `MODULE_NOT_LICENSED` | Osnovna licenca važi, ali modul iz polja `module` (advance ili email) nije uključen. | Uključite modul preko BokaPOS administracije ili ne koristite tu funkciju u produkciji. | later | | 422 | `TAX_LABEL_NOT_CURRENT` | Bar jedna poreska oznaka nije u svežoj konfiguraciji V-PFR-a (polje `invalidLabels`). | Pročitajte `GET /v1/tax-rates` i koristite samo oznake koje vrati; sandbox i produkcija imaju različit skup. | fix-request | | 422 | `REFERENCE_DOCUMENT_NOT_FOUND` | Referentni dokument (`reference.fiscalDocumentId`) ne postoji. | Proverite identifikator iz odgovora originalnog računa. | fix-request | | 422 | `REFERENCE_DOCUMENT_TYPE_NOT_ALLOWED` | Kombinacija vrste računa i transakcije ne sme da se poziva na tu vrstu izvornog dokumenta (zvanična matrica referenci). | Pogledajte tabelu referenci na stranici Konvencije. | fix-request | | 409 | `PROFORMA_TRAINING_WORKFLOW_RESERVATION_CONFLICT` | Izvorni dokument već ima nerazrešenu ili završenu refundaciju. | Pročitajte tok iz `workflowId` u odgovoru. | never | | 409 | `PROFORMA_TRAINING_SOURCE_ALREADY_REFUNDED` | Predračun ili obuka je već refundirana u celosti. | Nema dalje akcije. | never | --- # Katalog, obveznici i poreske stope Podaci koje fiskalni zahtev pretpostavlja: obveznik i prodajno mesto (čitaju se), aktuelne poreske oznake (čitaju se sveže) i katalog proizvoda (vodi se kroz API ili CSV, opciono). ## Obveznici i prodajna mesta Obveznika (PIB, naziv, PDV status) i prodajna mesta (identifikator poslovnog prostora Poreske uprave, naziv, režim plaćanja) kreira BokaPOS pri otvaranju organizacije, a vlasnik ih održava u portalu. API ih čita; identifikatori su stabilni i mogu da stoje u konfiguraciji vašeg sistema. GET /v1/taxpayers: ```bash curl -X GET "https://api.bokapos.rs/v1/taxpayers" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "items": [ { "id": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "taxIdentifier": "115711881", "legalName": "BOKA GROUP DOO", "environment": "sandbox", "status": "active", "registrationNumber": "22196456", "address": "Roze Luksemburg 16", "city": "Beograd", "municipality": "Rakovica", "activityCode": "6201", "activityName": "Računarsko programiranje", "vatStatus": "in_vat", "createdAt": "2026-08-21T09:00:00.000Z", "updatedAt": "2026-08-21T09:00:00.000Z" } ] } ``` GET /v1/taxpayers/{taxpayerId}/business-premises: ```bash curl -X GET "https://api.bokapos.rs/v1/taxpayers/3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11/business-premises" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "items": [ { "id": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "puIdentifier": "1234567", "name": "Web shop", "commerceMode": "distance", "environment": "sandbox", "paymentMode": "all", "status": "active", "createdAt": "2026-08-21T09:05:00.000Z", "updatedAt": "2026-08-21T09:05:00.000Z" } ] } ``` | Polje prodajnog mesta | Značenje | | --- | --- | | `puIdentifier` | identifikator poslovnog prostora iz evidencije Poreske uprave; nepromenljiv | | `commerceMode` | uvek `distance` (prodaja na daljinu); drugi režim nije dozvoljen na V-PFR-u | | `paymentMode` | `all` (svi načini plaćanja) ili `restricted` (samo OTHER, CASH, WIRE_TRANSFER, VOUCHER) | | `status` | `active`, `suspended`, `closed`; fiskalizacija traži `active` | `vatStatus` obveznika (`in_vat`, `not_in_vat`, `null`) je izjava vlasnika: obveznik van sistema PDV-a sme da koristi samo oznaku bez PDV-a, a pokušaj sa PDV oznakom vraća `422 TAX_LABEL_NOT_ALLOWED_OUTSIDE_VAT`. ## Poreske stope `GET /v1/tax-rates` svaki put pita V-PFR, sa tačnim bezbednosnim elementom prodajnog mesta, i vraća aktuelnu grupu oznaka. BokaPOS nema ugrađenu listu i ne pamti staru; ako V-PFR ne odgovori, odgovor je `503`. Pozovite ga pri pokretanju i osvežavajte razumno (na primer na sat vremena ili kad dobijete `TAX_LABEL_NOT_CURRENT`), ne pre svakog računa. GET /v1/tax-rates: ```bash curl -X GET "https://api.bokapos.rs/v1/tax-rates?taxpayerId=3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11&businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "source": "PFR", "environment": "sandbox", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "currentTaxGroupId": 8, "validFrom": "2022-05-01T00:00:00", "fetchedAt": "2026-09-01T08:14:02.118Z", "labels": [ { "label": "F", "category": "ECAL", "categoryType": 0, "rate": 11, "activeFrom": "2022-05-01T00:00:00" }, { "label": "N", "category": "N-TAX", "categoryType": 0, "rate": 0, "activeFrom": "2022-05-01T00:00:00" }, { "label": "P", "category": "PBL", "categoryType": 2, "rate": 0.5, "activeFrom": "2022-05-01T00:00:00" }, { "label": "E", "category": "STT", "categoryType": 0, "rate": 6, "activeFrom": "2022-05-01T00:00:00" }, { "label": "T", "category": "TOTL", "categoryType": 1, "rate": 2, "activeFrom": "2022-05-01T00:00:00" }, { "label": "A", "category": "VAT", "categoryType": 0, "rate": 10, "activeFrom": "2022-05-01T00:00:00" }, { "label": "B", "category": "VAT", "categoryType": 0, "rate": 0, "activeFrom": "2022-05-01T00:00:00" }, { "label": "Ж", "category": "VAT", "categoryType": 0, "rate": 19, "activeFrom": "2022-05-01T00:00:00" }, { "label": "C", "category": "VAT-EXCL", "categoryType": 0, "rate": 0, "activeFrom": "2022-05-01T00:00:00" } ] } ``` Note: Sandbox Poreske uprave nosi generički test skup oznaka. U produkciji dobijate zvanične srpske oznake (na primer Ђ 20%, Е 10%, Г 0%, А bez PDV-a). Nikad ne ugrađujte oznake u kod. | Polje oznake | Značenje | | --- | --- | | `label` | oznaka koja ide u `taxLabels` stavke, tačno kako je napisana (razlikuje ćirilicu i latinicu) | | `category` | naziv kategorije poreza kako ga V-PFR štampa (`VAT`, `N-TAX`...) | | `categoryType` | 0 obična stopa, 1 zbirna, 2 iznos po jedinici | | `rate` | stopa u procentima | | `currentTaxGroupId`, `validFrom` | identitet grupe; menja se kad Poreska uprava promeni stope | ## Katalog proizvoda Katalog je opcion: stavka računa može biti potpuno slobodna (naziv, jedinica, cena, oznake). Ako želite da BokaPOS vodi šifarnik (isti podaci za cloud POS operatere i za API), koristite `/v1/products`. Stavka koja pošalje `catalogProductId` i dalje nosi sve svoje vrednosti; katalog je izvor za vaš sistem, ne zamena za polja. POST /v1/products: ```bash curl -X POST "https://api.bokapos.rs/v1/products" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "sku": "BT-HP-001", "gtin": "8606012345678", "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "grossUnitPrice": 8990, "taxLabels": [ "F" ] }' ``` Response 201: ```json { "id": "d2e3f4a5-b6c7-4d8e-9f0a-1b2c3d4e5f60", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "sku": "BT-HP-001", "gtin": "8606012345678", "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "grossUnitPrice": 8990, "taxLabels": [ "F" ], "isActive": true, "createdAt": "2026-08-22T10:00:00.000Z", "updatedAt": "2026-08-22T10:00:00.000Z" } ``` GET /v1/products: ```bash curl -X GET "https://api.bokapos.rs/v1/products?taxpayerId=3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11&search=slu%C5%A1alice&isActive=true" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` PUT /v1/products/{productId}: ```bash curl -X PUT "https://api.bokapos.rs/v1/products/d2e3f4a5-b6c7-4d8e-9f0a-1b2c3d4e5f60" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "sku": "BT-HP-001", "gtin": "8606012345678", "name": "Bluetooth slušalice Pro", "unitOfMeasure": "kom", "grossUnitPrice": 9490, "taxLabels": [ "F" ], "isActive": true }' ``` `PUT` zamenjuje sva uređiva polja; `isActive: false` sklanja proizvod iz izbora, a računi koji su ga već koristili ostaju nepromenjeni. ### Uvoz i izvoz CSV Sve ili ništa: do 1.000 redova ili 5 MB po zahtevu. Kolone su tačno `sku,name,gtin,unitOfMeasure,grossUnitPrice,taxLabels,isActive`; više oznaka se razdvaja sa `|`. Postojeći `sku` se ažurira, nov se kreira. Prihvata se i CSV kakav pravi srpski Excel (BOM, `sep=;`, tačka-zarez i decimalni zarez). POST /v1/products/import: ```bash curl -X POST "https://api.bokapos.rs/v1/products/import?taxpayerId=3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Content-Type: text/csv" \ --data-binary @katalog.csv ``` Response 200: ```json { "created": 1, "updated": 1, "total": 2 } ``` GET /v1/products/export: ```bash curl -X GET "https://api.bokapos.rs/v1/products/export?taxpayerId=3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ --output katalog.csv ``` Response 200 (text/csv): ```text sku,name,gtin,unitOfMeasure,grossUnitPrice,taxLabels,isActive BT-HP-001,Bluetooth slušalice,8606012345678,kom,8990.00,F,true SRV-INST,Instalacija,,h,4000.00,F,true ``` ## Greške | HTTP | Code | Meaning | What to do | Retry | | --- | --- | --- | --- | --- | | 404 | `TAXPAYER_NOT_FOUND` | Obveznik ne postoji u vašoj organizaciji i okruženju ili nije aktivan. | Pročitajte `GET /v1/taxpayers` istim ključem i koristite tačan `id`; obveznik drugog okruženja je nevidljiv. | fix-request | | 404 | `BUSINESS_PREMISE_NOT_FOUND` | Prodajno mesto ne postoji u vašem okruženju ili ne pripada navedenom obvezniku. | Pročitajte `GET /v1/taxpayers/{taxpayerId}/business-premises`. | fix-request | | 409 | `CATALOGUE_SKU_ALREADY_EXISTS` | Šifra (`sku`) već postoji kod tog obveznika. | Izmenite postojeći proizvod (`PUT`) ili upotrebite drugu šifru. | fix-request | | 422 | `CATALOGUE_IMPORT_TOO_MANY_ROWS` | CSV ima više od 1.000 redova. | Podelite uvoz na više datoteka. | fix-request | | 422 | `CATALOGUE_IMPORT_HEADERS_INVALID` | Zaglavlje CSV-a nema očekivane kolone. | Preuzmite `GET /v1/products/export` kao šablon. | fix-request | | 503 | `CURRENT_TAX_CONFIGURATION_UNAVAILABLE` | V-PFR nije vratio svežu poresku konfiguraciju, pa zahtev nije ni rezervisan. | Ponovite kasnije istim ključem. | same-key | --- # Dnevnik, izveštaji i stanje Sve što je BokaPOS uradio za vašu organizaciju je pretraživo: elektronski dnevnik sa svakim pokušajem, CSV izvoz, izveštaj o prometu po PFR vremenu, stanje pojedinačne operacije, sertifikati i licenca. ## Pretraga dnevnika `GET /v1/fiscal-documents` vraća operacije svih vrsta (promet, avans, kopija, predračun, obuka; prodaja i refundacija), uključujući odbijene i nepoznate ishode. Sve filtere možete kombinovati. | Filter | Značenje | | --- | --- | | `taxpayerId`, `businessPremiseId` | suženje na obveznika ili prodajno mesto | | `status` | jedan od statusa dokumenta (`FISCALIZED`, `REJECTED`, `OUTCOME_UNKNOWN`...) | | `invoiceType`, `transactionType` | vrsta računa i transakcije | | `createdFrom`, `createdTo` | vreme prijema u BokaPOS (uključeno, isključeno) | | `pfrFrom`, `pfrTo` | vreme potpisa V-PFR-a; isključuje zapise bez računa | | `clientReference`, `idempotencyKey`, `pfrNumber`, `cashierId`, `buyerId` | tačna vrednost | | `search` | sadrži, bez razlike velikih i malih slova, po bezbednim identifikatorima | | `cursor`, `pageSize` | paginacija; `pageSize` do 200 | GET /v1/fiscal-documents: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents?businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22&status=FISCALIZED&createdFrom=2026-09-01T00%3A00%3A00Z&pageSize=50" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "items": [ { "id": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-sale-1", "clientReference": "ORDER-4127", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1042", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 897, "totalCounter": 1042, "invoiceCounterExtension": "ПП", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n115711881\nBOKA GROUP DOO\nBokaPOS sandbox\nРоза Луксембург 16\nБеоград-Раковица\nКасир: web-shop\nЕСИР број: 1656/1.0.0\n-------------ПРОМЕТ ПРОДАЈА-------------\nАртикли\n========================================\nНазив Цена Кол. Укупно\nBluetooth slušalice/kom (F)\n 8.990,00 1 8.990,00\n----------------------------------------\nУкупан износ: 8.990,00\nПлатна картица: 8.990,00\n========================================\nОзнака Име Стопа Порез\nF ECAL 11,00% 890,90\n----------------------------------------\nУкупан износ пореза: 890,90\n========================================\nПФР време: 01.09.2026. 10:15:32\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1042\nБројач рачуна: 897/1042ПП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/official-text", "jsonUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ], "nextCursor": "eyJjcmVhdGVkQXQiOiIyMDI2LTA5LTAxVDA4OjE1OjMyLjQ4M1oiLCJpZCI6IjlmOGU3ZDZjIn0" } ``` Note: Pošaljite `nextCursor` kao `cursor` za sledeću stranicu; `null` znači kraj. Lista nikad ne vraća `pfrRejection`; za dijagnozu odbijenog dokumenta pročitajte ga pojedinačno. GET /v1/fiscal-documents/{fiscalDocumentId}: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4129-sale-1", "clientReference": "ORDER-4129", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "REJECTED", "fiscalized": false, "failureCode": "PFR_VALIDATION_REJECTED", "retryable": false, "pfr": null, "receipt": null, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z", "pfrRejection": { "items": [ { "property": "items[0].unitPrice", "codes": [ "2804" ] } ] } } ``` Note: Šifra 2804 (format) je ono što sandbox vraća za cenu sa više od dve decimale. Odbijen dokument nije račun; ispravite zahtev i pošaljite ga sa novim ključem. ## Izvoz dnevnika (CSV) Isti filteri, deterministički CSV do 10.000 redova, bez sirovih PFR podataka i bez tajni. Zaglavlje `Boka-Export-Schema-Version` nosi verziju formata (`boka-fiscal-journal-csv-v2`). Ako filteri hvataju više od 10.000 redova, zahtev pada u celini (`422`), pa suzite period. GET /v1/fiscal-documents/export: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/export?businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22&createdFrom=2026-09-01T00%3A00%3A00Z&createdTo=2026-10-01T00%3A00%3A00Z" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ --output dnevnik-2026-09.csv ``` Response 200 (text/csv): ```text schemaVersion,fiscalDocumentId,taxpayerId,businessPremiseId,idempotencyKey,clientReference,invoiceType,transactionType,cashierId,buyerId,status,fiscalized,failureCode,pfrInvoiceNumber,pfrTime,createdAt,updatedAt,retryable,esirNumber,issuingSoftwareVersion,issuingReceiptRepresentationVersion,issuingBuildCommit boka-fiscal-journal-csv-v2,9f8e7d6c-5b4a-4321-8765-0fedcba98761,3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11,b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22,order-4127-sale-1,ORDER-4127,NORMAL,SALE,web-shop,,FISCALIZED,true,,JWX4K9PL-JWX4K9PL-1042,2026-09-01T08:15:32.483Z,2026-09-01T08:15:31.902Z,2026-09-01T08:15:32.611Z,false,,1.0.0,boka-receipt-representation-v21,1f0d454e8b2c9a7d6f5e4c3b2a1908f7e6d5c4b3 ``` Note: Zaglavlje `Boka-Export-Schema-Version: boka-fiscal-journal-csv-v2` označava verziju formata. ## Izveštaj o prometu Lokalni nepromenljivi zbir fiskalizovanih računa za promet i avans po vremenu potpisa V-PFR-a, za jedno prodajno mesto i period. Prodaja i refundacija su odvojeni pozitivni iznosi; iznosi po načinu plaćanja dolaze iz proverenog kanonskog zahteva, porez po oznaci iz proverenog originalnog odgovora V-PFR-a, a osnovica i ukupno po oznaci iz stavki računa koje nose tu oznaku (ukupno je bruto tih stavki, osnovica je ukupno umanjeno za porez). Iznosi nose četiri decimale, kao i porez koji V-PFR potpisuje; zaokružite ih na dve za prikaz. Ovo je vaš izveštaj, ne zamena za dnevni izveštaj na SUF portalu Poreske uprave. Vremenske granice primaju bilo koji RFC 3339 pomak (`Z`, `+00:00`, `+02:00`) i porede se kao trenuci. GET /v1/fiscal-documents/turnover-report: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/turnover-report?taxpayerId=3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11&businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22&pfrFrom=2026-09-01T00%3A00%3A00%2B02%3A00&pfrTo=2026-09-02T00%3A00%3A00%2B02%3A00" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "source": "BOKA_LOCAL_IMMUTABLE_PFR", "periodBasis": "PFR_SDC_TIME", "amountConvention": "SALE_REFUND_SEPARATE", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "pfrFrom": "2026-08-31T22:00:00Z", "pfrTo": "2026-09-01T22:00:00Z", "documentCount": 2, "firstDocument": { "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "pfrInvoiceNumber": "JWX4K9PL-JWX4K9PL-1042", "pfrTime": "2026-09-01T10:15:32.483+02:00" }, "lastDocument": { "fiscalDocumentId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "pfrInvoiceNumber": "JWX4K9PL-JWX4K9PL-1045", "pfrTime": "2026-09-01T16:40:05.120+02:00" }, "paymentTotals": [ { "securityElementJid": "JWX4K9PL", "paymentType": "CARD", "saleAmount": 8990, "refundAmount": 8990 } ], "taxTotals": [ { "invoiceType": "NORMAL", "categoryType": 0, "label": "F", "rate": 11, "categoryName": "ECAL", "saleTaxableAmount": 8099.0991, "saleTaxAmount": 890.9009, "saleTotalAmount": 8990, "refundTaxableAmount": 8099.0991, "refundTaxAmount": 890.9009, "refundTotalAmount": 8990 } ] } ``` GET /v1/fiscal-documents/turnover-report/export: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/turnover-report/export?taxpayerId=3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11&businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22&pfrFrom=2026-09-01T00%3A00%3A00%2B02%3A00&pfrTo=2026-09-02T00%3A00%3A00%2B02%3A00" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ --output promet-2026-09-01.csv ``` ## Stanje operacije `GET /v1/operations/{operationId}` je lakši oblik dokumenta, iz baze, bez kontakta sa V-PFR-om. Identifikator operacije je isti kao `id` dokumenta. Koristite ga kada `409` vrati `operationId`, i kao poziv koji pratite posle `OUTCOME_UNKNOWN`. GET /v1/operations/{operationId}: ```bash curl -X GET "https://api.bokapos.rs/v1/operations/9f8e7d6c-5b4a-4321-8765-0fedcba98761" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f70", "kind": "FISCAL_DOCUMENT", "status": "OUTCOME_UNKNOWN", "fiscalized": false, "failureCode": "PFR_RESPONSE_NOT_OBSERVED", "retryable": false, "resourceUrl": "/v1/fiscal-documents/4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f70", "createdAt": "2026-09-01T09:00:00.000Z", "updatedAt": "2026-09-01T09:00:31.000Z" } ``` `resourceUrl` vodi na pun dokument. Kada se nepoznat ishod razreši, `status` postaje `FISCALIZED` (račun je postojao kod V-PFR-a) i tada je porudžbina fiskalizovana bez ijednog novog zahteva. ## Bezbednosni elementi Bezbedni metapodaci sertifikata po prodajnom mestu: JID, okruženje, važenje, `certificateExpiryStatus` (`current`, `warning` 30 dana pre isteka, `critical` 7 dana, `expired`) i `replacementRecommended`. Tajne se nikad ne vraćaju. Korisno za nadzor: upozorite vlasnika pre isteka, jer zamenu sertifikata radi on u portalu Poreske uprave i u BokaPOS portalu. GET /v1/security-elements: ```bash curl -X GET "https://api.bokapos.rs/v1/security-elements?businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "items": [ { "id": "e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a80", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "environment": "sandbox", "jid": "JWX4K9PL", "certificateThumbprint": "A1B2C3D4E5F60718293A4B5C6D7E8F9012345678", "certificateSubject": "CN=JWX4K9PL, O=BOKA GROUP DOO, C=RS", "certificateIssuer": "CN=Sandbox ICA, O=Poreska uprava Republike Srbije, C=RS", "certificateSerialNumber": "3F9C2A8E6B1D", "certificateNotBefore": "2026-08-20T00:00:00Z", "certificateNotAfter": "2028-08-20T00:00:00Z", "certificateExpiryStatus": "current", "replacementRecommended": false, "status": "active", "createdAt": "2026-08-21T09:10:00.000Z", "updatedAt": "2026-08-21T09:12:00.000Z" } ] } ``` ## Licenca `GET /v1/license` kaže da li je produkciona fiskalizacija trenutno dozvoljena, koji su moduli uključeni i koje cene važe. Pozovite ga pri pokretanju i posle svakog `403 LICENSE_*`. Sandbox se nikad ne naplaćuje i nikad ne blokira. GET /v1/license: ```bash curl -X GET "https://api.bokapos.rs/v1/license" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "state": "active", "productionFiscalizationAllowed": true, "modules": { "advance": true, "email": false }, "startsOn": "2026-09-01", "endsOn": null, "prices": { "basePricePerElement": 1600, "includedDocuments": 600, "overageDocumentPrice": 1, "advanceModulePrice": 600, "emailModulePrice": 600, "vatRate": 0.2 } } ``` --- # Greške Svaki neuspeh ima HTTP status, kod i jasno pravilo šta sme da se ponovi. Ovde je katalog kodova koje integrator sreće, šifre odbijanja V-PFR-a i preporuke za robusnu obradu. ## Oblici odgovora - `{ "code": "..." }` sa opcionim `message` i dodatnim poljima (`invalidLabels`, `module`, `operationId`): pravilo BokaPOS-a, licenca ili okruženje. - RFC 9457 problem sa `errors` po polju (`application/problem+json`): validacija oblika zahteva, uvek 422. - Fiskalni dokument sa `fiscalized: false` (503): V-PFR nedostupan ili nepoznat ishod; `status`, `failureCode` i `retryable` kažu šta dalje. - Tok (refundacija, predračun, avans) sa svojim `status`/`state` i ugrađenim dokumentima: greška se čita iz stanja toka. Response 422 (application/problem+json): ```json { "type": "https://tools.ietf.org/html/rfc9110#section-15.5.21", "title": "One or more validation errors occurred.", "status": 422, "errors": { "totals": [ "The item and payment totals must match after the mandated two-decimal currency rounding." ] } } ``` 403: modul nije u licenci: ```json { "code": "MODULE_NOT_LICENSED", "module": "advance", "message": "This module is not included in the organization's licence. Contact BokaPOS Administration to enable it." } ``` 422: oznaka nije u svežoj konfiguraciji: ```json { "code": "TAX_LABEL_NOT_CURRENT", "invalidLabels": ["Ђ"], "message": "Every tax label must be present in the freshly fetched current PFR configuration." } ``` Response 503: ```json { "id": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-sale-1", "clientReference": "ORDER-4127", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "NOT_FISCALIZED", "fiscalized": false, "failureCode": "PFR_SUBMISSION_FAULT", "retryable": true, "pfr": null, "receipt": null, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` ## Katalog kodova Kolona **Ponavljanje**: *isti ključ* znači da isti zahtev sa istim `Idempotency-Key` ima smisla; *ispravi zahtev* znači nov sadržaj i nov ključ; *kasnije* znači da se stanje menja van vašeg sistema (licenca, podešavanja); *nikad* znači da ponavljanje ne može da pomogne. | HTTP | Code | Meaning | What to do | Retry | | --- | --- | --- | --- | --- | | 401 | `401` | Token nedostaje, istekao je (važi 300 sekundi) ili nije izdat za ovaj API. | Zatražite nov token client credentials tokom i ponovite poziv. | same-key | | 403 | `CREDENTIAL_ENVIRONMENT_MISMATCH` | Sandbox kredencijal pokušava da koristi produkcioni bezbednosni element ili obrnuto. Retko: obveznici, prodajna mesta i dokumenti drugog okruženja su za vaš ključ nevidljivi (`404`), pa se ovo vidi samo ako element i prodajno mesto ne pripadaju istom okruženju. | Proverite koji kredencijal je u konfiguraciji; okruženje određuje kredencijal, ne adresa. | fix-request | | 403 | `CREDENTIAL_ENVIRONMENT_REQUIRED` | Kredencijal ne nosi okruženje (`boka_env`), pa ne može da registruje obveznika. Kredencijali koje izdaje BokaPOS uvek ga nose. | Koristite kredencijal koji je izdala BokaPOS administracija; ako ga imate i dalje vidite ovo, javite se podršci. | never | | 403 | `LICENSE_REQUIRED` | Organizacija nema licencu, a poziv cilja produkcioni element. | Sandbox nastavlja da radi. Za produkciju kontaktirajte BokaPOS administraciju. | later | | 403 | `LICENSE_NOT_STARTED` | Licenca postoji, ali počinje kasnije. | Pročitajte `GET /v1/license` za datum početka. | later | | 403 | `LICENSE_EXPIRED` | Licenca je istekla. | Kontaktirajte BokaPOS administraciju. Refundacije i storna avansa i dalje rade. | later | | 403 | `LICENSE_SUSPENDED` | BokaPOS je suspendovao licencu. | Kontaktirajte BokaPOS administraciju. | later | | 403 | `MODULE_NOT_LICENSED` | Osnovna licenca važi, ali modul iz polja `module` (advance ili email) nije uključen. | Uključite modul preko BokaPOS administracije ili ne koristite tu funkciju u produkciji. | later | | 404 | `TAXPAYER_NOT_FOUND` | Obveznik ne postoji u vašoj organizaciji i okruženju ili nije aktivan. | Pročitajte `GET /v1/taxpayers` istim ključem i koristite tačan `id`; obveznik drugog okruženja je nevidljiv. | fix-request | | 404 | `BUSINESS_PREMISE_NOT_FOUND` | Prodajno mesto ne postoji u vašem okruženju ili ne pripada navedenom obvezniku. | Pročitajte `GET /v1/taxpayers/{taxpayerId}/business-premises`. | fix-request | | 404 | `FISCAL_DOCUMENT_NOT_FOUND` | Dokument ne postoji u vašoj organizaciji i okruženju. | Proverite identifikator; dokumenti druge organizacije i drugog okruženja su nevidljivi. | fix-request | | 409 | `IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_REQUEST` | Isti `Idempotency-Key` je već upotrebljen sa drugačijim sadržajem zahteva. Odgovor nosi `operationId` originala. | Pročitajte original preko `GET /v1/operations/{operationId}`. Nova prodaja mora dobiti nov ključ. | never | | 409 | `IDEMPOTENCY_KEY_REUSED_IN_OTHER_ENVIRONMENT` | Isti `Idempotency-Key` je vaša organizacija već upotrebila kredencijalom drugog okruženja (na primer u sandbox testiranju). Ključevi su jedinstveni po organizaciji u oba okruženja. | Pošaljite zahtev ponovo sa novim ključem. Ništa nije izdato. | never | | 422 | `LPFR_REQUIRED_FOR_IN_PERSON_SALES` | Prodajno mesto nije za prodaju na daljinu. BokaPOS fiskalizuje samo prodaju na daljinu preko V-PFR-a. | Za prodaju licem u lice potreban je L-PFR (na primer BokaLPFR). | never | | 422 | `BUSINESS_PREMISE_INACTIVE` | Prodajno mesto je suspendovano ili zatvoreno. | Aktivirajte ga u portalu ili koristite drugo. | later | | 422 | `PAYMENT_TYPE_NOT_ALLOWED_ON_PREMISE` | Prodajno mesto radi u ograničenom režimu plaćanja (OTHER, CASH, WIRE_TRANSFER, VOUCHER), a zahtev nosi drugi način. | Promenite način plaćanja ili režim prodajnog mesta u portalu. | fix-request | | 422 | `ACTIVE_SECURITY_ELEMENT_REQUIRED` | Prodajno mesto nema aktivan bezbednosni element. | U sandboxu BokaPOS dodeljuje element; u produkciji vlasnik ga otprema u portalu, BokaPOS ga aktivira. | later | | 422 | `TAX_LABEL_NOT_CURRENT` | Bar jedna poreska oznaka nije u svežoj konfiguraciji V-PFR-a (polje `invalidLabels`). | Pročitajte `GET /v1/tax-rates` i koristite samo oznake koje vrati; sandbox i produkcija imaju različit skup. | fix-request | | 422 | `TAX_LABEL_NOT_ALLOWED_OUTSIDE_VAT` | Obveznik je označen kao van sistema PDV-a, a stavka nosi PDV oznaku. | Koristite oznaku bez PDV-a ili ispravite PDV status obveznika u portalu. | fix-request | | 422 | `REFERENCE_DOCUMENT_NOT_FOUND` | Referentni dokument (`reference.fiscalDocumentId`) ne postoji. | Proverite identifikator iz odgovora originalnog računa. | fix-request | | 422 | `REFERENCE_DOCUMENT_NOT_FISCALIZED` | Referentni dokument nije fiskalizovan, pa ne može biti referenca. | Referenca sme da pokazuje samo na dokument sa statusom FISCALIZED. | fix-request | | 422 | `REFERENCE_DOCUMENT_SCOPE_MISMATCH` | Referentni dokument pripada drugom obvezniku ili prodajnom mestu. | Referenca mora biti na istom obvezniku i prodajnom mestu. | fix-request | | 422 | `REFERENCE_DOCUMENT_TYPE_NOT_ALLOWED` | Kombinacija vrste računa i transakcije ne sme da se poziva na tu vrstu izvornog dokumenta (zvanična matrica referenci). | Pogledajte tabelu referenci na stranici Konvencije. | fix-request | | 422 | `REFUND_QUANTITY_EXCEEDS_ORIGINAL` | Vraćena količina je veća od količine na izvornoj liniji. | Smanjite količinu; delimična refundacija je dozvoljena. | fix-request | | 422 | `REFUND_CUMULATIVE_QUANTITY_EXCEEDED` | Zbir svih dosadašnjih refundacija te linije premašio bi izvornu količinu. | Proverite ranije refundacije u dnevniku. | never | | 422 | `REFUND_ITEM_MUST_MATCH_ORIGINAL_LINE` | Naziv, cena, oznake ili GTIN se ne poklapaju sa izvornom linijom `originalLineIndex`. | Prepišite stavku iz izvornog računa (`GET /v1/fiscal-documents/{id}/representations/canonical-json`). | fix-request | | 422 | `REFUND_ORIGINAL_LINE_NOT_FOUND` | `originalLineIndex` ne postoji na izvornom računu. | Indeksi su od nule, po redosledu stavki originala. | fix-request | | 422 | `COPY_SOURCE_NOT_COPYABLE` | Kopija, predračun i obuka se ne mogu kopirati. | Kopirajte samo račun za promet ili avans. | never | | 422 | `COPY_SOURCE_NOT_FISCALIZED` | Izvor kopije nije fiskalizovan. | Kopija postoji samo za dokument sa statusom FISCALIZED. | never | | 409 | `ADVANCE_CASE_NOT_OPEN` | Slučaj je zatvoren, neuspešan ili čeka razrešenje ishoda. | Pročitajte `GET /v1/advance-cases/{id}` i polje `state`. | never | | 422 | `ADVANCE_CANCELLATION_TARGET_NOT_LATEST` | Može se stornirati samo poslednja fiskalizovana avansna prodaja. | Pošaljite `id` poslednje stavke iz `advanceSales` koja nije u `cancelledAdvanceSaleIds`. | fix-request | | 422 | `ADVANCE_CLOSE_TOTAL_MISMATCH` | `remainingPayments` nije jednako konačnom iznosu umanjenom za ukupan avans. | Izračunajte razliku iz `advanceSales` i pošaljite je; kad je nula, jedan element sa iznosom 0. | fix-request | | 422 | `ADVANCE_CASE_HAS_NO_FISCALIZED_SALE` | Ne može se zatvoriti slučaj bez ijedne fiskalizovane avansne prodaje (osim kad postoji `externalAdvance`). | Prvo fiskalizujte uplatu. | never | | 409 | `ADVANCE_PAYMENT_SUPERSEDED` | Ponovljeni zahtev cilja uplatu koja više nije poslednja u lancu. | Pročitajte slučaj i nastavite od aktuelnog stanja. | never | | 409 | `ADVANCE_CASE_CLOSE_ALREADY_RESERVED` | Zatvaranje je već rezervisano drugim ključem. | Ponovite zatvaranje istim `Idempotency-Key` ključem kojim je započeto. | same-key | | 503 | `ADVANCE_REFUND_NOT_FISCALIZED` | Poreska uprava je odbila avansnu refundaciju pri zatvaranju: slučaj je `FAILED` sa šifrom odbijanja, a rezervisani konačni račun nikad nije poslat i ima ovaj `failureCode`, `NOT_FISCALIZED`, `retryable: false`. | Pročitajte `failureCode` slučaja i `advanceRefund.pfrRejection`, ispravite podatke i otvorite nov slučaj. Ponavljanje istog zatvaranja ne šalje ništa. | never | | 409 | `PROFORMA_TRAINING_WORKFLOW_RESERVATION_CONFLICT` | Izvorni dokument već ima nerazrešenu ili završenu refundaciju. | Pročitajte tok iz `workflowId` u odgovoru. | never | | 409 | `PROFORMA_TRAINING_SOURCE_ALREADY_REFUNDED` | Predračun ili obuka je već refundirana u celosti. | Nema dalje akcije. | never | | 409 | `CATALOGUE_SKU_ALREADY_EXISTS` | Šifra (`sku`) već postoji kod tog obveznika. | Izmenite postojeći proizvod (`PUT`) ili upotrebite drugu šifru. | fix-request | | 422 | `CATALOGUE_IMPORT_TOO_MANY_ROWS` | CSV ima više od 1.000 redova. | Podelite uvoz na više datoteka. | fix-request | | 422 | `CATALOGUE_IMPORT_HEADERS_INVALID` | Zaglavlje CSV-a nema očekivane kolone. | Preuzmite `GET /v1/products/export` kao šablon. | fix-request | | 422 | `JOURNAL_EXPORT_RESULT_LIMIT_EXCEEDED` | Više od 10.000 redova odgovara filterima izvoza. | Suzite period (`createdFrom`, `createdTo`) i izvezite u delovima. | fix-request | | 422 | `RECEIPT_DELIVERY_DISABLED` | Obveznik nije uključio dostavu e-poštom u podešavanjima portala. | Uključite dostavu u portalu (Dokumenti, E-mail računi) ili šaljite račun iz svog sistema. | later | | 422 | `RECEIPT_DELIVERY_DOCUMENT_NOT_FISCALIZED` | Dokument nije fiskalizovan, pa nema šta da se dostavi. | Šaljite samo dokumente sa `fiscalized: true`. | never | | 422 | `RECEIPT_DELIVERY_DOCUMENT_NOT_ISSUED_TO_BUYER` | Račun Avans-Refundacija se ne izdaje kupcu, pa ga BokaPOS ne šalje na adresu kupca. Isto važi i za njegovu kopiju. | Pošaljite završni račun avansnog slučaja (Promet-Prodaja). Avans-Refundacija ostaje dostupna za štampu i u elektronskom dnevniku. | never | | 503 | `RECEIPT_DELIVERY_UNAVAILABLE` | Platformski e-mail transport nije konfigurisan ili nije dostupan. Ništa nije stavljeno u red. | Ponovite kasnije istim ključem ili pošaljite račun iz svog sistema; fiskalizacija je već završena. | same-key | | 503 | `PFR_SANDBOX_NOT_CONFIGURED` | Fiskalni adapter nije konfigurisan na ovoj instalaciji. Odgovor je dokument sa `fiscalized: false`. | Ne dešava se na api.bokapos.rs; javlja se samo na lokalnim instalacijama bez adaptera. | same-key | | 503 | `PFR_ENVIRONMENT_DISABLED` | Fiskalni promet je isključen za okruženje ovog elementa (produkcija do njenog uključenja). | Sandbox radi; produkcija se uključuje po odluci BokaPOS-a. | later | | 503 | `CURRENT_TAX_CONFIGURATION_UNAVAILABLE` | V-PFR nije vratio svežu poresku konfiguraciju, pa zahtev nije ni rezervisan. | Ponovite kasnije istim ključem. | same-key | | 503 | `PFR_SUBMISSION_FAULT` | V-PFR nije bio dostupan pre slanja; dokument je `NOT_FISCALIZED`, `retryable: true`. | Ponovite isti zahtev istim `Idempotency-Key` ključem posle kratke pauze. | same-key | | 503 | `OUTCOME_UNKNOWN` | Zahtev je možda stigao do V-PFR-a, ali odgovor nije stigao nazad. Status `OUTCOME_UNKNOWN`, `retryable: false`. Nije račun, ali može da postane. | Ne šaljite nov zahtev za istu prodaju. Proveravajte `GET /v1/operations/{id}`; BokaPOS sam razrešava ishod čitanjem, nikad ponovnim slanjem. | never | | 422 | `REJECTED` | V-PFR je odbio zahtev. Dokument ima status `REJECTED`, a `GET /v1/fiscal-documents/{id}` vraća `pfrRejection` sa putanjom polja i šifrom (2310 nepostojeća oznaka; 2800 do 2808 obavezno polje, dužina, opseg, vrednost, format, veličina liste). | Ispravite zahtev i pošaljite ga sa novim ključem. | fix-request | ## Šifre odbijanja V-PFR-a Kada V-PFR odbije zahtev, dokument dobija status `REJECTED`, `failureCode: PFR_VALIDATION_REJECTED`, a pojedinačno čitanje (`GET /v1/fiscal-documents/{id}`) nosi `pfrRejection.items` sa putanjom polja iz vašeg zahteva i šifrom: | Šifra | Značenje | Tipičan uzrok | | --- | --- | --- | | `2310` | nepostojeća poreska oznaka | oznaka nije u aktuelnoj grupi (BokaPOS to obično uhvati ranije kao `TAX_LABEL_NOT_CURRENT`) | | `2800` | obavezno polje nedostaje | prazan naziv, kasir, plaćanje | | `2801` | dužina | predugačak naziv, kasir ili referenca | | `2802` | opseg | količina ili iznos van dozvoljenog opsega | | `2803` | vrednost | nedozvoljena vrednost enumeracije | | `2804` | format | više od dve decimale u ceni ili iznosu, pogrešan format vremena | | `2805` do `2808` | veličina liste i srodne provere | prazna lista stavki ili plaćanja | ## Robusna integracija - Izvedite `Idempotency-Key` iz porudžbine i sačuvajte ga pre slanja, da posle prekida možete da ponovite isti zahtev. - Na `503` sa `retryable: true` ponovite istim ključem uz eksponencijalno čekanje (na primer 2, 5, 15 sekundi), najviše nekoliko puta; zatim označite porudžbinu za operatera. - Na `OUTCOME_UNKNOWN` nikad ne šaljite nov zahtev: zapamtite `id` i proveravajte `GET /v1/operations/{id}` sve dok status ne postane `FISCALIZED` ili operater ne odluči. - Na `422` i `REJECTED` beležite `errors` odnosno `pfrRejection` uz porudžbinu, ispravite izvor podataka i pošaljite sa novim ključem. - Na `401` uzmite nov token i ponovite isti zahtev. Na `403` pročitajte `GET /v1/license`. - Osvežite poreske oznake kad dobijete `TAX_LABEL_NOT_CURRENT`, ne pre svakog računa. - Postavite HTTP timeout na fiskalnim pozivima velikodušno (na primer 60 sekundi): V-PFR odgovara obično za oko dve sekunde, ali prekid veze sa vaše strane pretvara siguran ishod u nepoznat. - Logujte `id`, `status`, `failureCode` i `pfr.invoiceNumber`; nikad ne logujte token ni tajnu. --- # Prelazak u produkciju Kod se ne menja. Menjaju se sertifikat, licenca i kredencijal, a nekoliko stvari koje su u sandboxu bile opuštene postaju stroge. Ovo je redosled i kontrolna lista. ## Redosled 1. **Vlasnik pribavi bezbednosni element** Ovlašćeno lice obveznika u portalu Poreske uprave zatraži bezbednosni element u obliku datoteke za poslovni prostor za prodaju na daljinu i preuzme originalni ZIP (PFX, lozinka, PAK). BokaPOS nikad ne pristupa portalu Poreske uprave u vaše ime. 2. **Vlasnik otpremi element u BokaPOS portal** U `cloud.bokapos.rs`, Bezbednosni elementi: originalni ZIP plus lozinka i PAK, kroz šifrovanu jednokratnu sesiju u pregledaču. Element je vezan za tačnog obveznika i prodajno mesto. 3. **BokaPOS proveri i aktivira** BokaPOS administracija proverava lanac, JID i PIB i aktivira element jednim dokumentom obuke (Обука), koji ne utiče na porez. Od tada element može da potpisuje. 4. **Licenca** BokaPOS izdaje licencu organizaciji (osnovna pretplata po produkcionom elementu, plus moduli Avans i E-mail po potrebi). `GET /v1/license` vraća `productionFiscalizationAllowed: true`. 5. **Produkcioni kredencijal** BokaPOS izdaje `boka-prod-...` client id i tajnu. Vaš sistem ih dobija kao tajnu konfiguracije. 6. **Zamena i provera** Zamenite client id i tajnu, pozovite `GET /v1/runtime`, pa `GET /v1/tax-rates`. Prvi produkcioni račun proverite na `suf.purs.gov.rs` preko `pfr.verificationUrl`. 7. **Sandbox ostaje dostupan** Sandbox kredencijal i element nastavljaju da rade za dalje testiranje. Od trenutka kada je produkcioni kredencijal aktivan, portal sakriva sandbox podatke organizacije (probnog obveznika BOKA GROUP DOO, njegovo prodajno mesto, probni element i sve sandbox dokumente) da ih niko ne pomeša sa pravim računima; vlasnik ih može ponovo prikazati u Podešavanjima. API to ne menja: svaki ključ vidi samo svoje okruženje. ## Šta je drugačije u produkciji | Tema | Sandbox | Produkcija | | --- | --- | --- | | Adresa i kod | `api.bokapos.rs` | isto | | Kredencijal | `boka-sbx-...` | `boka-prod-...`; objekat drugog okruženja je za vas `404`, a ukrštanje elementa vraća `403 CREDENTIAL_ENVIRONMENT_MISMATCH` | | Podaci | samo sandbox obveznici, prodajna mesta, elementi i dokumenti | samo produkcioni; isti PIB može da postoji jednom u svakom okruženju | | Bezbednosni element | BokaPOS-ov iz fonda, PIB BOKA GROUP DOO na računu | vaš sertifikat, vaš PIB i naziv na računu | | Verifikacija | `sandbox.suf.purs.gov.rs` | `suf.purs.gov.rs` | | Poreske oznake | test skup (`F`, `A`, `Ж`...) | zvanične srpske oznake (`Ђ`, `Е`, `Г`, `А`...), iz `GET /v1/tax-rates` | | Avansne stavke | `10: Аванс (X)` za bilo koju oznaku | isključivo `10: Аванс (Ђ)`, `11: Аванс (Е)`, `12: Аванс (Г)`, `13: Аванс (А)` | | Licenca | nikad ne blokira | prodaja, kopija, predračun, obuka i avans traže važeću licencu; refundacija i storno nikad | | Moduli | sve radi | Avans i E-mail traže uključen modul | | Dostava e-poštom | radi ako je uključena u portalu | isto, plus modul E-mail | | Cena | besplatno | po [cenovniku](https://bokapos.rs/cena); 600 dokumenata mesečno uključeno | ## Kontrolna lista pre prvog produkcionog računa - Poreske oznake se čitaju iz `GET /v1/tax-rates`, ne iz konfiguracije; mapiranje vaših poreskih grupa na oznake je proverljivo i pokriva sve stope koje prodajete. - `Idempotency-Key` se čuva pre slanja i ponavlja istim ključem posle prekida. - Obrada `OUTCOME_UNKNOWN` postoji i testirana je: bez novog zahteva, sa praćenjem `GET /v1/operations/{id}` i eskalacijom operateru. - Iznosi su na dve decimale, količine na tri; zbir stavki i plaćanja se poklapa. - Kupac dobija verifikacioni link (i PDF ili sliku) za svaki račun, a fiskalni deo se ne menja. - Refundacija ide kroz `/v1/refund-workflows` sa identifikacijom kupca; kod gotovine štampate kopiju za potpis. - Ako koristite avanse: nazivi avansnih stavki se sastavljaju iz oznake, `commercialFooter` je popunjen, zatvaranje šalje samo doplatu. - Nadzor: `GET /v1/security-elements` (istek sertifikata) i `GET /v1/license` (stanje) se proveravaju periodično; `401`/`403`/`503` se alarmiraju. - Tajna kredencijala je samo na serveru, u tajnama okruženja; logovi ne sadrže token. - Test u sandboxu je prošao: jedna prodaja, jedna delimična refundacija, jedna pretraga dnevnika, jedan PDF. ## Podrška BokaPOS administracija: [office@bokagroup.rs](mailto:office@bokagroup.rs), [+381 69 558 55 88](tel:+381695585588). Uz zahtev pošaljite `id` operacije i `clientReference`; nikad token, tajnu ni sertifikat. Promene ugovora se najavljuju u [OpenAPI datoteci](https://api.bokapos.rs/openapi.yaml) (verzija u `info.version`) i na ovoj stranici. --- # Referenca operacija Svaka operacija koju mašinski kredencijal može da pozove: parametri, telo, odgovori i primer u pet jezika. Generisano iz OpenAPI ugovora koji API služi na /openapi.yaml. ## Fiskalni dokumenti Sinhrono izdavanje računa za promet, kopije, prikazi računa, elektronski dnevnik i izveštaj o prometu. ### POST /v1/fiscal-documents **Izdaj račun za promet** (operationId `createFiscalDocument`, scope `fiscal:write`, requires `Idempotency-Key` header) Glavni poziv. Šaljete stavke, plaćanja, kasira i po potrebi kupca; BokaPOS potpiše zahtev bezbednosnim elementom prodajnog mesta, pošalje ga V-PFR-u i vraća 201 tek kada je potpisani odgovor trajno sačuvan. Refundacije, avansi, predračun i obuka imaju svoje tokove i ovde se odbijaju. Contract notes: Accepts a business-level command and succeeds only after a signed V-PFR result has been durably recorded. A 503 response is not a fiscal receipt and may be retried with the same Idempotency-Key. Refund commands are rejected here and must use a server-managed workflow. Advance, Proforma, and Training chains must use their dedicated workflow APIs. An optional unitPriceBeforeDiscount is a Boka-local immutable display/audit fact; unitPrice is always the final reduced gross price sent to V-PFR. No discount field is invented in the supplier request. Repeating the identical command under the same Idempotency-Key after a 201 answers 200 with the stored document and never fiscalizes a second time; only the first 201 with fiscalized=true is the issuing of a receipt. Request body (application/json, FiscalDocumentCreate): - `taxpayerId` (uuid, required) - `businessPremiseId` (uuid, required) - `clientReference` (string, required): Caller-owned order, invoice, or transaction reference. - `invoiceType` (InvoiceType, required): NORMAL | PROFORMA | COPY | TRAINING | ADVANCE - `transactionType` (TransactionType, required): SALE | REFUND - `cashier` (Cashier, required) - `id` (string, required) - `displayName` (string) - `buyer` (Buyer) - `id` (string): Official prefix and value, for example 10:123456789. - `optionalField` (string): Official buyer-cost-center prefix and value where applicable. - `reference` (ReferenceTarget) - one of `BokaDocumentReference`: - `source` (const "BOKA", required) - `fiscalDocumentId` (uuid, required) - one of `ExternalFiscalReference`: - `source` (const "EXTERNAL", required) - `pfrNumber` (string, required) - `pfrTime` (date-time, required) - `invoiceType` (InvoiceType, required): NORMAL | PROFORMA | COPY | TRAINING | ADVANCE - `transactionType` (TransactionType, required): SALE | REFUND - `transactionOccurredAt` (date-time): Accepted only for an Advance Sale containing a wire-transfer payment, where the official earlier-payment ESIR-time rule applies; it never overrides PFR time. - `items` (array, required) [min 1 items] - `catalogProductId` (uuid): Optional; arbitrary inline items are permitted. - `name` (string, required) [min 1, max 2048] - `unitOfMeasure` (string): Required on every item except the codebook advance literals (10: Аванс (Ђ) and siblings), which are prescribed verbatim without a unit. The API refuses any other item without one (422, Items.UnitOfMeasure) and composes it into the signed item name as name/unit. [min 1, max 50] - `quantity` (number, required): V-PFR Decimal(14,3). [>= 0.001, <= 99999999999.999, step 0.001] - `unitPrice` (number, required): Final gross unit price sent to V-PFR as Decimal(28,4). Boka applies the mandated fiscal rounding rules. [>= 0, step 0.01] - `unitPriceBeforeDiscount` (number): Optional Boka-local immutable gross unit price before discount. When present it must be greater than unitPrice; it is displayed outside the exact PFR journal and is never sent as a supplier field. [>= 0, step 0.0001] - `gtin` (string) [min 8, max 14] - `taxLabels` (array, required) [min 1 items, unique] - `payments` (array, required) [min 1 items] - `type` (PaymentType, required): OTHER | CASH | CARD | CHECK | WIRE_TRANSFER | VOUCHER | INSTANT_PAYMENT - `amount` (number, required): At most two decimals (the V-PFR rejects more with validation code 2804); the field type on the wire is Decimal(28,4). [>= 0, step 0.01] - `commercialFooter` (string): Non-fiscal text rendered only in the permitted area outside the fiscal boundary. - `metadata` (object): Non-fiscal caller metadata; never sent as a substitute for a mandated field. Responses: - 200 (FiscalDocument): Idempotent replay of the already fiscalized document under the same Idempotency-Key; no new receipt was issued - 201 (FiscalDocument): Fiscalized document - 409 (IdempotencyConflict): The key was already used with different canonical content - 422 (ErrorCode): The command violates a Boka or fiscal rule - 503 (FiscalDocument): No fiscal receipt was issued because V-PFR was unavailable or its outcome requires reconciliation Example: ```bash curl -X POST "https://api.bokapos.rs/v1/fiscal-documents" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-4127-sale-1" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4127", "invoiceType": "NORMAL", "transactionType": "SALE", "cashier": { "id": "web-shop", "displayName": "Web shop" }, "items": [ { "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 8990, "gtin": "8606012345678", "taxLabels": [ "F" ] } ], "payments": [ { "type": "CARD", "amount": 8990 } ], "metadata": { "orderId": "4127", "channel": "web" } }' ``` Response 201: ```json { "id": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-sale-1", "clientReference": "ORDER-4127", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1042", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 897, "totalCounter": 1042, "invoiceCounterExtension": "ПП", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n115711881\nBOKA GROUP DOO\nBokaPOS sandbox\nРоза Луксембург 16\nБеоград-Раковица\nКасир: web-shop\nЕСИР број: 1656/1.0.0\n-------------ПРОМЕТ ПРОДАЈА-------------\nАртикли\n========================================\nНазив Цена Кол. Укупно\nBluetooth slušalice/kom (F)\n 8.990,00 1 8.990,00\n----------------------------------------\nУкупан износ: 8.990,00\nПлатна картица: 8.990,00\n========================================\nОзнака Име Стопа Порез\nF ECAL 11,00% 890,90\n----------------------------------------\nУкупан износ пореза: 890,90\n========================================\nПФР време: 01.09.2026. 10:15:32\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1042\nБројач рачуна: 897/1042ПП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/official-text", "jsonUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` Response 409: ```json { "code": "IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_REQUEST", "operationId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761" } ``` Response 422 (application/problem+json): ```json { "type": "https://tools.ietf.org/html/rfc9110#section-15.5.21", "title": "One or more validation errors occurred.", "status": 422, "errors": { "totals": [ "The item and payment totals must match after the mandated two-decimal currency rounding." ] } } ``` Response 503: ```json { "id": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-sale-1", "clientReference": "ORDER-4127", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "NOT_FISCALIZED", "fiscalized": false, "failureCode": "PFR_SUBMISSION_FAULT", "retryable": true, "pfr": null, "receipt": null, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` Example (buyer): ```bash curl -X POST "https://api.bokapos.rs/v1/fiscal-documents" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-4128-sale-1" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4128", "invoiceType": "NORMAL", "transactionType": "SALE", "cashier": { "id": "web-shop" }, "buyer": { "id": "10:106952811" }, "items": [ { "name": "Godišnja licenca", "unitOfMeasure": "kom", "quantity": 2, "unitPrice": 12000, "taxLabels": [ "F" ] }, { "name": "Instalacija", "unitOfMeasure": "h", "quantity": 1.5, "unitPrice": 4000, "unitPriceBeforeDiscount": 5000, "taxLabels": [ "F" ] } ], "payments": [ { "type": "WIRE_TRANSFER", "amount": 20000 }, { "type": "CARD", "amount": 10000 } ], "commercialFooter": "Hvala na kupovini. Reklamacije: podrska@primer.rs" }' ``` Response 201: ```json { "id": "8e7d6c5b-4a39-4210-8765-fedcba987650", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4128-sale-1", "clientReference": "ORDER-4128", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": "10:106952811", "buyerDetails": { "legalName": "PRIMER DOO BEOGRAD", "taxIdentifier": "106952811", "registrationNumber": "20712345", "address": "Bulevar kralja Aleksandra 1", "city": "Beograd", "source": "nbs-jrr", "resolvedAt": "2026-09-01T08:20:11.004Z" }, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1043", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 898, "totalCounter": 1043, "invoiceCounterExtension": "ПП", "totalAmount": 30000, "totalTax": 2972.973, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1043\nБројач рачуна: 898/1043ПП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/official-text", "jsonUrl": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/8e7d6c5b-4a39-4210-8765-fedcba987650/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` ### GET /v1/fiscal-documents **Pretraži dnevnik** (operationId `listFiscalDocuments`, scope `fiscal:read`) Elektronski dnevnik organizacije: svaki pokušaj izdavanja, uključujući odbijene i one sa nepoznatim ishodom. Filtrira se po obvezniku, prodajnom mestu, statusu, vrsti, vremenu, referenci, PFR broju, kasiru i kupcu; stranice se nižu preko cursor-a. Contract notes: Returns durable fiscal-operation state ordered by createdAt and id, both descending. createdFrom and pfrFrom are inclusive; createdTo and pfrTo are exclusive. The opaque cursor continues the same ordering. A journal entry whose fiscalized value is false is not a fiscal receipt. Scoped to the caller's environment: a machine credential never sees documents of the other environment, and fetching one by id is 404. Parameters: - `taxpayerId` (query, uuid) - `businessPremiseId` (query, uuid) - `fiscalDocumentId` (query, uuid) - `status` (query, FiscalDocumentStatus): RECEIVED | VALIDATED | SUBMITTING | FISCALIZED | REJECTED | NOT_FISCALIZED | OUTCOME_UNKNOWN | RECONCILING - `invoiceType` (query, InvoiceType): NORMAL | PROFORMA | COPY | TRAINING | ADVANCE - `transactionType` (query, TransactionType): SALE | REFUND - `createdFrom` (query, date-time); Inclusive lower bound for durable operation creation time. Any RFC 3339 offset is accepted (Z, +00:00, +02:00) and compared as an instant. - `createdTo` (query, date-time); Exclusive upper bound for durable operation creation time. Any RFC 3339 offset is accepted and compared as an instant. - `pfrFrom` (query, date-time); Inclusive lower bound for authoritative PFR signing time; excludes entries with no PFR receipt. Any RFC 3339 offset is accepted and compared as an instant. - `pfrTo` (query, date-time); Exclusive upper bound for authoritative PFR signing time; excludes entries with no PFR receipt. Any RFC 3339 offset is accepted and compared as an instant. - `idempotencyKey` (query, string) - `clientReference` (query, string) - `pfrNumber` (query, string) - `cashierId` (query, string) - `buyerId` (query, string) - `search` (query, string); Case-insensitive contains search across safe identifiers only; raw PFR payload, journal, metadata, and secrets are excluded. - `cursor` (query, string); Opaque keyset cursor returned by the preceding journal page. - `pageSize` (query, integer) Responses: - 200 (FiscalDocumentPage): Page of fiscal documents - 400 (ErrorCode): The command violates a Boka or fiscal rule - 422 (ErrorCode): The command violates a Boka or fiscal rule Example: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents?businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22&status=FISCALIZED&createdFrom=2026-09-01T00%3A00%3A00Z&pageSize=50" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "items": [ { "id": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-sale-1", "clientReference": "ORDER-4127", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1042", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 897, "totalCounter": 1042, "invoiceCounterExtension": "ПП", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n115711881\nBOKA GROUP DOO\nBokaPOS sandbox\nРоза Луксембург 16\nБеоград-Раковица\nКасир: web-shop\nЕСИР број: 1656/1.0.0\n-------------ПРОМЕТ ПРОДАЈА-------------\nАртикли\n========================================\nНазив Цена Кол. Укупно\nBluetooth slušalice/kom (F)\n 8.990,00 1 8.990,00\n----------------------------------------\nУкупан износ: 8.990,00\nПлатна картица: 8.990,00\n========================================\nОзнака Име Стопа Порез\nF ECAL 11,00% 890,90\n----------------------------------------\nУкупан износ пореза: 890,90\n========================================\nПФР време: 01.09.2026. 10:15:32\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1042\nБројач рачуна: 897/1042ПП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/official-text", "jsonUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ], "nextCursor": "eyJjcmVhdGVkQXQiOiIyMDI2LTA5LTAxVDA4OjE1OjMyLjQ4M1oiLCJpZCI6IjlmOGU3ZDZjIn0" } ``` Note: Pošaljite `nextCursor` kao `cursor` za sledeću stranicu; `null` znači kraj. ### GET /v1/fiscal-documents/export **Izvezi dnevnik (CSV)** (operationId `exportFiscalDocuments`, scope `fiscal:read`) Isti filteri kao pretraga, rezultat je deterministički CSV do 10.000 redova bez sirovih PFR podataka. Ako se poklopi više redova, zahtev pada u celini, pa suzite period. Contract notes: Applies the same tenant-scoped filters and descending createdAt/id ordering as the electronic journal. The export contains at most 10,000 safe projection rows and never includes the raw fiscal command, caller metadata, complete PFR response, official journal text, verification URL, signature data, or secret material. Text cells that could be interpreted as spreadsheet formulas are neutralized. If more than 10,000 rows match, the request fails without returning a partial file. Parameters: - `taxpayerId` (query, uuid) - `businessPremiseId` (query, uuid) - `fiscalDocumentId` (query, uuid) - `status` (query, FiscalDocumentStatus): RECEIVED | VALIDATED | SUBMITTING | FISCALIZED | REJECTED | NOT_FISCALIZED | OUTCOME_UNKNOWN | RECONCILING - `invoiceType` (query, InvoiceType): NORMAL | PROFORMA | COPY | TRAINING | ADVANCE - `transactionType` (query, TransactionType): SALE | REFUND - `createdFrom` (query, date-time); Inclusive lower bound for durable operation creation time. Any RFC 3339 offset is accepted (Z, +00:00, +02:00) and compared as an instant. - `createdTo` (query, date-time); Exclusive upper bound for durable operation creation time. Any RFC 3339 offset is accepted and compared as an instant. - `pfrFrom` (query, date-time); Inclusive lower bound for authoritative PFR signing time; excludes entries with no PFR receipt. Any RFC 3339 offset is accepted and compared as an instant. - `pfrTo` (query, date-time); Exclusive upper bound for authoritative PFR signing time; excludes entries with no PFR receipt. Any RFC 3339 offset is accepted and compared as an instant. - `idempotencyKey` (query, string) - `clientReference` (query, string) - `pfrNumber` (query, string) - `cashierId` (query, string) - `buyerId` (query, string) - `search` (query, string); Case-insensitive contains search across safe identifiers only; raw PFR payload, journal, metadata, and secrets are excluded. Responses: - 200: Complete filtered journal CSV in stable descending order - 422 (ErrorCode): Invalid filters or more than 10,000 matching rows Example: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/export?businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22&createdFrom=2026-09-01T00%3A00%3A00Z&createdTo=2026-10-01T00%3A00%3A00Z" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ --output dnevnik-2026-09.csv ``` Response 200 (text/csv): ```text schemaVersion,fiscalDocumentId,taxpayerId,businessPremiseId,idempotencyKey,clientReference,invoiceType,transactionType,cashierId,buyerId,status,fiscalized,failureCode,pfrInvoiceNumber,pfrTime,createdAt,updatedAt,retryable,esirNumber,issuingSoftwareVersion,issuingReceiptRepresentationVersion,issuingBuildCommit boka-fiscal-journal-csv-v2,9f8e7d6c-5b4a-4321-8765-0fedcba98761,3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11,b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22,order-4127-sale-1,ORDER-4127,NORMAL,SALE,web-shop,,FISCALIZED,true,,JWX4K9PL-JWX4K9PL-1042,2026-09-01T08:15:32.483Z,2026-09-01T08:15:31.902Z,2026-09-01T08:15:32.611Z,false,,1.0.0,boka-receipt-representation-v21,1f0d454e8b2c9a7d6f5e4c3b2a1908f7e6d5c4b3 ``` Note: Zaglavlje `Boka-Export-Schema-Version: boka-fiscal-journal-csv-v2` označava verziju formata. ### POST /v1/fiscal-documents/{fiscalDocumentId}/copies **Izdaj kopiju** (operationId `createFiscalDocumentCopy`, scope `fiscal:write`, requires `Idempotency-Key` header) Zvanična Копија računa za promet ili avans, izgrađena na serveru iz sačuvanog originala i potpisana kao novi dokument. Kopija refundacije nosi liniju za potpis kupca. Predračun, obuka i kopija se ne mogu kopirati. Contract notes: Issues a Copy (Копија Продаја or Копија Рефундација) of a fiscalized Normal or Advance document. The copy is built on the server from the stored original: the same items, payments, buyer identification and stored buyer lines, referenced to the original's PFR number and time, with the cashier given here. It is signed by the V-PFR as a new document and prints ОВО НИЈЕ ФИСКАЛНИ РАЧУН; a Копија Рефундација prints the customer signature line. Copy, Proforma and Training documents cannot be copied (422 COPY_SOURCE_NOT_COPYABLE), nor can a document that is not fiscalized (422 COPY_SOURCE_NOT_FISCALIZED). Same idempotency and outcome rules as createFiscalDocument. Parameters: - `fiscalDocumentId` (path, uuid, required) Request body (application/json, FiscalDocumentCopyCreate): - `cashier` (Cashier, required) - `id` (string, required) - `displayName` (string) - `clientReference` (string | null): Defaults to COPY- followed by the original's client reference. [max 200] Responses: - 200 (FiscalDocument): Idempotent replay of the already fiscalized copy under the same Idempotency-Key; no new document was issued - 201 (FiscalDocument): Fiscalized copy - 404: The original does not exist in this organization (code FISCAL_DOCUMENT_NOT_FOUND) - 409 (IdempotencyConflict): The key was already used with different canonical content - 422 (ErrorCode): The command violates a Boka or fiscal rule - 503 (FiscalDocument): No fiscal receipt was issued because V-PFR was unavailable or its outcome requires reconciliation Example: ```bash curl -X POST "https://api.bokapos.rs/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/copies" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-4127-copy-1" \ -H "Content-Type: application/json" \ -d '{ "cashier": { "id": "web-shop" } }' ``` Response 201: ```json { "id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-copy-1", "clientReference": "COPY-ORDER-4127", "invoiceType": "COPY", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1044", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 899, "totalCounter": 1044, "invoiceCounterExtension": "КП", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1044\nБројач рачуна: 899/1044КП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/official-text", "jsonUrl": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "pfrNumber": "JWX4K9PL-JWX4K9PL-1042", "pfrTime": "2026-09-01T10:15:32.483+02:00" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` ### GET /v1/fiscal-documents/{fiscalDocumentId} **Pročitaj dokument** (operationId `getFiscalDocument`, scope `fiscal:read`) Stanje jednog dokumenta sa PFR podacima i linkovima ka prikazima. Odbijen dokument ovde nosi i pfrRejection sa putanjom polja i šifrom V-PFR-a, što lista nikad ne vraća. Parameters: - `fiscalDocumentId` (path, uuid, required) Responses: - 200 (FiscalDocument): Fiscal document - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope Example: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-sale-1", "clientReference": "ORDER-4127", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1042", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 897, "totalCounter": 1042, "invoiceCounterExtension": "ПП", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n115711881\nBOKA GROUP DOO\nBokaPOS sandbox\nРоза Луксембург 16\nБеоград-Раковица\nКасир: web-shop\nЕСИР број: 1656/1.0.0\n-------------ПРОМЕТ ПРОДАЈА-------------\nАртикли\n========================================\nНазив Цена Кол. Укупно\nBluetooth slušalice/kom (F)\n 8.990,00 1 8.990,00\n----------------------------------------\nУкупан износ: 8.990,00\nПлатна картица: 8.990,00\n========================================\nОзнака Име Стопа Порез\nF ECAL 11,00% 890,90\n----------------------------------------\nУкупан износ пореза: 890,90\n========================================\nПФР време: 01.09.2026. 10:15:32\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1042\nБројач рачуна: 897/1042ПП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/official-text", "jsonUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` Example (rejected): ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4129-sale-1", "clientReference": "ORDER-4129", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "REJECTED", "fiscalized": false, "failureCode": "PFR_VALIDATION_REJECTED", "retryable": false, "pfr": null, "receipt": null, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z", "pfrRejection": { "items": [ { "property": "items[0].unitPrice", "codes": [ "2804" ] } ] } } ``` Note: Šifra 2804 (format) je ono što sandbox vraća za cenu sa više od dve decimale. Odbijen dokument nije račun; ispravite zahtev i pošaljite ga sa novim ključem. ### GET /v1/fiscal-documents/turnover-report **Izveštaj o prometu** (operationId `getTurnoverReport`, scope `fiscal:read`) Lokalni nepromenljivi zbir fiskalizovanih računa za promet i avans po PFR vremenu, sa prodajom i refundacijom kao odvojenim pozitivnim iznosima, po načinu plaćanja i po poreskoj oznaci. Nije zamena za izveštaje na SUF portalu. Contract notes: Aggregates only tenant-scoped FISCALIZED Normal (Promet) and Advance (Avans) receipts whose authoritative PFR signing time is within the inclusive pfrFrom and exclusive pfrTo bounds. Sale and Refund amounts remain separate positive totals; the API does not infer a net value. Payment data comes from the hash-verified canonical request and tax bases/tax amounts come from the hash-verified complete PFR response. This is a Boka-local immutable report, not the SUF portal daily report; it does not claim SUF-only knowledge about missing or scanned receipts. Parameters: - `taxpayerId` (query, uuid, required) - `businessPremiseId` (query, uuid, required) - `pfrFrom` (query, date-time, required); Inclusive lower bound for authoritative PFR signing time. Any RFC 3339 offset is accepted (Z, +00:00, +02:00) and compared as an instant. - `pfrTo` (query, date-time, required); Exclusive upper bound for authoritative PFR signing time. Any RFC 3339 offset is accepted and compared as an instant. Responses: - 200 (TurnoverReport): Immutable local turnover report - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope - 409 (ErrorCode): A selected receipt failed source-integrity validation or totals exceeded the supported decimal range - 422 (ErrorCode): The command violates a Boka or fiscal rule Example: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/turnover-report?taxpayerId=3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11&businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22&pfrFrom=2026-09-01T00%3A00%3A00%2B02%3A00&pfrTo=2026-09-02T00%3A00%3A00%2B02%3A00" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "source": "BOKA_LOCAL_IMMUTABLE_PFR", "periodBasis": "PFR_SDC_TIME", "amountConvention": "SALE_REFUND_SEPARATE", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "pfrFrom": "2026-08-31T22:00:00Z", "pfrTo": "2026-09-01T22:00:00Z", "documentCount": 2, "firstDocument": { "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "pfrInvoiceNumber": "JWX4K9PL-JWX4K9PL-1042", "pfrTime": "2026-09-01T10:15:32.483+02:00" }, "lastDocument": { "fiscalDocumentId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "pfrInvoiceNumber": "JWX4K9PL-JWX4K9PL-1045", "pfrTime": "2026-09-01T16:40:05.120+02:00" }, "paymentTotals": [ { "securityElementJid": "JWX4K9PL", "paymentType": "CARD", "saleAmount": 8990, "refundAmount": 8990 } ], "taxTotals": [ { "invoiceType": "NORMAL", "categoryType": 0, "label": "F", "rate": 11, "categoryName": "ECAL", "saleTaxableAmount": 8099.0991, "saleTaxAmount": 890.9009, "saleTotalAmount": 8990, "refundTaxableAmount": 8099.0991, "refundTaxAmount": 890.9009, "refundTotalAmount": 8990 } ] } ``` ### GET /v1/fiscal-documents/turnover-report/export **Izvezi izveštaj o prometu (CSV)** (operationId `exportTurnoverReport`, scope `fiscal:read`) Isti izveštaj kao JSON verzija, u normalizovanom CSV-u sa redovima SUMMARY, FIRST_DOCUMENT, LAST_DOCUMENT, PAYMENT_TOTAL i TAX_TOTAL. Contract notes: Reuses the exact same hash-reverified BOKA_LOCAL_IMMUTABLE_PFR report result as the JSON operation. The normalized CSV contains SUMMARY, FIRST_DOCUMENT, LAST_DOCUMENT, PAYMENT_TOTAL, and TAX_TOTAL record types. Sale and Refund remain separate positive amounts. This is not a SUF portal report and contains no official receipt journal or raw PFR payload. Parameters: - `taxpayerId` (query, uuid, required) - `businessPremiseId` (query, uuid, required) - `pfrFrom` (query, date-time, required); Inclusive lower bound for authoritative PFR signing time. Any RFC 3339 offset is accepted (Z, +00:00, +02:00) and compared as an instant. - `pfrTo` (query, date-time, required); Exclusive upper bound for authoritative PFR signing time. Any RFC 3339 offset is accepted and compared as an instant. Responses: - 200: Complete normalized turnover-report CSV - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope - 409 (ErrorCode): A selected receipt failed source-integrity validation or totals exceeded the supported decimal range - 422 (ErrorCode): The command violates a Boka or fiscal rule Example: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/turnover-report/export?taxpayerId=3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11&businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22&pfrFrom=2026-09-01T00%3A00%3A00%2B02%3A00&pfrTo=2026-09-02T00%3A00%3A00%2B02%3A00" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ --output promet-2026-09-01.csv ``` Response 200 (text/csv): ```text schemaVersion,recordType,source,periodBasis,amountConvention,taxpayerId,businessPremiseId,pfrFrom,pfrTo,documentCount,fiscalDocumentId,pfrInvoiceNumber,pfrTime,securityElementJid,paymentType,invoiceType,categoryType,taxLabel,taxRate,taxCategoryName,saleAmount,refundAmount,saleTaxableAmount,saleTaxAmount,saleTotalAmount,refundTaxableAmount,refundTaxAmount,refundTotalAmount boka-turnover-report-csv-v1,SUMMARY,BOKA_LOCAL_IMMUTABLE_PFR,PFR_SDC_TIME,SALE_REFUND_SEPARATE,3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11,b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22,2026-08-31T22:00:00Z,2026-09-01T22:00:00Z,2,,,,,,,,,,,,,,,,,, boka-turnover-report-csv-v1,FIRST_DOCUMENT,BOKA_LOCAL_IMMUTABLE_PFR,PFR_SDC_TIME,SALE_REFUND_SEPARATE,3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11,b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22,2026-08-31T22:00:00Z,2026-09-01T22:00:00Z,,9f8e7d6c-5b4a-4321-8765-0fedcba98761,JWX4K9PL-JWX4K9PL-1042,2026-09-01T08:15:32.483Z,,,,,,,,,,,,,,, boka-turnover-report-csv-v1,PAYMENT_TOTAL,BOKA_LOCAL_IMMUTABLE_PFR,PFR_SDC_TIME,SALE_REFUND_SEPARATE,3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11,b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22,2026-08-31T22:00:00Z,2026-09-01T22:00:00Z,,,,,JWX4K9PL,CARD,,,,,,8990.00,8990.00,,,,,, boka-turnover-report-csv-v1,TAX_TOTAL,BOKA_LOCAL_IMMUTABLE_PFR,PFR_SDC_TIME,SALE_REFUND_SEPARATE,3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11,b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22,2026-08-31T22:00:00Z,2026-09-01T22:00:00Z,,,,,,,NORMAL,0,F,11,ECAL,,,8099.0991,890.9009,8990.0000,8099.0991,890.9009,8990.0000 ``` ### GET /v1/fiscal-documents/{fiscalDocumentId}/representations/{representationFormat} **Preuzmi prikaz računa** (operationId `getFiscalDocumentRepresentation`, scope `fiscal:read`) Sedam prikaza istog fiskalizovanog računa: zvanični tekst žurnala, kanonski JSON, QR kod (SVG), PDF u A4, 80 mm i 58 mm, i PNG pregled. Svaki se generiše iz nepromenljivog paketa i nosi ETag. Contract notes: Generates the selected representation only from a tenant-scoped FISCALIZED operation after rechecking the canonical request and complete original PFR response hashes. official-text is the exact stored supplier journal. canonical-json omits caller metadata and opaque encrypted/signature values. The direct PDF and PNG preview layouts keep the verification QR at 45 mm. Fixed media use only bundled local rendering resources and include no network-loaded content. No representation is generated for an unresolved, rejected, unavailable, corrupt, or non-fiscalized operation. Parameters: - `fiscalDocumentId` (path, uuid, required) - `representationFormat` (path, string, required): canonical-json | official-text | qr-svg | pdf-a4 | pdf-80mm | pdf-58mm | preview-png Responses: - 200 (ReceiptCanonicalPackage): Selected immutable receipt representation - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope - 409 (ErrorCode): Receipt unavailable or stored source integrity validation failed Example: ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-a4" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ --output racun-ORDER-4127.pdf ``` Response 200 (application/pdf): ```text %PDF-1.7 ... (binarni sadržaj, A4 račun) ``` Example (text): ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/official-text" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200 (text/plain): ```text ============ ФИСКАЛНИ РАЧУН ============ 115711881 BOKA GROUP DOO BokaPOS sandbox Роза Луксембург 16 Београд-Раковица Касир: web-shop ЕСИР број: 1656/1.0.0 -------------ПРОМЕТ ПРОДАЈА------------- Артикли ======================================== Назив Цена Кол. Укупно Bluetooth slušalice/kom (F) 8.990,00 1 8.990,00 ---------------------------------------- Укупан износ: 8.990,00 Платна картица: 8.990,00 ======================================== Ознака Име Стопа Порез F ECAL 11,00% 890,90 ---------------------------------------- Укупан износ пореза: 890,90 ======================================== ПФР време: 01.09.2026. 10:15:32 ПФР број рачуна: JWX4K9PL-JWX4K9PL-1042 Бројач рачуна: 897/1042ПП ======================================== ======== КРАЈ ФИСКАЛНОГ РАЧУНА ========= ``` Example (json): ```bash curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/canonical-json" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "schemaVersion": "boka-receipt-representation-v21", "sourceSha256": "5d41402abc4b2a76b9719d911017c592e99f0d3b4a7c1e6f8b2d9a0c3e5f7a1b", "canonicalRequestSha256": "9b74c9897bac770ffc029102a200c5de3a4b1c6d7e8f9a0b1c2d3e4f5a6b7c8d", "originalPfrResponseSha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4127", "invoiceType": "NORMAL", "transactionType": "SALE", "request": { "cashierId": "web-shop", "cashierDisplayName": "Web shop", "buyer": null, "items": [ { "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 8990, "gtin": "8606012345678", "taxLabels": [ "F" ] } ], "payments": [ { "type": "CARD", "amount": 8990 } ], "reference": null, "transactionOccurredAt": null, "commercialFooter": null }, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1042", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "invoiceCounter": "897/1042ПП", "invoiceCounterExtension": "ПП", "totalCounter": 1042, "transactionTypeCounter": 897, "totalAmount": 8990, "taxGroupRevision": 8, "taxItems": [ { "categoryType": 0, "label": "F", "amount": 890.9009, "rate": 11, "categoryName": "ECAL", "taxableAmountPerLabel": 8099.0991 } ], "businessName": "BOKA GROUP DOO", "tin": "115711881", "locationName": "BokaPOS sandbox", "address": "Роза Луксембург 16", "district": "Београд-Раковица", "mrc": null, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "officialJournal": "============ ФИСКАЛНИ РАЧУН ============\n115711881\nBOKA GROUP DOO\nBokaPOS sandbox\nРоза Луксембург 16\nБеоград-Раковица\nКасир: web-shop\nЕСИР број: 1656/1.0.0\n-------------ПРОМЕТ ПРОДАЈА-------------\nАртикли\n========================================\nНазив Цена Кол. Укупно\nBluetooth slušalice/kom (F)\n 8.990,00 1 8.990,00\n----------------------------------------\nУкупан износ: 8.990,00\nПлатна картица: 8.990,00\n========================================\nОзнака Име Стопа Порез\nF ECAL 11,00% 890,90\n----------------------------------------\nУкупан износ пореза: 890,90\n========================================\nПФР време: 01.09.2026. 10:15:32\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1042\nБројач рачуна: 897/1042ПП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========", "officialJournalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "opaqueFiscalDataStored": true }, "branding": null } ``` ## Refundacije Potpuna ili delimična refundacija računa koji je BokaPOS izdao, sa automatskom kopijom kod povraćaja gotovine. ### POST /v1/refund-workflows **Refundiraj račun** (operationId `createRefundWorkflow`, scope `refund:write`, requires `Idempotency-Key` header) Potpuna ili delimična refundacija računa za promet koji je BokaPOS izdao. Navodite izvorni dokument, stavke po indeksu izvorne linije i vraćena plaćanja; kupac je obavezan. Ako se vraća gotovina, BokaPOS odmah izdaje i kopiju refundacije. Contract notes: Supports full and partial Normal Refunds. Boka-issued originals are resolved only within the exact taxpayer and premise, and cumulative quantities are prevented from exceeding each stored original line. When any returned payment is cash, Boka automatically issues the required Copy Refundation and renders its customer-signature line. This first bounded workflow accepts only a Boka-stored original; external originals remain unsupported because their cumulative returned quantity cannot be independently proven. Normal fiscal traffic remains governed by the same disabled-by-default provider and uncertain-outcome safeguards. Request body (application/json, RefundWorkflowCreate): - `taxpayerId` (uuid, required) - `businessPremiseId` (uuid, required) - `clientReference` (string, required) - `original` (BokaDocumentReference, required) - `source` (const "BOKA", required) - `fiscalDocumentId` (uuid, required) - `cashier` (Cashier, required) - `id` (string, required) - `displayName` (string) - `buyer` (Buyer, required) - `id` (string): Official prefix and value, for example 10:123456789. - `optionalField` (string): Official buyer-cost-center prefix and value where applicable. - `items` (array, required) [min 1 items] - `originalLineIndex` (integer, required): Zero-based index of the exact line on the identified original receipt. [>= 0] - `catalogProductId` (uuid): Optional; must match the Boka-stored original line when source is BOKA. - `name` (string, required) [min 1, max 2048] - `unitOfMeasure` (string): Required on every item except the codebook advance literals (10: Аванс (Ђ) and siblings), which are prescribed verbatim without a unit. The API refuses any other item without one (422, Items.UnitOfMeasure) and composes it into the signed item name as name/unit. [min 1, max 50] - `quantity` (number, required): Quantity returned from this original line. [>= 0.001, <= 99999999999.999, step 0.001] - `unitPrice` (number, required): Must match the final gross unit price on the identified original line when source is BOKA. [>= 0, step 0.01] - `unitPriceBeforeDiscount` (number): Optional Boka-local pre-discount price; when the source line has it, the value must match exactly and remain greater than unitPrice. [>= 0, step 0.0001] - `gtin` (string) [min 8, max 14] - `taxLabels` (array, required) [min 1 items, unique] - `payments` (array, required) [min 1 items] - `type` (PaymentType, required): OTHER | CASH | CARD | CHECK | WIRE_TRANSFER | VOUCHER | INSTANT_PAYMENT - `amount` (number, required): At most two decimals (the V-PFR rejects more with validation code 2804); the field type on the wire is Decimal(28,4). [>= 0, step 0.01] Responses: - 200 (RefundWorkflow): Idempotent replay of a completed refund workflow - 201 (RefundWorkflow): Completed refund workflow - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope - 409 (IdempotencyConflict): The key was already used with different canonical content - 422 (ErrorCode): The command violates a Boka or fiscal rule - 503 (RefundWorkflow): The refund workflow is incomplete; no missing fiscal step is claimed as issued Example: ```bash curl -X POST "https://api.bokapos.rs/v1/refund-workflows" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-4127-refund-1" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4127-R1", "original": { "source": "BOKA", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761" }, "cashier": { "id": "web-shop" }, "buyer": { "id": "20:001234567" }, "items": [ { "originalLineIndex": 0, "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 8990, "gtin": "8606012345678", "taxLabels": [ "F" ] } ], "payments": [ { "type": "CARD", "amount": 8990 } ] }' ``` Response 201: ```json { "id": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4127-R1", "status": "COMPLETED", "original": { "source": "BOKA", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "pfrNumber": "JWX4K9PL-JWX4K9PL-1042", "pfrTime": "2026-09-01T10:15:32.483+02:00", "invoiceType": "NORMAL", "transactionType": "SALE" }, "refund": { "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-refund-1", "clientReference": "ORDER-4127-R1", "invoiceType": "NORMAL", "transactionType": "REFUND", "cashierId": "web-shop", "buyerId": "20:001234567", "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1045", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 900, "totalCounter": 1045, "invoiceCounterExtension": "ПР", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1045\nБројач рачуна: 900/1045ПР\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/official-text", "jsonUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "pfrNumber": "JWX4K9PL-JWX4K9PL-1042", "pfrTime": "2026-09-01T10:15:32.483+02:00" }, "createdAt": "2026-09-01T14:40:04.310Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "cashRefundCopy": null, "failureCode": null, "createdAt": "2026-09-01T14:40:04.300Z", "updatedAt": "2026-09-01T14:40:05.120Z" } ``` Example (cash): ```bash curl -X POST "https://api.bokapos.rs/v1/refund-workflows" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-4127-refund-1" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4127-R1", "original": { "source": "BOKA", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761" }, "cashier": { "id": "web-shop" }, "buyer": { "id": "20:001234567" }, "items": [ { "originalLineIndex": 0, "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 8990, "gtin": "8606012345678", "taxLabels": [ "F" ] } ], "payments": [ { "type": "CASH", "amount": 8990 } ] }' ``` Response 201: ```json { "id": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-4127-R1", "status": "COMPLETED", "original": { "source": "BOKA", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "pfrNumber": "JWX4K9PL-JWX4K9PL-1042", "pfrTime": "2026-09-01T10:15:32.483+02:00", "invoiceType": "NORMAL", "transactionType": "SALE" }, "refund": { "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-refund-1", "clientReference": "ORDER-4127-R1", "invoiceType": "NORMAL", "transactionType": "REFUND", "cashierId": "web-shop", "buyerId": "20:001234567", "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1045", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 900, "totalCounter": 1045, "invoiceCounterExtension": "ПР", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1045\nБројач рачуна: 900/1045ПР\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/official-text", "jsonUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "pfrNumber": "JWX4K9PL-JWX4K9PL-1042", "pfrTime": "2026-09-01T10:15:32.483+02:00" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "cashRefundCopy": { "id": "6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-4127-refund-1:copy", "clientReference": "COPY-ORDER-4127-R1", "invoiceType": "COPY", "transactionType": "REFUND", "cashierId": "web-shop", "buyerId": "20:001234567", "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1046", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 901, "totalCounter": 1046, "invoiceCounterExtension": "КР", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1046\nБројач рачуна: 901/1046КР\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/official-text", "jsonUrl": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "pfrNumber": "JWX4K9PL-JWX4K9PL-1045", "pfrTime": "2026-09-01T16:40:05.120+02:00" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "failureCode": null, "createdAt": "2026-09-01T14:40:04.300Z", "updatedAt": "2026-09-01T14:40:06.902Z" } ``` Note: Kod povraćaja gotovine BokaPOS odmah izdaje i kopiju refundacije (`cashRefundCopy`) sa linijom za potpis kupca; odštampajte je i dajte kupcu na potpis. ## Avansi Serverski vođen lanac avansa: avansne prodaje, storniranje pogrešnog avansa i zatvaranje konačnim računom. ### GET /v1/advance-cases **Lista avansnih slučajeva** (operationId `listAdvanceCases`, scope `fiscal:read`) Lanci avansa po vremenu poslednje promene, sa filterom stanja (OPEN, CLOSED, FAILED) i pretragom po referenci. Contract notes: Returns tenant-scoped advance chains in most-recently-updated order so an operator can continue a chain without handling an internal identifier. Filters narrow by state, reference text and last change. Parameters: - `taxpayerId` (query, uuid) - `businessPremiseId` (query, uuid) - `state` (query, string): OPEN | CLOSED | FAILED; OPEN is every chain still in progress (including unknown-outcome states the operator must resolve); CLOSED and FAILED are terminal. - `search` (query, string); Case-insensitive substring of the client reference. - `updatedFrom` (query, date-time); Only chains changed at or after this instant. Any RFC 3339 offset is accepted and compared as an instant. - `pageSize` (query, integer) Responses: - 200 (AdvanceCasePage): Recent advance chains - 422 (ErrorCode): The command violates a Boka or fiscal rule Example: ```bash curl -X GET "https://api.bokapos.rs/v1/advance-cases?businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22&state=OPEN&search=ORDER-5001" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "items": [ { "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-5001", "externalAdvance": null, "state": "OPEN", "advanceSales": [], "cancellations": [], "cancelledAdvanceSaleIds": [], "advanceRefund": null, "finalSale": null, "failureCode": null, "createdAt": "2026-09-03T09:00:00.000Z", "updatedAt": "2026-09-03T09:01:00.700Z" } ] } ``` ### POST /v1/advance-cases **Otvori avansni slučaj** (operationId `createAdvanceCase`, scope `advance:write`, requires `Idempotency-Key` header) Slučaj vezuje sve avansne prodaje jedne narudžbine na istom obvezniku i prodajnom mestu. Ne izdaje račun; to radi sledeći poziv. Može da preuzme i avanse naplaćene pre eFiskalizacije. Contract notes: Creates a Boka-owned, same-taxpayer/same-premise chain. External and pre-eFiscalization starting references are deliberately outside this bounded workflow. Request body (application/json, AdvanceCaseCreate): - `taxpayerId` (uuid, required) - `businessPremiseId` (uuid, required) - `clientReference` (string, required) [min 1, max 200] - `externalAdvance` (ExternalAdvance | null): Advances collected before eFiscalization that this case closes. The first Advance Sale then references the last pre-fiscal document as XXXXXXXX-XXXXXXXX-, or the close starts with the Advance Refund referencing it when no Advance Sale was fiscalized, and the closing Advance Refund sums pre-fiscal and fiscal advances alike. - `amount` (number, required): Sum of every advance collected before eFiscalization; at most two decimals. [> 0, step 0.01] - `taxLabel` (string, required): Tax label of the future supply; must be a prescribed advance label. - `paymentType` (PaymentType, required): OTHER | CASH | CARD | CHECK | WIRE_TRANSFER | VOUCHER | INSTANT_PAYMENT - `lastDocumentNumber` (string, required): Number of the last pre-fiscal advance document, digits only (1 to 20). It is sent as the `` part of the reference `XXXXXXXX-XXXXXXXX-`; the official examples are `17`, `121` and `159`, and the V-PFR rejects any other form. Anything but digits returns 422 with the `ExternalAdvance.LastDocumentNumber` validation key. [min 1, max 20, pattern ^[0-9]{1,20}$] - `lastDocumentTime` (date-time, required): Issue date of that document; must precede the request. Responses: - 200 (AdvanceCase): Idempotent replay of the same case creation - 201 (AdvanceCase): Advance case - 409 (IdempotencyConflict): The key was already used with different canonical content - 422 (ErrorCode): The command violates a Boka or fiscal rule Example: ```bash curl -X POST "https://api.bokapos.rs/v1/advance-cases" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-5001-advance-case" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-5001" }' ``` Response 201: ```json { "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-5001", "externalAdvance": null, "state": "OPEN", "advanceSales": [], "cancellations": [], "cancelledAdvanceSaleIds": [], "advanceRefund": null, "finalSale": null, "failureCode": null, "createdAt": "2026-09-03T09:00:00.000Z", "updatedAt": "2026-09-03T09:00:00.000Z" } ``` ### GET /v1/advance-cases/{advanceCaseId} **Pročitaj avansni slučaj** (operationId `getAdvanceCase`, scope `fiscal:read`) Ceo lanac: avansne prodaje, storna, konačna refundacija avansa i konačni račun, plus stanje koje kaže šta je sledeće dozvoljeno. Parameters: - `advanceCaseId` (path, uuid, required) Responses: - 200 (AdvanceCase): Advance case - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope Example: ```bash curl -X GET "https://api.bokapos.rs/v1/advance-cases/c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-5001", "externalAdvance": null, "state": "OPEN", "advanceSales": [ { "id": "d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-5001-advance-1", "clientReference": "ORDER-5001", "invoiceType": "ADVANCE", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1049", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 904, "totalCounter": 1049, "invoiceCounterExtension": "АП", "totalAmount": 3000, "totalTax": 297.2973, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1049\nБројач рачуна: 904/1049АП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/official-text", "jsonUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ], "cancellations": [], "cancelledAdvanceSaleIds": [], "advanceRefund": null, "finalSale": null, "failureCode": null, "createdAt": "2026-09-03T09:00:00.000Z", "updatedAt": "2026-09-03T09:01:00.700Z" } ``` ### POST /v1/advance-cases/{advanceCaseId}/payments **Fiskalizuj avansnu uplatu** (operationId `fiscalizeAdvancePayment`, scope `advance:write`, requires `Idempotency-Key` header) Izdaje sledeću avansnu prodaju u lancu; BokaPOS sam upisuje referencu na prethodnu. Stavke su propisani avansni artikli (10: Аванс (Ђ) i srodni), komercijalni tekst je obavezan. Contract notes: Boka references the immediately preceding fiscalized Advance Sale stored in this exact case. Any unresolved prior outcome blocks another payment, and a changed idempotent replay is rejected. Parameters: - `advanceCaseId` (path, uuid, required) Request body (application/json, AdvancePaymentCreate): - `cashier` (Cashier, required) - `id` (string, required) - `displayName` (string) - `buyer` (Buyer) - `id` (string): Official prefix and value, for example 10:123456789. - `optionalField` (string): Official buyer-cost-center prefix and value where applicable. - `paymentOccurredAt` (date-time): Actual earlier payment time for the documented wire-transfer case. When supplied, it must precede the fiscalization attempt and at least one payment must be Wire Transfer. - `items` (array, required) [min 1 items] - `catalogProductId` (uuid): Optional; arbitrary inline items are permitted. - `name` (string, required) [min 1, max 2048] - `unitOfMeasure` (string): Required on every item except the codebook advance literals (10: Аванс (Ђ) and siblings), which are prescribed verbatim without a unit. The API refuses any other item without one (422, Items.UnitOfMeasure) and composes it into the signed item name as name/unit. [min 1, max 50] - `quantity` (number, required): V-PFR Decimal(14,3). [>= 0.001, <= 99999999999.999, step 0.001] - `unitPrice` (number, required): Final gross unit price sent to V-PFR as Decimal(28,4). Boka applies the mandated fiscal rounding rules. [>= 0, step 0.01] - `unitPriceBeforeDiscount` (number): Optional Boka-local immutable gross unit price before discount. When present it must be greater than unitPrice; it is displayed outside the exact PFR journal and is never sent as a supplier field. [>= 0, step 0.0001] - `gtin` (string) [min 8, max 14] - `taxLabels` (array, required) [min 1 items, unique] - `payments` (array, required) [min 1 items] - `type` (PaymentType, required): OTHER | CASH | CARD | CHECK | WIRE_TRANSFER | VOUCHER | INSTANT_PAYMENT - `amount` (number, required): At most two decimals (the V-PFR rejects more with validation code 2804); the field type on the wire is Decimal(28,4). [>= 0, step 0.01] - `commercialFooter` (string, required): Mandatory non-fiscal commercial area for the Advance Sale. [min 1, max 2000] Responses: - 200 (FiscalDocument): Idempotent replay of the fiscalized Advance Sale - 201 (FiscalDocument): Fiscalized Advance Sale - 409 (IdempotencyConflict): The key was already used with different canonical content - 422 (ErrorCode): The command violates a Boka or fiscal rule - 503 (FiscalDocument): No fiscal receipt was issued because V-PFR was unavailable or its outcome requires reconciliation Example: ```bash curl -X POST "https://api.bokapos.rs/v1/advance-cases/c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f/payments" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-5001-advance-1" \ -H "Content-Type: application/json" \ -d '{ "cashier": { "id": "web-shop" }, "items": [ { "name": "10: Аванс (F)", "quantity": 1, "unitPrice": 3000, "taxLabels": [ "F" ] } ], "payments": [ { "type": "WIRE_TRANSFER", "amount": 3000 } ], "paymentOccurredAt": "2026-09-02T11:30:00+02:00", "commercialFooter": "Avans za porudžbinu ORDER-5001. Isporuka po uplati ostatka." }' ``` Response 201: ```json { "id": "d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-5001-advance-1", "clientReference": "ORDER-5001", "invoiceType": "ADVANCE", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1049", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 904, "totalCounter": 1049, "invoiceCounterExtension": "АП", "totalAmount": 3000, "totalTax": 297.2973, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1049\nБројач рачуна: 904/1049АП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/official-text", "jsonUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-03T09:01:00.000Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` Note: U produkciji naziv stavke je propisani `10: Аванс (Ђ)` (ili 11/12/13 za Е, Г, А) sa istom oznakom. Sandbox nema te oznake, pa prima `10: Аванс (X)` za bilo koju oznaku iz sveže konfiguracije. ### POST /v1/advance-cases/{advanceCaseId}/cancellations **Storniraj poslednji avans** (operationId `cancelAdvanceSale`, scope `advance:write`, requires `Idempotency-Key` header) Avansna refundacija koja poništava poslednju avansnu prodaju u celosti, sa PIB-om prodavca kao kupcem, kako propisuje zvanični postupak. Slučaj ostaje otvoren. Contract notes: Issues an Advance Refund that repeats the complete latest Advance Sale of the open case, references it, and carries the seller's own PIB as the buyer (10:), as the official cancellation procedure prescribes. The case stays open; the next Advance Sale chains to the sale before the cancelled one. Only the latest fiscalized Advance Sale can be cancelled. Parameters: - `advanceCaseId` (path, uuid, required) Request body (application/json, AdvanceCancellationCreate): - `cashier` (Cashier, required) - `id` (string, required) - `displayName` (string) - `advanceSaleFiscalDocumentId` (uuid, required): The latest fiscalized Advance Sale of the open case; nothing else can be cancelled. Responses: - 200 (FiscalDocument): Idempotent replay of the fiscalized Advance Refund - 201 (FiscalDocument): Fiscalized Advance Refund cancelling the Advance Sale - 409 (IdempotencyConflict): The key was already used with different canonical content - 422 (ErrorCode): The command violates a Boka or fiscal rule - 503 (FiscalDocument): No fiscal receipt was issued because V-PFR was unavailable or its outcome requires reconciliation Example: ```bash curl -X POST "https://api.bokapos.rs/v1/advance-cases/c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f/cancellations" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-5001-advance-1-cancel" \ -H "Content-Type: application/json" \ -d '{ "cashier": { "id": "web-shop" }, "advanceSaleFiscalDocumentId": "d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80" }' ``` Response 201: ```json { "id": "a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-5001-advance-1-cancel", "clientReference": "ORDER-5001", "invoiceType": "ADVANCE", "transactionType": "REFUND", "cashierId": "web-shop", "buyerId": "10:115711881", "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1050", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 905, "totalCounter": 1050, "invoiceCounterExtension": "АР", "totalAmount": 3000, "totalTax": 297.2973, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1050\nБројач рачуна: 905/1050АР\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/official-text", "jsonUrl": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/a9b8c7d6-e5f4-4a3b-8c2d-1e0f9a8b7c6d/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80", "pfrNumber": "JWX4K9PL-JWX4K9PL-1049", "pfrTime": "2026-09-03T11:01:00.500+02:00" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` ### POST /v1/advance-cases/{advanceCaseId}/close **Zatvori avansni slučaj** (operationId `closeAdvanceCase`, scope `advance:close`, requires `Idempotency-Key` header) Dva dokumenta u jednom pozivu: avansna refundacija ukupnog avansa, pa konačni račun za promet sa stavkama isporuke i preostalim plaćanjem. Ako drugi korak ne stigne do V-PFR-a, odgovor 202 to kaže, a ponovni poziv istim ključem ponavlja samo njega. Contract notes: This is a recoverable two-document workflow. If the Advance Refund is fiscalized but the final Sale is confirmed not submitted, the response exposes the pending state and an idempotent replay retries only that stored final operation. An unknown outcome blocks instead of retrying. If the V-PFR rejects the Advance Refund, the case is `FAILED` with the rejection code, the refund document is `REJECTED`, and the final Sale reserved with it is never sent: it is closed as `NOT_FISCALIZED` with `ADVANCE_REFUND_NOT_FISCALIZED` and `retryable: false`. Open a new case to try again; a replay of the failed close re-drives nothing. This bounded operation closes the whole Boka-owned chain; partial and legacy/external realization remain unsupported. The Advance Refund is not a customer-delivery document. Parameters: - `advanceCaseId` (path, uuid, required) Request body (application/json, AdvanceCaseClose): - `cashier` (Cashier, required) - `id` (string, required) - `displayName` (string) - `buyer` (Buyer) - `id` (string): Official prefix and value, for example 10:123456789. - `optionalField` (string): Official buyer-cost-center prefix and value where applicable. - `finalItems` (array, required) [min 1 items] - `catalogProductId` (uuid): Optional; arbitrary inline items are permitted. - `name` (string, required) [min 1, max 2048] - `unitOfMeasure` (string): Required on every item except the codebook advance literals (10: Аванс (Ђ) and siblings), which are prescribed verbatim without a unit. The API refuses any other item without one (422, Items.UnitOfMeasure) and composes it into the signed item name as name/unit. [min 1, max 50] - `quantity` (number, required): V-PFR Decimal(14,3). [>= 0.001, <= 99999999999.999, step 0.001] - `unitPrice` (number, required): Final gross unit price sent to V-PFR as Decimal(28,4). Boka applies the mandated fiscal rounding rules. [>= 0, step 0.01] - `unitPriceBeforeDiscount` (number): Optional Boka-local immutable gross unit price before discount. When present it must be greater than unitPrice; it is displayed outside the exact PFR journal and is never sent as a supplier field. [>= 0, step 0.0001] - `gtin` (string) [min 8, max 14] - `taxLabels` (array, required) [min 1 items, unique] - `remainingPayments` (array, required): Must equal the final amount less the stored advance amount. Supply one explicit zero-amount element when the remaining balance is zero, because Create Invoice requires at least one payment element. [min 1 items] - `type` (PaymentType, required): OTHER | CASH | CARD | CHECK | WIRE_TRANSFER | VOUCHER | INSTANT_PAYMENT - `amount` (number, required): At most two decimals (the V-PFR rejects more with validation code 2804); the field type on the wire is Decimal(28,4). [>= 0, step 0.01] - `commercialFooter` (string) [max 1500] Responses: - 200 (AdvanceCloseResult): Idempotent replay of an already closed case - 201 (AdvanceCloseResult): Closed advance case - 202 (AdvanceCloseResult): Advance Refund is fiscalized; final Sale remains pending - 409 (IdempotencyConflict): The key was already used with different canonical content - 422 (ErrorCode): The command violates a Boka or fiscal rule - 503 (FiscalDocument): No fiscal receipt was issued because V-PFR was unavailable or its outcome requires reconciliation Example: ```bash curl -X POST "https://api.bokapos.rs/v1/advance-cases/c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f/close" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-5001-close" \ -H "Content-Type: application/json" \ -d '{ "cashier": { "id": "web-shop" }, "finalItems": [ { "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 8990, "gtin": "8606012345678", "taxLabels": [ "F" ] } ], "remainingPayments": [ { "type": "CARD", "amount": 5990 } ], "commercialFooter": "Hvala na kupovini." }' ``` Response 201: ```json { "case": { "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "ORDER-5001", "externalAdvance": null, "state": "CLOSED", "advanceSales": [ { "id": "d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-5001-advance-1", "clientReference": "ORDER-5001", "invoiceType": "ADVANCE", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1049", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 904, "totalCounter": 1049, "invoiceCounterExtension": "АП", "totalAmount": 3000, "totalTax": 297.2973, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1049\nБројач рачуна: 904/1049АП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/official-text", "jsonUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ], "cancellations": [], "cancelledAdvanceSaleIds": [], "advanceRefund": { "id": "e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-5001-close:refund", "clientReference": "ORDER-5001", "invoiceType": "ADVANCE", "transactionType": "REFUND", "cashierId": "web-shop", "buyerId": "10:115711881", "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1051", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 906, "totalCounter": 1051, "invoiceCounterExtension": "АР", "totalAmount": 3000, "totalTax": 297.2973, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1051\nБројач рачуна: 906/1051АР\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/official-text", "jsonUrl": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80", "pfrNumber": "JWX4K9PL-JWX4K9PL-1049", "pfrTime": "2026-09-03T11:01:00.500+02:00" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "finalSale": { "id": "f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "order-5001-close:sale", "clientReference": "ORDER-5001", "invoiceType": "NORMAL", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1052", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 907, "totalCounter": 1052, "invoiceCounterExtension": "ПП", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1052\nБројач рачуна: 907/1052ПП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/official-text", "jsonUrl": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/f7a8b9c0-d1e2-4f3a-8b4c-5d6e7f8091a2/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "reference": { "fiscalDocumentId": "e6f7a8b9-c0d1-4e2f-9a3b-4c5d6e7f8091", "pfrNumber": "JWX4K9PL-JWX4K9PL-1051", "pfrTime": "2026-09-05T13:20:44.010+02:00" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "failureCode": null, "createdAt": "2026-09-03T09:00:00.000Z", "updatedAt": "2026-09-05T11:20:45.300Z" } } ``` Note: Konačni račun nosi ukupnu vrednost isporuke (8.990) i referencu na avansnu refundaciju; `remainingPayments` je samo doplata (5.990). ## Predračun i obuka Ograničeni tok za predračun (Проформа) i obuku (Обука), sa refundacijom koja mora da ponovi ceo izvorni dokument. ### POST /v1/proforma-training-workflows **Izdaj predračun ili račun za obuku** (operationId `createProformaTrainingWorkflow`, scope `proforma-training:write`, requires `Idempotency-Key` header) Predračun (Проформа) je ponuda bez poreskog efekta, obuka (Обука) je vežba. Prodaja obuke ne sme imati referencu; refundacija mora tačno da ponovi izvorni dokument i identifikuje kupca. Contract notes: Accepts only Proforma or Training transactions through the dedicated workflow scope. Training Sale forbids a reference. Training Refund must reference an exact Boka-issued Training Sale. Proforma Sale may omit a reference or reference a Boka-issued Proforma Sale or Refund; Proforma Refund must reference a Boka-issued Proforma Sale. Refunds must exactly reproduce every source item and payment, identify the buyer, and only one unresolved or completed full refund may reserve a source. External and legacy references remain outside this bounded workflow. An unknown PFR outcome is terminal for automatic submission and an idempotent replay never creates a second fiscal request. Request body (application/json, ProformaTrainingWorkflowCreate): - `taxpayerId` (uuid, required) - `businessPremiseId` (uuid, required) - `clientReference` (string, required) [min 1, max 200] - `invoiceType` (string, required): PROFORMA | TRAINING - `transactionType` (TransactionType, required): SALE | REFUND - `cashier` (Cashier, required) - `id` (string, required) - `displayName` (string) - `buyer` (Buyer) - `id` (string): Official prefix and value, for example 10:123456789. - `optionalField` (string): Official buyer-cost-center prefix and value where applicable. - `original` (BokaDocumentReference) - `source` (const "BOKA", required) - `fiscalDocumentId` (uuid, required) - `items` (array, required) [min 1 items] - `catalogProductId` (uuid): Optional; arbitrary inline items are permitted. - `name` (string, required) [min 1, max 2048] - `unitOfMeasure` (string): Required on every item except the codebook advance literals (10: Аванс (Ђ) and siblings), which are prescribed verbatim without a unit. The API refuses any other item without one (422, Items.UnitOfMeasure) and composes it into the signed item name as name/unit. [min 1, max 50] - `quantity` (number, required): V-PFR Decimal(14,3). [>= 0.001, <= 99999999999.999, step 0.001] - `unitPrice` (number, required): Final gross unit price sent to V-PFR as Decimal(28,4). Boka applies the mandated fiscal rounding rules. [>= 0, step 0.01] - `unitPriceBeforeDiscount` (number): Optional Boka-local immutable gross unit price before discount. When present it must be greater than unitPrice; it is displayed outside the exact PFR journal and is never sent as a supplier field. [>= 0, step 0.0001] - `gtin` (string) [min 8, max 14] - `taxLabels` (array, required) [min 1 items, unique] - `payments` (array, required) [min 1 items] - `type` (PaymentType, required): OTHER | CASH | CARD | CHECK | WIRE_TRANSFER | VOUCHER | INSTANT_PAYMENT - `amount` (number, required): At most two decimals (the V-PFR rejects more with validation code 2804); the field type on the wire is Decimal(28,4). [>= 0, step 0.01] - `commercialFooter` (string) [max 2000] - `metadata` (object): Non-fiscal caller metadata. Responses: - 200 (ProformaTrainingWorkflow): Idempotent replay of a completed workflow - 201 (ProformaTrainingWorkflow): Fiscalized Proforma or Training document - 202 (ProformaTrainingWorkflow): The request is durably reserved but has not been submitted - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope - 409: Idempotency, source-reservation, or terminal workflow conflict - 422: The command violates a Boka or fiscal rule, or PFR definitively rejected the reserved operation - 503: No fiscal receipt is claimed; the workflow is unavailable or its outcome is unresolved Example: ```bash curl -X POST "https://api.bokapos.rs/v1/proforma-training-workflows" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: quote-2210-proforma-1" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "QUOTE-2210", "invoiceType": "PROFORMA", "transactionType": "SALE", "cashier": { "id": "web-shop" }, "buyer": { "id": "10:106952811" }, "items": [ { "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 8990, "gtin": "8606012345678", "taxLabels": [ "F" ] } ], "payments": [ { "type": "WIRE_TRANSFER", "amount": 8990 } ], "commercialFooter": "Ponuda važi 7 dana." }' ``` Response 201: ```json { "id": "0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "QUOTE-2210", "invoiceType": "PROFORMA", "transactionType": "SALE", "state": "COMPLETED", "original": null, "document": { "id": "1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "quote-2210-proforma-1", "clientReference": "QUOTE-2210", "invoiceType": "PROFORMA", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": "10:106952811", "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1047", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 902, "totalCounter": 1047, "invoiceCounterExtension": "ПрП", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1047\nБројач рачуна: 902/1047ПрП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/official-text", "jsonUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "failureCode": null, "createdAt": "2026-09-02T07:02:10.000Z", "updatedAt": "2026-09-02T07:02:11.204Z" } ``` Example (training): ```bash curl -X POST "https://api.bokapos.rs/v1/proforma-training-workflows" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: training-2026-09-02-1" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "TRAINING-1", "invoiceType": "TRAINING", "transactionType": "SALE", "cashier": { "id": "operater-1" }, "items": [ { "name": "Test artikal", "unitOfMeasure": "kom", "quantity": 1, "unitPrice": 100, "taxLabels": [ "F" ] } ], "payments": [ { "type": "CASH", "amount": 100 } ] }' ``` Response 201: ```json { "id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "TRAINING-1", "invoiceType": "TRAINING", "transactionType": "SALE", "state": "COMPLETED", "original": null, "document": { "id": "3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "training-2026-09-02-1", "clientReference": "TRAINING-1", "invoiceType": "TRAINING", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": null, "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1048", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 903, "totalCounter": 1048, "invoiceCounterExtension": "ОП", "totalAmount": 100, "totalTax": 9.9099, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1048\nБројач рачуна: 903/1048ОП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/official-text", "jsonUrl": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "failureCode": null, "createdAt": "2026-09-02T07:10:00.000Z", "updatedAt": "2026-09-02T07:10:01.100Z" } ``` ### GET /v1/proforma-training-workflows/{proformaTrainingWorkflowId} **Pročitaj tok predračuna ili obuke** (operationId `getProformaTrainingWorkflow`, scope `fiscal:read`) Stanje toka i njegov dokument, uključujući OUTCOME_UNKNOWN koji sistem mora da razreši pre novog pokušaja. Parameters: - `proformaTrainingWorkflowId` (path, uuid, required) Responses: - 200 (ProformaTrainingWorkflow): Persisted workflow and fiscal-document state - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope Example: ```bash curl -X GET "https://api.bokapos.rs/v1/proforma-training-workflows/0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "clientReference": "QUOTE-2210", "invoiceType": "PROFORMA", "transactionType": "SALE", "state": "COMPLETED", "original": null, "document": { "id": "1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "idempotencyKey": "quote-2210-proforma-1", "clientReference": "QUOTE-2210", "invoiceType": "PROFORMA", "transactionType": "SALE", "cashierId": "web-shop", "buyerId": "10:106952811", "buyerDetails": null, "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "pfr": { "invoiceNumber": "JWX4K9PL-JWX4K9PL-1047", "sdcTime": "2026-09-01T10:15:32.483+02:00", "requestedBy": "JWX4K9PL", "signedBy": "JWX4K9PL", "transactionTypeCounter": 902, "totalCounter": 1047, "invoiceCounterExtension": "ПрП", "totalAmount": 8990, "totalTax": 890.9009, "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1047\nБројач рачуна: 902/1047ПрП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА =========" }, "receipt": { "textUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/official-text", "jsonUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/canonical-json", "pdfA4Url": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/pdf-a4", "pdf80mmUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/pdf-80mm", "pdf58mmUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/pdf-58mm", "previewImageUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/preview-png", "qrImageUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/qr-svg", "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...", "preferredPaperFormat": "a4" }, "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" }, "failureCode": null, "createdAt": "2026-09-02T07:02:10.000Z", "updatedAt": "2026-09-02T07:02:11.204Z" } ``` ## Dostava računa e-poštom Slanje fiskalizovanog računa kupcu sa platforme, sa verifikacionim linkom i PDF prilozima (modul E-mail). ### GET /v1/receipt-deliveries **Lista dostava jednog računa** (operationId `listReceiptDeliveries`, scope `fiscal:read`) Sve e-mail dostave jednog fiskalnog dokumenta sa statusom i brojem pokušaja. Parameters: - `fiscalDocumentId` (query, uuid, required) Responses: - 200: Deliveries in creation order (at most 100) - 422 (ErrorCode): The command violates a Boka or fiscal rule Example: ```bash curl -X GET "https://api.bokapos.rs/v1/receipt-deliveries?fiscalDocumentId=9f8e7d6c-5b4a-4321-8765-0fedcba98761" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "items": [ { "id": "f6a7b8c9-d0e1-4f2a-9b3c-4d5e6f7a8b90", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "channel": "EMAIL", "recipient": "kupac@example.com", "language": "sr-Latn", "attachments": [ "a4" ], "status": "DELIVERED", "attempts": 1, "failureCode": null, "createdAt": "2026-09-01T08:15:40.000Z", "deliveredAt": "2026-09-01T08:15:52.418Z", "updatedAt": "2026-09-01T08:15:52.418Z" } ] } ``` ### POST /v1/receipt-deliveries **Pošalji račun e-poštom** (operationId `createReceiptDelivery`, scope `fiscal:write`, requires `Idempotency-Key` header) Stavlja u red jednu poruku sa verifikacionim linkom i izabranim PDF prilozima, na jeziku obveznika. Radi samo za fiskalizovan dokument i samo ako je obveznik uključio dostavu u podešavanjima; u produkciji traži modul E-mail. Status dostave nikad nije dokaz fiskalizacije. Contract notes: Queues one email delivery of one fiscalized document from the platform mailbox, in the taxpayer's chosen language, with the official verification URL as an active link and the A4 PDF attached. Delivery is queued only after the signed result is durably stored, only when the taxpayer enabled email delivery in its settings (422 RECEIPT_DELIVERY_DISABLED otherwise; the taxpayer then delivers through its own system), and only while the platform transport is configured (503 RECEIPT_DELIVERY_UNAVAILABLE otherwise). A delivery outcome is never evidence of fiscalization. Tenant branding stays outside the fiscal receipt boundary. Request body (application/json, ReceiptDeliveryCreate): - `fiscalDocumentId` (uuid, required) - `channel` (const "EMAIL", required) - `recipient` (email, required) [max 320] - `language` (ReceiptDeliveryLanguage | null): sr-Cyrl | sr-Latn | en; Defaults to the taxpayer's setting. - `attachments` (ReceiptDeliveryAttachments | null): a4 | 80mm | 58mm | png; Defaults to the taxpayer's setting. Responses: - 200 (ReceiptDelivery): Idempotent replay - 202 (ReceiptDelivery): Delivery queued - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope - 409 (IdempotencyConflict): The key was already used with different canonical content - 422 (ErrorCode): The command violates a Boka or fiscal rule - 503: The platform mail transport is not configured Example: ```bash curl -X POST "https://api.bokapos.rs/v1/receipt-deliveries" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Idempotency-Key: order-4127-email-1" \ -H "Content-Type: application/json" \ -d '{ "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "channel": "EMAIL", "recipient": "kupac@example.com", "language": "sr-Latn", "attachments": [ "a4" ] }' ``` Response 202: ```json { "id": "f6a7b8c9-d0e1-4f2a-9b3c-4d5e6f7a8b90", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "channel": "EMAIL", "recipient": "kupac@example.com", "language": "sr-Latn", "attachments": [ "a4" ], "status": "QUEUED", "attempts": 0, "failureCode": null, "createdAt": "2026-09-01T08:15:40.000Z", "deliveredAt": null, "updatedAt": "2026-09-01T08:15:40.000Z" } ``` ### GET /v1/receipt-deliveries/{receiptDeliveryId} **Pročitaj dostavu** (operationId `getReceiptDelivery`, scope `fiscal:read`) Stanje jedne dostave: QUEUED, SENDING, DELIVERED ili FAILED sa šifrom. Parameters: - `receiptDeliveryId` (path, uuid, required) Responses: - 200 (ReceiptDelivery): Delivery - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope Example: ```bash curl -X GET "https://api.bokapos.rs/v1/receipt-deliveries/f6a7b8c9-d0e1-4f2a-9b3c-4d5e6f7a8b90" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "f6a7b8c9-d0e1-4f2a-9b3c-4d5e6f7a8b90", "fiscalDocumentId": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "channel": "EMAIL", "recipient": "kupac@example.com", "language": "sr-Latn", "attachments": [ "a4" ], "status": "DELIVERED", "attempts": 1, "failureCode": null, "createdAt": "2026-09-01T08:15:40.000Z", "deliveredAt": "2026-09-01T08:15:52.418Z", "updatedAt": "2026-09-01T08:15:52.418Z" } ``` ## Operacije Trajno stanje jedne fiskalne operacije, bez kontakta sa V-PFR-om. ### GET /v1/operations/{operationId} **Pročitaj operaciju** (operationId `getOperation`, scope `operations:read`) Isto stanje kao fiskalni dokument, u kraćem obliku, iz baze i bez kontakta sa V-PFR-om. Koristite kad 409 vrati operationId ili kad proveravate nepoznat ishod. Contract notes: Reads Boka's durable PostgreSQL operation state without contacting V-PFR, opening a security element, recovering an outcome, or retrying a fiscal command. A false fiscalized value is never a receipt. Parameters: - `operationId` (path, uuid, required) Responses: - 200 (Operation): Operation - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope Example: ```bash curl -X GET "https://api.bokapos.rs/v1/operations/9f8e7d6c-5b4a-4321-8765-0fedcba98761" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "9f8e7d6c-5b4a-4321-8765-0fedcba98761", "kind": "FISCAL_DOCUMENT", "status": "FISCALIZED", "fiscalized": true, "failureCode": null, "retryable": false, "resourceUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761", "createdAt": "2026-09-01T08:15:31.902Z", "updatedAt": "2026-09-01T08:15:32.611Z" } ``` Example (unknown): ```bash curl -X GET "https://api.bokapos.rs/v1/operations/4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f70" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f70", "kind": "FISCAL_DOCUMENT", "status": "OUTCOME_UNKNOWN", "fiscalized": false, "failureCode": "PFR_RESPONSE_NOT_OBSERVED", "retryable": false, "resourceUrl": "/v1/fiscal-documents/4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f70", "createdAt": "2026-09-01T09:00:00.000Z", "updatedAt": "2026-09-01T09:00:31.000Z" } ``` ## Katalog Proizvodi i usluge sa cenom, jedinicom mere, GTIN-om i poreskim oznakama; uvoz i izvoz CSV-a. ### GET /v1/products/{productId} **Pročitaj proizvod** (operationId `getProduct`, scope `catalogue:read`) Jedan proizvod po identifikatoru. Parameters: - `productId` (path, uuid, required) Responses: - 200 (Product): Product - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope Example: ```bash curl -X GET "https://api.bokapos.rs/v1/products/d2e3f4a5-b6c7-4d8e-9f0a-1b2c3d4e5f60" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "d2e3f4a5-b6c7-4d8e-9f0a-1b2c3d4e5f60", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "sku": "BT-HP-001", "gtin": "8606012345678", "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "grossUnitPrice": 8990, "taxLabels": [ "F" ], "isActive": true, "createdAt": "2026-08-22T10:00:00.000Z", "updatedAt": "2026-08-22T10:00:00.000Z" } ``` ### PUT /v1/products/{productId} **Izmeni proizvod** (operationId `updateProduct`, scope `catalogue:write`) Zamena svih uređivih polja. Obveznik je nepromenljiv; deaktivacija čuva istorijske snimke na računima. Contract notes: The owning taxpayer is immutable; deactivation preserves historical receipt snapshots. Parameters: - `productId` (path, uuid, required) Request body (application/json, ProductUpdate): - `sku` (string, required) [min 1, max 100] - `gtin` (string | null) [max 32] - `name` (string, required) [min 1, max 500] - `unitOfMeasure` (string, required) [min 1, max 50] - `grossUnitPrice` (number, required) [>= 0, step 0.01] - `taxLabels` (array, required) [min 1 items, unique] - `isActive` (boolean, required) Responses: - 200 (Product): Updated product - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope - 409 (Conflict): The requested resource conflicts with an existing tenant-scoped record - 422 (ErrorCode): The command violates a Boka or fiscal rule Example: ```bash curl -X PUT "https://api.bokapos.rs/v1/products/d2e3f4a5-b6c7-4d8e-9f0a-1b2c3d4e5f60" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "sku": "BT-HP-001", "gtin": "8606012345678", "name": "Bluetooth slušalice Pro", "unitOfMeasure": "kom", "grossUnitPrice": 9490, "taxLabels": [ "F" ], "isActive": true }' ``` Response 200: ```json { "id": "d2e3f4a5-b6c7-4d8e-9f0a-1b2c3d4e5f60", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "sku": "BT-HP-001", "gtin": "8606012345678", "name": "Bluetooth slušalice Pro", "unitOfMeasure": "kom", "grossUnitPrice": 9490, "taxLabels": [ "F" ], "isActive": true, "createdAt": "2026-08-22T10:00:00.000Z", "updatedAt": "2026-09-04T12:00:00.000Z" } ``` ### POST /v1/products/import **Uvezi katalog (CSV)** (operationId `importProducts`, scope `catalogue:write`) Sve ili ništa: do 1.000 redova ili 5 MB, oznake razdvojene sa |. Prihvata i CSV iz srpskog Excela (BOM, sep=;, decimalni zarez). Contract notes: The import is all-or-nothing, accepts at most 1,000 rows or 5 MB, and uses `|` between tax labels. Parameters: - `taxpayerId` (query, uuid, required) Request body (text/csv): Responses: - 200 (ProductImportResult): Import counts - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope - 409 (Conflict): The requested resource conflicts with an existing tenant-scoped record - 422 (ErrorCode): The command violates a Boka or fiscal rule Example: ```bash curl -X POST "https://api.bokapos.rs/v1/products/import?taxpayerId=3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Content-Type: text/csv" \ --data-binary @katalog.csv ``` Response 200: ```json { "created": 1, "updated": 1, "total": 2 } ``` ### GET /v1/products/export **Izvezi katalog (CSV)** (operationId `exportProducts`, scope `catalogue:read`) Deterministički CSV jednog obveznika, isti format kao uvoz. Parameters: - `taxpayerId` (query, uuid, required) Responses: - 200: Catalogue CSV using invariant decimals and `|`-separated tax labels - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope Example: ```bash curl -X GET "https://api.bokapos.rs/v1/products/export?taxpayerId=3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ --output katalog.csv ``` Response 200 (text/csv): ```text sku,name,gtin,unitOfMeasure,grossUnitPrice,taxLabels,isActive BT-HP-001,Bluetooth slušalice,8606012345678,kom,8990.00,F,true SRV-INST,Instalacija,,h,4000.00,F,true ``` ### GET /v1/products **Lista proizvoda** (operationId `listProducts`, scope `catalogue:read`) Katalog po obvezniku, sa pretragom po nazivu, šifri ili GTIN-u i filterom aktivnosti. Stranice preko cursor-a. Parameters: - `taxpayerId` (query, uuid) - `search` (query, string) - `isActive` (query, boolean) - `cursor` (query, uuid) - `pageSize` (query, integer) Responses: - 200 (ProductPage): Product page - 400 (ErrorCode): The command violates a Boka or fiscal rule - 422 (ErrorCode): The command violates a Boka or fiscal rule Example: ```bash curl -X GET "https://api.bokapos.rs/v1/products?taxpayerId=3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11&search=slu%C5%A1alice&isActive=true" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "items": [ { "id": "d2e3f4a5-b6c7-4d8e-9f0a-1b2c3d4e5f60", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "sku": "BT-HP-001", "gtin": "8606012345678", "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "grossUnitPrice": 8990, "taxLabels": [ "F" ], "isActive": true, "createdAt": "2026-08-22T10:00:00.000Z", "updatedAt": "2026-08-22T10:00:00.000Z" } ], "nextCursor": null } ``` ### POST /v1/products **Dodaj proizvod** (operationId `createProduct`, scope `catalogue:write`) Proizvod ili usluga sa šifrom, nazivom, jedinicom mere, bruto cenom (dve decimale) i poreskim oznakama. Stavke računa mogu, ali ne moraju, da se pozivaju na katalog. Request body (application/json, ProductCreate): - `taxpayerId` (uuid, required) - `sku` (string, required) [min 1, max 100] - `gtin` (string | null) [max 32] - `name` (string, required) [min 1, max 500] - `unitOfMeasure` (string, required) [min 1, max 50] - `grossUnitPrice` (number, required) [>= 0, step 0.01] - `taxLabels` (array, required) [min 1 items, unique] Responses: - 201 (Product): Product - 409 (Conflict): The requested resource conflicts with an existing tenant-scoped record - 422 (ErrorCode): The command violates a Boka or fiscal rule Example: ```bash curl -X POST "https://api.bokapos.rs/v1/products" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "sku": "BT-HP-001", "gtin": "8606012345678", "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "grossUnitPrice": 8990, "taxLabels": [ "F" ] }' ``` Response 201: ```json { "id": "d2e3f4a5-b6c7-4d8e-9f0a-1b2c3d4e5f60", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "sku": "BT-HP-001", "gtin": "8606012345678", "name": "Bluetooth slušalice", "unitOfMeasure": "kom", "grossUnitPrice": 8990, "taxLabels": [ "F" ], "isActive": true, "createdAt": "2026-08-22T10:00:00.000Z", "updatedAt": "2026-08-22T10:00:00.000Z" } ``` Response 409: ```json { "code": "CATALOGUE_SKU_ALREADY_EXISTS", "message": "A product with this SKU already exists for the taxpayer." } ``` ## Poreske stope Aktuelne poreske oznake i stope koje V-PFR vraća za tačan bezbednosni element prodajnog mesta. ### GET /v1/tax-rates **Aktuelne poreske stope** (operationId `listTaxRates`, scope `configuration:read`) Svež upit ka V-PFR-u sa tačnim bezbednosnim elementom prodajnog mesta. Oznake koje vrati su jedine koje račun sme da nosi; BokaPOS nema ugrađeni spisak niti rezervnu vrednost. Contract notes: Performs a fresh authenticated PFR status fetch for the exact active premise security element. The response is not a cache authority and no built-in label or rate fallback exists. Parameters: - `taxpayerId` (query, uuid, required) - `businessPremiseId` (query, uuid, required) Responses: - 200 (CurrentTaxConfiguration): Current fiscal tax configuration - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope - 409 (Conflict): The requested resource conflicts with an existing tenant-scoped record - 422 (ErrorCode): The command violates a Boka or fiscal rule - 503: A fresh authoritative PFR configuration could not be obtained Example: ```bash curl -X GET "https://api.bokapos.rs/v1/tax-rates?taxpayerId=3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11&businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "source": "PFR", "environment": "sandbox", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "currentTaxGroupId": 8, "validFrom": "2022-05-01T00:00:00", "fetchedAt": "2026-09-01T08:14:02.118Z", "labels": [ { "label": "F", "category": "ECAL", "categoryType": 0, "rate": 11, "activeFrom": "2022-05-01T00:00:00" }, { "label": "N", "category": "N-TAX", "categoryType": 0, "rate": 0, "activeFrom": "2022-05-01T00:00:00" }, { "label": "P", "category": "PBL", "categoryType": 2, "rate": 0.5, "activeFrom": "2022-05-01T00:00:00" }, { "label": "E", "category": "STT", "categoryType": 0, "rate": 6, "activeFrom": "2022-05-01T00:00:00" }, { "label": "T", "category": "TOTL", "categoryType": 1, "rate": 2, "activeFrom": "2022-05-01T00:00:00" }, { "label": "A", "category": "VAT", "categoryType": 0, "rate": 10, "activeFrom": "2022-05-01T00:00:00" }, { "label": "B", "category": "VAT", "categoryType": 0, "rate": 0, "activeFrom": "2022-05-01T00:00:00" }, { "label": "Ж", "category": "VAT", "categoryType": 0, "rate": 19, "activeFrom": "2022-05-01T00:00:00" }, { "label": "C", "category": "VAT-EXCL", "categoryType": 0, "rate": 0, "activeFrom": "2022-05-01T00:00:00" } ] } ``` Note: Sandbox Poreske uprave nosi generički test skup oznaka. U produkciji dobijate zvanične srpske oznake (na primer Ђ 20%, Е 10%, Г 0%, А bez PDV-a). Nikad ne ugrađujte oznake u kod. ## Obveznici i prodajna mesta Identifikatori obveznika i poslovnog prostora koje svaki fiskalni zahtev nosi. Kreiraju se u portalu, API ih čita. ### GET /v1/taxpayers **Lista obveznika** (operationId `listTaxpayers`, scope `tenant:read`) Obveznici (pravna lica) organizacije kojoj kredencijal pripada, samo u okruženju kredencijala: sandbox ključ vidi sandbox obveznike, produkcioni produkcione. Contract notes: Scoped to the caller's environment: a machine credential sees only the taxpayers of its own environment, a portal user sees both unless the organization hides its sandbox data. Responses: - 200 (TaxpayerPage): Taxpayers - 400 (ErrorCode): The command violates a Boka or fiscal rule Example: ```bash curl -X GET "https://api.bokapos.rs/v1/taxpayers" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "items": [ { "id": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "taxIdentifier": "115711881", "legalName": "BOKA GROUP DOO", "environment": "sandbox", "status": "active", "registrationNumber": "22196456", "address": "Roze Luksemburg 16", "city": "Beograd", "municipality": "Rakovica", "activityCode": "6201", "activityName": "Računarsko programiranje", "vatStatus": "in_vat", "createdAt": "2026-08-21T09:00:00.000Z", "updatedAt": "2026-08-21T09:00:00.000Z" } ] } ``` ### GET /v1/taxpayers/{taxpayerId} **Pročitaj obveznika** (operationId `getTaxpayer`, scope `tenant:read`) Jedan obveznik sa PIB-om, statusom i PDV statusom. Parameters: - `taxpayerId` (path, uuid, required) Responses: - 200 (Taxpayer): Taxpayer - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope Example: ```bash curl -X GET "https://api.bokapos.rs/v1/taxpayers/3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "taxIdentifier": "115711881", "legalName": "BOKA GROUP DOO", "environment": "sandbox", "status": "active", "registrationNumber": "22196456", "address": "Roze Luksemburg 16", "city": "Beograd", "municipality": "Rakovica", "activityCode": "6201", "activityName": "Računarsko programiranje", "vatStatus": "in_vat", "createdAt": "2026-08-21T09:00:00.000Z", "updatedAt": "2026-08-21T09:00:00.000Z" } ``` ### GET /v1/taxpayers/{taxpayerId}/business-premises **Lista prodajnih mesta** (operationId `listBusinessPremises`, scope `tenant:read`) Prodajna mesta obveznika (poslovni prostori Poreske uprave). Svako ima svoj bezbednosni element i režim plaćanja. Parameters: - `taxpayerId` (path, uuid, required) Responses: - 200 (BusinessPremisePage): Premises - 400 (ErrorCode): The command violates a Boka or fiscal rule Example: ```bash curl -X GET "https://api.bokapos.rs/v1/taxpayers/3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11/business-premises" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "items": [ { "id": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "puIdentifier": "1234567", "name": "Web shop", "commerceMode": "distance", "environment": "sandbox", "paymentMode": "all", "status": "active", "createdAt": "2026-08-21T09:05:00.000Z", "updatedAt": "2026-08-21T09:05:00.000Z" } ] } ``` ### GET /v1/taxpayers/{taxpayerId}/business-premises/{businessPremiseId} **Pročitaj prodajno mesto** (operationId `getBusinessPremise`, scope `tenant:read`) Jedno prodajno mesto sa PU identifikatorom, režimom plaćanja i statusom. Parameters: - `taxpayerId` (path, uuid, required) - `businessPremiseId` (path, uuid, required) Responses: - 200 (BusinessPremise): Business premise - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope Example: ```bash curl -X GET "https://api.bokapos.rs/v1/taxpayers/3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11/business-premises/b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "puIdentifier": "1234567", "name": "Web shop", "commerceMode": "distance", "environment": "sandbox", "paymentMode": "all", "status": "active", "createdAt": "2026-08-21T09:05:00.000Z", "updatedAt": "2026-08-21T09:05:00.000Z" } ``` ## Bezbednosni elementi Bezbedni metapodaci sertifikata (JID, važenje, status) bez tajni. Za praćenje isteka i okruženja. ### GET /v1/security-elements **Lista bezbednosnih elemenata** (operationId `listSecurityElements`, scope `security-elements:read`) Metapodaci sertifikata po obvezniku i prodajnom mestu: JID, okruženje, važenje, status isteka i preporuka zamene. Tajne se nikad ne vraćaju. Contract notes: Secret envelope references and plaintext values are never returned. Scoped to the caller's environment like every other tenant read. Parameters: - `taxpayerId` (query, uuid) - `businessPremiseId` (query, uuid) Responses: - 200: Tenant-scoped security elements Example: ```bash curl -X GET "https://api.bokapos.rs/v1/security-elements?businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "items": [ { "id": "e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a80", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "environment": "sandbox", "jid": "JWX4K9PL", "certificateThumbprint": "A1B2C3D4E5F60718293A4B5C6D7E8F9012345678", "certificateSubject": "CN=JWX4K9PL, O=BOKA GROUP DOO, C=RS", "certificateIssuer": "CN=Sandbox ICA, O=Poreska uprava Republike Srbije, C=RS", "certificateSerialNumber": "3F9C2A8E6B1D", "certificateNotBefore": "2026-08-20T00:00:00Z", "certificateNotAfter": "2028-08-20T00:00:00Z", "certificateExpiryStatus": "current", "replacementRecommended": false, "status": "active", "createdAt": "2026-08-21T09:10:00.000Z", "updatedAt": "2026-08-21T09:12:00.000Z" } ] } ``` ### GET /v1/security-elements/{securityElementId} **Pročitaj bezbednosni element** (operationId `getSecurityElement`, scope `security-elements:read`) Jedan element po identifikatoru, isti bezbedni skup polja. Parameters: - `securityElementId` (path, uuid, required) Responses: - 200 (SecurityElement): Security element metadata - 404 (ErrorCode): Resource does not exist within the authenticated tenant scope Example: ```bash curl -X GET "https://api.bokapos.rs/v1/security-elements/e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a80" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "id": "e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a80", "taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11", "businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22", "environment": "sandbox", "jid": "JWX4K9PL", "certificateThumbprint": "A1B2C3D4E5F60718293A4B5C6D7E8F9012345678", "certificateSubject": "CN=JWX4K9PL, O=BOKA GROUP DOO, C=RS", "certificateIssuer": "CN=Sandbox ICA, O=Poreska uprava Republike Srbije, C=RS", "certificateSerialNumber": "3F9C2A8E6B1D", "certificateNotBefore": "2026-08-20T00:00:00Z", "certificateNotAfter": "2028-08-20T00:00:00Z", "certificateExpiryStatus": "current", "replacementRecommended": false, "status": "active", "createdAt": "2026-08-21T09:10:00.000Z", "updatedAt": "2026-08-21T09:12:00.000Z" } ``` ## Licenca Stanje licence i uključeni moduli, da sistem zna unapred da li je produkcija dozvoljena. ### GET /v1/license **Stanje licence** (operationId `getLicenseSummary`, scope `tenant:read`) Da li je produkciona fiskalizacija trenutno dozvoljena, koji su moduli uključeni i koje cene važe. Sandbox se nikad ne naplaćuje i ne blokira. Contract notes: Any customer human or API client. Reports the licence state (none, active, suspended, not-started, expired), whether production fiscalization is currently allowed, which paid modules (Advance, E-mail) are enabled, and the effective prices in RSD with VAT included. Sandbox elements and sandbox traffic are never gated by licensing. A refused production command returns 403 with LICENSE_REQUIRED, LICENSE_NOT_STARTED, LICENSE_EXPIRED, LICENSE_SUSPENDED or MODULE_NOT_LICENSED before anything is reserved or sent to the V-PFR. Refunds of already fiscalized receipts and advance cancellations are never refused by licensing. Responses: - 200 (LicenseSummary): Licence summary Example: ```bash curl -X GET "https://api.bokapos.rs/v1/license" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "state": "active", "productionFiscalizationAllowed": true, "modules": { "advance": true, "email": false }, "startsOn": "2026-09-01", "endsOn": null, "prices": { "basePricePerElement": 1600, "includedDocuments": 600, "overageDocumentPrice": 1, "advanceModulePrice": 600, "emailModulePrice": 600, "vatRate": 0.2 } } ``` ## Runtime Identitet ESIR-a, verzija i spremnost fiskalnog adaptera, kako ih vidi vaš kredencijal. ### GET /v1/runtime **Runtime i spremnost** (operationId `getRuntime`, scope `tenant:read`) Prvi poziv posle tokena. Vraća proizvođača, ESIR broj (prazan dok Poreska uprava ne dodeli), verziju, organizaciju i client id iz tokena, i da li je fiskalni adapter konfigurisan. Koristite ga za proveru kredencijala i u health proverama. Responses: - 200 (RuntimeInfo): Runtime context Example: ```bash curl -X GET "https://api.bokapos.rs/v1/runtime" \ -H "Authorization: Bearer $BOKAPOS_TOKEN" ``` Response 200: ```json { "manufacturer": "BOKA GROUP DOO", "productName": "BokaPOS", "esirNumber": "", "softwareVersion": "1.0.0", "buildCommit": "1f0d454e8b2c9a7d6f5e4c3b2a1908f7e6d5c4b3", "instanceId": "api-bokapos-rs", "organizationId": "7c1e9a4b-2d3f-4e5a-b6c7-8d9e0f1a2b3c", "clientId": "boka-sbx-k7m2p9x4q1wz", "fiscalEndpointsEnabled": true, "pfrAdapter": "configured" } ```