Realtime

Webhooks

Receive signed events, inspect delivery attempts, replay failed deliveries, and requeue dead-lettered events.

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.

Node verificationjavascript
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.json` and 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`.