c3api

module
v0.0.1-beta.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2026 License: AGPL-3.0

README

⚡ c3api

A lightweight AI gateway — one entry point for the OpenAI Responses API, the Anthropic Messages API, and the OpenAI Chat Completions API, with a built-in admin console, usage tracking, and billing.

English | 中文

Release Stars License Go

OpenAI Responses API Anthropic Messages API OpenAI Chat Completions API

c3api is a self-hosted AI gateway that fronts multiple upstream providers with one unified entry point. It speaks all six request formats — OpenAI Responses API (including its WebSocket variant), Anthropic Messages API, OpenAI Chat Completions API, OpenAI Images API, Codex web search, and an OpenAI-compatible model list — and maps them onto your configured upstream accounts with model routing, quotas, usage accounting, and an embedded admin console.

Status: Beta

c3api is in beta: feature-complete, but breaking changes are free to happen.

  • Not backward-compatible — database schemas and configuration are not backward-compatible across versions, and no migration path is provided.
  • Upgrade = fresh setup — upgrading from an earlier version means provisioning a brand-new database and re-checking your configuration from scratch.
  • See CHANGELOG.md for release notes.

Features

Six formats, one gateway OpenAI Responses API (REST + WebSocket), Anthropic Messages API, OpenAI Chat Completions API, OpenAI Images API, Codex web search, and the OpenAI-compatible model list — each with its own upstream orchestration and protocol conversion
Template & account management Model templates, upstream accounts, groups, credentials, and per-template format/model allowlists
Admin console React web UI embedded in the binary (/app), plus a full OpenAPI-defined admin API (/api/admin)
Billing & usage Per-user balance with pre-check deductions, FEFO temporary quotas, per-model pricing synced from litellm, daily-partitioned usage logs and statistics — billing is enabled by default (config.example.toml billing.enabled=true)
Intelligent routing A background compiler turns durable per-attempt quality statistics (Wilson-bounded success + log-TTFT), procurement cost multipliers, cache domains, and runtime health into immutable routing plans (Primary / Explore / Degraded lanes); a small steady-state exploration share (1–5%) keeps sampling non-primary candidates; selection is plan-only (no off-plan fallback; AI traffic answers 503 until the first compiled plan publishes), executing the precompiled plan with distinct replay-safe failover (1–8 attempts); requests carrying prompt_cache_key / conversation_id / session_id get soft cache-domain affinity. No manual weights
Rules engine Typed throttle (transient runtime health) and fail_account (terminal) actions with count/ratio windows, plus response shaping — replaces the old hardcoded backoff; customizable via /api/admin/rules
Multi-instance ready PostgreSQL-based state, NOTIFY-based cross-instance invalidation, Redis-heartbeat instance discovery (cluster size auto-detected) — zero-config horizontal scaling
Single binary Go binary with embedded frontend, non-root Docker image, drop-in deployment
Request formats
Format Endpoint Upstream
OpenAI Responses API POST /v1/responses OpenAI Responses (REST)
OpenAI Responses API — WebSocket WS /v1/responses (GET with upgrade header) OpenAI Responses WebSocket (e.g. Codex client)
Anthropic Messages API POST /v1/messages Anthropic Messages (REST + SSE)
OpenAI Chat Completions API POST /v1/chat/completions OpenAI Chat Completions (REST + SSE)
OpenAI Images API POST /v1/images/generations / POST /v1/images/edits OpenAI Images (JSON + multipart, REST + SSE)
Codex web search POST /v1/alpha/search Codex SDK Search (Codex client only)
OpenAI model list GET /v1/models In-memory scheduler snapshot (zero DB)

Quick Start

Run the prebuilt image (pull) — for production, remove the build: block in compose.yml so up runs the pulled image instead of building:

cp .env.example .env        # fill in AUTH_JWT_SECRET (ADMIN_TOKEN optional — see below)
docker compose pull
docker compose up -d

Self-build — compose builds the image locally (image and build coexist, build wins):

cp .env.example .env        # fill in AUTH_JWT_SECRET (ADMIN_TOKEN optional — see below)
docker compose up -d --build

