For the complete documentation index, see llms.txt. This page is also available as Markdown.

Extractions

Run a field schema over many documents or papers and get a table back, with a citation per cell.

Endpoints

MethodPathScopeCreditsDescription
POST/v1/extraction-schemasextractions:write0Create a reusable schema
GET/v1/extraction-schemas/{id}extractions:read0Retrieve
POST/v1/extractionsextractions:write2 or 5 per sourceRun a schema (async)
GET/v1/extractions/{id}extractions:read0Retrieve rows
POST/v1/extractions/{id}/exportextractions:read0csv, xlsx, ris → File

This endpoint is asynchronous

Large runs finish per-document. Partial results are readable while status: running.

Parameters

ParameterTypeRequiredDescription
schema_id or schemastring / objectyesReusable ID, or an inline schema
document_idsstring[]one of
paper_idsstring[]one of
depthenumno

The extraction object

json
{ "object": "extraction", "id": "extr_4c8pn0wsz2", "status": "succeeded", "schema_id": "exsc_2hq7bnv6ld", "row_count": 512, "rows": [ { "source": { "type": "document", "id": "doc_…" }, "values": { "sample_size": { "value": 4500000, "citation": { "quote": "…", "locations": [ { "page": 7, "bbox": {} } ] } }, "intervention": { "value": null, "citation": null } }, "error": null } ] }
  • Every value is { value, citation }. A field that could not be found is null with citation: null — the extractor does not guess.

  • Per-row error isolates failures: one unparseable PDF does not fail the run.

Partial failure

A run does not fail as a whole. Each source succeeds or fails on its own, and the extraction reaches succeeded with per-row status — so always read rows[].status, never just the top-level one.

json
{ "object": "extraction", "id": "extr_4c8pn0wsz2", "status": "succeeded", "schema_id": "exsc_2hq7bnv6ld", "row_count": 3, "succeeded_count": 2, "failed_count": 1, "credits_cost": 4, "rows": [ { "source": { "type": "document", "id": "doc_8ba2f01c47" }, "status": "succeeded", "fields": { "sample_size": 384, "study_design": "randomised controlled trial", "primary_outcome": "30-day mortality" }, "citations": [ { "field": "sample_size", "quote": "384 patients were randomised", "locations": [ { "page": 3, "bbox": {} } ] } ], "error": null }, { "source": { "type": "document", "id": "doc_1f7cba9e05" }, "status": "succeeded", "fields": { "sample_size": null, "study_design": "cohort", "primary_outcome": "readmission" }, "citations": [], "error": null }, { "source": { "type": "document", "id": "doc_5aa30bd812" }, "status": "failed", "fields": null, "citations": [], "error": { "type": "invalid_request_error", "code": "document_not_parseable", "message": "Document has no extractable text layer." } } ] }

Note the difference between the two succeeded rows: a null field means the model looked and did not find it, which is a finding. A failed row means nothing was read at all, which is a retry. Do not collapse the two.

Reconciling a run

Retry only the failed rows, and only for causes that can change. document_not_parseable will fail identically forever — send it to a human.

Python
RETRYABLE = {"extraction_timeout", "model_overloaded"} def reconcile(extraction, schema_id, max_rounds=3): results = {r.source.id: r for r in extraction.rows if r.status == "succeeded"} pending = [r.source.id for r in extraction.rows if r.status == "failed" and r.error.code in RETRYABLE] quarantine = [r for r in extraction.rows if r.status == "failed" and r.error.code not in RETRYABLE] for _ in range(max_rounds): if not pending: break run = client.extractions.create( schema_id=schema_id, sources=[{"type": "document", "id": i} for i in pending], ).wait(timeout=600) for row in run.rows: if row.status == "succeeded": results[row.source.id] = row pending = [r.source.id for r in run.rows if r.status == "failed" and r.error.code in RETRYABLE] return results, quarantine + [{"id": i, "reason": "retries_exhausted"} for i in pending]

Retries are charged

Each retried source costs its per-source price again. Cap the rounds, and never retry a permanent error — see cost-control.

Errors

StatuscodeWhen
400schema_invalidunsupported field type or empty fields
413too_many_sourcesmore than 500 sources in one run

Limits and cost

LimitValue
Credits2 per source at standard, 5 at high_quality — independent of field count
Sources per run500
Fields per schema50
Field typesstring, integer, number, boolean, date, enum, string[]
Concurrencyone run holds one async slot; see rate-limits
Retentionrows kept until you delete the extraction or its documents

Cost is per source, not per field, so a 50-field schema costs the same as a 5-field one. Write the schema you actually want.

extraction-schema · batch-extraction · citation · files

Last updated