February 9, 2026

Open AI Conversations API

Crete Conversations and Create Create Responses

The Conversations API is a part of the OpenAI platform that helps you keep and manage long running chat state on the server. You can think of a conversation object as a stored chat thread. It remembers messages, files, tool calls, and other items across many requests so that you do not need to resend the full history every time you call the model. The goal is to give you a durable place where the complete context of a user session lives, while your app only sends the new turn and some options each time.

The Responses API is the main entry point when you want the model to actually think and generate output. A Responses request says which model you want, what inputs to give it, which tools it may call, and how you want the result to look. For example, you can ask for plain text, JSON, or tool calls. Under the hood, this API replaces the older Chat Completions style and adds stronger support for tools and multi step reasoning. For most new projects, you call Responses whenever you want the model to answer a question, write some content, run tools, or perform a reasoning task.

The relationship between these two pieces is simple. The Responses API does the thinking for a single request. The Conversations API keeps track of everything that has been said or done across many Responses calls. When you pass a conversation id into a Responses request, the server loads the stored items for that conversation, prepends them to your new inputs, lets the model generate a result, and then automatically appends the new input and output items back into the same conversation. This gives you a clean mental model. Responses is the brain that answers the current question. Conversations is the memory that stores the full story of the chat.

To see how this works in practice, imagine a simple web chat app that uses both APIs together. When a new user opens the app, your backend first creates a conversation. Each time the user sends a message, your server calls the Responses API with that message and the id of the conversation. The platform automatically includes all previous messages from this conversation so the model has context, and when the model replies, the new user message and the new assistant reply are both stored as items in the same conversation. You can later retrieve the conversation to show full history in your UI, or delete it when the session ends. This pattern gives you clean server side state without having to rebuild your own database schema for every token of the chat.

The following JavaScript example shows this pattern in code. It creates a conversation, sends the first user message through the Responses API, and then prints the latest assistant reply that is stored in the conversation. In a real app you would wrap this in your request handler and reuse the same conversation id for each turn from the same user.

