Qoder (international) as an OpenAI-compatible API — deploy as a single Cloudflare Worker or run the Python Flask server locally/on any box. 3 files per runtime, zero crypto dependencies, one device-flow login.
An implementation of the Qoder COSY protocol, based on the reverse-engineered client in RobbsLuo/Coding2API (MIT).
| Cloudflare Worker | Python (Flask) | |
|---|---|---|
| Files | worker.js + cosy.js + rsa-pkcs1.js |
server.py + cosy.py |
| Runtime | edge, no server | local machine, VPS, Docker, systemd… |
| Credential | QODER_CREDENTIAL secret |
QODER_CREDENTIAL env or ./credential.json |
| Crypto | WebCrypto + pure-JS RSA | stdlib (hashlib, pure-Python AES + RSA) |
| Install | npx wrangler deploy |
pip install -r requirements.txt |
Both expose the identical endpoints and wire format. The Python port is byte-for-byte cross-validated against the Worker's COSY implementation (custom base64, MD5 signatures, SPKI/RSA key wrap, AES identity envelope — including WebCrypto's double-pad behavior).
kimi-k3 · glm-5.3 · deepseek-v4.1-flash · deepseek-v4-pro · minimax-m3 ·
kimi-k2.8-preview · qwen3.7-max · qwen3.7-plus · qwen3.8-max ·
auto · efficient · performance · ultimate · sonus · cantus
GET /v1/models returns the live list (credit rate, context, modality
flags included).
# 1. login — prints a credential JSON (device flow; token never touches a browser)
pip install httpx
python3 qoder_oauth.py --testnpx wrangler login
npx wrangler deploy
wrangler secret put QODER_CREDENTIAL # paste the credential JSON
wrangler secret put API_KEY # your client-facing key (optional lock)Or use the deploy button above, then set the two secrets in the dashboard.
pip install -r requirements.txt # flask + httpx
export QODER_CREDENTIAL='<credential JSON from qoder_oauth.py>'
# — or save it once: echo '<credential JSON>' > credential.json
export API_KEY='my-secret-key' # optional client-facing lock
python3 server.py # serves on 0.0.0.0:8080 (PORT/HOST to override)
# test
curl http://localhost:8080/v1/chat/completions \
-H "Authorization: Bearer my-secret-key" -H "Content-Type: application/json" \
-d '{"model":"kimi-k3","messages":[{"role":"user","content":"hi"}]}'Production options:
gunicorn -w 1 -b 0.0.0.0:8080 server:app # WSGI (keep 1 worker: in-memory state)
flask --app server run --host 0.0.0.0 --port 8080 # dev serverA Dockerfile is included: docker build -t qoder2api . && docker run -p 8080:8080 -e QODER_CREDENTIAL='...' qoder2api.
GET /v1/models live model catalog (credit rate, context, flags)
POST /v1/chat/completions OpenAI wire (stream + non-stream, tools)
GET /health
| File | What it is |
|---|---|
worker.js |
Worker routes, OpenAI wire, SSE envelope decode, streaming |
cosy.js |
the COSY protocol (JS): custom base64 wire encoding, MD5 request signatures, device fingerprints, AES-128-CBC identity envelope, session material |
rsa-pkcs1.js |
RSAES-PKCS#1-v1_5 in pure BigInt modexp (WebCrypto omits v1.5 encryption; the protocol requires it) — DER SPKI parser included |
server.py |
Flask routes, OpenAI wire, SSE envelope decode, streaming (same behavior as worker.js) |
cosy.py |
the COSY protocol (Python, stdlib-only crypto): same custom base64 / MD5 signatures / fingerprints / AES envelope / RSA wrap as cosy.js |
qoder_oauth.py |
standalone device-flow login → prints the credential JSON (--test verifies quota) |
Protocol notes: session keys are wrapped with the server's RSA public key;
identity JSON is AES-128-CBC encrypted with the session key doubling as the
IV; every request is MD5-signed over payload · cosy_key · date · body · path. Nothing is stored server-side — both runtimes derive everything from
your credential per request.
Implementation quirk preserved in
cosy.py: WebCrypto's AES-CBC encrypt always appends its own PKCS#7 pad block (even to aligned input), so the Worker's identity envelope is double-padded — upstream decrypts exactly that, and the Python port reproduces it byte-for-byte.
Qoder credentials last ~30 days and the token refreshes on the server side
during normal use — a deployment just uses the access token until it
expires. When chat starts returning auth errors, re-run qoder_oauth.py
and update the QODER_CREDENTIAL secret (Workers) or env/credential.json
(Python).
Self-hosting the full multi-channel engine (CodeBuddy, TRAE, CodeArts, check-ins, quota dashboards) instead? Use the upstream RobbsLuo/Coding2API — our QODER-SETUP.md documents the intl-channel gotchas we hit (dual endpoint env vars, login-before-restart trap) which apply there too.
MIT — COSY protocol reverse-engineering © Hongsheng Luo (Robbs); Worker port, Python port, auth script and docs © nullstacks. See LICENSE + NOTICE.