How to Use the OpenAI SDK with DeepSeek in Python and Node.js

Yes, you can use the OpenAI SDK with DeepSeek. Install the official openai client library, authenticate with a DeepSeek API key, point the client to https://api.deepseek.com, and select a current DeepSeek model such as deepseek-flash or deepseek-v4-pro.

The OpenAI SDK is only the client library in this setup. Your requests go to DeepSeek—not OpenAI—because the client uses DeepSeek’s base URL, key, models, billing account, and server behavior. The request format is compatible enough to reuse familiar SDK methods, but DeepSeek is not a feature-for-feature replacement for every OpenAI API capability.

Last reviewed: November 7, 2026.

Quick configuration: use the openai package, set DEEPSEEK_API_KEY, configure Python with base_url="https://api.deepseek.com" or JavaScript with baseURL: "https://api.deepseek.com", and pass a current DeepSeek model ID.

What changes when you point the OpenAI SDK at DeepSeek?

You keep the OpenAI client library and familiar methods, but change the provider-specific configuration.

SettingUse with DeepSeekImportant detail
Client libraryopenaiThe package is maintained by OpenAI, but it can send requests to a compatible custom endpoint.
API keyA key created in the DeepSeek platformDo not use an OpenAI API key or assume a ChatGPT subscription provides DeepSeek credits.
Python optionbase_urlUse snake case in the Python SDK.
JavaScript optionbaseURLUse camel case in the JavaScript and TypeScript SDK.
Base URLhttps://api.deepseek.comPass the API root, not the full /chat/completions path.
General-purpose modeldeepseek-flashDeepSeek currently maps this ID to DeepSeek-V4.1-Flash-1017.
Higher-priced modeldeepseek-v4-proDeepSeek currently maps this ID to DeepSeek-V4-Pro-0813.
BillingDeepSeek account balanceOpenAI and DeepSeek billing remain separate.
Feature behaviorDefined by DeepSeekAn OpenAI-compatible request shape does not guarantee identical tools, parameters, state, or streaming events.

OpenAI also documents separate billing for ChatGPT subscriptions and API usage. Even when the same SDK is used, a ChatGPT Plus subscription does not fund DeepSeek requests, and an OpenAI API balance cannot be used as a DeepSeek balance.

Prerequisites

  • A DeepSeek platform account and API key
  • Available DeepSeek API balance
  • Python 3.10 or later for the current OpenAI Python package
  • Node.js 22 or later for the current OpenAI JavaScript package
  • A server-side environment where the API key can remain secret

The current OpenAI JavaScript SDK also supports TypeScript 4.9 or later, Bun, Deno, and several serverless runtimes. Browser execution is disabled by default because embedding a long-lived API key in client-side code exposes it to users.

Use the OpenAI Python SDK with DeepSeek

1. Install the SDK

python -m pip install --upgrade openai

You can verify the installed SDK version with:

python -c "import openai; print(openai.__version__)"

2. Store your DeepSeek key in an environment variable

On macOS or Linux:

export DEEPSEEK_API_KEY="your_deepseek_api_key"

On Windows PowerShell:

$env:DEEPSEEK_API_KEY="your_deepseek_api_key"

Do not commit the key to Git, place it in a public notebook, or include it in a screenshot.

3. Send a Chat Completions request

Chat Completions is the simplest starting point because it closely resembles older OpenAI SDK integrations and gives you explicit control over the message history.

from __future__ import annotations

import os

from openai import APIError, APITimeoutError, OpenAI

api_key = os.getenv("DEEPSEEK_API_KEY")
if not api_key:
    raise SystemExit("Set the DEEPSEEK_API_KEY environment variable.")

client = OpenAI(
    api_key=api_key,
    base_url="https://api.deepseek.com",
    timeout=60.0,
    max_retries=2,
)

try:
    response = client.chat.completions.create(
        model="deepseek-flash",
        messages=[
            {
                "role": "system",
                "content": "Answer clearly and concisely.",
            },
            {
                "role": "user",
                "content": "Explain what an API client library does.",
            },
        ],
        extra_body={
            "thinking": {
                "type": "disabled",
            }
        },
    )

    print(response.choices[0].message.content or "")

