Appearance
Webhooks
Get message and call events on your backend as signed POSTs. Optional after you’ve set up session token issuance — use this for CRM, moderation, or offline call ring, not for basic chat.
New here?
Finish Quick start and Issue session tokens first.
What you need
- Public HTTPS URL on your server
- Webhook secret
whsec_…(dashboard / account settings) — not an API key
Events
event | When |
|---|---|
message.created / updated / deleted | Message lifecycle |
call.started / ended / missed | Call lifecycle (call.started → offline ring push) |
Body: { event, roomId, message?, call? }.
Verify every request
Header: X-Webhook-Signature: sha256=<hex>
HMAC-SHA256 of the raw body with whsec_….
js
import { createHmac } from "node:crypto";
const expected =
"sha256=" +
createHmac("sha256", process.env.SENDSAR_WEBHOOK_SECRET)
.update(rawBody)
.digest("hex");
if (expected !== request.headers.get("x-webhook-signature")) {
throw new Error("Invalid webhook signature");
}php
$expected = 'sha256=' . hash_hmac(
'sha256',
$request->getContent(),
config('sendsar.webhook_secret')
);
if (!hash_equals($expected, $request->header('X-Webhook-Signature', ''))) {
abort(401, 'Invalid webhook signature');
}go
mac := hmac.New(sha256.New, []byte(webhookSecret))
mac.Write(rawBody)
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(expected), []byte(r.Header.Get("X-Webhook-Signature"))) {
http.Error(w, "Invalid signature", http.StatusUnauthorized)
}Return 2xx quickly; do heavy work async.
Next
- Push notifications — use
call.startedfor background ring - Issue session tokens — store
SENDSAR_WEBHOOK_SECRETwith your other secrets - API Reference