Using DeepSeek With the OpenAI SDK: A Compatibility Guide

If you already have a working OpenAI integration and you want to point it at DeepSeek’s current models, the answer is genuinely two lines of code. DeepSeek OpenAI compatibility means the wire format mirrors OpenAI’s Chat Completions API closely enough that the official openai Python and Node SDKs work against https://api.deepseek.com after you swap the base_url and api_key. No request rebuilding, no response parser changes, no new dependency.
The catch — and there always is one — is in the DeepSeek-specific parameters (thinking mode is on by default), the stateless conversation model, the JSON-mode caveats, and the legacy model IDs that DeepSeek retired. This guide walks through what migrates cleanly, what needs adjusting, what the Responses API and Anthropic formats add, and where the OpenAI-compatible surface stops behaving like OpenAI.
What “OpenAI-compatible” actually means here

DeepSeek’s Your First API Call page states it plainly: “The DeepSeek API uses an API format compatible with OpenAI/Anthropic. By modifying the configuration, you can use the OpenAI/Anthropic SDK or softwares compatible with the OpenAI/Anthropic API to access the DeepSeek API.” In practice that means the Chat Completions request and response envelopes — the messages array, the role/content shape, the choices[0].message.content path, the usage block, the stream=true SSE chunks — all match.
You point the SDK at DeepSeek by changing two values:
base_url→https://api.deepseek.comapi_key→ your DeepSeek key from the platform console
The chat endpoint is POST /chat/completions. Beta features such as Chat Prefix Completion, FIM (fill-in-the-middle) and strict-mode tool calls live under https://api.deepseek.com/beta.
One distinction worth getting right up front: DeepSeek supports three API formats on the same models, not one.
- OpenAI Chat Completions — base URL
https://api.deepseek.com; the subject of most of this guide. - OpenAI Responses API — the same base URL,
https://api.deepseek.com. DeepSeek added it for Codex;client.responses.createworks withdeepseek-flashanddeepseek-v4-pro. - Anthropic Messages API — a separate base URL,
https://api.deepseek.com/anthropic, for the Anthropic SDK and tools built on it.
Pick whichever SDK matches your existing code; all three reach the same two models. A Responses API call, following DeepSeek’s guide:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ.get("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com",
)
response = client.responses.create(
model="deepseek-flash",
instructions="You are a helpful assistant.",
input="Hi, how are you?",
)
print(response.output_text)
And an Anthropic SDK call, with the base URL and key taken from ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic and ANTHROPIC_API_KEY (your DeepSeek key) in the environment:
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_BASE_URL and ANTHROPIC_API_KEY
message = client.messages.create(
model="deepseek-flash",
max_tokens=1000,
system="You are a helpful assistant.",
messages=[{"role": "user", "content": [{"type": "text", "text": "Hi, how are you?"}]}],
)
print(message.content)
Quickstart: curl and Python
Here is the smallest possible call against deepseek-flash, the default model, using DeepSeek’s default thinking mode. (For non-thinking mode, explicitly pass "thinking": {"type": "disabled"} in the JSON body, or extra_body={"thinking": {"type": "disabled"}} in Python.) First, the curl version of POST /chat/completions:
curl https://api.deepseek.com/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
-d '{
"model": "deepseek-flash",
"messages": [
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Summarise the OpenAI Chat Completions schema in one sentence."}
],
"stream": false
}'
The same call with the official OpenAI Python SDK — note that the only changes from a real OpenAI integration are base_url, the API key and the model string:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ.get("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com",
)
resp = client.chat.completions.create(
model="deepseek-flash",
messages=[
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Hello"},
],
)
print(resp.choices[0].message.content)
To use deepseek-v4-pro with an explicit thinking setting, switch the model ID and pass DeepSeek-specific fields through extra_body, which is how the OpenAI SDK forwards non-OpenAI parameters to the server:
resp = client.chat.completions.create(
model="deepseek-v4-pro",
messages=[{"role": "user", "content": "Plan the migration."}],
reasoning_effort="high",
extra_body={"thinking": {"type": "enabled"}},
)
If you are just starting, our walkthrough on how to get a DeepSeek API key covers the console setup and topping up your balance — requests return 402 Insufficient Balance when the balance runs out.
Current model IDs and legacy migration
DeepSeek’s Models & Pricing page lists two models that share the same OpenAI-compatible surface but differ in capabilities and price:
| Model ID | Served by | Context / max output | Vision | Concurrency (per account) |
|---|---|---|---|---|
deepseek-flash |
DeepSeek-V4.1-Flash-1017 | 1M / 384K tokens | Supported | 2,500 |
deepseek-v4-pro |
DeepSeek-V4-Pro-0813 | 1M / 384K tokens | Not supported | 500 |
Both support non-thinking and thinking mode, with thinking the default, and both work through the Chat Completions, Responses and Anthropic formats. Background on the model family lives on the DeepSeek V4 page.
If you have an existing integration on older IDs, here is the migration table:
| Legacy ID | Status | Replace with |
|---|---|---|
deepseek-chat |
Scheduled for retirement on 2026-07-24 at 15:59 UTC (until then routed to deepseek-v4-flash, non-thinking); no longer listed in the docs |
deepseek-flash with extra_body={"thinking": {"type": "disabled"}} |
deepseek-reasoner |
Scheduled for retirement on 2026-07-24 at 15:59 UTC (until then routed to deepseek-v4-flash, thinking); no longer listed in the docs |
deepseek-flash (thinking is the default) |
deepseek-v4-flash, deepseek-v4-flash-vision-exp |
Still accepted; the models are retired and requests are served by DeepSeek-V4.1-Flash-1017 at the Flash price | deepseek-flash |
DeepSeek’s 10 September 2026 Change Log is explicit: “Change the model name to deepseek-flash to call the latest V4.1 Flash model.” The base_url does not change. Migration is a one-line diff per call site.
Thinking mode is a parameter, not a model
This is the single biggest change for anyone coming from the V3.x era or from OpenAI’s reasoning models. Thinking is a request parameter on either model, not a separate ID, and it is enabled by default with effort high. The settings in Chat Completions format:
- Non-thinking: pass
extra_body={"thinking": {"type": "disabled"}}. Fastest and cheapest per request. (The Chat Completions API reference also acceptsreasoning_effort="none"to switch thinking off.) - Thinking:
reasoning_effort="low"or"high"plusextra_body={"thinking": {"type": "enabled"}}. For compatibility,minimalis mapped tolow, andmediumandxhightohigh. - Thinking-max:
reasoning_effort="max"(ultramaps here too).max_tokensdefaults to 128K at this level (64K for other thinking levels, 8K without thinking); you can raise it to 384K (393,216).
In the other formats the same control is {"output_config": {"effort": "low/high/max"}} (Anthropic) and {"reasoning": {"effort": "none/low/high/max"}} (Responses API, where none disables thinking).
When thinking is on, the response carries reasoning_content alongside the final content; DeepSeek’s Thinking Mode guide says the chain-of-thought is returned via reasoning_content, at the same level as content. Two operational details that matter:
- Thinking mode does not support
temperature,presence_penaltyorfrequency_penalty; for compatibility, setting them triggers no error but has no effect.top_pdepends on the model: ondeepseek-flashit only takes effect in thinking mode (effective range 0.95–1.0); ondeepseek-v4-proit is ignored in thinking mode and takes effect in non-thinking mode. - When a request carries
tools, you must pass back thereasoning_contentof all previous turns — even turns without a tool call — or the API returns a 400. Withouttools, passing it back is unnecessary: the API ignores it.
Parameter compatibility, line by line
| Parameter | OpenAI | DeepSeek | Notes |
|---|---|---|---|
model |
Required | Required | deepseek-flash or deepseek-v4-pro |
messages |
Required | Required | Same role/content shape; image parts on deepseek-flash only |
temperature |
Yes | 0–2, default 1 (no effect in thinking mode) | DeepSeek recommends 0.0 for code and math, 1.0 for data analysis, 1.3 for conversation and translation, 1.5 for creative writing |
top_p |
Yes | Yes, model-specific | deepseek-flash: thinking mode only (0.95–1.0); deepseek-v4-pro: non-thinking mode only |
max_tokens |
Yes | Up to 393,216 (384K) | Defaults 8K / 64K / 128K (non-thinking / thinking / max); set explicitly when using JSON mode |
stream / stream_options |
Yes | Yes | Reasoning streams as delta.reasoning_content; usage always rides on the last chunk |
response_format |
Yes | text or json_object |
JSON mode — see caveats below |
tools / tool_choice |
Yes | Yes | OpenAI-format function declarations work as-is; required or a named tool returns 400 in thinking mode |
reasoning_effort |
Reasoning models | Both models | "none", "low", "high" (default) or "max" |
thinking |
n/a | Pass via extra_body |
{"type": "enabled"} (default) or {"type": "disabled"} |
logprobs / top_logprobs |
Yes | Yes | top_logprobs 0–20, requires logprobs: true |
frequency_penalty / presence_penalty |
Yes | No longer supported | Accepted without error, no effect |
user_id |
n/a | Pass via extra_body |
Content-safety, KV-cache and scheduling isolation per end user |
For a deeper walk through the request shape, the DeepSeek API documentation explainer covers headers, error shapes, and the /models and /user/balance helper endpoints.
The stateless gotcha
The web chat at chat.deepseek.com keeps your conversation history. The API does not. Every POST /chat/completions call is independent — the server has no memory of previous turns. Your client must resend the full messages array on every request to sustain a multi-turn conversation. This is identical to OpenAI’s Chat Completions behaviour, but worth stating because the chatbot UI obscures it. (The Responses API is stateless on DeepSeek too: previous_response_id, conversation and store are not supported.)
Practically, that means a multi-turn loop looks like this:
messages = [{"role": "system", "content": "You are a helpful assistant."}]
while True:
user_text = input("> ")
messages.append({"role": "user", "content": user_text})
resp = client.chat.completions.create(
model="deepseek-flash",
messages=messages,
)
reply = resp.choices[0].message
messages.append({"role": "assistant", "content": reply.content})
print(reply.content)
Without tools, appending only content is fine — any reasoning_content you send back is ignored. If your requests carry tools, append the whole assistant message (messages.append(resp.choices[0].message)) so that reasoning_content goes back with it.
JSON mode, tool calling, FIM, streaming
The advanced features all work through the OpenAI SDK; they just need the right caveats.
JSON mode
Set response_format={"type": "json_object"}. JSON mode is designed to return valid JSON, but DeepSeek’s JSON Output guide notes that the API may occasionally return empty content. Three rules keep production code safe:
- Include the word json in your prompt and a small example schema.
- Set
max_tokenshigh enough that the JSON cannot be truncated. - Handle the case where
contentcomes back empty.
The mechanics in detail are covered in our DeepSeek API JSON mode guide.
Tool calling
OpenAI-format tools declarations work without modification. The model emits tool_calls entries on the assistant message, your code executes them, and you append a {"role": "tool", "tool_call_id": ..., "content": ...} turn before the next request. Both thinking and non-thinking modes support tools; in thinking mode, remember the reasoning_content pass-back rule above. Strict mode ("strict": true on every function, Beta base URL) makes the server validate your JSON schema and keep tool-call output to it.
FIM completion (Beta)
Fill-in-the-middle is available on both models in non-thinking mode only, through client.completions.create against the https://api.deepseek.com/beta base URL, with a 4K maximum output. Useful for IDE-style code suggestions; not useful if you also want step-by-step reasoning.
Streaming
Set stream=true and consume the SSE chunks. The deltas carry delta.content as on OpenAI; in thinking mode they additionally carry delta.reasoning_content. The streaming patterns, keep-alive comments and proxy tips are in our DeepSeek API streaming reference. (Responses API streams use semantic events and end with response.completed, response.incomplete or response.failed — there is no data: [DONE] line.)
A worked cost example: deepseek-flash vs deepseek-v4-pro
Switching SDKs does not change the bill; the model and the time of day do. Prices per 1M tokens as of October 2026, from DeepSeek’s pricing page — verify there before committing:
| Model | Cache hit input (peak / off-peak) | Cache miss input (peak / off-peak) | Output (peak / off-peak) |
|---|---|---|---|
deepseek-flash |
$0.006 / $0.003 | $0.30 / $0.15 | $1.20 / $0.60 |
deepseek-v4-pro |
$0.044 / $0.022 | $1.32 / $0.66 | $3.96 / $1.98 |
Peak hours are 01:00–04:00 and 06:00–10:00 UTC, Monday through Friday, excluding Chinese public holidays; everything else is off-peak at half price. Take one call with a 2,000-token system prompt that hits the cache, a 200-token user message that misses (the cache only matches persisted prefixes, not new user input), and a 300-token response:
deepseek-flash: 2,000 × $0.006/M + 200 × $0.30/M + 300 × $1.20/M = $0.000012 + $0.00006 + $0.00036 = $0.000432 at peak; $0.000216 off-peak.deepseek-v4-pro: 2,000 × $0.044/M + 200 × $1.32/M + 300 × $3.96/M = $0.000088 + $0.000264 + $0.001188 = $0.00154 at peak; $0.00077 off-peak.
Pro costs about 3.6× Flash on this request in either period. For interactive estimates, the DeepSeek pricing calculator takes the same three buckets and produces a per-call number. Repeated prefixes get the cache-hit price tier automatically — the prefix-cache mechanics are covered in DeepSeek context caching.
Error handling and rate limits
Error codes match the OpenAI envelope. A few DeepSeek specifics, from its Error Codes and Rate Limit pages and the API reference, worth remembering:
402 Insufficient Balancemeans your account has run out of balance. Top up before integration testing.422 Invalid Parametersand400 Invalid Formatcarry hints in the error message — for example,stream_optionswithoutstream: true, ortool_choice="required"in thinking mode, return a 400.429 Rate Limit Reachedfires when you send requests too quickly or exceed the per-account concurrency limit (2,500 fordeepseek-flash, 500 fordeepseek-v4-pro). Retry 429 and 5xx errors with exponential backoff.
Wrap calls in a retry helper that handles 429 and 5xx with exponential backoff; do not retry other 4xx errors automatically — they are logic bugs, not transient failures. The full table of codes lives in the DeepSeek API error codes reference.
When OpenAI compatibility stops being a perfect fit

