Companies
A company is the fiscal identity. The OIB, the VAT registration status, the signing certificate and the mode all live here, never on the tenant.
That is forced by the regulation rather than chosen: the Tax Administration rejects any message
whose payload OIB differs from the signing certificate’s OIB (s005). Each company has its own
OIB, so each company needs its own certificate. A tenant with several companies is routine; a
tenant with one is just the common case.
List companies
GET /v1/companies| Parameter | Notes |
|---|---|
status | active, suspended, archived |
limit | 1–200, default 50 |
cursor | From next_cursor |
all_tenants | Platform operators only, session-authenticated. Ignored for everyone else. See cross-tenant listing. |
curl -sS https://api.fiskhub.com/v1/companies \ -H "Authorization: Bearer $FISKHUB_API_KEY"{ "object": "list", "data": [ { "id": "3a5f2b18-7c4d-4e91-9a2b-6d8e0f1c3a57", "name": "AWAIT 8 J.D.O.O.", "oib": "25089460814", "vat_registered": true, "address": { "street": "Ilica 1", "city": "Zagreb", "postal_code": "10000", "country": "HR" }, "fiscal_config": { "sequence_mode": "P" }, "mode": "live", "status": "active", "certificate_status": "valid", "certificate_expires_at": "2028-09-22T12:00:00+02:00", "created_at": "2026-06-14T08:20:11+02:00" } ], "has_more": false, "next_cursor": null}| Field | Notes |
|---|---|
oib | 11 digits with an ISO 7064 MOD 11,10 check digit. |
vat_registered | USustPdv. |
fiscal_config | Country-specific defaults — sequence mode, tax defaults, endpoint override. |
mode | test or live. Decides which Tax Administration endpoint is used. |
certificate_status | missing, valid, expiring (under 60 days), expired. |
certificate_expires_at | When the whole fleet stops being able to fiscalize. |
Cross-tenant listing
GET /v1/companies?all_tenants=trueFiskHub platform operators — support and operations staff, not customers — can list companies
across every tenant. The same parameter works on
GET /v1/devices, and nowhere else.
If you are integrating against FiskHub, this section does not apply to you. Nothing about a tenant’s access has changed: a tenant user, with or without this parameter, sees exactly and only their own tenant’s companies. There is no way to opt in, and no way to be opted in by someone else.
The constraints are worth stating plainly, because they are the point of the design:
| Constraint | |
|---|---|
| Session only | The caller must be an authenticated dashboard session. An API key is never eligible, whatever it is scoped to. A machine credential that could enumerate every customer is a far larger blast radius than a human session. |
| Platform admin only | The user must hold is_platform_admin. This is not a tenant role — no tenant owner or admin has it, and no tenant can grant it. |
| Read only | Listing, and only these two collections. There is no cross-tenant write path anywhere, and no cross-tenant read of invoices, certificates or users. |
| Opt in per request | Omitting the parameter gives a platform admin the ordinary tenant-scoped list. Widening every list an operator opens would make it easy to act on the wrong customer’s data by accident. |
| Audited | Every cross-tenant read writes an audit_log entry against the operator who made it. |
Anyone else sending all_tenants=true gets the ordinary tenant-scoped list. The parameter is
ignored, not rejected — there is no error to probe for, and no difference in response shape
that would reveal whether the capability exists. The underlying database functions re-check the
capability themselves and return zero rows if it is absent, so a route that forgot to check
would leak nothing.
The rows are the same Company objects as the tenant-scoped listing, with no added tenant field.
Pagination works the same way.
Create a company
POST /v1/companies| Field | Type | Required | Notes |
|---|---|---|---|
name | string 1–200 | yes | |
oib | 11 digits | yes | Checksum-validated before anything is stored. Must match the certificate you will upload. |
vat_registered | boolean | no | Default true. |
address | object | no | Default {}. |
fiscal_config | object | no | Default {}. |
mode | test | live | no | Default test. |
curl -sS https://api.fiskhub.com/v1/companies \ -H "Authorization: Bearer $FISKHUB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "AWAIT 8 J.D.O.O.", "oib": "25089460814", "vat_registered": true, "address": { "street": "Ilica 1", "city": "Zagreb", "postal_code": "10000", "country": "HR" }, "mode": "test" }'Returns 201 with the company, certificate_status: "missing".
A new company cannot fiscalize yet. It needs a certificate whose subject OIB equals this one and a device with an assigned ISU number.
Errors
| Status | Code |
|---|---|
400 | hr.invalid_oib — the checksum failed |
400 | invalid_request — name missing or too long |
409 | invalid_request — a company with this OIB already exists |
Update a company
PATCH /v1/companies/{id}Only the fields present in the body change.
| Field | Notes |
|---|---|
name | |
vat_registered | |
address, fiscal_config | Replaced wholesale, not merged. |
mode | Switching to live requires a valid certificate. |
status | active, suspended, archived. |
curl -sS -X PATCH \ "https://api.fiskhub.com/v1/companies/3a5f2b18-7c4d-4e91-9a2b-6d8e0f1c3a57" \ -H "Authorization: Bearer $FISKHUB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "mode": "live" }'Switching to live without a valid certificate returns
company_missing_certificate.