Changelog
Additive changes ship continuously; anything breaking gets a new OH-Version and a deprecation notice here first.
Webhook delivery is live
2026-10-12 OH-Version 2026-05-16
OfficeHero now delivers integration webhooks in production. An endpoint receives the events it subscribes to that happen after it was created — signed, retried on the published schedule and replayable. Before announcing it we checked delivery end to end in production: a real delivery passed every verifier on this site, and each of them refused tampered, wrong-secret, stale and future copies.
- Verifier helpers accept any header capitalisation. HTTP header names
are case-insensitive, and servers and proxies change them on the way to
your code: php-fpm’s
getallheaders(), Go and many proxies hand overX-Oh-Signature, and Node lower-cases every name. The PHPohVerifyDualSignlooked only forX-OH-Signatureandx-oh-signature, so it refused genuine deliveries read throughgetallheaders(). The TypeScript and Python…DualSignhelpers had the same two-name lookup. All three now take the request’s whole header map and find both signature headers under any capitalisation. They also accept list values (PSR-7getHeaders()), a header sent twice, and whitespace around a value. - If you copied the PHP helper, copy it again from
Verifying signatures. Do the same for the
TypeScript
…DualSignhelper unless you pass it Node’s lower-casedreq.headers, and for the Python one if you pass it a plaindictinstead of your framework’srequest.headers.ohVerifySignatureand the Go, Ruby, Java and C# verifiers work as before: they take the header value, so read it with your framework’s case-insensitive accessor, as their comments now say. - Every verifier reads the header the same way. The TypeScript
ohVerifySignaturenow returnsfalsefor a missing header instead of throwing, and takes a list of values like the Python one. The Go verifier now refuses atwith a sign and an upper-casev1, and the Python one atwritten in non-ASCII digits, as the others always did. Genuine deliveries pass exactly as before. - A delivered delivery reports no error. In
GET /v1/webhook_endpoints/{id}/deliveries,error_classanderror_detaildescribe the last failed attempt. A delivery that succeeds on a retry (or after a429) now has both set tonull.attemptstill shows how many attempts it took. Deliveries that succeeded before this change keep the values they showed.
Integrations API and developer portal launch
2026-10-10 OH-Version 2026-05-16
The Integrations API is open on https://api.officehero.io with
OH-Version: 2026-05-16, together with this portal.
- Read invoices, payments, bills, purchase orders, work orders, vehicles, fuel logs, employees, leave requests, timesheets, tickets and document metadata. Write invoices: create and update drafts, and void issued invoices. A draft is issued — or discarded — in the Finance app.
- Webhook endpoints can be created and managed through the API, for a catalogue of 112 event types (108 of them sent today), signed with HMAC-SHA256, with delivery history and replay. Delivery has not started yet: an entry here will say when it does.
- 14 scopes you pick per API key in Settings → API keys.
- Every
*_attimestamp is RFC 3339 UTC (2026-09-14T08:30:00Z). - Each webhook delivery attempt is signed when it is sent, so retries pass a 300-second timestamp check.
Known limitations in this version, documented on each resource: lists have
no filters or sort options; employee name, email, department and job title
are always null, and so is a leave request’s reason; a document’s
shared_with is always []; a vehicle’s last_seen_at and a timesheet’s
regular_hours/overtime_hours are always null; a payment’s status is
derived from its direction; invoice lines are not returned; document lists
include deleted and quarantined files; webhook subscriptions to compliance,
e-invoicing, DATEV, tachograph, dashcam and e-signature events need an
int:* key, which the apps do not offer.