Why a packet, not just a file
Extraction is scoped to the packet, not to the individual files inside it. That means:- Cross-file context is preserved — parse and extract see the whole bundle at once, not one file at a time.
- Results come back at the packet level, as a single set of extracted fields for the whole document.
- Classify, split, and validate operate on the packet as one input.
Packets and files
| What it is | What it’s for | |
|---|---|---|
| Document packet | The bundle. The runnable unit. | The handle you upload, run, and pull results against. |
| File | One artifact inside the packet — a PDF, an image, an email. | Reading an individual file’s parsed content or per-file breakdown. |
Two API names — one object. On v3 the packet is addressed natively: every request and response uses
document_packet_id (see the packet endpoints). The frozen v2 surface still calls the same object a file collection — file_collection_id, sometimes collection_id — used the same way. The ids are interchangeable across versions; mapping details in the migration guide.How you get one
You create a packet by uploading. Two ways to hand anyformat the bytes:- Direct upload (multipart) — send the file bytes in the request. The response comes back with
status: "uploaded"once the bytes are in storage; you can run immediately. Best when the bytes are on the user’s machine or in your app’s memory. - From a URL — give anyformat an HTTPS URL (a presigned S3 link, a hosted asset) and the server fetches the bytes for you. Best when the file already lives in object storage you can presign, or at a public URL — no need to stream it through your backend.
Two API shapes — one concept. On v3, upload with
POST .../upload/ (multipart, 1–10 files into one packet) or POST .../upload/from-url/ (1–10 HTTPS URLs, all-or-nothing) — the URL import is atomic, so a 201 means the packet is fully in storage and there is no pending-fetch state to reason about. On v2, use POST .../files/ or POST .../files/from-url/, where the URL fetch completes asynchronously: the response returns status: "pending" while the fetch is in flight, and you should trigger the run on the returned packet id straight away rather than polling the packet listing — the listing’s status reflects extraction state, not upload-fetch state.One file vs. multiple files
One file (the default). Every upload creates its own single-file packet. In everyday use the packet id and the file id are effectively interchangeable — you address the packet. Multiple files. Bundle them into one packet only when they belong together as a single document. The packet is then processed as a whole; extraction runs over the bundle, not file-by-file. If two files are unrelated, upload them as two packets — that keeps their results independent.What’s next?
Files
Supported formats, size limits, and per-file mechanics
Runs & results
What happens when you run a workflow on a packet, and the shape of what comes back
