LevelChat delivers events as outbound HTTPS POSTs. Receivers must be idempotent — we deliver
at-least-once and retry on backoff: 0s, 30s, 1m, 5m, 15m, 1h, 6h, 24h then dead-letter.
Register an endpoint
~
curl -X POST $LC_API_URL/v1/webhooks \
-H "Authorization: Bearer lc_pk_xxx.yyy" \
-d '{
"url": "https://your-app.example/lc-events",
"events": ["room.ended","recording.ready","qos.alert"]
}'The response includes a one-time-readable secret you'll use to verify the HMAC signature.
Verify a delivery
TypeScript
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verify(req: Request, secret: string): boolean {
const sig = req.headers.get('x-levelchat-signature'); // "sha256=..."
const ts = req.headers.get('x-levelchat-timestamp');
if (!sig || !ts) return false;
const expected = createHmac('sha256', secret).update(`${ts}.${req.body}`).digest('hex');
const got = sig.replace(/^sha256=/, '');
return timingSafeEqual(Buffer.from(expected), Buffer.from(got));
}Reject anything older than 5 minutes — replay protection is your responsibility.
Event catalog
The full list lives in the API reference. The high-traffic ones:
| Event | When | Use it for |
|---|---|---|
room.ended | Last participant left or host ended | Billing rollups, ticket close |
recording.ready | Compression + HLS done | Email notification, CDN mirror |
participant.left | Per-participant disconnect | Attendance, session reconciliation |
qos.alert | Loss storm / low bitrate / high RTT | Pager, customer support tooling |
license.revoked | On-prem license invalidated | Force-stop on tenants you've offboarded |
Headers
text
X-LevelChat-Webhook-Id: wh_01HF...
X-LevelChat-Event: room.ended
X-LevelChat-Delivery: d_01HF...
X-LevelChat-Timestamp: 1735000000000
X-LevelChat-Signature: sha256=...Dedupe on X-LevelChat-Webhook-Id. The same event can be delivered more than once if your
endpoint fails a previous attempt.