The gateway listens on http://127.0.0.1:18080 — admin console at /app, user console at /user, health check at /healthz.

First admin user (bootstrap) — the first user to register on a fresh database automatically becomes a platform_admin and can sign into the admin console (/app) right after startup; later signups get the regular user role.

Prebuilt images are published to GHCR (ghcr.io/is7qin/c3api): :beta tracks the latest beta release, and version-pinned tags such as :v0.0.1-beta.1 are also available. Pull standalone: docker pull ghcr.io/is7qin/c3api:beta.

Option B: Local development
# 0. Inject local dev secrets once (config.toml keeps empty values; placeholder
#    values like change-me are rejected by config.Load)
export C3API_ADMIN_TOKEN=local-admin-token
export C3API_AUTH_JWT_SECRET=$(openssl rand -hex 16)

# 1. Start the gateway (default :18080)
go run ./cmd/server -config config.toml

# 2. Start the frontend dev server (:5173, proxies /api to 18080)
cd web && pnpm install && pnpm run dev

Point any OpenAI/Anthropic-compatible SDK at the gateway URL — the request format is selected by path, so a single base URL serves all six request formats.

Sponsors

Sponsor About
ForZTN Next-gen VPC-based IDC cloud panel · network/VM exchange

Architecture

                    ┌───────────────────────────────┐
 OpenAI SDK / curl ─▶│   c3api gateway (1 binary)    │
 Anthropic SDK ─────▶│  ┌─────────────────────────┐  │
 Codex client ──────▶│  │ chi router              │  │──▶ OpenAI upstream (REST + SSE)
   Browser (SPA) ───▶│  │ /healthz /api/admin /api/user + SPA / /user /app │  │──▶ Anthropic upstream (REST + SSE)
                    │  │ /v1/*                    │  │──▶ Responses / resp-ws upstream
                    │  │ proxy: auth → gate →     │  │
                    │  │         route → forward  │  │
                    │  └──────────┬──────────────┘  │
                     │   workers: billing / usage /  │
                     │   errlog / scheduler / notify │
                     │   retention / stats-agg /     │
                     │   pricing-sync / rule-engine  │
                     │   quality-sync                │
                     │   auth-sync / invalidate /    │
                     │   discovery                   │
                    └───────┼───────────────┼──────┘
                            ▼               ▼
              PostgreSQL 18 (state + NOTIFY) │
                                             ▼
                        Redis 8 (ephemeral: coordination +
                        short-lived verification codes)
  • Single binary: the frontend is built and embedded via go:embed, so the runtime is one server process plus a mounted config file.
  • Stateless gateway, stateful DB: all shared state lives in PostgreSQL; instances coordinate through NOTIFY on the c3api_invalidate channel. The cluster instance count for multi-instance budget sharing is auto-discovered via Redis heartbeats — scale horizontally by just adding instances (no manual setting).
  • Persistent workers: billing deduction, usage/statistics flushing, error-log auditing, partition retention, offline stats aggregation, price sync, realtime quality sync (quality-sync), and the rule scheduler run as long-lived workers with graceful shutdown draining. The routing plan compiler is not a separate worker: it runs as a serial compile lane inside the scheduler, with freshness surfaced through the scheduler's ops stats.

Performance

A 30 s CPU profile of the gateway (go tool pprof -http=:8081 <profile.pprof>):

CPU flame graph

The hot spots are I/O and garbage collection, not request-path logic:

  • ~23% syscall — network reads/writes (upstream connections, pgx)
  • ~15% GC — allocation-heavy paths (span class sizing + object/span scanning)
  • ~4% selectgo — concurrency wait; ~1% memmove — data copies

The request path itself (JSON parsing, routing, quota/billing) stays a single-digit share of total CPU, leaving headroom for higher throughput. GC tuning hooks (GOGC / GOMEMLIMIT) are wired through the compose stack — see .env.example.

Configuration

The gateway loads config.toml (see config.example.toml), overlaid by C3API_-prefixed environment variables (the prefix must be uppercase):

Variable Description
C3API_ADMIN_TOKEN Admin API token (optional; leave empty to disable static-token auth — /api/admin then accepts platform_admin JWTs only)
C3API_AUTH_JWT_SECRET JWT signing secret for user auth (required; stable across restarts and instances)
C3API_DB_DSN PostgreSQL DSN
C3API_REDIS_ADDR Redis address (required; e.g. 127.0.0.1:6379 — instance discovery, short-lived verification codes and other ephemeral state)
C3API_SERVER_TIME_ZONE Deployment timezone for pricing time/day-of-week conditions (IANA name, e.g. Asia/Shanghai; empty = process local)

See config.example.toml for the full schema (server, log, admin, auth, db, redis, proxy, upstream, limit, scheduler, usage, billing).

  • Fresh setup only (no migration path) — schemas and configuration are not backward-compatible between versions: an upgrade means a brand-new database and a re-checked configuration (see Status: Beta).
  • Env-only deployments (e.g. K8s): pass -config "" to skip the config file entirely — the flag defaults to config.toml, and a missing file is a startup error.
  • Config is read once at startup — changes require a rolling restart (no hot reload).
  • Invalid config fails fast at startup with the offending key: non-positive durations/intervals, unknown keys (typos, removed keys), missing required secrets, and placeholder values (change-me, dev-admin-token, …) are all rejected.

Deployment

  • compose.yml — production stack: one db (postgres:18-alpine, bind-mounted data under deploy/data/pg) + one redis (redis:8-alpine, ephemeral coordination + short-lived verification codes — no persistence) + one app container (non-root, read-only config mount from deploy/config.toml, healthcheck).
  • Dockerfile — three-stage build (node → go → alpine), producing a single static binary with the UI embedded.
  • Dual required dependencies: PostgreSQL 18 (all durable state, source of record) + Redis 8 (ephemeral coordination + short-lived email verification codes — instance discovery heartbeats and verification codes; never a cache layer). Both are startup-mandatory. Do not set an eviction policy (allkeys-lru etc.) for this instance: an evicted code is benign (the user just re-requests one), but keep it out of the configuration.
GC tuning (optional, default off)

Under high concurrency (25k+ concurrent streams) the default Go GC becomes a measurable cost. A/B-tested at 50k concurrency on a 24-core box, GOGC=off + GOMEMLIMIT=17179869184 (16 GiB — plain bytes, the env var rejects unit suffixes like 16G) measured:

  • Throughput +14.5% (25.1k → 28.75k req/s)
  • Per-request CPU -27.7% (331 → 239 µs)
  • First-byte latency -21% (1103 → 873 ms); p99 first-byte -36% (5785 → 3705 ms)

Trade-off: the heap grows to the limit (~13 GiB with a 16 GiB cap) and GC fires roughly every ~10 s instead of every ~2-3 s — fine on a 64 GiB box; raise GOMEMLIMIT to cut the frequency further at the cost of memory. Set both in .env (empty values keep Go defaults):

GOGC=off
GOMEMLIMIT=17179869184

License

c3api is open source under the GNU AGPL v3.0-or-later (LICENSE) — free to use, modify, and deploy, including for commercial and hosted services, with the single obligation that modifications are contributed back under the same terms. No purchase is required.

Need closed-source deployment (exempt from the AGPL obligations on your deployment)? A commercial license (LICENSE.commercial) is available — it waives the AGPL obligations for your deployment.

External code contributions require a CLA (contributor license agreement) so that contributed code can be merged under this dual-license scheme — see CLA.md and CONTRIBUTING.md.

Contact

  • GitHub: is7Qin/c3api
  • Issues: open a GitHub issue for bugs, questions, or feature requests
  • Security: report vulnerabilities via SECURITY.md (private report)
  • Changelog: CHANGELOG.md

Directories

Path Synopsis
cmd
server command
SPDX-License-Identifier: AGPL-3.0-or-later
SPDX-License-Identifier: AGPL-3.0-or-later
internal
auth
Package auth 承载用户认证体系:bcrypt 密码哈希(与 sub2api 同参数)、 JWT 签发/验证(HS256,TTL 24h)与 RBAC 中间件(/user 组 RequireJWT + 快照用户状态校验;/admin = 静态 token OR platform_admin JWT)。
Package auth 承载用户认证体系:bcrypt 密码哈希(与 sub2api 同参数)、 JWT 签发/验证(HS256,TTL 24h)与 RBAC 中间件(/user 组 RequireJWT + 快照用户状态校验;/admin = 静态 token OR platform_admin JWT)。
billing
Package billing 计费核心:service_tier 归一化 + 价格矩阵纯函数 + 余额快照 + 批量扣费 flusher。
Package billing 计费核心:service_tier 归一化 + 价格矩阵纯函数 + 余额快照 + 批量扣费 flusher。
continuation
SPDX-License-Identifier: AGPL-3.0-or-later
SPDX-License-Identifier: AGPL-3.0-or-later
credential
Package credential 是账号凭据抽象层:类型注册表 + Provider 分发,为后续 多种号池类型(codex oauth、codex personal_access_token、claude code 等) 打地基。
Package credential 是账号凭据抽象层:类型注册表 + Provider 分发,为后续 多种号池类型(codex oauth、codex personal_access_token、claude code 等) 打地基。
discovery
Package discovery Redis 实例发现(spec 2026-08-25-redis-instance-discovery-design, 基建面见 2026-08-25-redis-foundation-design):单 ZSET 心跳成员协议替换手工 cluster.instances 设置——实例心跳注册、活体计数即多实例预算分摊基数 N。
Package discovery Redis 实例发现(spec 2026-08-25-redis-instance-discovery-design, 基建面见 2026-08-25-redis-foundation-design):单 ZSET 心跳成员协议替换手工 cluster.instances 设置——实例心跳注册、活体计数即多实例预算分摊基数 N。
domain
SPDX-License-Identifier: AGPL-3.0-or-later Dual-licensed: AGPL-3.0-or-later (open source) or commercial license (closed-source deployment exemption); see LICENSE and LICENSE.commercial.
SPDX-License-Identifier: AGPL-3.0-or-later Dual-licensed: AGPL-3.0-or-later (open source) or commercial license (closed-source deployment exemption); see LICENSE and LICENSE.commercial.
ent
handler
Package handler provides primitives to interact with the openapi HTTP API.
Package handler provides primitives to interact with the openapi HTTP API.
handler/httpface
Package httpface 管理面/用户面 HTTP 边界:响应书写(WriteJSON/WriteErr/ WriteServiceErr,service 错误→HTTP 状态映射表唯一一份)+ 请求参数边界 (ClampLimit——两面包共享的分页上限钳制)。
Package httpface 管理面/用户面 HTTP 边界:响应书写(WriteJSON/WriteErr/ WriteServiceErr,service 错误→HTTP 状态映射表唯一一份)+ 请求参数边界 (ClampLimit——两面包共享的分页上限钳制)。
handler/user
Package user provides primitives to interact with the openapi HTTP API.
Package user provides primitives to interact with the openapi HTTP API.
invalidate
Package invalidate 管理面变更的去抖定向失效:
Package invalidate 管理面变更的去抖定向失效:
latch
Package latch 是规则失效锁存的一等组件(根因重开):单实例内存 锁存(account+fingerprint+revision)+ 规则失败事件的同步扇出中介。
Package latch 是规则失效锁存的一等组件(根因重开):单实例内存 锁存(account+fingerprint+revision)+ 规则失败事件的同步扇出中介。
notify
Package notify 多实例变更广播(基础层):PG LISTEN/NOTIFY 定向刷新。
Package notify 多实例变更广播(基础层):PG LISTEN/NOTIFY 定向刷新。
protoconv
Package protoconv 提供网关级协议转换(只补差语义):客户端协议请求体 → 模板协议请求体(ConvertRequest)、模板协议响应 → 客户端协议响应 (ConvertResponse 非流式 JSON / StreamMapper 流式 SSE 事件映射)。
Package protoconv 提供网关级协议转换(只补差语义):客户端协议请求体 → 模板协议请求体(ConvertRequest)、模板协议响应 → 客户端协议响应 (ConvertResponse 非流式 JSON / StreamMapper 流式 SSE 事件映射)。
proxy
SPDX-License-Identifier: AGPL-3.0-or-later
SPDX-License-Identifier: AGPL-3.0-or-later
quality
SPDX-License-Identifier: AGPL-3.0-or-later
SPDX-License-Identifier: AGPL-3.0-or-later
repository
SPDX-License-Identifier: AGPL-3.0-or-later Dual-licensed: AGPL-3.0-or-later (open source) or commercial license (closed-source deployment exemption); see LICENSE and LICENSE.commercial.
SPDX-License-Identifier: AGPL-3.0-or-later Dual-licensed: AGPL-3.0-or-later (open source) or commercial license (closed-source deployment exemption); see LICENSE and LICENSE.commercial.
rule
Package rule 实现规则引擎(可编排状态管理):事件 → 有界 channel → 规则 worker (priority 首中匹配)→ typed 动作(Throttle→RuntimeHealth / FailAccount→latch+CAS) + 响应整形。
Package rule 实现规则引擎(可编排状态管理):事件 → 有界 channel → 规则 worker (priority 首中匹配)→ typed 动作(Throttle→RuntimeHealth / FailAccount→latch+CAS) + 响应整形。
scheduler
SPDX-License-Identifier: AGPL-3.0-or-later
SPDX-License-Identifier: AGPL-3.0-or-later
sdkbridge
Package sdkbridge 是 SDK 适配层与网关之间的契约面(零 SDK 依赖——SDK 调用从此后):统一失效回调 + 失效处理链装配(写失效字段 / 调度摘除 / 审计)、网关侧信封错误与凭据传递形态(AccountCredential 派生在 internal/domain)。
Package sdkbridge 是 SDK 适配层与网关之间的契约面(零 SDK 依赖——SDK 调用从此后):统一失效回调 + 失效处理链装配(写失效字段 / 调度摘除 / 审计)、网关侧信封错误与凭据传递形态(AccountCredential 派生在 internal/domain)。
server
Package server 装配 chi 路由:/api/admin/*(静态 token OR platform_admin JWT)+ /api/user/*(JWT 保护,register/login 公开)+ 三个 AI 端点 + /healthz。
Package server 装配 chi 路由:/api/admin/*(静态 token OR platform_admin JWT)+ /api/user/*(JWT 保护,register/login 公开)+ 三个 AI 端点 + /healthz。
service
SPDX-License-Identifier: AGPL-3.0-or-later Dual-licensed: AGPL-3.0-or-later (open source) or commercial license (closed-source deployment exemption); see LICENSE and LICENSE.commercial.
SPDX-License-Identifier: AGPL-3.0-or-later Dual-licensed: AGPL-3.0-or-later (open source) or commercial license (closed-source deployment exemption); see LICENSE and LICENSE.commercial.
service/errors
Package serviceerr 定义 service 层错误哨兵(单一真相)。
Package serviceerr 定义 service 层错误哨兵(单一真相)。
settingssnap
Package settingssnap 是 settings 全量内存快照的唯一事实源(根因重开): Service 与 MailWorker 同源共享单个 *Snapshot(单指针,无双快照分叉)。
Package settingssnap 是 settings 全量内存快照的唯一事实源(根因重开): Service 与 MailWorker 同源共享单个 *Snapshot(单指针,无双快照分叉)。
snapshot
Package snapshot 统一网关各内存快照的生命周期:启动就绪(ReloadAll 全量首刷) + NOTIFY 事件分发(按 scope 精确重载)+ 状态可观测(Status)。
Package snapshot 统一网关各内存快照的生命周期:启动就绪(ReloadAll 全量首刷) + NOTIFY 事件分发(按 scope 精确重载)+ 状态可观测(Status)。
usage
归属说明:retention worker 放 usage 包——原 Recorder.janitorLoop(逐行 DELETE)已删除,保留策略整体移交本 worker;保留天数与 Recorder 配置同源 (config usage.log_retention_days),故与 Recorder 同包管理。
归属说明:retention worker 放 usage 包——原 Recorder.janitorLoop(逐行 DELETE)已删除,保留策略整体移交本 worker;保留天数与 Recorder 配置同源 (config usage.log_retention_days),故与 Recorder 同包管理。
verification
Package verification 邮箱验证码的 Redis 存储(spec 2026-08-25-emailcode-redis-migration §2):一个 (purpose,email) 一个 HASH,四命令直映 service.EmailCodeStore,零 Lua。
Package verification 邮箱验证码的 Redis 存储(spec 2026-08-25-emailcode-redis-migration §2):一个 (purpose,email) 一个 HASH,四命令直映 service.EmailCodeStore,零 Lua。
worker
Package worker 提供统一后台任务抽象(Global Constraints):顺序启动、 反向排空、panic 捕获(进程不崩)。
Package worker 提供统一后台任务抽象(Global Constraints):顺序启动、 反向排空、panic 捕获(进程不崩)。
pkg
aiclient
Package aiclient 是 openai/anthropic 官方 SDK 的唯一引用点:客户端懒构建 + 鉴权头注入 + 非流式超时策略。
Package aiclient 是 openai/anthropic 官方 SDK 的唯一引用点:客户端懒构建 + 鉴权头注入 + 非流式超时策略。
httpx
Package httpx 构造共享的上游 HTTP 客户端(规格 §10.2 连接层参数)。
Package httpx 构造共享的上游 HTTP 客户端(规格 §10.2 连接层参数)。
logx
Package logx 是 zap 的薄包装:业务代码只允许经本包取日志,禁止直接 import zap。
Package logx 是 zap 的薄包装:业务代码只允许经本包取日志,禁止直接 import zap。
redisx
Package redisx 全仓唯一 Redis 客户端构造点(spec 2026-08-25-redis-foundation-design §2.2):cmd/server/main.go 调 Open,产物 *redis.Client 以构造注入分发。
Package redisx 全仓唯一 Redis 客户端构造点(spec 2026-08-25-redis-foundation-design §2.2):cmd/server/main.go 调 Open,产物 *redis.Client 以构造注入分发。
sserelay
Package sserelay 提供原始字节级 SSE relay:从 io.Reader 增量读取 SSE 帧, 原样转发给 http.ResponseWriter,自适应批量 Flush,并以 Observer 旁路暴露 事件信息(仅用于 usage 提取,不参与转发决策)。
Package sserelay 提供原始字节级 SSE relay:从 io.Reader 增量读取 SSE 帧, 原样转发给 http.ResponseWriter,自适应批量 Flush,并以 Observer 旁路暴露 事件信息(仅用于 usage 提取,不参与转发决策)。
tools
fakeupstream command
fakeupstream 模拟 OpenAI chat/completions 上游:支持流式(chunks 个事件 + usage + [DONE])。
fakeupstream 模拟 OpenAI chat/completions 上游:支持流式(chunks 个事件 + usage + [DONE])。
loadtest command
loadtest 对网关打压测:固定并发 goroutine 持续请求,支持流式首字节和非流式完整响应延迟。
loadtest 对网关打压测:固定并发 goroutine 持续请求,支持流式首字节和非流式完整响应延迟。
loadtest/setup command
setup 构造多租户压测数据(数据模型 + 计费字段 + intelligent routing 新契约):模板(四格式 × 随机模型池 + loadtest 固定请求模型必含)→ 公开组 → 账号(分散模板/组/上游,可选采购成本倍率 + 共享缓存域)→ 用户(可选 余额/并发区间)→ 逐个登录建 key(可选多 key/并发/额度区间),key 明文写文件 (loadtest -keys 用)。
setup 构造多租户压测数据(数据模型 + 计费字段 + intelligent routing 新契约):模板(四格式 × 随机模型池 + loadtest 固定请求模型必含)→ 公开组 → 账号(分散模板/组/上游,可选采购成本倍率 + 共享缓存域)→ 用户(可选 余额/并发区间)→ 逐个登录建 key(可选多 key/并发/额度区间),key 明文写文件 (loadtest -keys 用)。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL