Responses API
/v1/responses implements OpenAI’s Responses format. It takes a single input
instead of a messages array, and unlike
/v1/chat/completions it
holds state: a response gets an id you can fetch later, chain the next turn onto,
or cancel while it runs.
Reach for it when you want the server to keep the thread, when you want to start
long work and collect it later, or when you need store, metadata or
background, which are specific to this endpoint. See OpenAI
Compatibility for the
full comparison.
Creating a response
cURL
Python
The OpenAI SDK’s responses client works against this endpoint unchanged, so
create, retrieve, stream, cancel and delete are all available on it.
Every Python example further down this page reuses the client built here.
output_text is an SDK convenience that concatenates the text for you; the
underlying object is below.
The reply is a response object:
The three fields you will reach for:
id- what you pass to retrieve, cancel, delete, orprevious_response_id.status-completed,failed,incompleteorcancelledonce the run has ended;queuedorin_progresswhile it is still going. This is what you poll on for a background response.output- an array of items, not a single string. The assistant’s text is in themessageitem, atcontent[0].text. Reasoning and tool calls arrive as their own items in the same array, reasoning first as above, so walk it bytyperather than assuming position.
usage uses the Responses spelling: input_tokens and output_tokens rather
than the prompt_tokens and completion_tokens you get from
/v1/chat/completions.
There are three ways to take delivery, and they are the main decision on this endpoint.
Synchronous is the default and is right for short work. Streaming is right for anything a person is waiting on. Background is right for work you want to start and collect later, possibly from a different process.
background requires store to be left at its default of true. A background
response is delivered by id, so it has to be retrievable. Sending
"background": true with "store": false returns a 400.
Storing and retrieving
Responses are stored by default, which is what makes the rest of this page possible. Fetch one by id:
cURL
Python
A stored response stays retrievable for three days after it finishes. After that
GET, cancel, delete and chaining onto it all return a 404, which means
gone rather than still running.
Send "store": false on create when you do not want the response kept. It is
then delivered on the request itself and is not retrievable afterwards, so all
four of those stop applying to it immediately.
GET /v1/responses/{id}/input_items returns the input items for that single
turn. It does not return the whole reconstructed conversation.
Streaming
Send "stream": true on create and the POST returns server-sent events. Each
frame carries a named event: and a JSON data: payload, which is the main
difference from /v1/chat/completions, where every frame is an anonymous chunk
containing choices[0].delta.
response.created carries the response id, which is how you capture it when
streaming a create: you need it to cancel the run or to chain the next turn onto
it.
A full run emits, in order: response.created, response.in_progress,
response.output_item.added, response.content_part.added, one
response.output_text.delta per fragment, response.output_text.done,
response.content_part.done, response.output_item.done, and a terminal event.
Reasoning arrives first, on response.reasoning_text.delta events closed by a
response.reasoning_text.done, as its own output item ahead of the text.
Three event types are terminal, and receiving any of them means the stream is finished:
response.completed carries the finished response object, including usage.
That is where to read token counts when streaming; the earlier events do not
carry them.
There is no [DONE] sentinel on this endpoint: a terminal event is the end of
the stream. Treat the event set as open and ignore any type you do not recognize,
so new event types do not break your client.
Cancelling a run also produces response.incomplete, so read the response
status to tell a cancellation from a token limit.
The OpenAI SDK handles the framing and gives you the assembled response at the
end, so you branch on event.type rather than parsing frames yourself:
A background response can also be streamed from the retrieve endpoint, which is how you attach to work that was started elsewhere:
cURL
Python
Streaming from retrieve applies to background responses. Adding ?stream=true
to a response that was not created with "background": true returns a 400.
Retrieve it without the parameter to get the stored snapshot.
Continuing a conversation
Pass a previous response’s id as previous_response_id and the server
reconstructs the thread for you, including any tool calls and reasoning it
contains. You send only the new turn.
cURL
Python
This is the main practical difference from
/v1/chat/completions,
where you resend the whole messages array every turn.
Chain onto a parent that has finished and is still stored. Chaining onto a run
that is still going returns a 409, and onto one created with "store": false,
or older than the three-day window, a 404.
Cancelling and deleting
cURL
Python
Cancelling a response that has already finished returns the final response rather than an error, so a cancel racing a completion is safe to send. Deleting cancels the run first if it is still going, then removes the stored response.
What this endpoint takes
input takes either a string or an array of input items, so you can send a
whole thread in one request rather than a single prompt:
Image input
Send an image as an input_image part alongside your text. Every model takes
image input, under the same rules as
/v1/chat/completions:
inline as a data: URI, up to 20 MB per image once decoded, and up to ten
images per request.
detail is optional and defaults to auto; low, high and original are
also accepted. An input_image identified by file_id is not supported; send
the image in image_url.
Images belong on an input role. An input_image on an assistant message is
rejected, because an assistant turn has no stored image to read back. Send the
image in the turn that asks about it: when a request replays earlier turns that
also carried images, the per-request limit is spent on the most recent images
first, so the one you are asking about is never the one left out.
An image that cannot be read is rejected rather than quietly left out, so a
200 means every image you sent was used. The request returns 400 with
code: "unsupported_content_part" and param naming the part, in this
endpoint’s own vocabulary (input[0].content[1]), for an input_image carrying
no URL, base64 that does not decode, an image over 20 MB once decoded, more
images than the model accepts, a host ASI:One does not fetch from, and any
content part that is not input_text, output_text or input_image. See
Errors.
Reasoning uses OpenAI’s standard reasoning object here. enable_thinking and
thinking_budget also work on this endpoint, so you can migrate at your own
pace. See
Reasoning.
Tool calling works on both endpoints, and this one additionally accepts the flat Responses tool shape alongside the nested one. See Tool Calling.
Structured output uses text.format here rather than response_format, taking
the same JSON schema. See Structured
Data.
max_output_tokens bounds the tokens generated for the response, the way
max_tokens does on /v1/chat/completions.
metadata takes up to 16 key-value string pairs, which are stored with the
response and returned again when you retrieve it. Use it to tag a response with
your own trace or tenant id so you can match it up later.
Planner mode runs on
/v1/chat/completions.
Next steps
- Chat Completions API - The stateless endpoint, and where planner mode runs
- OpenAI Compatibility - Which parameters are supported on each endpoint
- Tool Calling - Let the model call your own functions
- Errors and Rate Limits - What each status code means and what to retry