except APITimeoutError as exc:
    raise SystemExit("The DeepSeek request timed out.") from exc

except APIError as exc:
    raise SystemExit(
        f"DeepSeek request failed: {type(exc).__name__}"
    ) from exc

This example disables DeepSeek Thinking Mode deliberately. Thinking is enabled by default in the current models, but a basic non-thinking request is easier to understand, typically returns sooner, and avoids exposing reasoning fields that the application does not need.

What each configuration value does

  • api_key authenticates the request with your DeepSeek account.
  • base_url redirects the OpenAI SDK from OpenAI’s servers to DeepSeek’s API.
  • model identifies the DeepSeek model that should answer the request.
  • timeout prevents the application from waiting indefinitely.
  • max_retries controls the SDK’s built-in retry behavior.
  • extra_body lets the Python SDK send a DeepSeek-specific field that is not part of the standard typed Chat Completions parameters.

Use the OpenAI Node.js SDK with DeepSeek

1. Install the package

npm install openai

The current OpenAI JavaScript SDK supports Node.js 22 and 24 LTS, with Node.js 22 as the minimum supported Node version.

2. Create a server-side request

import OpenAI from "openai";

const apiKey = process.env.DEEPSEEK_API_KEY;

if (!apiKey) {
  throw new Error("Set the DEEPSEEK_API_KEY environment variable.");
}

const client = new OpenAI({
  apiKey,
  baseURL: "https://api.deepseek.com",
  timeout: 60_000,
  maxRetries: 2,
});

try {
  const response = await client.chat.completions.create({
    model: "deepseek-flash",
    messages: [
      {
        role: "system",
        content: "Answer clearly and concisely.",
      },
      {
        role: "user",
        content: "Explain what an API client library does.",
      },
    ],
    thinking: {
      type: "disabled",
    },
  });

  console.log(response.choices[0]?.message?.content ?? "");

} catch (error) {
  if (error instanceof OpenAI.APIError) {
    console.error(
      `DeepSeek request failed with status ${error.status ?? "unknown"}.`
    );
  } else {
    console.error("DeepSeek request failed.");
  }

  process.exitCode = 1;
}

The JavaScript option is baseURL, while Python uses base_url. Using the wrong casing means the custom provider address may not be applied.

Keep this code on a trusted server. Do not place DEEPSEEK_API_KEY in React, Vue, browser JavaScript, or a public mobile bundle. The OpenAI JavaScript SDK disables browser use by default because users can inspect and extract embedded credentials.

Use the API root, not the full endpoint, as the base URL

For the OpenAI SDK, use:

https://api.deepseek.com

Do not configure the client like this:

https://api.deepseek.com/chat/completions

The SDK method adds the resource path. If the full resource path is used as the base URL, the client may construct an invalid duplicated route.

Raw HTTP calls are different. A direct cURL request uses the complete resource URL, such as https://api.deepseek.com/chat/completions. The distinction is between an SDK API root and a raw HTTP endpoint.

Some DeepSeek endpoints, including Search and Fetch, contain /v1/ in their full raw HTTP paths. That does not mean you should append a resource-specific path to the SDK’s documented base URL.

Choose a current DeepSeek model ID

Model IDCurrent model versionInputsGood starting use
deepseek-flashDeepSeek-V4.1-Flash-1017Text and imagesGeneral chat, coding, structured output, vision, and cost-sensitive applications
deepseek-v4-proDeepSeek-V4-Pro-0813TextWorkloads that justify the higher model price or require its supported server-side tools

DeepSeek’s current documentation recommends deepseek-flash for the Flash model. Older names such as deepseek-v4-flash may still be accepted as aliases, but new code should use the current preferred ID rather than copying an old tutorial.

List currently available models through the SDK

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["DEEPSEEK_API_KEY"],
    base_url="https://api.deepseek.com",
    timeout=60.0,
)

models = client.models.list()

for model in models.data:
    print(model.id)

