Mindket

OpenAI API tutorial: the Responses API in Python and JavaScript

A black banner titled "OpenAI API" over the line "Responses, tools, structured output and agents".

The Responses API is the OpenAI API endpoint the docs recommend for new projects. You send a model id and an input, optionally with instructions, and get back a list of output items plus an output_text shortcut. This tutorial creates a key, installs the official Python and JavaScript SDKs, makes a first call, streams it and carries a conversation across turns.

In this lesson

  • Keep the secret in an environment variable and away from any page a visitor can open.
  • Switch on each item type in the output list once tools or reasoning join the request.
  • Send your behavior rules again on every chained turn.
  • Pick one place to hold history for each conversation and stay with it.
  • Port older chat code in small slices, plain text first.
All courses
On this page
  1. Before you start
  2. Make the first call and read what comes back
  3. Steer with instructions, then stream the reply
  4. Keep a conversation going across turns
  5. How Responses relates to Chat Completions
  6. What Atty Eleti and OpenAI Developers posted about the Responses API
  7. Common mistakes
  8. Try it yourself
  9. Next
  10. Check yourself
  11. Frequently asked questions
  12. Sources

Before you start

You need an OpenAI platform account and an API key, which you create on the API keys page of the dashboard. Every official SDK reads the key from the OPENAI_API_KEY environment variable, so it never has to sit in your code. On macOS or Linux, run export OPENAI_API_KEY="your_api_key_here". In PowerShell, run setx OPENAI_API_KEY "your_api_key_here".

A key you create for yourself acts with your own access. For a deployed app, a scheduled job or CI, the API keys guide points to a project service account instead. That is a non-human identity that owns its own keys, so the workload does not depend on one developer staying on the team. The API shows a service-account key in full only once, when it is created, so it goes straight into a secret manager.

Scopes on a key can narrow what it may do, but they never grant access its owner lacks. Rotation follows a fixed order: issue a replacement, update the workload, confirm it works, then revoke the old key. The service account keeps its identity while its keys change. Separate projects can isolate resources, members and usage for different apps or environments. A workload that runs on an identity provider OpenAI supports can use workload identity federation and store no long-lived key at all.

The Python SDK needs Python 3.10 or later. The JavaScript SDK supports Node.js 22 and 24 LTS, plus Deno, Bun and Cloudflare Workers. Node.js 20 reached end of life on 30 April 2026 and is no longer supported. Browsers are blocked by default. The dangerouslyAllowBrowser option turns them on, and then anyone who opens the page can read your key.

Make the first call and read what comes back

The quickstart's first request is three moves: create a client, call responses.create with a model and an input, print output_text. Below is the Python version from the developer quickstart. In JavaScript the call is await client.responses.create({ model, input }), saved as example.mjs, with console.log(response.output_text) at the end.

What comes back is a response object with its own id, not a string. Its output property is a list of items. In the text guide's example for this exact prompt, the list holds one item. Its id starts with msg_, its type is message and its role is assistant. Inside sits a content list with one output_text part: the unicorn story, next to an empty annotations list where citations land when a tool supplies them.

The migration guide prints the same request run on gpt-5.5, and there the list starts with a reasoning item whose id begins with rs_. The message comes second. output_text is an SDK helper that joins every text part into one string, so it hides that difference. It suits a quick script. Code that adds tools or keeps history should walk the list instead, because the text guide warns that the reply is not reliably at output[0].content[0].text.

from openai import OpenAI

client = OpenAI()

response = client.responses.create(
    model="gpt-6-astra",
    input="Write a one-sentence bedtime story about a unicorn.",
)

print(response.output_text)
  1. Export the key in the shell that will run the code.
  2. Install the SDK: pip install openai for Python, or npm install openai for JavaScript.
  3. Save the code as example.py, or the JavaScript version as example.mjs.
  4. Run python example.py or node example.mjs. One short story prints when the call returns.
  5. Print response.output instead of output_text and read the item types behind that string.
Item types from the migration guide and the tool guides, read on 5 November 2026.
Item typeWhen it shows upWhat your code does
messageThe model wrote text for the userRead its text parts, or use output_text
reasoningA reasoning model worked before it answeredKeep it and send it back if you replay history yourself
function_callThe model wants one of your functions runRun it and reply with a function_call_output that carries the same call_id
web_search_call or file_search_callA built-in tool ran on OpenAI's sideNothing to run, read the citations in the message

Steer with instructions, then stream the reply

instructions is a top-level parameter for how the model should behave: tone, goals, examples of a good answer. It takes priority over the prompt in input. Sending it is roughly the same as putting a message with the developer role at the top of the input list. Developer messages carry your application's rules and rank ahead of user messages, which carry what the person typed. The model's own turns have the assistant role.

