DEV Community

Cover image for Stop Guessing Your AI Client Settings: Chat Completions vs. Anthropic Messages vs. Responses API
Arga Prayoga
Arga Prayoga

Posted on

Stop Guessing Your AI Client Settings: Chat Completions vs. Anthropic Messages vs. Responses API

If you have ever configured an AI coding assistant, local agent, or LLM gateway (like OpenCode, Cline, Cursor, or LiteLLM), you have probably stared at a settings screen that looks like this:

AI Client Provider Configuration — Base URL & API Format

Most developers pick Chat completions by muscle memory, cross their fingers, and hope it works. When it throws a 404 Not Found or 401 Unauthorized, debugging feels like guesswork.

Once you understand how Base URL and API Format work together—and why three incompatible JSON dialects exist—you will never misconfigure an AI client again.


1. The Core Formula: Base URL + API Format

Think of your AI client settings as a two-part URL builder combined with a JSON translator:

Full Request URL = Base URL + API Format Path
Enter fullscreen mode Exit fullscreen mode

For example, if you set:

  • Base URL: https://opencode.ai/zen/go/v1
  • API Format: Chat completions (/chat/completions)

Your client fires an HTTP POST request to:

https://opencode.ai/zen/go/v1/chat/completions
Enter fullscreen mode Exit fullscreen mode

This looks trivial until you switch formats. Notice how the second option in many clients includes /v1 in its path (/v1/messages). If your Base URL already ends with /v1, naive clients concatenate them into a broken path:

❌ https://opencode.ai/zen/go/v1/v1/messages   (404 Not Found)
✅ https://opencode.ai/zen/go/v1/messages      (or remove /v1 from Base URL)
Enter fullscreen mode Exit fullscreen mode

More importantly, API Format does not just change the URL path. It completely changes the authentication headers, JSON request body, JSON response shape, and Server-Sent Events (SSE) streaming structure.


2. Dialect #1: Chat completions (/chat/completions)

The "USB-C" of LLM APIs

