Concepts
Webhooks
Webhooks let you receive HTTP POST requests whenever events happen in your workspaces. Instead of polling for changes, you get notified the moment a VM stops, a workload fails, or your credit balance drops.
How it works
- You register a webhook URL and choose which events to subscribe to
- When a matching event fires, Oblien sends a JSON POST to your URL
- Your endpoint processes the payload and returns a 2xx status
- Oblien records the delivery status for debugging
Supported events
Workspace events
| Event | Description |
|---|---|
vm.stopped | Workspace VM has shut down |
vm.archived | VM removed on exit (ephemeral / temporary mode) |
Workload events
| Event | Description |
|---|---|
workload.started | A process started inside the VM |
workload.exited | A process finished cleanly |
workload.failed | A process exited with an error |
workload.stopped | A process was force-stopped |
workload.restart_loop | A process is stuck in a crash loop |
Credit events
| Event | Description |
|---|---|
credits.usage | Fired on each billing cycle — includes namespace, workspace, and detailed resource breakdown |
credits.low | Balance dropped below threshold — includes namespace and workspace context |
credits.depleted | Balance reached zero or overdraft limit hit — workspaces may be stopped |
credits.usage_spike | Unusual credit consumption detected across your namespaces |
Credit events include rich context so you can track per-namespace and per-workspace spend:
{
"event": "credits.usage",
"timestamp": "2026-03-12T14:30:00.000Z",
"data": {
"balance": 142.5,
"credits_used": 3.25,
"namespace": "production",
"workspace_id": "ws_abc123",
"workspace_name": "my-agent",
"period_start": "2026-03-12T14:25:00.000Z",
"period_end": "2026-03-12T14:30:00.000Z",
"usage": {
"cpu_time_minutes": 4.2,
"memory_gb_minutes": 2.1,
"disk_io_gb": 0.003,
"network_gb": 0.0015
}
}
}Payload format
Every webhook delivery is a POST request with a JSON body:
{
"event": "vm.stopped",
"timestamp": "2026-03-12T14:30:00.000Z",
"data": {
"workspace_id": "ws_abc123",
"reason": "ttl_expired"
}
}The payload shape under data varies by event type.
Signature verification
If you provide a secret when creating the webhook, every delivery includes an X-Webhook-Signature header containing an HMAC-SHA256 hex digest of the raw request body.
To verify:
import crypto from 'crypto';
function verifyWebhook(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}Always use a timing-safe comparison to prevent timing attacks.
Delivery behavior
- Timeout: 10 seconds per delivery attempt
- Fire-and-forget: Failed deliveries are not retried automatically
- Status tracking: The last HTTP status code and trigger time are recorded per webhook
- Limit: Up to 10 webhooks per account
Managing webhooks
You can create, update, toggle, and delete webhooks from the Dashboard or via the API:
| Method | Endpoint | Description |
|---|---|---|
GET | /developer/webhooks | List all webhooks |
POST | /developer/webhooks | Create a webhook |
GET | /developer/webhooks/:id | Get a single webhook |
PUT | /developer/webhooks/:id | Update a webhook |
DELETE | /developer/webhooks/:id | Delete a webhook |
Best practices
- Always verify signatures if you set a secret — don't trust payloads blindly
- Respond quickly — return a 200 within a few seconds, do heavy processing async
- Use HTTPS endpoints — never send webhook traffic over plain HTTP
- Handle duplicates — use the event timestamp + workspace ID to deduplicate if needed
- Monitor delivery status — check the dashboard for failed status codes