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:
/v1/chat/completions: Returns the payload directly to the client with no server-side storage./v1/responses: Persists the final response in an in-memory store (internal/httpapi/openai/responses/response_store.go) viah.getResponseStore().
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.createdresponse.output_item_addedresponse.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/completionsfor drop-in replacement with existing clients expectingchoices[0].message. - Structured reasoning separation: Use
/v1/responseswhen downstream tools need to distinguish between reasoning chains, final text, and tool calls via distinctoutputitems. - Stateful retrieval: Use
/v1/responseswhen you need to fetch generated content later usingGET /v1/responses/{response_id}. - Granular streaming: Use
/v1/responsesfor SSE events that track individual output items (response.output_item_added) rather than simple text deltas.
Summary
/v1/chat/completionsininternal/httpapi/openai/chat/handler_chat.goprovides standard OpenAI compatibility withchoices[0].messageoutput and no persistence./v1/responsesininternal/httpapi/openai/responses/responses_handler.gooffers decomposed output viaBuildResponseObject, separating reasoning and text into distinct items.- Only the Responses endpoint utilizes
responseStorefor in-memory persistence and supportsGET /v1/responses/{response_id}retrieval. - Both share the same DeepSeek upstream call (
h.DS.CallCompletion) and authentication, but diverge in normalization (NormalizeOpenAIChatRequestvsNormalizeOpenAIResponsesRequest) 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →