Pricing

One credit balance. No separate proxy, browser or stealth credits, and captcha handling is included rather than metered.

Generated from the rate card and the capability registry at request time. A capability with no registry row cannot appear here, and neither can a rate nothing produces.

Plans

PlanCredits / monthConcurrent browsersRequests / minute
free10002120
builder100005300
pro50000251500
scale2500001006000

Rates

CreditsMetered asPaid by
1 per minute of browser timecontext_secondsagent, cdp
1 per pagepage_loadscrape, crawl, search, monitors.check
5 per 10 search resultssearch_resultsearch
2000 per GB relayed through a residential exit, both directionsproxy_bytescdp, agent
the model's own cost, in credits at your plan's price per credit (Free at the Builder price); nothing when your own model key served itmodel_cost_usdagent, monitors.check

What a call costs

RouteCharge
POST /v1/scrape1 per page
POST /v1/crawl1 per page
GET /v1/crawl/{id}free — watching a crawl you are already paying for. The crawl bills per page, and a per-page charge a customer cannot poll without adding to it is a charge they cannot verify — the poll would grow the number it reports.
GET /v1/crawl/{id}/resultsfree — collecting pages already bought. Every page here was produced by a crawl that billed for producing it; a second charge for fetching it would mean a crawl whose pages were paginated cost more than one whose pages fit inline.
POST /v1/crawl/{id}/cancelfree — this is how a customer stops spending. A charge for turning something off is a charge for the fix — the same line `monitors.delete` takes, and a sharper one here, because the thing being turned off bills by the page while the question is being asked.
POST /v1/search5 per 10 search results; 1 per page
POST /v1/monitorsfree — a control-plane write. The scheduled checks it causes are metered by the render path when they run; charging at creation would bill work nobody has done, and a monitor can be created and deleted without ever firing.
GET /v1/monitorsfree — a control-plane read of rows we already store.
DELETE /v1/monitors/{id}free — a control-plane write, and it is how a customer stops spending. A charge for turning something off is a charge for the fix.
POST /v1/agentthe model's own cost, in credits at your plan's price per credit (Free at the Builder price); nothing when your own model key served it; 1 per minute of browser time
GET /v1/agentfree — a control-plane read of rows we already store.
GET /v1/agent/{id}free — watching a run you are already paying for. The run bills per minute, and a per-minute charge a customer cannot poll without adding to it is a charge they cannot verify — the poll would grow the number it reports.
GET /v1/agent/{id}/eventsfree — the same watching, in more detail, and free for the same reason. Its bytes are deliberately not recorded either: unlike a crawl, whose stream IS the deliverable, this stream is a projection of rows the run already produced and already paid for, and metering it would charge twice for one delivery — once as the run, once as reading it.
GET /v1/agent/{id}/resultsfree — collecting output already bought. Every record here was produced by a run that billed for producing it; a second charge for fetching it would mean a run whose output was paginated cost more than one whose output fit inline.
POST /v1/agent/{id}/cancelfree — this is how a customer stops spending. A charge for turning something off is a charge for the fix — the same line `monitors.delete` takes, and a sharper one here, because the thing being turned off bills by the minute while the question is being asked.
POST /v1/agent/{id}/controlfree — steering a run you are already paying for, and the sharpest case of it: taking the wheel is what a customer does when the agent cannot finish a step, so a charge for it would price the recovery of a run that has already been billed for. The HOLD it starts is not free, though: from take to release (or the hold’s thirty-minute expiry) the run’s clock keeps running and is billed as run time, because a customer can take the wheel as often as they like and a free hold would be browser time with no ceiling. The one unbilled wait is inside a step: a person who takes the page in the live viewer mid-action parks the agent on `awaitHandback`, and `CapLedger.park` stops the clock for exactly that wait.
POST /v1/agent/{id}/answerfree — answering a question our agent asked. Charging for it would be charging a customer to be interrupted, and it would price the one seam that turns a run which would otherwise guess or fail into one that finishes. The question park itself costs the run nothing either: the loop parks the ledger (`CapLedger.park`) while it waits for the answer, bounded by the ask’s own wait, so that wait is excluded from the duration it bills. That is the loop’s own park, and not an `agent.control` hold, which is billed.
POST /v1/agent/{id}/filesfree — handing a run its own input. The run is the expensive thing and it already bills per minute for the work it does with the file; charging to deliver the file would charge a customer for the SETUP of work they are about to pay for, and would make a task that needs a document cost more than the identical task that does not. Storage is also not the cost here — the file exists for the length of one run and is destroyed at its terminal transition, which is the shortest-lived object in the bucket by a factor of seven days.
GET /v1/agent/{id}/downloadsfree — `sessions.downloads`' argument, for a run: the download was metered as `proxy_bytes` when the run's browser fetched it.
POST /v1/agent/{id}/secretsfree — handing a run its own input, on `agent.files`' argument: the run bills per minute for the work it does with the secret, and the secret itself is kept nowhere to be priced. It is also usually the answer to a question the run asked, and `agent.answer` is free for the reason it gives.
POST /v1/agent/{id}/secret-intentsfree — a control-plane write that stores one row and no value, on `secrets.intent`'s argument: asking for permission to hand a run a secret is free because handing it one is.
POST /v1/profilesfree — a control-plane write that consumes no metered resource. We do not charge for storage, so holding a profile is free and creating one is therefore free too — what gets metered is the sessions that later use it.
GET /v1/profilesfree — a control-plane read of rows we already store.
GET /v1/profiles/{id}free — a control-plane read of rows we already store.
DELETE /v1/profiles/{id}free — a control-plane write, and nothing about storage is billed, so deleting a profile neither reduces a charge nor may earn one.
GET /v1/sessionsfree — a control-plane read of rows we already store.
GET /v1/sessions/{id}free — this is the dispute path: the registry row says it is how a charge is disputed. Billing for the evidence of a charge bills it twice. The ?live feed is free for the same reason — a customer watching a run they are already paying for.
POST /v1/sessions/{id}/exportfree — bytes_egress: the price list has no line for our own response bytes. Its one byte line is Egress at 2,000 credits/GB, which was calculated for residential proxy bandwidth and is now charged as proxy_bytes on the capabilities where the customer decides the byte count; these bytes leave via Workers and R2 at ~0 marginal cost. Pricing them as well would bill one scrape the residential rate twice, once for the origin bytes we bought and once for our own reply. The count is kept because it is what sessions.export already reports to the caller and what answers "how much did we serve them". sessions.export is therefore metered and unpriced BY DECISION, not pending one: a replay is the evidence of a charge, billing for the evidence bills the same work twice, and the whole line would have billed about 1,281 credits in all of history as of 2026-09-06 — against 19.57 MB of proxy_bytes, the only per-GB cost this business actually pays.
GET /v1/sessions/{id}/eventsfree — the recording is the evidence of a charge, on the reasoning sessions.get gives: billing for reading what a run did bills that run twice.
GET /v1/sessions/{id}/networkfree — the recording is the evidence of a charge, on the reasoning sessions.get gives: billing for reading what a run did bills that run twice.
GET /v1/sessions/{id}/digestfree — the recording is the evidence of a charge, on the reasoning sessions.get gives: billing for reading what a run did bills that run twice.
GET /v1/sessions/{id}/requestfree — the recording is the evidence of a charge, on the reasoning sessions.get gives: billing for reading what a run did bills that run twice.
GET /v1/sessions/{id}/consolefree — the recording is the evidence of a charge, on the reasoning sessions.get gives: billing for reading what a run did bills that run twice.
GET /v1/sessions/{id}/harfree — the recording is the evidence of a charge, on the reasoning sessions.get gives: billing for reading what a run did bills that run twice.
GET /v1/sessions/{id}/videosfree — the recording is the evidence of a charge, on the reasoning sessions.get gives: billing for reading what a run did bills that run twice.
GET /v1/sessions/{id}/downloadsfree — the owner's 2026-10-19 decision: no charge beyond the bandwidth the download already meters. The bytes were billed as `proxy_bytes` when they crossed the session's exit; listing them, or fetching them from storage, would bill the same file twice.
POST /v1/sessions/{id}/sharefree — a control-plane write of who may watch a recording; sharing the evidence of a charge must not cost anything.
DELETE /v1/sessions/{id}free — closing is free: the session's own `context_seconds` row is its bill, and a charge for stopping a browser would be a charge for stopping the charge.
GET /v1/usagefree — metering the meter. The registry row promises nothing appears here that was not visible on the call that caused it, and a usage query that generated usage would make that untrue of itself.
GET /v1/creditsfree — reading what you were given. It is the same argument `usage` makes one row up and a sharper version of it: this route exists so a customer can see a granted or promotional balance and when it lapses, and a charge for looking would draw down the very pool being reported. An account with an exhausted pool asking why would be billed for the answer.
POST /v1/secretsfree — a control-plane write, and the same argument `profiles.create` makes: we do not charge for storage, so holding a credential is free and storing one is therefore free too. What gets metered is the run that uses it — and a charge for storing a card is a charge levied before any work exists to defend it.
GET /v1/secretsfree — a control-plane read of rows we already store. It is also the only window a customer has onto what an agent can reach on their behalf, and a charge for reading your own blast radius is a charge for checking whether you are safe.
DELETE /v1/secrets/{id}free — a control-plane write, and nothing about storage is billed. Sharper than `profiles.delete`: this is the revoke button on a payment credential, and a charge for turning something off is a charge for the fix.
POST /v1/secrets/intentsfree — a control-plane write that stores one row and no value, on `secrets.create`'s argument: storing a credential is free, so asking for permission to store one is free too. The spend it enables — the browser's `PUT` — is not a capability at all and bills nothing either.
POST /v1/secrets/batchfree — `secrets.create`, five hundred at a time, on its argument: storing a credential is free, so storing many is free too. A charge per imported card would be a charge levied before any run exists to use one.
GET /v1/rulesfree — a control-plane read of rows we already store, and the sharpest instance of the argument `secrets.list` and `integrations.list` both make. This route answers ONE question: which of the rules you wrote are actually enforced and which are only advice a model can trade away. A customer who has not read that answer does not know what their agent is allowed to spend. Charging to find out whether your own spend ceiling is real is a charge for checking whether you are safe.
PUT /v1/rulesfree — a control-plane write, on `profiles.create`'s argument: we do not charge for storage, so holding a rule row is free and writing one is free too. And the direction matters here in a way it does not for a profile — a rule only ever NARROWS what a run may do, so every charge on this route would be a charge for reducing our own bill. The metered thing is the run the rules bound, which pays by the minute either way.
POST /v1/integrationsfree — a control-plane write, on `profiles.create`'s argument: we do not charge for storage, so holding a connector row is free and creating one is free too. What gets metered is the RUN that calls the tools — and it already is, by the minute, because a run that stops to read a mailbox is a run whose wall clock is running. Charging here would price the setup of work about to be paid for, and would make a task that needs a 2FA code cost more than the identical task on an account that never hits one.
POST /v1/integrations/testfree — a connect-time check that stores nothing, on `integrations.connect`'s argument: connecting is free, and the check is the part of connecting that tells a customer whether it will work. Charging for it would price finding out that a key is wrong, which is the moment a customer is least able to tell whether they did anything billable.
GET /v1/integrationsfree — a control-plane read of rows we already store, and — the sharper half, shared verbatim with `secrets.list` — the only window a customer has onto WHAT AN AGENT CAN REACH OUTSIDE THE BROWSER. A charge for reading your own blast radius is a charge for checking whether you are safe, and a customer who cannot see it cannot consent to it.
PATCH /v1/integrations/{id}free — a control-plane write to a row we already store, on `integrations.connect`'s argument: nothing about storage is billed, and rotating the secret a connector authenticates with is maintenance a customer must be free to do. The runs that call the tools are what is metered, by the minute.
DELETE /v1/integrations/{id}free — a control-plane write, and nothing about storage is billed. This is the revoke button on a live connection to a mailbox; a charge for turning something off is a charge for the fix, and here the fix is the incident response.
GET /v1/agent/{id}/purchasesfree — a control-plane read of rows we already store: what one run paid, which is the reconciliation a customer owes their own books. Charging to see what an agent spent of your money is `secrets.list`'s charge for checking whether you are safe.
GET /v1/purchasesfree — a control-plane read of rows we already store, on `agent.purchases`' argument, across runs.
GET /v1/wallet/settingsfree — a control-plane read of one row we already store, on `rules.get`'s argument: whether a person is asked before a large purchase.
PUT /v1/wallet/settingsfree — a control-plane write, on `rules.set`'s argument: the threshold only ever ADDS a question before a purchase, so a charge here would be a charge for being careful.
GET /v1/wallet/providersfree — a read of six static rows: what each card provider is and whether this deployment can connect it. Charging to learn what you could connect is a charge before any work exists.
GET /v1/wallet/connectionsfree — a control-plane read of rows we already store, on `secrets.list`'s argument: the connections that can mint cards are this workspace's blast radius.
GET /v1/wallet/connections/{id}free — a control-plane read of one row we already store, on `wallet.connections.list`' argument.
POST /v1/wallet/connectionsfree — a control-plane write, on `secrets.create`'s argument: storing a credential is free. The provider test it runs is read-only and costs us one outbound request, and charging for it would charge for proving a credential works.
POST /v1/wallet/connections/intentsfree — a control-plane write that stores one row and no value, on `secrets.intent`'s argument.
POST /v1/wallet/connections/{id}/testfree — a read-only provider call that checks a connection still works, on `integrations.test`'s argument: a charge for checking whether you are safe.
DELETE /v1/wallet/connections/{id}free — the revoke button on a credential that mints cards, on `secrets.delete`'s argument: a charge for turning something off is a charge for the fix.

