订阅平台对接
概述
这份文档面向需要把订阅服务和 zeoapi 打通的后端工程师。如果你的产品按月或按年向用户出售模型调用额度,zeoapi 提供一组接口,让你在用户开通套餐时自动发放 API key,每个账单周期到期时自动重置额度并延长有效期。
整套对接由四个接口完成:创建 key、续期、查询、删除。zeoapi 不持有你的订阅状态,也不参与计费决策;何时发放、何时续期、何时停发,完全由你这边的订阅系统决定。
业务流程图
你的订阅平台 zeoapi 服务
───────────── ───────────────
用户开通 Pro 套餐 ───► 1. 创建 API key
2. 写入月度额度
3. 返回 sk-... 给你
│
▼
你将 sk-... 安全交付给最终用户
每月续期日 ───► 重置该 key 额度,延长有效期
(同一把 key 跨月持续可用)
用户取消订阅 ───► 停止续期任务
key 在当前 expired_time 后自动失效
准备工作
选择凭证模式
调用 zeoapi 管理接口需要一组凭证,本文统称为「凭证 A」(access_token,作为 Authorization 头)和「凭证 B」(用户 ID 整数,作为 New-Api-User 头)。两者必须配套使用。
凭证有两种来源:
A. 个人模式
适合自营服务、个人开发者、小型团队。
- 登录 zeoapi 控制台,进入「个人设置」,切换到「安全设置」选项卡,点击生成「系统访问令牌」(即本文的凭证 A)。「个人信息」选项卡可以看到你的用户 ID(即凭证 B)
- 创建出来的所有 API key 归你的账号名下
- 调用频次:当前对个人模式和服务账号模式的管理类接口调用都保持宽松策略,正常的开通、续期、批量补单场景不会遇到限流。请合理使用,避免短时间内单出口 IP 的极端峰值流量(例如每秒数百次的持续请求)
B. 服务账号模式
适合与 zeoapi 有 B2B 合作的合作伙伴。
- 由 zeoapi 团队配发一组专用 access_token 和用户 ID
- 更宽松的调用容量与优先技术支持,适合成批处理大量租户
- 通过现有合作渠道申请
两种模式的接口调用方式完全一致,本文示例可以直接套用,只需替换为你拿到的实际凭证即可。
如怀疑凭证泄露:个人模式可在控制台「个人设置 → 安全设置」中立即重置系统访问令牌,旧值会同步失效;服务账号模式请通过原合作渠道申请重置。
接入端点
所有请求都发往 https://www.zeoapi.com。建议在你的项目中以环境变量集中配置 base URL,并通过域名访问,不要直接连 IP。
Key 命名约定
zeoapi 不强制 key 的命名格式。推荐使用以下结构,便于后续调试与对账:
ext:<tenant_id>:<tier>:<YYYY-MM>
| 字段 | 说明 | 示例 |
|---|---|---|
tenant_id | 你系统中的租户/客户 ID,限 25 字符以内,建议只用字母、数字、.、-、_ | acme-7 |
tier | 订阅档位,限 10 字符以内 | pro |
YYYY-MM | 该 key 首次创建的年月,续期时不变 | 2026-07 |
完整示例:ext:acme-7:pro:2026-07。这样命名后,tenant_id + YYYY-MM 在你的数据库中刚好可作为该 key 的天然主键。
TIP
对接多个产品线(多个 tier)或多套环境时,建议在 tenant_id 中加上区域或环境前缀,例如 cn-acme-7、global-acme-7,方便后期做数据隔离。
流程一:开通时发放 API key
在用户首次支付成功后,按以下四步发放 key。
确定 key 的名字和初始额度
按上一节推荐格式生成 name。额度单位是 quota,1 USD ≈ 500,000 quota。例如月套餐售价 300 美元时,remain_quota 写 150,000,000。
创建 key
POST /api/token/。响应不包含新 key 的 ID,需要在下一步用搜索接口取回。
curl -fsS -X POST "https://www.zeoapi.com/api/token/" \
-H "Authorization: 凭证 A" \
-H "New-Api-User: 凭证 B" \
-H "Content-Type: application/json" \
-d '{
"name": "ext:<tenant_id>:<tier>:<YYYY-MM>",
"remain_quota": 150000000,
"expired_time": 1893456000,
"unlimited_quota": false,
"group": "default",
"model_limits_enabled": false
}'
成功响应:
{ "success": true, "message": "" }
取回 key 的 ID
用 GET /api/token/search 按名字反查。keyword 走模糊匹配,把名字 URL 编码后两侧各加一个 %。
curl -fsS "https://www.zeoapi.com/api/token/search?keyword=%25ext%3Aacme-7%3Apro%3A2026-07%25" \
-H "Authorization: 凭证 A" \
-H "New-Api-User: 凭证 B"
响应中 data.items[0].id 即是 key 的 ID。把它和你自己的 tenant_id 一起持久化到数据库,后续续期和查询都靠它定位。
取出原始 key 并拼出 sk- 前缀
POST /api/token/<token_id>/key 取出 48 位十六进制原始 key。zeoapi 不会重复返回这个值,错过后只能重建。建议在开通时一次取好,不要反复调用。
curl -fsS -X POST "https://www.zeoapi.com/api/token/<token_id>/key" \
-H "Authorization: 凭证 A" \
-H "New-Api-User: 凭证 B"
响应:
{ "success": true, "data": { "key": "ab12cd34ef56..." } }
在前面拼上 sk- 前缀,得到最终交给最终用户的 Bearer key:
sk-ab12cd34ef56...
把它通过安全通道交付给用户。当前策略下该接口对合理使用无严格频次限制,但仍建议在开通流程中一次性取出并妥善保存,避免重复调用。
WARNING
zeoapi 对单次写入的 remain_quota 设有上限(远高于常见月度套餐金额)。如果你的业务场景需要更高额度(例如企业版套餐),请通过支持渠道协商。
流程二:每月自动续期
在你的账单周期任务中触发续期(按月底或按用户开通日 + 30 天均可)。
生成幂等键并发起续期
幂等键是你为本次续期生成的唯一标识。推荐格式:
ext:<tenant_id>:<tier>:cycle-<N>
N 是该用户的续期次数(首次开通 N=1,第二次开通 N=2,依此类推)。zeoapi 用这个键去重:同一个 idempotency_key 反复调用,返回的始终是首次成功时记录的额度和有效期,请求体中后改的值不会被采纳。这让你可以在网络抖动时安全重试。
curl -fsS -X POST "https://www.zeoapi.com/api/token/external/renew" \
-H "Authorization: 凭证 A" \
-H "New-Api-User: 凭证 B" \
-H "Content-Type: application/json" \
-d '{
"token_id": 12345,
"set_remain_quota": 150000000,
"set_expired_time": 1893456000,
"idempotency_key": "ext:acme-7:pro:cycle-2"
}'
首次调用的成功响应:
{
"success": true,
"data": {
"token_id": 12345,
"name": "ext:acme-7:pro:2026-07",
"remain_quota": 150000000,
"expired_time": 1893456000,
"status": 1,
"idempotent_replay": false
}
}
校验响应字段
每次调用后请关注三个字段:
success:必须为true,否则本次额度未生效。idempotent_replay:若为true,表示 zeoapi 已处理过相同的idempotency_key,本次返回的是首次结果,本次请求体中的额度与有效期不会覆盖原值。这是预期行为,常见于网络重试或任务重复触发。remain_quota/expired_time:与你目标值是否一致。同一幂等键反复调用,这两个字段始终保持首次结果。
处理异常与重试
续期是单次原子操作:额度、有效期、审计记录要么一起写入,要么全部回滚,不存在中间状态。重试是安全的。
建议你的任务实现以下行为:
- 网络断开 / 5xx / 超时:用相同
idempotency_key重试,直到收到响应。idempotent_replay: true不是错误。 - 校验失败(
success: false):通常是请求体本身的问题(额度超限、过期时间不合法等),重试同一请求不会改变结果。修正参数后用新的idempotency_key(即cycle-N+1)再发起一次。 - 鉴权失败(HTTP 401):凭证 A 或 凭证 B 错误或失效。个人模式可在控制台「个人设置 → 安全设置」核对或重新生成系统访问令牌;服务账号模式请通过合作渠道核实。
- 找不到 key(HTTP 200 +
success: false):通常是token_id错了,或这把 key 已在 zeoapi 中删除。请用 search 接口重新定位。
流程三:用户取消订阅
推荐做法是停止续期任务,不调用任何接口。这把 key 会在当前 expired_time 自然失效,之后所有调用会被 zeoapi 直接拒绝。这种方式不会引入额外的状态同步,是大多数订阅产品默认的处理方式。
如果业务场景需要立即停发(例如已退款、用户主动停用),可以调用 DELETE /api/token/<token_id>:
curl -fsS -X DELETE "https://www.zeoapi.com/api/token/12345" \
-H "Authorization: 凭证 A" \
-H "New-Api-User: 凭证 B"
调用成功后该 key 立即失效,之后的请求会被拒绝。该操作不可由你这边自助恢复,请在确认要永久停止访问时再使用。
流程四:查询用量(可选)
zeoapi 提供两种查询方式,覆盖不同场景。
由最终用户用 sk-key 自查
适合在你产品的用户中心或 dashboard 里展示「本月剩余」。最终用户用自己的 sk-key 即可,无需用到你的凭证 A / 凭证 B:
curl -fsS "https://www.zeoapi.com/api/usage/token/" \
-H "Authorization: Bearer sk-abc123..."
返回:
{
"code": true,
"data": {
"total_available": 150000000,
"expires_at": 1893456000
}
}
WARNING
URL 末尾的斜杠 /api/usage/token/ 必须保留。漏写时 zeoapi 会以 301 重定向到带斜杠的版本,curl 在没有 -L 选项时不会跟进重定向,看起来像「响应为空」。
这个查询走最终用户的 sk-key 鉴权,不计入凭证 A / 凭证 B 的速率配额,因此可以放心暴露给前端 dashboard 高频调用。
由你用凭证 A / 凭证 B 查询
适合做月度对账或跨租户报表。返回字段比上面更全,包含已用额度、剩余额度、状态、过期时间、分组、模型限制等:
curl -fsS "https://www.zeoapi.com/api/token/12345" \
-H "Authorization: 凭证 A" \
-H "New-Api-User: 凭证 B"
错误处理
zeoapi 的业务类失败(参数校验、资源不存在等)一律返回 HTTP 200 + 响应体中 success: false。只有鉴权失败会返回 HTTP 401。请你的代码读 success 字段判断结果,不要只依赖 HTTP 状态码。
WARNING
关于速率限制:当前对个人模式和服务账号模式的管理类接口调用保持宽松策略,常见的月度续期、开通时取 sk-key、批量初始化等场景都可以正常运行。但请合理使用——避免同一出口 IP 每秒数百次的持续洪流请求。如果你的业务需要长期大量并发调用(例如同时对上千租户执行操作),请通过合作渠道提前告知运营方,以便协调容量。若未来因异常流量导致策略收紧,运营方会通过合作渠道通知。
常见错误的处理建议:
| 类别 | 触发条件 | 处理方式 |
|---|---|---|
| 参数校验失败 | remain_quota 或 expired_time 超限 / 格式错误,idempotency_key 为空或过长 | 修正请求体,并使用新的幂等键再次调用 |
| 凭证失效 | Authorization 头错误或已被吊销 | 个人模式:在控制台「个人设置 → 安全设置」重新生成系统访问令牌;服务账号模式:通过合作渠道申请重置 |
| 用户标识不匹配 | New-Api-User 头与凭证 A 不配对 | 检查 New-Api-User 是否就是凭证 A 对应账户的用户 ID |
| 资源不存在 | token_id 错误,或这把 key 不属于你的账户 | 用 search 接口重新定位 token_id |
| 速率限制(HTTP 429) | 极端峰值流量(同一出口 IP 每秒数百次的持续请求) | 退避重试。持续大批量需求请通过合作渠道协商 |
最佳实践
- 凭证保密。凭证 A / 凭证 B 必须放在环境变量或密钥管理服务中,不要写入代码或配置文件,不要下发给最终用户。定期轮换;个人模式可在控制台自助轮换,服务账号模式通过合作渠道处理。
- 幂等键不可修改。同一笔续期重试时,必须保持完全相同的
idempotency_key(包括cycle-N中的N)。修改幂等键意味着发起一笔新的续期,会被记入新的审计行。 - 取消订阅优先走自然过期,避免使用
DELETE。DELETE不可由你自助恢复,仅在确认永久停发时使用。 - 命名规范有助于排障。建议所有 key 都按
ext:<tenant_id>:<tier>:<YYYY-MM>命名,便于在控制台搜索和与你自己的数据库对账。 - 额度换算函数化。
quota = dollars × 500_000这类换算只在一处实现,避免散落多处导致单位混淆。 - 月度任务做错峰、重试和告警。避免所有租户在每月 1 号同时触发;失败请重试,连续失败时触发人工介入。
- 区分凭证用途。最终用户拿到的始终是他自己的 sk-key;凭证 A / 凭证 B 只在你的服务端使用,不应出现在前端、客户端 SDK 或最终用户能接触到的任何地方。
完整示例
以下是从开通到首次续期再到用量查询的端到端 bash 脚本。替换 <...> 占位符后即可运行。
#!/usr/bin/env bash
set -euo pipefail
# ===== 配置 =====
ZEO_BASE="https://www.zeoapi.com"
ZEO_TOKEN="<凭证 A>" # 你的 access_token
ZEO_USER="<凭证 B>" # 你的用户 ID(整数)
TENANT_ID="<your-tenant-id>" # 例如 acme-42
TIER="pro"
YYYY_MM=$(date +%Y-%m)
NAME="ext:${TENANT_ID}:${TIER}:${YYYY_MM}"
CYCLE=1 # 首次开通算第 1 次
# 1 USD = 500,000 quota;以 300 美元月套餐为例
QUOTA=150000000
EXPIRY=$(( $(date +%s) + 30*86400 )) # 30 天后
# ===== 1. 开通时创建 key =====
echo ">>> 创建 key: ${NAME}"
curl -fsS -X POST "${ZEO_BASE}/api/token/" \
-H "Authorization: ${ZEO_TOKEN}" \
-H "New-Api-User: ${ZEO_USER}" \
-H "Content-Type: application/json" \
-d "{\"name\":\"${NAME}\",\"remain_quota\":${QUOTA},\"expired_time\":${EXPIRY},\"unlimited_quota\":false,\"group\":\"default\",\"model_limits_enabled\":false,\"allow_ips\":\"\"}"
# ===== 2. 用 search 接口取回 token_id =====
echo ">>> 取回 token_id"
TOKEN_ID=$(curl -fsS "${ZEO_BASE}/api/token/search?keyword=%25$(printf %s "$NAME" | jq -sRr @uri)%25" \
-H "Authorization: ${ZEO_TOKEN}" \
-H "New-Api-User: ${ZEO_USER}" \
| jq -r ".data.items[] | select(.name == \"${NAME}\") | .id" | head -n1)
echo "TOKEN_ID=${TOKEN_ID}"
# 把 TOKEN_ID 与 tenant_id 一起持久化到你的数据库
# ===== 3. 取出原始 key 并拼出 sk- 前缀 =====
SK_KEY="sk-$(curl -fsS -X POST "${ZEO_BASE}/api/token/${TOKEN_ID}/key" \
-H "Authorization: ${ZEO_TOKEN}" \
-H "New-Api-User: ${ZEO_USER}" \
| jq -r .data.key)"
echo "Subscriber sk-key: ${SK_KEY}"
# 通过安全通道把 SK_KEY 交付给最终用户
# ===== 4. 一个月后:续期 =====
sleep 1 # 实际场景:放在月度任务里
CYCLE=$((CYCLE + 1))
NEW_EXPIRY=$(( $(date +%s) + 30*86400 ))
IDEM_KEY="ext:${TENANT_ID}:${TIER}:cycle-${CYCLE}"
echo ">>> 续期 cycle=${CYCLE} idempotency_key=${IDEM_KEY}"
curl -fsS -X POST "${ZEO_BASE}/api/token/external/renew" \
-H "Authorization: ${ZEO_TOKEN}" \
-H "New-Api-User: ${ZEO_USER}" \
-H "Content-Type: application/json" \
-d "{\"token_id\":${TOKEN_ID},\"set_remain_quota\":${QUOTA},\"set_expired_time\":${NEW_EXPIRY},\"idempotency_key\":\"${IDEM_KEY}\"}" \
| jq
# ===== 5. 用户侧自查(用 sk-key,不用凭证 A/B)=====
echo ">>> 用户用 sk-key 自查"
curl -fsS "${ZEO_BASE}/api/usage/token/" \
-H "Authorization: Bearer ${SK_KEY}" | jq
把第 1 至 3 步接入「用户开通成功」回调,把第 4 步接入月度任务,第 5 步可作为前端 dashboard 展示数据来源。订阅 + 用量两条主链路就接通了。
联系与支持
下列情况欢迎通过支持渠道联系 zeoapi 团队:
- 个人模式凭证:登录 zeoapi 控制台「个人设置 → 安全设置」自助生成系统访问令牌,无需联系
- 服务账号模式凭证申请,或 B2B 合作洽谈
- 单次额度上限超出默认值的协商
- 速率限制超出默认配额的协商
- 出口 IP 白名单或来源限制
- 接口返回了未在本文档列出的错误,或者最终用户报告无法调用
反馈时请提供:tenant_id、调用时间、请求 ID(如有)以及响应体原文。这些信息能显著加快排查。
本文档随 zeoapi 接口变化更新。如果实际响应与本文不一致,请以接口实际返回为准,并通过支持渠道反馈。