Errors
Every failure carries a stable machine-readablecode. Branch on the code,
never on the message; messages are written for humans and will change. The
TypeScript client raises one OperatorError subclass per class below.
Only six codes are retryable, in the sense that waiting and re-sending the
same request can succeed:
rate_limited, quota_exceeded, device_busy,
device_not_ready, provider_error, browser_unavailable. Everything else
is a verdict.
A 404 means “no such row in your organization”. A row in another
organization answers identically, so a 404 is never evidence that an id does
not exist.
Idempotency
Exactly two routes accept anIdempotency-Key header: POST /v1/devices and
POST /v1/devices/{id}/tasks. A create that times out and is retried with the
same key replays the first result instead of provisioning a second browser or
submitting a second task.
Derive your key from the work, not from a clock; a generated key dies with the
process that made it. provision:${orderId} survives a crash,
${Date.now()} does not. Reusing a key with a different body is
409 idempotency_conflict. No other route accepts the header.
Pagination
Lists are keyset-paginated with an opaque cursor.next_cursoris server state. Do not parse it, construct one, or persist it across deploys; a tampered cursor is400 invalid_cursor.- Page size defaults to 20 and is clamped to 100.
- The TypeScript client exposes lists as async iterators (per item, per page,
or
collect(n)), so most code never touches a cursor.