A model appearing in the list does not prove that it supports every feature. Check DeepSeek’s model documentation before assuming that a listed model supports images, server-side web search, Tool Calls, or a particular output format.

Chat Completions or Responses API?

DeepSeek supports both through the OpenAI SDK, but its Responses implementation is only partially compatible with OpenAI’s full Responses feature set.

CapabilityChat CompletionsDeepSeek Responses API
SDK methodclient.chat.completions.create()client.responses.create()
Primary inputmessagesinput and optional instructions
Convenient text outputresponse.choices[0].message.contentresponse.output_text
Conversation stateYour application resends message historyStateless; your application resends the required input history
previous_response_idNot applicableNot supported
Stored responsesNo managed conversation state impliedstore is not supported and remains false
Background modeNot applicable to standard chat callsNot supported
StreamingChat-completion chunksSemantic response events
FunctionsSupportedSupported with a different tool-object shape
Server-side web searchNot a standard Chat Completions built-inSupported with deepseek-v4-pro
Unsupported parametersDepend on the Chat Completions referenceSeveral OpenAI fields are silently ignored
Official DeepSeek Responses API compatibility table showing unsupported conversation state, response storage, and background parameters.

Chat Completions is the safer choice when migrating a conventional messages-based application. Responses is useful when your existing code already uses client.responses.create(), when you need its event model, or when you need a supported Responses-specific capability.

Minimal Responses API example

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["DEEPSEEK_API_KEY"],
    base_url="https://api.deepseek.com",
    timeout=60.0,
    max_retries=2,
)

response = client.responses.create(
    model="deepseek-flash",
    instructions="Answer clearly and concisely.",
    input="Explain the difference between an SDK and an API.",
    reasoning={
        "effort": "none",
    },
)

print(response.output_text)

DeepSeek’s Responses API is stateless. It does not support previous_response_id, conversation, store, or background. If your OpenAI integration depends on those fields, changing only the base URL will not preserve the same behavior.

DeepSeek also documents several unsupported Responses parameters as silently ignored. A successful HTTP response therefore does not prove that every supplied feature was honored.

Stream DeepSeek responses through the OpenAI SDK

Chat Completions streaming in Python

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["DEEPSEEK_API_KEY"],
    base_url="https://api.deepseek.com",
    timeout=60.0,
)

stream = client.chat.completions.create(
    model="deepseek-flash",
    messages=[
        {
            "role": "user",
            "content": "Give me three practical uses for an API client.",
        }
    ],
    stream=True,
    extra_body={
        "thinking": {
            "type": "disabled",
        }
    },
)

for chunk in stream:
    delta = chunk.choices[0].delta

    if delta.content:
        print(delta.content, end="", flush=True)

print()

At the raw wire level, Chat Completions streaming ends with data: [DONE]. The SDK normally abstracts that marker and yields typed chunks.

Responses API streaming in Python

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["DEEPSEEK_API_KEY"],
    base_url="https://api.deepseek.com",
    timeout=60.0,
)

stream = client.responses.create(
    model="deepseek-flash",
    input="Give me three practical uses for an API client.",
    reasoning={
        "effort": "none",
    },
    stream=True,
)

for event in stream:
    if event.type == "response.output_text.delta":
        print(event.delta, end="", flush=True)

    elif event.type == "response.failed":
        raise RuntimeError("The DeepSeek response failed.")

print()

Responses streaming uses semantic events and ends with response.completed, response.incomplete, or response.failed. It does not end with the Chat Completions [DONE] marker. Do not reuse one streaming parser unchanged for both APIs.

Control DeepSeek Thinking Mode

Thinking Mode is enabled by default with a default effort of high. It can improve complex reasoning and coding performance, but it may increase latency and output-token usage.

Enable Thinking Mode in Python Chat Completions

response = client.chat.completions.create(
    model="deepseek-flash",
    messages=[
        {
            "role": "user",
            "content": "Find and explain the bug in this algorithm.",
        }
    ],
    reasoning_effort="high",
    extra_body={
        "thinking": {
            "type": "enabled",
        }
    },
)

