Skip to content

Serbian fiscalization API: a fiscal receipt from your code

BokaPOS is a REST API for fiscalization in Serbia. Your system sends the items and payments in one call, and BokaPOS issues the fiscal receipt through the Tax Administration's V-PFR and returns the PFR number, verification link, QR code and PDF. BokaPOS is an approved ESIR (IB 1774) for distance selling; the sandbox is free.

Examples in curl, Node.js, PHP, C# and Python. The OpenAPI contract is public.

Approved by the Tax Administration

IB 1774
Decision
000-092-00-00256/2026-0000
Date
29 October 2026
Model
BokaPOS 1.0.1, ESIR class Advanced
Scope
Distance selling only, portable

What the API does

You send a business request; BokaPOS assembles the fiscal document by the Tax Administration's rules.

  • Issues fiscal receipts

    Normal (sale and refund), advance, proforma, training and copy, with every reference the rules require.

  • Returns a finished receipt

    PFR number, time and counter, verification link, official text, PDF in A4, 80 mm and 58 mm, PNG preview and QR code.

  • Runs the complex flows

    Refunds with a copy for cash, the advance chain with closure, proforma with a reference: BokaPOS runs them on the server.

  • Keeps the journal

    Every operation, including rejected ones and unknown outcomes, with search, export and a turnover report.

Your first receipt in three calls

Token, tax labels, receipt. A fourth call fetches the PDF or another representation when you need it; the URLs are already in the response.

  1. Get a token

    POSTauth.bokapos.rs/realms/boka/protocol/openid-connect/token

    OAuth 2.0 client credentials with your client id and secret. The token is valid for 300 seconds; cache it and refresh it before expiry.

  2. Read the tax labels

    GET/v1/tax-rates

    The labels in the response are the only ones a receipt may carry. Sandbox and production have different sets, so never hard-code them.

  3. Issue the receipt

    POST/v1/fiscal-documents

    With an Idempotency-Key header derived from the order. A 201 with fiscalized: true is a fiscal receipt; nothing else is.

  4. Fetch a representation (when needed)

    GET/v1/fiscal-documents/{id}/representations/pdf-a4

    When you need the PDF itself, an image or the QR code. The same document has seven representations.

Before the first receipt, read your taxpayerId and businessPremiseId once (GET /v1/taxpayers) and keep them in configuration.

Quick start in the API documentation

Example: the receipt request and the 201 response, shortened
POST/v1/fiscal-documents
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"
  },
  "items": [
    {
      "name": "Bluetooth slušalice",
      "unitOfMeasure": "kom",
      "quantity": 1,
      "unitPrice": 8990,
      "taxLabels": [
        "F"
      ]
    }
  ],
  "payments": [
    {
      "type": "CARD",
      "amount": 8990
    }
  ]
}'
201Created
{
  "id": "9f8e7d6c-5b4a-4321-8765-0fedcba98761",
  "clientReference": "ORDER-4127",
  "status": "FISCALIZED",
  "fiscalized": true,
  "pfr": {
    "invoiceNumber": "JWX4K9PL-JWX4K9PL-1042",
    "sdcTime": "2026-09-01T10:15:32.483+02:00",
    "totalAmount": 8990,
    "verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA..."
  },
  "receipt": {
    "pdfA4Url": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/pdf-a4",
    "qrImageUrl": "/v1/fiscal-documents/9f8e7d6c-5b4a-4321-8765-0fedcba98761/representations/qr-svg"
  }
}

What is in the response

The 201 response carries everything the customer and the accountant need, from the V-PFR's signed response.

Fields you keep with the order

pfr.invoiceNumber
the PFR receipt number, the official number assigned by the V-PFR
pfr.sdcTime
the PFR time, the official time of the receipt
pfr.verificationUrl
the link for checking at the Tax Administration; the same one is in the QR code
pfr.journal
the official text of the receipt
id
the key for copies, refunds and journal search

Every fiscalized receipt has seven representations. Send the customer a PDF or a link, and your system the JSON.

  • Official textofficial-text
  • PDF A4pdf-a4
  • PDF 80 mmpdf-80mm
  • PDF 58 mmpdf-58mm
  • Image for e-mailpreview-png
  • QR code for verificationqr-svg
  • JSON packagecanonical-json

No duplicate receipts

Every fiscal mutation carries an Idempotency-Key header, 16 to 200 characters long, derived from your order. The key is bound to the request content, so repeating never issues a second receipt.

Example key
Idempotency-Key: order-4127-sale-1
  • Same key, same content200

    The API returns the original operation (200 instead of 201) and never issues a second receipt, however many times you repeat.

  • Same key, different content409

    IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_REQUEST with the original's operationId. Nothing is issued.

  • Nothing was sent503, retryable: true

    Wait a few seconds and send the same request with the same key; the attempt that issues the receipt answers 201 with the same id.

  • Outcome unknownOUTCOME_UNKNOWN

    Do not send a new request for the same sale. Poll GET /v1/operations/{id}; BokaPOS resolves the outcome purely by reading from the V-PFR.

Conventions: idempotency and statuses

What is free and what is paid

Development and testing cost nothing. Production is paid, per security element and by volume.

Free

Sandbox
no expiry, never blocked by licensing
WooCommerce plugin
no charge for installation, updates or support
Integration help
sandbox access and examples for your system, with support from BokaPOS Administration

Paid monthly

VAT included
Base per production element
RSD 1,600
Documents included per organization
600
Each additional document
RSD 1
Advance module
RSD 600
E-mail module
RSD 600