import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); async function runExample() { // 1. Create a new conversation to hold state const conversation = await client.conversations.create({ title: "Demo chat with a user" }); // 2. Ask the model a question inside this conversation const response = await client.responses.create({ model: "gpt-5.1-chat-latest", conversation: conversation.id, input: [ { role: "user", content: [ { type: "input_text", text: "Explain what the Conversations API does in simple terms." } ] } ] }); // 3. The output text is the model reply for this turn console.log("Assistant reply for this turn:"); console.log(response.output[0].content[0].text); // 4. Later you can retrieve the same conversation const fullConversation = await client.conversations.retrieve(conversation.id); console.log("Stored items in this conversation:"); for (const item of fullConversation.items) { console.log(item.type, item.role, JSON.stringify(item)); } } runExample().catch(console.error);

You use the Responses API whenever you want the model to answer something, and you attach a conversation id when you want that answer to live inside a persistent chat history. The Conversations API then gives you endpoints to create, read, update, and delete that history as a first class object in the platform, which keeps your application logic much cleaner as your project grows.

When you pass a conversation id into responses.create, you are telling the platform:
“Use this conversation as the long term memory for this user, and store the new turn there as well.”
So that one id becomes the handle for the full chat history on the server.

What you can do later with the same conversation id

First, you can keep using it for more responses.create calls. Every time you send a new request with the same conversation id, the API will load all existing items in that conversation as context, then append the new user input and the new model output back into the same conversation. Conversations store items such as messages, tool calls and tool outputs, so the thread grows over time.

Second, you can fetch the stored state via the Conversations API. In particular:

  • GET /conversations/{conversation_id} returns the conversation object and metadata such as creation time and any custom metadata.

  • GET /conversations/{conversation_id}/items returns a list of all items in that conversation. Items include user messages, assistant messages, tool call items and tool call output items, and they use the same schema as the output of a Response.

This is what you would use to rebuild the full chat history in your own UI.

About “multiple responses” and getting them back

If you call responses.create many times and always pass the same conversation id:

  • Each call creates a new Response object with its own response.id

  • At the same time, the outputs of that Response are written into the conversation as items

Later, if you want to see “all the responses” for that conversation, you usually do not query Responses by conversation id. Instead, you call GET /conversations/{conversation_id}/items and iterate through the items. The items give you everything the model has produced in that conversation, regardless of which Response object created them.

If you specifically need the Response objects themselves you have two options:

  • Store each response.id in your own database when you create it, then call responses.retrieve(responseId) later

  • Or keep using only conversation items, which is the simpler pattern for a chat style app

There is also a previous_response_id field on the Responses API, but you do not use it together with conversation. You either use conversation for a durable server side thread, or you chain responses one by one with previous_response_id.

Small TypeScript example that reads all messages in a conversation

import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY! }); async function printConversation(conversationId: string) { // Fetch the conversation metadata const convo = await client.conversations.retrieve(conversationId); console.log("Conversation title metadata:", convo.metadata); // List all items in this conversation const items = await client.conversations.items.list(conversationId, { limit: 100, }); for (const item of items.data) { if (item.type === "message" && item.role === "assistant") { const textBlock = item.content.find( part => part.type === "output_text" || part.type === "text" ); console.log("Assistant:", textBlock?.text); } if (item.type === "message" && item.role === "user") { const textBlock = item.content.find( part => part.type === "input_text" || part.type === "text" ); console.log("User:", textBlock?.text); } } }

So in short: yes, if you always send the same conversation id, you can later use that id to fetch all the history for that chat. You do it by listing the conversation items, which represent all the responses and other events that happened in that conversation.

What GET /conversations/{conversation_id} returns

Let us walk through your exact scenario step by step, with concrete objects.

Assumptions

You have one conversation id, for example conv_123.

You call responses.create three times, always with conversation: "conv_123":

  1. User asks for flights to NYC (meaning New York City), the model calls a search_flights tool, and then answers.

  2. User asks for flights to LA (meaning Los Angeles), again a search_flights tool call and an answer.

  3. User asks for flights to LAX (meaning Los Angeles International Airport), tool call and answer.

Each time, input items and output items of the response are automatically stored in the conversation.

This endpoint (conversations) returns the conversation metadata only. It does not return the messages or tool calls. The shape is very small.

Example after all three responses.create calls:

GET /v1/conversations/conv_123 { "id": "conv_123", "object": "conversation", "created_at": 1739100000, "metadata": { "user_id": "user_42", "title": "Flight search demo" } }

From the API reference, the conversation object always has:

  • id, created_at, metadata, object: "conversation"

Notice that you do not see anything about NYC or LA here. This object is just the “header” for the conversation.

What GET /conversations/{conversation_id}/items returns

This endpoint returns all the items stored in that conversation.

Items can be:

  • messages (type: "message", with role: "user" or role: "assistant")

  • tool calls (type: "function_call" for function tools)

  • tool call outputs (type: "function_call_output")

  • other things like reasoning items, web search calls, computer calls, and so on

The result is a list object, for example:

GET /v1/conversations/conv_123/items { "object": "list", "data": [ { "id": "item_1", "type": "message", "role": "user", "created_at": 1739100001, "content": [ { "type": "input_text", "text": "Find me flights from SFO to NYC on March 10." } ] }, { "id": "item_2", "type": "function_call", "created_at": 1739100002, "name": "search_flights", "arguments": "{\"from\": \"SFO\", \"to\": \"JFK\", \"date\": \"2026-03-10\"}" }, { "id": "item_3", "type": "function_call_output", "created_at": 1739100003, "call_id": "call_1", "output": "{\"best_price\": 320, \"airline\": \"ACME Air\", \"flight_number\": \"AC123\"}" }, { "id": "item_4", "type": "message", "role": "assistant", "created_at": 1739100004, "content": [ { "type": "output_text", "text": "I found a nonstop flight from SFO to JFK for 320 dollars on March 10 with ACME Air, flight AC123." } ] }, { "id": "item_5", "type": "message", "role": "user", "created_at": 1739100101, "content": [ { "type": "input_text", "text": "Now find flights from SFO to LA on March 12." } ] }, { "id": "item_6", "type": "function_call", "created_at": 1739100102, "name": "search_flights", "arguments": "{\"from\": \"SFO\", \"to\": \"LAX\", \"date\": \"2026-03-12\"}" }, { "id": "item_7", "type": "function_call_output", "created_at": 1739100103, "call_id": "call_2", "output": "{\"best_price\": 180, \"airline\": \"ACME Air\", \"flight_number\": \"AC456\"}" }, { "id": "item_8", "type": "message", "role": "assistant", "created_at": 1739100104, "content": [ { "type": "output_text", "text": "For March 12 I found a flight from SFO to Los Angeles at 180 dollars on ACME Air, flight AC456." } ] }, { "id": "item_9", "type": "message", "role": "user", "created_at": 1739100201, "content": [ { "type": "input_text", "text": "Finally, search flights from SFO to LAX for March 15 and show me only early morning options." } ] }, { "id": "item_10", "type": "function_call", "created_at": 1739100202, "name": "search_flights", "arguments": "{\"from\": \"SFO\", \"to\": \"LAX\", \"date\": \"2026-03-15\", \"time_window\": \"morning\"}" }, { "id": "item_11", "type": "function_call_output", "created_at": 1739100203, "call_id": "call_3", "output": "{\"best_price\": 150, \"departure_time\": \"07:30\", \"airline\": \"ACME Air\", \"flight_number\": \"AC789\"}" }, { "id": "item_12", "type": "message", "role": "assistant", "created_at": 1739100204, "content": [ { "type": "output_text", "text": "On March 15 the best morning option from SFO to LAX is ACME Air flight AC789 at 07:30 for 150 dollars." } ] } ], "first_id": "item_1", "last_id": "item_12", "has_more": false }

How this connects back to your three responses.create calls:

  • First responses.create for NYC
    Adds items 1 to 4 into the conversation.

  • Second responses.create for LA
    Adds items 5 to 8.

  • Third responses.create for LAX
    Adds items 9 to 12.

When you call responses.create the next time with conversation: "conv_123", the API will take all these items, prepend them to your new input items, and let the model see the full context. The new user message, any new tool calls, tool outputs and assistant messages will then be appended as more items at the end.

GET conversations GET conversation items 

  1. After you pass a conversation id into responses.create, later GET /conversations/{conversation_id} gives you only the conversation metadata. It is a small object with id, created_at, metadata, and object.

  2. If you have called responses.create three times with the same conversation id and each call had a tool call and an answer, then GET /conversations/{conversation_id}/items will give you all the user messages, tool calls, tool call outputs and assistant answers from those three calls, as a list of items in time order.

You do not “list all Responses” through the conversation id. You list all items instead, and those items are everything that happened in that conversation, including the content that came from your three Responses.

No comments:

Post a Comment