Rate Limits & Polling
Rate limits
Rate limiting is not currently enforced on the REST API or the MCP server — both sit behind the same API Gateway usage plan and key, and neither has an active throttle configured today. Don't build a client that depends on this: enforcement can be turned on without notice, and it's good practice to pace requests sensibly regardless (see polling guidance below). This section will be updated with real per-plan numbers once throttling is enabled.
The MCP server shares this same (currently unenforced) limit with the REST API — there's no separate bucket for MCP traffic.
Polling for extraction results
GET /v1/documents/{document_id}/run_parser (and the equivalent extract_document MCP tool) is asynchronous — it returns a request_id immediately, before the document has been parsed. Get the result by polling GET /files?request_id=... (or check_extraction_status over MCP) until request_status is completed, failed, or exception.
There's no published typical duration for a job to go from pending to completed — it depends on document length and the OCR/model settings used. What's fixed by the infrastructure: extraction runs as an async job specifically because a synchronous call can't outlast API Gateway's 29-second request limit, and the backing job has generous worst-case ceilings (well beyond what a normal document should ever take) — so a client that gives up after a minute or two on a normal-sized document isn't cutting things short.
Instead of polling on a fixed interval, use exponential backoff so short jobs resolve quickly and long jobs don't hammer the endpoint:
import time
import requests
def poll_result(request_id, api_key, max_wait_seconds=120):
url = "https://api.documentpro.ai/files"
headers = {"x-api-key": api_key}
delay = 1 # start at 1s
elapsed = 0
while elapsed < max_wait_seconds:
response = requests.get(url, headers=headers, params={"request_id": request_id})
result = response.json()
if result["request_status"] in ("completed", "failed", "exception"):
return result
time.sleep(delay)
elapsed += delay
delay = min(delay * 2, 10) # cap backoff at 10s between polls
raise TimeoutError(f"Extraction did not complete within {max_wait_seconds}s")
A few guidelines regardless of the exact interval you choose:
- Don't poll faster than once per second. Tight polling loops waste requests for no benefit, and while nothing enforces a limit today, that's not guaranteed to stay true.
- Cap your backoff (e.g. at 10–15 seconds between polls) so long-running jobs on large documents don't feel unresponsive.
- Set a max wait and give up. If a job hasn't resolved after a couple of minutes, treat it as exceptional and surface that to the caller rather than polling indefinitely.
- Prefer a webhook when you can. If your Workflow doesn't need a synchronous response, set a
webhook_urlon the Workflow instead of polling — see Create Workflow and Webhooks.