reasoning = response.choices[0].message.reasoning_content
answer = response.choices[0].message.content

print(answer)

For Chat Completions in the Python SDK, DeepSeek documents the provider-specific thinking field inside extra_body. The standard reasoning_effort field controls the requested effort level.

In Thinking Mode, temperature, presence_penalty, and frequency_penalty have no effect. DeepSeek accepts them for compatibility rather than rejecting the request.

When Tool Calls are included in a multi-turn Chat Completions workflow, preserve the full assistant messages, including reasoning_content. Removing that history can cause a 400 error on the next request.

Do not assume that reasoning text is appropriate to store permanently. It may contain sensitive intermediate content, so apply the same access, retention, and redaction controls used for prompts and final outputs.

Request JSON output

DeepSeek supports JSON Output through the OpenAI-compatible Chat Completions method.

import json
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["DEEPSEEK_API_KEY"],
    base_url="https://api.deepseek.com",
    timeout=60.0,
)

response = client.chat.completions.create(
    model="deepseek-flash",
    messages=[
        {
            "role": "system",
            "content": (
                "Return valid JSON with two fields: "
                "\"topic\" and \"summary\"."
            ),
        },
        {
            "role": "user",
            "content": "Summarize what an API client library does.",
        },
    ],
    response_format={
        "type": "json_object",
    },
    max_tokens=500,
    extra_body={
        "thinking": {
            "type": "disabled",
        }
    },
)

content = response.choices[0].message.content or ""

if not content.strip():
    raise RuntimeError("DeepSeek returned blank JSON content.")

data = json.loads(content)

print(data["topic"])
print(data["summary"])

DeepSeek requires the prompt to explicitly request JSON. It also warns that content the API cannot recognize as JSON may be replaced with spaces, causing an apparently empty response even when the finish reason is stop. Always strip, parse, validate, and handle blank output.

Valid JSON does not guarantee factual accuracy or compliance with your business rules. Validate required fields, types, ranges, ownership, and permissions in application code.

Use Tool Calls without assuming the model executes functions

DeepSeek supports function tools through the OpenAI SDK. The model can request a tool name and arguments, but your application must validate, authorize, and execute the function before returning a result.

  1. Define an allowlisted function and JSON Schema.
  2. Send the tool definitions with the user request.
  3. Inspect message.tool_calls.
  4. Parse the arguments defensively.
  5. Reject unknown functions or unauthorized operations.
  6. Execute the approved local handler.
  7. Return a role: "tool" message with the matching tool_call_id.
  8. Continue until DeepSeek returns a final answer or the application reaches a safe round limit.

Tool arguments can contain invalid JSON or fields that were not declared. Never use eval, dynamically import a model-generated function name, or treat a valid schema as authorization for a payment, deletion, message, or database update.

If your application needs a complete production-oriented Tool Calls implementation, review DeepSeek’s official Tool Calls documentation separately rather than reducing the workflow to a few incomplete lines.

Send images through the OpenAI-compatible API

The current deepseek-flash model supports image input. DeepSeek documents JPEG, PNG, GIF, and WebP images supplied through supported URL, base64, or Files API patterns.

Do not assume that deepseek-v4-pro supports images, and do not infer that PDF, DOCX, or other generic document inputs are supported merely because image input works.

For sensitive images, avoid public URLs and review the relevant data-handling requirements before uploading content to any hosted AI service.

Understand retries and timeouts before adding your own retry loop

The current OpenAI Python and JavaScript SDKs automatically retry certain transient failures twice by default using a short exponential backoff. Retried conditions include connection failures, HTTP 408, 409, 429, and server errors at or above 500 when the request body can be safely resent.

The default SDK timeout is currently 10 minutes. That may be too long for an interactive application, so the examples in this guide use 60 seconds.

Be careful when adding application-level retries. If the SDK performs two retries and your outer loop also retries the operation, one user action can produce substantially more requests than expected.

  • Do not retry authentication failures without correcting the key.
  • Do not retry insufficient-balance errors without adding funds.
  • Do not retry invalid request formats or parameters unchanged.
  • Use bounded backoff for rate limits and temporary server failures.
  • Use idempotency protections when a request can trigger an external side effect.
  • Record request IDs and safe diagnostic details without logging prompts, secrets, or confidential outputs unnecessarily.

