Developer Dashboard

Responses vs. Chat Completions

Compare the Responses API and Chat Completions API.

This guide explains the key differences between the Responses API and Chat Completions API, helping you choose the right approach for your application.

Adapted from OpenAI's official Migrate to the Responses API, function calling, and Structured Outputs documentation, with AvalAI endpoint, API key, and route-availability notes.

Why the Responses API?

The Responses API is the newest core API and an agentic API primitive, combining the simplicity of Chat Completions with the ability to perform more agentic tasks. As model capabilities evolve, the Responses API provides a flexible foundation for building action-oriented applications, including route- and model-dependent built-in tools:

OpenAI also positions Responses as the better foundation for reasoning workflows, typed tool loops, stateful context with previous_response_id, flexible input plus top-level instructions, and future model capabilities. In AvalAI, treat those benefits as route- and model-dependent: start new OpenAI-style text, reasoning, and tool flows with Responses when your selected model supports /v1/responses, and keep Chat Completions for stable integrations or providers that only expose chat compatibility.

Capabilities Comparison

CapabilityChat Completions APIResponses API
Text generation
AudioRoute/model dependent; use /v1/audio or Realtime routes when available
Vision
Structured Outputs
Function calling
Web searchRoute/model dependent
File searchRoute/model dependent
Computer useRoute/model dependent
Code interpreterPlanned / route dependent
Remote MCP / connectorsRoute/model/account dependent
Image generation as a toolRoute/model dependent; otherwise use /v1/images
Reasoning summariesRoute/model dependent

AvalAI keeps the OpenAI-style request shape, but hosted tools are not universal across every provider. Before shipping a migration, verify the selected model and route in the relevant provider page or API reference. For provider-independent web retrieval, prefer AvalAI /v1/search unless your chosen Responses route explicitly supports web_search.

The Chat Completions API Is Not Going Away

The Chat Completions API is an industry standard for building AI applications, and it remains supported for existing integrations. The Responses API is recommended for new OpenAI-style projects because it simplifies workflows involving tool use, code execution, state management, and future model capabilities.

A Stateful API and Semantic Events

Events are simpler with the Responses API. It has a predictable, event-driven architecture, whereas the Chat Completions API continuously appends to the content field as tokens are generated—requiring you to manually track differences between each state. Multi-step conversational logic and reasoning are easier to implement with the Responses API.

The Responses API clearly emits semantic events detailing precisely what changed (e.g., specific text additions), so you can write integrations targeted at specific emitted events (e.g., text changes), simplifying integration and improving type safety.

Model Availability in Each API

Whenever possible, all new models will be added to both the Chat Completions API and Responses API. Some models may only be available through the Responses API if they use built-in tools (e.g., computer use models), or trigger multiple model generation turns behind the scenes (e.g., o1-pro). The detail pages for each model will indicate if they support Chat Completions, Responses, or both.

Migration Path

Migrate one integration at a time:

  1. Change the endpoint from POST /v1/chat/completions to POST /v1/responses.
  2. Move simple messages into input; move stable system or developer guidance into top-level instructions.
  3. Read final text from response.output_text instead of choices[0].message.content.
  4. For reasoning, tools, files, images, or multimodal output, iterate over response.output and branch on each item type.
  5. For multi-turn workflows, choose previous_response_id for API-managed state or pass prior output items back yourself for stateless control.
  6. Update streaming consumers to handle typed Responses events instead of Chat Completions delta chunks.
  7. Move Structured Outputs schemas from response_format to text.format.
  8. If you migrate function calls, return tool results as function_call_output items with the matching call_id.
  9. Update function schemas for Responses: tools are internally tagged, and compatible schemas may be normalized into strict mode unless you set strict: false.
  10. Decide whether to keep stored state (store: true) or explicitly disable retention with store: false.

Migration Field Map

Use this map when updating request builders, SDK wrappers, and stream parsers:

