Horato emits domain events after account sync, API writes, approvals, booking lifecycle changes, and operational jobs.
Signature verification
Each delivery is a POST with the JSON event as the body and two headers: horato-event (the event type) and horato-signature in the form t=<timestamp>,v1=<signature>. The signature is HMAC-SHA256(secret, "<timestamp>.<raw_body>"), hex-encoded, using the signing secret returned once when you create the webhook.
Verify over the raw request body before parsing JSON, compare signatures in constant time, and reject timestamps older than a few minutes to reduce replay risk. The legacy x-okcal-event / x-okcal-signature header names are still sent as aliases for consumers that verified against the pre-rebrand names.
import crypto from "node:crypto";
function verifyHoratoWebhook(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const expected = crypto
.createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
return ok && fresh;
}
verifyHoratoWebhook(rawBody, req.headers["horato-signature"], process.env.HORATO_WEBHOOK_SECRET);Event catalog
Subscribe a webhook to specific event types, or omit the filter to receive all of them. Events are namespaced by domain.
- Connections:
connection.reauth_required. - Email:
email.received,email.sent,email.draft.created,email.draft.updated. - Scheduling:
scheduling.booking.created,scheduling.booking.rescheduled,scheduling.booking.cancelled. - Recording:
recording.bot.started,recording.meeting.status_change,recording.transcript.updated,recording.recording.completed. - The complete, current list is in
/docs/openapi.jsonand the events column of the API reference.
Delivery repair
Horato retries failed deliveries with exponential backoff and moves exhausted events to a dead-letter queue. Use the delivery inspector when a receiver returns a non-2xx status: fix the receiver, replay the delivery, then clear dead-letter queues intentionally.
- List deliveries with
/v1/webhooks/deliveries. - Replay one delivery with
/v1/webhooks/deliveries/{delivery_id}/replay. - Requeue dead-lettered events with
/v1/webhooks/dead-letter/{event_id}/requeue.