Data conventions
The same rules hold for every resource and every webhook.
Field names
Fields are snake_case. Unknown fields may be added to a response at any time
without a new version — ignore fields you do not recognise. Removing or
renaming a field needs a new version.
Exception: the data of four webhook events uses camelCase keys —
fin.datev.export.completed (exportRunId, rowCount, …),
compliance.uk_mtd.itsa.penalty_received,
compliance.uk_mtd.itsa.submission_accepted and
compliance.ai_act.decision_chain.integrity_violation. They are sent exactly
as the event catalogue shows them; match them
exactly.
Ids
Ids are UUID strings, e.g. 0199c3a2-4b7e-7f30-9c2e-6a8d4f1b2c01. Treat them
as opaque. Webhook events are the exception: the envelope id is evt_
followed by a UUID.
Money
Amounts are integers in the currency’s minor unit, in fields ending in
_minor, next to an ISO 4217 currency:
{ "total_minor": 147500, "currency": "EUR" }
is €1,475.00. Divide by 10 to the power of the currency’s decimals (2 for EUR, MKD and most others; 0 for JPY).
Dates and timestamps
| Kind | Fields | Format | Example |
|---|---|---|---|
| Point in time | names ending in _at | RFC 3339, UTC, whole seconds | 2026-09-14T08:30:00Z |
| Calendar date | names ending in _date, plus period_start, period_end, start_date, end_date, hire_date | YYYY-MM-DD | 2026-09-14 |
A few _at fields are recorded by OfficeHero as a date only — a work order’s
scheduled_at, a payment’s received_at and a purchase order’s
expected_at. They are sent as midnight UTC of that date.
The *_at rule holds for webhook data too, including the camelCase
detectedAt of compliance.ai_act.decision_chain.integrity_violation. A few
event fields hold a point in time under another name and are not normalised:
the tachograph fields activity_start, activity_end, window_start and
window_end are sent as stored (e.g. 2026-09-14 08:30:00+00), and
since_iso / until_iso as the request carried them. The catalogue says so
on each.
Nulls
A field that has no value is present with null — fields are not left out. A
handful of fields are always null in this version because the data is not
exposed yet; the reference says so on each one.
Personal data the REST API withholds
Some personal data is never returned by a GET, because the same data over
webhooks needs an explicit personal-data permission: an employee’s name and
e-mail address, a leave request’s free-text reason, and the recipients of a
shared document (shared_with). They are null (or []).
The tenant
Every response is for the company the API key belongs to. Most resources carry
that company’s id as tenant_id; invoices do not.
Text and encoding
Requests and responses are UTF-8 JSON. Send Content-Type: application/json
on requests with a body. The language of the human-readable detail in an
error follows your Accept-Language header; data is never translated.