Responses
POST /v1/responses creates a model response in the OpenAI Responses format. It is stateless: nothing is stored between requests, and a request that points at stored state is refused with stateless_only.
Request#
| Field | Type | Notes |
|---|---|---|
model | string | Required. A model id from GET /v1/models |
input | string or array | A string is one user message; an array is input items |
instructions | string | System-level instructions, sent as the first system message |
stream | boolean | Default false. With true, Responses events |
max_output_tokens | integer | Output cap. When omitted the model's maximum applies. The cap is lowered to what the balance covers when needed, and x-token-notice says so |
tools | array | Function and custom tools. Hosted tools (web_search, file_search, code_interpreter, computer_use, mcp, local_shell) are left out and named in x-token-notice. image_generation is refused with 400 image_generation_unsupported |
tool_choice | string or object | auto, none, required or a named tool |
reasoning | object | effort sets the reasoning effort; summary is ignored |
text.format | object | json_object or a json_schema, on models that support it |
prompt_cache_key | string | A stable key for the prompt cache |
user | string | End-user id for attribution. safety_identifier is an alias |
metadata | object | Flat tags kept with the request |
conversation | string or object | Names the session for caching. Nothing is stored for it |
temperature, top_p | number | Sampling controls |
store | any | Accepted and ignored |
include | array | reasoning.encrypted_content is honoured on models that return it; other values are accepted and ignored |
Two tools that resolve to one name are refused with a 400, as are input items of a type the format does not define.
Stateless#
| Request | Answer |
|---|---|
previous_response_id | 400 stateless_only: send the whole conversation in input |
background: true | 400 stateless_only: stream the response or wait for it |
a stored prompt | 400 stateless_only: send instructions and input |
an item_reference input item | 400 stateless_only |
store: true | Accepted, nothing is stored |
Input items#
A message item has a role of user, assistant, system or developer with content parts. input_image takes a URL or a data URI; a file id or an input_file part is refused. Assistant-side items in a row, an assistant message, a reasoning item and function_call items, form one assistant turn: reasoning becomes reasoning_content and calls become tool_calls. A function_call_output item becomes a tool message.
To keep reasoning across turns without stored state, ask for include: ["reasoning.encrypted_content"] and replay the reasoning item as it came. A model that cannot return the ciphertext replays the reasoning text as reasoning_content instead.
Items of hosted tools, a web_search_call for instance, degrade to an assistant note rather than failing the request:
A configuration_update item may carry reasoning.effort, which becomes the request's effort when the request sends no reasoning parameter.
Streaming#
With stream: true the answer arrives as Responses events: response.created, response.output_item.added, response.output_text.delta, response.reasoning_summary_text.delta where the model reports reasoning, then response.completed or response.incomplete, carrying the final response object with usage.
The terminal event is response.incomplete, not a completed with a status, when the model hit its token ceiling (incomplete_details.reason: max_output_tokens) or a content filter (content_filter). An error after the headers are out is a response.failed event whose response object carries the same id, the model and the failure, with status, retry_after_ms and x_should_retry.
Response#
The structure follows the Responses format, with ai_generated and ai_notice added. On a stream the marker sits on the response of response.created. usage.input_tokens includes cached and written tokens, itemised in input_tokens_details; reasoning_tokens sits inside output_tokens.
Count input tokens#
POST /v1/responses/input_tokens returns {"object": "response.input_tokens", "input_tokens": N} for an input without running it. Nothing is billed.