BrowserBox Platform Reference

REST API and embed reference

BrowserBox exposes two integration layers: REST endpoints for session lifecycle and the <browserbox-webview> element for in-session control. This page documents both using current method and event names from the canonical implementation.

Base endpoint

https://win9-5.com

All REST endpoints return JSON.

Authentication

Send Authorization: Bearer <api_key> on protected endpoints.

Embed contract

Set login-link on <browserbox-webview> (not src).

Quickstart

  1. Create a paid session with POST /api/v1/sessions and store login_url.
  2. Provide one routing hint: region, clientIP, or lat + lon.
  3. If you will embed in an iframe, include allowedEmbeddingOrigins at claim time.
  4. Render <browserbox-webview login-link="..."> in your application UI.
  5. Await whenReady(), then use tab/navigation/automation methods.
const session = await fetch('https://win9-5.com/api/v1/sessions', { method: 'POST', headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json', 'Idempotency-Key': 'sess-create-001' }, body: JSON.stringify({ minutes: 15, region: 'na-east', allowedEmbeddingOrigins: ['https://app.example.com'] }) }).then((r) => r.json()); const bbx = document.querySelector('browserbox-webview'); bbx.setAttribute('login-link', session.login_url); await bbx.whenReady();

Authentication

Include your API key with each protected request:

curl -H "Authorization: Bearer bbx_your_api_key_here" \ https://win9-5.com/api/v1/balance
  • Keys are issued after minute-pack purchase.
  • Prefix: bbx_.
  • Support: api@browserbox.io

REST Endpoints

POST /api/v1/sessions

Create an isolated paid browser session and deduct allocated minutes.

Request body

FieldTypeRequiredDescription
minutesnumberNoDefaults to 15, max 120.
regionstringConditionalLogical region hint such as na-east, eu-west, or ap-southeast.
clientIPstringConditionalPublic client IPv4/IPv6 address used for geo-routing. You may also send client_ip.
latnumberConditionalLatitude for geo-routing when you do not send region.
lonnumberConditionalLongitude for geo-routing when you do not send region.
allowedEmbeddingOriginsstring[]NoClaim-time iframe embedding allowlist for paid sessions. Accepts exact origins or patterns such as https://app.example.com, https://*.customer.example, or https://*.customer.example:*. Paths, query strings, fragments, and credentials are rejected.

One of region, clientIP, or lat + lon is required.

If you reuse an Idempotency-Key, allowedEmbeddingOrigins must remain identical or the server returns 409 idempotency_conflict.

Example

curl -X POST https://win9-5.com/api/v1/sessions \ -H "Authorization: Bearer bbx_abc123..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: sess-create-001" \ -d '{ "minutes": 15, "region": "na-east", "allowedEmbeddingOrigins": ["https://app.example.com"] }'

Response (201 created / 200 idempotent replay)

{ "id": "cc57975684b942fc...", "provider": "fly", "region": "na-east", "machine_id": "68365e2c721798", "login_url": "https://bbx-iad.fly.dev/login?token=...&mid=68365e2c721798", "duration_minutes": 15, "created_at": 1770611914916, "expires_at": 1770612814916 }
GET /api/v1/sessions/:id

Retrieve stored session metadata for the authenticated API key.

Example

curl https://win9-5.com/api/v1/sessions/cc57975684b942fc... \ -H "Authorization: Bearer bbx_abc123..."

Response (200)

{ "id": "cc57975684b942fc...", "provider": "fly", "region": "na-east", "machine_id": "68365e2c721798", "login_url": "https://bbx-iad.fly.dev/login?token=...&mid=68365e2c721798", "duration_minutes": 15, "created_at": 1770611914916, "expires_at": 1770612814916, "deleted_at": null }
DELETE /api/v1/sessions/:id

End a session and return unused minutes to your account balance.

Example

curl -X DELETE https://win9-5.com/api/v1/sessions/cc57975684b942fc... \ -H "Authorization: Bearer bbx_abc123..."

Response (200)

{ "id": "cc57975684b942fc...", "status": "ended", "refunded_minutes": 12 }
GET /api/v1/balance

Return current minute balance and account metadata.

Example

curl https://win9-5.com/api/v1/balance \ -H "Authorization: Bearer bbx_abc123..."
GET /api/v1/pricing

List minute packs and defaults. No authentication required.

Example

curl https://win9-5.com/api/v1/pricing
POST /api/v1/checkout

Create a Stripe Checkout URL for minute-pack purchases. No API key required.

Request body

FieldTypeRequiredDescription
productstringYesminutes_60, minutes_300, minutes_1000, subscription
emailstringNoPrefill customer email in checkout.

Example

curl -X POST https://win9-5.com/api/v1/checkout \ -H "Content-Type: application/json" \ -d '{"product":"minutes_300","email":"you@example.com"}'

Demo Session Endpoints

Cookie-authenticated endpoints for the hosted demo. No API key required — sessions are tracked via a bbx_sid cookie, and browser POSTs must come from the same origin or a server-configured trusted origin.

allowedEmbeddingOrigins is not accepted on demo session creation. Claim-time embedder overrides are available only on paid /api/v1/sessions requests.

POST /api/session

Create a demo browser session. If an active session already exists for the cookie, it is returned instead. Sessions last up to 15 minutes.

Example

curl -X POST https://win9-5.com/api/session \ -H "Content-Type: application/json" \ --cookie "bbx_sid=..."

Response (201 created / 200 existing)

{ "id": "cc57975684b942fc...", "provider": "fly", "region": "iad", "machine_id": "68365e2c721798", "login_url": "https://bbx-iad.fly.dev/login?token=...&mid=68365e2c721798", "duration_minutes": 15, "created_at": 1770611914916, "expires_at": 1770612814916 }
GET /api/session/status

Lightweight session liveness check. Returns whether the cookie holder has an active session. Useful for resuming UI state after a page reload or browser reopen.

Example

curl https://win9-5.com/api/session/status \ --cookie "bbx_sid=..."

Response (200) — active session

{ "active": true, "id": "cc57975684b942fc...", "provider": "fly", "region": "iad", "machine_id": "68365e2c721798", "login_url": "https://bbx-iad.fly.dev/login?token=...&mid=68365e2c721798", "duration_minutes": 15, "created_at": 1770611914916, "expires_at": 1770612814916 }

Response (200) — no active session

{ "active": false }
POST /api/session/disconnect

Signal that the client is leaving. Supports defer (mark disconnected, allow grace-period reconnect) or hard (immediate teardown).

Request body

FieldTypeRequiredDescription
modestringNodefer (default) or hard.
sessionIdstringNoTarget a specific session. Omit to affect all sessions for this cookie.

Example

curl -X POST https://win9-5.com/api/session/disconnect \ -H "Content-Type: application/json" \ --cookie "bbx_sid=..." \ -d '{"mode":"defer"}'

Response (200)

{ "ok": true, "mode": "defer", "ended": 0, "marked": 1 }

Error Model

Errors return JSON with an error field and may include extra context keys.

{ "error": "Provide clientIP, or region (global code), or lat+lon for geo-routing", "code": "missing_region" }
StatusMeaning
400Invalid input, invalid JSON, or missing routing data.
401Missing or invalid API key.
402Insufficient minute balance.
404Session not found.
409Idempotency-Key reused with different request semantics, including different allowedEmbeddingOrigins.
429Concurrent paid-session limit reached.
503No BrowserBox capacity available right now.

Embedding with <browserbox-webview>

Load the canonical component script and set login-link to the login_url returned by POST /api/v1/sessions.

If the page embedding the iframe is not one of BrowserBox's built-in defaults, include that page origin in allowedEmbeddingOrigins when you claim the paid session. The allowlist is applied at claim time.

<script src="https://win9-5.com/browserbox-webview.js" type="module"></script> <browserbox-webview login-link="https://bbx-instance.run.app/login?token=..." width="100%" height="600" request-timeout-ms="30000" ></browserbox-webview> <script> const bbx = document.querySelector('browserbox-webview'); await bbx.whenReady(); await bbx.navigateTo('https://example.com'); </script>
Attributes
AttributeTypeDefaultDescription
login-linkstringnoneRequired login URL with session token.
widthstring/number100%Component width. Bare numbers are interpreted as px.
heightstring/number100%Component height. Bare numbers are interpreted as px.
parent-originstring*Origin check for postMessage input validation.
request-timeout-msnumber30000Per-call timeout floor is 100ms.
ui-visiblebooleantrueShow or hide BrowserBox chrome UI.
allow-user-toggle-uibooleantrueAllow end user to toggle UI visibility.
chromestringdefaultChrome presentation hint: none, minimal, default, custom.
augment-rootstringopenAugment inspectability hint: open or closed.
capturestringsnapshotCapture policy hint: off, snapshot, sampled.
Properties
PropertyMaps toNotes
loginLinklogin-linkSet/remove source URL.
routingMidderivedRead-only resolved routing machine id.
widthwidthString values preserved.
heightheightString values preserved.
parentOriginparent-originDefaults to wildcard.
requestTimeoutMsrequest-timeout-msParsed as integer.
Events

Lifecycle and transport events

EventDetail payloadDescription
ready{ type }Legacy handshake completed.
api-ready{ methods: string[], policy?: PolicySnapshot }Modern API handshake completed and may include the current server policy snapshot.
ready-timeout{ timeoutMs, error }Soft timeout while awaiting readiness.
disconnected{}Session disconnected or source changed.
iframe-retry{ attempt, maxAttempts, delayMs }Automatic iframe reload retry in progress.
mid-synced{ mid, attempts }Routing-mid synchronization succeeded.
mid-sync-timeout{ attempts, mid }Routing-mid synchronization timed out.
usability-changed{ usable, reason }Browser usability state changed.

Runtime forwarded events

EventDetail payload (typical)Description
tab-created{ index, id, url }Tab creation observed.
tab-closed{ index, id }Tab close observed.
tab-updated{ id, url, title, faviconDataURI }Tab metadata changed.
active-tab-changed{ index, id }Active tab changed.
did-start-loading{ tabId, url }Navigation started loading.
did-stop-loading{ tabId, url }Navigation stopped loading.
did-navigate{ tabId, url }Navigation committed.
policy-denied{ url, reason }Policy blocked requested action.
policy.changed{ reason, policy, capabilities }Effective policy and capability set changed.
favicon-changed{ ... }Favicon metadata updated.
sos{ reasonCode, message, retryUrl }Fatal unusable signal from embedded BrowserBox.
Methods

Lifecycle and generic dispatch

MethodDescription
whenReady({ timeoutMs })Wait for handshake readiness.
listApiMethods(options?)Return available remote methods.
callApi(method, ...args)Generic method dispatcher.
refresh()Hard reload iframe and reset transport state.
updateIframe()Recompute routing MID, apply login-link, and re-apply dimensions.
stopReconnectAttempts(reason?)Stop retry loop and reject pending calls.

Tabs and navigation

MethodDescription
getTabs(), getTabCount(), getActiveTabIndex()Tab inspection helpers.
createTab(url?), createTabs(count, opts?)Create one or many tabs.
closeTab(index?), closeTabById(targetId), closeAllTabs(opts?)Close tab(s) by index or target id.
switchToTab(index), switchToTabById(targetId)Switch active tab.
navigateTo(url, opts?), navigateTab(index, url, opts?)Navigate active or selected tab.
submitOmnibox(query, opts?)Submit URL or search query.
reload(), goBack(), goForward(), stop()Standard browser navigation controls.

Waiting and diagnostics

MethodDescription
waitForTabCount(count, opts?), waitForTabUrl(index, opts?)Polling helpers for tab convergence and URL matching.
getFavicons(), waitForNonDefaultFavicon(index, opts?)Favicon metadata helpers.
getScreenMetrics(), getTransportDiagnostics()Viewport/transport diagnostics.
health({ timeoutMs }?)Return a structured health report with readiness, transport, latency, and last-error diagnostics.

Automation

MethodDescription
click(selector, opts?)Click an element by CSS selector. Waits for the selector first by default.
type(selector, text, opts?)Type text into a matched element. Waits for the selector first.
evaluate(expression, opts?)Evaluate a JavaScript expression in the active tab and return the result.
waitForSelector(selector, opts?)Wait for a CSS selector to appear in the DOM (polls with exponential backoff).
waitForNavigation(opts?)Wait for the current navigation to complete.

Unified action dispatch

MethodDescription
act({ navigate: url })Navigate the active tab.
act({ click: { selector, ...opts } })Click an element by CSS selector.
act({ type: { selector, text, ...opts } })Type text into a matched element.
act({ evaluate: expression })Evaluate a JavaScript expression in the page.
act({ waitForSelector: { selector, ...opts } })Wait for a CSS selector to appear.
act({ waitForNavigation: opts })Wait for navigation to complete. Returns { ok, action, value }.

UI controls

MethodDescription
uiVisible(visible?)Show or hide the BrowserBox chrome UI. Returns current visibility state.
allowUserToggleUI(allow?)Allow or deny the user from toggling UI visibility.
Namespaced API (Session Host)

The element exposes a namespaced session-host API alongside the classic flat methods. Access via bbx.session, bbx.tabs, etc.

session

Property / MethodDescription
session.idRead-only routing machine id.
session.usableRead-only browser usability flag.
session.transportRead-only transport mode (modern, legacy, unknown).
session.readyRead-only readiness flag.
session.health()Return { ok, usable, ready, transport, sessionId, timestamp, latencyMs, diagnostics }.
session.refresh()Hard reload and reset transport.
session.disconnect()Explicit session teardown.
session.capabilities()Return current effective capabilities map.

tabs

MethodDescription
tabs.list()Return all tabs with normalized metadata.
tabs.getActive()Return the active tab info.
tabs.create({ url, active })Create a tab, optionally without activating it.
tabs.activate(tabId)Switch to tab by id.
tabs.close(tabId)Close tab by id.
tabs.closeAll()Close all tabs.

page

MethodDescription
page.navigate(url)Navigate the active tab.
page.reload(), page.back(), page.forward(), page.stop()Standard navigation controls.
page.url(), page.title(), page.favicon()Active-tab metadata.
page.metrics()Normalized viewport/document metrics.
page.text({ mainContentOnly })Extract visible page text.

capture

MethodDescription
capture.frame({ format, quality })Capture the current rendered frame as a data URL.
capture.viewport({ format, quality })Capture the viewport as a data URL.

augment (capability-gated)

MethodDescription
augment(spec)Create an overlay (sidebar, toolbar, toast, highlight, custom). Typed content is preferred: { type: 'text'|'html'|'json', ... }. Returns a handle with update() and remove().
augment.update(id, patch)Update an existing augment.
augment.remove(id)Remove an augment.
augment.list()List all active augments.

select (capability-gated)

MethodDescription
select({ prompt, intent })Enter interactive pick mode. getRaw() returns { selector, selectors, text, href, htmlSnippet }; generalized previews/extracts return normalized selector results.

policy

MethodDescription
policy.get()Return the merged effective policy snapshot. Server policy is authoritative; embedder attributes can only further restrict it.

Event helpers

MethodDescription
on(eventName, handler)Subscribe to events. Returns an unsubscribe function.
off(eventName, handler)Unsubscribe from events.
observe(config)Create a structured observer with filter config. Returns { id, config, on, off, unsubscribe }.
events(config)Async iterator yielding { id, type, timestamp, sessionId, tabId?, detail }.

Canonical event aliases

Legacy event names continue to work. New canonical dot-notation names are also emitted:

Legacy nameCanonical alias
api-readyapi.ready
tab-createdtab.created
tab-closedtab.closed
tab-updatedtab.updated
active-tab-changedtab.activated
did-navigatepage.navigated
did-start-loadingpage.load.started
did-stop-loadingpage.load.stopped
policy-deniedpolicy.denied
policy.changedpolicy.changed
usability-changedsession.usability.changed
disconnectedsession.disconnected

Transport behavior

The component probes modern RPC first (bbx-api-call). If unavailable, it falls back to legacy message types and emulates compatibility for core tab/navigation operations. Use session.capabilities() or listApiMethods() for capability-based branching.

Advanced surfaces (augment, capture, select) are capability-gated and disabled by default. Enable them by setting the corresponding policy attributes or using interaction-mode presets.

Server policy is pushed over the existing BrowserBox runtime/meta path into the iframe, included in the initial bbx-api-ready handshake, and forwarded mid-session as bbx-policy-sync. The webview merges that authoritative snapshot with local attribute policy and emits policy.changed when capabilities change.

Error model

Public API failures use stable BrowserBoxError codes: ERR_NOT_READY, ERR_POLICY_DENIED, ERR_TIMEOUT, ERR_TRANSPORT, ERR_UNSUPPORTED, ERR_INVALID_ARGUMENT, ERR_NOT_FOUND, ERR_CONFLICT, and ERR_INTERNAL. Errors may also include status and retriable.

Test coverage

55/55 tests passing (2026-03-09) across session, tabs, page, navigation, automation (click, waitForSelector, evaluate, act), capture, diagnostics, policy, augment, events, and observer APIs.