Webhooks API
The Webhooks API lets you receive real-time HTTP POST notifications for session, machine, command,
and file events. Create webhooks with POST /webhooks, subscribe to specific event types,
verify payloads using HMAC-SHA256 signatures, and test endpoints before going live. Failed
deliveries are retried 3 times with exponential backoff.
The Webhooks API is planned and not yet available — the relay does not currently expose a /webhooks surface. This page documents the intended contract (endpoints, event types, signature scheme, retry policy) so integrations can be designed against it ahead of time. For live event delivery today, use the realtime channels described in the SDKs.
How do I list webhooks?
GET /webhooksResponse
{
"data": [
{
"id": "hook_abc123",
"url": "https://example.com/webhook",
"events": ["machine.offline", "command.failed"],
"enabled": true,
"created_at": "2024-01-15T10:30:00Z"
}
]
}How do I create a webhook?
POST /webhooksRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Webhook endpoint URL |
events | array | Yes | Events to subscribe to |
secret | string | No | Signing secret |
enabled | boolean | No | Default: true |
Example
curl -X POST https://api.cmdop.com/v1/webhooks \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhook",
"events": ["machine.offline", "command.failed", "schedule.failed"],
"secret": "your-secret-key"
}'Response
{
"data": {
"id": "hook_abc123",
"url": "https://example.com/webhook",
"events": ["machine.offline", "command.failed", "schedule.failed"],
"enabled": true,
"created_at": "2024-01-20T15:45:00Z"
}
}How do I update a webhook?
PATCH /webhooks/:idRequest Body
{
"events": ["machine.offline"],
"enabled": false
}How do I delete a webhook?
DELETE /webhooks/:idWhat event types are available?
Session Events
| Event | Description |
|---|---|
session.created | New session created |
session.connected | Agent connected to session |
session.client_attached | Client attached to session |
session.client_detached | Client detached from session |
session.grace_period | Session entered grace period |
session.disconnected | Session ended |
Machine Events
| Event | Description |
|---|---|
machine.online | Machine came online |
machine.offline | Machine went offline |
machine.registered | New machine registered |
Command Events
| Event | Description |
|---|---|
command.started | Command started executing |
command.completed | Command finished successfully |
command.failed | Command failed (non-zero exit) |
command.timeout | Command timed out |
File Events
| Event | Description |
|---|---|
file.uploaded | File uploaded |
file.downloaded | File downloaded |
file.deleted | File deleted |
What does the webhook payload look like?
Webhooks are sent as POST requests with JSON body:
{
"id": "evt_xyz789",
"type": "machine.offline",
"timestamp": "2024-01-20T15:45:00Z",
"data": {
"machine_id": "mach_abc123",
"machine_name": "production-server",
"last_seen": "2024-01-20T15:44:00Z"
}
}How do I verify webhook signatures?
If you provided a secret, verify the signature:
X-Cmdop-Signature: sha256=abc123...Node.js Example
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return `sha256=${expected}` === signature;
}
// In your handler
app.post('/webhook', (req, res) => {
const signature = req.headers['x-cmdop-signature'];
const valid = verifySignature(req.rawBody, signature, process.env.WEBHOOK_SECRET);
if (!valid) {
return res.status(401).send('Invalid signature');
}
// Process webhook
const event = req.body;
console.log(`Received ${event.type}`);
res.status(200).send('OK');
});What is the retry policy?
Failed deliveries are retried:
- 3 attempts
- Exponential backoff: 1min, 5min, 30min
- After all retries, webhook is disabled
How do I test a webhook?
POST /webhooks/:id/testSends a test event to your endpoint:
{
"id": "evt_test",
"type": "test",
"timestamp": "2024-01-20T15:45:00Z",
"data": {
"message": "This is a test webhook"
}
}