POST to your endpoint for every meeting, bot and calendar
connection event in a workspace, however it was created. Each event carries the current
resource.
Register an endpoint
Webhook endpoints belong to a workspace. With a key that is an owner or admin of it, register yours withPOST /webhook_endpoints
and choose the events it receives:
secret from the response. It starts with whsec_ and is shown only once;
send your own secret instead to use one you already hold.
An endpoint covers every meeting, bot and calendar connection in its workspace, however
it was created. If you run one workspace per customer, each workspace needs its own
endpoint; the URL and the secret can be the same.
Endpoints must be public HTTPS URLs. Redirects are not followed. An endpoint is pinned to
the API version of the request that created it, or to api_version if you send one, so
its events keep the shape your code was written against.
Event types
Each event has a reference page with the full payload schema, collocated with its
resource’s endpoints in the sidebar.
Event payload
Event metadata sits at the top level; the current resource is underdata.object:
For
meeting.* events, data.object is the meeting as
GET /meetings/{id} returns it; for
calendar_connection.* events, the calendar connection.
For bot.* events, data.object is the bot as
GET /bots/{id} returns it, with the recording choices
that apply to it — including bots sent from a connected calendar or manually from the
product. The bot carries no results: on bot.transcript_ready and bot.summary_ready,
read GET /meetings/{meeting_id}/results. Webhook payloads never
include a MeetingKit editor or share URL.
Verify signatures
Each request carries three headers:
Both digests are lowercase hex HMAC-SHA256, keyed with the endpoint’s full signing
secret,
whsec_ prefix included:
Verification code
Every request carriesX-HappyScribe-Signature: t=<unix_timestamp>,v1=<hex_digest>.
The digest is an HMAC-SHA256 of <timestamp>.<raw request body>, keyed with the full
signing secret, whsec_ prefix included.
Verify before parsing the JSON, on the raw bytes you received, and reject
timestamps older than five minutes:
Retries and ordering
- Acknowledge fast. Return any
2xxwithin 10 seconds. Anything else, or a timeout, is retried with backoff: up to 21 attempts over about 14 hours, with at most an hour between two. - Store, then acknowledge. Write the event somewhere durable before you return
2xx, and process it from there. - Deduplicate on the event
id. Delivery is at least once. A retry has the sameidand a fresh signature timestamp, so return2xxfor anidyou already stored. - Don’t rely on order. Events for one resource usually arrive in order, but not
always. Treat an event as a signal: read the resource again (
GET /meetings/{id},GET /bots/{id}) and save what the read returns. - Keep a fallback. Webhooks are the fast path, not the only one. If a bot or a
meeting you expect to be finished has sent nothing, read it with
GET /bots/{id}orGET /meetings/{id}. - Recover missed events. After an outage, list
GET /webhook_events?delivery_status=failedfrom when it started and process the ones you have not stored, or redeliver one to your endpoint.GET /webhook_events/{id}shows every delivery attempt and what your server answered.
Test locally
MeetingKit can only deliver to public HTTPS URLs. During development, expose your local receiver with a tunnel such asngrok http 8787 or
cloudflared tunnel --url http://localhost:8787, and register the tunnel’s URL.
Then call POST /webhook_endpoints/{id}/test
to check that your receiver answers 2xx and verifies the signature: the response carries
the status code it returned. A test event is a sample: its IDs do not exist, so do not
fetch them. To see real events, run the Quickstart with the endpoint
registered.
A failed bot’s reason values are listed in Failure reasons.
Webhooks don’t change MeetingKit email behavior — meeting-summary emails continue to follow the
existing product and user notification preferences.