The Files API lets you upload a document once and reference it by file_id in as many Messages requests as you want, instead of re-sending bytes every call. It is now GA, so no beta header is required. Files are scoped to your workspace, so never accept a file_id from an untrusted user.
1. Install the SDK and set ANTHROPIC_API_KEY
pip install -U anthropic
Installs the official SDK, which reads your key from the environment.
export ANTHROPIC_API_KEY="sk-ant-..."
Export the key once so anthropic.Anthropic() picks it up with no argument.
2. Upload a file and capture the file_id
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY
uploaded = client.files.upload(
file=("policy.pdf", open("policy.pdf", "rb"), "application/pdf"),
)
print(uploaded.id) # file_...
Uploads a local PDF and returns a FileMetadata object whose id you reuse everywhere.
3. Reference the file_id in a Messages request
msg = client.messages.create(
model="claude-opus-5-5",
max_tokens=1024,
messages=[{"role": "user", "content": [
{"type": "text", "text": "Summarize the cancellation policy."},
{"type": "document", "source": {"type": "file", "file_id": uploaded.id}},
]}],
)
print(msg.content[0].text)
A document block with source.type: "file" points at the stored PDF, no base64 in the payload.
4. List and delete files
for f in client.files.list():
print(f.id, f.filename, f.size_bytes)
client.files.delete(uploaded.id)
Lists every file in the workspace, then removes one by id; deletion cannot be undone.
5. Limits and when to inline instead
One file is capped at 500 MB and the organization total at 1 TB; uploads, lists, and deletes are free, while file content you reference is billed as input tokens. Images use an image block and datasets a container_upload block, both with the same file_id. For a one-off PDF you read once, the inline base64 approach in send a PDF to the Claude API is simpler; reach for the Files API when the same document feeds many requests.
Verify it worked
client.files.list() should show your upload, and the Messages call should answer from the document.
If it fails:
- 404
File ... not found— thefile_idis wrong, deleted, or from another workspace; files are workspace-scoped, so use a key for the same workspace. - 400 invalid file type — you put a PDF in an
imageblock (or vice versa); match the block to the MIME type. - 400 not downloadable — you tried
client.files.download()on a file you uploaded; only files produced by skills or the code execution tool are downloadable.