# Get a signed webhook on every event | Busymate AI

Source: https://busymate.ai/ro/docs/guides/webhooks
Last modified: 2026-09-13T09:04:36+03:00
Busymate AI can call your own system on every event that matters — a conversation starts, a message arrives, a visitor asks for a person, an identity is verified, a tool runs. Each call is a signed HTTPS POST you verify and act on however you like. This guide sets one up end to end.

## 1. Register an endpoint

In [Console → Connections](https://busymate.ai/console/connections), open Webhooks and add an endpoint. Give it a public `https://` address that your server controls, pick the events you want, and save. The platform generates a signing secret and shows it once — copy it now and store it where your server reads its secrets. You will not see it again; if you lose it, rotate the endpoint for a new one.

## 2. Verify every call

Each delivery carries three headers: `X-Busymate-Timestamp` (unix seconds), `X-Busymate-Signature` (`t=<timestamp>,v1=<hex>`), and `X-Busymate-Delivery` (a stable id). Recompute the signature as an HMAC-SHA256 over the exact string `<timestamp>.<raw request body>` using your signing secret, and compare it to the `v1` value in constant time. Reject the call if it does not match, and reject it if the timestamp is more than five minutes from your clock — that window stops an old call being replayed.

## 3. Choose your events

Subscribe only to what you use. The available events are `conversation.started`, `message.received`, `handoff.requested`, `handoff.resolved`, `identity.verified`, and `tool.called`; a subscription of `*` receives all of them. Every payload has the same envelope: the event name, your tenant id, an `occurred_at` timestamp, and a `data` object with the ids for that event. Change the list any time from the same card.

## 4. Send a test event

Use "Send test event" on the endpoint to queue a `webhook.test` delivery. It is signed exactly like a real one, so it proves your verification code before any real traffic depends on it. If you want to inspect the raw call first, the card offers a hosted capture URL that records what it receives so you can read the exact headers and body.

## 5. Retries and the dead-letter state

Delivery is at-least-once: because a call can be retried, the same `X-Busymate-Delivery` id may arrive more than once, so treat that id as an idempotency key and ignore a repeat. A call that does not return a 2xx is retried with growing backoff; after several failed attempts it moves to a dead-letter state you can see in the same card, with the last status and error. Fix your endpoint, then retry a dead-lettered delivery from there.

## Verify

1. Confirm the endpoint shows as saved in Connections with your chosen events.
2. Send a test event and confirm your server receives a `webhook.test` POST.
3. Confirm your code accepts the signature and rejects a tampered body.
4. Confirm a call whose timestamp is older than five minutes is rejected.
5. Point the endpoint at a broken URL, send a test event, and confirm it retries and then shows in the dead-letter state.

<!-- qa:start -->
### Where do I get the signing secret?
It is generated when you create the endpoint and shown once in that same response. Rotate the endpoint to get a new one; the old secret stops working immediately.

### What exactly do I sign to verify a call?
The string `timestamp.body` — the value of `X-Busymate-Timestamp`, a literal dot, then the raw request body — with HMAC-SHA256 under your signing secret. Compare the hex result to the `v1` part of `X-Busymate-Signature`.

### Why did I receive the same event twice?
Delivery is at-least-once, so a retry can repeat an event. Use `X-Busymate-Delivery` as an idempotency key and skip a delivery id you have already handled.

### What happens if my endpoint is down?
The call is retried with exponential backoff. After several failures it is dead-lettered and stops retrying; you can see it, fix your endpoint, and retry it from Connections.

### Can I manage endpoints without the Console?
Yes. The same actions are on the MCP server as `set_webhook_endpoint`, `get_webhook_status`, `list_webhook_deliveries` and related tools, so an agent or script can manage them too.
<!-- qa:end -->