Billed without a capability row

Two things bill and have no row in the registry, so they are stated here rather than derived from it: a browser session is a URL and a redirect, and a monitor check is work on a schedule that nobody calls.

RouteChargeWhat it is
GET /connect1 per minute of browser time; 2000 per GB relayed through a residential exit, both directionsa stealth browser driven over CDP: authenticate, get a 302 to a fleet Mac, drive it with your own Playwright
monitors.check1 per page; the model's own cost, in credits at your plan's price per credit (Free at the Builder price); nothing when your own model key served itone scheduled monitor check. Created through POST /v1/monitors, which is itself free

Measured and not charged for

These quantities are recorded on every call that produces them and priced at nothing. The reason is on the record because it is the answer to "why is there no row for this on my bill".

bytes_egress
the price list has no line for our own response bytes. Its one byte line is Egress at 2,000 credits/GB, which was calculated for residential proxy bandwidth and is now charged as proxy_bytes on the capabilities where the customer decides the byte count; these bytes leave via Workers and R2 at ~0 marginal cost. Pricing them as well would bill one scrape the residential rate twice, once for the origin bytes we bought and once for our own reply. The count is kept because it is what sessions.export already reports to the caller and what answers "how much did we serve them". sessions.export is therefore metered and unpriced BY DECISION, not pending one: a replay is the evidence of a charge, billing for the evidence bills the same work twice, and the whole line would have billed about 1,281 credits in all of history as of 2026-09-06 — against 19.57 MB of proxy_bytes, the only per-GB cost this business actually pays.
tokens
the price list has no token line. Model usage is priced in dollars on model_cost_usd, from the provider's own per-call cost; pricing the tokens as well would charge the same calls twice. The count is kept for attribution.