Credits & rate limits
Your plan includes a monthly allowance of credits. Every successful call spends some, according to what that call costs us to run — so a plan stretches a long way on cheap operations and less far on expensive ones.
What each call costs
One credit is one page fetch. Everything else is priced relative to that. This table is generated from the same source the API meters with, so it is never out of date:
| Endpoint | Credits | Calls a Free plan buys |
|---|---|---|
| /console | 1 | 1,000 |
| /html | 1 | 1,000 |
| /markdown | 1 | 1,000 |
| /meta | 1 | 1,000 |
| 1 | 1,000 | |
| /screenshot | 1 | 1,000 |
| /technologies | 1 | 1,000 |
| /lighthouse | 2 | 500 |
| /keywords | 15 | 66 |
| /summarize | 17 | 58 |
| /extract | 24 | 41 |
One option sits outside this table because it is priced per page fetch rather than per call: residential exits, covered below.
The split is not arbitrary. /html, /screenshot, /pdf and /console all come from one visit to the page in a real headless Chrome and cost us the same; /lighthouse runs a full audit that takes minutes of CPU in a limited lane, so it is worth two. /markdown converts the page we have already rendered, in the browser and without a model, so it costs a page fetch and nothing more, and so does /meta, which reads what the page declares about itself, and /technologies, which matches fingerprints against the same visit. The AI endpoints send the page to a language model, and what they pay depends on how much of it the model has to read and write back: /summarize reads the whole article and writes several paragraphs back, and /extract reads the whole page, markup and structured data included, with a stronger model that reasons before it answers.
Fetching from a residential address
One option is priced on its own, because what it buys is not work on the page but the connection the page arrives over. Residential exits fetch a page from a home broadband address instead of a datacentre one, for the sites that answer the two differently. They add 25 credits per page fetch — once per request, not once per operation, so a /scrape pays for one exit however many results it takes off the visit.
A worked example
Say a month's traffic is 500 /html calls, 100 /meta lookups and 25 /summarize calls, and a third of the requests repeat a URL you've already fetched:
Raw calls 500 /html + 100 /meta + 25 /summarize
Cache hits (33%) −165 /html −33 /meta −8 /summarize → free
Billable 335 /html 67 /meta 17 /summarize
335 × 1 = 335 credits
67 × 1 = 67 credits
17 × 17 = 289 credits
---
691 credits → fits the Free plan (1,000)The calculator on the pricing page does this for you, including the cache-hit discount.
Allowance per plan
These are the monthly allowances each plan includes. They are read from the same source the API enforces, so this table is never out of date.
| Plan | Credits / month | In parallel | Page fetches | /summarize calls |
|---|---|---|---|---|
| Free | 1,000 | 1 | 1,000 | 58 |
| Starter | 20,000 | 3 | 20,000 | 1,176 |
| Pro | 55,000 | 8 | 55,000 | 3,235 |
| Scale | 175,000 | 20 | 175,000 | 10,294 |
See pricing for what each plan costs, or the Billing screen in your dashboard to change plan. Every paid plan keeps serving past its allowance, uncapped, at $1.50 / 1,000 — see overage. Volumes past Scale run on a contract we size with you — email us.
Cache hits are free
The same goes for a repeat of a request that is still running: it shares the first one's work and spends nothing. See retries & duplicates.
Failed requests are free too
You are only charged for work that produced a result. However an analysis fails — a DNS failure, a refused connection, a timeout, a bad certificate, a page that 404s, or a site that puts a bot check in front of it we cannot clear — the call spends nothing. That includes the residential surcharge on a fetch that came back with nothing to sell you, and it includes a request we could not find a residential exit for at all.
Results we got wrong come back to you
Some failures don't look like failures: the page loaded, but the result missed what was on it. Open the request in your dashboard's History and report it, with a note if you like. We check every report by hand against the stored result, and when we got it wrong, the credits it spent go back into that month's allowance. The request's page shows where your report stands, and we email you our answer. A request can be reported for as long as its result is kept — 30 days.
Reading your balance from a response
You don't have to wait for a 429 to find out where you stand. Every response says what it cost and what is left:
- Name
X-Quota-Cost- Type
- integer
- Description
- What this request spent. Zero on a cache hit or a failed analysis, and on a
/scrapethe sum over the operations that actually did work — plus any residential exit it used. On a429it is what the request would have cost — the figure that didn't fit.
- Name
X-Quota-Limit- Type
- integer
- Description
- The monthly credit allowance included in your plan, or
unlimited.
- Name
X-Quota-Remaining- Type
- integer
- Description
- What is left of that allowance after this request. The count is taken after your request, so it's what you have now.
- Name
X-Quota-Overage- Type
- integer
- Description
- Credits spent past the allowance this month. Zero until it runs out; after that, what will be billed when the month closes. There is no ceiling on it.
- Name
X-Quota-Reset- Type
- timestamp
- Description
- When the allowance rolls over, as an ISO 8601 timestamp.
Running out never stops you: overage
On a paid plan, spending the last of your monthly credits changes the price and nothing else. Your calls keep working — there is no cap, no ceiling and no cut-off — and every credit past the allowance costs $1.50 / 1,000. Nothing is charged mid-request: the extra credits are totalled when the month closes and arrive as a single invoice of their own, itemised down to the block.
| Plan | Included credits | Each extra 1,000 | 10,000 extra would cost |
|---|---|---|---|
| Free | 1,000 | — | Requests are refused |
| Starter | 20,000 | $1.50 | $15.00 |
| Pro | 55,000 | $1.50 | $15.00 |
| Scale | 175,000 | $1.50 | $15.00 |
Overage is deliberately dearer than the credits your plan already includes — it is there so a spike is never refused, not so it can replace the right plan. A Starter account settling at Pro-sized traffic pays more in overage than Pro costs, and the billing screen says so while it is happening.
1,000 credits, and a partial block counts as a full one — 1,200 extra credits is two blocks, $3.00. That keeps a busy month from producing an invoice for four cents.Knowing you have crossed over
Three ways, none of which require you to go looking. Every response carries X-Quota-Overage, the credits you have spent past the allowance this month — zero until you cross, and after that the number that gets billed. We email your organization admins the first time in a month you cross. And the app shows a banner, with the running total, for as long as you are over.
There is deliberately no header saying how much further you can go, because there is no answer: on a plan with a card on file you are never cut off for credits.
When you do run out
Only the Free plan is ever refused, and only because there is no card to bill the extra to. When it happens URLpipe returns 429 Too Many Requests with a JSON body describing exactly where you stand. Nothing is executed and nothing is spent — a /scrape that can't afford all of its operations runs none of them, rather than silently dropping some.
{
"error": "quota_exceeded",
"message": "Your Free plan includes 1000 credits per month. You've used 990 and this request needs 17. Quota resets on 2026-10-01 (UTC).",
"limit": 1000,
"used": 990,
"needed": 17,
"resets_at": "2026-10-01T00:00:00Z"
}- Name
error- Type
- string
- Description
- Always
quota_exceededfor this response.
- Name
limit- Type
- integer
- Description
- The monthly credit allowance included in your plan.
- Name
used- Type
- integer
- Description
- Credits you've spent this period.
- Name
needed- Type
- integer
- Description
- What the refused request would have cost. Worth reading: a request for a cheaper operation may still fit.
- Name
resets_at- Type
- timestamp
- Description
- When the allowance resets — the 1st of next month, UTC — as an ISO 8601 timestamp.
Handling it gracefully
- Watch
X-Quota-Overage. On a paid plan no 429 is coming, so this is the only signal there is: the moment it goes above zero you're paying per call, and that is the point at which a bigger plan usually costs less than carrying on. - Read
resets_atand back off until then rather than retrying immediately. - Widen
max_ageso more requests are served from cache for free. - Reach for a cheaper endpoint where it will do. If you only need a page's title and description,
/metacosts 1 credit against the 17 of/summarize. - Drop
residentialfrom the calls that do not need it. Most pages come back complete on the standard network, and the exit is the dearest thing on the rate card. - Watch the breakdown on the Billing screen — it itemises the month by operation, residential fetches on a line of their own, so you can see which endpoint is actually spending your allowance.
Dormant free organizations
A free organization that nobody signs in to and that makes no API request for six months is treated as dormant. We email its admins and show a notice in the app; 30 days later the organization and its request history are deleted.
Anything counts as activity — one sign-in, one request. So a project whose only job is a nightly cron against /markdown never goes dormant, and neither does an account somebody logs into now and then. If a notice does arrive, using the organization cancels it, as does upgrading it or the button in your organization settings. Paid plans are never affected. The full policy is in the terms.
Parallel requests
Separately from how many credits a month buys, each plan sets how many requests you can run in parallel. Credits are how much work you can do in a month; this is how fast you get through it.
| Plan | Parallel requests | What that suits |
|---|---|---|
| Free | 1 | Cron jobs, a page per visitor, and steady background work. |
| Starter | 3 | A small worker pool, or a busier site fetching pages on demand. |
| Pro | 8 | Batch jobs that have to finish inside a window. |
| Scale | 20 | Crawls and pipelines, where wall-clock time is the point. |
A crawl of 5,000 pages costs the same credits however fast you run it — running 20 in parallel instead of one at a time is the difference between minutes and hours. Every response carries X-Concurrency-Limit, so a worker pool can size itself from the plan rather than by trial and error.
A request counts from the moment we accept it until it finishes, which for an async request includes the time it spends queued waiting for us to start it. A /scrape is one request however many operations it runs, because they come from a single page visit. And a cache hit occupies no slot at all — it does no work — so widening max_age buys you concurrency as well as lowering your bill.
Go over and the request is refused with 429 Too Many Requests and error: "concurrency_limit". Nothing is spent and nothing is queued — retry as soon as one of your own requests finishes.
{
"error": "concurrency_limit",
"message": "Your Starter plan runs 3 requests in parallel, and 3 are already running. Retry when one finishes, or move to a plan that runs more in parallel. Nothing was spent on this request.",
"limit": 3,
"running": 3
}Retry-After on this response, deliberately: the answer is "when one of yours finishes", not a fixed number of seconds. A client that tracks its own in-flight requests always knows sooner than a header could tell it.Your limit is about your own work. We separately cap how many requests run against any one target site at a time, across all customers together, so URLpipe never hammers somebody else's server — and when a site starts struggling, we slow down further until it recovers. Those requests queue rather than being refused, and time a request spends waiting on a site we are pacing does not count against your parallel limit. You didn't cause that wait, so you don't pay for it.
Rate limits
Separately from your monthly allowance, every request is rate limited per project (keyed by your API key) so a runaway script can't flood the service. Two ceilings apply at once:
- Up to
60requests per minute. - Up to
15requests per 10 seconds (a short-burst ceiling).
Exceed either and URLpipe returns 429 Too Many Requests with a Retry-After header giving the seconds to wait. This response is distinct from the credit one above — its error is rate_limited, so you can tell "slow down" apart from "you've used your allowance".
{
"error": "rate_limited",
"message": "Too many requests. Slow down and retry after 12 seconds.",
"retry_after": 12
}So three different things can answer 429, and the error field is what tells them apart: rate_limited means you are sending too fast, concurrency_limit means too many of yours are already running, and quota_exceeded means the month's credits are gone. Each one tells you what to do next: slow down, wait for one of your own requests to finish, or wait for the 1st.