Croatia Fiscalization Guide
What is Croatian fiscalization?
Croatia operates Fiskalizacija, run by Porezna uprava (PU — Croatian Tax Administration) through the CIS (Centralni Informacijski Sustav — Central Information System). Cash invoices must be confirmed by CIS at the moment of issuance; CIS responds with a unique invoice identifier (JIR) which must appear on the receipt alongside the locally-computed protective code (ZKI).
In plain English: Like Slovenia, Croatia is a synchronous "approve-each-sale" regime. The cashier doesn't notice — Zyntem completes the round-trip in well under a second.
Zyntem manages the FINA-issued application certificate, computes the ZKI, signs the SOAP envelope with XMLDSIG, talks to CIS, parses the response, and prints both the ZKI and the JIR on your receipt.
How it works
Croatia's flow is synchronous and online, with a 48-hour grace period if CIS is unreachable:
- Your POS creates a transaction via
POST /v1/transactions. - Zyntem computes the ZKI (Zaštitni kod izdavatelja — Issuer Protection Code), an MD5 hash of taxpayer + receipt-number + timestamp + total, signed with the FINA cert.
- Zyntem submits the SOAP
RacunZahtjevrequest to CIS over TLS (cis.porezna-uprava.hr:8449). - CIS responds with the JIR (Jedinstveni identifikator računa — Unique Invoice Identifier).
- The transaction returns with
fiscal_id= ZKI andfiscal_id_upstream= JIR.
Submission window: Synchronous. If CIS is unreachable, Croatia allows 48 hours to retry — Zyntem queues with the ZKI on the receipt and the JIR is filled in once CIS accepts.
Fiskalizacija 2.0: Set use_v2: true to enable the new namespace (f95), RSA-SHA256 ZastKodv2, and tip support. Default false keeps v1.x semantics. Coordinate with PU before flipping for a live merchant.
Country config fields
The country_config object for Croatian locations:
| Field | Type | Required | Description |
|---|---|---|---|
oib | string | Yes | 11-digit Croatian taxpayer ID (no HR prefix). |
signing_key_id | string | Yes | KMS reference for the FINA-issued PFX. |
poslovni_prostor | string (≤20) | Yes | OznPosPr — pre-registered business premise mark. |
naplatni_uredjaj | string (≤20) | Yes | OznNapUr — cash register / device mark within the premise. |
ozn_slijed | string | Yes | P = numbering scoped to premise, N = scoped to (premise, device). |
u_sust_pdv | boolean | Yes | True if the merchant is registered in the VAT system (USustPdv). |
operator_oib | string | Yes | Default cashier OIB written to OibOper. |
default_nacin_plac | string | Yes | Default payment method: G cash, K card, C cheque, T transfer, O other. |
use_v2 | boolean | No | Enable Fiskalizacija 2.0 (default false). |
Premise pre-registration. Each new
poslovni_prostormust be pre-registered with PU via aPoslovniProstorrequest before any invoices can be issued from it. Zyntem performs this registration automatically when you create the location.
Configuration example
curl -X POST https://api.zyntem.dev/v1/locations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer zyn_test_abc123def456..." \
-d '{
"name": "Zagreb Store",
"country": "HR",
"address": "Ilica 1, 10000 Zagreb",
"country_config": {
"oib": "11111111119",
"signing_key_id": "kms://hr/fina-cert",
"poslovni_prostor": "POSL1",
"naplatni_uredjaj": "1",
"ozn_slijed": "N",
"u_sust_pdv": true,
"operator_oib": "11111111119",
"default_nacin_plac": "G"
}
}'
Creating a transaction
Example: A EUR 24.00 sale at a Zagreb store, paid by card.
curl -X POST https://api.zyntem.dev/v1/transactions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer zyn_test_abc123def456..." \
-d '{
"location_id": "loc_abc123",
"type": "sale",
"amount": 2400,
"currency": "EUR",
"payment_method": "card",
"line_items": [
{
"description": "T-shirt",
"quantity": 1,
"unit_price": 2400,
"vat_rate": 2500
}
]
}'
Response
{
"id": "txn_abc123",
"status": "success",
"fiscal_id": "a3b2c1...32hex",
"fiscal_id_upstream": "12345678-90AB-CDEF-1234-567890ABCDEF",
"country": "HR",
"created_at": "2026-03-15T14:30:22Z"
}
Both ZKI (fiscal_id) and JIR (fiscal_id_upstream) are required on the printed receipt under Croatian law.
Receipt numbering
Croatia uses a composite receipt number: <sequence>/<premise>/<device> (e.g. 42/POSL1/1). The counter restarts at 1 each calendar year. Zyntem manages the counter automatically; you never assign receipt numbers.
Sandbox access
CIS demo runs at cistest.apis-it.hr:8449. Sandbox routing is automatic with a test API key. Sandbox FINA certificates are obtained from demo.e-porezna.hr — typical onboarding is 1–2 weeks.
Error handling
When CIS rejects an invoice, error.category distinguishes:
transient— network blip or CIS 5xx. Zyntem retries within the 48-hour window.regulatory_reject— CIS business-validation error (error.authority_codecarries thes00xSOAP fault code).duplicate_as_success— CIS responded with a JIR collision (re-submission of an already-accepted invoice). Treated as success.
See the Error handling guide for the full taxonomy.