Synento docs
Guides

Webhooks Guide

Set up event-driven integrations that react to Synento session events.

View as Markdown

Set up event-driven integrations that react to Synento session events.

Overview

Synento automatically emits webhook events for key lifecycle moments:

  • session.created — a new session is created via API
  • session.started — the first participant joins a session
  • session.ended — all participants leave (last one departs)
  • recording.ready — stream recording is fully persisted and replayable
  • export.completed — MP4 export finishes successfully

Setting Up a Webhook Receiver

1. Create the webhook endpoint on your server

// Example: Express.js handler
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-synento-signature'] ?? '';

  // Verify HMAC-SHA256 over the raw body, exactly as received
  const crypto = require('crypto');
  const expected = crypto.createHmac('sha256', YOUR_WEBHOOK_SECRET)
    .update(req.body)
    .digest('hex');

  if (signature.length !== expected.length ||
      !crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).send('Invalid signature');
  }

  const payload = JSON.parse(req.body.toString());

  // Dispatch based on event type
  switch (payload.type) {
    case 'session.created':
      console.log('New session:', payload.session_id);
      break;
    case 'session.started':
      console.log('Session started:', payload.session_id);
      break;
    case 'session.ended':
      console.log('Session ended:', payload.session_id);
      break;
    case 'recording.ready':
      console.log('Recording ready:', payload.session_id);
      break;
    case 'export.completed':
      console.log('Export completed:', payload.session_id);
      break;
  }

  res.status(200).send('OK');
});

2. Register the webhook with Synento

curl -X POST https://api.synento.com/v1/webhooks \
  -H "Authorization: Bearer sk_live_xxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhook",
    "events": ["session.created", "session.started", "session.ended"]
  }'

3. List your webhooks to verify

curl https://api.synento.com/v1/webhooks \
  -H "Authorization: Bearer sk_live_xxxxx"

Webhook Payload Structure

Each webhook event has the following structure:

{
  "id": "<event-uuid>",
  "type": "session.started",
  "timestamp": "2025-01-01T12:00:00.000Z",
  "project_id": "<project-uuid>",
  "session_id": "<session-uuid>"
}

Signature Verification

Every webhook includes an X-Synento-Signature header containing an HMAC-SHA256 digest of the raw request body, signed with your webhook's secret key.

Always verify this signature before processing — never trust the payload without verification.

The digest is lowercase hex. Compute it over the raw body bytes exactly as they arrived — not over JSON you have parsed and re-serialised, which will not match — and compare in constant time, as the receiver example above does.

Event Delivery & Retry

Synento delivers each webhook with the following reliability guarantees:

AspectDetail
Delivery modelBest-effort POST to your endpoint
Timeout5 seconds per attempt (AbortController)
RetryA failed delivery (network error, timeout or non-2xx) is retried by a background job with exponential backoff, about 2 then 4 minutes apart. Pending retries are stored durably and survive a server restart.
Delivery logEvery attempt is recorded; see the Webhooks page in the dashboard
OrderingEvents for the same session are generally ordered but not guaranteed

Monitoring & Debugging

When testing locally:

  1. Use ngrok or similar to expose your localhost endpoint
  2. Register the public URL as the webhook target
  3. Create a session and check your local logs for incoming webhooks

Once verified, switch to a stable production URL.

Best Practices

  1. Always verify signatures — unverified webhooks could be spoofed
  2. Respond quickly (200 OK) — process the payload asynchronously; don't block on long operations
  3. Log all incoming events — use logs to audit and debug event flows
  4. Handle idempotency — if an event is delivered twice, your handler should handle it gracefully
  5. Use session.started + session.ended — together they give you accurate session duration

On this page