सामग्री पर जाएँ
Busymate AI

यह गाइड फिलहाल अंग्रेजी में है।

गाइड

हर घटना पर हस्ताक्षरित webhook पाइए

एक एंडपॉइंट रजिस्टर करिए, हर कॉल पर हस्ताक्षर और समय की पुष्टि करिए, अपनी घटनाओं को चुनिए, और रिट्राई और डेड-लेटर स्थिति को संभालिए।

इस पेज पर

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 → Webhooks, 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 — never ===, which leaks timing information a byte at a 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.

javascript
import { createHmac, timingSafeEqual } from "node:crypto";

// req.rawBody must be the EXACT bytes received — a body a framework has
// already JSON.parse'd and re-stringified will not reproduce the same hash.
function verify(req, signingSecret) {
  const timestamp = req.headers["x-busymate-timestamp"];
  const header = req.headers["x-busymate-signature"]; // "t=<ts>,v1=<hex>"
  if (!timestamp || !header) return false;

  const ageSeconds = Math.abs(Date.now() / 1000 - Number(timestamp));
  if (!Number.isFinite(ageSeconds) || ageSeconds > 300) return false; // stop a replayed call

  const given = header.split(",").find((p) => p.startsWith("v1="))?.slice(3);
  if (!given) return false;

  const expected = createHmac("sha256", signingSecret)
    .update(`${timestamp}.${req.rawBody}`, "utf8")
    .digest("hex");

  const a = Buffer.from(given, "hex");
  const b = Buffer.from(expected, "hex");
  return a.length === b.length && timingSafeEqual(a, b);
}
python
import hashlib
import hmac
import time

def verify(headers, raw_body: bytes, signing_secret: str) -> bool:
    timestamp = headers.get("x-busymate-timestamp")
    header = headers.get("x-busymate-signature")  # "t=<ts>,v1=<hex>"
    if not timestamp or not header:
        return False

    if abs(time.time() - float(timestamp)) > 300:
        return False  # stop a replayed call

    given = next((p[3:] for p in header.split(",") if p.startswith("v1=")), None)
    if not given:
        return False

    message = f"{timestamp}.".encode() + raw_body
    expected = hmac.new(signing_secret.encode(), message, hashlib.sha256).hexdigest()
    return hmac.compare_digest(given, expected)

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 workspace id, an occurred_at timestamp, and a data object with the ids for that event — a real handoff.requested delivery:

json
{
  "event": "handoff.requested",
  "tenant_id": "3d9d9a3e-2a35-4d3c-8a2e-2a6b7c9c2f10",
  "occurred_at": "2026-09-18T14:02:31.045Z",
  "data": {
    "handoff_id": "8f5e2b7e-9a3e-4b13-9f21-6b0a2f7d5c44",
    "session_id": "b7e2a3c1-4f6d-4a2e-9c3b-1d2e3f4a5b6c",
    "requested_by": "visitor"
  }
}

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. Handle retries and dead letters

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 the last attempt 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.

AttemptDelay since previousElapsed
1 (first send)—0m
21m1m
32m3m
44m7m
58m15m
616m31m
732m63m
8 (last)64m127m
dead-letterafter attempt 8 fails—

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.

सवाल

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.