API Reference
Complete reference for the BabelWrap REST API. Manage browser sessions, perform actions with natural language, and track usage.
Base URL & Authentication
Base URL
https://api.babelwrap.com/v1
Authentication
All API requests (except /v1/health) require a Bearer token in the Authorization header:
Authorization: Bearer bw_your_api_key_here
bw_ and should be kept secret.Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /v1/sessions | Create a browser session |
| GET | /v1/sessions/{id} | Get session info |
| DEL | /v1/sessions/{id} | Close session |
| POST | /v1/sessions/{id}/navigate | Navigate to URL |
| POST | /v1/sessions/{id}/snapshot | Read current page |
| POST | /v1/sessions/{id}/click | Click element |
| POST | /v1/sessions/{id}/fill | Fill input field |
| POST | /v1/sessions/{id}/submit | Submit form |
| POST | /v1/sessions/{id}/extract | Extract structured data |
| POST | /v1/sessions/{id}/screenshot | Take screenshot |
| POST | /v1/sessions/{id}/press | Press keyboard key |
| POST | /v1/sessions/{id}/upload | Upload file to input |
| POST | /v1/sessions/{id}/hover | Hover over element |
| POST | /v1/sessions/{id}/back | Navigate back |
| POST | /v1/sessions/{id}/forward | Navigate forward |
| POST | /v1/sessions/{id}/scroll | Scroll page |
| POST | /v1/sessions/{id}/wait_for | Wait for condition |
| POST | /v1/sessions/{id}/batch | Execute multiple actions |
| GET | /v1/sessions/{id}/pages | List open pages |
| POST | /v1/sessions/{id}/switch_page | Switch tab |
| POST | /v1/sessions/{id}/cookies | Add cookies |
| GET | /v1/sessions/{id}/history | Get action history |
| GET | /v1/usage | Get usage stats |
| GET | /v1/health | Health check (no auth) |
Sessions
Sessions represent isolated browser contexts. Each session has its own cookies, localStorage, and page state. All browser interactions happen within a session.
Create Session
Create a new browser session. The session is immediately active and ready for actions.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
metadata | object | No | Arbitrary key-value labels for this session (e.g., {"label": "checkout-flow"}) |
Response 201 Created
{
"session_id": "d4e5f6a7-1234-5678-9abc-def012345678",
"status": "active",
"created_at": "2026-04-03T10:00:00Z",
"expires_at": "2026-04-03T11:00:00Z"
}
| Field | Type | Description |
|---|---|---|
session_id | string (uuid) | Unique identifier for the session |
status | string | Always "active" on creation |
created_at | string (ISO 8601) | When the session was created |
expires_at | string (ISO 8601) | When the session will expire if no actions are taken (default: 1 hour) |
Errors
| Status | Code | Description |
|---|---|---|
429 | session_limit_exceeded | You have reached your plan's concurrent session limit |
429 | rate_limited | Too many requests. Wait and retry. |
Examples
curl -X POST https://api.babelwrap.com/v1/sessions \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"metadata": {"label": "my-flow"}}'
import httpx
resp = await client.post(
"https://api.babelwrap.com/v1/sessions",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"metadata": {"label": "my-flow"}},
)
session_id = resp.json()["session_id"]
const resp = await fetch("https://api.babelwrap.com/v1/sessions", {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ metadata: { label: "my-flow" } }),
});
const { session_id } = await resp.json();
Get Session
Retrieve the current state of a session.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
session_id | string (uuid) | The session ID |
Response 200 OK
{
"session_id": "d4e5f6a7-1234-5678-9abc-def012345678",
"status": "active",
"current_url": "https://example.com/dashboard",
"created_at": "2026-04-03T10:00:00Z",
"last_active": "2026-04-03T10:05:23Z",
"expires_at": "2026-04-03T11:05:23Z",
"metadata": { "label": "my-flow" }
}
| Field | Type | Description |
|---|---|---|
session_id | string (uuid) | Unique identifier |
status | string | One of: active, closed, expired, error |
current_url | string or null | The URL the session is currently on, or null if no navigation has occurred |
created_at | string (ISO 8601) | When the session was created |
last_active | string (ISO 8601) | When the last action was performed |
expires_at | string (ISO 8601) | When the session will expire (resets on each action) |
metadata | object or null | User-defined labels |
Errors
| Status | Code | Description |
|---|---|---|
404 | session_not_found | The session does not exist or belongs to another user |
Examples
curl https://api.babelwrap.com/v1/sessions/d4e5f6a7-1234-5678-9abc-def012345678 \
-H "Authorization: Bearer $BABELWRAP_API_KEY"
resp = await client.get(
f"https://api.babelwrap.com/v1/sessions/{session_id}",
headers={"Authorization": f"Bearer {API_KEY}"},
)
session = resp.json()
print(f"Status: {session['status']}, URL: {session['current_url']}")
const resp = await fetch(
`https://api.babelwrap.com/v1/sessions/${session_id}`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
);
const session = await resp.json();
console.log(`Status: ${session.status}, URL: ${session.current_url}`);
Close Session
Close a session and release all associated browser resources. The session's browser context, cookies, and page state are permanently destroyed.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
session_id | string (uuid) | The session ID to close |
Response 200 OK
{
"success": true,
"session_id": "d4e5f6a7-1234-5678-9abc-def012345678"
}
Errors
| Status | Code | Description |
|---|---|---|
404 | session_not_found | The session does not exist or belongs to another user |
Examples
curl -X DELETE https://api.babelwrap.com/v1/sessions/d4e5f6a7-1234-5678-9abc-def012345678 \
-H "Authorization: Bearer $BABELWRAP_API_KEY"
resp = await client.delete(
f"https://api.babelwrap.com/v1/sessions/{session_id}",
headers={"Authorization": f"Bearer {API_KEY}"},
)
print(resp.json()["success"]) # True
const resp = await fetch(
`https://api.babelwrap.com/v1/sessions/${session_id}`,
{ method: "DELETE", headers: { Authorization: `Bearer ${API_KEY}` } }
);
const { success } = await resp.json();
Session Lifecycle
Created (POST /sessions)
|
v
Active <--- each action resets expiry timer
|
+---> Closed (DELETE /sessions/:id) - manual cleanup
|
+---> Expired (auto, after 1h inactivity) - automatic cleanup
|
+---> Error (unrecoverable browser failure)
- Active: The session is ready for actions. Each action resets the expiration timer to 1 hour from now.
- Closed: The session was manually closed via
DELETE. Resources have been freed. - Expired: The session was automatically closed after 1 hour of inactivity.
- Error: The session's browser context encountered an unrecoverable error. Create a new session.
Actions
All action endpoints operate within a session and return a standard response envelope. Every action returns a snapshot of the current page state after the action completes, so the caller always knows what the page looks like.
Standard Response Envelope
All action endpoints (except extract and screenshot, which extend it) return this structure:
{
"action_id": "a1b2c3d4-5678-9abc-def0-123456789abc",
"success": true,
"duration_ms": 340,
"snapshot": {
"url": "https://example.com",
"title": "Example Page",
"content": "...",
"inputs": [],
"actions": [],
"navigation": [],
"alerts": [],
"forms": []
},
"error": null
}
| Field | Type | Description |
|---|---|---|
action_id | string (uuid) | Unique identifier for this action |
success | boolean | Whether the action completed successfully |
duration_ms | integer | How long the action took in milliseconds |
snapshot | object | Structured snapshot of the page after the action (see Snapshot Format) |
error | string or null | Error message if success is false |
Common Action Errors
All action endpoints may return these errors:
| Status | Code | Description |
|---|---|---|
404 | session_not_found | Session does not exist or belongs to another user |
410 | session_expired | Session has expired or been closed |
429 | usage_limit_exceeded | Monthly action limit reached |
429 | rate_limited | Too many requests |
Navigate
Navigate to a URL. The browser loads the page and returns a snapshot of the result.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | The URL to navigate to. Must include protocol (e.g., https://). Max 2048 characters. |
Response 200 OK
Standard action envelope with snapshot of the loaded page.
{
"action_id": "a1b2c3d4-5678-9abc-def0-123456789abc",
"success": true,
"duration_ms": 1240,
"snapshot": {
"url": "https://news.ycombinator.com",
"title": "Hacker News",
"content": "Hacker News new | past | comments | ask | show ...",
"inputs": [],
"actions": [
{ "id": "story-1", "label": "Show HN: BabelWrap", "type": "link" }
],
"navigation": ["new", "past", "comments", "ask", "show", "jobs"],
"alerts": [],
"forms": []
},
"error": null
}
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/navigate" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://news.ycombinator.com"}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/navigate",
headers=HEADERS,
json={"url": "https://news.ycombinator.com"},
)
snapshot = resp.json()["snapshot"]
print(f"Title: {snapshot['title']}")
const resp = await fetch(`${BASE}/sessions/${session_id}/navigate`, {
method: "POST",
headers,
body: JSON.stringify({ url: "https://news.ycombinator.com" }),
});
const { snapshot } = await resp.json();
console.log(`Title: ${snapshot.title}`);
Snapshot
Get the current page state without performing any action. Useful for re-reading a page or checking what changed.
Request Body
Empty ({}). No parameters required.
Response 200 OK
Standard action envelope with snapshot of the current page.
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/snapshot" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/snapshot",
headers=HEADERS,
json={},
)
snapshot = resp.json()["snapshot"]
const resp = await fetch(`${BASE}/sessions/${session_id}/snapshot`, {
method: "POST",
headers,
body: JSON.stringify({}),
});
const { snapshot } = await resp.json();
Click
Click an element on the page identified by a natural language description. BabelWrap uses LLM-assisted resolution to match your description to the correct element.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
target | string | Yes | Natural language description of the element to click. Max 500 characters. |
"the Login button""first search result""Next page link""the Add to Cart button for Wireless Headphones"
Response 200 OK
Standard action envelope with snapshot of the page after clicking.
Additional Errors
| Status | Code | Description |
|---|---|---|
422 | target_not_found | No element matching the description was found |
422 | ambiguous_target | Multiple elements match. Response includes candidates list. |
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/click" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"target": "the Sign In button"}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/click",
headers=HEADERS,
json={"target": "the Sign In button"},
)
snapshot = resp.json()["snapshot"]
const resp = await fetch(`${BASE}/sessions/${session_id}/click`, {
method: "POST",
headers,
body: JSON.stringify({ target: "the Sign In button" }),
});
const { snapshot } = await resp.json();
Ambiguous Target Error Example
{
"error": {
"code": "ambiguous_target",
"message": "Multiple elements match 'Submit button'. Please be more specific.",
"candidates": [
{ "id": "submit-form-1", "label": "Submit Application", "type": "button" },
{ "id": "submit-form-2", "label": "Submit Feedback", "type": "button" }
]
}
}
Fill
Fill an input field with a value. The field is identified by a natural language description.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
target | string | Yes | Natural language description of the input field. Max 500 characters. |
value | string | Yes | The value to fill in. Max 10,000 characters. |
Response 200 OK
Standard action envelope with snapshot showing the field's updated value.
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/fill" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"target": "Email address field", "value": "alice@example.com"}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/fill",
headers=HEADERS,
json={"target": "Email address field", "value": "alice@example.com"},
)
snapshot = resp.json()["snapshot"]
# Verify the field was filled
email_input = next(i for i in snapshot["inputs"] if "email" in i["label"].lower())
print(f"Email value: {email_input['value']}")
const resp = await fetch(`${BASE}/sessions/${session_id}/fill`, {
method: "POST",
headers,
body: JSON.stringify({
target: "Email address field",
value: "alice@example.com",
}),
});
const { snapshot } = await resp.json();
Submit
Submit a form on the current page. If target is omitted, BabelWrap submits the most prominent form.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
target | string | No | Natural language description of which form to submit. If omitted, submits the most prominent form. |
Response 200 OK
Standard action envelope with snapshot of the resulting page (which may be a new page if the form triggers navigation).
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/submit" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"target": "the login form"}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/submit",
headers=HEADERS,
json={"target": "the login form"},
)
snapshot = resp.json()["snapshot"]
print(f"Redirected to: {snapshot['url']}")
const resp = await fetch(`${BASE}/sessions/${session_id}/submit`, {
method: "POST",
headers,
body: JSON.stringify({ target: "the login form" }),
});
const { snapshot } = await resp.json();
console.log(`Redirected to: ${snapshot.url}`);
submit with no target to submit the default form. This is useful on pages with a single prominent form like login or search.Extract
Extract structured data from the current page using a natural language query. Returns both the extracted data and a page snapshot.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
query | string | Yes | Natural language description of what data to extract. Max 2,000 characters. |
Response 200 OK
Extended action envelope with an additional data field:
{
"action_id": "f6a7b8c9-abcd-ef01-2345-6789abcdef01",
"success": true,
"duration_ms": 450,
"data": [
{ "name": "Widget A", "price": "$29.99" },
{ "name": "Widget B", "price": "$49.99" }
],
"snapshot": { /* ... */ },
"error": null
}
| Field | Type | Description |
|---|---|---|
data | array or object | The extracted structured data. Usually an array of objects, but may be a single object for scalar queries. |
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/extract" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "all product names and prices"}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/extract",
headers=HEADERS,
json={"query": "all product names and prices"},
)
products = resp.json()["data"]
for product in products:
print(f"{product['name']}: {product['price']}")
const resp = await fetch(`${BASE}/sessions/${session_id}/extract`, {
method: "POST",
headers,
body: JSON.stringify({ query: "all product names and prices" }),
});
const { data: products } = await resp.json();
products.forEach((p) => console.log(`${p.name}: ${p.price}`));
Screenshot
Take a screenshot of the current page. Returns a base64-encoded PNG image. Intended for debugging.
Request Body
Empty ({}). No parameters required.
Response 200 OK
Extended action envelope with an additional image field:
{
"action_id": "a7b8c9d0-bcde-f012-3456-789abcdef012",
"success": true,
"duration_ms": 320,
"image": "iVBORw0KGgoAAAANSUhEUgAAA...",
"snapshot": { /* ... */ },
"error": null
}
| Field | Type | Description |
|---|---|---|
image | string | Base64-encoded PNG screenshot of the page |
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/screenshot" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{}' | jq -r '.image' | base64 --decode > screenshot.png
import base64
resp = await client.post(
f"{BASE}/sessions/{session_id}/screenshot",
headers=HEADERS,
json={},
)
image_b64 = resp.json()["image"]
with open("screenshot.png", "wb") as f:
f.write(base64.b64decode(image_b64))
const resp = await fetch(`${BASE}/sessions/${session_id}/screenshot`, {
method: "POST",
headers,
body: JSON.stringify({}),
});
const { image } = await resp.json();
// image is base64-encoded PNG
const buffer = Buffer.from(image, "base64");
await fs.writeFile("screenshot.png", buffer);
Press
Press a keyboard key. Useful for submitting forms with Enter, navigating with Tab, dismissing dialogs with Escape, or interacting with custom keyboard shortcuts.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
key | string | Yes | Key to press (e.g., Enter, Tab, Escape, ArrowDown, ArrowUp, Backspace) |
Response 200 OK
Standard action envelope with snapshot of the page after the key press.
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/press" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"key": "Enter"}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/press",
headers=HEADERS,
json={"key": "Enter"},
)
snapshot = resp.json()["snapshot"]
const resp = await fetch(`${BASE}/sessions/${session_id}/press`, {
method: "POST",
headers,
body: JSON.stringify({ key: "Enter" }),
});
const { snapshot } = await resp.json();
Upload
Upload a file to a file input field on the page. The file is provided as base64-encoded content and matched to the target input element using natural language.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
target | string | Yes | Description of the file input field. Max 500 characters. |
file_base64 | string | Yes | Base64-encoded file content |
filename | string | Yes | Name of the file with extension (e.g., report.pdf) |
Response 200 OK
Standard action envelope with snapshot of the page after the file is attached.
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/upload" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"target": "the resume upload field",
"file_base64": "JVBERi0xLjQgMSAwIG9i...",
"filename": "resume.pdf"
}'
import base64
with open("resume.pdf", "rb") as f:
file_b64 = base64.b64encode(f.read()).decode()
resp = await client.post(
f"{BASE}/sessions/{session_id}/upload",
headers=HEADERS,
json={
"target": "the resume upload field",
"file_base64": file_b64,
"filename": "resume.pdf",
},
)
snapshot = resp.json()["snapshot"]
const fs = await import("fs/promises");
const fileBuffer = await fs.readFile("resume.pdf");
const fileBase64 = fileBuffer.toString("base64");
const resp = await fetch(`${BASE}/sessions/${session_id}/upload`, {
method: "POST",
headers,
body: JSON.stringify({
target: "the resume upload field",
file_base64: fileBase64,
filename: "resume.pdf",
}),
});
const { snapshot } = await resp.json();
Hover
Hover over an element on the page. Useful for revealing tooltips, dropdown menus, or triggering hover states.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
target | string | Yes | Natural language description of the element to hover over. Max 500 characters. |
Response 200 OK
Standard action envelope with snapshot of the page after hovering (may include newly visible tooltips or menus).
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/hover" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"target": "the user avatar in the top right"}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/hover",
headers=HEADERS,
json={"target": "the user avatar in the top right"},
)
snapshot = resp.json()["snapshot"]
# Check for newly visible dropdown menu
const resp = await fetch(`${BASE}/sessions/${session_id}/hover`, {
method: "POST",
headers,
body: JSON.stringify({ target: "the user avatar in the top right" }),
});
const { snapshot } = await resp.json();
Back
Navigate back in the browser history, equivalent to clicking the browser's back button.
Request Body
Empty ({}). No parameters required.
Response 200 OK
Standard action envelope with snapshot of the previous page.
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/back" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/back",
headers=HEADERS,
json={},
)
snapshot = resp.json()["snapshot"]
print(f"Back to: {snapshot['url']}")
const resp = await fetch(`${BASE}/sessions/${session_id}/back`, {
method: "POST",
headers,
body: JSON.stringify({}),
});
const { snapshot } = await resp.json();
console.log(`Back to: ${snapshot.url}`);
Forward
Navigate forward in the browser history, equivalent to clicking the browser's forward button.
Request Body
Empty ({}). No parameters required.
Response 200 OK
Standard action envelope with snapshot of the next page in history.
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/forward" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/forward",
headers=HEADERS,
json={},
)
snapshot = resp.json()["snapshot"]
print(f"Forward to: {snapshot['url']}")
const resp = await fetch(`${BASE}/sessions/${session_id}/forward`, {
method: "POST",
headers,
body: JSON.stringify({}),
});
const { snapshot } = await resp.json();
console.log(`Forward to: ${snapshot.url}`);
Scroll
Scroll the page up or down. Useful for loading lazy content, reaching elements below the fold, or navigating long pages.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
direction | string | No | Scroll direction: "up" or "down". Default: "down". |
amount | string | No | Scroll amount: "page", "half", or a pixel count (e.g., "500"). Default: "page". |
Response 200 OK
Standard action envelope with snapshot of the page after scrolling (content may have changed if lazy-loading is present).
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/scroll" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"direction": "down", "amount": "page"}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/scroll",
headers=HEADERS,
json={"direction": "down", "amount": "half"},
)
snapshot = resp.json()["snapshot"]
const resp = await fetch(`${BASE}/sessions/${session_id}/scroll`, {
method: "POST",
headers,
body: JSON.stringify({ direction: "down", amount: "half" }),
});
const { snapshot } = await resp.json();
Wait For
Wait for a condition to be met before returning. Useful for waiting on dynamic content, AJAX responses, or navigation changes. Provide at least one of text, selector, or url_contains.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
text | string | No | Wait for this text to appear on the page |
selector | string | No | Wait for a CSS selector to be present in the DOM |
url_contains | string | No | Wait for the URL to contain this string |
timeout_ms | integer | No | Maximum time to wait in milliseconds. Default: 10000 (10 seconds). |
Response 200 OK
Standard action envelope with snapshot of the page once the condition is met.
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/wait_for" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "Results loaded", "timeout_ms": 5000}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/wait_for",
headers=HEADERS,
json={"text": "Results loaded", "timeout_ms": 5000},
)
snapshot = resp.json()["snapshot"]
const resp = await fetch(`${BASE}/sessions/${session_id}/wait_for`, {
method: "POST",
headers,
body: JSON.stringify({ text: "Results loaded", timeout_ms: 5000 }),
});
const { snapshot } = await resp.json();
"success": false with an error message. The snapshot still reflects the page state at timeout.Batch
Execute multiple actions in sequence within a single API call. Each action in the batch is executed one after another. Useful for reducing round trips when performing multi-step flows.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
actions | array | Yes | Array of action objects. Each object has action (string, required) and optional fields: target, value, key, query. |
continue_on_error | boolean | No | If true, continue executing remaining actions after a failure. Default: false. |
Response 200 OK
Returns an array of action results, one per action in the batch:
{
"success": true,
"results": [
{
"action_id": "a1b2c3d4-...",
"success": true,
"duration_ms": 120,
"snapshot": { /* ... */ },
"error": null
},
{
"action_id": "b2c3d4e5-...",
"success": true,
"duration_ms": 85,
"snapshot": { /* ... */ },
"error": null
}
]
}
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/batch" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"actions": [
{"action": "fill", "target": "email field", "value": "alice@example.com"},
{"action": "fill", "target": "password field", "value": "secret123"},
{"action": "click", "target": "Sign In button"}
]
}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/batch",
headers=HEADERS,
json={
"actions": [
{"action": "fill", "target": "email field", "value": "alice@example.com"},
{"action": "fill", "target": "password field", "value": "secret123"},
{"action": "click", "target": "Sign In button"},
],
},
)
results = resp.json()["results"]
for r in results:
print(f"{r['action_id']}: {r['success']}")
const resp = await fetch(`${BASE}/sessions/${session_id}/batch`, {
method: "POST",
headers,
body: JSON.stringify({
actions: [
{ action: "fill", target: "email field", value: "alice@example.com" },
{ action: "fill", target: "password field", value: "secret123" },
{ action: "click", target: "Sign In button" },
],
}),
});
const { results } = await resp.json();
results.forEach((r) => console.log(`${r.action_id}: ${r.success}`));
List Pages
List all open pages (tabs) in the session. Returns the index, URL, and title of each page. Use the index with switch_page to change the active tab.
Request Body
No request body. This is a GET request.
Response 200 OK
{
"pages": [
{ "index": 0, "url": "https://example.com", "title": "Example" },
{ "index": 1, "url": "https://example.com/about", "title": "About Us" }
],
"active_index": 0
}
Examples
curl "https://api.babelwrap.com/v1/sessions/$SESSION_ID/pages" \
-H "Authorization: Bearer $BABELWRAP_API_KEY"
resp = await client.get(
f"{BASE}/sessions/{session_id}/pages",
headers=HEADERS,
)
data = resp.json()
for page in data["pages"]:
print(f"[{page['index']}] {page['title']} - {page['url']}")
const resp = await fetch(`${BASE}/sessions/${session_id}/pages`, {
headers,
});
const { pages, active_index } = await resp.json();
pages.forEach((p) => console.log(`[${p.index}] ${p.title} - ${p.url}`));
Switch Page
Switch the active page (tab) in the session. Use pages to list available tabs and get the index.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
index | integer | Yes | Index of the page to switch to (from the pages endpoint) |
Response 200 OK
Standard action envelope with snapshot of the newly active page.
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/switch_page" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"index": 1}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/switch_page",
headers=HEADERS,
json={"index": 1},
)
snapshot = resp.json()["snapshot"]
print(f"Switched to: {snapshot['title']}")
const resp = await fetch(`${BASE}/sessions/${session_id}/switch_page`, {
method: "POST",
headers,
body: JSON.stringify({ index: 1 }),
});
const { snapshot } = await resp.json();
console.log(`Switched to: ${snapshot.title}`);
Add Cookies
Add cookies to the session's browser context. Useful for setting authentication tokens, session IDs, or other cookies before navigating to a site.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
cookies | array | Yes | Array of cookie objects. Each object should include name, value, domain, and optionally path, secure, httpOnly, sameSite, expires. |
Response 200 OK
{
"success": true,
"cookies_added": 2
}
Examples
curl -X POST "https://api.babelwrap.com/v1/sessions/$SESSION_ID/cookies" \
-H "Authorization: Bearer $BABELWRAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"cookies": [
{"name": "session_token", "value": "abc123", "domain": ".example.com"},
{"name": "prefs", "value": "dark_mode=1", "domain": ".example.com", "path": "/"}
]
}'
resp = await client.post(
f"{BASE}/sessions/{session_id}/cookies",
headers=HEADERS,
json={
"cookies": [
{"name": "session_token", "value": "abc123", "domain": ".example.com"},
{"name": "prefs", "value": "dark_mode=1", "domain": ".example.com", "path": "/"},
],
},
)
print(f"Added {resp.json()['cookies_added']} cookies")
const resp = await fetch(`${BASE}/sessions/${session_id}/cookies`, {
method: "POST",
headers,
body: JSON.stringify({
cookies: [
{ name: "session_token", value: "abc123", domain: ".example.com" },
{ name: "prefs", value: "dark_mode=1", domain: ".example.com", path: "/" },
],
}),
});
const { cookies_added } = await resp.json();
console.log(`Added ${cookies_added} cookies`);
Action History
Get a chronological list of all actions performed in this session. Useful for debugging, auditing, or replaying workflows.
Request Body
No request body. This is a GET request.
Response 200 OK
{
"session_id": "d4e5f6a7-1234-5678-9abc-def012345678",
"actions": [
{
"action_id": "a1b2c3d4-...",
"action": "navigate",
"params": { "url": "https://example.com" },
"success": true,
"duration_ms": 1240,
"timestamp": "2026-04-03T10:01:00Z"
},
{
"action_id": "b2c3d4e5-...",
"action": "click",
"params": { "target": "Sign In button" },
"success": true,
"duration_ms": 340,
"timestamp": "2026-04-03T10:01:05Z"
}
]
}
Examples
curl "https://api.babelwrap.com/v1/sessions/$SESSION_ID/history" \
-H "Authorization: Bearer $BABELWRAP_API_KEY"
resp = await client.get(
f"{BASE}/sessions/{session_id}/history",
headers=HEADERS,
)
history = resp.json()["actions"]
for entry in history:
print(f"{entry['timestamp']} {entry['action']} - {entry['success']}")
const resp = await fetch(`${BASE}/sessions/${session_id}/history`, {
headers,
});
const { actions } = await resp.json();
actions.forEach((a) => console.log(`${a.timestamp} ${a.action} - ${a.success}`));
Usage & Health
These endpoints let you check your current usage against plan limits and verify the API is operational.
Get Usage
Returns current-month usage statistics for the authenticated user, including action counts, active sessions, and plan limits.
Response 200 OK
{
"plan": "usage",
"period": "2026-04",
"actions_used": 1243,
"actions_limit": null,
"sessions_active": 2,
"sessions_limit": 50,
"reset_date": "2026-05-01",
"estimated_cost_usd": 12.43
}
| Field | Type | Description |
|---|---|---|
plan | string | Current plan: free or usage |
period | string | Current billing period in YYYY-MM format |
actions_used | integer | Number of actions used this period |
actions_limit | integer or null | Maximum actions allowed this period. null for usage plan (metered billing). |
sessions_active | integer | Number of currently active sessions |
sessions_limit | integer or null | Maximum concurrent sessions allowed. null for unlimited. |
reset_date | string | Date when usage counters reset (first of next month, YYYY-MM-DD) |
Examples
curl https://api.babelwrap.com/v1/usage \
-H "Authorization: Bearer $BABELWRAP_API_KEY"
resp = await client.get(
"https://api.babelwrap.com/v1/usage",
headers={"Authorization": f"Bearer {API_KEY}"},
)
usage = resp.json()
print(f"Plan: {usage['plan']}")
print(f"Actions: {usage['actions_used']}/{usage['actions_limit']}")
print(f"Sessions: {usage['sessions_active']}/{usage['sessions_limit']}")
print(f"Resets: {usage['reset_date']}")
const resp = await fetch("https://api.babelwrap.com/v1/usage", {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const usage = await resp.json();
console.log(`Plan: ${usage.plan}`);
console.log(`Actions: ${usage.actions_used}/${usage.actions_limit}`);
console.log(`Sessions: ${usage.sessions_active}/${usage.sessions_limit}`);
console.log(`Resets: ${usage.reset_date}`);
Plan Limits Reference
| Plan | Actions / Month | Concurrent Sessions | Overage Rate |
|---|---|---|---|
| Free | 500 | 2 | N/A (hard limit) |
| Usage-based | Unlimited | 50 | $0.01/action |
Health Check
Returns the current system status. This endpoint does not require authentication and is suitable for uptime monitoring.
Response 200 OK
{
"status": "ok",
"version": "0.1.0",
"timestamp": "2026-04-03T12:00:00Z"
}
| Field | Type | Description |
|---|---|---|
status | string | System status. "ok" when healthy. |
version | string | Current API version |
timestamp | string (ISO 8601) | Current server time |
Examples
curl https://api.babelwrap.com/v1/health
resp = await client.get("https://api.babelwrap.com/v1/health")
health = resp.json()
print(f"Status: {health['status']}, Version: {health['version']}")
const resp = await fetch("https://api.babelwrap.com/v1/health");
const health = await resp.json();
console.log(`Status: ${health.status}, Version: ${health.version}`);
Error Format
All API errors follow a consistent JSON format:
{
"error": {
"code": "session_not_found",
"message": "Session d4e5f6a7-1234-5678-9abc-def012345678 not found"
}
}
| Field | Type | Description |
|---|---|---|
error.code | string | Machine-readable error code |
error.message | string | Human-readable error description |
error.candidates | array or null | Only present for ambiguous_target errors. Lists the candidate elements. |
HTTP Status Codes
| Status | Meaning |
|---|---|
200 | Success |
201 | Created (session creation) |
400 | Bad request (invalid JSON, missing required fields) |
401 | Unauthorized (missing or invalid API key) |
404 | Not found (session does not exist) |
410 | Gone (session expired or closed) |
422 | Unprocessable entity (target not found, ambiguous target) |
429 | Too many requests (rate limit or usage limit exceeded) |
500 | Internal server error |