Banata

Operate

Webhooks

Receive real-time HTTP notifications when browser sessions, sandboxes, and machines change state.

Banata can send HTTP POST requests to your server whenever important events occur — a browser session becomes ready, a sandbox fails, a machine is suspended, and more. Webhooks let you build reactive workflows without polling.


How It Works

  1. You register an HTTPS endpoint in the dashboard or via the API.
  2. When an event fires, Banata enqueues a delivery for every matching webhook.
  3. Each delivery is a signed JSON POST with retry logic.
  4. Your server verifies the signature and processes the payload.

Creating a Webhook

From the Dashboard

  1. Sign in to the Banata dashboard.
  2. Navigate to Webhooks in the sidebar.
  3. Click Create Webhook.
  4. Enter your HTTPS endpoint URL.
  5. Select which event types to subscribe to (or leave all selected).
  6. Copy the signing secret — it is only shown once.

From the API

bash
curl -X POST "https://api.boxes.banata.dev/v1/webhooks" \
  -H "Authorization: Bearer br_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/banata",
    "description": "Production handler",
    "event_types": ["session.ready", "session.ended", "sandbox.failed"]
  }'

The response includes the signing_secret. Store it securely — you will need it to verify signatures.


Event Types

Browser Session Events

EventFired when
session.createdA browser session is created
session.assignedThe session is assigned to a machine
session.readyThe browser is running and the CDP endpoint is available
session.endingSession termination has been initiated
session.endedThe session has fully terminated
session.failedThe session could not be started or crashed

Sandbox Events

EventFired when
sandbox.createdA sandbox is created
sandbox.assignedThe sandbox is assigned to a machine
sandbox.readyThe sandbox runtime is up and accepting commands
sandbox.endingSandbox termination has been initiated
sandbox.endedThe sandbox has fully terminated
sandbox.failedThe sandbox could not be started or crashed
sandbox.pausedThe sandbox has been paused
sandbox.resumedA paused sandbox has been resumed

Sandbox Extension Events

EventFired when
sandbox.opencode.updatedThe opencode runtime state changed
sandbox.browser_preview.updatedThe browser preview state changed
sandbox.handoff.requestedA human handoff was requested
sandbox.handoff.acceptedA human handoff was accepted
sandbox.handoff.completedA human handoff was completed
sandbox.artifacts.updatedSandbox artifacts were updated

Payload Format

Every webhook delivery is a JSON POST with the following structure:

json
{
  "event_type": "session.ready",
  "event_id": "evt_abc123",
  "org_id": "org_xyz",
  "timestamp": 1710000000,
  "data": {
    "resource": {
      "type": "browser_session",
      "id": "sess_abc123"
    }
  }
}

Headers

Each delivery includes the following headers:

HeaderDescription
X-Banata-EventThe event type (e.g. session.ready)
X-Banata-Event-IdUnique event ID for deduplication
X-Banata-Delivery-AttemptAttempt number (1-based)
X-Banata-TimestampUnix timestamp of the delivery
X-Banata-SignatureHMAC-SHA256 signature for verification

Verifying Signatures

Every delivery is signed with your webhook's signing secret using HMAC-SHA256. Always verify the signature before processing the payload.

The X-Banata-Signature header has the format:

typescript
t={timestamp},v1={signature}

To verify:

  1. Extract the timestamp (t) and signature (v1) from the header.
  2. Construct the signed payload: {timestamp}.{request_body}.
  3. Compute the HMAC-SHA256 of the signed payload using your signing secret.
  4. Compare your computed signature with v1.

Example (Node.js)

typescript
import crypto from "crypto";
 
function verifyWebhookSignature(
  payload: string,
  signatureHeader: string,
  secret: string,
): boolean {
  const parts = Object.fromEntries(
    signatureHeader.split(",").map((p) => p.split("=", 2) as [string, string])
  );
 
  const timestamp = parts.t;
  const signature = parts.v1;
 
  if (!timestamp || !signature) return false;
 
  const signedPayload = `${timestamp}.${payload}`;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(signedPayload)
    .digest("hex");
 
  return crypto.timingSafeEqual(
    Buffer.from(signature, "hex"),
    Buffer.from(expected, "hex"),
  );
}

Example (Python)

python
import hmac, hashlib
 
def verify_webhook_signature(payload: str, signature_header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in signature_header.split(","))
    timestamp = parts.get("t", "")
    signature = parts.get("v1", "")
 
    signed_payload = f"{timestamp}.{payload}"
    expected = hmac.new(
        secret.encode(), signed_payload.encode(), hashlib.sha256
    ).hexdigest()
 
    return hmac.compare_digest(signature, expected)

Retry Policy

If your endpoint does not return a 2xx status code, Banata retries the delivery with exponential backoff:

AttemptDelay
1Immediate
25 seconds
330 seconds
42 minutes
510 minutes

After 5 failed attempts, the delivery is marked as permanently failed. You can view failed deliveries and their error messages in the dashboard under Webhooks → Recent Deliveries.


Testing Webhooks

You can send a test delivery from the dashboard:

  1. Go to Webhooks.
  2. Click the ⋯ menu on any webhook endpoint.
  3. Select Send Test.

This sends a test payload with event_type: "session.created" and a webhook_test resource type so your handler can distinguish test deliveries from real ones.

You can also send a test via the API:

bash
curl -X POST "https://api.boxes.banata.dev/v1/webhooks/test" \
  -H "Authorization: Bearer br_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "id": "WEBHOOK_ID" }'

Best Practices

Respond quickly

Return a 200 response as fast as possible. Do heavy processing asynchronously (e.g. push to a queue). Banata waits up to 30 seconds for a response before marking the delivery as failed.

Idempotency

Use the X-Banata-Event-Id header to deduplicate events. The same event may be delivered more than once if your server responds slowly or if a retry is in progress when a success is recorded.

HTTPS only

Webhook URLs must use HTTPS. Banata rejects plain HTTP endpoints.

Monitor delivery health

Check the Webhooks page in the dashboard regularly. If a webhook is consistently failing, Banata shows its status as Failing so you can investigate.


Managing Webhooks via the API

List webhooks

bash
curl "https://api.boxes.banata.dev/v1/webhooks" \
  -H "Authorization: Bearer br_live_YOUR_KEY"

Delete a webhook

bash
curl -X DELETE "https://api.boxes.banata.dev/v1/webhooks?id=WEBHOOK_ID" \
  -H "Authorization: Bearer br_live_YOUR_KEY"

List deliveries

bash
curl "https://api.boxes.banata.dev/v1/webhooks/deliveries?limit=20" \
  -H "Authorization: Bearer br_live_YOUR_KEY"

Next Steps

  • API Keys — Create an API key with org:manage permissions to manage webhooks via the API
  • Browser Sessions — Learn about session lifecycle events
  • Sandboxes — Learn about sandbox lifecycle events
  • API Reference — Full API endpoint documentation