Skip to main content
This guide covers setting up webhooks for external notifications and workflows for running custom code when events occur in your rooms.

Webhooks vs Workflows

FeatureWebhooksWorkflows
WhatHTTP POST to your serverCustom JS/TS code executed in Cloudflare Workers
WhereYour own infrastructureCollabKit’s infrastructure
Use caseNotify external services, update databasesProcess events, transform data, trigger side effects
SetupProvide a URLProvide source code
AuthHMAC-SHA256 signature verificationN/A (runs in a secure sandbox)

Part 1: Webhooks

Create a Webhook

Register a URL to receive HTTP callbacks when events occur:
curl -X POST https://api.collab-kit.com/v1/accounts/${ACCOUNT_ID}/webhooks \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://api.example.com/collab-webhook",
    "events": ["participant.joined", "participant.left", "user.created"]
  }'
Save the secret from the response — you need it to verify webhook signatures.

Available Events

EventWhen It Fires
participant.joinedA user comes online in a room
participant.leftA user goes offline
session.startedFirst user joins a room (new session)
session.closedLast user leaves a room (session ends)
user.createdA new user is added to a room via POST /users
user.updatedA user’s fields are changed
user.deletedA user is removed from a room

Webhook Payload

Each delivery sends a POST request with a JSON body:
{
  "event": "participant.joined",
  "data": {
    "userId": "user-001",
    "roomId": "c3003c93-60cf-4184-..."
  },
  "timestamp": "2026-05-29T10:06:00.000Z"
}

Verify Webhook Signatures

Each delivery includes an HMAC-SHA256 signature. Verify it to ensure the payload is authentic:
import { createHmac, timingSafeEqual } from 'crypto';

function verifyWebhookSignature(
  body: string,
  signature: string,
  secret: string
): boolean {
  const expected = createHmac('sha256', secret)
    .update(body)
    .digest('hex');

  return timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

// In your webhook handler (Express example)
app.post('/collab-webhook', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const body = JSON.stringify(req.body);

  if (!verifyWebhookSignature(body, signature, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  // Process the event
  const { event, data } = req.body;
  switch (event) {
    case 'participant.joined':
      console.log(`User ${data.userId} joined room ${data.roomId}`);
      break;
    case 'session.closed':
      console.log(`Session ended in room ${data.roomId}`);
      break;
  }

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

Scope to a Room

Limit webhooks to a specific room:
curl -X POST https://api.collab-kit.com/v1/accounts/${ACCOUNT_ID}/webhooks \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://api.example.com/room-webhook",
    "events": ["participant.joined"],
    "roomId": "c3003c93-60cf-4184-b85f-20be14d26dac"
  }'

Monitor Deliveries

Check the delivery log to debug issues:
curl "https://api.collab-kit.com/v1/accounts/${ACCOUNT_ID}/webhooks/wh_abc123/deliveries?limit=10" \
  -H "Authorization: Bearer ${TOKEN}"
Each delivery shows the status (pending, success, failed), HTTP status code, attempt count, and next retry time.

Part 2: Workflows

Workflows let you run custom JavaScript in response to events, directly on CollabKit’s infrastructure.

Create a Workflow

curl -X POST https://api.collab-kit.com/v1/accounts/${ACCOUNT_ID}/workflows \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Log new participants",
    "events": ["participant.joined", "participant.left"],
    "code": "export default async function(event, { room }) {\n  const roomData = await room.get();\n  console.log(`[${event.event}] User ${event.data.userId} in room ${roomData.name}`);\n  return { logged: true };\n}"
  }'

Workflow Bindings

Your workflow code receives the event and a set of bindings:
export default async function(event, bindings) {
  // event.event    -- "participant.joined", etc.
  // event.data     -- event-specific payload

  const { store, room, files } = bindings;

  // Read from KV stores
  const value = await store.get('tasks', 'task-1');
  const all = await store.getAll('tasks');

  // Read room and user data
  const roomData = await room.get();
  const users = await room.getUsers();

  // Work with files
  const fileList = await files.list();

  return { success: true };
}
BindingMethodsDescription
storeget(store, key), getAll(store)Read-only KV store access
roomget(), getUsers()Read-only room and user metadata
fileslist()Scoped R2 file listing
event(passed as first arg)The triggering event data

Example: Notify Slack on Session Start

export default async function(event, { room }) {
  if (event.event !== 'session.started') return;

  const roomData = await room.get();

  await fetch('https://hooks.slack.com/services/YOUR/WEBHOOK/URL', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      text: `Collaboration session started in "${roomData.name}"`,
    }),
  });

  return { notified: true };
}

Example: Auto-Create Welcome Store Entry

export default async function(event, { store }) {
  if (event.event !== 'user.created') return;

  // Note: workflow store access is read-only
  // Use this to check existing state, then use fetch()
  // to call external APIs with the data
  const existing = await store.get('settings', event.data.userId);
  console.log('User settings:', existing);

  return { checked: true };
}

Monitor Executions

Check the execution log:
curl "https://api.collab-kit.com/v1/accounts/${ACCOUNT_ID}/workflows/wf_abc123/executions?limit=10" \
  -H "Authorization: Bearer ${TOKEN}"
Each execution shows status, duration, and the result or error message.

Enable/Disable Workflows

# Disable
curl -X PATCH https://api.collab-kit.com/v1/accounts/${ACCOUNT_ID}/workflows/wf_abc123 \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'

# Re-enable
curl -X PATCH https://api.collab-kit.com/v1/accounts/${ACCOUNT_ID}/workflows/wf_abc123 \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'

Next Steps