Skip to content

API reference

Base URL https://api.fiskhub.com/v1. Bearer authentication with an fh_live_… or fh_test_… key.

Endpoints

MethodPath
POST/v1/invoicesFiscalize a sale — synchronous, Idempotency-Key required
GET/v1/invoices/{id}Retrieve an invoice
GET/v1/invoicesList invoices
POST/v1/invoices/{id}/retryRetry an invoice
GET POST PATCH/v1/companiesCompanies
GET POST PATCH/v1/devicesDevices
POST/v1/devices/importBulk CSV import
POST/v1/certificatesUpload a certificate — multipart, write-only
GET/v1/certificatesList certificate metadata — never key material
GET/v1/countries/{code}/schemasCountry schemas
GET/v1/healthService health
GET/v1/health/fiscalTax Administration reachability

That is the whole API. There are no webhooks and no batch endpoint — the synchronous flow removed the need for both.

The machine-readable version is the OpenAPI 3.1 specification.

Conventions

Authentication

Authorization: Bearer fh_live_9tK2xQ7mA4vD8nR1sB6yE3wZ0pL5cH

The prefix selects the mode. GET /v1/health, GET /v1/health/fiscal and GET /v1/countries/{code}/schemas need no key. See getting started.

Money

Always a string with exactly two decimals and a dot separator: "4.50". Never a JSON number — see getting started.

Time

ISO 8601 with an explicit offset: "2026-08-27T10:32:11+02:00". Responses are rendered in the same form. occurred_at is the sale moment, not the request moment.

Idempotency

Idempotency-Key is required on POST /v1/invoices, and accepted on every other POST. Identical body replays; different body is a 409. See idempotency.

Pagination

List endpoints return:

{
"object": "list",
"data": [],
"has_more": true,
"next_cursor": "Y3Vyc29yOjIwMjYtMDgtMjdUMTA6NDE6MDcrMDI6MDA"
}

Pass next_cursor back as cursor for the next page. limit defaults to 50, maximum 200. Cursors are opaque; never construct one.

Errors

Every 4xx and 5xx has the same body, and code is stable forever:

{
"error": {
"type": "validation_error",
"code": "hr.device_missing_isu",
"message": "Device VM-0043 has no ISU number assigned. Register the premises in ePorezna and add the ISU number before fiscalizing.",
"param": "device_id",
"upstream": null,
"doc_url": "https://docs.fiskhub.com/errors/hr.device_missing_isu"
}
}

See the error taxonomy for every code.

Headers

Request
AuthorizationRequired except on GET /v1/health, GET /v1/health/fiscal and GET /v1/countries/{code}/schemas.
Idempotency-KeyRequired on POST /v1/invoices, optional elsewhere.
X-Request-IdYour correlation id. Echoed back and attached to our logs.
Response
X-Request-IdYours if you sent one, otherwise generated.
RateLimit-Limit, RateLimit-Remaining, RateLimit-ResetSee rate limits.
Retry-AfterOn 429.
Idempotent-Replayedtrue when the response came from the idempotency store.

Rate limits

20,000 requests per minute per principal and per IP, on every endpoint including POST /v1/invoices. Sign-in is held much tighter at 30 per 15 minutes per IP. See rate limits.

Versioning

/v1 never breaks; changes are additive only. See versioning.