Chat Completions field or behaviorResponses equivalentAvalAI migration note
messagesinput as a string or array of input ItemsSimple transcripts can often move directly; split stable system/developer guidance into instructions when it should apply to every turn.
choices[0].message.contentresponse.output_text or response.outputUse output_text for plain text; inspect typed output Items for tools, reasoning, images, or multimodal output.
choices[].message.tool_callsresponse.output Items with type: "function_call"Send tool results back as function_call_output Items with the same call_id.
response_formattext.formatPrefer strict JSON Schema when supported; keep a JSON-mode fallback only when schema adherence is unavailable.
reasoning_effortreasoning.effortUse only on models/routes that expose reasoning controls; verify behavior per provider.
n for multiple choicesNot supportedMake separate Responses requests if you need multiple candidates and budget for each one.
Chat stream chunks such as choices[].deltaTyped SSE events such as response.created, response.output_text.delta, response.completed, error, and function-call argument eventsRewrite stream consumers before changing endpoints; branch on event.type and do not append non-text events to the UI text buffer.
usersafety_identifier and/or prompt_cache_keyPrefer privacy-preserving opaque IDs; do not send raw PII or request IDs as cache keys.

Incremental Rollout Checklist

  • Start with a simple text-generation flow before moving tool-heavy paths.
  • Compare behavior, latency, token usage, and errors before routing production traffic.
  • Keep Chat Completions running for existing stable integrations while you migrate one flow at a time.
  • For compliance-sensitive or stateless workflows, avoid assuming previous_response_id is allowed; pass the required output items back explicitly.
  • Remember that previous_response_id simplifies context handling but prior context can still count toward input usage in chained requests.

Measure each migrated flow before widening traffic:

MeasureWhat to compare
Output qualityGolden prompts, reasoning/tool success rate, structured-output validity, and refusal behavior.
LatencyTime to first token for streams, full response latency, background job completion time, and provider-specific tail latency.
CostInput/output tokens, reasoning tokens, prompt-cache hit rate where exposed, and extra tool-call costs.
ReliabilityError codes, retry behavior, incomplete responses, stream disconnects, and tool-call idempotency.
ComplianceWhether the flow uses store: true, previous_response_id, encrypted reasoning, manual Item replay, or application-side storage.

Statefulness, Storage, And Compliance

OpenAI's migration guide highlights three state patterns that are useful to preserve in AvalAI integrations:

  • API-managed state: Use previous_response_id when the selected AvalAI route stores prior Responses state and your policy allows server-side continuity. Resend stable instructions on each request instead of assuming the previous response carries them forward.
  • Application-managed state: Use store: false and pass the required prior input/output items yourself when you need stateless operation, deterministic replay, or stricter retention control.
  • Reasoning continuity: If the route supports encrypted reasoning items, request them with include: ["reasoning.encrypted_content"] and pass those items back on later turns. If it does not, preserve normal reasoning, function_call, and function_call_output items or use previous_response_id.

Do not treat previous_response_id as a cost shortcut: earlier context in the response chain can still be billed as input tokens. For regulated workloads, document which state mode you selected and verify it against your data-retention requirements before enabling it in production.

Native Tools vs. Custom Functions

When you migrate a tool-heavy Chat Completions flow, first decide whether each tool should become a native Responses capability or stay as an application-managed custom function.

  • Use AvalAI /v1/search for provider-independent web retrieval; use Responses web_search only when the selected route and model explicitly support it.
  • Keep custom function tools for internal databases, CRMs, billing systems, private APIs, write actions, and any side effect your server must authorize. Always validate arguments server-side and make retries idempotent before executing the action.
  • Treat hosted tools such as file search, code interpreter, computer use, image generation, Remote MCP, and connectors as route-, model-, and account-dependent in AvalAI. Keep a fallback path through your own retrieval layer, sandbox, image endpoint, file workflow, or app-managed MCP proxy.
  • For tool-heavy reasoning migrations, do not drop typed output items when manually carrying context. Preserve reasoning, function_call, and function_call_output items, preserve phase if the response includes it, or use previous_response_id when stored state is allowed.
  • Put most tool-specific instructions in the tool descriptions: what the tool does, when to use it, required inputs, side effects, retry safety, and common errors. Reserve system or developer instructions for global policy that applies across tools.

Compare the Code

The following examples show how to make a basic API call to the Chat Completions API and the Responses API.

Text Generation Example

Both APIs make it easy to generate output from models. A completion requires a messages array, but a response requires an input (string or array, as shown below).

python
# Chat Completions API
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["AVALAI_API_KEY"],
    base_url="https://api.avalai.ir/v1",
)

completion = client.chat.completions.create(
    model="gpt-5.5",
    messages=[
        {
            "role": "user",
            "content": "Write a one-sentence bedtime story about a unicorn.",
        }
    ],
)

