Preview — sandbox webhooks are newly available and still evolving; the shape may change. We’d love your feedback.
event:
deliveryId — verifyWebhook sets it from the svix-id header (stable across retries and redelivery). Need to route on your own metadata? Attach metadata when you register the destination and it rides as custom HTTP headers on every request — there’s no metadata in the body.
Events
Subscribe to all events, or filter witheventTypes (exact like sandbox.stopped, or a prefix like sandbox.*).
Destinations
A destination is org-scoped by default (all your sandboxes), or pinned to one sandbox withsandboxId. Set enabled: false to pause a destination — it stops receiving deliveries until you re-enable it; events that occur while it’s paused aren’t backfilled.
secret, OpenComputer generates one (whsec_…) and returns it on create. The secret is re-fetchable any time via webhooks.getSecret(id) (GET /api/webhooks/:id/secret), and rotatable via webhooks.update(id, { rotateSecret: true }).
- TypeScript SDK
- REST API
Subscribe at create
sandbox.created and sandbox.ready fire before a separate webhooks.create call could know the sandbox id. To capture a sandbox’s full lifecycle, register the webhook with the sandbox — it’s pinned to that sandbox and gets every event from created on:
Deliveries
Every send and its outcome — the data behind a deliveries dashboard.- TypeScript SDK
- REST API
status and the consumer’s responseStatusCode; Svix retries failed attempts on its managed schedule and retains recent attempt history (the attempt index lags a send by a few seconds). A deleted destination’s history is no longer queryable.
svix-id) — for when the original never landed. A receiver that dedupes on svix-id treats it as the same message.
Signing, retries, and dedupe
- HTTPS only, checked at registration. The delivery layer (Svix) additionally blocks private, loopback, link-local, and cloud-metadata addresses at send time.
- Always signed with Standard Webhooks (delivery is by Svix). Every request carries
svix-id,svix-timestamp, andsvix-signature=v1,<base64(HMAC-SHA256(secret, "{svix-id}.{svix-timestamp}.{rawBody}"))>. Verify against the raw request body, before parsing it; the timestamp guards replay. Any custom headers you attached as destinationmetadataride along too. Your signingsecretis re-fetchable any time viaGET /api/webhooks/{id}/secretand rotatable via update (rotateSecret: true). - At-least-once. Once an event is handed off it’s retried until it succeeds or the delivery layer gives up. A duplicate can still arrive, so dedupe on
svix-id(the verifier exposes it as bothdeliveryIdanddedupeId). - Not strictly ordered. Events for one sandbox can arrive out of order (e.g.
sandbox.readybeforesandbox.created). Treat each event independently and key offevent.type; don’t assume an ordering. - Success / retry / give-up. A delivery succeeds on HTTP
2xx. Failures are retried on Svix’s managed backoff (immediately, then 5s, 5m, 30m, 2h, 5h, 10h, 10h); an endpoint that keeps failing for ~5 days is auto-disabled. Inspect attempts and recover failed messages via the deliveries API. Unsafe targets (private / loopback / cloud-metadata addresses) are blocked by the delivery layer.
Verify a webhook
The SDK ships a verifier — no extra dependency, runs in Node / Cloudflare Workers / browsers — that checks the signature and returns the parsed envelope. It’s the sameverifyWebhook used for session webhooks; pass SandboxLifecycleEvent to type the nested event:
svix-id / svix-timestamp / svix-signature headers.
Webhooks here cover sandbox lifecycle. To deliver an agent’s session events (turns, messages, results), see Agent Sessions webhooks — verified with the same
verifyWebhook helper. Session webhooks differ in a couple of specifics today: their webhook-id is the event id, and signing is opt-in (set a secret).