Files API (OpenAI Compatible)¶
Upload and manage files via an OpenAI-compatible interface. Files are stored in Amazon S3 and can be referenced directly in Chat Completions requests. Large files can be uploaded in parts using the Uploads API.
-
Simple Upload
Upload any file with a singlemultipart/form-datarequest. Files are immediately available for use in inference. -
Multipart Upload
Stream large files in parts via the Uploads API. Parts are assembled by S3 native multipart upload. -
Optional Expiry
Setexpires_afterto automatically expire files after a configurable number of seconds (1 hour to 30 days). -
Paginated Listing
List files with ascending or descending order and cursor-based pagination using theafterparameter. -
Chat Integration
Reference uploaded files directly in Chat Completions messages using"type": "file"content parts.
Available Endpoints¶
| Endpoint | Method | Description | MCP Tool |
|---|---|---|---|
/v1/files |
POST |
Upload a file | openai_file |
/v1/files |
GET |
List files with pagination | openai_file_list |
/v1/files/{file_id} |
GET |
Retrieve file metadata | openai_files_get |
/v1/files/{file_id} |
DELETE |
Delete a file | openai_files_delete |
/v1/files/{file_id}/content |
GET |
Download raw file bytes | openai_file_content |
/v1/uploads |
POST |
Create a multipart upload session | openai_upload |
/v1/uploads/{upload_id}/parts |
POST |
Add a part to an upload session | openai_upload_part |
/v1/uploads/{upload_id}/complete |
POST |
Complete the upload and produce a file | openai_upload_complete |
/v1/uploads/{upload_id}/cancel |
POST |
Cancel a pending upload session | openai_upload_cancel |
Feature Compatibility¶
| Feature | Status | Notes |
|---|---|---|
| Upload | ||
file (multipart) |
Required binary form field | |
file (JSON body) |
Base64, data URI, HTTPS URL, or S3 URI — for MCP / AI agents | |
purpose |
Accepted as any string; informational only | |
expires_after[anchor] |
Only "created_at" is accepted |
|
expires_after[seconds] |
Range: 3 600 – 2 592 000 (1 hour – 30 days) | |
| Listing | ||
order=asc / order=desc |
Ascending and descending supported; default desc |
|
after cursor |
Forward cursor pagination | |
limit |
1 – 10 000; default 10 000 | |
purpose filter |
Filter results by uploaded purpose | |
| File size cap | No artificial limit; S3 object limit (~5 TB) | |
| Expiry enforcement | Expired files return 404 at read time; S3 Lifecycle as backstop | |
| Chat integration | Use file_id in type: "file" content parts |
|
status field |
Always "processed" — no async processing pipeline |
Legend:
- Supported — Fully compatible with OpenAI API
- Partial — Supported with limitations or differences
- Unsupported — Not available in this implementation
- Extra Feature — Enhanced capability beyond OpenAI API
Quick Start¶
Upload a File¶
curl -X POST "$BASE/v1/files" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-F "file=@document.pdf;type=application/pdf" \
-F "purpose=assistants"
Response:
{
"id": "file-0190c51c7de7455d9b8c2efe27dfbf67",
"object": "file",
"bytes": 102400,
"created_at": 1745000000,
"filename": "document.pdf",
"purpose": "assistants",
"status": "processed"
}
Upload via JSON Body (MCP and AI Agents)¶
When using MCP tools or HTTP clients that cannot construct multipart/form-data requests, pass the file as a base64 string, data URI, HTTPS URL, or S3 URI in a JSON body instead.
Data URI (inline content):
curl -X POST "$BASE/v1/files" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file": "data:text/plain;base64,SGVsbG8gV29ybGQ=",
"purpose": "user_data"
}'
HTTPS URL (server fetches the file):
curl -X POST "$BASE/v1/files" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file": "https://example.com/document.pdf",
"purpose": "assistants"
}'
Raw base64:
curl -X POST "$BASE/v1/files" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file": "SGVsbG8gV29ybGQ=",
"purpose": "user_data"
}'
All three variants return the same FileObject response as a multipart upload.
Upload with Expiry¶
curl -X POST "$BASE/v1/files" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-F "file=@temp.txt;type=text/plain" \
-F "purpose=assistants" \
-F "expires_after[anchor]=created_at" \
-F "expires_after[seconds]=3600"
Expiry Semantics
Expiry is enforced lazily at read time: calls to retrieve metadata, download content, or reference the file in inference return HTTP 404 once the expiry time has passed. S3 Lifecycle rules clean up expired objects as a background backstop.
Retrieve Metadata¶
curl "$BASE/v1/files/file-0190c51c7de7455d9b8c2efe27dfbf67" \
-H "Authorization: Bearer $OPENAI_API_KEY"
List Files¶
# Default (newest first, up to 10 000 files)
curl "$BASE/v1/files" \
-H "Authorization: Bearer $OPENAI_API_KEY"
# Ascending, limit 20
curl "$BASE/v1/files?order=asc&limit=20" \
-H "Authorization: Bearer $OPENAI_API_KEY"
# Next page using after cursor
curl "$BASE/v1/files?order=asc&limit=20&after=file-0190c51c7de7455d9b8c2efe27dfbf67" \
-H "Authorization: Bearer $OPENAI_API_KEY"
# Filter by purpose
curl "$BASE/v1/files?purpose=fine-tune" \
-H "Authorization: Bearer $OPENAI_API_KEY"
Download Content¶
curl "$BASE/v1/files/file-0190c51c7de7455d9b8c2efe27dfbf67/content" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-o downloaded.pdf
Delete a File¶
curl -X DELETE "$BASE/v1/files/file-0190c51c7de7455d9b8c2efe27dfbf67" \
-H "Authorization: Bearer $OPENAI_API_KEY"
Response:
{
"id": "file-0190c51c7de7455d9b8c2efe27dfbf67",
"object": "file",
"deleted": true
}
Uploads API¶
The Uploads API lets you stream large files to S3 in parts without buffering the entire file in memory. Each upload session is backed by an S3 native multipart upload.
Upload ID format¶
Upload IDs use the same base32-encoded payload as file IDs. The prefix is swapped (upload_ → file-) when the upload is completed, so the resulting file ID is known upfront.
Create an Upload Session¶
curl -X POST "$BASE/v1/uploads" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"bytes": 6291456,
"filename": "large_dataset.bin",
"mime_type": "application/octet-stream",
"purpose": "assistants"
}'
Response:
{
"id": "upload_0190c51c7de7455d9b8c2efe27dfbf67",
"object": "upload",
"status": "pending",
"bytes": 6291456,
"filename": "large_dataset.bin",
"purpose": "assistants",
"created_at": 1745000000,
"expires_at": 1745086400
}
Add Parts¶
Each part except the last must be at least 5 MiB (S3 minimum part size). The last part may be any size.
Binary upload (multipart/form-data):
curl -X POST "$BASE/v1/uploads/upload_0190c51c7de7455d9b8c2efe27dfbf67/parts" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-F "data=@part1.bin"
JSON body (MCP and AI agents):
When using MCP tools or HTTP clients that cannot construct multipart/form-data, pass the chunk as a base64 string, data URI, HTTPS URL, or S3 URI:
curl -X POST "$BASE/v1/uploads/upload_0190c51c7de7455d9b8c2efe27dfbf67/parts" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": "data:application/octet-stream;base64,AAEC..."
}'
Response:
{
"id": "part_0190c51c7de700010001abcdef012345",
"object": "upload.part",
"upload_id": "upload_0190c51c7de7455d9b8c2efe27dfbf67",
"created_at": 1745000001
}
Complete the Upload¶
curl -X POST "$BASE/v1/uploads/upload_0190c51c7de7455d9b8c2efe27dfbf67/complete" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"part_ids": [
"part_0190c51c7de700010001abcdef012345",
"part_0190c51c7de700020002fedcba987654"
]
}'
Response: A completed Upload object with the file field populated.
{
"id": "upload_0190c51c7de7455d9b8c2efe27dfbf67",
"object": "upload",
"status": "completed",
"bytes": 6291456,
"filename": "large_dataset.bin",
"purpose": "assistants",
"created_at": 1745000000,
"expires_at": 1745086400,
"file": {
"id": "file-0190c51c7de7455d9b8c2efe27dfbf67",
"object": "file",
"bytes": 6291456,
"created_at": 1745000005,
"filename": "large_dataset.bin",
"purpose": "assistants",
"status": "processed"
}
}
Cancel an Upload¶
curl -X POST "$BASE/v1/uploads/upload_0190c51c7de7455d9b8c2efe27dfbf67/cancel" \
-H "Authorization: Bearer $OPENAI_API_KEY"
Upload sessions expire after 1 day
If an upload is not completed within 1 day of creation it is automatically aborted. Parts uploaded to an expired session are discarded by S3.
Uploads Feature Compatibility¶
| Feature | Status | Notes |
|---|---|---|
bytes (declared size) |
Validated at completion against actual assembled size | |
filename |
Carried through to the final file object | |
mime_type |
Set as the S3 ContentType for the assembled object |
|
purpose |
Echoed to the final file object | |
| Part data (binary) | Standard multipart/form-data binary upload via the data field |
|
| Part data (JSON body) | Base64, data URI, HTTPS URL, or S3 URI — for MCP / AI agents | |
| Part ordering | Caller controls order via part_ids list at completion |
|
md5 checksum |
Accepted but not validated | |
| Session TTL | 1 day from creation |
End-to-End Example (Uploads)¶
# 1. Create an upload session
UPLOAD_ID=$(curl -s -X POST "$BASE/v1/uploads" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"bytes": 6291456,
"filename": "large_file.bin",
"mime_type": "application/octet-stream",
"purpose": "assistants"
}' | jq -r .id)
# 2. Upload parts (first part >= 5 MiB, last part any size)
PART_A_ID=$(curl -s -X POST "$BASE/v1/uploads/$UPLOAD_ID/parts" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-F "data=@part1.bin" | jq -r .id)
PART_B_ID=$(curl -s -X POST "$BASE/v1/uploads/$UPLOAD_ID/parts" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-F "data=@part2.bin" | jq -r .id)
# 3. Complete — file is immediately available
FILE_ID=$(curl -s -X POST "$BASE/v1/uploads/$UPLOAD_ID/complete" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"part_ids\": [\"$PART_A_ID\", \"$PART_B_ID\"]}" | jq -r .file.id)
echo "File ready: $FILE_ID"
# Cleanup
curl -X DELETE "$BASE/v1/files/$FILE_ID" \
-H "Authorization: Bearer $OPENAI_API_KEY"
Chat Completions Integration¶
Reference an uploaded file inside a POST /v1/chat/completions message using "type": "file":
curl -X POST "$BASE/v1/chat/completions" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic.claude-haiku-4-5-20251001-v1:0",
"max_tokens": 512,
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "Summarise this document."
},
{
"type": "file",
"file": {
"file_id": "file-0190c51c7de7455d9b8c2efe27dfbf67"
}
}
]
}
]
}'
Model Support
Document and image file types are supported by models that accept those input modalities. Use a vision-capable model (e.g. Claude Haiku or Sonnet) when passing PDFs or images via file_id. Amazon Nova models do not currently support document inputs.
End-to-End Example¶
# 1. Upload the file
FILE_ID=$(curl -s -X POST "$BASE/v1/files" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-F "file=@document.pdf;type=application/pdf" \
-F "purpose=assistants" | jq -r .id)
# 2. Reference in a chat completion
curl -X POST "$BASE/v1/chat/completions" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"model\": \"anthropic.claude-haiku-4-5-20251001-v1:0\",
\"max_tokens\": 512,
\"messages\": [{
\"role\": \"user\",
\"content\": [
{\"type\": \"text\", \"text\": \"What is the key finding in this document?\"},
{\"type\": \"file\", \"file\": {\"file_id\": \"$FILE_ID\"}}
]
}]
}"
# 3. Cleanup
curl -X DELETE "$BASE/v1/files/$FILE_ID" \
-H "Authorization: Bearer $OPENAI_API_KEY"
Error Reference¶
| HTTP | Cause |
|---|---|
| 400 | Invalid expires_after range, bad filename, size mismatch, or unknown part ID |
| 404 | File or upload not found, already deleted, expired, or not pending |
| 503 | AWS_S3_BUCKET is not configured |
Configuration¶
Files are stored in S3 under the prefix configured by AWS_S3_FILES_PREFIX (default: files/). Configure S3 Lifecycle rules on this prefix to automatically delete expired objects and apply Intelligent-Tiering.
Store files once, use them across requests. See Anthropic Files API for the Anthropic-compatible equivalent.