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

Responses API

The OpenAI Responses shape, translated at the edge onto the same order pipeline as chat. A request here is priced, queued, charged, logged and replayed exactly as a chat request; only the wire differs. It keeps no state between calls, so each turn resends its input.

Create a response

POST /v1/responses
curl https://api.openfill.ai/v1/responses \  -H "Authorization: Bearer $OPENFILL_API_KEY" \  -H "Content-Type: application/json" \  -d '{"model": "placeholder-large", "input": "hi", "max_price": 0.10}'

Request body

The Responses fields first, then the OpenFill extensions, which carry the same names and rules as on chat. A field absent from this table is forwarded to the model untouched.

FieldTypeDefaultMeaning
modelstringthe default modelA served model id or alias.
inputstring or arrayrequiredA string is one user message. An array holds message items with role user, assistant, system or developer and text parts, function_call items, function_call_output items and reasoning items, in conversation order.
instructionsstringnoneBecomes the system message at the front.
toolsarraynoneFunction tools in the Responses shape, name and parameters at the top level. A web_search entry is dropped without error, since Codex sends one by default; every other hosted tool is refused.
tool_choicestring or objectautonone, auto, required, or a named function. allowed_tools becomes auto or required from its mode; the restriction to the listed tools is passed to the model as a preference and is otherwise unenforced.
max_output_tokensintegerthe model's max outputThe output cap, clamped down to the model's max output length.
temperature, top_pnumbernone0 to 2, and 0 to 1.
text.formatobjectnonejson_object and json_schema become response_format for the model; text is the default.
reasoning.effortstringnoneForwarded to the model as reasoning_effort. Summary settings are dropped.
parallel_tool_callsbooleannoneForwarded.
metadataobjectnoneUp to 16 string pairs, echoed on the response and kept with the request log.
storebooleannoneAccepted and echoed. Storage here follows the account's data storage setting; retention_days below is the per-request switch.
streambooleanfalseServer-sent events, in the Responses event vocabulary.
max_pricenumberkey or accountThe most you will pay, in USD per 1M input tokens at the reference mix. None anywhere is 400 missing_bid. The X-Max-Price header carries it for a tool with no body field.
price_lockbooleanaccount settingBid the lower of the published quote and max_price, and start within the execute window or expire with 429 capacity_unavailable.
max_waitintegeraccount settingSeconds an unlocked order may wait. Alias expires_after; the X-Expires-After header carries it too.
retention_daysintegeraccount settingKeep this request's data for fewer days. 0 keeps nothing durable.

Refused with 400

SentWhy
previous_response_id, conversationThis endpoint keeps no state. Resend the full input each turn.
background: trueUse detached on POST /v1/chat/completions and poll the order.
promptServer-side prompt templates do not exist here; send the text in input.
truncation: autoThe input reaches the model unchanged, so it cannot be honoured.
detached: trueThe stored result is chat-shaped, so the detached path is POST /v1/chat/completions.
input_image, input_file, input_audio partsText only. Nothing is charged.
item_reference and every hosted-tool itemThey need server-side state or a tool the market does not run.
tools other than functionOnly function tools run here; web_search is dropped rather than refused.

Response

The Responses object, with every key the OpenAI reference shows present and null where it has no value. The id carries the order id, so the request can be found under GET /v1/orders/{id}.

json
{  "id": "resp_<order_id>", "object": "response", "created_at": 1756800000, "completed_at": 1756800042,  "status": "completed", "error": null, "incomplete_details": null, "model": "placeholder-large",  "output": [    {"id": "rs_<order_id>", "type": "reasoning", "status": "completed", "summary": [],     "content": [{"type": "reasoning_text", "text": "..."}]},    {"id": "msg_<order_id>", "type": "message", "status": "completed", "role": "assistant",     "content": [{"type": "output_text", "text": "...", "annotations": []}]},    {"id": "fc_<order_id>_0", "type": "function_call", "status": "completed",     "call_id": "...", "name": "get_weather", "arguments": "{\"city\": \"Boston\"}"}  ],  "usage": {"input_tokens": 1234, "input_tokens_details": {"cached_tokens": 1000},            "output_tokens": 56, "output_tokens_details": {"reasoning_tokens": 0}, "total_tokens": 1290,            "x_market": {"level_at_execution": 0.23, "bid": 0.5, "charged_usd": 0.0023}},  "store": false, "metadata": {}, ...}
FieldMeaning
statuscompleted on a normal finish; incomplete with incomplete_details.reason max_output_tokens when the cap stopped it.
outputA reasoning item when the model sent reasoning, then the message, then one function_call item per call, in that order. An item absent from the answer is absent from the list.
output[].content[].typereasoning_text carries the raw chain of thought; Codex shows it only with show_raw_agent_reasoning on.
usage.input_tokensEvery prompt token, cached ones included; input_tokens_details.cached_tokens says how many were cached.
usage.x_marketThe receipt: the price the order was charged at, what it bid, and the debit.
metadata, storeEcho the request, as do instructions, tools, tool_choice, text and reasoning.

Streaming

200 and a text/event-stream body. Every frame carries an event: line, the same name in the JSON type, and a sequence_number that starts at 0 and rises by one on every event. There is no [DONE] sentinel: the body ends after the terminal event.

a text answer, in order
event: response.createdevent: response.in_progress          <- also every 10 s of silence while the order waitsevent: response.output_item.addedevent: response.content_part.addedevent: response.output_text.delta    <- one per fragmentevent: response.output_text.doneevent: response.content_part.doneevent: response.output_item.doneevent: response.completed            <- carries the response object with usage and x_market
CaseEvents
A function calloutput_item.added with the call's name and call_id, function_call_arguments.delta per fragment, function_call_arguments.done, output_item.done.
Reasoning before the answerA reasoning item with reasoning_text.delta events, closed before the message item opens.
The output cap stopped itresponse.incomplete in place of response.completed, with incomplete_details.reason max_output_tokens.
An error after the stream openedOne response.failed event with response.error.code and message, then the body ends. The status stays 200 and nothing is charged.

The queue comment lines the chat stream writes are kept, and every keepalive also sends a response.in_progress event, because Codex resets its idle timer only on a parsed event. Its default of five minutes therefore needs no change for a long wait.

Statuses

The same statuses, envelope and charging rules as chat. An Idempotency-Key works here and a replay comes back in this shape; a streaming replay is the whole event sequence at once.