Webhook Signatures
When a webhook has a signing secret, every delivery includes an X-Webhook-Signature header containing the HMAC-SHA256 hex digest of the request body.
Payload format
Section titled “Payload format”{ "event": "snapshot.created", "data": { "snapshotId": "a1b2c3d4-...", "machineName": "james-mbp" }, "timestamp": "2026-02-07T12:00:00.000Z"}Event payloads
Section titled “Event payloads”| Event | Data fields |
|---|---|
snapshot.created | snapshotId, machineName |
snapshot.deleted | snapshotId |
file.uploaded | fileId, filename |
file.deleted | fileId, filename |
member.invited | memberId, role, invitedBy |
member.removed | memberId, apiKeyId |
Verification
Section titled “Verification”Compute the HMAC-SHA256 of the raw request body with your webhook secret and compare it to X-Webhook-Signature.
Node.js
Section titled “Node.js”import { createHmac, timingSafeEqual } from 'crypto';
function verify(body, secret, signature) { const expected = createHmac('sha256', secret).update(body).digest('hex'); return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));}Python
Section titled “Python”import hmac, hashlib
def verify(body: bytes, secret: str, signature: str) -> bool: expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, signature)Delivery behavior
Section titled “Delivery behavior”| Property | Value |
|---|---|
| Method | POST |
| Content-Type | application/json |
| Timeout | 10 seconds |
| Retries | None (single attempt) |
| Stored response | First 1,000 characters |
Check delivery status via GET /machine/webhooks/:id.