https://txtfetch.com/docs/limits/
Every number, one page.
These numbers are not marketing copy. They come from the same config file the extraction Lambda reads at runtime. The build fails if this page and that file disagree.
You are about to send real traffic at this API. You want the real ceilings, not a rough guess. Below is every one of them, grouped the way you will actually hit them: per plan, per request, per fetch, per archive, and per counter.
One note, stated once instead of on every row: almost every value below is an environment default, not a fixed promise. It can change with a config update on our side. What stays stable is the mechanism: what counts against a limit, what resets it, and which error code fires when you cross it. Build against the mechanism.
Two numbers are missing on purpose. The exact per-plan requests-per-minute figure and the abuse-breaker's threshold are internal tuning knobs, not part of the published contract. You still get the mechanism for each in the Counters group below. Every metered response also carries the headers your own client needs to back off correctly.
Per plan
The two numbers that change with your plan. Everything else on this page is the same for every plan.
| capability | current default | on breach |
|---|---|---|
| Documents / month | Hobby 500 · Developer 10,000 · Scale 100,000 | The next request returns a 429 for the rest of the billing period. Only successful extractions count against it. See quota_exceeded. |
| Max file size | Hobby 10 MB · Developer 50 MB · Scale 200 MB | A direct upload over your plan's ceiling is rejected before extraction starts. See too_large. |
Request processing
One request, whether the input is a file upload or a ?url= fetch.
| capability | current default | on breach |
|---|---|---|
| Sync processing budget | 25 seconds | The request times out. Retry, or add ?async=true to run it off the request/response cycle. See timeout. |
| Async auto-switch threshold | 8 MB | A body over this size is routed to the async path automatically. No error, no client change needed. |
| Sync upload ceiling | 10 MB | The API gateway itself refuses a larger direct upload. Use ?url= for a bigger file; that path fetches it server-side, with a much higher ceiling. See too_large. |
?url= fetch
Rules for the server-side fetch that runs when you pass ?url= instead of a file.
| capability | current default | on breach |
|---|---|---|
| Schemes and ports | http and https only, ports 80 and 443 (or the URL's own default port) | Any other scheme or port is refused before a connection is attempted. Private, internal, and link-local addresses are also blocked, by design. See fetch_failed. |
| Redirects | 3 hops | A longer redirect chain is abandoned. See fetch_failed. |
| Connect timeout | 5 seconds | The fetch gives up if the source doesn't accept a connection in time. See fetch_failed. |
| Read timeout | 15 seconds | The fetch gives up if the source stalls mid-response. See fetch_failed. |
| Total wall clock | 20 seconds | Caps the whole fetch across every redirect hop. This sits on top of the per-hop timeouts above, so a chain of slow hops can't run unbounded. See fetch_failed. |
Containers and archives
Guards applied to zip-based files (DOCX, XLSX, PPTX, ODF, and raw zips) before Tika ever opens them.
| capability | current default | on breach |
|---|---|---|
| Entries per archive | 10,000 | An archive with more entries is refused before extraction, as a zip-bomb guard. See too_large. |
| Inflated size | 256 MB | An archive that would inflate past this size is refused. See too_large. |
| Compression ratio | 200:1 | An archive compressed past this ratio is refused, even if it stays under the size caps above. That ratio alone is the classic zip-bomb signature. See too_large. |
| Embedded resources per container | 1,000 | Tika's own nested-resource cap, a backstop for containers the archive guard above doesn't parse. See too_large. |
Premium quality (quality=premium)
Guardrails around the vision-model path, checked before it runs.
| capability | current default | on breach |
|---|---|---|
| Pages | 50 | A document over the cap downgrades to standard-quality extraction instead of erroring. |
| Bytes | 32 MB | Same downgrade: standard-quality extraction runs instead of an error. |
| Wall clock | 3 minutes | A premium call still running past this is stopped and the result downgrades to standard quality. |
Counters
The two independent meters on every key, and what resets them. Neither one's numeric limit is published here. Both ride the X-RateLimit-* and X-Quota-* response headers instead, so your own client reads its real limit rather than a number that can drift.
| capability | current default | on breach |
|---|---|---|
| Rate limit window | A fixed 60-second window | Every accepted request counts, including ones that go on to fail. A request over the limit still counts against the window it's flooding. See rate_limited. |
| Quota period | One calendar month, UTC | Only successful extractions count. The counter resets at the next UTC month boundary. See quota_exceeded. |
| Abuse circuit breaker | A rolling window of recent outcomes, weighted toward oversized/malformed rejections | A key that trips it is locked out for a cooldown period, independent of both counters above. See abuse_detected. |
Retention
How long usage data lives after it's written.
| capability | current default | on breach |
|---|---|---|
| Usage counters | 120 days | Counters older than this are deleted. This is bookkeeping retention, not a limit you can hit. |
| Usage records | 400 days | Per-request usage records older than this are deleted. |
machine-readable-spec
This table is drift-tested at build time against api/extract/src/config.js and api/extract/src/plans.js, the same files the running Lambda imports. If a limit changes in code and this page falls behind, the build breaks. For the header contract and every error code these limits can raise, see the error reference →.
Watch it run, then take a key.
The playground replays a real recorded response for every sample document.
Open the playground →