Rate Limits & Errors
Error codes, rate limits, and retry strategies.
Rate Limits
10 requests/second per API key on all endpoints.
The tabular parse endpoint (POST /tabular/parse) has an additional limit of 5 requests/minute.
429 Too Many RequestsWait briefly and retry with exponential backoff: 1s, 2s, 4s, 8s, etc.
Error Format
{{
"detail": {{
"code": "unknown_form",
"message": "Unknown form: irs_w99_2024",
"status": 400
}}
}}
Error Reference
Client Errors (4xx)
| Status | Code | Description | Action |
|---|---|---|---|
400 | unknown_form | Form ID doesn't exist | Check GET /forms |
400 | invalid_format | Bad output format | Use: json, csv, pdf_typed |
400 | invalid_schema | Malformed column schema | Check column types |
400 | parse_failed | NL prompt not parseable | Rephrase with clearer names |
401 | — | Key missing, invalid, or revoked | Check Authorization header |
403 | — | Missing required scope | Create key with needed scope |
404 | — | Resource not found | Check ID; you can only access your own resources |
409 | job_not_completed | Download before job finishes | Poll until completed |
410 | — | Tabular data expired (>48h) | Re-run the job |
429 | — | Rate limit exceeded | Wait and retry with backoff |
Server Errors (5xx)
| Status | Description | Action |
|---|---|---|
500 | Internal server error | Retry after a brief delay |
502 | Backend unavailable | Service is temporarily down; retry |
Retry Strategy
import time, httpx
def request_with_retry(method, url, **kwargs):
for attempt in range(5):
resp = httpx.request(method, url, **kwargs)
if resp.status_code != 429:
return resp
wait = min(2 ** attempt, 30)
time.sleep(wait)
return resp
TipDon't retry 4xx errors (except 429) — they indicate a problem with your request.