开发者文档

沧云 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 —— 用你的密钥自查余额、流水与用量,不计费。
  1. 先跑 /v1/models 与 /v1/credits/balance 两步免费自检——确认网络、目录、密钥、余额四件事都通;
  2. 把 SDK 接上;
  3. 需要流式的话改一个参数;
  4. 遇到报错查错误码表,再查排障清单。

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(见计费口径一节)。
不要把密钥写进代码仓库、前端 bundle、客户端安装包或日志。用环境变量注入,并且用 export 而不是直接写在命令行里——否则密钥会落进 shell history。
bash
export CANGYUN_BASE_URL="https://gw.cangyunai.com/v1"
export CANGYUN_API_KEY="wxk-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

鉴权:只有一个头

平台只认一种写法:Authorization: Bearer <密钥>。注意 Bearer 是精确大小写(bearer 小写会被当成没带),Bearer 与密钥之间是一个空格。

http
Authorization: Bearer wxk-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
#规则违反时的响应
1Authorization 的值必须以 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
从旧文档迁来的客户注意:x-api-key 写法已退役。请求里带着它也会被忽略,结果只取决于 Authorization 是否设置正确——请只保留 Authorization。

端点范围:POST 的 OpenAI 兼容端点(chat completions、responses、embeddings、audio、images、rerank 等)经鉴权与准入后透传上游;GET /v1/models 与 GET /v1/prices 免鉴权自答;GET /v1/credits/balance 等自查端点用同一把密钥。

快速开始:两步免费自检

前两步不产生用量、不计费、不扣余额,可以放心反复跑。

第一步,验证网络与目录(免鉴权,不带密钥):

bash
curl -sS "https://gw.cangyunai.com/v1/models"

返回 200 且 body 形如:

json
{"object":"list","data":[{"id":"model-a","object":"model"},{"id":"model-b","object":"model"}]}

第二步,验证密钥与余额(带密钥,不计费):

bash
curl -sS "https://gw.cangyunai.com/v1/credits/balance" \
  -H "Authorization: Bearer wxk-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

返回 200 且含 available_credits = 密钥有效、账户里有余额:

json
{
  "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 压到个位数:

bash
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 ……正是平台唯一支持的鉴权写法,不需要任何额外鉴权配置。

python
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)
ts
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() 开箱可用。

清单什么时候会变生效时延
运营方上架 / 下架模型立即(配置热生效)
上游服务商下架某个模型运营方同步后从目录移除
不要把清单硬编码进代码。启动时或定期拉一次 /v1/models,用它做模型选择的依据;清单里没有的模型,调用大概率会失败。
模型清单以 GET /v1/models 为准;对清单外模型的调用不保证可用。未配置计价系数的模型会被 404 model_not_priced 响亮拒绝——不会静默免费。

各模型的积分价格见定价页 →

一个边界:GET /v1/models/{模型名}(单模型详情)不支持;要查清单请只用不带模型名的 GET /v1/models。

GET /v1/prices:公开价目与折扣窗口

免鉴权。返回当前计价快照:每个模型模式 × 计费维度的系数,以及生效中的闲时忙时折扣窗口。1 积分 = ¥0.01 面值。

bash
curl -sS "https://gw.cangyunai.com/v1/prices"

返回形如:

json
{
  "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(关闭缓冲),否则看不到逐字输出。

bash
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] 结束。平台透传上游的流,不做缓冲聚合。

text
data: {"choices":[{"delta":{"content":"你"}}]}

data: {"choices":[{"delta":{"content":"好"}}]}

data: [DONE]
流式请求中途出错时,错误可能以 SSE 事件形式出现在流里而不是 HTTP 状态码——因为 HTTP 头在第一个 chunk 时就已经发出去了。客户端要在流处理里也做异常分支。

计费口径与积分

  • 按 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)。

json
{
  "error": {
    "code": "insufficient_credits",
    "message": "积分余额不足,请前往门户充值",
    "balance_credits": 0.42,
    "inflight_credits": 0.9,
    "recharge_url": "https://www.cangyunai.com/console/billing"
  }
}
HTTPcode含义客户端应对
401missing_api_key没带 Authorization,或值不是 Bearer 前缀(精确大小写)补上 Authorization: Bearer <密钥>;不可重试
401invalid_api_key密钥无效或已吊销核对密钥;已吊销请运营方重签;不可重试
402insufficient_credits可用积分不足(余额 − 在途冻结 ≤ 0)按 error.recharge_url 充值;重试无用
404model_not_priced模型未配置计价系数,平台拒绝放行(不会静默免费)换用 /v1/models 清单内的模型;不可重试
404(无 code)路径拼错或端点不存在核对 Base URL 是否以 /v1 结尾、路径拼写

上游或网络环节产生的错误:

HTTP含义客户端应对
5xx上游模型服务故障或平台异常带 X-Cy-Request-Id 报障;可做有限次指数退避重试
平台当前不对数据面限流:不会返回 429,响应头也不带限流配额。请不要按 429 写重试分支;需要自我约束的是你自己的并发与预算。

准入通过后的每个响应都带 X-Cy-Request-Id 头,报障时请提供它(401 / 402 发生在准入阶段、不带这个头,这两类报错提供 error.code 与发生时间即可)。

402 是唯一「要花钱才能恢复」的信号,不可自愈——重试一万次也没用,去充值。

排障清单

按顺序走,多数问题在前 4 步内定位:

症状先查说明
连接超时 / 拒绝连接Base URL 的主机与端口与运营方确认地址;确认出口防火墙放行
404(无 error.code)Base URL 是否以 /v1 结尾见 Base URL 一节的拼错对照表
401 missing_api_keyAuthorization 是否没带,或 Bearer 写成了小写平台只认精确的 Bearer 前缀(含一个空格)
401 invalid_api_key密钥是否完整、是否已被吊销复制时被截断是高发原因
402 insufficient_creditsGET /v1/credits/balance 看 available_credits充值后数秒自动恢复;不要重试
404 model_not_priced模型名是否在 GET /v1/models 清单里不在 = 未上架或未配价,换清单内模型
余额数字没立刻变结算周期(≤5 分钟,峰值约 15 分钟)流水与余额都是已结算口径,稍等再看
流式没有逐字输出curl 是否带 -N、客户端是否禁用了缓冲见流式输出一节
5xx记下 X-Cy-Request-Id带它报障,运营方据此查平台日志
报障时请一并提供:X-Cy-Request-Id(若响应里带)、HTTP 状态码、error.code、发生时间(含时区)、模型名。不要提供密钥明文。

变更与支持

  • 本文档随平台更新。协议层面向后兼容:新增能力不会改变既有端点的请求/响应结构;
  • 错误 message 文案可能调整,请始终按 HTTP 状态码 + error.code 分支;
  • 模型目录与价目会随运营调整变化,请以 GET /v1/models 与 GET /v1/prices 的实时返回为准,不要硬编码;
  • 套餐、充值与单价的调整见门户定价页,或联系运营方。