Docs
Build calls

Webhooks

Receive signed room and participant events on your server.

Provide a receiver URL

Use a server-side client configured with a secret key that has webhooks:write. See RelayServer.

TypeScript
import { RelayServer } from '@relayrtc/node'
 
const relay = new RelayServer({
  apiUrl: process.env.RELAYRTC_API_URL!,
  apiKey: process.env.RELAYRTC_SECRET_KEY!,
})

The webhook URL is an HTTP endpoint in your own backend. RelayRTC sends events to that endpoint. It is not the browser signaling URL or a URL generated by the SDK.

Create and configure the endpoint through the console, REST or the Node SDK.

TypeScript
const endpoint = await relay.webhooks.create({
  url: 'https://your-app.example/webhooks/relayrtc',
  eventTypes: ['room.ended', 'participant.joined'],
})

Save endpoint.signingSecret securely. It is returned on creation and rotation, not on ordinary reads.

Verify before parsing

This example uses Express. Install it alongside the Node SDK:

Shell
pnpm add express
TypeScript
import express from 'express'
import { verifyWebhookRequest } from '@relayrtc/node'
 
const app = express()
 
app.post('/webhooks/relayrtc', express.raw({ type: 'application/json' }), (req, res) => {
  const valid = verifyWebhookRequest(
    process.env.RELAYRTC_WEBHOOK_SECRET!,
    req.body,
    req.headers,
  )
  if (!valid) return res.sendStatus(401)
 
  const event = JSON.parse(req.body.toString('utf8'))
  console.log(event.id, event.type)
  return res.sendStatus(204)
})
 
app.use(express.json())
Process each event once

This receiver shows verification only. Before applying side effects, atomically record the event ID with your processing result. Retries and explicit replay can deliver an event more than once.

Delivery policy

Each run allows 8 attempts over at most 7 days. Network errors, HTTP 408, 425, 429 and 5xx responses are retried. Other unsuccessful HTTP responses stop the run.

Backoff delays are 5 seconds, 30 seconds, 2 minutes, 10 minutes, 30 minutes, 1 hour and 6 hours, with up to 20% additional jitter.

Completed delivery logs are retained for 30 days after the latest outcome. Inspect delivery logs before retrying a failed receiver.

Explicit replay

Replay starts a new run while retaining event and delivery IDs. It requires an enabled endpoint, a terminal delivery and its current replay count.

TypeScript
await relay.webhooks.deliveries.replay(endpoint.id, delivery.id, {
  expectedReplayCount: delivery.replayCount,
})

There are at most 100 explicit replays per delivery.

Secret rotation

Rotation immediately replaces the previous secret. Update your receiver promptly. Older signatures cannot be verified with the new secret.

For the exact headers and signing format, see verifyWebhookRequest.

Receiver address and replay destination

Use a public HTTPS endpoint. Delivery rejects localhost, private network addresses and other destinations that could reach internal services. A local receiver needs a public tunnel.

Explicit replay uses the endpoint’s current URL and signing secret; automatic retries retain the URL selected for that delivery run. See event types and payloads.