DS2API /v1/chat/completions vs /v1/responses: Key Differences Explained

The /v1/chat/completions endpoint returns a standard OpenAI-compatible chat completion with no server-side persistence, while /v1/responses provides a structured payload separating reasoning, output text, and function calls, complete with a built-in retrieval API.

DS2API is an OpenAI-compatible gateway that proxies requests to DeepSeek models, exposing two distinct completion interfaces. Understanding the difference between /v1/chat/completions and /v1/responses in DS2API helps you choose between standard chat interoperability and advanced response decomposition with stateful retrieval.

Request Normalization

Both endpoints share authentication and session creation logic, but they use different normalization functions to prepare the upstream request.

Chat Completions – Uses NormalizeOpenAIChatRequest in internal/promptcompat/standard_request.go to parse the classic messages array into a StandardRequest.

Responses – Uses NormalizeOpenAIResponsesRequest in internal/promptcompat/request_normalize.go to handle the responses-specific contract, including special processing for output_text and function call definitions.

// From handler_chat.go
stdReq, err := promptcompat.NormalizeOpenAIChatRequest(h.Store, req, requestTraceID(r))

// From responses_handler.go
stdReq, err := promptcompat.NormalizeOpenAIResponsesRequest(h.Store, req, traceID)

Handler Logic and Response Construction

After normalization, both handlers call h.DS.CallCompletion to reach the DeepSeek model, but they diverge in how they construct the final JSON payload.

Chat Handler

Located in internal/httpapi/openai/chat/handler_chat.go, this handler invokes openaifmt.BuildChatCompletion to generate a chat.completion object:

respBody := openaifmt.BuildChatCompletion(completionID, model, finalPrompt,
             finalThinking, finalText, toolNames)

The output conforms to the standard OpenAI schema with a choices array containing message objects.

Responses Handler

Located in internal/httpapi/openai/responses/responses_handler.go, this handler uses openaifmt.BuildResponseObject (defined in internal/format/openai/render_responses.go) to create a richer structure:

responseObj := openaifmt.BuildResponseObject(responseID, model,
             finalPrompt, sanitizedThinking, sanitizedText, toolNames)

This produces a type: "response" envelope containing an output array that separates reasoning blocks, output text, and function-call items, plus a top-level output_text field.

Persistence and Retrieval API

A critical architectural difference is persistence:

The Responses endpoint exposes a retrieval interface:

GET /v1/responses/{response_id}

This allows clients to fetch previously generated responses by ID, a feature absent from the chat completions endpoint.

Streaming Behavior

Both endpoints support Server-Sent Events (SSE), but the event schemas differ significantly.

Chat completions emit standard delta messages representing incremental content for the assistant's message.

Responses emit a richer event stream defined in internal/format/openai/render_stream_events.go, including:

  • response.created
  • response.output_item_added
  • response.output_item_done

These events allow granular tracking of reasoning steps versus final output versus tool invocations.

Practical Code Examples

Calling the Chat Completions Endpoint

curl -X POST https://api.example.com/v1/chat/completions \
  -H "Authorization: Bearer $DS2API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "model": "gpt-4o-mini",
        "messages": [{"role":"user","content":"Explain quantum tunneling"}],
        "stream": false
      }'

Response:

{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1714139205,
  "model": "gpt-4o-mini",
  "choices": [{
    "index": 0,
    "message": {"role":"assistant","content":"Quantum tunneling is ..."},
    "finish_reason":"stop"
  }],
  "usage": {"prompt_tokens":12,"completion_tokens":45,"total_tokens":57}
}

Calling the Responses Endpoint

curl -X POST https://api.example.com/v1/responses \
  -H "Authorization: Bearer $DS2API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "model": "gpt-4o-mini",
        "messages": [{"role":"user","content":"Give me a summary and a function call"}],
        "stream": false
      }'

Response:

{
  "id": "resp_4c8e1b2f-7a6d-4f2e-9c3b-b1a5d9c6e5f7",
  "type": "response",
  "object": "response",
  "created_at": 1714139210,
  "status": "completed",
  "model": "gpt-4o-mini",
  "output": [
    {
      "type": "function_call",
      "id": "fc_1d2c3e4f-5a6b-7c8d-9e0f-1234567890ab",
      "call_id": "call_9f8e7d6c-5b4a-3c2d-1e0f-9876543210fe",
      "name": "summarize",
      "arguments": {"text":"Quantum tunneling ..."},
      "status":"completed"
    },
    {
      "type": "message",
      "id": "msg_a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
      "role": "assistant",
      "content": [
        {"type":"reasoning","text":"I reasoned about the physics first."},
        {"type":"output_text","text":"Quantum tunneling is ..."}
      ]
    }
  ],
  "output_text": "Quantum tunneling is ...",
  "usage": {"prompt_tokens":15,"completion_tokens":60,"total_tokens":75}
}

Retrieving a Stored Response

curl -X GET https://api.example.com/v1/responses/resp_4c8e1b2f-7a6d-4f2e-9c3b-b1a5d9c6e5f7 \
  -H "Authorization: Bearer $DS2API_KEY"

When to Use Each Endpoint

  • Standard OpenAI SDK compatibility: Use /v1/chat/completions for drop-in replacement with existing clients expecting choices[0].message.
  • Structured reasoning separation: Use /v1/responses when downstream tools need to distinguish between reasoning chains, final text, and tool calls via distinct output items.
  • Stateful retrieval: Use /v1/responses when you need to fetch generated content later using GET /v1/responses/{response_id}.
  • Granular streaming: Use /v1/responses for SSE events that track individual output items (response.output_item_added) rather than simple text deltas.

Summary

  • /v1/chat/completions in internal/httpapi/openai/chat/handler_chat.go provides standard OpenAI compatibility with choices[0].message output and no persistence.
  • /v1/responses in internal/httpapi/openai/responses/responses_handler.go offers decomposed output via BuildResponseObject, separating reasoning and text into distinct items.
  • Only the Responses endpoint utilizes responseStore for in-memory persistence and supports GET /v1/responses/{response_id} retrieval.
  • Both share the same DeepSeek upstream call (h.DS.CallCompletion) and authentication, but diverge in normalization (NormalizeOpenAIChatRequest vs NormalizeOpenAIResponsesRequest) and streaming event formats.

Frequently Asked Questions

Can I retrieve a chat completion later using its ID?

No. According to the source code in handler_chat.go, the /v1/chat/completions endpoint does not persist responses to the responseStore. Only /v1/responses stores data for later retrieval via GET /v1/responses/{response_id}.

Does the Responses endpoint support standard OpenAI client libraries?

While DS2API maintains OpenAI-compatible request structures, the /v1/responses output schema differs from the standard chat.completion format. Standard SDKs expecting choices[0].message will require custom parsing to handle the output array and output_text fields generated by BuildResponseObject.

How does streaming differ between the two endpoints?

The chat completions endpoint emits SSE delta messages for incremental content, while the responses endpoint emits structured events like response.created and response.output_item_done as defined in internal/format/openai/render_stream_events.go, allowing real-time tracking of reasoning versus final output.

Which endpoint should I use for function calling?

Both endpoints support function calling, but /v1/responses is architecturally superior for complex agent workflows because it explicitly separates function calls into typed output items (e.g., type: function_call) distinct from reasoning and text content, making downstream parsing more reliable.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →