Skip to main content
A document packet is the unit a workflow runs on: one or more files that anyformat treats as a single document. Almost always it’s a packet of one — you upload a file, you get a packet, and the two ideas line up 1-to-1. The packet only stands out as its own concept when you deliberately bundle several files (say, a contract and its two annexes) that belong together for extraction.

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.
For a one-file packet this looks identical to file-level processing. For a multi-file packet, it’s what lets you treat “contract + annexes” or “invoice + supporting scans” as one document.

Packets and files

The packet has an id; each file inside it has its own id too. You spend almost all your time working with packets — file ids only come up when you need to look at one specific file within a multi-file packet.
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 collectionfile_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.
Both produce a packet id you can run, poll, and pull results against. See Files for supported formats and size limits.
Two ways to create a packet. Upload with POST .../upload/ (multipart, 1–10 files into one packet) or POST .../upload/from-url/ (1–10 HTTPS URLs, all-or-nothing; each file is named by its response’s Content-Disposition, else by the URL’s path). 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.

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.

Attaching metadata

Every v3 create path accepts an optional metadata field — a free-form JSON object stapled to the packet at creation time. There is no schema: the only validation is “must be a JSON object”. The value is echoed back verbatim on GET /v3/document-packets/{document_packet_id}/ and, when the packet is run, the extract node sees it inline in its prompt. Two uses come with it out of the box:
  • Carry structured context alongside the bytes. Anything you already know about the document — the vendor id you fetched it for, the account it belongs to, the batch you’re processing — travels with the packet without needing a side channel. Fetch the packet later and the same JSON comes back.
  • Let extraction source a datapoint from your context. A top-level key whose name matches an extract-schema field is picked up: the LLM prefers the metadata value over anything it might read from the document. The extracted field’s evidence then carries the marker text: "metadata.<key>" — a signal you can key on client-side to tell “sourced from caller metadata” apart from “sourced from the document” (see Runs & results → Evidence).
The prompt copy is hardened, because the metadata is your input and the prompt is an instruction channel: control characters collapse to spaces, each value is capped at 512 characters, and the whole block is capped at 8192 characters. A block over that cap keeps as many top-level keys as fit, in alphabetical order, and the platform logs which keys it dropped. The packet itself still echoes your original JSON back verbatim. Send it as a JSON-encoded string on the multipart uploads (.../upload/ and .../upload/run/) — multipart can’t carry a nested object natively — and as a plain JSON object on the URL import (.../upload/from-url/).

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