Skip to content
XYW110Public

About

Qoder2api demo via nodejs

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Qoder2API

q

A Node.js HTTP bridge that exposes the Qoder AI coding assistant API as an OpenAI-compatible /v1/chat/completions endpoint. It accepts requests in OpenAI, Anthropic Claude, and Google Gemini formats, translates them to Qoder's internal API, and streams responses back in the caller's native SSE format.

Features

  • OpenAI Compatible — Drop-in replacement for any OpenAI SDK client
  • Multi-Format Support — Works with OpenAI, Claude (Anthropic), and Gemini clients simultaneously
  • Dynamic Model Catalog — Fetches the full Qoder model catalog in real-time (Qwen, DeepSeek, GLM, Kimi, MiniMax, etc.), not limited to a single model
  • Account Info API — Query plan, quota, and session status via /v1/user/status and /v1/user/quota
  • Streaming — Full SSE streaming support for all three API formats
  • Tool Calls — Handles both structured tool calls and text-based tool call fallback parsing
  • API Key Auth — Optional Bearer token authentication for production deployments
  • Proxy Support — HTTP CONNECT and SOCKS5 proxy support (no external dependencies)
  • Docker Ready — Multi-arch Docker images published to GitHub Container Registry

Supported API Formats

Format Endpoints
OpenAI /v1/chat/completions, /v1/models, /v1/completions, /v1/responses, /v1/messages, /v1/user/status, /v1/user/quota
OpenAI Prefix /openai/v1/chat/completions, /openai/v1/models
Claude /claude/v1/messages, /v1/messages (Anthropic Messages API)
Gemini /gemini/v1beta/models, /gemini/v1beta/models/{model}:generateContent, /gemini/v1beta/models/{model}:streamGenerateContent

Supported Models

Models are fetched dynamically from the Qoder API at runtime. GET /v1/models returns the chat-scene catalog only (other Qoder scenes — quest, nap, qwork, experts, qwake, assistant, inline — use different API surfaces that this bridge does not implement). Each entry carries metadata the frontend can use to render the model picker:

Field Meaning
id Internal key used as the model parameter (e.g. qmodel_latest)
display_name Human-readable name (e.g. Qwen3.7-Max)
enable true if the caller's plan can use this model right now
is_free true if the model is free-tier (available to PLAN_TIER_FREE)
is_default true if this is the default chat model
is_new true if the model is flagged as new in the catalog
is_reasoning / is_vl Reasoning and vision capabilities
architecture OpenRouter-style modality hint; input_modalities includes "image" for vision (is_vl) models
price_factor Current price factor (may be discounted; original_price_factor is included when different)
max_input_tokens Maximum input context size
context_config Available context window options (when the model supports switching)
thinking_config Available thinking/effort options (when the model supports it)

Image input (vision): all vision (is_vl) models accept images. Send them the usual way for each API — OpenAI image_url parts, Claude image blocks (base64 or url), or Gemini inlineData — and the bridge forwards them to the model as image_url content (base64 data-URIs work; no upload step needed).

The catalog includes models such as:

Model Key Reasoning Vision Notes
Qwen3.7-Max qmodel_latest - Y Default, free-tier
Qwen3.7-Plus qmodel Y Y
DeepSeek-V4-Pro dmodel Y Y
DeepSeek-V4-Flash dfmodel Y Y
GLM-5.1 gm51model Y Y
Kimi-K2.6 kmodel - Y
MiniMax-M3 mmodel - Y
Ultimate ultimate Y Y Premium tier
Performance performance Y Y Premium tier
Efficient efficient - Y Low cost

Note: Model availability depends on your Qoder plan. Free-tier accounts (PLAN_TIER_FREE) see only Qwen3.7-Max with enable=true; every other model has enable=false. Use GET /v1/user/status to check your plan and GET /v1/models to see which models are enabled for your account.

Use the model key (e.g. qmodel_latest, dmodel) or display name (e.g. Qwen3.7-Max, DeepSeek-V4-Pro) as the model parameter in chat requests.

Quick Start

Prerequisites

  • Node.js >= 18
  • A Qoder personal access token (QODER_PAT)

Install & Run

# Clone the repository
git clone https://github.com/emptysuns/qoder2api.git
cd qoder2api

# Install dependencies
npm install

# Run
QODER_PAT=your_token npm start

The server starts on http://127.0.0.1:8963 by default.

Development

# Auto-restart on file changes
QODER_PAT=your_token npm run dev

Configuration

Environment Variables

