Turn chat.deepseek.com into an OpenAI-compatible API.
A lightweight, dependency-free Go proxy that speaks the OpenAI Chat Completions protocol.
deepseek2api wraps the chat.deepseek.com web app behind a clean,
OpenAI-compatible HTTP API. It is written in pure Go using only the standard
library, so it ships as a single static binary with no runtime dependencies.
Point any OpenAI client at it — Cherry Studio, LobeChat, Open WebUI, the
official OpenAI SDKs, curl — and talk to DeepSeek without an official API key.
Bring your own account. You supply the web
userTokenfrom your own logged-in browser session. The proxy never phones home.
- OpenAI Chat Completions compatible —
POST /v1/chat/completions, streaming and non-streaming. - Model listing —
GET /v1/models. - Image input —
image_urlcontent blocks accept base64 data URLs and http(s) links; images are uploaded to DeepSeek and sent asref_file_ids. - Automatic proof-of-work — the server solves the web client's DeepSeekHashV1 challenge (a 23-round Keccak variant) in parallel, typically under 100 ms.
- Reasoning support — thinking output is mapped to
reasoning_content, matching the official DeepSeek API. - Multi-account token pool — round-robin across accounts; tokens stay server-side.
- Multi-turn context — automatic prefix caching reuses a DeepSeek session; an explicit
conversation_idpassthrough is also supported. - Future-proof model names — unknown
deepseek-*ids are mapped heuristically (reasoner/think/search keywords), so clients that hardcode newer names keep working. - Self-cleaning — idle sessions are deleted upstream so your web chat list stays tidy.
- Docker / Docker Compose ready.
| Model ID | Web behavior | Aliases |
|---|---|---|
deepseek-chat |
Fast mode | deepseek-v3 |
deepseek-reasoner |
Fast mode + deep thinking | deepseek-r1 |
deepseek-search |
Fast mode + web search | |
deepseek-reasoner-search |
Deep thinking + web search |
-
Log in to chat.deepseek.com in your browser.
-
Open DevTools (F12) → Console and run:
JSON.parse(localStorage.userToken).value
-
Copy the output. It stays valid until you sign out; repeat for extra accounts.
go build -o deepseek2api .Single account:
PROXY_API_KEY='your-proxy-key' DEEPSEEK_TOKEN='your-token' PORT=8080 ./deepseek2apiMultiple accounts: create accounts.txt in the working directory, one token per
line (blank lines and # comments are ignored):
eyJhbGciOi...token1
eyJhbGciOi...token2
PROXY_API_KEY='your-proxy-key' ./deepseek2apicurl http://127.0.0.1:8080/v1/chat/completions \
-H 'Authorization: Bearer your-proxy-key' \
-H 'Content-Type: application/json' \
-d '{
"model": "deepseek-reasoner",
"messages": [{"role": "user", "content": "Hello"}],
"stream": true
}'docker build -t deepseek2api .
docker run --rm -p 8080:8080 \
-e PROXY_API_KEY='your-proxy-key' \
-e DEEPSEEK_TOKEN='your-token' \
deepseek2apiOr with Compose:
PROXY_API_KEY='your-proxy-key' DEEPSEEK_TOKEN='your-token' docker compose up --build| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
Local HTTP port |
PROXY_API_KEY |
none — required | Key clients use to call the proxy |
DEEPSEEK_TOKEN |
empty | DeepSeek web userToken |
DEEPSEEK_ACCOUNTS_FILE |
accounts.txt |
Multi-account file, one token per line |
DEEPSEEK_BASE_URL |
https://chat.deepseek.com |
Upstream base URL |
DEFAULT_MODEL |
deepseek-chat |
Model used when a request omits one |
CONVERSATION_TTL |
30m |
Idle time before a session is deleted upstream |
MAX_CONVERSATIONS |
1024 |
Max sessions kept in memory (LRU eviction) |
- Automatic mode (recommended). Clients send the full
messagesarray as usual. The proxy fingerprints the history (everything except the last message); on a hit it reuses the same DeepSeek session and sends only the new turn, otherwise it creates a fresh session. Mainstream clients work with no changes. - Passthrough mode. Responses include a non-standard
conversation_idfield (the DeepSeek session id). Send it in a later request body to reuse that session; only the last user message is used as the prompt.
Cold start note: after a restart, if the history has more than one turn, only the system prompt and the latest user message are replayed. This is a deliberate simplification.
Every /v1/* request needs:
Authorization: Bearer <PROXY_API_KEY>DEEPSEEK_TOKEN / accounts.txt are used server-side only and are never
exposed to callers.
- Images: ≤ 20 MB each, up to 8 per request, png/jpg/webp/gif/bmp. Only the last user message's images are processed; older ones already live in the upstream session. Vision requests add a few seconds of first-token latency.
- Usage is estimated: totals come from the upstream session's cumulative token delta, and the split is approximated by character count.
- Upstream
429maps to429; an invalid token maps to401. - Do not commit your tokens.
accounts.txtis already in.gitignore.
main.go HTTP server and routing
config/ environment configuration
handlers/ OpenAI-compatible handlers, SSE, image upload
deepseek/ upstream client, proof-of-work, streaming
docs/api-analysis.md reverse-engineering notes on the upstream API
assets/ logo and banner
Released under the MIT License.