Theme
Language
·4 min read

Responses API vs Chat Completions: what differs and which to use

The practical differences between /v1/responses and /v1/chat/completions on an OpenAI-compatible API: request shape, conversation history, tools, streaming events, and which one to pick. Every example ran live on GetVibe API.

Responses API vs Chat Completions: what differs and which to use

OpenAI-compatible APIs now have two main request formats: the long-standing /v1/chat/completions and the newer /v1/responses. GetVibe API accepts both with one key and one base URL, https://getvibeapi.com/v1. Here is how they differ in practice, which one to choose, and the one trap when you move between them.

The short version

Chat CompletionsResponses
EndpointPOST /v1/chat/completionsPOST /v1/responses
Inputa messages arrayinput: a string or an array of items
System prompta message with the system rolethe instructions field
Answerchoices[0].messagean output array: reasoning, message, function calls
Output limitmax_tokensmax_output_tokens
Who uses itmost SDKs, frameworks and chat appsCodex CLI and newer agent SDKs

The format does not change the model, the price or the token count: you are billed for the model's input and output tokens either way.

The same request in both formats

Chat Completions:

curl https://getvibeapi.com/v1/chat/completions \
  -H "Authorization: Bearer $GETVIBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-luna",
    "messages": [
      {"role": "system", "content": "Answer in one sentence."},
      {"role": "user", "content": "What does HTTP 429 mean?"}
    ],
    "max_tokens": 300
  }'

Responses:

curl https://getvibeapi.com/v1/responses \
  -H "Authorization: Bearer $GETVIBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-luna",
    "instructions": "Answer in one sentence.",
    "input": "What does HTTP 429 mean?",
    "max_output_tokens": 300
  }'

In Chat Completions the text is in choices[0].message.content. In Responses it sits inside output: for reasoning models the first item is a reasoning item and the answer is the item of type message. You do not have to walk the array by hand; the Python SDK has an output_text property.

import os
from openai import OpenAI

client = OpenAI(base_url="https://getvibeapi.com/v1", api_key=os.environ["GETVIBE_API_KEY"])

chat = client.chat.completions.create(
    model="gpt-6-luna",
    messages=[{"role": "system", "content": "Answer in one sentence."},
              {"role": "user", "content": "What does HTTP 429 mean?"}],
)
print(chat.choices[0].message.content)

resp = client.responses.create(
    model="gpt-6-luna",
    instructions="Answer in one sentence.",
    input="What does HTTP 429 mean?",
)
print(resp.output_text)

Responses is not limited to OpenAI models. Before publishing we sent the same Responses request to gpt-6-luna, claude-sonnet-5.5 and deepseek-v4.1-flash, and all three answered. DeepSeek returned a reasoning item before its message, exactly as described above.

Conversation history: send it yourself

This is the one thing to know before you switch. OpenAI's own Responses API can keep a conversation on the server, so the next request points at the previous one with previous_response_id. GetVibe API does not store your conversations, so previous_response_id is not supported and store is ignored. When we tried it, the request was rejected with a 400 error.

The working pattern is the same as with Chat Completions: send the whole history in input.

history = [{"role": "user", "content": "My name is Ana. Remember it."}]
first = client.responses.create(model="gpt-6-luna", input=history)

history.append({"role": "assistant", "content": first.output_text})
history.append({"role": "user", "content": "What is my name? One word."})
second = client.responses.create(model="gpt-6-luna", input=history)
print(second.output_text)  # Ana

Tools: a different shape

Function calling works in both formats, but the tool definition looks different. In Chat Completions the function fields are nested inside a function object; in Responses they sit directly on the tool. The call arrives as a separate function_call item, and you return the result as a function_call_output item with the same call_id.

import json

tools = [{
    "type": "function",
    "name": "get_weather",
    "description": "Current weather in a city",
    "parameters": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
        "additionalProperties": False,
    },
}]

items = [{"role": "user", "content": "What's the weather in Denver?"}]
resp = client.responses.create(model="gpt-6-luna", input=items, tools=tools)

for item in resp.output:
    if item.type == "function_call":
        result = {"city": "Denver", "temp_f": 54, "sky": "overcast"}  # your function
        items.append({"type": "function_call", "call_id": item.call_id,
                      "name": item.name, "arguments": item.arguments})
        items.append({"type": "function_call_output", "call_id": item.call_id,
                      "output": json.dumps(result)})

final = client.responses.create(model="gpt-6-luna", input=items, tools=tools)
print(final.output_text)

In our run the model called get_weather with {"city":"Denver"}, and the second request answered that Denver is 54°F and overcast. The Chat Completions version of the same loop is in our function calling guide.

Streaming

Both formats support "stream": true, but the events differ. Chat Completions sends uniform data: lines, with each new piece of text in choices[0].delta.content. Responses sends named events: response.created first, response.output_text.delta with the text pieces, and response.completed at the end. If you parse the stream yourself instead of through an SDK, you need a parser for the specific format.

Which one to choose

  • Chat Completions if you already have code on it, or you use a framework, a chat app or a no-code platform. Almost every tool speaks it, and there is no reason to rewrite working code just to change formats.
  • Responses if a tool requires it. The main example is Codex CLI, which talks to /v1/responses; setup is in the Codex CLI docs and in our Codex CLI guide.

Either way, the model list and prices are the same. See the API reference for every field, and the models page for live prices.

Responses API vs Chat CompletionsOpenAI Responses API/v1/responseschat completions APIprevious_response_idCodex CLI Responses API

Try GetVibe API for free

GPT, Claude, Gemini and more through one OpenAI-compatible API. Pay in USD by card or crypto.

Related articles

Responses API vs Chat Completions: what differs and which to use | GetVibe API