print(completion.choices[0].message.content)

# Responses API
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["AVALAI_API_KEY"],
    base_url="https://api.avalai.ir/v1",
)

response = client.responses.create(
    model="gpt-5.5",
    input=[
        {
            "role": "user",
            "content": "Write a one-sentence bedtime story about a unicorn.",
        }
    ],
)

print(response.output_text)
javascript
// Chat Completions API
import OpenAI from "openai";
const client = new OpenAI({
  apiKey: process.env.AVALAI_API_KEY,
  baseURL: "https://api.avalai.ir/v1",
});

const completion = await client.chat.completions.create({
  model: "gpt-5.5",
  messages: [
    {
      role: "user",
      content: "Write a one-sentence bedtime story about a unicorn.",
    },
  ],
});

console.log(completion.choices[0].message.content);

const response = await client.responses.create({
  model: "gpt-5.5",
  input: [
    {
      role: "user",
      content: "Write a one-sentence bedtime story about a unicorn.",
    },
  ],
});

console.log(response.output_text);
bash
# Chat Completions API
curl https://api.avalai.ir/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AVALAI_API_KEY" \
  -d '{
    "model": "gpt-5.5",
    "messages": [
      {
        "role": "user",
        "content": "Write a one-sentence bedtime story about a unicorn."
      }
    ]
  }'

# Responses API
curl https://api.avalai.ir/v1/responses \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AVALAI_API_KEY" \
  -d '{
    "model": "gpt-5.5",
    "input": [
      {
        "role": "user",
        "content": "Write a one-sentence bedtime story about a unicorn."
      }
    ]
  }'
go
// Chat Completions API
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/option"
	"github.com/openai/openai-go/v3/responses"
)

func main() {
	client := openai.NewClient(
		option.WithAPIKey(os.Getenv("AVALAI_API_KEY")),
		option.WithBaseURL("https://api.avalai.ir/v1"),
	)

	// Chat Completions API
	completion, err := client.Chat.Completions.New(
		context.Background(),
		openai.ChatCompletionNewParams{
			Model: openai.F(openai.ChatModel("gpt-5.5")),
			Messages: openai.F([]openai.ChatCompletionMessageParamUnion{
				openai.UserMessage("Write a one-sentence bedtime story about a unicorn."),
			}),
		},
	)
	if err != nil {
		panic(err)
	}
	fmt.Println(completion.Choices[0].Message.Content)

	// Responses API
	response, err := client.Responses.New(
		context.Background(),
		openai.ResponseNewParams{
			Model: "gpt-5.5",
			Input: responses.ResponseNewParamsInputUnion{
				OfString: openai.String("Write a one-sentence bedtime story about a unicorn."),
			},
		},
	)
	if err != nil {
		panic(err)
	}
	fmt.Println(response.OutputText())
}
php
<?php
// Chat Completions API
require 'vendor/autoload.php';

$client = OpenAI::factory()
    ->withApiKey(getenv('AVALAI_API_KEY'))
    ->withBaseUri('https://api.avalai.ir/v1')
    ->make();

$result = $client->chat()->create([
    'model' => 'gpt-5.5',
    'messages' => [
        ['role' => 'user', 'content' => 'Write a one-sentence bedtime story about a unicorn.'],
    ],
]);

echo $result->choices[0]->message->content;

// Responses API
$client = OpenAI::factory()
    ->withApiKey(getenv('AVALAI_API_KEY'))
    ->withBaseUri('https://api.avalai.ir/v1')
    ->make();

$result = $client->responses()->create([
    'model' => 'gpt-5.5',
    'input' => [
        ['role' => 'user', 'content' => 'Write a one-sentence bedtime story about a unicorn.'],
    ],
]);

echo $result->output_text;
?>
Responses API version

Use this version when the selected model supports /v1/responses. messages moves to input, and the final text is read from response.output_text.

python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["AVALAI_API_KEY"],
    base_url="https://api.avalai.ir/v1",
)

response = client.responses.create(
    model="gpt-5.5",
    instructions="You are a helpful assistant.",
    input="Write a one-sentence bedtime story about a unicorn.",
)

print(response.output_text)
javascript
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.AVALAI_API_KEY,
  baseURL: "https://api.avalai.ir/v1",
});

const response = await client.responses.create({
  model: "gpt-5.5",
  instructions: "You are a helpful assistant.",
  input: "Write a one-sentence bedtime story about a unicorn.",
});

