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.