Skip to content

API documentation

Authentication and environments

OAuth 2.0 client credentials over plain TLS. One URL for everyone; sandbox and production differ by credential, not by host.

Updated: 29 August 2026 · Contract version 1.0.0

URLs

WhatValue
APIhttps://api.bokapos.rs
OpenAPI contracthttps://api.bokapos.rs/openapi.yaml (public, no login)
Token (client credentials)https://auth.bokapos.rs/realms/boka/protocol/openid-connect/token
Portal for humanshttps://cloud.bokapos.rs

There is no separate sandbox host. The same code, URLs and calls work in both environments; only the client id and secret change.

Credentials

BokaPOS Administration issues an API credential (client id and secret) at the request of the organization's Owner, separately for sandbox (boka-sbx-...) and production (boka-prod-...). The secret is shown once, at issuance, and cannot be read again; if it is lost, the credential is revoked and a new one issued. A credential is bound to one organization and one environment and carries the fixed bundle of scopes described below.

Getting a token

A standard client_credentials request, application/x-www-form-urlencoded. No scope parameter is needed; the token receives every scope of the credential.

POST token
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"
Response
{
  "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"
}
  • The token is valid for 300 seconds. Cache it in process memory and refresh it when, say, fewer than 30 seconds remain. Do not request a new token for every call.
  • A 401 on any call means an expired or invalid token: get a new one and repeat the same request (with the same Idempotency-Key).
  • The token is a JWT with org_id (your organization) and boka_env (sandbox or production) claims. You need not read them; the API enforces them.
  • A wrong client id or secret returns 401 with error: invalid_client from the identity server.

Headers on every call

Headers
Authorization: Bearer <access_token>
Content-Type: application/json
Idempotency-Key: order-4127-sale-1      (fiscal mutations only)
Accept: application/json

Credential scopes

Every API credential receives the same bundle of twelve scopes. They decide which operations it may call; every other operation in the contract belongs to the portal and the BokaPOS console.

ScopeAllows
fiscal:writeissuing Normal Sale receipts, copies and e-mail delivery
fiscal:readreading documents, representations, the journal, reports, deliveries, advance cases
refund:writerefunds through /v1/refund-workflows
advance:writeopening an advance case, advance payments, cancellations
advance:closeclosing an advance case
proforma-training:writeproforma and training
operations:readoperation state
catalogue:read, catalogue:writethe product catalogue, import and export
configuration:readtax rates
tenant:readtaxpayers, premises, runtime, licence
security-elements:readcertificate metadata

Sandbox and production

  • The credential carries the environment. A sandbox credential can only work with a sandbox security element, a production credential only with a production one. Crossing them returns 403 CREDENTIAL_ENVIRONMENT_MISMATCH before anything is reserved.
  • BokaPOS assigns the sandbox element from its own pool; sandbox receipts therefore issue under BOKA GROUP DOO's PIB and verify at sandbox.suf.purs.gov.rs. The production element is your company's certificate, uploaded by the Owner in the portal.
  • The sandbox is free and never blocked by licensing. Production requires a valid licence; GET /v1/license tells you in advance whether fiscalization is allowed.
  • Tax labels differ. The Tax Administration sandbox carries a generic test set; production carries the official Serbian labels. That is why labels are always read from GET /v1/tax-rates.
  • A credential sees only its own environment. Every read is scoped: a sandbox key lists only sandbox taxpayers, premises, security elements and documents, a production key only production ones. An object of the other environment does not exist for you, so fetching it by id returns 404, and setup you register (POST /v1/taxpayers) belongs to your key's environment. A tax identifier is unique per environment, so your company can exist once in sandbox and once in production.
  • Idempotency keys are unique per organization across both environments. Reusing a key from sandbox testing in production returns 409 IDEMPOTENCY_KEY_REUSED_IN_OTHER_ENVIRONMENT; choose a new key rather than retrying.
  • Same organization, both environments. The Owner sees sandbox and production documents side by side in the portal until the organization goes live; from then on the portal hides sandbox data by default (the Owner can show it again in Settings). Your system tells them apart by the credential it called with.

Moving to production is described on Going to production: certificate, activation, licence, production credential, swap in configuration. The code does not change.

Check after signing in

GET /v1/runtime
curl -X GET "https://api.bokapos.rs/v1/runtime" \
  -H "Authorization: Bearer $BOKAPOS_TOKEN"
200 OK
{
  "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 and fiscalEndpointsEnabled: true mean fiscalization is possible for your environment. esirNumber is empty until the Tax Administration assigns the approval number; once assigned, it prints on every receipt.