· ·Sources
Ask the internet how to call the DeepSeek API and most answers hand you a new SDK, a wrapper library, or a tutorial written for someone else's stack. None of it is needed. If you have ever used the OpenAI SDK, you already know how to call DeepSeek V4: the protocol is the same — it speaks the Anthropic dialect too — and the whole port is two strings, a base_url and a model ID. But the two strings are the easy part. This is the three-minute setup plus the three behaviors the quickstart buries in footnotes: your old code starts thinking the moment it points at V4, some of your tuning parameters stop existing without telling you, and the model ID you ship is a pointer, not a promise.
base_url at https://api.deepseek.com (bare domain — no /v1 anywhere in the current quickstart), put deepseek-v4-flash or deepseek-v4-pro in model, and a standard OpenAI-SDK script runs unchanged.high. A naive port reasons before every single answer. That may be exactly what you want; if it isn't, the off switch is extra_body={"thinking": {"type": "disabled"}}. Section 3 has the full dial.temperature, top_p and the two penalty parameters are silently ignored — accepted without error, no effect on output. Your tuning knob isn't turned down; it isn't connected.Assuming Python and a key from platform.deepseek.com in your environment:
pip install openai
from openai import OpenAI
import os
client = OpenAI(
api_key=os.environ["DEEPSEEK_API_KEY"],
base_url="https://api.deepseek.com", # line 1
)
resp = client.chat.completions.create(
model="deepseek-v4-flash", # line 2
messages=[{"role": "user", "content": "Say hi in five words."}],
)
print(resp.choices[0].message.content)
The official quickstart's own example uses deepseek-v4-pro; both strings come from the same model list, and Flash is the cheaper tier — a hello-world neither needs nor deserves more. One thing to know before you run it: this five-word greeting will be reasoned about first. That is not a bug; it is the default, and section 3 is about owning it.
stream = client.chat.completions.create(
model="deepseek-v4-flash",
messages=[{"role": "user", "content": "Explain undated model IDs in one paragraph."}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="")
The quickstart says it plainly: the examples are non-streaming, set stream=true for streaming. With thinking on — remember, that's the default — the chain-of-thought streams in ahead of the answer, every time.
If you are porting from the V3 era, the mental model changed: the current model list has no separate reasoner — reasoning moved into a request parameter. The docs' footnote is the part worth reading twice: thinking mode is enabled by default, with the default effort being high. So the two-line port above doesn't just call a model; it calls a model that thinks hard on every call, including the ones that don't deserve it.
# plain chat, no reasoning — the explicit off switch
resp = client.chat.completions.create(
model="deepseek-v4-flash",
messages=[{"role": "user", "content": "Rewrite this so a beginner gets it."}],
extra_body={"thinking": {"type": "disabled"}},
)
# full reasoning, maximum effort — when the task earns it
resp = client.chat.completions.create(
model="deepseek-v4-pro",
messages=[{"role": "user", "content": "Plan a migration, then defend the plan."}],
reasoning_effort="max", # top-level, as in the official sample
extra_body={"thinking": {"type": "enabled"}},
)
print(resp.choices[0].message.content) # the answer — the reasoning rode along in the response
Two behaviors from the docs that most tutorials skip:
low, high, max. The official table maps every accepted spelling onto one of the three, identically on Flash and Pro.temperature, top_p, presence_penalty, frequency_penalty — accepted, no error, no effect. If your port "works" but ignores your temperature, now you know: it isn't a bug in your code, it's the mode.One more thing the response hands you: the reasoning itself, alongside the answer. What happens to it on the next turn depends on whether tools are in play — see section 5, because one branch of that rule throws a 400.
deepseek-v4-flash is not frozen. The quickstart's footnote: the model "has been updated to DeepSeek-V4-Flash-0731" (and Pro to -0813), and the calling method remains unchanged — the same string serves the latest version. Good for staying current; the opposite of good for anything you measure: an eval suite that passed on Monday can drift by Friday because the pointer moved, and your git history shows no diff — the change wasn't yours.
The docs don't show a pinning mechanism, so the honest playbook is bookkeeping: log the model version from each response alongside your outputs, and treat the footnote on the model page as a changelog that re-baselines your evals. Thirty seconds of discipline buys you a real answer to "did my code get worse, or did the model change". (There's also an experimental deepseek-v4-flash-vision-exp that takes images — it's out of scope for a three-minute setup.) Which tier the string should name is a workload question, not a setup question: Flash vs Pro decision rules.
Tool calling is supported inside thinking mode, and the model can alternate reasoning and tool calls across several sub-turns before the final answer. The convenience is real: each response comes back as one message object carrying the reasoning, the answer and any tool calls together — so appending that whole object back into your history is all the bookkeeping a turn needs.
The rule that bites: if the request carries tools, the reasoning from all previous turns must go back too — the API stitches it into context, and dropping it returns a 400. Without tools, the opposite: old reasoning is ignored rather than stitched in, so you needn't carry it at all. One parameter in the request, two opposite rules. That asymmetry is the single most likely thing to break a copied-from-OpenAI agent loop, and the error message won't explain it.
The hello-world above costs a rounding error. What moves a DeepSeek bill is never the first call; it is three decisions made later: whether every call needs to think (the default says yes — if your workload is mostly rewrite-and-format, the disabled switch is the cheapest knob on this page), which tier runs the workload (tier choice), whether it can run at discounted hours (official off-peak discount), and which provider hosts the same model cheapest today (our comparison). We link those instead of pasting numbers here, because prices move and this page's job is the setup.
https://api.deepseek.com/anthropic) exists on the same page for exactly that crowd.
No. The docs define the API as OpenAI/Anthropic-format compatible and the official examples use the OpenAI SDK. A wrapper library buys you nothing this page doesn't do with two strings and one extra_body.
Yes — same two strings, camelCase spelling: new OpenAI({ apiKey, baseURL: "https://api.deepseek.com" }). The thinking fields ride the same request body exactly as the official curl shows them.
extra_body={"thinking": {"type": "disabled"}}. Don't just lower the effort — the dial's floor is low, not zero.
Almost certainly the reasoning pass-back rule: with tools present, the reasoning from every previous turn must be sent back intact. Appending the full returned message object per turn satisfies it automatically; hand-rolled message dicts that strip the reasoning out don't.
The current docs show no pinning — the footnote explicitly says the same string serves the latest snapshot (Flash-0731, Pro-0813 at writing time). Log the model version from each response and watch that footnote; if a dated pinning option ever appears on the model page, use it for anything with tests.
Partially, and labelled: the Novita link is a ref link (commission to us, disclosed, sponsored-tagged per Google's rules). It sits behind no claim on this page — the setup steps work identically without clicking it, and the official platform link above is not a ref link.
Every protocol claim on this page traces to these, checked 7 Sep 2026:
extra_body passthrough is its documented mechanism for provider-specific fields.One honesty note, in keeping with how this site reports: this is a setup guide built from three official documentation pages as they stood on 7 Sep 2026. It is not a benchmark and not a first-hand evaluation; nothing above measures latency, quality, or uptime, and no number appears here that wasn't taken from a source above. Model strings, snapshots, defaults, and prices move; treat the linked pages as the live truth. And if a future update ever changes the protocol itself, this page gets a dated correction, not a silent rewrite.
Transparency: links marked ref link are affiliate links — we may earn a commission if you sign up, at no extra cost to you. This never affects the comparison: the cheapest option is highlighted in green regardless of who pays us. Verify current rates before committing spend.