Variable Required Default Description
QODER_PAT Yes — Qoder personal access token(s). Supports comma-separated multiple tokens for round-robin load balancing (e.g. token1,token2,token3).
API_KEY No — API key for Bearer Token auth. When set, all /v1/* requests require Authorization: Bearer <key>. Public endpoints (/health, /version, /auth/login) remain open.
LOG_LEVEL No info Log verbosity: debug, info, warn, or error.
QODER_HOST No 127.0.0.1 HTTP server listen address
QODER_PORT No 8963 HTTP server listen port
HTTPS_PROXY No — Proxy URL for upstream connections. Supports http://, https://, socks5://. Also checks: https_proxy, HTTP_PROXY, http_proxy, SOCKS_PROXY, socks_proxy, ALL_PROXY, all_proxy.

Examples

# With API key authentication
QODER_PAT=your_token API_KEY=sk-your-secret-key npm start

# With multiple PATs (round-robin load balancing)
QODER_PAT=token1,token2,token3 npm start

# With SOCKS5 proxy
QODER_PAT=your_token HTTPS_PROXY=socks5://127.0.0.1:1080 npm start

# With HTTP proxy
QODER_PAT=your_token HTTPS_PROXY=http://127.0.0.1:7890 npm start

# Custom host and port
QODER_PAT=your_token QODER_HOST=0.0.0.0 QODER_PORT=3000 npm start

# Enable debug logging
QODER_PAT=your_token LOG_LEVEL=debug npm start

# Only show warnings and errors
QODER_PAT=your_token LOG_LEVEL=warn npm start

Multi-Account Load Balancing

Configure multiple Qoder accounts with comma-separated PATs to distribute requests across them using round-robin:

QODER_PAT=pt-token-aaa,pt-token-bbb,pt-token-ccc npm start
  • Each incoming request is assigned to the next account in rotation
  • All accounts are authenticated at startup; failed accounts will cause startup to fail
  • Single token still works as before (backward compatible)

Docker

Build & Run

docker build --platform linux/amd64 -t qoder2api .
docker run -e QODER_PAT=your_token -p 8963:8963 qoder2api

Docker Compose

Create a .env file:

QODER_PAT=your_token
API_KEY=sk-your-secret-key
LOG_LEVEL=info

Then run:

docker compose up

Pre-built Images

Multi-arch images (linux/amd64, linux/arm64) are published to GitHub Container Registry on every v* tag:

docker pull ghcr.io/emptysuns/qoder2api:latest

Usage Examples

Query Account Info

# Check plan and quota
curl http://127.0.0.1:8963/v1/user/status \
  -H "Authorization: Bearer sk-your-secret-key"

# List all available models
curl http://127.0.0.1:8963/v1/models \
  -H "Authorization: Bearer sk-your-secret-key"

OpenAI SDK (Python)

from openai import OpenAI

client = OpenAI(
    base_url="http://127.0.0.1:8963/v1",
    api_key="sk-your-secret-key"  # your API_KEY, or "anything" if not set
)

# Use any model from the catalog (check /v1/models for available ones)
response = client.chat.completions.create(
    model="Qwen3.7-Max",  # or "DeepSeek-V4-Pro", "qmodel_latest", "dmodel", etc.
    messages=[{"role": "user", "content": "Hello!"}],
    stream=True
)

for chunk in response:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")

Claude SDK (Python)

import anthropic

client = anthropic.Anthropic(
    base_url="http://127.0.0.1:8963/claude",
    api_key="sk-your-secret-key"
)

message = client.messages.create(
    model="Qwen3.7-Max",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello!"}]
)

print(message.content[0].text)

curl

curl http://127.0.0.1:8963/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-your-secret-key" \
  -d '{
    "model": "Qwen3.7-Max",
    "messages": [{"role": "user", "content": "Hello!"}],
    "stream": true
  }'

API Endpoints

Public (no auth required)

Method Path Description
GET /health Health check — returns { "status": "ok" }
GET /version Version info — returns { "version": "x.y.z" }
POST /auth/login Login stub — returns { "status": "ok" }

Models

Method Path Description
GET /v1/models List available models from Qoder's real-time catalog (includes enable status, pricing, context windows)

Account Info

Method Path Description
GET /v1/user/status User plan, quota, feature switches, and session info
GET /v1/user/quota Quota summary (remaining credits, plan tier, exceeded status)

Chat Completions

Method Path Description
POST /v1/chat/completions OpenAI chat completions
POST /v1/completions Alias for chat completions
POST /v1/complete Alias for chat completions

Claude

Method Path Description
POST /claude/v1/messages Anthropic Messages API
POST /v1/messages Anthropic Messages API (shared endpoint)

Gemini

Method Path Description
GET /gemini/v1beta/models List Gemini models
POST /gemini/v1beta/models/:model/generateContent Non-streaming generation
POST /gemini/v1beta/models/:model/streamGenerateContent Streaming generation

Architecture

OpenAI client  → POST /v1/chat/completions ─┐
Claude client  → POST /claude/v1/messages    ├→ Fastify server on :8963
Gemini client  → POST /gemini/v1beta/models  │    → normalizes request to OpenAI format
                .../streamGenerateContent    ─┘    → translates messages to Qoder format
                                                    → BearerApiClient signs + sends to Qoder SSE API
                                                    → StreamAccumulator converts Qoder SSE deltas
                                                      back to client's native SSE format

Modules

Module Description
src/index.js Entry point. Reads env vars, creates bridge, starts server.
src/bridge.js Core OpenAiBridge class. Fastify HTTP server with multi-format routing, message translation, SSE streaming, tool call handling.
src/bearer-client.js BearerApiClient: authenticated HTTP client with COSY bearer token signing.
src/bearer-builder.js Session context construction and bearer token signing (RSA + AES + MD5).
src/proxy.js Proxy-aware HTTPS helper. Supports HTTP CONNECT and SOCKS5 with no external dependencies.
src/signature-client.js Exchanges PAT for job token via Qoder's auth center.
src/signature.js Static request signing for the auth center.
src/encoding.js Custom base64 variant used for all Qoder API payloads.
src/logger.js Leveled logger (debug/info/warn/error). Controlled via LOG_LEVEL env var.
src/local-auth.js Reads cached auth from ~/.qoder/.auth/.

Security

When API_KEY is set, all AI endpoints require Authorization: Bearer <key>. The server uses timing-safe string comparison to prevent timing attacks. Public endpoints (/health, /version, /auth/login) remain accessible without authentication.

Recommendations:

  • Always set API_KEY in production
  • Use QODER_HOST=127.0.0.1 (default) unless you need external access
  • Use a reverse proxy (nginx, Caddy) with TLS for public deployments

License

See LICENSE for details.

Credits

  • Qoder — The underlying AI coding assistant
  • Fastify — The HTTP framework powering this bridge

About

Qoder2api demo via nodejs

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages