Banata

API Reference

API Reference

Complete HTTP API reference for all Banata browser session, sandbox, billing, and health endpoints.

Base URL: https://api.boxes.banata.dev

All endpoints require a Bearer token in the Authorization header unless noted otherwise:

typescript
Authorization: Bearer br_live_...

Browser Sessions

POST /v1/browsers

Create a new browser session.

Request body:

FieldTypeDefaultDescription
weight"light" | "medium" | "heavy""light"Memory allocation tier
isolation"shared" | "dedicated""shared"Machine sharing mode
egressProfile"shared-dc" | "dedicated-dc" | "rotating-residential" | "static-residential" | "byo-proxy"AutoOutbound IP profile
stealthbooleanfalseEnable anti-detection (Builder+)
recordingbooleanfalseEnable MP4 session recording (Pro+)
captchabooleanfalseEnable auto CAPTCHA solving
maxDurationMsnumberPlan limitPer-session time limit (ms)
proxyobjectYour own proxy server
profileKeystringSaved browser profile key
regionstringPreferred region (3-letter code)

Proxy object:

FieldTypeRequired
protocol"http" | "https" | "socks5"Yes
hoststringYes
portnumberYes
usernamestringNo
passwordstringNo

Response (201):

json
{
  "id": "j57f40gk2nm535kdj49n8e051s81wt6y",
  "status": "queued",
  "cdpUrl": null,
  "weight": "light",
  "isolation": "shared",
  "egressProfile": "shared-dc"
}

Permission: browser_sessions:create Rate limit: 60/min (burst: 20)


GET /v1/browsers

Get session status or list active sessions.

With id — single session:

typescript
GET /v1/browsers?id=SESSION_ID
json
{
  "id": "...",
  "status": "ready",
  "cdpUrl": "wss://...",
  "weight": "light",
  "isolation": "shared",
  "egressProfile": "shared-dc",
  "artifacts": { "screenshots": [], "har": null, "recording": null },
  "duration": null,
  "createdAt": 1772078705353
}

Without id — list active sessions:

typescript
GET /v1/browsers
GET /v1/browsers?limit=50
json
{
  "data": [
    {
      "id": "...",
      "status": "ready",
      "cdpUrl": "wss://...",
      "weight": "light",
      "egressProfile": "shared-dc",
      "createdAt": 1772078705353,
      "startedAt": 1772078708000
    }
  ]
}

limit range: 1–100, default: 25.

Session statuses: queuedassigningreadyactiveendingended | failed

Permission: browser_sessions:read Rate limit: 600/min (burst: 100)


DELETE /v1/browsers?id={sessionId}

End a session and trigger cleanup.

Response (200): { "ok": true }

Permission: browser_sessions:delete Rate limit: 120/min (burst: 30)


Sandbox Sessions

POST /v1/sandboxes

Create a new sandbox session.

Request body:

FieldTypeDefaultDescription
runtime"bun" | "python" | "base""bun"Runtime environment
size"standard""standard"Standard 2 shared vCPU / 4 GB sandbox shape.
envRecord<string, string>Environment variables
ephemeralbooleantrueEphemeral workspace
maxDurationMsnumberPlan limitMax duration (ms, max 7,200,000)
regionstringPreferred region (3-letter code)
capabilitiesobjectAdvanced features (see below)

Capabilities object:

json
{
  "opencode": { "enabled": true, "defaultAgent": "build", "allowPromptApi": true },
  "browser": { "mode": "paired-banata-browser", "recording": true, "persistentProfile": true, "streamPreview": true, "humanInLoop": true },
  "documents": { "libreofficeHeadless": true },
  "storage": { "workspace": "checkpointed", "artifactPrefix": "prefix/" }
}

Response (201):

json
{
  "id": "k82g51hl...",
  "status": "queued",
  "runtime": "bun",
  "size": "standard",
  "capabilities": null
}

Permission: sandbox_sessions:create Rate limit: 60/min (burst: 20)


GET /v1/sandboxes

Get sandbox status or list all sandboxes.

With id: Returns full session details including terminalUrl, capabilities, pairedBrowser, opencode, browserPreview, humanHandoff, artifacts.

If you need a standalone human-viewable browser page, use the SDK’s derived browserPreviewViewerUrl or construct a viewer URL on your app host from the preview metadata. The raw API returns preview transport metadata, not a rendered HTML page.

Without id: Returns { "items": [...] } with all sessions for your org.

Permission: sandbox_sessions:read Rate limit: 600/min (burst: 100)


DELETE /v1/sandboxes?id={sessionId}

End a sandbox session.

Response (200): { "ok": true }

Permission: sandbox_sessions:delete Rate limit: 120/min (burst: 30)


POST /v1/sandboxes/pause

Suspend a sandbox, preserving workspace state.

Body: { "id": "SANDBOX_ID" } Response: { "ok": true } Permission: sandbox_sessions:delete


POST /v1/sandboxes/resume

Resume a paused sandbox.

Body: { "id": "SANDBOX_ID" } Response: { "ok": true } Permission: sandbox_sessions:create


Sandbox Execution

POST /v1/sandboxes/exec

Execute a shell command. Requires ready or active state.

Body: { "id": "...", "command": "...", "args": [...], "timeout": 30000 }

Permission: sandbox_sessions:exec Rate limit: 300/min (burst: 50)


POST /v1/sandboxes/code

Execute a code snippet. Requires ready or active state.

Body: { "id": "...", "code": "...", "timeout": 30000 }

Permission: sandbox_sessions:exec Rate limit: 300/min (burst: 50)


GET /v1/sandboxes/terminal?id={id}

Get WebSocket URL and token for interactive terminal.

Response: { "terminalUrl": "wss://...", "token": "eyJ..." }

Permission: sandbox_sessions:exec Rate limit: 600/min (burst: 100)


Sandbox File System

GET /v1/sandboxes/fs/read?id={id}&path={path}

Read a file from the sandbox.

Permission: sandbox_sessions:exec Rate limit: 300/min (burst: 50)

POST /v1/sandboxes/fs/write

Write a file to the sandbox.

Body: { "id": "...", "path": "...", "content": "..." }

Permission: sandbox_sessions:exec Rate limit: 300/min (burst: 50)

GET /v1/sandboxes/fs/list?id={id}&path={path}

List directory contents. path defaults to /workspace.

Permission: sandbox_sessions:exec Rate limit: 300/min (burst: 50)


Sandbox Browser Preview

GET /v1/sandboxes/browser-preview?id={id}

Get browser preview metadata (requires browser capability).

This returns the raw preview transport metadata used by the dashboard and SDK. It is intended for embedding a viewer or warming the preview backend, not for directly pasting into a browser tab.

Permission: sandbox_sessions:read

POST /v1/sandboxes/browser-preview/control

Switch browser control mode.

Body: { "id": "...", "mode": "human"|"ai"|"shared", "controller": "...", "leaseMs": 300000 }

Permission: sandbox_sessions:exec


Sandbox OpenCode

GET /v1/sandboxes/opencode/state?id={id}

Get the current OpenCode state for a sandbox.

Query: ensureSession=1|true optionally creates an OpenCode session if one does not exist yet. agent=build|plan selects the default agent when ensuring a session.

Permission: sandbox_sessions:read

GET /v1/sandboxes/opencode/messages?id={id}&sessionId={sessionId}

Get the current OpenCode message history.

Permission: sandbox_sessions:read

GET /v1/sandboxes/opencode/events?id={id}&sessionId={sessionId}

Stream OpenCode events as Server-Sent Events (SSE).

This is the recommended primitive if you are building your own OpenCode chat UI. The Banata dashboard uses the same stream to render the chat timeline incrementally.

Permission: sandbox_sessions:read

POST /v1/sandboxes/opencode/prompt-async

Queue an async prompt for OpenCode.

Body: { "id": "...", "prompt": "...", "agent": "build"|"plan", "sessionId": "..." }

Permission: sandbox_sessions:exec Rate limit: 300/min (burst: 50)

