v2 keeps working through its deprecation window. Every
/v2/ response now carries Deprecation and Sunset headers (RFC 8594) announcing the retirement date. Nothing breaks today — but new integrations should start on v3, and existing ones should plan the move. See Versioning & deprecation for how to alert on these headers automatically. The v2 deprecation timeline has the exact window dates and the per-route successor Link headers.The one-sentence version
Where v2 said file or collection, v3 says document packet; where v2 made you poll a nested/results/ sub-path, v3 gives every execution its own run you read flat — status and results in one 200.
Path-by-path mapping
Workflows
Uploading documents
v2’s
text form field (plain text instead of a file) has no dedicated v3 counterpart — upload the text as a small .txt file in the multipart files field instead.Reading packets and results
Identifier renames
v2’sfile_id / collection_id / file_collection_id all collapse into one identifier:
A v2 collection is a v3 document packet — same underlying object, one name. Per-file ids still exist inside a packet (
files[].id on packet responses) for the rare case where you need to address one file of a multi-file packet. 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 returned412 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:
statustells you where the run is:queued,in_progress,processed,error, orcancelled.resultsisnulluntilstatusreachesprocessed, then carries the results envelope inline.- A run that ended in
errororcancelledstays readable withresults: null.
parse, classifications, splits, extractions — is byte-compatible with v2’s; see Response formats. Only the read path moved.
PUT to PATCH: field identity round-trips
v2 edited workflows withPUT /v2/workflows/{id}/, and the round-trippable graph lived on a separate GET .../definition/. v3 folds both into the workflow resource:
GET /v3/workflows/{workflow_id}/returns the workflow with its graph inline — every field carries its server-assignedpersistent_id.- Mutate the graph, keep only
{name, description, nodes, edges}(the read-onlyid,created_at,updated_atare rejected with422), and send it back viaPATCH /v3/workflows/{workflow_id}/. - Echo each field’s
persistent_idunchanged — including across renames — and the field keeps its identity: analytics history, ground truth, and quality metrics stay attached. - The PATCH response echoes the stored graph back in the exact GET shape (new fields included, with their freshly assigned
persistent_ids), so you can edit and PATCH again.
persistent_id only for genuinely new fields — the server assigns one. A field without persistent_id is always treated as new, so omitting it on an existing field replaces that field with a fresh one and detaches its history. An echoed persistent_id that doesn’t match any field in the current version is rejected with 400. There is no PUT in v3.
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 whennext_cursorisnull. ?limit=caps at 100 — values above are rejected with400, not clamped.- There are no totals or page numbers. If you rendered
countin a UI, switch to cursor-driven “load more” semantics.
Idempotency (new)
The packet-creating and run-triggering POSTs accept anIdempotency-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 — if you built retry-dedup logic client-side, you can delete it. See Idempotency.
Version header
Every/v3/ response is stamped X-API-Version: 3.0.0 (v2 responses say 2.0.0 and additionally carry Deprecation / Sunset). If you tag metrics by API version, the header is the reliable source.
What did not change
- Authentication — same API keys, same
Authorization: Bearerheader. - Error envelope — same
{error, detail, error_code, retryable, request_id}shape (Errors). - Results envelope — same
parse/classifications/splits/extractionssections (Response formats). - Rate limiting — same two-tier limits and
x-ratelimit-*headers. - Webhooks — existing webhook subscriptions keep firing; management stays on the current endpoints (Webhooks).
- The typed-graph workflow body —
POST /v3/workflows/accepts the same{name, description, nodes, edges}shape asPOST /v2/workflows/.
Migration checklist
- Swap base paths
/v2/→/v3/per the tables above; renamefile_id/collection_idvariables todocument_packet_id. - Replace
/results/polling (412-tolerant) withGET /v3/runs/{run_id}/polling onstatus. - Replace
PUTworkflow edits with GET → mutate →PATCH, preservingpersistent_ids. - Replace
page/page_sizepagination withcursor/limit; drop any use ofcount. - Add an
Idempotency-Keyto upload and run-trigger POSTs if you retry on timeouts. - Wire an alert on the
Sunsetheader so your v2 traffic can’t outlive the window unnoticed — see the header reference.
