Every business runs on documents.
Contracts decide what was promised. Invoices decide what is owed. Policies decide what is allowed. Reports decide what happened. The truth of an organization doesn't live in its chat logs or its dashboards. It lives in its files.
And for decades, we've treated those files as attachments. Blobs in a bucket. Something to store, download, and forget.
AI changed the stakes. Models can finally read, reason, and act on what's inside a document. But they can only be as trustworthy as the context we hand them. Feed a model a mangled string of OCR output and it will confidently answer from it. Give it no source and it will invent one.
The AI era doesn't need more models. It needs a foundation they can stand on.
We call that foundation document infrastructure. These are the principles we build it by.
A document has a shape. Titles, sections, paragraphs, tables, figures, footnotes. Reading order. Pages. That shape is meaning.
Here's what an annual report becomes when you flatten it into text:
2026 Annual Report
Revenue increased by 24%.
Regional Performance
North America
$12.4M
Europe
$8.7M Which line is a heading? Which is a table cell? Nobody can tell anymore, least of all a model.
We refuse to throw that shape away. In Paperful, every document becomes a Paper, and every Paper becomes a Paper Graph: an ordered sequence of nodes that remember what they are and where they came from.
const graph = await paperful.papers.graph(paper.id);
for (const node of graph.nodes) {
console.log(node.position, node.type, node.page);
} An answer without a source is a rumor.
That might be fine for brainstorming. It is not fine for insurance claims, customer contracts, financial reports, or the policy that decides whether someone gets paid. In those places, "trust me" is not a feature.
Citations are not a UI detail to bolt on at the end. They are a primitive. Every passage your system retrieves should carry its document, its page, and its place on that page, so a person can always check the work.
Search results in Paperful point straight into the Paper Graph. The citation is already there:
const { items } = await paperful.search.query("What are the payment terms?");
for (const result of items) {
for (const { page } of result.nodes) {
console.log(`${result.paper.fileName}, page ${page}`);
}
} A number in a vendor quote can be a unit price or a page total. A column belongs to a specific SKU. A footnote quietly changes the delivery date. Plain text keeps all the characters and loses all the relationships.
When the structure matters, work with the structure:
const tables = graph.nodes.filter((node) => node.type === "table"); No regex archaeology. No guessing where the table ended. See Read the paper graph.
An agent should never see a document simply because it happened to sit in the same index.
A support copilot answers for this customer, not every customer on your platform. A contract assistant searches these contracts, not the HR folder next door. Scoping is not an optimization. It's a boundary, and boundaries belong at the start of the retrieval path, not bolted on after the results come back.
Attach what you already know at the moment a document arrives:
const paper = await paperful.papers.upload({
file,
fileName: "msa-acme.pdf",
metadata: { tenantId: "acme", type: "contract" },
}); Then make every query honor it:
const { items } = await paperful.search.query(
"Does this contract renew automatically?",
{ metadata: { tenantId: "acme", type: "contract" } },
); Filtering results after they come back means the wrong content has already left your retrieval layer. Learn more in Manage metadata.
Stuffing a whole PDF into a prompt is not a retrieval strategy. Neither is a 512-token chunk that split a table from its header.
The right context is small, relevant, and whole: the passage that matched, plus just enough of what surrounds it to make sense.
const [result] = items;
const graph = await paperful.papers.graph(result.paper.id);
const node = graph.nodes.find((n) => n.id === result.nodes[0].id);
const context = await node?.context({ before: 3, after: 3 }); Start from the part you care about. Expand only as far as you need. See Search to context.
A lawyer searching for "change of control" wants those exact words. A founder asking whether a contract renews automatically wants the meaning, whatever words the contract used.
Both are right. Infrastructure that forces you to choose is wrong.
await paperful.search.query("change of control", { mode: "fulltext" });
await paperful.search.query("Does this renew automatically?", { mode: "semantic" });
await paperful.search.query("payment terms"); // hybrid, by default See Choose a search mode.
Upload handling. File lifecycles. Async jobs and retries. OCR vendors. Layout parsers. Metadata stores. Indexes. Chunking strategies. Observability.
Every team building with documents rebuilds this stack, one script at a time, until it's infrastructure nobody meant to own. None of it is what your customers pay you for.
Your product is the workflow, the interface, the judgment about what a good answer looks like in your domain. That's where your engineering should go. The file-to-context pipeline should be something you call, not something you maintain:
import { Paperful } from "@paperful/sdk";
const paperful = new Paperful(); // reads PAPERFUL_API_KEY
const paper = await paperful.papers.upload({ file, fileName: "report.pdf" }); Storage, OCR, layout analysis, enrichment, and search, behind one API and one SDK.
Own the logic. Rent the plumbing. Swap pieces when you need to. This isn't all-or-nothing.
Not every reader of your documents will be a person, or even your code. Assistants and agents are becoming colleagues, and they need the same thing everyone else does: real documents, with real sources.
The Paperful MCP server gives assistants like Claude, ChatGPT, and Cursor read-only access to your Papers. No code. And they cite the document and page for every claim.
https://mcp.paperful.io "Did the model get it right?" is the wrong first question. Ask instead:
Build your evals from real files: bad scans, duplicate versions, multi-column reports, questions with no answer. Track retrieval precision, citation coverage, and how often a human has to step in. Those numbers tell you whether you've built something people can trust, or just something that sounds right.
We're done treating documents as the last mile of software. They are the first mile. The place where facts are recorded, decisions are made, and money changes hands.
The AI era will be built on them, or it will be built on guesses.
We're building the infrastructure for the first one. Start with one workflow: a contract review queue, a policy copilot, an invoice exception flow. Give the documents structure. Preserve their provenance. Make them programmable.
Then watch what your product can do when it can finally read.