Common DeepSeek OpenAI SDK errors

Status or symptomLikely causeWhat to checkRetry unchanged?
400Invalid request-body formatEndpoint shape, unsupported fields, Thinking configuration, response format, and message structureNo
401Authentication failedConfirm that the key is a valid DeepSeek key and that the environment variable is loadedNo
402Insufficient DeepSeek balanceCheck the account balance and billing configurationNo
422Invalid parameterModel ID, field names, ranges, and unsupported valuesNo
429Rate or concurrency limitRequest pace, concurrent requests, SDK retries, and account limitsAfter slowing down
500DeepSeek server errorService status, request ID, and bounded retry policyUsually after a pause
503DeepSeek server overloadCurrent status and traffic conditionsUsually with backoff
Model not foundOutdated or misspelled IDModels and Pricing page, changelog, or client.models.list()No
Blank JSON contentThe output was not recognized as JSON and was replaced with spacesPrompt wording, JSON example, output limit, and local blank-content handlingAfter correcting the prompt
Missing or duplicated pathThe full endpoint was used as the SDK base URLUse https://api.deepseek.com as the client base URLNo
Feature appears to do nothingA Responses parameter may be silently ignoredDeepSeek’s compatibility table for the exact fieldNo

Do not expose a DeepSeek key in browser code

The OpenAI JavaScript SDK blocks browser use by default because credentials embedded in client-side code can be extracted. Setting dangerouslyAllowBrowser: true does not make a long-lived DeepSeek key safe.

For a web application, use this architecture:

  1. The browser sends an authenticated request to your own backend.
  2. Your backend validates the user and the requested operation.
  3. Your server loads the DeepSeek key from a secret store.
  4. Your server calls DeepSeek.
  5. Your server returns only the necessary result to the browser.

Rate-limit the backend route, validate input length, restrict allowed models and features, enforce spending limits, and do not let the browser supply an arbitrary provider URL.

Migration checklist for an existing OpenAI SDK application

  1. Create a DeepSeek key. Keep it separate from your OpenAI credentials.
  2. Add provider-specific environment variables. Do not overload one variable with keys from multiple providers.
  3. Change the base URL. Use the DeepSeek API root in the SDK client.
  4. Change the model ID. Select a current DeepSeek model rather than an OpenAI model or historical alias.
  5. Audit request parameters. Identify fields that DeepSeek supports, ignores, or handles differently.
  6. Audit response parsing. Confirm the text, reasoning, usage, tool, and streaming fields your code reads.
  7. Test Chat Completions. Verify system instructions, message history, output limits, and error handling.
  8. Test Responses separately. Do not assume stateful OpenAI features such as previous_response_id work.
  9. Test Thinking Mode. Measure latency, token usage, output quality, and history handling.
  10. Test streaming. Use a parser that matches the chosen API format.
  11. Test JSON Output. Handle blank or truncated content and validate the decoded object.
  12. Test Tool Calls. Validate arguments, preserve call IDs, and enforce authorization.
  13. Test images if used. Confirm the model, format, size, and content-block shape.
  14. Review retries. Avoid multiplying automatic SDK retries with an unlimited application loop.
  15. Run regression tests. Use representative prompts and compare accepted-result quality, latency, and cost.
  16. Keep rollback available. Do not remove the previous provider until the DeepSeek path is proven for your workload.

Use separate clients when supporting OpenAI and DeepSeek together

A multi-provider application should normally create separate client instances instead of mutating one global client between requests.

import os
from openai import OpenAI

openai_client = OpenAI(
    api_key=os.environ["OPENAI_API_KEY"],
)

deepseek_client = OpenAI(
    api_key=os.environ["DEEPSEEK_API_KEY"],
    base_url="https://api.deepseek.com",
)