The text guide compares the two roles to code. A developer message is the function definition, holding the rules and business logic. A user message is the arguments that definition runs on.

It applies to one request only. A turn chained with previous_response_id does not see the instructions you sent earlier, so code that chains has to send them again on every call. The prompt itself belongs in your code, where it gets typed inputs, review and tests. OpenAI is retiring the reusable prompt objects some older tutorials store on the platform, as the timeline shows.

By default the API writes the whole answer before it sends one HTTP response, and on a long answer that wait is what a user sees. Streaming fixes the wait with one more flag. Set stream to true and the SDK gives you typed server-sent events, a one-way HTTP stream the server keeps writing to. The sample joins the text guide's instructions example with the streaming guide's event loop.

The docs' example also sets reasoning: { effort: "low" }. Reasoning effort tells a reasoning model how much to think before it answers, and lower effort favors speed and fewer tokens. Supported values depend on the model, and the reasoning guide gives medium as the default for GPT-6.1 Sol and GPT-6 Luna. In Python, pass stream=True and iterate with for event in stream, checking the same event.type names.

import OpenAI from "openai";
const client = new OpenAI();

const stream = await client.responses.create({
  model: "gpt-6-astra",
  reasoning: { effort: "low" },
  instructions: "Talk like a pirate.",
  input: "Are semicolons optional in JavaScript?",
  stream: true,
});

for await (const event of stream) {
  if (event.type === "response.output_text.delta") {
    process.stdout.write(event.delta);
  } else if (event.type === "response.completed") {
    console.log("\nResponse completed.");
  } else if (event.type === "error") {
    console.error(event.message);
  }
}
  • response.created arrives once, when the response starts.
  • response.output_text.delta arrives many times, each with the next piece of text in delta.
  • response.completed arrives once, when generation ends.
  • error can arrive in the middle of a stream, so the loop needs its own branch for it.
Older API surfaces and their dates
  1. Prompt creation de-emphasized

    Reusable prompt objects begin their deprecation, and the text guide asks you to keep prompts in code.

    Source: OpenAI Docs: Text generation (read November 5, 2026)

  2. Assistants API sunset

    It is no longer available, and the migration guide moves its users to the Responses API.

    Source: OpenAI Docs: Migrate to the Responses API (read November 5, 2026)

  3. The prompts endpoint shuts down

    The date the text guide gives for v1/prompts to stop working.

    Source: OpenAI Docs: Text generation (read November 5, 2026)

Once you start reading a stream, the Python SDK does not retry it, because a replay could repeat text your app already showed. Streaming also makes moderation harder, because a partial answer is harder to judge than a finished one. Moderation scores, if you ask for them, arrive only after the full output.

Keep a conversation going across turns

Ask "tell me a joke", then "explain why this is funny" in a second request, and the second request knows nothing about the first. Each call stands alone. You have three ways to give the model that context.

Manual replay is the plainest. Keep a list of items in your app, append the model's output after each reply, add the next user message and send the whole list as input. Nothing is stored for you, and nothing is hidden from you.

The lightest is previous_response_id: pass the id of the last response with only the new user input, and OpenAI supplies the earlier turns. It works because responses are stored by default, and stored response objects are kept for 30 days. The code is the conversation state guide's own example.

The chain saves you from resending text. It does not save you from paying for it: every earlier input token in the chain is billed as input again on the next turn. If you came from the Claude API course, the shift is real, because Anthropic's Messages API is stateless and your code always resends the history.

For a thread that must outlive one session or move between devices, create a conversation with client.conversations.create() and pass its id as conversation on each request. A conversation stores messages, tool calls and tool outputs as items under its own durable id.

All three hit the same ceiling. The context window is the most tokens one request can use, and it counts input, output and reasoning tokens together. A long thread grows toward it turn by turn, and output past the limit may be cut off. For that case the guide points to compaction, set on /responses with context_management and a compact_threshold. Its tokenizer tool counts how many tokens a string holds before you send it.

from openai import OpenAI

client = OpenAI()

response = client.responses.create(
    model="gpt-6-astra",
    input="tell me a joke",
)
print(response.output_text)

second_response = client.responses.create(
    model="gpt-6-astra",
    previous_response_id=response.id,
    input=[{"role": "user", "content": "explain why this is funny."}],
)
print(second_response.output_text)
From the conversation state guide, read on 5 November 2026.
WayWhere the history livesWhat you send each turnHow long it is kept
Manual replayYour applicationEvery earlier item plus the new messageAs long as you keep it, and store can be false
previous_response_idOpenAI, response by responseThe last response id and the new inputResponse objects, 30 days by default
Conversations APIA conversation object with its own idThe conversation id and the new inputIts items have no 30-day limit

