# 苏岛代理充值 API v1 接口地址:`https://zovotao.aishoppi.com/api/v1` 在线文档:https://zovotao.aishoppi.com/docs/api OpenAPI 文件:https://zovotao.aishoppi.com/docs/openapi.json 本接口供代理服务器使用:持有有效 API Key 和苏岛签发的 `SD-` 卡密,完成账号确认、充值申请及订单查询。套餐和地区固定在卡密内,代理不能覆盖。API Key 不提供发码、付款卡管理、平台余额或其他代理订单的访问权限。只支持本文列出的本站自有码。 ## 1. 获取 API Key 由站主登录 `https://zovotao.aishoppi.com/`,进入“代理 API”,填写代理名称并点击“生成 API Key”。完整密钥只显示一次,可下载后私密交付对应代理。不要交付站主管理密码。密钥丢失时,由站主对原代理执行“重置密钥”;原订单归属保留,旧密钥立即失效。不要重新创建一个代理来代替原代理,否则新身份不能查询原代理订单。 每次请求携带以下请求头: ```http Authorization: Bearer sk_sd_你的密钥 Content-Type: application/json Accept: application/json ``` 密钥只保存在代理服务器。不要放进网页 JavaScript、URL、客户端安装包、聊天群或日志。接口不开放跨域浏览器调用,也不使用后台登录 Cookie 作为 API 凭据。 ## 2. 套餐、地区与卡密 | plan | 套餐名称 | 卡密套餐标识 | | --- | --- | --- | | plus | Plus 月卡 | PLUS | | go | Go | GO | | pro_5x | Pro100(5x) | PRO100 | | pro_20x | Pro200(20x) | PRO200 | | pro_50x | Pro500(50x) | PRO500 | | country | 地区 | 币种 | 卡密地区标识 | | --- | --- | --- | --- | | PH | 菲律宾 | PHP | PP | | EG | 埃及 | EGP | EG | | CL | 智利 | CLP | CL | 格式示例:`SD-PLUS-PP-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX`。X 为占位符,不是有效卡密。Pro100/200/500 是套餐名称,不代表当地币种报价。能否提交以卡密状态、实时套餐可用性和账号预检结果为准。现有订阅升级或续费不保证适用,请先向站主确认售卖规则。 ## 3. 标准接入流程 1. 调用“校验卡密”,确认套餐、地区和是否未使用。 2. 在用户授权后获取其完整 Session JSON。调用“预览账号”,向用户显示返回的邮箱、套餐和地区。 3. 用户确认后,保存你业务系统的唯一订单号 `client_request_id`,再提交充值。`consent` 必须为 `true`。 4. 保存响应中的 `order_id`,每隔至少 10 秒查询一次,直到 `completed` 或需要人工处理。 5. 提交超时先按原 `client_request_id` 查单。不要换卡密、换请求号或把超时当失败重充。 `session_payload` 是完整 Session JSON 序列化后的**字符串**,不是嵌套 JSON 对象。其中应包含账号邮箱和有效的 `accessToken` 或 `sessionToken`;接口不接收邮箱密码。请求正文最大 70 KiB,Session 字符串最大 64 KiB。预览只做本地账号确认,不是支付成功或上游资格通过的证明。 ## 4. 通用响应与限流 成功响应使用 `code: 0`。HTTP `202` 只表示本地充值申请已受理,可能仍在等待付款卡,不能据此交付“开通成功”。只有订单 `status: completed` 表示充值流程确认完成。 ```json {"code":0,"data":{},"message":"ok"} ``` 错误响应使用非零 `code`;代理应同时检查 HTTP 状态码和 `code`,不要解析中文错误消息判断业务状态。 ```json {"code":"INVALID_API_KEY","data":null,"message":"请提供有效的 Bearer API Key。"} ``` 每个代理密钥每滚动 60 秒最多 60 次请求,其中新建和恢复充值合计最多 10 次。相同请求号的已受理重放不占新建次数,但仍占总请求次数。另有站点 IP 和上游限流。收到 HTTP `429` 时按 `Retry-After` 等待;如响应没有该头,至少等待 30 秒。不要无限并发或密集轮询。客户端超时建议 45 秒。 ## 5. 查询套餐 `GET /products` 无需请求正文。返回 `data.products` 数组,每项包含 `plan`、`name`、`country`、`region_name`、`currency`、`code_prefix`、`enabled`。`enabled` 表示当时的套餐地区配置可用,不保证任何账号或付款卡都能完成支付。 ## 6. 校验卡密 `POST /codes/verify` ```json {"code":"SD-PLUS-PP-完整卡密"} ``` 返回 `valid`、`plan`、`country`、`plan_name`、`status`、`can_redeem`、`order_id`。未使用卡密的 `order_id` 为 `null`;已由当前代理登记的卡密返回原订单号。已由其他代理登记的卡密返回 `404`。此接口不扣费、不消耗卡密、不绑定代理归属。 ## 7. 预览充值账号 `POST /recharges/preview` ```json { "code":"SD-PLUS-PP-完整卡密", "session_payload":"{\"user\":{\"email\":\"user@example.com\"},\"accessToken\":\"用户凭据占位符\"}" } ``` 返回 `email`、`name`、`plan_name`、`plan`、`country`、`confirmation_token`、`expires_in: 300`。请让用户核对邮箱后再提交充值。确认令牌绑定当前代理、卡密及原始 Session 字符串;五分钟内有效。重新预览会替换该代理对这张卡密的旧令牌。服务重启后需重新预览。 ## 8. 提交充值 `POST /recharges` | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | code | string | 是 | 完整 SD 卡密 | | session_payload | string | 是 | 与预览时逐字一致的 Session JSON 字符串 | | confirmation_token | string | 是 | 当前预览返回的确认令牌 | | client_request_id | string | 是 | 当前代理下唯一的业务订单号,8–80 位,仅字母、数字、点、下划线、冒号和短横线 | | consent | boolean | 是 | 用户已确认账号、套餐、地区及凭据转交授权后传 true | ```json { "code":"SD-PLUS-PP-完整卡密", "session_payload":"与预览时完全相同的字符串", "confirmation_token":"预览接口返回值", "client_request_id":"merchant-order-20261104-0001", "consent":true } ``` 成功返回 HTTP `202`,以下仅为示例: ```json { "code":0, "data":{ "order_id":"11111111-1111-4111-8111-111111111111", "client_request_id":"merchant-order-20261104-0001", "status":"waiting_card", "plan":"plus", "country":"PH", "plan_name":"Plus 月卡 · 菲律宾", "account_email":"us***@example.com", "message":"订单已登记,正在等待供货商准备付款卡。", "can_resume":false, "poll_after_ms":10000, "created_at":"2026-11-04T06:30:00.000Z", "completed_at":"", "replayed":false }, "message":"ok" } ``` `order_id` 是本站固定订单号,不是上游订单号。第一次受理后,订单绑定当前代理身份和 `client_request_id`。同一请求号、同一卡密和同一原始 Session 字符串再次提交会返回原订单,并带 `replayed: true`;不会重复付款,已受理后的重放不要求确认令牌仍有效。同一请求号改用其他卡密或 Session 内容返回 `409 IDEMPOTENCY_CONFLICT`。同一卡密换请求号也不会创建第二单。 请求号必须在你的业务数据库中先保存后发送。每笔业务订单使用自己的请求号;网络超时、程序重启、响应丢失后继续使用原号,不要临时重新生成。 ## 9. 查询订单 `GET /recharges/{order_id}` 或者在提交响应丢失时使用: `GET /recharges/by-request?client_request_id=merchant-order-20261104-0001` 两者返回相同订单结构,不包含上游主密钥、客户 Session 或付款卡信息。只允许查询当前代理的订单。请求号包含特殊字符时请做 URL 编码。按请求号暂时查不到不证明上一次请求最终未受理;先等待并保持原请求号核对,必要时联系站主。 | status | 含义 | 代理处理 | | --- | --- | --- | | waiting_card | 已登记,等待处理或付款卡准备 | 保留原单,继续查询 | | needs_account | 尚未付款,需要重新确认同一账号 | 按第 10 节恢复原单 | | submitting | 已开始确认是否被充值服务受理,结果尚未明确 | 继续查询,不能新建补单 | | processing | 充值处理中 | 继续查询 | | completed | 充值流程已确认完成 | 标记成功,停止轮询 | | review | 需要人工核对 | 联系站主,不自动补充付款或换码重充 | 校验卡密接口还可能返回 `unused`。被停用的未使用卡密直接返回错误。失败或人工核对不等于已经退款,不要自行释放卡密或重新付款。 ## 10. 凭据过期后恢复原单 等待订单的账号凭据只在内存保留最多十分钟。超时或服务重启后,尚未付款的订单进入 `needs_account`。从用户处重新取得**同一账号**的 Session,使用原卡密再次调用 `/recharges/preview`,然后提交: `POST /recharges/{order_id}/resume` ```json { "session_payload":"本次重新预览的 Session JSON 字符串", "confirmation_token":"本次预览返回的令牌", "consent":true } ``` 返回 HTTP `202` 和原订单。此接口保留原 `order_id`、请求号及代理归属。已开始支付或已在排队的订单收到重复恢复请求,只返回原进度,不重新付款。新 Session 不要用原 `/recharges` 创建请求重放,需走此恢复接口。 ## 11. 错误处理 | HTTP / code | 说明 | 处理 | | --- | --- | --- | | 401 INVALID_API_KEY | 缺少、错误或已停用的密钥 | 联系站主,核对 Bearer 请求头 | | 400 INVALID_REQUEST_ID | 业务请求号格式无效 | 提交前修正格式 | | 400 CONSENT_REQUIRED | 未传用户确认 | 确认后传 consent: true | | 400 INVALID_SESSION / OWN_CDK_ERROR / ZOVO_ERROR | Session 或卡密参数无效 | 核对参数,错误消息仅供展示 | | 400/404 CDK_UNAVAILABLE | 卡密不可用或不属于当前代理订单 | 核对完整卡密及代理身份 | | 404 ORDER_NOT_FOUND | 当前代理没有可查询的对应订单 | 核对订单号、请求号和密钥身份 | | 409 CONFIRMATION_REQUIRED | 确认令牌过期或 Session 内容改变 | 重新预览;已受理的原单优先查单 | | 409 IDEMPOTENCY_CONFLICT | 请求号已绑定另一份参数 | 查原单,不自动换号重试 | | 409 CDK_IN_USE / RESUME_NOT_ALLOWED | 卡密已登记或不允许恢复 | 查询原单或联系站主 | | 429 RATE_LIMITED / rate_limited | 触发请求限制 | 按 Retry-After 等待 | | 503 或其他 5xx | 暂停、存储或服务异常 | 提交后先按原请求号查单,勿自动换码重充 | 所有写请求超时和 `5xx` 都按“结果待确认”处理。站点代理层的错误可能是 HTML 而非 JSON,请先检查状态和 Content-Type,并保留你自己的请求号。站主停用密钥只阻止后续 API 请求,已受理订单继续处理;请联系站主查询或核对结果。 ## 12. Python 接入示例 此示例只使用 Python 标准库。密钥和卡密通过环境变量读取;`session.json` 为用户提供的完整 Session 对象。请把示例的文件存储替换为业务数据库,并按每笔订单分别保存请求号及原始 Session 字符串;不要把真实凭据、密钥或卡密写入日志。示例不会自动重试充值。 ```python import json import os import urllib.request import urllib.error BASE = "https://zovotao.aishoppi.com/api/v1" API_KEY = os.environ["SD_API_KEY"] def api(method, path, body=None): data = None if body is None else json.dumps(body).encode("utf-8") req = urllib.request.Request(BASE + path, data=data, method=method, headers={ "Authorization": "Bearer " + API_KEY, "Content-Type": "application/json", "Accept": "application/json", "User-Agent": "SudaoAgentIntegration/1.0", }) try: with urllib.request.urlopen(req, timeout=45) as response: payload = json.load(response) except urllib.error.HTTPError as error: # 不输出错误正文、请求头、Session 或完整卡密。 raise RuntimeError("HTTP " + str(error.code) + "; 查询原请求号后处理") from None if payload.get("code") != 0: raise RuntimeError(str(payload.get("code"))) return payload["data"] code = os.environ["SD_CDK"] with open("session.json", encoding="utf-8") as f: session_payload = json.dumps(json.load(f), ensure_ascii=False) # 必须使用已经保存在业务数据库中的该笔订单号。 request_id = os.environ["SD_CLIENT_REQUEST_ID"] verified = api("POST", "/codes/verify", {"code": code}) preview = api("POST", "/recharges/preview", { "code": code, "session_payload": session_payload, }) # 在你的页面向用户展示 preview["email"]、套餐及地区,取得明确确认。 confirmed = input("用户已核对账号、套餐、地区并授权?输入 YES:") == "YES" if not confirmed: raise SystemExit("未提交充值") order = api("POST", "/recharges", { "code": code, "session_payload": session_payload, "confirmation_token": preview["confirmation_token"], "client_request_id": request_id, "consent": True, }) # 将 order_id 保存到业务数据库;至少间隔 10 秒后查询。 print("本站订单号:", order["order_id"], "状态:", order["status"]) # api("GET", "/recharges/" + order["order_id"]) ``` 提交超时的恢复示例(仍使用原请求号): ```python from urllib.parse import urlencode order = api("GET", "/recharges/by-request?" + urlencode({ "client_request_id": request_id, })) ``` ## 13. 范围与验收 接口不提供代理余额充值、自动采购卡密、自动开卡、代理之间转移订单或回调通知;订单结果使用轮询获取。代理 API 本身不额外扣取代理余额,站主与代理的供货结算按双方约定。卡密生成不发起充值;执行充值时实际服务费及订阅费用由站主配置的充值账户承担。 接入后先验证鉴权、套餐、无效卡密及查单错误处理。真实卡密提交会触发真实充值,请使用明确授权的测试账号和一张指定测试卡密。模拟测试、HTTP 202 和能够选卡都不能代替真实充值成功验收。