开发者文档
沧云 AI 网关对外是标准 OpenAI 兼容协议。一把访问密钥加一个 Base URL 即可接入;目录、价目与余额都有免鉴权或不计费的自查端点,接入前就能验证链路。
- Base URL
https://gw.cangyunai.com/v1- 访问密钥
wxk-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx由运营方签发,以 wxk- 开头,中段是租户标识。你的积分余额决定能调用多少;可调用的模型目录见 /v1/models。
概览
你拿到的是一把访问密钥和一个 Base URL,两样东西就够了。网关对外是标准 OpenAI 兼容协议,任何支持自定义 base_url 的 OpenAI SDK、框架或工具都能直接接,不需要写适配代码。
密钥同时承担两件事:身份识别与积分计量——你的每一次调用按模型与用量维度折算成积分,从账户余额里扣减。
你会用到的端点:
- /v1/models —— 当前可调用的模型目录,免鉴权、不计费;
- /v1/chat/completions —— 对话与代码生成的主端点,支持流式;
- /v1/prices —— 公开价目与闲时忙时折扣窗口,免鉴权;
- /v1/credits/balance、/v1/credits/ledger、/v1/credits/usage —— 用你的密钥自查余额、流水与用量,不计费。
- 先跑 /v1/models 与 /v1/credits/balance 两步免费自检——确认网络、目录、密钥、余额四件事都通;
- 把 SDK 接上;
- 需要流式的话改一个参数;
- 遇到报错查错误码表,再查排障清单。
Base URL 与访问密钥
Base URL 形如 https://<您的网关地址>/v1,注意结尾是 /v1,后续路径直接拼在其后。
| 写法 | 结果 |
|---|---|
| https://gw.example.cn/v1 | 正确 |
| https://gw.example.cn/v1/ | 多数 SDK 可容忍,但自己拼字符串会得到 //chat/completions |
| https://gw.example.cn | 缺 /v1,404 |
| 控制台(管理端)的网址 | 管理端与数据面不是同一个入口,请向运营方确认数据面地址 |
- 密钥形如 wxk- 开头,中段是租户标识,尾段是随机串;
- 明文只在签发那一刻展示一次,之后任何界面与接口都无法再取回,请当场保存;
- 丢失只能由运营方吊销旧密钥、重新签发;
- 密钥本身不设有效期,只有「有效 / 已吊销」两态;
- 账户积分不足时调用返回 402(见计费口径一节)。
export CANGYUN_BASE_URL="https://gw.cangyunai.com/v1"
export CANGYUN_API_KEY="wxk-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"鉴权:只有一个头
平台只认一种写法:Authorization: Bearer <密钥>。注意 Bearer 是精确大小写(bearer 小写会被当成没带),Bearer 与密钥之间是一个空格。
Authorization: Bearer wxk-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| # | 规则 | 违反时的响应 |
|---|---|---|
| 1 | Authorization 的值必须以 Bearer 开头(精确大小写) | 401 + code: missing_api_key |
| 2 | 不支持把密钥放进 URL query 参数(如 ?api_key=) | 401 + code: missing_api_key |
| 3 | 不支持其它鉴权头名——带了也不会被读取,等于没带 | 401 + code: missing_api_key |
| 4 | 密钥不存在或已吊销 | 401 + code: invalid_api_key |
端点范围:POST 的 OpenAI 兼容端点(chat completions、responses、embeddings、audio、images、rerank 等)经鉴权与准入后透传上游;GET /v1/models 与 GET /v1/prices 免鉴权自答;GET /v1/credits/balance 等自查端点用同一把密钥。
快速开始:两步免费自检
第一步,验证网络与目录(免鉴权,不带密钥):
curl -sS "https://gw.cangyunai.com/v1/models"返回 200 且 body 形如:
{"object":"list","data":[{"id":"model-a","object":"model"},{"id":"model-b","object":"model"}]}第二步,验证密钥与余额(带密钥,不计费):
curl -sS "https://gw.cangyunai.com/v1/credits/balance" \
-H "Authorization: Bearer wxk-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"返回 200 且含 available_credits = 密钥有效、账户里有余额:
{
"tenant_id": "t-example",
"balance_credits": 3800,
"inflight_credits": 1.25,
"available_credits": 3798.75,
"settle_interval_s": 300
}| 验证项 | 失败时的表现 |
|---|---|
| 到网关的网络路径通、Base URL 拼对 | 连接超时 / 404 |
| 密钥有效、未吊销 | 401(missing_api_key / invalid_api_key) |
| 账户里有可用余额 | 看 available_credits;为 0 时调模型会 402 |
前两步证明的是「网络 + 目录 + 密钥 + 余额」,不证明某个模型在上游真能出结果。要证明后者必须发一次真实请求,而真实请求会计费。把成本压到最低的做法是把 max_tokens 压到个位数:
curl -sS "https://gw.cangyunai.com/v1/chat/completions" \
-H "Authorization: Bearer wxk-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"model": "model-a",
"messages": [{"role": "user", "content": "hi"}],
"max_tokens": 8
}'返回 200 且 choices[0].message.content 非空 = 这条链路端到端可用。
OpenAI SDK 接入
SDK 会把 apiKey 渲染成 Authorization: Bearer ……正是平台唯一支持的鉴权写法,不需要任何额外鉴权配置。
import os
from openai import OpenAI
client = OpenAI(
base_url=os.environ["CANGYUN_BASE_URL"], # https://gw.cangyunai.com/v1
api_key=os.environ["CANGYUN_API_KEY"],
)
# 免费自检:当前模型目录(不计费)
for m in client.models.list().data:
print(m.id)
# 真实调用(计费)
resp = client.chat.completions.create(
model="model-a",
messages=[{"role": "user", "content": "你好"}],
)
print(resp.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({
baseURL: process.env.CANGYUN_BASE_URL,
apiKey: process.env.CANGYUN_API_KEY,
});
// 免费自检(不计费)
const models = await client.models.list();
console.log(models.data.map((m) => m.id));
// 真实调用(计费)
const resp = await client.chat.completions.create({
model: "model-a",
messages: [{ role: "user", content: "你好" }],
});
console.log(resp.choices[0]?.message?.content);GET /v1/models:全局模型目录
这个端点由平台自答、免鉴权,请求不会转发到上游模型服务商。因此:
- 不产生 token 用量,不计费——可以放心高频调用;
- 响应极快(不受上游延迟影响);
- 返回的是全局目录:所有客户看到同一份清单,不按密钥过滤。
响应格式是标准 OpenAI Models 列表,所有 OpenAI SDK 的 models.list() 开箱可用。
| 清单什么时候会变 | 生效时延 |
|---|---|
| 运营方上架 / 下架模型 | 立即(配置热生效) |
| 上游服务商下架某个模型 | 运营方同步后从目录移除 |
一个边界:GET /v1/models/{模型名}(单模型详情)不支持;要查清单请只用不带模型名的 GET /v1/models。
GET /v1/prices:公开价目与折扣窗口
免鉴权。返回当前计价快照:每个模型模式 × 计费维度的系数,以及生效中的闲时忙时折扣窗口。1 积分 = ¥0.01 面值。
curl -sS "https://gw.cangyunai.com/v1/prices"返回形如:
{
"snapshot_id": 3,
"credit_face": "1 积分 = ¥0.01",
"prices": [
{
"model_pattern": "qwen/*",
"coefficients": [
{"dimension": "input_token", "unit_divisor": 1000000, "credits_per_unit_batch": 260},
{"dimension": "cached_input_token", "unit_divisor": 1000000, "credits_per_unit_batch": 104},
{"dimension": "output_token", "unit_divisor": 1000000, "credits_per_unit_batch": 390},
{"dimension": "reasoning_token", "unit_divisor": 1000000, "credits_per_unit_batch": 390}
]
}
],
"discounts": [
{"model_pattern": "*", "start_min": 1320, "end_min": 360, "factor": 0.5, "timezone": "Asia/Shanghai"}
]
}- 系数按「模型模式 × 计费维度」给出:input_token / cached_input_token / output_token / reasoning_token 等,单位是「每百万 token 多少积分」;
- discounts 是生效中的闲时忙时折扣窗口:start_min / end_min 是规则时区里的分钟数(1320 = 22:00),factor < 1 表示折扣(0.5 = 五折),按请求完成时刻是否落窗生效;
- snapshot_id 单调递增:每次调价换版;进行中的请求按发起时的快照结算,不受中途调价影响。
门户定价页是这份数据的渲染;数字以接口实时返回为准。
流式输出
加一个参数即可,其余不变。curl 请带 -N(关闭缓冲),否则看不到逐字输出。
curl -N "https://gw.cangyunai.com/v1/chat/completions" \
-H "Authorization: Bearer wxk-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"model": "model-a",
"messages": [{"role": "user", "content": "写一段介绍"}],
"stream": true
}'响应是标准 SSE:content-type: text/event-stream,每条以 data: 开头,以 data: [DONE] 结束。平台透传上游的流,不做缓冲聚合。
data: {"choices":[{"delta":{"content":"你"}}]}
data: {"choices":[{"delta":{"content":"好"}}]}
data: [DONE]计费口径与积分
- 按 token 计价:单价以「每百万 token 多少积分」表示(见 /v1/prices),输入 / 输出 / 缓存输入 / 推理分维度计价;
- 1 积分 = ¥0.01 面值;内部按微积分记账,积分以下不产生取整损耗;
- 准入时按请求上限做一笔乐观冻结,结算时按真实用量多退少补,冻结随结算释放;
- 扣费不是实时的:结算按周期批量进行(默认 ≤5 分钟,高峰期最长约 15 分钟),余额接口返回的是已结算口径;
- 可用余额(余额 − 在途冻结)≤ 0 → 调用返回 402 insufficient_credits;充值后数秒内自动恢复,无需换密钥;
- 落在闲时忙时折扣窗口内完成的请求按窗口系数折算,流水里该条目带 discount_factor 字段。
用同一把密钥即可自查(这三个端点不计费):
| 端点 | 返回 |
|---|---|
| GET /v1/credits/balance | 余额、在途冻结、可用余额(balance_credits / inflight_credits / available_credits) |
| GET /v1/credits/ledger?limit=N | 逐笔流水:purchase / consume / adjust / refund / expire,消耗条目含 model 与 ref_id |
| GET /v1/credits/usage?group_by=model | 用量聚合;group_by 可取 model / day / dimension / key |
门户控制台是这三个接口的可视化;程序化对账建议直接调接口。
错误码完整语义
所有平台侧错误都是统一信封 {"error":{"code","message",...}}。判断错误种类请读 code,不要匹配 message 文案(文案可能调整);部分错误在 error 里带附加字段(例如 402 带 balance_credits 与 recharge_url)。
{
"error": {
"code": "insufficient_credits",
"message": "积分余额不足,请前往门户充值",
"balance_credits": 0.42,
"inflight_credits": 0.9,
"recharge_url": "https://www.cangyunai.com/console/billing"
}
}| HTTP | code | 含义 | 客户端应对 |
|---|---|---|---|
| 401 | missing_api_key | 没带 Authorization,或值不是 Bearer 前缀(精确大小写) | 补上 Authorization: Bearer <密钥>;不可重试 |
| 401 | invalid_api_key | 密钥无效或已吊销 | 核对密钥;已吊销请运营方重签;不可重试 |
| 402 | insufficient_credits | 可用积分不足(余额 − 在途冻结 ≤ 0) | 按 error.recharge_url 充值;重试无用 |
| 404 | model_not_priced | 模型未配置计价系数,平台拒绝放行(不会静默免费) | 换用 /v1/models 清单内的模型;不可重试 |
| 404 | (无 code) | 路径拼错或端点不存在 | 核对 Base URL 是否以 /v1 结尾、路径拼写 |
上游或网络环节产生的错误:
| HTTP | 含义 | 客户端应对 |
|---|---|---|
| 5xx | 上游模型服务故障或平台异常 | 带 X-Cy-Request-Id 报障;可做有限次指数退避重试 |
准入通过后的每个响应都带 X-Cy-Request-Id 头,报障时请提供它(401 / 402 发生在准入阶段、不带这个头,这两类报错提供 error.code 与发生时间即可)。
排障清单
按顺序走,多数问题在前 4 步内定位:
| 症状 | 先查 | 说明 |
|---|---|---|
| 连接超时 / 拒绝连接 | Base URL 的主机与端口 | 与运营方确认地址;确认出口防火墙放行 |
| 404(无 error.code) | Base URL 是否以 /v1 结尾 | 见 Base URL 一节的拼错对照表 |
| 401 missing_api_key | Authorization 是否没带,或 Bearer 写成了小写 | 平台只认精确的 Bearer 前缀(含一个空格) |
| 401 invalid_api_key | 密钥是否完整、是否已被吊销 | 复制时被截断是高发原因 |
| 402 insufficient_credits | GET /v1/credits/balance 看 available_credits | 充值后数秒自动恢复;不要重试 |
| 404 model_not_priced | 模型名是否在 GET /v1/models 清单里 | 不在 = 未上架或未配价,换清单内模型 |
| 余额数字没立刻变 | 结算周期(≤5 分钟,峰值约 15 分钟) | 流水与余额都是已结算口径,稍等再看 |
| 流式没有逐字输出 | curl 是否带 -N、客户端是否禁用了缓冲 | 见流式输出一节 |
| 5xx | 记下 X-Cy-Request-Id | 带它报障,运营方据此查平台日志 |
变更与支持
- 本文档随平台更新。协议层面向后兼容:新增能力不会改变既有端点的请求/响应结构;
- 错误 message 文案可能调整,请始终按 HTTP 状态码 + error.code 分支;
- 模型目录与价目会随运营调整变化,请以 GET /v1/models 与 GET /v1/prices 的实时返回为准,不要硬编码;
- 套餐、充值与单价的调整见门户定价页,或联系运营方。