Replaying by hand with store set to false? Keep every item from output, the encrypted reasoning items included. In Python that is history += response.output before the next user message.

How Responses relates to Chat Completions

Chat Completions is the older endpoint, /v1/chat/completions, and it is still supported. The migration guide recommends Responses for all new projects, and some models settle the question: GPT-6 Astra and GPT-6.1 Sol only call tools through Responses. Starting with GPT-5.4, Chat Completions also refuses tool calls when the reasoning effort is anything other than none.

The guide frames a port as three changes. Requests go to /v1/responses, output is read from the typed output list, and you choose how the app carries state between turns. Text-only message lists port without edits, since the same array works as messages in one API and as input in the other.

Everything else changes shape, and the table is the map. Where Chat Completions glues text, tool calls and metadata into one message object, Responses splits them into separate items. The migration guide has side-by-side samples for every row.

Storage differs as well. Responses are stored by default, while Chat Completions are stored by default only for new accounts, and store: false turns storage off in either API. Two gaps catch people porting old code. Responses has no n, so ask more than once when you want several candidates. And the Assistants API is gone, so code that still calls it needs a rewrite on Responses.

From the migration guide, read on 5 November 2026.
Chat CompletionsResponses API
A messages arrayinput, a string or a list of items
A system or developer messageTop-level instructions
choices[0].message.contentoutput_text, or the message item in output
Tool calls inside the assistant messageA separate function_call item, matched by call_id
response_format for a JSON schematext.format
Stream chunks with a delta fieldTyped events such as response.output_text.delta
Several generations with nNot available, so make separate requests
Functions non-strict by defaultStrict mode tried first when strict is left out

What Atty Eleti and OpenAI Developers posted about the Responses API

Atty Eleti of OpenAI, one of the people who designed the endpoint, introduced the Responses API on X on 11 March 2025, the day it launched. He called it the new primitive of the OpenAI API, built on two years of lessons, and the foundation for building agents. His post opens a thread on how the team designed it. The typed item list from your first call is that primitive at work, so learn its types before you add tools.

OpenAI Developers posted on 26 August 2025 that the Assistants API beta would end one year later, with a guide for moving to Responses. The same post said Responses had already overtaken Chat Completions in token activity. That shutdown is the one in the timeline. Code that still calls Assistants needs a rewrite now, while Chat Completions code can move one flow at a time.

It’s our recommended path to integrate with the OpenAI API today, and for the future.

OpenAI Developers, OpenAI's official account for developers · X (read November 5, 2026)
Atty Eleti (@athyuttamre) on X, 11 March 2025: Introducing the Responses API: the new primitive of the OpenAI API. It is the culmination of 2 years of learnings designing the OpenAI API, and the foundation of our next chapter of building agents. Here is the story of how we designed it.
Atty Eleti on X, 11 March 2025
OpenAI Developers (@OpenAIDevs) on X, 26 August 2025: We are winding down the Assistants API beta. It will sunset one year from now, August 26, 2026. We have put together a guide to help you migrate to the Responses API. The post adds that the Responses API has already overtaken Chat Completions in token activity.
OpenAI Developers on X, 26 August 2025
OpenAI's Build Hour on the Responses API, from OpenAI's own YouTube channel.

Screenshots of X's own embeds of the posts, taken on 5 November 2026, with the time in UTC. Select one to open the post on X. X cuts the OpenAI Developers post short with Show more.

Common mistakes

  • Reading choices[0].message.content from a Responses object out of habit.
  • Taking output[0] as the answer when a reasoning item sits in front of the message.
  • Dropping reasoning or tool items while replaying history by hand.
  • Sending a chained turn without its instructions and wondering why the tone drifted.
  • Passing previous_response_id and also replaying the full transcript, so the model reads the same turns twice.
  • Expecting previous_response_id to make earlier turns free, when they are billed as input on every call.
  • Feeding typed Responses events to an old stream handler that waits for delta chunks.
  • Shipping the key to a public page with dangerouslyAllowBrowser.

Try it yourself

  • Print the type of every item in response.output for a plain question. Which types come back from gpt-6-astra?
  • Move your instructions into a developer message at the top of input and compare the two replies.
  • Chain three turns with previous_response_id and leave out instructions on the third. Does the tone hold?
  • Make one call with store=False, then try to chain a second turn from its id. What happens?
  • Ask the same question with reasoning effort set to low and then high, and time how long the first streamed word takes.
  • Port one Chat Completions call from your own code with the table, then compare the outputs side by side.

