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

  1. You register a webhook URL and choose which events to subscribe to
  2. When a matching event fires, Oblien sends a JSON POST to your URL
  3. Your endpoint processes the payload and returns a 2xx status
  4. Oblien records the delivery status for debugging

Supported events

Workspace events

EventDescription
vm.stoppedWorkspace VM has shut down
vm.archivedVM removed on exit (ephemeral / temporary mode)

Workload events

EventDescription
workload.startedA process started inside the VM
workload.exitedA process finished cleanly
workload.failedA process exited with an error
workload.stoppedA process was force-stopped
workload.restart_loopA process is stuck in a crash loop

Credit events

EventDescription
credits.usageFired on each billing cycle — includes namespace, workspace, and detailed resource breakdown
credits.lowBalance dropped below threshold — includes namespace and workspace context
credits.depletedBalance reached zero or overdraft limit hit — workspaces may be stopped
credits.usage_spikeUnusual 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:

MethodEndpointDescription
GET/developer/webhooksList all webhooks
POST/developer/webhooksCreate a webhook
GET/developer/webhooks/:idGet a single webhook
PUT/developer/webhooks/:idUpdate a webhook
DELETE/developer/webhooks/:idDelete 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