
Trying out the Claude Files API
This page has been translated by machine translation. View original
This is Suenaga from the Retail App Co-Creation Division.
The Claude API has a Files API that lets you upload a file once and reference it by file_id. This means you don't have to re-attach the same document with every request, and it can also be used for input and output with the code execution (code interpreter) tool. It's a feature that was added about a year ago, but I hadn't really played around with it, so this time I actually ran through everything from upload to deletion to see how it works.
What You Can Do with the Files API
With regular file attachments, you send the file contents with every request, but with the Files API, you upload once and then reference the returned file_id in subsequent Messages requests. The file operations themselves — upload, list, metadata retrieval, deletion, and download — are free, and you're only charged for the input tokens from files attached in Messages requests.
Supported formats include PDFs, plain text, images, and datasets handled by the code execution tool. The file size limit is 500MB per file and 500GB total per organization.
There are restrictions on downloading. You cannot retrieve files you uploaded yourself — only files generated by Claude can be downloaded.
You can only download files that were created by skills or the code execution tool. Files that you uploaded cannot be downloaded.
If you want to download a file that Claude created, you combine it with the code execution tool. The generated file is returned with a file_id, which you then use to download it. Since the goal this time was to verify the upload side of things, I won't cover that here.
Data Handling and Storage Policy
Before using this in a business context, the key question is where uploaded files are stored and for how long.
Files are stored on Anthropic's storage infrastructure and are scoped to the workspace of the API key. Within the same workspace, files can be referenced from other keys as well.
Regarding retention, the standard Anthropic API automatically deletes inputs and outputs within 30 days, but the Files API is an exception — files persist until you explicitly delete them. When handling sensitive files, it's probably a good idea to explicitly delete them once you're done.
Running It in Practice
For testing, I used TypeScript and the official @anthropic-ai/sdk. Since the Files API is in beta, you pass the files-api-2025-04-14 beta identifier in requests.
Uploading is just a matter of reading the file and passing it in. You then reuse the returned ID in subsequent requests.
const uploaded = await client.beta.files.upload({
file: await toFile(
fs.createReadStream("sample/report.txt"),
"report.txt",
{ type: "text/plain" },
),
betas: ["files-api-2025-04-14"],
});
// Reference uploaded.id in subsequent requests
Here's the response right after uploading. Notice that downloadable is false, reflecting the spec I mentioned earlier — uploaded files cannot be downloaded.
{
"type": "file",
"id": "file_011CbYiUKCX8XHCpunzWYtb6",
"size_bytes": 849,
"created_at": "2026-05-30T11:59:50.169000Z",
"filename": "report.txt",
"mime_type": "text/plain",
"downloadable": false
}
To confirm the attachment is actually working, you can include the file_id in a Messages request and ask for a summary. Text files are referenced using a document block.
const message = await client.beta.messages.create({
model,
max_tokens: 512,
betas: ["files-api-2025-04-14"],
messages: [
{
role: "user",
content: [
{ type: "text", text: "添付ファイルの内容を3行以内の箇条書きで日本語要約してください。" },
{ type: "document", source: { type: "file", file_id: uploaded.id } },
],
},
],
});
A summary came back that reflected the contents of the fictional report I uploaded. Since it could read the file's contents, the attachment worked.
- Strong sales: Revenue up 18% YoY at 420M yen, driven by flagship SaaS "Nimbus" surpassing 1,250 companies...
- New contracts and challenges: 7 enterprise contracts secured, while North American infrastructure costs exceeded budget (12%)...
- Next steps: Focus on cost optimization, onboarding automation, and diversifying recruitment channels
After that, I confirmed the uploaded file via list and metadata retrieval, then tried downloading it as a sanity check — and as expected, it was rejected with a 400 error.
status = 400
error = {"type":"invalid_request_error",
"message":"File 'file_011CbYiUKCX8XHCpunzWYtb6' is not downloadable"}
Finally, I deleted it. The deletion response returns file_deleted, and after deletion, trying to fetch metadata using the same ID returns a 404.
# DELETE /v1/files/{file_id}
{ "id": "file_011CbYiUKCX8XHCpunzWYtb6", "type": "file_deleted" }
# Fetching again after deletion
status = 404
error = {"type":"not_found_error",
"message":"File `file_011CbYiUKCX8XHCpunzWYtb6` not found."}
As a side note, the upload itself went through regardless of file extension or mimeType in most cases. Sending a text file as application/pdf, or omitting the mimeType entirely (in which case it becomes application/octet-stream), both succeeded. Type mismatches appear to be checked at the point of referencing via a document or image block.
Closing Thoughts
Honestly, if an interaction is just a single exchange, attaching files inline each time is sufficient, so there aren't that many situations where the Files API really shines. The main use cases seem to be when you want to reuse the same file across multiple requests, or when combining it with the code execution tool to pass inputs and outputs back and forth. I haven't tried the latter yet, so I'd like to give it a go another time.
See you 👋