Next

Lesson 2 gives the model tools: your own functions described in JSON Schema, plus the web search and file search that OpenAI runs for you. It starts from the function_call item in the first table and the call_id that pairs it with your result.

Every limit and bill in this lesson is counted in tokens. What are tokens in AI shows how text turns into them before it reaches a model, which helps when a chained thread starts to cost more than you planned.

Check yourself

  1. You chain a second turn with previous_response_id. What happens to the instructions you sent on the first turn?

    Show answer

    B. They are not in the context, so you send them again instructions applies to the current request only, so a chained turn needs them sent again.

  2. Which way of reading the reply holds up once reasoning or tools are involved?

    Show answer

    A. Loop over response.output and check each item type The output list can start with a reasoning item or a tool call, so code should switch on each item type.

  3. Which streaming event carries the next piece of text?

    Show answer

    D. response.output_text.delta Each response.output_text.delta event holds the next piece of text in its delta field.

  4. You move a Chat Completions request that uses a JSON schema to Responses. Where does the schema go?

    Show answer

    C. text.format Structured Outputs moved from response_format to text.format in the Responses API.

Frequently asked questions

Is the OpenAI API free to use?

Only for a first test. The quickstart calls your first request a free test, then sends you to the billing page to add credits for real use. After that, usage is metered in tokens and billed to your organization. Prices change often, so this lesson leaves them out.

Which OpenAI model should I start with?

On 5 November 2026 the models page suggests GPT-6 Astra for complex reasoning and coding, GPT-6.1 Sol to balance intelligence and cost, and GPT-6 Luna for high-volume work. Each lists a context window of 1,050,000 tokens and up to 128,000 output tokens. For production, the text guide asks you to pin a dated snapshot, such as gpt-5.5-2026-04-23, so behavior stays the same between releases.

What do the SDKs retry on their own?

Connection errors and the 408, 409, 429 and 500-level statuses, each retried twice by default with a short exponential backoff. Requests time out after 10 minutes. Change that with max_retries in Python or maxRetries in JavaScript, and log _request_id from failed calls, as the Python SDK README suggests.

Do I have to rewrite my Chat Completions code now?

Not in one go. The guide suggests moving one user flow at a time, starting with plain text generation, and comparing latency, token usage and errors before routing more traffic over. Any flow that needs function calling on the newest models moves first.

Sources

  1. OpenAI Docs: Developer quickstart (read November 5, 2026)https://developers.openai.com/api/docs/quickstart
  2. OpenAI Docs: Text generation (read November 5, 2026)https://developers.openai.com/api/docs/guides/text
  3. OpenAI Docs: Streaming API responses (read November 5, 2026)https://developers.openai.com/api/docs/guides/streaming-responses
  4. OpenAI Docs: Conversation state (read November 5, 2026)https://developers.openai.com/api/docs/guides/conversation-state
  5. OpenAI Docs: Migrate to the Responses API (read November 5, 2026)https://developers.openai.com/api/docs/guides/migrate-to-responses
  6. OpenAI Docs: Reasoning models (read November 5, 2026)https://developers.openai.com/api/docs/guides/reasoning
  7. OpenAI Docs: SDKs and CLI (read November 5, 2026)https://developers.openai.com/api/docs/libraries
  8. OpenAI Docs: API keys and service accounts (read November 5, 2026)https://developers.openai.com/api/docs/guides/api-keys
  9. OpenAI Docs: Models (read November 5, 2026)https://developers.openai.com/api/docs/models
  10. OpenAI Docs: GPT-6 Astra (read November 5, 2026)https://developers.openai.com/api/docs/models/gpt-6-astra
  11. openai/openai-python on GitHub (read November 5, 2026)https://github.com/openai/openai-python
  12. openai/openai-node on GitHub (read November 5, 2026)https://github.com/openai/openai-node
  13. X: Atty Eleti introduces the Responses API (read November 5, 2026)https://x.com/athyuttamre/status/1899541471532867821
  14. X: OpenAI Developers on winding down the Assistants API beta (read November 5, 2026)https://x.com/OpenAIDevs/status/1960409187122602172
  15. YouTube (OpenAI): Build Hour: Responses API (read November 5, 2026)https://www.youtube.com/watch?v=hNr5EebepYs

Share this lesson

See agents built on these APIs

Browse AI agents other developers list on Mindket, read their setup notes, then list one of your own.

Browse AI agents

This lesson as Markdown · OpenAI API course: Responses, tools, structured output and agents · All courses