Docs menu

Envelope and headers

Every event arrives in the same envelope; only type and data change.

Envelope

{
  "id": "evt_0199c3a4-adbe-7fc0-8b2c-475869708b30",
  "type": "fin.invoice.paid",
  "occurred_at": "2026-10-02T09:14:00Z",
  "tenant": {
    "id": "0199c39f-1a2b-7c3d-8e4f-5a6b7c8d9e01",
    "slug": "northwind-transport"
  },
  "schema_version": "2026-05-16",
  "data": {
    "id": "0199c3a2-4b7e-7f30-9c2e-6a8d4f1b2c01",
    "number": "INV-2026-00418",
    "status": "paid",
    "currency": "EUR",
    "total_minor": 147500,
    "paid_minor": 147500,
    "balance_minor": 0
  },
  "metadata": {
    "request_id": null,
    "actor": { "type": "user", "id": "0199c38a-2536-7748-83a4-cfd0e1f20322" }
  }
}

(data is shortened here; each event’s full payload is in the event catalogue.)

data is the record as OfficeHero published it, with every *_at value in RFC 3339 UTC. Fields that only mean something inside OfficeHero are never sent: the company’s database schema name (identify the company by the envelope’s tenant.id), storage keys, keyed hashes (such as nino_hmac) and raw provider callback bodies.

FieldMeaning
idThe event id: evt_ + UUID. The same event keeps its id across retries and replays — deduplicate on it.
typeThe event type, e.g. fin.invoice.paid.
occurred_atWhen it happened, RFC 3339 UTC.
tenant.id, tenant.slugThe company the event belongs to: join on id, show slug. There are no other tenant fields.
schema_versionThe payload version, 2026-05-16.
dataThe event payload. Its shape depends on type.
metadata.request_idFor a write made through the Integrations API, the x-trace-id that request was answered with. Usually null otherwise.
metadata.actorWho caused it: {type, id}. api_key and the key’s id for a write made through the Integrations API — use it to recognise your own writes; user and a user id for a change made in the apps; system and null for automatic changes.

Headers

HeaderValue
Content-Typeapplication/json
User-AgentOfficeHero-Webhooks/1.0
X-OH-Signaturet=<unix seconds>,v1=<hex> — see Verifying signatures
X-OH-Signature-AlgorithmHMAC-SHA256-RAW
X-OH-Signature-LegacyThe pre-2026 signature, for receivers built before it changed. Sent until the date below.
X-OH-Signature-Deprecation-Date2026-12-17 — when X-OH-Signature-Legacy stops
OH-Event-IdSame as the envelope id
OH-Event-TypeSame as the envelope type
OH-Event-Attempt1 for the first attempt, then 2, 3, …
OH-Endpoint-Idwhe_ + your endpoint id
OH-VersionYour endpoint’s pinned_version
Idempotency-KeySame as OH-Event-Id

Header names are case-insensitive. Proxies and servers often change their capitalisation on the way to your code — X-Oh-Signature, x-oh-signature, Oh-Version — so look them up with your framework’s header accessor, not as exact keys of a map.

Deliveries are never redirected: a 3xx answer counts as a failure.