Files

Persist a document once, then reference it across chat completions by id - no need to re-upload bytes on every request.

The Files API lets you upload documents once and reference them by id in chat completions. It is the persistent counterpart to inline file_data / file_url parts.

POST   /v1/files
GET    /v1/files
GET    /v1/files/:file_id
GET    /v1/files/:file_id/content
DELETE /v1/files/:file_id

Files are scoped to the API key's project. Two requests cannot see each other's files, even when they hit the same gateway.

Why use it

Inline file parts (file_data, file_url) are great for one-off requests. The Files API wins whenever a document is:

  • Reused across turns - a 10 MB PDF in a 20-turn conversation costs ~200 MB of upload traffic if you inline it every time. Uploaded once, it costs ~30 bytes per reference.
  • Large - inline base64 inflates payload by ~33%. The Files API ingests raw bytes once.
  • Reused across sessions - your front-end can drop the bytes after upload and persist just the file_id.
  • Subject to retention rules - explicit DELETE gives you a clean audit boundary; expires_after automates cleanup for batch jobs.

Two ways to attach a file

Both modes use the same {type: 'file'} content part inside chat completions - they only differ in where the bytes live.

ModeWhere bytes liveSend each requestBest for
InlineNowhere - bytes flow through the gateway onlyfile_data (base64) or file_urlOne-off requests, public URLs
Managed (Files API)Project file storage, scoped per userfile_id (~30 bytes)Multi-turn, reuse, large files

Managed files are cached to reduce latency on repeated access, and save on upload bandwidth for repeat requests.

Lifecycle

  1. Upload with POST /v1/files. You get back a FileObject with id (file-...), bytes, created_at, purpose, and optional expires_at.

  2. Reference the id from chat completions:

    {
      "type": "file",
      "file": { "file_id": "file-abc123..." }
    }
  3. Inspect at any time with GET /v1/files or GET /v1/files/:id.

  4. Delete with DELETE /v1/files/:id when done.

Storage limits

ConstraintValue
Max single upload100 MB
Per-request inline file budget50 MB across all parts
expires_after[seconds] range3600 (1 hour) - 2592000 (30 days)
Default retention without expires_afterindefinite, until deleted

File object

The shape returned by upload / retrieve / list endpoints, and accepted by the OpenAI SDK as FileObject.

FieldTypeDescription
idstringUnique file identifier, prefixed with file-. Use this anywhere a file_id is accepted.
object'file'Always file.
bytesintegerSize of the uploaded file in bytes.
created_atintegerUnix timestamp (seconds) when the file was uploaded.
filenamestringOriginal filename as sent in the upload form.
purposestringOne of assistants, batch, fine-tune, vision, user_data, evals. Set at upload time.
statusstringProcessing state: uploaded, processed, or error.
expires_atintegerOptional Unix timestamp when the file will be auto-deleted. Only present when expires_after was set at upload.

Endpoints

MethodEndpointDescription
POST/v1/filesUpload file
GET/v1/filesList files
GET/v1/files/:idRetrieve file
GET/v1/files/:id/contentRetrieve content
DELETE/v1/files/:idDelete file

Every endpoint expects a bearer token in the Authorization header. Create keys at Manage API Keys.

Supported file formats

When a file is referenced in chat completions, the gateway extracts its text content automatically. The following formats are supported:

CategoryFormats
DocumentsPDF, DOCX, DOC, ODT, Pages, RTF
PresentationsPPTX, PPT, Keynote
SpreadsheetsXLSX, XLS
Text-basedAny plain text, source code, config, markup, or data file (e.g. .txt, .md, .json, .csv, .html, .py, .ts, .yaml, .sql, .sh, and hundreds more)

Text-based files are detected by MIME type or extension. If it starts with text/ or is a known structured format (JSON, XML, YAML, TOML, GraphQL, Protobuf, etc.), it will be read as-is without conversion.

Extraction results are cached per unique file content, so repeated references to the same file have significantly lower latency.

Errors

All errors follow the standard error shape:

{ "error": { "type": "invalid_request_error", "message": "..." } }
Statuserror.typeMeaning
400invalid_request_errorMissing or invalid form fields.
401invalid_request_errorMissing or invalid API key.
403invalid_request_errorAPI key has no associated user.
404invalid_request_errorNo such File object: file-...
413invalid_request_errorUpload exceeds the 100 MB max.
500internal_server_errorUnexpected failure.

For full compatibility with the official OpenAI client, the gateway tags every Files-domain error as invalid_request_error regardless of HTTP status. SDKs branch on the status code (NotFoundError for 404, etc.).