Devices
A device is one self-service machine. It carries the ISU number (OznNapUr) that identifies it
to the Tax Administration, and device_id is what POST /v1/invoices takes.
List devices
GET /v1/devices| Parameter | Notes |
|---|---|
company_id | UUID |
premises_code | string, OznPosPr |
isu_status | pending, assigned, mismatch |
status | active, suspended, archived |
limit | 1–200, default 50 |
cursor | From next_cursor |
all_tenants | Platform operators only, session-authenticated. Ignored for everyone else. |
Filtering by isu_status=pending lists every device that cannot yet fiscalize — a useful check
before a new site goes live.
all_tenants=true lets a FiskHub platform operator list devices across every tenant, under the
same rules as GET /v1/companies?all_tenants=true:
session principals only, never an API key, read-only, is_platform_admin required, and audited.
Tenant users are unaffected — with or without the parameter they see only their own tenant’s
devices.
curl -sS -G https://api.fiskhub.com/v1/devices \ -H "Authorization: Bearer $FISKHUB_API_KEY" \ --data-urlencode "isu_status=pending"{ "object": "list", "data": [ { "id": "6f1c0f9e-2b7a-4a56-9d3e-1f0b8a4c7d21", "company_id": "3a5f2b18-7c4d-4e91-9a2b-6d8e0f1c3a57", "premises_code": "POSL1", "premises_address": "Ilica 1, 10000 Zagreb", "label": "VM-0042", "isu_number": "42", "isu_status": "assigned", "device_config": { "special_purpose": "Parking bay 3" }, "status": "active", "installed_at": "2026-06-20T11:00:00+02:00", "last_seen_at": "2026-08-27T10:41:07+02:00", "last_success_at": "2026-08-27T10:32:13+02:00", "created_at": "2026-06-20T10:55:41+02:00" } ], "has_more": false, "next_cursor": null}| Field | Notes |
|---|---|
label | Your name for the device. Unique within the company; the match key for CSV import. |
isu_number | OznNapUr, digits with no leading zeros. null until ePorezna issues one. |
isu_status | pending (cannot fiscalize), assigned, mismatch (rejected upstream — re-check it in ePorezna). |
last_seen_at | The last POST /v1/invoices from this device, successful or not. |
last_success_at | The last sale from it confirmed with a JIR. |
A device whose last_seen_at is recent but whose last_success_at is not is one worth looking
at — it is selling but not being confirmed.
Create a device
POST /v1/devices| Field | Type | Required | Notes |
|---|---|---|---|
company_id | UUID | yes | |
premises_code | string | yes | OznPosPr as registered in ePorezna. Letters and digits, max 20. |
premises_address | string | no | Free text for your own dashboards. Never sent to the Tax Administration. |
label | string 1–200 | yes | Unique within the company. |
isu_number | digits, no leading zeros | no | Omit until ePorezna issues one. |
device_config | object | no | Per-device fiscal defaults. Default {} — see below. |
curl -sS https://api.fiskhub.com/v1/devices \ -H "Authorization: Bearer $FISKHUB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "company_id": "3a5f2b18-7c4d-4e91-9a2b-6d8e0f1c3a57", "premises_code": "POSL1", "premises_address": "Ilica 1, 10000 Zagreb", "label": "VM-0042", "isu_number": "42", "device_config": { "special_purpose": "Parking bay 3" } }'Returns 201. Without isu_number the device is created with isu_status: "pending", which is
a legitimate state to provision into — it just cannot fiscalize yet.
Errors
| Status | Code |
|---|---|
400 | invalid_request — missing label, or an isu_number with leading zeros |
404 | invalid_request — no such company |
409 | invalid_request — the label or the ISU number is already taken |
Update a device
PATCH /v1/devices/{id}| Field | Notes |
|---|---|
label | |
premises_address | Free text. premises_code is immutable — see below. |
isu_number | A value moves isu_status to assigned; null moves it back to pending. |
device_config | Replaced wholesale, not merged. |
status | active, suspended, archived. |
The usual reason to call this is attaching an ISU number once ePorezna has issued it. The device can fiscalize from the next request onwards.
curl -sS -X PATCH \ "https://api.fiskhub.com/v1/devices/b74a1c33-8e2f-4d05-91a6-3c7b5e0d2f18" \ -H "Authorization: Bearer $FISKHUB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "isu_number": "43" }'company_id cannot be changed — a device belongs to the fiscal identity that signs for it.
premises_code cannot be changed. It is OznPosPr, so it is part of the business key and the
ZKI of every future receipt, and it is the key receipt numbering runs on — changing it would
leave a gap in one sequence and a collision risk in another. Archive the device and register a
new one at the new premises. Past invoices keep the premises they were fiscalized
under.
Bulk import from CSV
POST /v1/devices/importCreates devices, or attaches ISU numbers to devices that already exist. This is the practical way to apply a batch of ISU numbers after registering several premises in ePorezna.
multipart/form-data:
| Part | Required | Notes |
|---|---|---|
company_id | yes | Every row belongs to this company. |
file | yes | The CSV. Maximum 1 MB, maximum 5000 data rows. |
dry_run | no | true validates and reports without writing anything. |
CSV format
UTF-8, comma-separated, with a header row.
| Column | Required | Meaning |
|---|---|---|
label | yes | Device label. Unique within the company; the match key for updates. |
premises_code | yes | The business premises code (OznPosPr) as registered in ePorezna. |
isu_number | no | Digits, no leading zeros. Leave blank if ePorezna has not issued one yet. |
device_config | no | A JSON object as a single quoted field. Merged into the existing config. |
Unknown columns are ignored, so an export enriched with extra fields still imports.
label,premises_code,isu_number,device_configVM-0042,POSL1,42,"{""model"":""K3""}"VM-0043,POSL1,43,VM-0044,POSL2,,curl -sS -X POST https://api.fiskhub.com/v1/devices/import \ -H "Authorization: Bearer $FISKHUB_API_KEY" \ -F "company_id=3a5f2b18-7c4d-4e91-9a2b-6d8e0f1c3a57" \ -F "dry_run=true" \Behaviour
Each row is matched on (company_id, label): an existing device is updated, a new label creates
one. Rows are processed independently and valid rows are applied even when others fail.
Re-uploading a corrected file is safe: applying the same row twice produces the same device.
{ "object": "device_import", "dry_run": false, "processed": 4, "created": 2, "updated": 1, "failed": 1, "errors": [ { "row": 4, "label": "VM-0045", "code": "invalid_request", "message": "Premises code \"POSL 9\" is not valid — OznPosPr allows only 0-9, a-z and A-Z.", "param": "premises_code" } ]}row counts the header as line 1, so it matches what a text editor shows.
A 400 means the file could not be parsed at all — wrong encoding, missing required header
column, more than 5000 rows. A 413 means it exceeds 1 MB.
device_config — per-device fiscal defaults
device_config is not asset data. It is the middle level of the resolution chain a sale walks
when a field is absent from the request:
request field → devices.device_config → companies.fiscal_config → spec defaultso a key set here becomes the default for every sale that device files, and a sale can still override it. Only these keys are read — anything else is stored and ignored:
sale_type, sequence_mark, register_mark, operator_oib, recipient_oib,
paragon_number, special_purpose, payment_method, late_delivery, vat_registered,
vat, consumption_tax, other_taxes, fees, vat_exempt_amount, margin_amount,
non_taxable_amount
The spellings are the request’s own, so a value typed here behaves exactly as it would on the
invoice. A null means explicitly none and masks the level below it, rather than falling
through to the company’s default.