Using DeepSeek With the OpenAI SDK: A Compatibility Guide

DeepSeek OpenAI compatibility: swap base_url and reuse OpenAI SDKs with deepseek-flash or deepseek-v4-pro. Code, parameters, Responses and Anthropic formats.

API·April 25, 2026·By DS Guide Editorial
DeepSeek OpenAI compatibility title card: eyebrow 'API · OpenAI compatibility', title 'OpenAI Compatibility', tagline 'Swap base_url and key; keep your OpenAI SDK code.', and four stats: 2 values to change, 3 API formats, Flash default model, and High default effort, beside a punch-card illustration.

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

Title card: eyebrow 'Base URLs · One key', title 'Three API Formats', tagline 'api.deepseek.com serves all three; one DeepSeek key.', and four stats: Chat Completions on the same base URL, Responses API on the same base URL, Anthropic format on the /anthropic path, and Beta features such as FIM on /beta, beside a mainframe illustration.

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.com
  • api_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.create works with deepseek-flash and deepseek-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 accepts reasoning_effort="none" to switch thinking off.)
  • Thinking: reasoning_effort="low" or "high" plus extra_body={"thinking": {"type": "enabled"}}. For compatibility, minimal is mapped to low, and medium and xhigh to high.
  • Thinking-max: reasoning_effort="max" (ultra maps here too). max_tokens defaults 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_penalty or frequency_penalty; for compatibility, setting them triggers no error but has no effect. top_p depends on the model: on deepseek-flash it only takes effect in thinking mode (effective range 0.95–1.0); on deepseek-v4-pro it is ignored in thinking mode and takes effect in non-thinking mode.
  • When a request carries tools, you must pass back the reasoning_content of all previous turns — even turns without a tool call — or the API returns a 400. Without tools, 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:

  1. Include the word json in your prompt and a small example schema.
  2. Set max_tokens high enough that the JSON cannot be truncated.
  3. Handle the case where content comes 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 Balance means your account has run out of balance. Top up before integration testing.
  • 422 Invalid Parameters and 400 Invalid Format carry hints in the error message — for example, stream_options without stream: true, or tool_choice="required" in thinking mode, return a 400.
  • 429 Rate Limit Reached fires when you send requests too quickly or exceed the per-account concurrency limit (2,500 for deepseek-flash, 500 for deepseek-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

Title card: eyebrow 'Migration · Model IDs', title 'Swap the Model ID', tagline 'Old IDs out: set model, keep base_url and key.', and four stats: Flash, deepseek-flash; Pro, deepseek-v4-pro; same base_url; and 1 line to change, beside a compact-desktop illustration.

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.create natively, but statelessly: previous_response_id, conversation, store, background, prompt_cache_key and several other parameters are not supported, and unsupported parameters are silently ignored rather than rejected. Tools are limited to function, the apply_patch custom tool and web_search (with deepseek-v4-pro only); reasoning.summary is 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. temperature defaults 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/anthropic rather than rewriting it. DeepSeek maps model names that start with claude-opus to deepseek-v4-pro and other claude names to deepseek-flash; thinking.budget_tokens, top_k and cache_control are ignored, and document content 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

  1. Get a key and top up your balance — calls fail with 402 when it runs out.
  2. Change base_url to https://api.deepseek.com (or https://api.deepseek.com/anthropic for the Anthropic SDK) and replace the API key.
  3. Replace OpenAI model strings with deepseek-flash (default) or deepseek-v4-pro.
  4. If you still have deepseek-chat, deepseek-reasoner or deepseek-v4-flash in your code, switch to deepseek-flash — the first two were scheduled for retirement on 2026-07-24 at 15:59 UTC.
  5. 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.
  6. Keep your retry/backoff layer; DeepSeek’s error codes match the OpenAI shape closely enough that existing handlers usually port over unchanged.
  7. 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

Last source check: October 25, 2026

Primary sources

Technical references

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.

Leave a Reply

Your email address will not be published. Required fields are marked *