Overview

Webhooks notify your app when something happens in Cyberdesk. Instead of polling, subscribe to the event types you care about (see the Event Catalog in the Webhooks portal). The most common one is run_complete, which we’ll use below as an example.
Typical flow: create a run with the SDK, return immediately to your user, and update your system when you receive the webhook.

1) Enable Webhooks in the Dashboard

  1. Go to the Cyberdesk Dashboard → Webhooks.
  2. Click “Activate Webhooks” (creates a Svix Application for your organization).
  3. Click “Add Endpoint” and enter your HTTPS URL.
  4. Subscribe to the event types you need (for getting started, run_complete is typical).
  5. Copy the endpoint’s signing secret (whsec_...).
Each endpoint has its own secret. Keep separate endpoints/secrets for dev and prod.

2) Implement the Endpoint (verify signatures)

Install dependencies

npm install cyberdesk svix
# or
yarn add cyberdesk svix
# or
pnpm add cyberdesk svix
We’re working on a managed Webhooks SDK with built‑in verification and typing. If you’d like this prioritized, please let the team know.

Endpoint handlers

import express from "express";
import { Webhook, WebhookVerificationError } from "svix";
import type { RunCompletedEvent } from "cyberdesk";

const app = express();
app.use(express.raw({ type: "application/json" })); // verify requires raw body

function assertRunCompletedEvent(x: unknown): asserts x is RunCompletedEvent {
  if (!x || (x as any).event_type !== "run_complete" || !(x as any).run) {
    throw new Error("Invalid run_complete payload");
  }
}

app.post("/webhooks/cyberdesk", (req, res) => {
  const secret = process.env.SVIX_WEBHOOK_SECRET!;
  const wh = new Webhook(secret);

  const headers = {
    "svix-id": req.header("svix-id")!,
    "svix-timestamp": req.header("svix-timestamp")!,
    "svix-signature": req.header("svix-signature")!,
  };

  try {
    const payload = wh.verify(req.body, headers);
    assertRunCompletedEvent(payload);
    const run = payload.run;
    // idempotency: upsert on headers["svix-id"] or payload.event_id
    // handle success/error/cancelled
    res.status(200).end();
  } catch (err) {
    if (err instanceof WebhookVerificationError) return res.status(400).end();
    res.status(500).end();
  }
});
import { createCyberdeskClient } from "cyberdesk";

async function onRunComplete(run: any) {
  const client = createCyberdeskClient(process.env.CYBERDESK_API_KEY!);

  // Example A: Start a follow-up workflow
  await client.runs.create({
    workflow_id: process.env.NEXT_WORKFLOW_ID!,
    input_values: { summary: run.output_data?.summary }
  });

  // Example B: Persist and enqueue for async processing
  await db.runs.upsert({ id: run.id, status: run.status, output: run.output_data });
  await queue.enqueue("postprocess-run", { runId: run.id });
}

3) Event payload

Payloads vary by event type. Refer to the Event Catalog in the portal for up‑to‑date schemas. Example for run_complete:
{
  "event_id": "uuid",
  "event_type": "run_complete",
  "occurred_at": "2025-08-16T19:19:44Z",
  "run": { /* RunResponse: id, workflow_id, status, error, output_data, input_values, attachment ids, created_at, ... */ }
}
Use run.status to branch your logic and output_data or attachments to continue your process.

4) Test

  • In the Webhooks tab, send a test event to your endpoint.
  • Use the Logs/Activity views to inspect payloads and delivery attempts, replay failures, and recover from downtime.

Next steps

  • See the Detailed Webhook Guide for signature details, retries, troubleshooting, and failure recovery.