Upload a file
POST /v1/files
Uploads one file to the Drive of the user who owns the key.
Send multipart/form-data with one file field, whose part includes a filename, and optionally an
expires_in_seconds field. The server accepts any file type. In a body over 10 MiB, expires_in_seconds must
come before file. The Python and .NET SDKs send it first. With the TypeScript SDK, write expires_in_seconds
before file in the object you pass to files.upload.
These limits apply:
- A file can be up to your deployment’s upload limit, which is 5 GiB unless your administrator set it lower.
- Send a
Content-Lengthheader. cURL and the SDKs send one for you. A request without one must use chunked encoding and be 10 MiB or smaller. - Each key can have up to 4 uploads in progress on one server instance, and each instance takes up to 8 in
total across all keys. Keep 4 or fewer uploads in progress, and retry on
429.
If the request fails partway, the server keeps nothing.
The key must have the files:write capability. For what each capability allows, see Keys.
Body (multipart/form-data)
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
file | binary | Yes | The file, with a filename. If the part has no media type, the server stores the file as application/octet-stream. | |
expires_in_seconds | integer | No | The number of seconds until the file expires on Anthropic’s API. Must be a whole number between 3600 and 7776000. It isn’t applied: the file is kept until you delete it, and the file object has no expires_at. |
Response
Returns 200 with the file object. For every field, see Files.
{ "id": "329409ba-f288-4b44-9c73-14a18150edee", "created_at": "2026-10-21T01:41:11.028Z", "filename": "cities.csv", "mime_type": "text/csv", "size_bytes": 46, "type": "file", "downloadable": true}Errors
This endpoint can return these errors as well as the common errors.
| Status | error.type | Cause and fix |
|---|---|---|
| 400 | invalid_request_error | The form has a field other than file and expires_in_seconds. Remove the other fields. |
| 400 | invalid_request_error | expires_in_seconds isn’t a whole number between 3600 and 7776000. Send a value in that range, or omit it. |
| 400 | invalid_request_error | expires_in_seconds comes after file in a body over 10 MiB. Send expires_in_seconds before file, or omit it. |
| 400 | invalid_request_error | The form has no file field, or more than one, or the filename is empty. Send exactly one file field with a non-empty filename. |
| 400 | invalid_request_error | The body doesn’t match its Content-Length: bytes follow the closing boundary, or the body ends early. The server keeps nothing. Send an exact Content-Length. |
| 413 | request_too_large | The file is over your deployment’s upload limit (5 GiB unless your administrator set it lower), or a chunked request is over 10 MiB. The message gives the limit. If the file is over the upload limit, send a smaller file. If the request is chunked and over 10 MiB, send it again with a Content-Length header. |
| 429 | rate_limit_error | This key already has 4 uploads in progress on the server instance that answered, or 8 are in progress there for all keys. Wait for the time in Retry-After, then retry. |
Example
curl -sS -X POST "$CONTEXT_BASE_URL/v1/files" -H "x-api-key: $CONTEXT_API_KEY" -F "file=@cities.csv;type=text/csv"from pathlib import Path
uploaded = client.beta.files.upload(file=Path("cities.csv"))print(uploaded.id)import { readFile } from "node:fs/promises"import { toFile } from "@anthropic-ai/sdk"
const uploaded = await client.beta.files.upload({ file: await toFile(await readFile("cities.csv"), "cities.csv", { type: "text/csv" }) })