POST /v1/sandboxes/opencode/prompt

Send a prompt to the AI agent (requires opencode capability with allowPromptApi not false).

Body: { "id": "...", "prompt": "...", "agent": "build"|"plan", "sessionId": "...", "noReply": false }

Permission: sandbox_sessions:exec Rate limit: 300/min (burst: 50)


Sandbox Human Handoff

GET /v1/sandboxes/handoff?id={id}

Get current handoff state.

Permission: sandbox_sessions:read

POST /v1/sandboxes/handoff/request

Request human intervention.

Body: { "id": "...", "reason": "mfa"|"captcha"|"approval"|"login_failed"|"ambiguous_ui"|"file_download"|"custom", "message": "...", "requestedBy": "sdk", "resumePrompt": "...", "expiresInMs": 300000 }

Permission: sandbox_sessions:exec

POST /v1/sandboxes/handoff/accept

Human accepts control.

Body: { "id": "...", "controller": "...", "leaseMs": 300000 }

Permission: sandbox_sessions:exec

POST /v1/sandboxes/handoff/complete

Human returns control.

Body: { "id": "...", "controller": "...", "note": "...", "returnControlTo": "ai"|"shared", "runResumePrompt": true }

Permission: sandbox_sessions:exec


Sandbox Artifacts

POST /v1/sandboxes/checkpoint

Persist workspace snapshot.

Body: { "id": "..." } Permission: sandbox_sessions:exec

GET /v1/sandboxes/artifacts?id={id}

List artifact pointers.

Permission: sandbox_sessions:read

GET /v1/sandboxes/artifacts/download?id={id}&key={key}&expiresIn={seconds}

Get a signed download URL. expiresIn range: 1–86400, default: 3600.

Response: { "id": "...", "key": "...", "url": "https://signed-url...", "expiresInSeconds": 3600 }

Permission: sandbox_sessions:read


Sandbox Runtime

GET /v1/sandboxes/runtime?id={id}

Get runtime status including capabilities, OpenCode state, browser state, handoff state, and artifacts.

Permission: sandbox_sessions:read


Usage & Billing

GET /v1/usage

Current billing period usage.

json
{
  "totalSessions": 42,
  "totalBrowserHours": 12.5,
  "weightBreakdown": { "light": 20, "medium": 15, "heavy": 7 },
  "periodStart": 1709251200000
}

Permission: org:billing Rate limit: 30/min (burst: 10)


GET /v1/billing

Billing info for your organization.

json
{
  "hasSubscription": true,
  "plan": "pro",
  "polarCustomerId": "cust_abc123",
  "currentPeriod": {
    "totalSessions": 42,
    "totalBrowserHours": 12.5,
    "weightBreakdown": { "light": 20, "medium": 15, "heavy": 7 }
  }
}

Permission: org:billing Rate limit: 30/min (burst: 10)


POST /v1/billing/checkout

Create a checkout session for plan upgrade.

Body:

FieldTypeRequiredDescription
plan"builder" | "pro" | "scale"YesTarget plan
successUrlstringNoHTTPS redirect URL after payment

Response:

json
{
  "checkoutUrl": "https://polar.sh/checkout/...",
  "checkoutId": "checkout_abc123"
}

Permission: org:billing Rate limit: 5/min (burst: 2)


Health

GET /health

System health summary. No authentication required.

json
{
  "status": "healthy",
  "timestamp": 1772078705353,
  "machines": { "running": 3, "total": 5 },
  "sessions": { "active": 2 },
  "errors": { "last5min": 0 }
}
StatusHTTP Code
healthy200
degraded503
unhealthy503

Common Error Codes

CodeMeaning
PLAN_FEATURE_UNAVAILABLEFeature requires a higher plan. Response includes requiredPlan and currentPlan.
PLAN_LIMIT_EXCEEDEDValue exceeds your plan's limit (e.g., maxDurationMs too high).
PERMISSION_DENIEDAPI key lacks the required permission.
SCHEDULING_FAILEDNo machine could be assigned. Includes a reason field.