From upload to a cited answer in one file.
Work server-side. Parse a document, index it, then stream a grounded answer from that context. The SDK waits for async steps by default; pass wait=False to manage polling yourself.
Install
Add the SDK to your backend service, or start with curl while wiring env vars.
export INFRATEX_API_KEY=infratex_sk_...Get an API key
Create a key in the dashboard. The full key is shown once — store it in server secrets.
Authorization: Bearer infratex_sk_your_key_here# 1. Parse
curl -X POST https://api.infratex.io/api/v1/documents \
-H "Authorization: Bearer $INFRATEX_API_KEY" \
-F "file=@contract.pdf" -F "method=standard"
# 2. Index (after status is "parsed")
curl -X POST https://api.infratex.io/api/v1/documents/{id}/indexes \
-H "Authorization: Bearer $INFRATEX_API_KEY" \
-H "Content-Type: application/json" -d '{"method":"hybrid"}'
# 3. Stream a cited answer
curl -N -X POST https://api.infratex.io/api/v1/responses \
-H "Authorization: Bearer $INFRATEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"message":"Summarize termination rights.","method":"hybrid","model":"fast","document_ids":["{id}"],"limit":5}'One resource model, Python or Node.
Python
ETL workers, extraction jobs, notebooks, and backend APIs. Sync client, waits by default.
pip install infratexNode.js
Next.js route handlers, Express, queues, and streaming backends. Zero-dependency, native fetch.
npm install infratexBoth SDKs expose the same resources — documents, extractions, searches, responses, collections, conversations, account, billing — and the same wait-by-default contract. Python uses snake_case; Node uses camelCase.
from infratex import Infratex
client = Infratex(api_key="infratex_sk_...")
doc = client.documents.upload("board_pack.pdf", method="standard")
client.documents.wait_until_parsed(doc.id)
markdown = client.documents.markdown(doc.id)
print(markdown[:1000])One header, tenant-scoped.
Every /api/v1/* route takes a server-side API key as a bearer token. Create keys in the dashboard — the full infratex_sk_... value is shown once. Keys are stored as SHA-256 hashes and never expire until revoked.
Authorization: Bearer infratex_sk_your_key_hereKeep keys server-side. Rotate on exposure. Scope work per tenant with separate keys.
Ship keys in browser or mobile bundles. Public, dashboard-only routes (keys, templates, AST) return 403 to API keys.
PDFs and images into clean Markdown.
Upload a PDF or an ordered image batch. Parsing is asynchronous — upload returns 202 with a pending document, then you poll status or let the SDK wait. The parse method you pick controls the engine, table fidelity, and cost.
| Method | Engine | Tables | Credits / page | Best for |
|---|---|---|---|---|
standard | Fast multimodal | Markdown pipe tables | 1cr | Default. Fast, high-quality Markdown for most documents. |
max | Fast multimodal | Markdown tables | 3cr | Adds [visual-note] lines for charts, figures, and photos. |
infratex-phi | In-house · self-deployable | OTSL tables; charts tabulated | 3cr | Dense tables, financial statements, faithfulness-first OCR. |
standard-ultra-2 | High-fidelity vision | Raw HTML tables (colspan/rowspan) | 3cr | Complex nested tables. API-only, advanced. |
Start with standard. Reach for max when figures and charts carry meaning, or infratex-phi for table-dense financial and legal documents. standard-ultra-2 is API-only for complex nested HTML tables.
/api/v1/documentsHTTP 202Upload a PDF
Multipart file + method + optional collection_id. Returns a pending document.
/api/v1/documents/imagesHTTP 202Upload page images
Repeated files — file order is page order. PNG, JPEG, WebP.
/api/v1/documents/{id}/markdownGet Markdown
Returns extracted Markdown as text/markdown after parsing.
/api/v1/documents/{id}Rename or move
Set filename, collection_id, or remove_collection.
Upload parameters — POST /api/v1/documents
| Parameter | Type | Default | Description |
|---|---|---|---|
filerequired | file | — | Single PDF, ≤ 50 MB. Must be a valid PDF. |
method | string | standard | One of standard, max, infratex-phi, standard-ultra-2. |
collection_id | uuid | — | Assign to an owned collection on upload. |
List parameters — GET /api/v1/documents
| Parameter | Type | Default | Description |
|---|---|---|---|
status | enum | — | Filter by pending, processing, parsed, indexed, error. |
collection_id | uuid | — | Filter by collection. |
limit | int | 50 | Page size. |
offset | int | 0 | Pagination offset. |
curl -X POST https://api.infratex.io/api/v1/documents \
-H "Authorization: Bearer $INFRATEX_API_KEY" \
-F "file=@report.pdf" \
-F "method=standard" \
-F "collection_id=col_123"
# then, after status is "parsed":
curl https://api.infratex.io/api/v1/documents/{id}/markdown \
-H "Authorization: Bearer $INFRATEX_API_KEY"Structured fields, with evidence.
Pull typed fields out of a parsed document. Provide inline inline_fields, or reference a dashboard template_id — exactly one. Set include_evidence to get the source span behind every value.
Extraction reads your document's parsed Markdown, so parse quality drives extraction quality. For dense tables parse with infratex-phi; for charts and figures use max. Large documents (Tier L) also require a ready vector or hybrid index before extracting.
Field types
| Type | Extra key | Shape |
|---|---|---|
string | — | { "name": "counterparty", "type": "string", "description": "Legal name" } |
number | — | { "name": "fee", "type": "number", "description": "Termination fee" } |
integer | — | { "name": "term_months", "type": "integer", "description": "Term length" } |
boolean | — | { "name": "auto_renews", "type": "boolean", "description": "Auto-renewal?" } |
date | — | { "name": "effective_date", "type": "date", "description": "Effective date" } |
enum | enum_values | { "type": "enum", "enum_values": ["NY","DE","CA"], ... } |
object | properties | { "type": "object", "properties": [ ...fields ], ... } |
array | items | { "type": "array", "items": { ...field }, ... } |
Every field needs name (1–64, ^[a-zA-Z_][a-zA-Z0-9_]*$) and a description (required). Optional instructions and required refine behavior. Nest with object.properties and array.items; an array<object> field is what CSV/XLSX export reads. Max 50 fields per run.
/api/v1/documents/{id}/extractionsHTTP 202Create a run
Inline fields or a template_id. Returns pending.
/api/v1/extractions/{run_id}Poll or fetch
Add include_evidence=true for evidence payloads.
/api/v1/documents/{id}/extractionsList runs
Prior runs for a document. limit 1–100.
/api/v1/extractions/{run_id}/exportExport tabular
format=xlsx (default) or csv for array<object> fields.
Run parameters — POST /api/v1/documents/{id}/extractions
| Parameter | Type | Default | Description |
|---|---|---|---|
inline_fields | FieldDefinition[] | — | Inline schema. Exactly one of this or template_id. |
template_id | uuid | — | Reference a dashboard-managed template. |
inline_system_prompt | string | — | Optional guidance (≤ 8000). Only valid with inline_fields. |
model | string | fast | fast or pro for harder documents. |
include_evidence | bool | false | Return per-field source evidence. |
curl -X POST https://api.infratex.io/api/v1/documents/{id}/extractions \
-H "Authorization: Bearer $INFRATEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "fast",
"include_evidence": true,
"inline_fields": [
{"name": "counterparty", "type": "string", "description": "Legal name of the counterparty"},
{"name": "effective_date", "type": "date", "description": "Contract effective date"}
]
}'
# poll (add ?include_evidence=true for evidence)
curl "https://api.infratex.io/api/v1/extractions/{run_id}?include_evidence=true" \
-H "Authorization: Bearer $INFRATEX_API_KEY"Build retrieval before you search or answer.
Indexing turns parsed Markdown into retrieval artifacts. It's asynchronous — poll GET /api/v1/documents/{id}/indexes/{method} until status is indexed.
Vector embeddings over chunks. Good default for natural-language questions. 20 credits / 1M tokens.
Vector + keyword + document-structure (AST) retrieval. Recommended for contracts, filings, and tables. 100 credits / 1M tokens.
/api/v1/documents/{id}/indexesHTTP 202Create index
Queues vector or hybrid indexing for a parsed document.
/api/v1/documents/{id}/indexes/{method}Get index status
Poll until status is indexed before search or responses.
Parameters — POST /api/v1/documents/{id}/indexes
| Parameter | Type | Default | Description |
|---|---|---|---|
method | string | vector | vector or hybrid. |
Search and responses require a ready index for the selected method. If you request hybrid, the selected documents or collection must already have a hybrid index.
curl -X POST https://api.infratex.io/api/v1/documents/{id}/indexes \
-H "Authorization: Bearer $INFRATEX_API_KEY" \
-H "Content-Type: application/json" -d '{"method":"hybrid"}'Cited context, no generation.
Search returns ranked chunks for previews, evidence panels, and retrieval debugging. Send one scope: document_ids or collection_id (not both).
/api/v1/searchesSearch indexed context
Returns ranked chunks with document, page, score, content, and metadata.
Parameters — POST /api/v1/searches
| Parameter | Type | Default | Description |
|---|---|---|---|
queryrequired | string | — | 1–4000 characters. |
method | string | vector | vector or hybrid. |
limit | int | 5 | Results to return. 1–50. |
document_ids | uuid[] | — | Restrict to these documents. Mutually exclusive with collection_id. |
collection_id | uuid | — | Restrict to a collection. Mutually exclusive with document_ids. |
curl -X POST https://api.infratex.io/api/v1/searches \
-H "Authorization: Bearer $INFRATEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"Find indemnity carve-outs","method":"hybrid","document_ids":["doc_123"],"limit":5}'Stream grounded, cited answers.
Lower-latency model for product surfaces, summaries, and routine Q&A.
Higher-capability model for complex synthesis, legal analysis, and cross-document questions.
/api/v1/responsesCreate streaming response
Server-sent events: sources, thinking (when enabled), text deltas, then done.
Parameters — POST /api/v1/responses
| Parameter | Type | Default | Description |
|---|---|---|---|
messagerequired | string | — | 1–8000 characters. |
method | string | vector | vector or hybrid. |
model | string | fast | fast or pro. |
reasoning | bool | false | When true, streams thinking events before text. |
limit | int | 5 | Source chunks. 1–20 (tighter than search's 50). |
document_ids | uuid[] | — | Mutually exclusive with collection_id. |
collection_id | uuid | — | Mutually exclusive with document_ids. |
conversation_id | uuid | — | Continue a thread. Omit scope selectors — scope comes from the conversation, else 400 conversation_scope_locked. |
Stream events
sourcesRetrieved source chunks, streamed first so UIs can render evidence.thinkingReasoning deltas — only when reasoning=true.textAnswer text deltas.doneStream complete.errorAn error occurred mid-stream.curl -N -X POST https://api.infratex.io/api/v1/responses \
-H "Authorization: Bearer $INFRATEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"message":"What are the top risks?","method":"hybrid","model":"fast","collection_id":"col_123","limit":8,"reasoning":false}'Create a conversation to persist scope across turns, then pass only conversation_id to each response — the conversation supplies document_ids / collection_id.
Group documents, persist threads.
Collections are a durable scope you can search and answer over together. Conversations persist a multi-turn thread with a fixed scope.
/api/v1/collectionsCreate collection
{ name } (1–255). Group documents for retrieval and responses.
/api/v1/documents/{id}Move document
Set collection_id or remove_collection on a document.
/api/v1/conversationsCreate conversation
{ title?, document_ids? | collection_id? } — scope is mutually exclusive.
/api/v1/conversations/{id}Get conversation
Returns the thread and its messages.
{
"message": "Compare warranty limits across the uploaded agreements.",
"method": "hybrid",
"model": "pro",
"collection_id": "col_123",
"limit": 10,
"reasoning": true
}Connect agent clients to the same pipeline.
The remote MCP server exposes the full pipeline — parsing, indexing, retrieval, and grounded answers — to any MCP client. Connect with a server-side API key (Claude Code, Claude Desktop, Cursor) or via OAuth (ChatGPT, Claude.ai web). Both resolve to the same tenant scope and billing as REST.
Streamable HTTP. The trailing slash is required — the no-slash URL redirects and most clients will fail to connect.
Claude Code, Claude Desktop, Cursor. Send Authorization: Bearer infratex_sk_... — no OAuth round-trip.
ChatGPT and Claude.ai web. Paste the URL; the client self-registers, then you sign in and approve on the Infratex consent screen.
claude mcp add --transport http infratex https://api.infratex.io/mcp/ \
--header "Authorization: Bearer infratex_sk_..."
# verify — status should be: ✔ Connected
claude mcp get infratex{
"mcpServers": {
"infratex": {
"type": "http",
"url": "https://api.infratex.io/mcp/",
"headers": {
"Authorization": "Bearer infratex_sk_..."
}
}
}
}Vector or hybrid retrieval across documents or collections.
Generate cited answers from indexed context.
Queue PDF parsing from a base64 payload.
Queue parsing for ordered image batches.
Queue vector or hybrid indexing.
Fetch extracted Markdown for a parsed document.
ChatGPT Deep Research: ranked results with id, title, text, url.
ChatGPT Deep Research: full document text for a result id.
Errors, credits, and the endpoint map.
Error codes
| Status | Meaning |
|---|---|
400 | Bad request — e.g. conversation_scope_locked, invalid_pdf. |
401 | Missing or invalid API key. |
402 | Insufficient credits. |
403 | Endpoint not available via API key (dashboard-only). |
409 | Not ready — document_not_ready, index_required_for_tier_l, extraction_not_done. |
413 | Payload too large — payload_too_large, context_too_large. |
415 | Unsupported media type. |
422 | Validation error — too_many_fields, markdown_unavailable. |
429 | Rate limited. |
Credits — 1 credit = $0.005
| Parameter | Type | Default | Description |
|---|---|---|---|
parse.standard | per page | — | 1 credit / page. |
parse.max / infratex-phi / standard-ultra-2 | per page | — | 3 credits / page. |
index.vector | per 1M tokens | — | 20 credits. |
index.hybrid | per 1M tokens | — | 100 credits. |
search.vector | per search | — | 2 credits. |
search.hybrid | per search | — | 10 credits. |
response.fast | per 1M tokens | — | 1500 in / 9000 out. |
response.pro | per 1M tokens | — | 5000 in / 30000 out. |
Documents
POST /api/v1/documentsPOST /api/v1/documents/imagesGET /api/v1/documents/{id}PATCH /api/v1/documents/{id}GET /api/v1/documents/{id}/markdownDELETE /api/v1/documents/{id}Retrieval
POST /api/v1/documents/{id}/indexesGET /api/v1/documents/{id}/indexesPOST /api/v1/searchesPOST /api/v1/responsesExtraction
POST /api/v1/documents/{id}/extractionsGET /api/v1/documents/{id}/extractionsGET /api/v1/extractions/{run_id}GET /api/v1/extractions/{run_id}/exportAccount
GET /api/v1/accountGET /api/v1/account/settingsGET /api/v1/billingGET /api/v1/collectionsPOST /api/v1/collectionssearches.limit accepts 1–50; responses.limit accepts 1–20. Easy to conflate — the response context window is tighter on purpose.