Skip to content

API documentation

Journal, reports and state

Everything BokaPOS did for your organization is searchable: the electronic journal with every attempt, CSV export, the turnover report by PFR time, the state of a single operation, certificates and the licence.

Updated: 29 August 2026 · Contract version 1.0.0

Searching the journal

GET /v1/fiscal-documents returns operations of every kind (Normal, Advance, Copy, Proforma, Training; sale and refund), including rejected ones and unknown outcomes. All filters combine.

FilterMeaning
taxpayerId, businessPremiseIdnarrow to a taxpayer or premise
statusone document status (FISCALIZED, REJECTED, OUTCOME_UNKNOWN...)
invoiceType, transactionTypeinvoice and transaction type
createdFrom, createdTotime of receipt by BokaPOS (inclusive, exclusive)
pfrFrom, pfrToV-PFR signing time; excludes entries without a receipt
clientReference, idempotencyKey, pfrNumber, cashierId, buyerIdexact value
searchcase-insensitive contains, across safe identifiers
cursor, pageSizepagination; pageSize up to 200
GET /v1/fiscal-documents
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"
200 OK
{
  "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"
}

Send `nextCursor` as `cursor` for the next page; `null` means the end.

The list never returns pfrRejection; to diagnose a rejected document, read it individually.

GET /v1/fiscal-documents/{fiscalDocumentId}
curl -X GET "https://api.bokapos.rs/v1/fiscal-documents/1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f" \
  -H "Authorization: Bearer $BOKAPOS_TOKEN"
200 OK
{
  "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"
        ]
      }
    ]
  }
}

Code 2804 (format) is what the sandbox returns for a price with more than two decimals. A rejected document is not a receipt; correct the request and send it with a new key.

Journal export (CSV)

The same filters, a deterministic CSV of at most 10,000 rows, without raw PFR data and without secrets. The Boka-Export-Schema-Version header carries the format version (boka-fiscal-journal-csv-v2). If the filters match more than 10,000 rows, the request fails as a whole (422), so narrow the period.

GET /v1/fiscal-documents/export
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
200 OK · text/csv
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

The `Boka-Export-Schema-Version: boka-fiscal-journal-csv-v2` header names the format version.

Turnover report

A local immutable sum of fiscalized Normal and Advance receipts by V-PFR signing time, for one premise and period. Sale and refund are separate positive amounts; per-payment-type amounts come from the verified canonical request, the tax per label from the verified original V-PFR response, and the base and total per label from the receipt lines carrying that label (the total is the gross of those lines, the base is that total minus the tax). Amounts carry four decimals, like the tax the V-PFR signs; round them to two for display. It is your report, not a substitute for the daily report on the Tax Administration's SUF portal. The time bounds accept any RFC 3339 offset (Z, +00:00, +02:00) and are compared as instants.

GET /v1/fiscal-documents/turnover-report
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"
200 OK
{
  "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
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

Operation state

GET /v1/operations/{operationId} is the lighter shape of a document, from the database, without contacting the V-PFR. The operation identifier equals the document id. Use it when a 409 returns an operationId, and as the call you poll after OUTCOME_UNKNOWN.

GET /v1/operations/{operationId}
curl -X GET "https://api.bokapos.rs/v1/operations/9f8e7d6c-5b4a-4321-8765-0fedcba98761" \
  -H "Authorization: Bearer $BOKAPOS_TOKEN"
200 OK
{
  "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 leads to the full document. When an unknown outcome is resolved, status becomes FISCALIZED (the receipt existed at the V-PFR) and the order is fiscalized without a single new request.

Security elements

Safe certificate metadata per premise: JID, environment, validity, certificateExpiryStatus (current, warning 30 days before expiry, critical 7 days, expired) and replacementRecommended. Secrets are never returned. Useful for monitoring: warn the Owner before expiry, because the replacement is done by them in the Tax Administration portal and in the BokaPOS portal.

GET /v1/security-elements
curl -X GET "https://api.bokapos.rs/v1/security-elements?businessPremiseId=b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22" \
  -H "Authorization: Bearer $BOKAPOS_TOKEN"
200 OK
{
  "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"
    }
  ]
}

Licence

GET /v1/license says whether production fiscalization is currently allowed, which modules are enabled and which prices apply. Call it at start-up and after any 403 LICENSE_*. The sandbox is never billed and never blocked.

GET /v1/license
curl -X GET "https://api.bokapos.rs/v1/license" \
  -H "Authorization: Bearer $BOKAPOS_TOKEN"
200 OK
{
  "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
  }
}