The compatibility surface is broad, but it is not 100%. A short, honest list of where it leaks:
- Responses API, with limits. DeepSeek supports
client.responses.createnatively, but statelessly:previous_response_id,conversation,store,background,prompt_cache_keyand several other parameters are not supported, and unsupported parameters are silently ignored rather than rejected. Tools are limited tofunction, theapply_patchcustom tool andweb_search(withdeepseek-v4-proonly);reasoning.summaryis accepted but no summary is generated. - No Assistants API, no embeddings. DeepSeek’s API reference covers Chat Completions, Responses, FIM, model listing, balance, a Files API (used for image inputs) and the Search & Fetch APIs — not the full OpenAI platform.
- Thinking-mode parameter quirks. Sampling controls are silently ignored in thinking mode, and
tool_choice="required"or a named tool returns 400 until you disable thinking. - Inserting tool calls mid-conversation. Per DeepSeek’s Tool Calls guide, Chat Completions does not support inserting tool calls that the model did not generate into the middle of the history; the Anthropic and Responses formats do.
- Sampling defaults differ.
temperaturedefaults to 1.0, and DeepSeek publishes per-task recommendations (see the table above); do not import another provider’s defaults. - Anthropic SDK works too. If your stack already speaks Claude’s message format, point it at
https://api.deepseek.com/anthropicrather than rewriting it. DeepSeek maps model names that start withclaude-opustodeepseek-v4-proand otherclaudenames todeepseek-flash;thinking.budget_tokens,top_kandcache_controlare ignored, anddocumentcontent blocks are not supported.
For broader patterns — retries, idempotency, observability — the DeepSeek API best practices page collects them in one place. And if you are evaluating whether to swap providers at all, DeepSeek vs ChatGPT walks through the trade-offs.
Migration checklist
- Get a key and top up your balance — calls fail with 402 when it runs out.
- Change
base_urltohttps://api.deepseek.com(orhttps://api.deepseek.com/anthropicfor the Anthropic SDK) and replace the API key. - Replace OpenAI model strings with
deepseek-flash(default) ordeepseek-v4-pro. - If you still have
deepseek-chat,deepseek-reasonerordeepseek-v4-flashin your code, switch todeepseek-flash— the first two were scheduled for retirement on 2026-07-24 at 15:59 UTC. - Decide thinking vs non-thinking per call site (thinking is the default); gate
reasoning_effort="max"behind a feature flag because the cost can spike. - Keep your retry/backoff layer; DeepSeek’s error codes match the OpenAI shape closely enough that existing handlers usually port over unchanged.
- Run a small evaluation harness — even ten representative prompts across both models will tell you whether Pro’s price is worth it on your data.
For a broader tour of what the API will and won’t do, see the full DeepSeek API docs and guides.
How do I use the OpenAI SDK with DeepSeek?
Install the official openai package, then construct the client with base_url="https://api.deepseek.com" and your DeepSeek API key. Set model to deepseek-flash or deepseek-v4-pro and call client.chat.completions.create() exactly as you would against OpenAI. Pass DeepSeek-specific fields like thinking through extra_body. Full setup steps are in our DeepSeek API getting started tutorial.
Is the DeepSeek API really compatible with OpenAI?
Yes for Chat Completions — the request and response shapes match closely enough that the OpenAI Python and Node SDKs work after changing base_url and api_key. The Responses API is supported too, statelessly and with some parameters ignored. Compatibility does not extend to OpenAI’s Assistants or embeddings, which are not part of DeepSeek’s API. For a deeper feature-by-feature breakdown, see the DeepSeek API review.
What is the base URL for DeepSeek’s OpenAI-compatible API?
Use https://api.deepseek.com — the base URL DeepSeek’s docs list for the OpenAI format, for both Chat Completions and the Responses API. Beta features like FIM and Chat Prefix Completion use https://api.deepseek.com/beta, and the Anthropic format uses https://api.deepseek.com/anthropic. Authentication and key scoping are covered in DeepSeek API authentication.
Can I keep using deepseek-chat and deepseek-reasoner?
You shouldn’t. Those legacy IDs were scheduled for retirement on 2026-07-24 at 15:59 UTC and are no longer listed in DeepSeek’s documentation; until then they routed to deepseek-v4-flash in non-thinking and thinking mode respectively. Swap the model string to deepseek-flash: thinking is now the default, so add extra_body={"thinking": {"type": "disabled"}} where you used to call deepseek-chat. More on the Flash line is on our DeepSeek V4-Flash page.
Why does my OpenAI code work for DeepSeek chat but not embeddings?
Because DeepSeek’s API has no embeddings endpoint — its reference covers chat, Responses, FIM, models, balance, files and Search & Fetch, but not embeddings or Assistants. If your application needs vector embeddings, run them through a separate provider or a self-hosted model and keep DeepSeek for generation. Code patterns and worked examples are collected in DeepSeek API code examples.
Sources & Methodology
Primary sources
- Official documentationDeepSeek API — Your First API CallOpenAI/Anthropic compatibility statement, base URLs, current model names (fetched 25 Oct 2026)Last checked: October 25, 2026
- Official documentationDeepSeek API — Using the Responses APIResponses API base URL, example, streaming events, unsupported parameters, tools, statelessnessLast checked: October 25, 2026
- Official documentationDeepSeek API — Using the Anthropic APIAnthropic base URL, SDK example, claude-* model mapping, ignored/unsupported fieldsLast checked: October 25, 2026
- Official documentationDeepSeek API — Chat Completions API referenceParameter table: reasoning_effort values and mapping, max_tokens range/defaults, top_logprobs, deprecated penalties, tool_choice limits, stream_optionsLast checked: October 25, 2026
- Official documentationDeepSeek API — Thinking Mode guideThinking default, effort control per format, top_p per model, reasoning_content pass-back ruleLast checked: October 25, 2026
- Official documentationDeepSeek API — Tool Calls guideStrict mode (Beta); mid-conversation tool-call insertion differs by formatLast checked: October 25, 2026
- Official documentationDeepSeek Models & Pricing pageModel versions, vision, concurrency, peak/off-peak prices, legacy-name billingLast checked: October 25, 2026
Technical references
- Technical reportDeepSeek-V3 technical report (arXiv:2412.19437)V3 architecture and training methodologyLast checked: October 25, 2026
Methodology
Pricing figures were checked against the official DeepSeek pricing page and normalised into estimated monthly costs using sample token usage scenarios. Actual costs may vary depending on caching, input/output ratio, regional availability, and provider updates.
Data confidence
High — figures checked directly against the official pricing page on the review date.
Editorial note
The site's pricing dataset is fetched daily from DeepSeek's official pricing page; this article reflects the prices on the date shown above.