The first month is prorated by day. Rejected and failed attempts are not charged.

Three routes to a fiscal receipt

The receipt is the same whichever route you take: the Tax Administration's V-PFR signs it. What differs is the work left to you.

What the integrator does on each route

The Tax Administration's free appTax Administration approvalnot your job; the Tax Administration publishes the appSecurity elementa file for distance commerceReceipts and representationsyou enter every order by hand and send the receipt to the customer yourselfMaintenanceno integration and no support
Your own ESIR on the V-PFRTax Administration approvalyour software becomes an ESIR: application, documentation and sample receipts, then a decision before the first real receiptSecurity elementyou keep and use every taxpayer's PFX, password and PAK yourselfReceipts and representationsyou build the official text, QR code, PDF and delivery yourself, per the Technical GuideMaintenancea change to fiscal functions or receipt appearance is reported and can require a new approval
An approved ESIR's API (BokaPOS)Tax Administration approvalalready in place: IB 1774, the decision is publicSecurity elementthe Owner uploads it to the portal once; it is stored encrypted and opened only for the exact business premiseReceipts and representationsseven representations in every response: official text, JSON, QR, PDF A4, 80 mm and 58 mm, PNGMaintenancethe ESIR supplier handles versions and approvals; tax labels are read from the Tax Administration before every issue

A taxpayer may use only an ESIR that the Tax Administration has approved and entered in its public register. Guide in Serbian: the free Tax Administration ESIR or a cloud ESIR

Integrating with AI?

Give the assistant two sources: the documentation bundle for AI and the OpenAPI contract. The prompt points it at both, gives it our rules (idempotency, unknown outcomes, tax labels) and tells it which questions to ask you before it writes code.

The prompt points at the English documentation because field names, codes and examples are English. The assistant answers in whichever language you use.

Questions about the API

Answers from the documentation, in short.

All questions about web shop fiscalization

Is there a free sandbox?

Yes. The sandbox is free, has no expiry and is never blocked by licensing. BokaPOS opens the organization, assigns a test security element and issues a sandbox credential; test receipts are issued under BOKA GROUP DOO's PIB and verify at sandbox.suf.purs.gov.rs.

Which programming languages have examples?

Five: curl, Node.js, PHP, C# and Python, for every operation. The API follows a public OpenAPI contract (api.bokapos.rs/openapi.yaml) from which you can generate a client in any language, and the documentation exists in Serbian and English, and as a PDF.

How does a system sign in to the API?

With OAuth 2.0 client credentials over TLS. The client id and secret get you a token valid for 300 seconds, which you cache and send as Authorization: Bearer. An Owner or Administrator of the organization collects the secret once in the portal, and it stays only on your server.

Do sandbox and production have different URLs?

No. Both environments use https://api.bokapos.rs; the credential decides the environment (boka-sbx-... or boka-prod-...). Every key sees only its own environment's data, so test and real receipts never mix.

What if I send the same request twice?

Nothing is issued twice. The same Idempotency-Key with the same content returns the original operation (200 instead of 201), and the same key with different content returns 409. Derive the key from the order, for example order-4127-sale-1.

How long does an integration take?

A day or two for a typical API integration, including sale and refund testing in the sandbox. With the WooCommerce plugin, setup takes an hour or two, without code.

Can one system issue receipts for several taxpayers or premises?

Yes. Every request carries taxpayerId and businessPremiseId, so the same code issues receipts for all taxpayers and premises of its organization, and each premise has its own security element. An agency gets a separate organization for every client.

What does going to production involve?

The code does not change. The Owner obtains the security element from the Tax Administration and uploads it to the portal, BokaPOS verifies and activates it and issues the licence and the production credential, and you swap the client id and secret in your configuration.

Where is the data stored?

In the European Union, separated per organization, with every receipt stored for good. The taxpayer's security element is encrypted in a vault and opened only for the exact business premise and purpose.

What if the Tax Administration does not answer?

Nothing is blindly sent again. If nothing was sent, the answer is 503 with retryable: true and you repeat the same request with the same key. If the request may have arrived, the status is OUTCOME_UNKNOWN: you send no new request, you poll GET /v1/operations/{id}, and BokaPOS resolves the outcome purely by reading from the V-PFR.

Is there a plugin for Shopify or other platforms?

No, a ready plugin exists only for WooCommerce, and it is free. Shopify, Magento, PrestaShop, OpenCart and custom systems call the same API, with one call per order, following the guide for each platform on the Integrations page.

How much does it cost?

RSD 1,600 per month per production security element, with 600 documents a month included per organization and RSD 1 per additional document, VAT included. The Advance and E-mail modules are RSD 600 a month each; the sandbox and the WooCommerce plugin are free.

Can I call the API from a browser or a mobile app?

No. The credential secret must never go into a browser, a mobile app, a public repository or a log; your backend always makes the calls to BokaPOS.

Do I send tax rates and the tax amount?

No. You send the gross price and a tax label from GET /v1/tax-rates; BokaPOS calculates the tax by the official rules and the V-PFR signs it. Do not hard-code labels, because sandbox and production differ.

Does the API work for sales in a physical shop?

No. BokaPOS is approved for distance selling only and does not support an L-PFR. Face-to-face sales need an L-PFR; for that the same company makes BokaLPFR.

Sandbox access and examples, the same working day

Send us a few sentences about your system. We reply the same working day with sandbox access and examples for your system.