Document Intelligence Limits
The Document Intelligence API uses three separate allowances: request rate, processing units, and the organization's API-call balance.
Plan Limits
These are the default DI tier values. A deployment can configure different values for its plans.
| Plan | Requests/minute per API key | Units/minute per organization | Maximum file size |
|---|---|---|---|
| Free / Default | 5 | 50 | 10 MiB |
| Basic | 20 | 400 | 25 MiB |
| Basic+ | 60 | 1,200 | 50 MiB |
| Pro | 200 | 4,000 | 100 MiB |
| Pro+ | 600 | 12,000 | 200 MiB |
| Enterprise | 2,000 | 40,000 | 500 MiB |
File size means decoded content, not the larger base64 string. One MiB is 1,048,576 bytes. Default DI tiers are configured for these plan families; a plan without a DI tier returns 403 with doc_intel_not_available.
Request and unit allowances refill continuously at their per-minute rate, up to the tier capacity. They do not reset together at the start of a calendar minute. A request must fit both allowances. If either is exhausted, the request is rejected with 429 and neither rate-limit allowance is deducted.
Multiple API keys have separate request-rate allowances but share the organization's unit allowance. Creating another key does not increase the organization's available units.
What Is a Unit?
A unit measures the declared processing cost for rate limiting. Units refill automatically; they are not a purchased balance and are not LLM tokens or API calls.
| Component | Units |
|---|---|
| Base parsing | 1 |
| OCR, when enabled for a file | +2 |
| LLM enhancement, when enabled for a file | +2 |
| Summarization | +1 |
| Structured extraction | +1 |
| Agentic task | +1 |
| Job-status lookup | 0.1 |
Costs are additive:
| Request | Basic file: both flags off | OCR only | LLM enhancement only | Both enabled |
|---|---|---|---|---|
| Parse a file | 1 | 3 | 3 | 5 |
| Summarize a file | 2 | 4 | 4 | 6 |
| Extract from a file | 2 | 4 | 4 | 6 |
| Agentic with a file | 2 | 4 | 4 | 6 |
Summarization and extraction with direct text each cost 1 unit. Agentic without a file costs 1 unit. Parsing flags do not add unit costs to requests without a file.
Default file cost
llm_enhanced defaults to true and ocr_enabled defaults to false. Omitting both flags costs 3 units for parsing a file or 4 units for a file-based summarize, extract, or agentic request. Set llm_enhanced: false for the basic-file costs above.
Units are deducted when processing is admitted. They are not refunded if later processing fails. An asynchronous submission pays its operation's unit cost once; the worker does not repeat that debit. Each status poll costs another 0.1 units, including reads of cached results and lookups that later return 404.
API-Call Consumption
The organization's api_calls resource is separate from DI units. After successful DI authentication and access checks, each processing submission costs one API call before processing. Job-status reads do not consume this balance.
| Action | API calls |
|---|---|
| Synchronous submission | 1 |
| Asynchronous submission | 1 |
| Each job-status poll, including a cached result | 0 |
| Background execution of an accepted job | 0 additional |
| Outgoing webhook delivery | 0 additional |
There are currently no refunds. A processing submission can consume an API call and subsequently fail input validation, operation-scope checks, DI rate admission, or processing. A DI rate-limit rejection therefore deducts no request/unit tokens but may already have consumed an API call. Missing or invalid keys do not reach charging.
An exhausted API-call allowance returns 429 for processing submissions and processing does not start. You can still retrieve existing jobs, subject to authentication, access, and DI rate limits. A charging-service failure returns 500 and also stops processing. Check your organization's usage and plan allowance; waiting for DI units to refill does not replenish the separate API-call balance. Other applicable model or resource usage is metered separately.
File and Processing Limits
| Limit | Behavior |
|---|---|
| Synchronous file threshold | Files up to 5 MiB can run synchronously; larger files automatically queue |
| Forced asynchronous mode | async: true queues any operation, including text and query-only requests |
| Synchronous timeout | 30 seconds by default; a timeout returns 504 |
| Job lifetime | 24 hours from creation |
| Completed-result retention | Up to 1 hour after completion, capped by job expiry |
Use asynchronous mode for long agentic tasks or processing that may exceed the synchronous timeout. A timed-out synchronous request is not automatically converted into a job; resubmitting creates a new request and charge.
DI currently enforces file size, not a page-count limit.
Response Headers
DI success and error responses include these headers:
| Header | Meaning |
|---|---|
Request-Id | Trace identifier to include in support requests |
X-RateLimit-Limit | Tier request allowance per minute |
X-RateLimit-Remaining | Whole request tokens available after the admission decision |
X-RateLimit-Cost | DI units deducted at admission; zero if not admitted |
X-RateLimit-Reset | Epoch seconds when the request allowance will be full, assuming no further requests |
X-RateLimit-Components | Admitted cost breakdown, such as parse=1, llm=2, summarize=1 |
X-RateLimit-Cost does not report the api_calls debit. A value of zero does not mean the request was free of API-call charges.
Before a rate-limit snapshot is available, X-RateLimit-Remaining and X-RateLimit-Reset are unknown. X-RateLimit-Limit is also unknown until the caller's tier is known. Cost is 0 and components are empty before admission or on a DI rate-limit rejection.
On a DI unit-limit rejection, request headers still describe the request allowance. The error's details includes scope: "units", unit_limit, unit_remaining, and requested_cost to explain the unit shortage.
Handling a 429
For a request-rate or unit-rate rejection, wait for the Retry-After header when supplied, then retry with backoff. The header gives seconds until the request can fit; X-RateLimit-Reset instead describes when the request allowance will be completely full.
Retry-After is not guaranteed for every 429, including an exhausted API-call balance or a request costing more units than the entire tier capacity. Inspect the error message and details. Avoid automatic retry loops that continue spending API calls on the same rejected request.
See errors and troubleshooting for the response envelope and other HTTP statuses.