# Use the appropriate client and model explicitly.
deepseek_response = deepseek_client.chat.completions.create(
    model="deepseek-flash",
    messages=[
        {
            "role": "user",
            "content": "Summarize this technical note.",
        }
    ],
    extra_body={
        "thinking": {
            "type": "disabled",
        }
    },
)

Keep provider-specific feature flags for Thinking Mode, image input, tools, streaming, and Responses behavior. A shared application interface can reduce duplicated code, but it should not silently discard unsupported fields.

Track token usage and cache behavior

DeepSeek returns usage information with API responses. Treat the API response as the source of truth for billing rather than estimating tokens from character counts.

Depending on the API format, useful fields can include:

  • Input or prompt tokens
  • Output or completion tokens
  • Reasoning tokens
  • Cached input tokens
  • prompt_cache_hit_tokens
  • prompt_cache_miss_tokens
  • Successful server-side search or fetch usage

DeepSeek applies context caching automatically on a best-effort basis. A repeated prefix may reduce billed input cost, but a cache hit is not guaranteed. Log usage totals and accepted-result cost rather than assuming every repeated prompt will receive the cached rate.

Production checklist

  • Use current OpenAI SDK releases on supported Python or Node.js versions.
  • Store DeepSeek keys in a managed secret store or server environment variable.
  • Use the official DeepSeek base URL.
  • Use current model IDs and record model versions where reproducibility matters.
  • Set explicit timeouts and bounded retry policies.
  • Log request IDs and safe error metadata.
  • Do not log credentials, confidential prompts, or sensitive reasoning content.
  • Validate all structured output locally.
  • Authorize every tool operation in application code.
  • Rate-limit public backend routes.
  • Enforce token, request, concurrency, and spending budgets.
  • Test provider-specific streaming and response fields.
  • Monitor DeepSeek’s status, changelog, models, and pricing documentation.
  • Keep regression tests for every feature your application relies on.

Frequently asked questions

Can I use the OpenAI SDK with DeepSeek?

Yes. Configure the OpenAI client with a DeepSeek API key, DeepSeek’s official base URL, and a current DeepSeek model ID. The SDK then sends requests to DeepSeek.

Does using the OpenAI SDK send my prompts to OpenAI?

Not when the client is configured with DeepSeek’s base URL. The SDK constructs requests, but the configured endpoint determines which provider receives them. Review any additional proxies, gateways, logging systems, or observability services in your application separately.

Do I need an OpenAI API key?

No. You need a DeepSeek API key for DeepSeek requests. An OpenAI key is needed only for requests sent to OpenAI.

Does ChatGPT Plus include DeepSeek API usage?

No. ChatGPT subscriptions, OpenAI API billing, and DeepSeek API billing are separate products and accounts.

What base URL should I use?

Use https://api.deepseek.com as the OpenAI SDK base URL. Do not pass the complete /chat/completions resource path as the client’s base URL.

What is the difference between base_url and baseURL?

base_url is the Python client option. baseURL is the JavaScript and TypeScript client option.

Is DeepSeek a drop-in replacement for OpenAI?

Not completely. Basic OpenAI-compatible requests may require only configuration changes, but model IDs, Thinking Mode, Responses state, built-in tools, unsupported parameters, streaming events, errors, and response fields can differ.

Should I use Chat Completions or Responses?

Use Chat Completions for the simplest migration from a messages-based integration. Use Responses when your application specifically needs its input, output, tool, or event structure and can accommodate DeepSeek’s stateless and partially compatible implementation.

Why did a Responses parameter have no effect?

DeepSeek silently ignores several unsupported OpenAI Responses parameters. Check DeepSeek’s current compatibility table instead of treating an HTTP 200 response as proof that every field was applied.

Does the OpenAI SDK retry DeepSeek requests automatically?

Yes. The current Python and JavaScript SDKs retry certain transient failures twice by default. Configure the retry count deliberately and avoid stacking it beneath an unbounded application retry loop.

Can I call DeepSeek directly from React?

Do not place a long-lived DeepSeek API key in public browser code. Send requests through a server-side route that stores the key securely, authenticates users, validates input, applies rate limits, and controls spending.

Sources checked