OpenFill is in development. Inference is off, but is tested end to end, and will switch on at launch. All data currently on the site is for live testing: it will be erased at launch.

Skip to content
openfill

Files and batches

The OpenAI shapes for a file and a batch, with the fields OpenFill adds. A file exists to be a batch input or a batch output; there is no other purpose.

Set shell variables such as ORDER_ID, FILE_ID and BATCH_ID to ids returned by the API before running the corresponding command.

Upload a file

POST /v1/files
curl https://api.openfill.ai/v1/files -H "Authorization: Bearer $OPENFILL_API_KEY" \  -F purpose=batch -F [email protected]

Multipart, one file, purpose of batch. The content is checked when a batch starts rather than at upload. A file over 50 MB is refused with 413.

json
{"id": "file-...", "object": "file", "bytes": 1234, "created_at": 1756700000, "expires_at": 1756786400, "filename": "requests.jsonl", "purpose": "batch", "status": "processed"}

expires_at is the retrieval deadline, derived from the account setting and batch.min_retention_days on GET /v1/rate-limits. The file can be deleted early or evicted under the storage cap. Both timestamps are epoch seconds.

Get a file and its content

GET /v1/files/{id}
curl "https://api.openfill.ai/v1/files/$FILE_ID" -H "Authorization: Bearer $OPENFILL_API_KEY"
GET /v1/files/{id}/content
curl "https://api.openfill.ai/v1/files/$FILE_ID/content" -H "Authorization: Bearer $OPENFILL_API_KEY" -o output.jsonl

The content is served as application/jsonl with a filename in Content-Disposition. A file past its expiry answers 410 result_unavailable while its metadata remains; after deletion of the file record it answers 404. A temporary read failure answers 503with Retry-After. Each download counts against the hourly allowance on rate limits.

List and delete files

GET /v1/files
curl "https://api.openfill.ai/v1/files?purpose=batch" -H "Authorization: Bearer $OPENFILL_API_KEY"

Newest first, optionally filtered by purpose (batch, batch_output or batch_errors). Pass last_id as after to continue; an unknown after id restarts the list. The response carries object, data, first_id, last_id and has_more. A full page has has_more true, so the final continuation can be empty. The limit bounds are in GET /openapi.json.

DELETE /v1/files/{id}
curl -X DELETE "https://api.openfill.ai/v1/files/$FILE_ID" -H "Authorization: Bearer $OPENFILL_API_KEY"

Set FILE_ID to an id returned by the API. Delete returns id, object: file and deleted: true. A repeated delete answers 404. A file used by an active batch answers 409 file_in_use; cancel the batch and wait for it to finish, or wait for normal completion.

Create a batch

POST /v1/batches
curl https://api.openfill.ai/v1/batches -H "Authorization: Bearer $OPENFILL_API_KEY" -H "Content-Type: application/json" \  -d '{"input_file_id": "'"$FILE_ID"'", "endpoint": "/v1/chat/completions", "completion_window": "24h", "price_limit": 0.02}'
FieldTypeDefaultMeaning
input_file_idstringrequiredA file uploaded with purpose batch.
endpointstringrequired/v1/chat/completions, /v1/completions, /v1/responses or /v1/messages. Every line's url must match it, and a line's body and output take that endpoint's shape.
completion_windowstring24hOnly 24h is accepted, as OpenAI's shape has it.
price_limitnumberkey or accountThe price limit every line on a market model inherits. A line's own body.price_limit wins. When omitted, each line resolves its model's key or account default. A line on a fixed-price model ignores it.
max_waitintegera dayThe deadline in seconds, clamped to the configured order timeout range. Lines still queued at expires_at expire unexecuted.
metadataobjectnoneUp to 16 pairs; keys up to 64 characters, values up to 512.

Create answers 200 with status validating. Each line resolves its own price; a missing price rejects a line on a market model as invalid_request, and a line on a fixed-price model needs none. The batch records every model's pricing when it is created, and a line whose model's pricing changed since is not run; it lands in the error file under prices_changed. The batch price_limit accepts 0 to 1000000000, and max_wait accepts positive integers up to 2592000. Too many active batches answers 429 withRetry-After. Up to 10,000 lines per file.

An input file past its retention deadline answers 410 result_unavailable before the batch is created.

The batch object

FieldMeaning
idbatch_ and 24 characters.
endpoint/v1/chat/completions, /v1/completions, /v1/responses or /v1/messages.
statusvalidating, in_progress, cancelling, completed, expired, cancelled or failed.
input_file_id, output_file_id, error_file_idThe files. Output and error are null until the batch finishes, and stay null when that file would have been empty.
errorsnull, or {object: list, data: [{code: batch_error, message}]} when validation failed.
completion_windowAlways 24h.
created_at, expires_at, completed_atEpoch seconds. expires_at is the real deadline.
request_counts{total, completed, failed}. failed folds in expired and cancelled lines.
metadataUp to 16 string pairs, as sent.
x_market{active, pending_result, expired, canceled, bid}. bid is the batch price_limit, or null.
x_retention{output_days, output_expires_at, output_deleted} for the output file.

List, retrieve and cancel

GET /v1/batches
curl "https://api.openfill.ai/v1/batches?limit=20" -H "Authorization: Bearer $OPENFILL_API_KEY"
json
{"object": "list", "data": [ ...batches... ], "first_id": "batch_...", "last_id": "batch_...", "has_more": true}

Newest first. Pass last_id as ?after= for the next page. has_more is true whenever a page is full, so the page after the last one is empty with has_more false. The limit defaults to the example above; its maximum is described by GET /openapi.json. An unknown after id restarts the list.

GET /v1/batches/{id}
curl "https://api.openfill.ai/v1/batches/$BATCH_ID" -H "Authorization: Bearer $OPENFILL_API_KEY"
POST /v1/batches/{id}/cancel
curl -X POST "https://api.openfill.ai/v1/batches/$BATCH_ID/cancel" -H "Authorization: Bearer $OPENFILL_API_KEY"

Cancel answers the batch with status cancelling; queued lines are cancelled and executing ones finish. Only validating and in_progress can be cancelled. A batch in any other state answers 409 batch_not_cancelable.

Line formats

input line
{"custom_id": "job-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "market-preview", "messages": [{"role": "user", "content": "hi"}], "price_limit": 0.03}}
output line
{"id": "batch_req_...", "custom_id": "job-1", "response": {"status_code": 200, "request_id": "<order_id>", "body": { ...the completion... }}, "error": null}
error line
{"id": "batch_req_...", "custom_id": "job-2", "response": null, "error": {"code": "expired", "message": "..."}}

The error codes, the statuses, and what a line cannot carry are on the batch page.