Skip to main content
v3 replaces v2’s file-centric surface with three first-class resources: workflows, document packets, and runs. The extraction engine, the results envelope, authentication, and the error envelope are unchanged. The paths, the identifiers, and the read model moved.
API v2 is retired. Every /v2/ request now answers 410 Gone with error_code ENDPOINT_RETIRED. Where a v2 operation has a direct v3 successor, the response’s Link header names it with rel="successor-version". Webhook management was v2-only, so v3 has no webhook endpoints: poll Get run until the run finishes.

The one-sentence version

Where v2 had a file or a collection, v3 has a document packet; where v2 polled a nested /results/ path, v3 reads a flat run that returns status and results in one 200.

Path-by-path mapping

Workflows

Uploading documents

v2’s text form field accepted plain text instead of a file. v3 has no counterpart: upload the text as a small .txt file in the multipart files field.

Reading packets and results

Standalone parse


Identifier renames

v2’s file_id / collection_id / file_collection_id all collapse into one identifier: A v2 collection is a v3 document packet: the same underlying object under one name. Per-file ids still exist inside a packet, as files[].id on packet responses, for the rare case where you address one file of a packet with several files. Path parameters are always snake_case: workflow_id, document_packet_id, run_id.

Semantic changes

Results polling: 412 to inline status

v2’s results read returned 412 Precondition Failed while the extraction was in flight, so clients had to treat an error status as “not yet”. In v3, GET /v3/runs/{run_id}/ always returns 200 while the run exists:
  • status tells you where the run is: queued, in_progress, processed, error, or cancelled.
  • results is null until status reaches processed, then carries the results envelope inline.
  • A run that ended in error or cancelled stays readable with results: null.
The results envelope stays byte-compatible with v2’s, down to the parse, classifications, splits and extractions sections. See Get run. Only the read path moved.

PUT to PATCH: field identity round-trips

v2 edited workflows with PUT /v2/workflows/{id}/, and the round-trippable graph lived on a separate GET .../definition/. v3 folds both into the workflow resource:
  1. GET /v3/workflows/{workflow_id}/ returns the workflow with its graph inline. Every field carries its server-assigned persistent_id.
  2. Mutate the graph and keep only {name, description, nodes, edges}, then send it back via PATCH /v3/workflows/{workflow_id}/. The read-only id, created_at and updated_at are rejected with 400 VALIDATION_ERROR.
  3. Echo each field’s persistent_id unchanged, including across renames. The field then keeps its identity: analytics history, ground truth, and quality metrics stay attached.
  4. The PATCH response echoes the stored graph back in the exact GET shape, including new fields with their freshly assigned persistent_ids. Edit that and PATCH again.
Omit persistent_id only for a genuinely new field, and the server assigns one. A field without persistent_id is always new. Omitting it on an existing field replaces that field and detaches its history. An echoed persistent_id that matches no field in the current version is rejected with 400. v3 has no PUT.

Pagination: offset to keyset

v2 lists used ?page= / ?page_size= with a count total. v3 lists return {items, next_cursor}:
  • Pass ?cursor=<next_cursor> to fetch the next page; stop when next_cursor is null.
  • ?limit= caps at 100. A larger value returns 400; the API does not clamp it.
  • v3 returns no totals or page numbers. If you rendered count in a UI, switch to cursor-driven “load more” semantics.
See Pagination.

Idempotency (new)

The packet-creating and run-triggering POSTs accept an Idempotency-Key header. Retrying with the same key replays the original response instead of creating a duplicate packet or billing a second extraction. v2 had no equivalent. Delete any retry-dedup logic you built client-side. See Idempotency.

Version header

Every /v3/ response is stamped X-API-Version: 3.0.0. If you tag metrics by API version, this header is the reliable source.

What did not change

  • Authentication: the same API keys and the same Authorization: Bearer header.
  • Error envelope: the same {error, detail, error_code, retryable, request_id} shape. See Errors.
  • Results envelope: the same parse, classifications, splits and extractions sections. See Get run.
  • Rate limiting: the same two-tier limits and x-ratelimit-* headers.
  • The typed-graph workflow body: POST /v3/workflows/ accepts the same {name, description, nodes, edges} shape as POST /v2/workflows/.

Migration checklist

  1. Swap base paths /v2/ → /v3/ per the tables above; rename file_id / collection_id variables to document_packet_id.
  2. Replace /results/ polling (412-tolerant) with GET /v3/runs/{run_id}/ polling on status.
  3. Replace PUT workflow edits with GET → mutate → PATCH, preserving persistent_ids.
  4. Replace page/page_size pagination with cursor/limit; drop any use of count.
  5. Add an Idempotency-Key to upload and run-trigger POSTs if you retry on timeouts.