Originally introduced by OpenAI, /chat/completions became the de facto universal standard of the AI ecosystem. Almost every model provider and local inference engine exposes an OpenAI-compatible endpoint:

  • Cloud Gateways & Inference: OpenRouter, Groq, DeepSeek, Together AI, Mistral
  • Google Gemini (Compatibility Mode): https://generativelanguage.googleapis.com/v1beta/openai/
  • Local Engines: Ollama (http://localhost:11434/v1), vLLM, LM Studio, llama.cpp

How It Looks Under the Hood

  • Auth Header: Authorization: Bearer <API_KEY>
  • State Model: Stateless. Your client must resend the entire conversation history on every turn inside the messages array.
  • System Prompt: Placed inside messages with "role": "system".
POST /chat/completions
Authorization: Bearer sk-...

{
  "model": "gpt-4o",
  "messages": [
    { "role": "system", "content": "You are a concise code reviewer." },
    { "role": "user", "content": "Review this SQL query for injection." }
  ],
  "temperature": 0.2
}
Enter fullscreen mode Exit fullscreen mode

When to Pick It

Choose Chat completions as your default for 90% of proxies, open-weight models (Llama, Qwen, DeepSeek), and local Ollama setups.


3. Dialect #2: Anthropic messages (/v1/messages)

Why Anthropic Refused to Copy OpenAI

Anthropic designed its /v1/messages protocol with stricter structural guarantees and native support for Claude-specific features like Prompt Caching and Extended Thinking.

If you send an OpenAI-formatted JSON body to a native Anthropic endpoint, the server rejects it immediately.

How It Differs

  • Auth Headers: Uses x-api-key: <API_KEY> and requires an explicit version header (anthropic-version: 2023-06-01) instead of Bearer.
  • System Prompt: Moved out of messages into a dedicated top-level "system" field.
  • max_tokens is Mandatory: Unlike OpenAI (where it is optional), Anthropic returns a 400 Bad Request if max_tokens is omitted.
  • Tool Calling Shape: Uses structured tool_use and tool_result content blocks rather than OpenAI's tool_calls array.
POST /v1/messages
x-api-key: sk-ant-...
anthropic-version: 2023-06-01

{
  "model": "claude-3-7-sonnet-latest",
  "max_tokens": 2048,
  "system": "You are a concise code reviewer.",
  "messages": [
    { "role": "user", "content": "Review this SQL query for injection." }
  ]
}
Enter fullscreen mode Exit fullscreen mode

When to Pick It

Pick Anthropic messages when:

  1. Connecting directly to https://api.anthropic.com (make sure your Base URL doesn't duplicate /v1).
  2. Using a multi-provider gateway (like OpenCode Zen or LiteLLM) with Claude models and you want native prompt caching or thinking blocks preserved without lossy translation.

4. Dialect #3: Responses (/responses)

OpenAI's Next-Gen Agentic Protocol

As models shifted from simple chatbots to autonomous reasoning agents (like OpenAI's o-series, GPT-5, and Codex models), /chat/completions started showing its age. Resending massive JSON arrays on every tool-call loop wastes bandwidth, and stateless turns make server-side reasoning token caching awkward.

Enter the Responses API (/responses)—OpenAI's unified interface designed for multi-step, agentic workflows.

How It Differs

  • Auth Header: Still uses Authorization: Bearer <API_KEY>.
  • input Instead of messages: Accepts either a raw string for simple prompts or a flexible array of input items.
  • instructions for System Guidance: Top-level "instructions" replaces the "role": "system" message.
  • Server-Side State (previous_response_id): Every response returns a unique ID (e.g., resp_abc123). Sending previous_response_id on your next call chains conversation state natively on the server—no need to resend full chat history.
  • Built-in Tools & Reasoning Items: First-class support for server-executed tools (web search, file search, code interpreter) and structured reasoning traces.
POST /responses
Authorization: Bearer sk-...

{
  "model": "gpt-5-codex",
  "instructions": "You are a concise code reviewer.",
  "input": "Review this SQL query for injection.",
  "previous_response_id": "resp_01abc..."
}
Enter fullscreen mode Exit fullscreen mode

⚠️ Hidden Gotcha with previous_response_id: While previous_response_id carries forward your conversation history, top-level instructions do not automatically persist across chained turns. Always resend instructions on every request if your agent relies on strict system rules or JSON schemas.

When to Pick It

Pick Responses when running modern OpenAI reasoning/Codex models directly or through a gateway that explicitly supports the /responses specification. Do not pick it for Ollama or standard open-weight proxies unless they explicitly advertise /responses support.


5. Quick Reference Cheat Sheet

Bookmark this table the next time you configure an AI client:

Feature Chat completions Anthropic messages Responses
Endpoint Path /chat/completions /v1/messages /responses
Auth Header Authorization: Bearer x-api-key + anthropic-version Authorization: Bearer
System Prompt Inside messages (role: system) Top-level "system" field Top-level "instructions" field
Prompt Field messages (array) messages (array) input (string or item array)
max_tokens Optional Required Optional (max_output_tokens)
State Model Stateless (resend history) Stateless (resend history) Stateful option (previous_response_id)
Best Used For Universal default (Ollama, Groq, OpenRouter, Gemini) Native Claude (Prompt Caching, Thinking) Modern OpenAI / Codex agentic & reasoning models

3 Common Mistakes That Break Your Setup

  1. The Double /v1 Trap: Pasting https://proxy.example.com/v1 into Base URL while selecting /v1/messages often triggers a silent /v1/v1/messages 404 error. Check your client's URL normalization behavior—or strip /v1 from the Base URL if it fails.
  2. Thinking "Error 400" Means a Bad API Key: If you get a 400 Bad Request mentioning messages, input, or max_tokens is required, your API key is fine—your API Format dropdown simply doesn't match what the server expects.
  3. Broken Streaming in IDE: Even if a "Test Connection" ping succeeds, picking the wrong format causes IDE chat panes to freeze or print raw JSON because SSE chunk schemas (choices[0].delta vs. content_block_delta vs. response.output_text.delta) are completely incompatible across the three dialects.

Rule of Thumb

  • Using Ollama, DeepSeek, Groq, Gemini, or OpenRouter? Use Chat completions.
  • Using Claude directly (or via a Claude-native gateway)? Use Anthropic messages.
  • Using modern OpenAI / Codex models with stateful reasoning? Use Responses.

Which API format has given you the biggest debugging headache—or which gateway trick do you use in your setup? Drop a comment below!

Top comments (0)