Chat Completions and Responses
Open the lesson playground and you'll find two buttons, one for each of OpenAI's two API shapes: Chat Completions and Responses. You'll meet both names again in other people's code and in the provider's own documentation, usually with no explanation of why there are two.
They do the same job. Both send instructions and a user message to a model and get a reply back. What differs is where you put each piece of the request, and where the reply text turns up afterwards, and that second difference is the one that bites when you're copying a snippet from somewhere.
Those playground buttons call routes on the Express server, the small Node program the course project runs alongside the page, so that model requests happen away from browser code and your API key is never exposed. In Scrimba, output from those server routes appears in the Runner tab instead of the Console tab.
Both examples below use the same client, built once from the values you saved in Provider setup:
import OpenAI from "openai"
const client = new OpenAI({
apiKey: process.env.AI_KEY,
baseURL: process.env.AI_URL,
})Chat Completions
Chat Completions places the system prompt and user input together in messages:
const response = await client.chat.completions.create({
model: process.env.AI_MODEL,
messages: [
{ role: "system", content: "You are a helpful assistant." },
{
role: "user",
content: "Give me a short explanation of why open-source tools matter.",
},
],
});The reply text is nested under the first choice:
response.choices[0].message.contentmessages list: the system prompt first, then your question. The reply comes back buried at response.choices[0].message.content. That path looks fussy the first few times you type it. It is worth reading slowly once, because you will see it in almost every code sample online!
Responses
Responses gives the system prompt its own instructions field. For a simple request, input can be a direct string:
const response = await client.responses.create({
model: process.env.AI_MODEL,
instructions: "You are a helpful assistant.",
input: "Give me a short explanation of why open-source tools matter.",
});The same direct string can be moved into a role/content message object when you need the message form:
input: [
{
role: "user",
content: "Give me a short explanation of why open-source tools matter.",
},
],Responses exposes the reply text directly:
response.output_textIt also keeps the complete response structure in response.output. A basic text response usually contains a message item whose content includes the same output text.
instructions field instead of sharing the list, and input can be a plain string when you're only asking one thing. Best part: the reply is at response.output_text. One step instead of three.
Why the course uses Responses
Chat Completions is still a valid API, and the agent functionality in this course could be built with it.
The course uses Responses because of the difference you can already see in the two code blocks above. Reading a reply is response.output_text instead of response.choices[0].message.content, and the system prompt has a named home instead of being the first item in an array you also append user turns to. Once tool calls and conversation history start accumulating, that shape means less code holding the pieces together.
Use the full output when you need the structure
output_text is the convenient way to read a final text reply. Use output when you need to inspect the complete set of response items.
You don't need to memorise the differences. Use Responses here, and recognise Chat Completions when you meet it elsewhere.
Where this goes next
Running the code locally explains how the browser and Express server connect after you download a lesson from Scrimba. If you haven't picked a model yet, Recommended models covers what agent work requires.

