Webhooks
Overview
Register HTTPS endpoints to receive real-time notifications when events occur on your tenant — collection + document changes, file uploads, new users, and billing events. Every payload is signed with HMAC-SHA256 (see Verify Signatures) and delivered over HTTPS only.
Payload Envelope
Every webhook request body has the same envelope. The data object carries only identifiers and non-sensitive metadata — if you need the full record, fetch it via the API using the id.
{
"event": "collection.document.created",
"delivery_id": "d1f0...uuid",
"occurred_at": "2026-07-01T00:00:00.000Z",
"data": { "id": "7c9e...uuid", "collection_slug": "posts" }
}Events
Subscribe to any of these event types when you register an endpoint. The data shape per event:
Collections
collection.created data: { id, slug, name }
collection.updated data: { id, slug }
collection.deleted data: { id, slug }
collection.document.created data: { id, collection_slug }
collection.document.updated data: { id, collection_slug }
collection.document.deleted data: { id, collection_slug }
Storage
storage.file.uploaded data: { id, filename, content_type, size_bytes }
storage.file.deleted data: { id, filename }
Users
user.created data: { id, email }
Billing
billing.subscription.created data: { subscription_id, status, current_period_end, cancel_at_period_end }
billing.subscription.updated data: { subscription_id, status, current_period_end, cancel_at_period_end }
billing.subscription.deleted data: { subscription_id, status, current_period_end, cancel_at_period_end }Register an Endpoint
// Requires secret key (sk)
const endpoint = await orbio.webhooks.createEndpoint({
url: 'https://yourapp.com/webhooks/orbio',
events: ['collection.document.created', 'billing.subscription.updated'],
description: 'Production webhook',
});
// IMPORTANT: Save endpoint.secret (your_webhook_secret) — shown only once
console.log('Webhook secret:', endpoint.secret);Manage Endpoints
// List all endpoints
const endpoints = await orbio.webhooks.listEndpoints();
// Update events or pause
await orbio.webhooks.updateEndpoint(endpoint.id, {
events: ['collection.document.created'],
is_active: false,
});
// Delete an endpoint
await orbio.webhooks.deleteEndpoint(endpoint.id);Verify Signatures
Always verify the signature before processing. The X-Orbio-Signature header has the form t=<unix>,v1=<hex>, where v1 is HMAC-SHA256 over `${t}.${rawBody}` — sign the timestamp + the raw request body, not the body alone. Verify against the RAW bytes (before any JSON re-serialization). Signatures older than 5 minutes should be rejected (replay protection).
import crypto from 'node:crypto';
// X-Orbio-Signature: `t=<unix>,v1=<hex>`, v1 = HMAC_SHA256(secret, `${t}.${rawBody}`)
function verifyWebhook(rawBody: string, header: string, secret: string): boolean {
const parts: Record<string, string> = {};
for (const kv of header.split(',')) {
const [k, v] = kv.split('=');
if (k && v) parts[k] = v;
}
const { t, v1 } = parts;
if (!t || !v1) return false;
// Replay protection: reject if the timestamp is more than 5 minutes off.
const ageSec = Math.floor(Date.now() / 1000) - Number(t);
if (!Number.isFinite(ageSec) || Math.abs(ageSec) > 300) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${t}.${rawBody}`)
.digest('hex');
const a = Buffer.from(v1, 'hex');
const b = Buffer.from(expected, 'hex');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Delivery History
// View delivery attempts
const deliveries = await orbio.webhooks.listDeliveries({
endpoint_id: endpoint.id,
status: 'failed', // 'pending' | 'delivered' | 'failed' | 'retrying'
});
// Each delivery shows: event_type, status, status_code, attempts, error_messageRequirements
Webhook URLs must use HTTPS (HTTP is rejected). Endpoints resolving to private/internal addresses are refused.
Endpoints must respond with a 2xx status within 10 seconds; redirects are not followed.
Failed deliveries are retried up to 3 times with exponential backoff, then marked failed.