Agent skill
Crusoe Cloud Webhooks Skill
Receive and verify Crusoe Cloud webhooks (Notifications service, delivered via Svix). Use when setting up a Crusoe Cloud webhook handler, debugging svix-id / svix-timestamp / svix-signature verification, or handling Crusoe notifications such as resource.automated_remediation (Command Center / AutoClusters node replacement), resource health, budget alerts, organization and Managed AI events.
Install this skill
npx skills add hookdeck/webhook-skills --skill crusoe-webhooks
Crusoe Cloud's Notifications service routes alerts (resource health and automated remediation from Command Center, budget alerts, organization changes, Managed AI events) to email, the console, Slack and generic webhook endpoints. Webhook endpoints are managed in a Svix dashboard opened from the Crusoe Cloud Console.
When to Use This Skill
- How do I receive Crusoe Cloud webhooks?
- How do I verify Crusoe webhook signatures?
- How do I handle Crusoe
resource.automated_(node replacement) notifications?remediation - How do I route Crusoe budget alerts or resource health alerts to my own service?
- Why is my Crusoe webhook signature verification failing?
Verification (core)
Inferred from Svix, not quoted from Crusoe. Crusoe's docs say webhooks are configured "on the Svix dashboard" but publish no verification details. The headers, algorithm and
whsec_secret format below are Svix defaults.
Each webhook carries svix-id, svix-timestamp (Unix seconds) and svix-signature (space-separated v1,<base64> entries). The signature is base64 HMAC-SHA256 over ${svix-id}.${svix-timestamp}.${raw body}, keyed with the base64-decoded secret after whsec_. Use the official svix SDK (Node and Python), which also enforces a 5-minute timestamp window and handles secret rotation:
import { Webhook } from 'svix'; // svix 2.8+ is ESM-only
const wh = new Webhook(process.env.CRUSOE_WEBHOOK_SECRET); // "whsec_..."
wh.verify(rawBody, { // raw Buffer/string, NOT parsed JSON
'svix-id': req.headers['svix-id'],
'svix-timestamp': req.headers['svix-timestamp'],
'svix-signature': req.headers['svix-signature'],
}); // throws WebhookVerificationError; returns undefined in svix 2.x
const payload = JSON.parse(rawBody.toString('utf8')); // parse only after verifying
Python: from svix.webhooks import Webhook and call Webhook(secret).verify(raw_ the same way.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Common Event Types
Crusoe documents one exact event type string; the rest are console categories you subscribe to per endpoint in the Svix dashboard.
| Event / category | Description |
|---|---|
resource.automated_ | Automated remediation of a node (e.g. Node Replacement after XID 79: GPU has fallen off the bus) |
| Resource Health | Hardware issues and automated remediation on your nodes |
| User Account and Organization Management | Changes to organization account settings and access controls |
| Billing | Budget alerts when a budget threshold is exceeded |
| Managed AI | Managed AI updates; self-serve deployment created / scaled / deleted |
Parse defensively. Crusoe says the body "varies by event type", and the documented resource.automated_ example has no type field. The examples read type / event_type when present, otherwise recognise remediation payloads by workflow_type + resource_id, and log anything else without failing.
Environment Variables
CRUSOE_WEBHOOK_SECRET=whsec_xxxxx # endpoint signing secret from the Svix dashboard
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 crusoe --path /webhooks/crusoe
Add the tunnel URL as a Webhook endpoint (Console → bell icon → All Notifications → Manage Slack/Webhook → Add Endpoint).
Reference Materials
- references/overview.md - Notification categories, events and payload structure
- references/setup.md - Add a webhook endpoint and get the signing secret
- references/verification.md - Svix signature verification details and gotchas