A webhook is a URL on your backend that you register with Livqeno. When an event happens, Livqeno sends it there as a signed HTTP POST.
Webhooks are the last step in the overall flow. They close the loop back to your backend:
Project → API key → backend mints a token → app joins → webhooks tell your backend what happened.
Why it's useful
Your backend learns about events right away. No polling, and no need for a browser tab to be open.
Example uses:
- Save every chat message into your own database (
message.created). - Send a push notification to a member who is offline.
- Mark a webinar as finished in your app when the stream ends.
Lifecycle of one delivery
1. alice sends a message → it's saved and delivered to connected apps first
2. Livqeno POSTs the event → to your webhook URL, signed
3. your backend checks the signature, replies 200 within 5 seconds
4. no 200? Livqeno retries → after 10s, 20s, 40s, 80s, 160s, 320s
5. still failing? → the delivery is marked failed
One environment per endpoint
Each endpoint belongs to one environment. A staging endpoint never gets production events. Livqeno checks this before sending. So register one endpoint per environment you use.
What a delivery looks like
{
"id": "evt_GSyoZrH7qF3tZms0QsW4Gw",
"type": "message.created",
"projectId": "3e48ccb1-...",
"environment": "PRODUCTION",
"createdAt": "2026-09-08T12:00:00.000Z",
"data": { "message": { "id": "msg_3xR…", "roomId": "conv_9WcQ…", "senderId": "alice", "text": "Hello" } }
}It comes with three headers: Swalvo-Signature, Livqeno-Event-Id, and Livqeno-Event-Type.
The same values are also sent as Raven-Signature, Raven-Event-Id and
Raven-Event-Type (the names used before the platform was renamed Livqeno),
so older receivers keep working.
Always check the signature
The signature proves the request came from Livqeno and wasn't changed:
Swalvo-Signaturelooks liket=<unix>,v1=<hmac-sha256>.- It's signed over
"<timestamp>.<raw body>"with your webhook secret. - The timestamp is part of what's signed, so an old delivery can't be replayed with a new timestamp.
See Webhooks for a ready-made verifier.
Delivery happens in the background
A message is saved and sent to connected apps first. The webhook is sent after. A slow endpoint never slows down your users.
Retries: after a failure, Livqeno retries after 10s, 20s, 40s, 80s, 160s, and 320s. Then the delivery is marked failed.
Auto-disable: an endpoint that fails 50 deliveries in a row is turned off.
Expect duplicates and out-of-order events
- A delivery can succeed but its response can get lost, so it's sent again.
Remove duplicates using
Livqeno-Event-Id. It's the same on every retry. (This is called being idempotent: handling the same event twice has the same result as handling it once.) - Retries can make an older event arrive after a newer one. Sort by
createdAt, not by arrival time.
Example
On your backend (TypeScript with Express), check the signature, reply fast, and do the real work later:
app.post('/hooks/livqeno', express.raw({ type: 'application/json' }), (req, res) => {
if (!verify(req.body.toString('utf8'), req.header('swalvo-signature')!, process.env.LIVQENO_WEBHOOK_SECRET!)) {
return res.sendStatus(400);
}
res.sendStatus(200); // ack fast
void enqueue(JSON.parse(req.body.toString('utf8'))); // work later
});express.raw keeps the body exactly as sent. The signature is over the raw
bytes, so a parsed-and-re-encoded body won't match.
Common mistakes
| Mistake | What you'll see | Fix |
|---|---|---|
| Verifying a parsed JSON body | Every signature check fails | Verify the raw body (express.raw). |
| Doing slow work before replying | Duplicate deliveries | Reply 200, then queue the work. |
| Not de-duplicating | The same message saved twice | Store Livqeno-Event-Id and skip repeats. |
| Staging endpoint, production key | No events arrive | Register an endpoint in the right environment. |
Next steps
- Handle webhooks: build a working receiver, step by step.
- Webhooks: setup, verification, and retries in full.
- Event catalogue: every event you can receive.