Two Anthropic features combine neatly for document Q&A workloads. The Files API (beta) lets you upload a document to Anthropic's storage once and get back a file_id you can reference in any later Messages request instead of re-sending the bytes. Citations make Claude's answers point at the exact passages in that document that support each claim. This article walks through wiring them together and reading what comes back.
Step 1: upload once, keep the file_id
The Files API is in beta, gated behind the header anthropic-beta: files-api-2025-04-14. The SDKs add it automatically on beta.files calls, but note that the Messages requests that later reference the file must carry the header too. Uploaded files are immutable, persist until you delete them, and are scoped to the workspace of the uploading API key — any key in the same workspace can reference them. Limits: 500 MB per file, 500 GB total per organization, and a beta rate limit of roughly 100 file-related API calls per minute. Upload, list, metadata, and delete operations are all free; you pay normal input-token pricing only when the file content is actually used in a Messages request.
What a file becomes in a request depends on its type: PDFs and text/plain files (including .txt, .csv, and .md uploaded as plain text) map to document blocks — the citable kind — while images map to image blocks and other formats to container_upload blocks for the code execution tool. Word and Excel files are not supported in document blocks; convert them to text or PDF first.
Step 2: reference it in a document block with citations enabled
A document block that references a file_id supports the same optional fields as an inline document: title, context, and citations: {"enabled": true}. Here is the full round trip on Claude Platform on AWS:
from anthropic import AnthropicAWS
client = AnthropicAWS() # AWS_REGION + ANTHROPIC_AWS_WORKSPACE_ID set
f = client.beta.files.upload(file=open("employee-handbook.pdf", "rb"))
msg = client.beta.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
betas=["files-api-2025-04-14"],
messages=[{"role": "user", "content": [
{"type": "document",
"source": {"type": "file", "file_id": f.id},
"title": "Employee handbook",
"citations": {"enabled": True}},
{"type": "text", "text": "What is the parental leave policy?"}]}])
Two rules carry over from ordinary citations: enabling is all-or-nothing across every document in the request, and citation-enabled documents cannot be combined with structured outputs (output_config.format) — that pairing returns a 400 error.
Step 3: read the citation objects
Claude's answer comes back as text blocks carrying citations arrays. The shape of each citation depends on the document type, not on how you supplied it — a stored file is cited exactly like the same document sent inline:
| Document type | Citation type | Points at |
|---|---|---|
| Plain text | char_location | 0-indexed character ranges (sentence-chunked) |
page_location | 1-indexed page ranges | |
| Custom content | content_block_location | 0-indexed content-block ranges |
Every citation also carries a document_index — 0-indexed across all document blocks in the request, in order — plus the cited text itself. Billing is friendly here: enabling citations slightly increases input tokens (system-prompt additions and chunking), but cited_text does not count toward output tokens, and when you pass it back in later turns it does not count as input either. If you stream, citations arrive as citations_delta events inside content_block_delta, one citation per delta.
Where this pattern runs — and where it can't
The citations feature itself is broadly available: GA on the Claude API, Claude Platform on AWS, Amazon Bedrock, and Google Vertex AI, and listed as a supported capability in Microsoft's Foundry documentation. The Files API is the narrower half of the pair: it is available on the Claude API, Claude Platform on AWS, and Microsoft Foundry (where it requires a Hosted on Anthropic deployment), and it is not currently available on Amazon Bedrock or Google Cloud. On Bedrock and Vertex you can still get identical citations — you just supply the document inline as base64 in each request instead of by file_id, or lean on prompt caching to avoid re-processing costs. One compliance note: citations are eligible for Zero Data Retention, but the Files API is not — stored files follow the standard retention policy, which may matter to your security review.
Where to go next
For finer-grained attribution than sentences or pages, see contract review at the retrieval-architecture level, which uses the custom content document type. For the RAG-oriented sibling of document citations, read how search_result content blocks work.