Skip to content

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 single multipart/form-data request. 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
    Set expires_after to 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 the after parameter.

  • 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.