Skip to content

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
ParameterNotes
company_idUUID
premises_codestring, OznPosPr
isu_statuspending, assigned, mismatch
statusactive, suspended, archived
limit1–200, default 50
cursorFrom next_cursor
all_tenantsPlatform 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.

Terminal window
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
}
FieldNotes
labelYour name for the device. Unique within the company; the match key for CSV import.
isu_numberOznNapUr, digits with no leading zeros. null until ePorezna issues one.
isu_statuspending (cannot fiscalize), assigned, mismatch (rejected upstream — re-check it in ePorezna).
last_seen_atThe last POST /v1/invoices from this device, successful or not.
last_success_atThe 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
FieldTypeRequiredNotes
company_idUUIDyes
premises_codestringyesOznPosPr as registered in ePorezna. Letters and digits, max 20.
premises_addressstringnoFree text for your own dashboards. Never sent to the Tax Administration.
labelstring 1–200yesUnique within the company.
isu_numberdigits, no leading zerosnoOmit until ePorezna issues one.
device_configobjectnoPer-device fiscal defaults. Default {} — see below.
Terminal window
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

StatusCode
400invalid_request — missing label, or an isu_number with leading zeros
404invalid_request — no such company
409invalid_request — the label or the ISU number is already taken

Update a device

PATCH /v1/devices/{id}
FieldNotes
label
premises_addressFree text. premises_code is immutable — see below.
isu_numberA value moves isu_status to assigned; null moves it back to pending.
device_configReplaced wholesale, not merged.
statusactive, 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.

Terminal window
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/import

Creates 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:

PartRequiredNotes
company_idyesEvery row belongs to this company.
fileyesThe CSV. Maximum 1 MB, maximum 5000 data rows.
dry_runnotrue validates and reports without writing anything.

CSV format

UTF-8, comma-separated, with a header row.

ColumnRequiredMeaning
labelyesDevice label. Unique within the company; the match key for updates.
premises_codeyesThe business premises code (OznPosPr) as registered in ePorezna.
isu_numbernoDigits, no leading zeros. Leave blank if ePorezna has not issued one yet.
device_confignoA 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_config
VM-0042,POSL1,42,"{""model"":""K3""}"
VM-0043,POSL1,43,
VM-0044,POSL2,,
Terminal window
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" \
-F "[email protected];type=text/csv"

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 default

so 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.