On this page

Webhooks

MIOSA sends HTTP POST requests to your endpoint whenever a sandbox or deployment changes state. Use webhooks to update your database, notify users, trigger downstream actions, or bill for compute.


Event taxonomy

Sandbox events

EventFires when
sandbox.createdThe sandbox row is inserted. The VM may still be booting.
sandbox.runningThe sandbox is fully booted and ready. external_user_id is available.
sandbox.pausedThe sandbox was paused due to an idle timeout or an explicit API call.
sandbox.resumedA paused sandbox was resumed.
sandbox.destroyedThe sandbox was permanently deleted.
sandbox.errorThe sandbox failed to boot or encountered a runtime error.

Deployment events

EventFires when
deployment.createdA new deployment was created.
deployment.build_startedA build started for a new version.
deployment.build_succeededA build finished successfully.
deployment.build_failedA build failed. The error field contains the failure reason.
deployment.publishedA version was promoted to the active release.
deployment.domain_attachedA custom domain was verified and attached.

Payload structure

Every webhook delivery has the same envelope:

{
  "id": "evt_01hzqmrkntq6g9gxnqhvpa8c7t",
  "type": "sandbox.running",
  "created_at": "2026-05-25T14:32:10Z",
  "data": {
    "id": "sbx_01hzq5pnmpgt6vdwp0r8d23c5n",
    "state": "running",
    "external_user_id": "user_42",
    "external_project_id": "proj_opendesigns_1",
    "metadata": {
      "customer_id": "user_42",
      "project_name": "brand-refresh",
      "source": "opendesigns-whitelabel"
    },
    "preview_url": "https://3000-sbx01hzq.sandbox.opendesigns.ai"
  }
}

The id field is a unique event ID. Use it to deduplicate deliveries.


HMAC-SHA256 signature verification

Every delivery includes a Miosa-Signature header:

Miosa-Signature: t=1716645130,v1=a3f2c8...
  • t — Unix timestamp (seconds) when MIOSA signed the request
  • v1 — HMAC-SHA256 hex digest of "<t>.<raw_body>"

The signed payload is timestamp + "." + raw request body bytes. Verify before parsing the JSON.


Idempotency

MIOSA may deliver the same event more than once (network retries, at-least-once semantics). Make your handler idempotent by storing the event id and discarding duplicates:

processed_events = set()  # use a database or cache in production

def handle_event(event: dict) -> None:
    event_id = event["id"]
    if event_id in processed_events:
        return  # duplicate — skip
    processed_events.add(event_id)

    match event["type"]:
        case "sandbox.running":
            notify_user(event["data"]["external_user_id"])
        case "sandbox.destroyed":
            release_resources(event["data"]["id"])
        case "sandbox.error":
            alert_oncall(event["data"])

Retry policy

AttemptDelay
1 (initial)Immediate
25 seconds
330 seconds
45 minutes
530 minutes

MIOSA stops retrying after five attempts. If your endpoint is unreachable for more than 30 minutes, check the webhook delivery log in the MIOSA dashboard.

Return a 2xx status code within 10 seconds to acknowledge receipt. If your processing takes longer, acknowledge immediately and handle the event asynchronously.


Register a webhook


Local testing

Use a tunnel to expose your local server during development:

# Option 1 — ngrok
ngrok http 8000
# Copy the https URL, set MIOSA_WEBHOOK_URL in .env

# Option 2 — cloudflared
cloudflared tunnel --url http://localhost:8000

Then run the one-time setup script to register the tunnel URL as your webhook endpoint. When you restart the tunnel and get a new URL, update the webhook:

# Update an existing webhook's URL
client.webhooks.update("whk_abc123", url="https://new-tunnel.ngrok.io/webhooks/miosa")

See also

Was this helpful?