console.log(response.output_text);
bash
curl https://api.avalai.ir/v1/responses \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AVALAI_API_KEY" \
  -d '
  {
    "model": "gpt-5.5",
    "input": "Write a one-sentence bedtime story about a unicorn.",
    "instructions": "You are a helpful assistant."
  }'
  • messagesinput
  • system message → instructions or a developer item
  • choices[0].message.contentresponse.output_text
  • for tools and multimodal output, inspect response.output by item type.

When you get a response back from the Responses API, the fields differ slightly. Instead of a message, you receive a typed response object with its own id. Responses are stored by default. Chat completions are stored by default for new accounts. To disable storage when using either API, set store: false.

Chat Completions API Response:

json
[
  {
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "Under the soft glow of the moon, Luna the unicorn danced through fields of twinkling stardust, leaving trails of dreams for every child asleep.",
      "refusal": null
    },
    "logprobs": null,
    "finish_reason": "stop"
  }
]

Responses API Response:

json
[
  {
    "id": "msg_67b73f697ba4819183a15cc17d011509",
    "type": "message",
    "role": "assistant",
    "content": [
      {
        "type": "output_text",
        "text": "Under the soft glow of the moon, Luna the unicorn danced through fields of twinkling stardust, leaving trails of dreams for every child asleep.",
        "annotations": []
      }
    ]
  }
]

Key Differences

  • The Responses API returns output, while the Chat Completions API returns a choices array.
  • Responses generates one candidate per request; Chat Completions supports multiple choices with n. Make separate Responses requests if you need multiple candidates.
  • Structured Outputs API shape is different. Instead of response_format, use text.format in Responses. Learn more in the Structured Outputs guide.
  • Function calling API shape is different—both for the function config on the request and function calls sent back in the response. See the full difference in the function calling guide.
  • Reasoning is different. Instead of reasoning_effort in Chat Completions, use reasoning.effort with the Responses API. Read more details in the reasoning guide.
  • The Responses SDK has an output_text helper, which the Chat Completions SDK does not have.
  • Conversation state: You have to manage conversation state yourself in Chat Completions, while Responses has previous_response_id to help you with long-running conversations.
  • Responses are stored by default. Chat completions are stored by default for new accounts. To disable storage, set store: false.
  • Streaming is event-based. Instead of reading only token delta chunks, handle typed events such as response.created, response.output_text.delta, response.completed, error, response.function_call_arguments.delta, and response.function_call_arguments.done.
  • Tool and reasoning workflows are item-based. Preserve reasoning, function_call, and function_call_output items when you manually carry context forward.

Common Migration Mistakes

Watch for these issues when moving production code from Chat Completions to Responses:

  • Reading choices[0].message.content instead of response.output_text or response.output.
  • Treating every response.output item as a message; reasoning, tool calls, and function calls are separate item types.
  • Dropping reasoning, function_call, or function_call_output items when manually replaying context.
  • Returning a function result without the matching call_id.
  • Assuming Chat Completions function schemas are still non-strict after moving to Responses; check strict, required, and additionalProperties.
  • Sending response_format to /v1/responses instead of text.format.
  • Reusing Chat Completions streaming handlers without branching on typed Responses events.
  • Assuming previous_response_id removes prior-context input billing; chained context can still count as input.

What This Means for Existing APIs

Chat Completions

The Chat Completions API remains the most widely used API. It will continue to be supported with new models and capabilities. If you don't need built-in tools for your application, you can confidently continue using Chat Completions.

New models will continue to be released to Chat Completions whenever their capabilities don't depend on built-in tools or multiple model calls. When you're ready for advanced capabilities designed specifically for agent workflows, the Responses API is recommended.

Assistants

Based on developer feedback from the Assistants API beta, key improvements have been incorporated into the Responses API to make it more flexible, faster, and easier to use. The Responses API represents the future direction for building agents on AvalAI.

OpenAI has announced that the Assistants API is deprecated as of August 26, 2025, with a sunset date of August 26, 2026. In AvalAI documentation, treat new agentic examples as Responses-first and keep Assistants references only for existing integrations or explicit migration notes.

When migrating Assistants-style apps, map assistants/threads/runs to Responses state, tools, previous_response_id, and application-managed storage. Verify which hosted tools are available on your selected AvalAI route before assuming OpenAI-hosted tool parity.