Skip to content

Webhooks

RTCstack delivers signed webhook payloads to your configured endpoints whenever LiveKit room events occur.

Configuring a Webhook

http
POST /v1/webhooks
Content-Type: application/json

{
  "url": "https://your-app.com/webhooks/rtcstack",
  "secret": "your-webhook-secret",
  "events": ["room_started", "room_finished", "participant_joined", "participant_left", "egress_ended"]
}

Response:

json
{
  "id": "wh_abc123",
  "url": "https://your-app.com/webhooks/rtcstack",
  "events": ["room_started", "room_finished", ...],
  "createdAt": "2024-04-21T10:00:00.000Z"
}

Managing Webhooks

http
GET    /v1/webhooks           # list all
GET    /v1/webhooks/:id       # get one
PUT    /v1/webhooks/:id       # update url/secret/events
DELETE /v1/webhooks/:id       # delete
POST   /v1/webhooks/:id/test  # send a test ping

Payload Format

Every delivery is a POST with Content-Type: application/json and a signature header:

http
POST https://your-app.com/webhooks/rtcstack
Content-Type: application/json
X-RTCstack-Webhook-Signature: sha256=<hmac>
X-RTCstack-Webhook-Event: room_finished

{
  "event": "room_finished",
  "room": {
    "id": "room-abc",
    "name": "room-abc",
    "createdAt": "2024-04-21T09:00:00.000Z",
    "endedAt": "2024-04-21T10:00:00.000Z",
    "numParticipants": 4
  },
  "timestamp": "2024-04-21T10:00:00.000Z"
}

Verifying Signatures

ts
import { createHmac } from 'crypto'

function verifyWebhook(body: string, signature: string, secret: string): boolean {
  const expected = 'sha256=' + createHmac('sha256', secret).update(body).digest('hex')
  return timingSafeEqual(Buffer.from(expected), Buffer.from(signature))
}

Always verify signatures before processing. Use timingSafeEqual to prevent timing attacks.

Delivery Retries

Failed deliveries (non-2xx response or timeout) are retried with exponential backoff:

AttemptDelay
1st retry5 seconds
2nd retry30 seconds
3rd retry5 minutes

After 3 retries, the delivery is marked failed. Use POST /v1/webhooks/:id/test to re-test connectivity.

Available Events

EventTrigger
room_startedFirst participant joins a new room
room_finishedLast participant leaves; room destroyed
participant_joinedA participant successfully connected
participant_leftA participant disconnected
track_publishedA participant published a track
track_unpublishedA participant unpublished a track
egress_startedRecording started
egress_endedRecording finished (includes file URL)
ingress_startedRTMP/WHIP stream started
ingress_endedRTMP/WHIP stream ended