Skip to main content

Overview

The downed_machines webhook tells your system when one or more important machines appear to need attention. Most teams route this event directly into Slack so operators see machine issues where they already work. Cyberdesk only monitors machines that you explicitly opt in. On a desktop’s detail page, enable Downed machine alerts to include that machine in the monitor.
Machines are not monitored by default. This avoids alerts for desktops that are intentionally offline or only used occasionally.

Send Machine Alerts To Slack

The fastest way to use machine alerts is with Cyberdesk’s existing Slack integration. You do not need to host your own webhook receiver unless you want custom routing logic outside Slack.
1

Create a machine-alert Slack endpoint

Go to Dashboard -> Webhooks -> Endpoints, click + Add Endpoint, then open the destination dropdown in the top right. Choose Send downed machine alerts to Slack.
2

Connect your workspace and channel

Click Connect to Slack. Slack will ask you to choose the workspace and channel that should receive machine alerts. Approve the connection, and you’ll return to Cyberdesk.
3

Review the selected event

The connector subscribes to the downed_machines event and includes a default Slack transformation that formats machine alerts into a structured Slack message.
4

Create the endpoint

Click Create. That’s it: newly downed opted-in machines will now post to your selected Slack channel.
You can use the default Slack message as-is. If your team wants different wording, routing context, or Slack Block Kit layout, edit the endpoint’s transformation code before creating it or any time later.
The machine-alert Slack connector includes a default Svix transformation similar to this. You only need to edit it if you want to customize the final Slack message:
function handler(webhook) {
  if (webhook.eventType !== "downed_machines") {
    return webhook;
  }

  const payload = webhook.payload || {};
  const machines = Array.isArray(payload.machines) ? payload.machines : [];

  if (machines.length === 0) {
    webhook.cancel = true;
    return webhook;
  }

  const maxMachinesToShow = 8;
  const visibleMachines = machines.slice(0, maxMachinesToShow);
  const hiddenCount = Math.max(0, machines.length - visibleMachines.length);
  const occurredAt = payload.occurred_at
    ? new Date(payload.occurred_at).toLocaleString()
    : "unknown time";

  function escapeMrkdwn(value) {
    return String(value ?? "")
      .replace(/&/g, "&")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;");
  }

  function truncate(value, maxLength) {
    const text = escapeMrkdwn(value || "Machine appears unreachable");
    return text.length > maxLength ? `${text.slice(0, maxLength - 1)}...` : text;
  }

  const machineBlocks = visibleMachines.map((machine, index) => {
    const name = escapeMrkdwn(machine.name || machine.machine_id || "Unnamed machine");
    const id = escapeMrkdwn(machine.machine_id || "unknown");
    const status = escapeMrkdwn(machine.status || "unknown");
    const reason = truncate(machine.reason, 180);

    return {
      type: "section",
      text: {
        type: "mrkdwn",
        text:
          `*:desktop_computer: ${index + 1}. ${name}*\n` +
          `*Status:* \`${status}\`\n` +
          `*Machine ID:* \`${id}\`\n` +
          `*Reason:* ${reason}`
      }
    };
  });

  const overflowBlocks = hiddenCount > 0
    ? [
        {
          type: "context",
          elements: [
            {
              type: "mrkdwn",
              text: `+ ${hiddenCount} additional downed machine${hiddenCount === 1 ? "" : "s"} not shown. Open Cyberdesk for the full list.`
            }
          ]
        }
      ]
    : [];

  webhook.payload = {
    blocks: [
      {
        type: "header",
        text: {
          type: "plain_text",
          text: "Cyberdesk Machine Alert",
          emoji: true
        }
      },
      {
        type: "section",
        text: {
          type: "mrkdwn",
          text:
            `*:rotating_light: ${machines.length} monitored machine${machines.length === 1 ? "" : "s"} currently need attention.*\n` +
            "This alert fired because at least one opted-in machine newly entered the downed state."
        }
      },
      {
        type: "context",
        elements: [
          {
            type: "mrkdwn",
            text: `Event: \`${payload.event_type || webhook.eventType}\` | Org: \`${payload.organization_id || "unknown"}\` | Detected: ${occurredAt}`
          }
        ]
      },
      { type: "divider" },
      ...machineBlocks,
      ...overflowBlocks,
      { type: "divider" },
      {
        type: "actions",
        elements: [
          {
            type: "button",
            text: {
              type: "plain_text",
              text: "Open Desktops Dashboard"
            },
            url: "https://cyberdesk.io/dashboard/desktops"
          }
        ]
      }
    ]
  };

  return webhook;
}
For screenshots and more detail on the Slack setup flow, see the full Slack integration guide. For more on editing and testing transform code, see Webhook Transformations.

When It Fires

Cyberdesk checks opted-in machines on a recurring schedule. A machine appears down when either:
  • Its Cyberdesk status is not connected.
  • Its status is connected, but Cyberdesk cannot complete a lightweight display dimensions probe after retries.
The webhook fires only when a new opted-in machine enters the down set. The payload still includes the full array of machines that currently appear down for the organization, so your alert can include context about any machines that were already down. Cyberdesk does not send a separate recovery webhook when a machine comes back online.

Enable Monitoring For A Machine

  1. Go to Dashboard -> Desktops.
  2. Enable alerts from the Alerts checkbox in the desktops table, or open a desktop and enable Downed machine alerts in the Machine Status card.
  3. In Dashboard -> Webhooks, make sure your Slack endpoint or webhook endpoint subscribes to downed_machines.

Payload

{
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_type": "downed_machines",
  "occurred_at": "2026-07-08T18:30:00Z",
  "organization_id": "org_123",
  "machines": [
    {
      "machine_id": "9f2c0c07-f694-4c8f-b4d5-5a6f936a9a75",
      "name": "checkout-worker-1",
      "organization_id": "org_123",
      "status": "connected",
      "last_seen": "2026-07-08T18:21:00Z",
      "reason": "Machine dimensions probe timeout"
    }
  ]
}

Verify And Handle The Event

import express from "express";
import { Webhook } from "svix";
import type { DownedMachinesEvent } from "cyberdesk";

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

function assertDownedMachinesEvent(x: unknown): asserts x is DownedMachinesEvent {
  if (!x || (x as any).event_type !== "downed_machines" || !Array.isArray((x as any).machines)) {
    throw new Error("Invalid downed_machines payload");
  }
}

app.post("/webhooks/cyberdesk", (req, res) => {
  const wh = new Webhook(process.env.SVIX_WEBHOOK_SECRET!);
  const payload = wh.verify(req.body, {
    "svix-id": req.header("svix-id")!,
    "svix-timestamp": req.header("svix-timestamp")!,
    "svix-signature": req.header("svix-signature")!,
  });

  assertDownedMachinesEvent(payload);

  for (const machine of payload.machines) {
    console.log(`${machine.name ?? machine.machine_id}: ${machine.reason}`);
  }

  res.status(204).send();
});
Use event_id for idempotency, then fan out to your alerting system. Because Cyberdesk only sends this event when a newly downed machine is found, your receiver usually does not need to dedupe repeated deliveries beyond Svix retry handling.
Svix may retry deliveries when your endpoint fails or times out. Always verify signatures and treat event_id or the svix-id header as idempotency keys.