API reference
Base URL https://api.fiskhub.com/v1. Bearer authentication with an fh_live_… or
fh_test_… key.
Endpoints
| Method | Path | |
|---|---|---|
POST | /v1/invoices | Fiscalize a sale — synchronous, Idempotency-Key required |
GET | /v1/invoices/{id} | Retrieve an invoice |
GET | /v1/invoices | List invoices |
POST | /v1/invoices/{id}/retry | Retry an invoice |
GET POST PATCH | /v1/companies | Companies |
GET POST PATCH | /v1/devices | Devices |
POST | /v1/devices/import | Bulk CSV import |
POST | /v1/certificates | Upload a certificate — multipart, write-only |
GET | /v1/certificates | List certificate metadata — never key material |
GET | /v1/countries/{code}/schemas | Country schemas |
GET | /v1/health | Service health |
GET | /v1/health/fiscal | Tax 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_9tK2xQ7mA4vD8nR1sB6yE3wZ0pL5cHThe 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 | |
|---|---|
Authorization | Required except on GET /v1/health, GET /v1/health/fiscal and GET /v1/countries/{code}/schemas. |
Idempotency-Key | Required on POST /v1/invoices, optional elsewhere. |
X-Request-Id | Your correlation id. Echoed back and attached to our logs. |
| Response | |
|---|---|
X-Request-Id | Yours if you sent one, otherwise generated. |
RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset | See rate limits. |
Retry-After | On 429. |
Idempotent-Replayed | true 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.