Plus API 完整接入手册
版本 v1 · 错误契约增补日期 2026-09-21。本手册只描述客户接口,不公开内部执行实现。
1. 地址、范围与接入准备
- 服务地址:
https://api.666666.homes。 - 客户自助中心:用 API Key 登录、兑换积分、管理私人银行卡、查看订单。
- 在线文档。
- 仅 ChatGPT Plus;不包括 Pro、5x 等升级产品。客户提供已获授权的完整 Session 和银行卡。
- 本域名是正式接口,不是测试沙箱。示例及离线测试不授权真实付款。
- 接口已发布;实时执行容量不足返回
503 execution_not_ready,并非保证随时有名额。 - OpenAPI YAML / OpenAPI JSON 可导入 Postman、Apifox。
- Python 客户端 / 回调验签示例;默认示例只查余额,不会自动付款。
接入顺序
管理员开户并发放 API Key → 兑换积分 → 查询账户
用户输入 Session / 卡资料 → 创建预检 → 保存预检 ID 和到期时间
用户明确点击确认付款 → 提交原预检 → 保存订单 ID
查询原单 / 接收签名回调 → 显示明确结果 → 成功后另取账单
预检不授权付款;只有用户明确确认后的订单提交才授权执行。预检 queued/preparing 时也能提交原预检,不要求顾客重复输入或重新创建。
2. 认证与公共约定
所有 /v1/ 接口均需服务端请求头:
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Key 是本服务密钥,不是 Session accessToken,也不是支付平台公钥,即使其前缀是 pk_live_ 也不能混用。URL 中的 api_key 不被接受;自助页 Cookie 不能代替 Bearer。不要把 Key 放进公开网页、客户端源码、截图、Git 或日志。
| 项目 | 契约 |
|---|---|
| 编码 | UTF-8 JSON;写请求体必须是对象,不接受未知字段 |
| 成功包装 | 直接返回对象,无统一 data/ok 包装 |
| 成功 HTTP | 创建、确认、兑换均为 200,不是 201/202 |
| 错误 | {"error":{"code":"invalid_api_key"}};网络边缘错误可能返回非 JSON |
| 时间 | Unix 秒,可有小数;前端日期转换乘 1000 |
| 尚未记录时间 | null,不是耗时 0 秒 |
| request_id | 8–128 字符,只允许字母、数字、下划线、点、冒号、短横线 |
| 幂等范围 | 同一客户;预检和订单分别计算。建议 pf-UUID / order-UUID |
| 普通请求体上限 | 8,192 字节 |
| 预检请求体上限 | 98,304 字节;其中 Session 字符串 20–65,536 UTF-8 字节 |
| 压缩请求体 | 不支持 gzip 等压缩格式 |
| 跨域调用 | 推荐客户服务端调用,不把 Bearer 暴露给浏览器 |
HTTP 200 仅表示请求成功,必须查看订单 status 才能判断充值结果。
3. 全部接口
| 方法 | 路径 | 用途 |
|---|---|---|
| GET | /v1/account | 账户与积分 |
| GET | /v1/cards | 当前 Key 的私人卡池 |
| POST | /v1/cards/import | 批量导入自己的银行卡 |
| POST | /v1/cards/{card_id} | 调整次数、暂停或删除私人卡 |
| POST | /v1/credits/redeem | 兑换积分卡密 |
| GET | /v1/credits/ledger | 积分流水 |
| POST | /v1/preflights | 提前准备,不付款 |
| GET | /v1/preflights/{preflight_id} | 预检状态及期限 |
| POST | /v1/orders | 顾客确认后正式提交 |
| GET | /v1/orders | 最近 50 条订单 |
| GET | /v1/orders/{order_id} | 原单状态与进度 |
| GET | /v1/orders/{order_id}/invoice | 成功后的账单 |
| GET | /v1/webhook | 查询回调配置 |
| POST | /v1/webhook | 设置回调并生成/轮换签名密钥 |
| DELETE | /v1/webhook | 关闭回调 |
没有客户生成积分、付款撤销、预检续期/取消、强制释放未知结果、手工重放回调接口。私人卡池不提供自动开卡或平台卡借用。
4. 账户与积分
GET /v1/account
curl --fail-with-body "https://api.666666.homes/v1/account" \
-H "Authorization: Bearer $PLUS_API_KEY"
{"id":"cus_example","name":"示例客户","balance":10,"frozen":2,"available":8,"concurrency":4}
| 字段 | 类型 | 含义 |
|---|---|---|
| id | string | 客户 ID,不是 Key ID |
| name | string | 管理员登记的名称 |
| balance | integer | 总积分,包含冻结 |
| frozen | integer | 在途和待核对订单的冻结积分 |
| available | integer | 可用积分,balance - frozen |
| concurrency | integer | 客户并发上限,非实时保证可用名额 |
多个 Key 共用该客户的积分、订单和限流额度,不会增加并发。但银行卡池严格按具体 Key 隔离,同一客户另一个 Key 也不能读取或选取这些卡。
结算规则
预检要求 available 至少为 1,但不扣、不冻结积分。正式订单接受后冻结 1 积分;充值成功只扣 1 积分;明确失败释放冻结;review 继续冻结,不能理解成已扣积分或未扣款。
充值成功后,账单和取消自动续费处理异常不改变成功,不额外扣积分。积分是服务次数,不是美元或银行卡金额。
当前 Plus 路线付款前要求 PHP 982.14(最小单位整数 98214);公开请求不接受覆盖金额、币种或产品的字段,不能关闭金额校验。
POST /v1/credits/redeem
请求:
{"code":"PC-YOUR-CREDIT-VOUCHER"}
首次返回:
{"credits":10,"already_redeemed":false}
同一客户重复兑换返回 already_redeemed=true,不重复入账;其他客户已兑换返回 409 voucher_already_redeemed。code 为 10–128 字符,服务端会去首尾空白并统一大写。兑换响应没有 balance,请另查账户。
GET /v1/credits/ledger
首次无参数,后续 ?before=上一页最后一条id。每页最多 50 条,id 倒序,空数组表示查完。没有 page/limit 参数。
{"entries":[{"id":12,"kind":"consume","reference":"ord_example","balance_delta":-1,"frozen_delta":-1,"balance_after":9,"frozen_after":0,"created_at":1789700030.5}]}
| kind | balance_delta | frozen_delta | 含义 |
|---|---|---|---|
| redeem | +N | 0 | 兑换入账 |
| freeze | 0 | +1 | 正式接单冻结 |
| consume | -1 | -1 | 成功结算 |
| release | 0 | -1 | 明确失败释放 |
reference 为兑换记录或订单标识,不返回卡密明文。流水不可由客户修改。
4.1 私人银行卡池
用当前 API Key 登录客户中心,在“我的银行卡”点击“导入银行卡”。输入、粘贴或修改资料后自动识别,无需点击识别按钮;核对尾号、有效期与成功次数上限后,只需点击“确认导入”。网页支持整段复制的“卡号、过期时间、CVV”等分行标签,以及全角数字、分组卡号和多张卡;也支持 卡号----月份----年份----安全码、卡号 月份/年份 安全码。年份可为两位或四位。网页识别后会先转为下述标准接口格式再提交;直接调用导入API仍应遵循其行格式。缺失或歧义资料必须修正,不会从下一张卡借用有效期或安全码。
卡片按尾号或有效期搜索、按状态筛选,默认每页 10 张,可切换为 20 或 50 张。列表独立滚动,具体次数调整、暂停、启用和删除均在该卡的“管理”弹窗完成;使用中或待核对卡不可修改。订单与积分兑换在独立导航页,不挤占卡片列表。退出时清空页面中的卡片输入和列表,不写入浏览器本地缓存。
POST /v1/cards/import
{"text":"YOUR_CARD_NUMBER 12/2029 YOUR_CVC","use_limit":5}
text 为字符串,每行一张,最多100张/32768字符,请求体最多65536字节。use_limit 可选,默认5,允许1–1000整数,表示每张卡总成功次数上限,不是金额额度。过期或非法行导致整个批次不导入。一个 Key 最多保存500张未删除卡。
{"added":2,"duplicates":1}
同一个 Key 重复导入同一卡号不会覆盖材料、上限、计数或占用;超时后可查询卡池或重复原导入,不会重复加卡。删除后再导入仍保留历史成功次数。只导入你有权使用的银行卡,不要把资料写入 URL、日志或公开截图。
GET /v1/cards
{"cards":[{"id":"pcard_0123456789abcdef0123456789abcdef","last4":"1234","expiry":"2029-12","use_limit":5,"success_count":1,"version":3,"remaining":4,"status":"available"}]}
不会返回完整卡号或安全码。状态:available可用;occupied使用中或待核对/清理;paused已暂停;expired已过期;exhausted次数已用完。remaining为次数余额,不代表当前卡一定空闲。
POST /v1/cards/{card_id}
传最新列表中的 version 防止旧页面覆盖新状态。use_limit、enabled、delete按需传入;occupied卡禁止修改、删除。
{"version":3,"use_limit":8}
{"version":3,"enabled":false}
{"version":3,"delete":true}
成功均返回 {"ok":true}。上限不得小于已经成功的次数。成功只计一次;取消续费/账单失败不退次数;明确未付款失败不扣;结果未知保持占用。没有强制解锁接口。
常见错误:no_available_private_card(409,当前Key没有可用卡,请补卡/等待占用结束);private_card_not_found(404,不属于当前Key或已删除);private_card_in_use(409,暂不可修改);card_version_conflict(409,刷新后再操作);card_limit_below_used(409,上限小于已用次数);expired_card(400);invalid_card_line_N(400,第N行格式有误)。禁止因这些错误换用平台卡或其他人的卡。
5. 预检
POST /v1/preflights
以下是结构模板;占位银行卡不可直接运行:
{
"request_id":"pf-your-unique-uuid",
"session":"{\"accessToken\":\"AUTHORIZED_TOKEN\",\"account\":{\"id\":\"PERSONAL_ACCOUNT_ID\"}}",
"card":{"number":"YOUR_CARD_NUMBER","exp_month":"09","exp_year":"2029","cvc":"YOUR_CVC"}
}
| 字段 | 必填 | 类型及约束 |
|---|---|---|
| request_id | 是 | string,固定的一次逻辑预检标识 |
| session | 是 | 完整 Session JSON 的字符串,不是对象,也不是仅传令牌 |
| card | 否 | 兼容原有逐单自带卡,object,仅下列四项;与card_id互斥 |
| card_id | 否 | 当前Key私人卡池中指定的卡;不能传其他Key或平台卡标识 |
| card.number | 是 | string,12–19 位数字,通过卡号校验;不要加空格 |
| card.exp_month | 传 card 时必填 | string,1–12,建议两位 |
| card.exp_year | 传 card 时必填 | string,四位 20xx,不是两位年份 |
| card.cvc | 传 card 时必填 | string,3–4 位数字,保留前导0 |
Session 需包含有效非空 accessToken 与账号标识(account.id 或现有资料中的 user.id)。请使用用户授权的原始完整 Session,不要根据邮箱自行编造/替换 ID,也不必删除原资料的其他字段。
使用私人卡池时,省略 card 和 card_id 即由当前 Key 的卡池选取一张空闲且剩余次数大于0的卡;也可仅传 card_id 指定自己的卡。缺卡、读取异常或卡在占用时不会借用平台卡,不会自动开卡。原有显式 card 模式仍只使用请求提供的卡,不会从平台取卡。需要卡池次数管理时请使用 card_id 或自动选卡模式。
{"request_id":"pf-your-pool-uuid","session":"AUTHORIZED_COMPLETE_SESSION_JSON_STRING"}
提交、查询这个预检必须继续使用创建时的 Key。同一 request_id 重试返回原分配,不会另外拿卡。
返回:
{"id":"pfapi_example","created_at":1789700000.0,"expires_at":1789700120.0,"order_id":"","status":"queued","error_code":"","customer_message":"","stage":"preflight","retryable":false,"next_action":"wait","cleanup_acknowledged":false,"payment_started":false,"card_consumed":false,"credit_state":"none"}
保存 id 为 preflight_id。当前有效期从创建开始 120 秒,以 expires_at 为准;ready 不延长期限。未正式提交时 order_id 为空字符串,不是 null。
相同 request_id 和相同内容返回原预检,不创建新的、不刷新期限;同 ID 修改资料返回 409 idempotency_conflict。
GET /v1/preflights/{preflight_id}
字段同创建接口。例如:
{"id":"pfapi_example","created_at":1789700000.0,"expires_at":1789700120.0,"order_id":"","status":"ready","error_code":"","customer_message":"","stage":"preflight","retryable":false,"next_action":"submit_order","cleanup_acknowledged":false,"payment_started":false,"card_consumed":false,"credit_state":"none"}
| status | 意义 | 处理 |
|---|---|---|
| queued | 等待准备 | 可在顾客确认后提交原预检 |
| preparing | 准备中 | 不必重建,可确认原预检 |
| ready | 已准备 | 等待顾客确认,不代表付款 |
| adopted | 已接管 | 有 order_id 时查询原订单 |
| cleanup_pending | 安全收尾中 | 不并行重复提交同账号/卡 |
| closed | 已关闭 | 不可再提交 |
| failed | 预检失败 | 未正式提交则不扣积分,修正后重做 |
| expired | 已过期且未接管 | 新预检需要新的 request_id |
预检的公开错误字段、Session 失效和订阅未到期的对应关系,见错误码与处理说明。接口不返回原始异常堆栈、上游正文、Session 或银行卡资料。 若已有 order_id,订单状态优先;不能因为预检时间届满把已提交订单判失败。 card_material_expired 指短期材料无法接管,不是断言银行卡已过期。 资源冲突时先核对原任务;不要用多个 Key 或新 ID 绕过账号/卡互斥。
6. 正式订单
POST /v1/orders
仅在用户明确确认付款后调用:
{"request_id":"order-your-unique-uuid","preflight_id":"pfapi_example","confirmed":true,"allow_fallback":false}
| 字段 | 必填 | 含义 |
|---|---|---|
| request_id | 是 | 固定的一次逻辑提交标识 |
| preflight_id | 是 | 自己的有效、可接管预检 |
| confirmed | 是 | 必须布尔 true;字符串 "true"、数字 1 都不接受 |
| allow_fallback | 否 | 布尔,默认 false,是否授权可用第三方接手 |
第三方接手前,需取得客户对必要 Session/卡资料处理的授权。true 不是所有失败都自动重试的承诺,不绕过未知付款结果限制。此接口无需再次传 Session 或卡资料。
{
"id":"ord_example","request_id":"order-your-unique-uuid","preflight_id":"pfapi_example",
"status":"queued","credit_state":"frozen","created_at":1789700010.0,
"started_at":null,"payment_at":null,"success_at":null,"finished_at":null,
"updated_at":1789700010.0,"result_code":"",
"error_code":"","customer_message":"","stage":"preflight","retryable":false,
"next_action":"wait_result","cleanup_acknowledged":null,"payment_started":false,"card_consumed":null
}
立即持久化 request_id → order_id。响应不含 events;200 只代表接单。queued/preparing/ready 的预检可提交,已完成工作会沿用。
GET /v1/orders/{order_id}
{
"id":"ord_example","request_id":"order-your-unique-uuid","preflight_id":"pfapi_example",
"status":"succeeded","credit_state":"consumed","created_at":1789700010.0,
"started_at":1789700011.0,"payment_at":1789700014.0,"success_at":1789700030.5,
"finished_at":1789700030.5,"updated_at":1789700030.5,"result_code":"",
"error_code":"","customer_message":"","stage":"payment","retryable":false,
"next_action":"none","cleanup_acknowledged":true,"payment_started":true,"card_consumed":true,
"events":[
{"id":101,"kind":"queued","created_at":1789700010.0},
{"id":102,"kind":"paying","created_at":1789700014.0},
{"id":103,"kind":"succeeded","created_at":1789700030.5}
]
}
| 字段 | 含义 |
|---|---|
| status | 业务判断依据,见下表 |
| credit_state | frozen / consumed / released |
| created_at | 正式订单接受时间,不含提前预检 |
| started_at | 正式执行开始,可空 |
| payment_at | 付款阶段记录时间,可空,不单独作为扣款证据 |
| success_at | 充值成功确认时间,可空 |
| finished_at | 终态记录时间,可空 |
| updated_at | 最近状态更新时间 |
| result_code | failed 时 PAYMENT_FAILED;review 时 PAYMENT_UNCONFIRMED;其他通常为空 |
| error_code / customer_message | 公开细分业务错误码与安全顾客文案;正常和成功时为空 |
| stage / retryable / next_action | 公开阶段、当前能否重试及应采取的动作,见错误说明 |
| payment_started / card_consumed | 付款是否开始、本次卡付款是否确认成功;允许 null,不可视为 false |
| cleanup_acknowledged | 资源清理是否确认,与付款和积分分别判断 |
| events | 详情接口的事件数组,按 ID 顺序,供进度展示 |
events.kind 可见 queued/preparing/paying/review/succeeded/failed/invoice_ready。中间阶段可能不齐;缺少某步不等于失败。不要把价格字段缺失或事件跳步当失败。
业务状态与积分
| status | 是否明确终态 | 积分 | 建议文案 |
|---|---|---|---|
| queued | 否 | frozen | 已提交,等待处理 |
| preparing | 否 | frozen | 正在准备 |
| paying | 否 | frozen | 正在确认支付 |
| review | 否,结果不确定 | frozen | 支付结果待核对,请勿重复提交 |
| succeeded | 是 | consumed | 充值成功 |
| failed | 是,确认失败 | released | 充值失败,积分已释放 |
充值成功立即显示成功,不等账单/取消续费。晚到的旧 paying 回调不能覆盖成功。 review 不能显示为失败,也不能允许再次付款;继续查询原单或联系管理员。
GET /v1/orders
返回 {"orders":[...订单摘要...]},最近最多 50 条,创建时间倒序。
摘要字段同 POST 返回,没有 events;目前没有日期、邮箱、page 或 limit 参数。
较早订单用已保存的 order_id 查询详情。不同客户的数据不可互查。
耗时口径
- 提交到成功:success_at - created_at,含队列时间,不含预检。
- 执行到成功:有 started_at 时为 success_at - started_at。
- 顾客点击到看到成功:客户端另记点击/渲染时间,不能混作服务端耗时。
- 接口不承诺固定几秒完成;不要将示例时间理解为 SLA。
7. 超时、幂等与限流
| 场景 | 正确处理 | 禁止做法 |
|---|---|---|
| 创建预检回包丢失 | 保留原 request_id 与完全相同资料,有限重试 | 换 ID 无限建预检 |
| 提交订单超时/5xx | 已有 order_id 则 GET;否则按原 ID/预检/参数恢复同一请求 | 认定未付款后重新建单 |
| 相同 ID 不同内容 | 修正客户端幂等记录 | 不断修改参数碰运气 |
| preflight 已绑定订单 | 查询 preflight.order_id | 再次提交另一订单 |
| GET 超时 | 退避后查原单,保留原状态 | 将网络失败转换为业务 failed |
| review | 原单查询,必要时联系管理员 | 再支付、换渠道再次扣款 |
| succeeded、账单未就绪 | 显示成功,稍后查账单 | 为获取账单重新充值 |
重复相同逻辑提交不会授权第二次付款;这不等于允许重发底层付款确认。 建议连接超时5秒、响应超时20秒;是客户端建议,不是服务端保证。 关闭 HTTP 自动重定向,防止 POST 被隐式重放或密钥被转发外域。 不知道 order_id 时可查最近订单匹配 request_id,但列表只有50条,必须自己持久化映射。
访问频率与容量
每客户读请求 120 次/分钟,写请求 30 次/分钟;来源 IP 另有认证入口 240 次/分钟。 多个 Key 共享客户额度,共享出口可能触发 IP 限制。 单单可每2–3秒查一次,长时间未终结应减速;并发多时用回调加少量兜底查询。 四单每2秒分别查会占满120次/分钟,连账户查询也没有余量,不建议长期如此。
429 rate_limited:降低访问频率、指数退避并加随机抖动。 429 customer_capacity_reached:等待在途任务释放名额,不要密集建单。 不能依赖一定返回 Retry-After。
8. 回调 Webhook
配置、读取、关闭
POST /v1/webhook:
{"url":"https://merchant.example.com/hooks/plus"}
{"url":"https://merchant.example.com/hooks/plus","enabled":true,"signing_secret":"whsec_EXAMPLE_ONLY","generation":1}
仅 HTTPS/443、公网地址;不可含账号密码、片段或指向内网。 保存成功只代表配置接受,不代表已经验证投递成功;实际投递时仍会校验 DNS 和目标地址。 签名密钥只在保存响应显示,请立即安全保存。
再次 POST 会轮换密钥,并非幂等读操作。 配置超时先 GET;无法恢复密钥时有意识地再次配置一次,并查询原订单补齐可能遗漏的通知,不要自动无限重试。
GET /v1/webhook 未配置:{"enabled":false};已配置:
{"url":"https://merchant.example.com/hooks/plus","enabled":1,"generation":1}
兼容 enabled 布尔值或0/1;GET 永不返回 signing_secret。
DELETE /v1/webhook 返回 {"ok":true},可重复关闭,不删除订单/积分。
回调格式
POST /hooks/plus HTTP/1.1
Content-Type: application/json
User-Agent: Plus-API-Webhook/1
X-Event-Id: evt_example
X-Webhook-Timestamp: 1789700031
X-Webhook-Signature: sha256=<64位小写十六进制HMAC>
{
"id":"evt_example","type":"order.updated","created_at":1789700030.5,
"data":{
"id":"ord_example","request_id":"order-your-unique-uuid","preflight_id":"pfapi_example",
"status":"succeeded","credit_state":"consumed","created_at":1789700010.0,
"started_at":1789700011.0,"payment_at":1789700014.0,"success_at":1789700030.5,
"finished_at":1789700030.5,"updated_at":1789700030.5,"result_code":"",
"error_code":"","customer_message":"","stage":"payment","retryable":false,
"next_action":"none","cleanup_acknowledged":true,"payment_started":true,"card_consumed":true
}
}
data 是订单摘要,无 events/Session/卡片/账单 URL。账单就绪也使用 order.updated,订单仍 succeeded,不是 invoice.ready 回调类型。
签名校验
message = UTF8(X-Webhook-Timestamp) + "." + 原始HTTP请求体字节
digest = HMAC-SHA256(UTF8(signing_secret), message)
expected = "sha256=" + digest 的小写 hex
使用原始字节,不要先解析 JSON 再序列化。完整 signing_secret(含 whsec_)作为密钥。 常数时间比较签名,校验 body.id 等于 X-Event-Id。建议接收端容忍时间差不超过300秒,并同步系统时间;此为客户端安全策略。
事件 ID 必须数据库持久化去重。同一事件重投 ID/正文不变,时间戳/签名改变。 可能重复、延迟、乱序;不能让旧事件降级 succeeded,不确定时 GET 原订单。 示例仅负责验签,业务去重与数据库事务由接入方实现。
重试与应答
先将验签成功的事件持久化,再快速回任意2xx,无需特定JSON。约5秒投递超时,耗时业务放后台。 非2xx、超时、网络故障重投;3xx不跟随。 最多8次尝试(首次+7次重试),间隔约1、5、30、120、600、1800、3600秒,实际调度可能更晚。 耗尽不再无限重投,必须保留订单查询兜底。 关闭/重新配置使旧配置待投递通知失效;新配置不保证历史补发。没有公开手工重放接口。
9. 账单下载
GET /v1/orders/{order_id}/invoice:
- 就绪:HTTP 303,Location 指向 HTTPS 账单地址,不返回JSON成功体。
- 未就绪:404
{"error":{"code":"invoice_not_ready"}}。 - 未拥有/不存在订单也可能返回 invoice_not_ready,不泄漏其他客户信息。
- 成功与账单生成分离,没有固定到账单耗时承诺。
关闭自动跳转,读取 Location 后使用不带本 API Bearer的新请求下载,或给已授权客户打开。账单链接也是敏感资料。账单404绝不能触发新一笔充值。
10. 错误码
| HTTP | code | 处理 |
|---|---|---|
| 400 | invalid_json / invalid_fields | 修正JSON和允许字段 |
| 400 | invalid_request_id | 使用规定格式的稳定逻辑操作ID |
| 400 | invalid_session / session_account_missing | 完整授权Session JSON字符串 |
| 400 | invalid_card_fields | 检查卡字符串、年份、月份、CVC格式 |
| 400 | explicit_confirmation_required | 必须用户确认,传布尔true |
| 400 | invalid_voucher | 检查积分卡密,不是银行卡或充值订单卡密 |
| 400 | invalid_page / invalid_https_url | 修正流水游标/回调URL |
| 401 | invalid_api_key | 检查Bearer、Key撤销、客户停用 |
| 402 | insufficient_credits | 预检时余额不足,先兑换 |
| 403 | customer_disabled | 联系管理员,不绕过禁用 |
| 404 | preflight_not_found / order_not_found | 检查ID及客户归属 |
| 404 | invoice_not_ready | 只影响账单,稍后重查 |
| 409 | idempotency_conflict | 相同ID内容变化,核对原请求 |
| 409 | voucher_already_redeemed | 已被其他客户使用 |
| 409 | insufficient_credits | 确认订单时余额不足,预检后余额可能变化 |
| 409 | preflight_already_submitted | 查询已绑定的原订单 |
| 409 | preflight_not_adoptable | 预检过期/关闭/失败等,先查预检 |
| 409 | card_material_expired | 短期材料失效,核对原单后重新准备 |
| 409 | resource_already_in_use / account_already_in_use / card_already_in_use | 原任务占用中,等待安全收尾 |
| 409 | account_recently_paid | 同账号北京时间当日另一笔充值已确认付款。查询原订单,不要换 request_id、卡片或渠道再次充值;本次拒绝不代表原付款失败,也不能把原成功归到新请求。跨天续费仍按原账号资格流程处理;正在付款或付款未知不会因跨天解锁。 |
| 413 | request_too_large | 请求体超过上限 |
| 415 | json_required / compressed_body_not_supported | 使用非压缩application/json |
| 429 | rate_limited | 降低请求频率并退避 |
| 429 | customer_capacity_reached | 等待在途任务释放容量 |
| 503 | execution_not_ready / secure_handoff_capacity | 暂无可接单资源,已有订单查原单 |
| 503 | open_api_not_enabled | 服务暂未开放,联系管理员 |
未知code保留脱敏HTTP状态、code、request_id、order_id和时间,请管理员核查。 HTTP/网络错误不是支付证据,不能直接转为业务 failed。
10.1 业务错误码与处理说明
适用:https://api.666666.homes 的 Plus API v1;契约增补日期 2026-09-21。可将本文件直接交给负责对接的开发者。完整端点、鉴权、参数、幂等和回调见接入手册,在线地址为 API 文档。
先分清两种返回
请求错误:HTTP 非 2xx,读取 error.code,例如 invalid_api_key、invalid_session、preflight_not_adoptable。含义是这次接口请求没有按要求完成;不能由此推断某个已有订单未付款。
业务结果:预检或订单查询通常返回 HTTP 200,读取顶层 status、error_code 和 next_action。HTTP 200 下仍可能是预检失败、Session 失效或订单结果待核对。对接端不要只看 HTTP 状态,也不要匹配中文文案或内部异常类名。
同步 invalid_session 表示提交的 Session 结构不合规;异步 SESSION_INVALID 表示执行中已得到登录凭据无效/过期的明确结果。两者都应引导客户提供有效 Session,但不能把一次超时或普通 403 页面自动归为 SESSION_INVALID。
公开业务字段
以下字段添加在预检和订单对象顶层。原字段、原状态和订单 result_code 保留;接入方应兼容以后增加的新字段和新错误码。
| 字段 | 类型 | 准确含义 |
|---|---|---|
| status | string | 预检/订单的流程状态,决定是否完成;两类对象状态集合不同 |
| error_code | string | 可稳定匹配的公开业务错误码;正常处理中、预检 ready、订单成功时为空字符串 |
| customer_message | string | 可给顾客显示的安全文案;措辞可能改进,不用它做程序判断 |
| stage | string | 出错或当前所在的公开阶段;不是完整的内部执行轨迹 |
| retryable | boolean | 当前结果是否允许按 next_action 重新发起相应业务操作;不授权重发付款确认 |
| next_action | string | 接入端应该采取的动作,见下表 |
| cleanup_acknowledged | boolean 或 null | true 表示相关资源清理已确认;false 表示未确认;null 表示当前对象没有可靠清理结论 |
| payment_started | boolean 或 null | 是否进入过付款处理;true 不等于已扣款,null 不可当作 false |
| card_consumed | boolean 或 null | 本服务对本单的银行卡成功使用标志;不是积分、余额、剩余次数或发卡方交易查询结果。未知为 null |
| credit_state | string | 预检未建订单为 none;关联订单为 frozen、consumed 或 released,指本服务积分。关联订单暂无法读取时为 unknown,不能按未扣积分处理 |
| result_code | string | 仅订单保留的旧分类:failed 为 PAYMENT_FAILED,review 为 PAYMENT_UNCONFIRMED,其余为空;细分原因读取 error_code |
card_consumed=false 不代表卡可立即重新使用;还必须看清理状态和原订单。银行卡实际账务最终以发卡方记录为准。credit_state=released 仅表示服务积分已解冻,不能替代银行卡结果证据。
未正式提交的预检没有付款授权,不扣也不冻结积分;预检 ready 只表示准备完成,绝不是付款成功。预检一旦带非空 order_id,立即改查该原订单;预检过期或关闭不能覆盖订单结果。
业务错误码对应表
| error_code | 表示什么 | 顾客/接入端应如何处理 |
|---|---|---|
| SESSION_INVALID | 已明确确认 Session 无效或过期 | 提示“Session 已失效,请重新登录账号后重试”;换有效 Session,在原流程安全结束后创建新预检 |
| GRACE_SESSION_REFRESH_REQUIRED | 已识别宽限期,续费此前已关闭或已尝试发起取消;本次未继续付款,不代表已核实取消成功 | 展示提示;next_action=renew_session,获取新 Session 后重新预检,不能自动重试旧 Session |
| GRACE_CANCEL_REQUIRED | 已识别宽限期,自动取消未能发出、接口明确拒绝,或当前渠道无法自动处理;本次未付款 | 展示提示;next_action=cancel_renewal_and_renew_session,顾客自行确认关闭续费并重新登录获取新Session;不得显示“已取消”或自动重试 |
| WEB_RENEWAL_CANCEL_UNVERIFIED | 付款前自动取消续费的结果未核实,不能确认宽限期或取消成功 | 展示提示;next_action=cancel_renewal_and_renew_session,顾客确认并关闭续费,再重新登录获取新Session;retryable=false,不自动重试旧Session |
| SUBSCRIPTION_NOT_EXPIRED | 当前订阅仍有效,暂不符合充值条件 | 提示会员尚未到期;不重复提交相同资料,不归因于银行卡或网络 |
| UNSUPPORTED_CHANNEL | 渠道不支持的预留公开码,仅在服务方有明确渠道结论时返回;当前版本未全面覆盖渠道识别 | 收到该码才提示不支持该渠道;不能自行把网络、币种或技术错误映射成该码 |
| PREFLIGHT_TECHNICAL_ERROR | 支付前准备发生技术失败,已归为可识别技术问题 | 清理已确认且 retryable=true 时,有限重做预检;不要把账号提示改为 Session 失效 |
| CHECKOUT_CREATE_RESPONSE_LOST | 创建支付页面的结果响应未可靠取得 | 这是准备阶段结果,不是“已经付款待核对”;按照清理和 next_action 处理,不重放底层创建/确认请求 |
| PREFLIGHT_EXPIRED | 预检有效期已结束 | 无关联订单、清理确认且允许重试时,新建预检;新 request_id 不刷新原预检 |
| PREFLIGHT_CLOSED | 预检已经关闭 | 不能再提交此预检;先看 order_id 和 next_action,再决定是否重新准备 |
| PREFLIGHT_CLEANUP_PENDING | 正在等待预检安全收尾,暂无更具体公开原因 | 等待原预检清理确认;不能并行抢占同一账号或卡 |
| PREFLIGHT_FAILED | 预检已失败,但旧记录或旧执行端没有保存细分原因 | 只显示“预检失败”;不可猜成 Session 失效、订阅未到期或付款未知。按 next_action 处理,必要时提供预检 ID 排查 |
| PAYMENT_FAILED | 订单已经确认失败;可能是未开始付款的准备失败,也可能是明确未付款的支付失败 | 展示失败并按积分状态释放本地服务占用;是否重试遵循 next_action,不无条件自动连环提交 |
| PAYMENT_UNCONFIRMED | 已有订单付款结果尚未确认 | 显示待核对,继续查询原单;不可报“未扣款”、不可重新付款或新建平行付款单 |
错误码和 status 共同解读。例如 status=cleanup_pending,error_code=SESSION_INVALID 表示已识别 Session 失效,但资源尚未安全释放;此时 next_action=wait_cleanup,不能立即重复请求。历史失败没有完整记录时返回兜底码,系统不会补造错误原因。
预检 ID 的实际字段名仍是 id,对接端可以在自己的系统中保存为 preflight_id;响应没有另造一个同义字段。公开 stage 可见 preflight、precheck、session_validating、subscription_check、context_preparing、checkout_creating、stripe_artifacts、reporting_ready、cleanup、payment、response_wait、reconciliation。阶段只作定位,不是必须依次出现的完整步骤表。
宽限期取消续费后需要新 Session
GRACE_SESSION_REFRESH_REQUIRED 表示已识别宽限期,续费此前已关闭,或服务端已经尝试取消。
取消回包丢失不等于已取消,也不再要求旧 Session 查询通过;本次没有继续付款。
展示 customer_message,要求客户重新登录并提供最新 Session,不要自行追加“已取消”的结论。
retryable=false、next_action=renew_session;禁止自动重复提交旧 Session。
取得新 Session 后使用新的请求 ID,重新预检并等待客户确认。清理未完成时先遵循
next_action=wait_cleanup。成功订单和付款结果未知的订单不能据此降级或重新付款。
此代码是可识别的正式处理结果,不意味着只调用预检就会执行取消续费;输入预检不修改订阅。
请求错误 error.code
请求被拒绝仍使用兼容的嵌套格式,不是上述顶层业务错误:
{"error":{"code":"invalid_api_key"}}
| HTTP | error.code | 处理 |
|---|---|---|
| 400 | invalid_json / invalid_fields | 修正 JSON、类型和允许字段 |
| 400 | invalid_request_id / invalid_preflight_id | 使用符合格式的原逻辑请求 ID/预检 ID |
| 400 | invalid_session / session_account_missing | 提供原始完整授权 Session JSON 字符串;这是输入格式错误,不是确认登录过期 |
| 400 | invalid_card_fields / conflicting_card_selection | 修正卡字段;card 和 card_id 不能同时传 |
| 400 | invalid_card_import / invalid_card_line_N | 修正导入文本,第 N 行有误;整批不导入 |
| 400 | invalid_card_use_limit / invalid_card_update | 修正次数、布尔操作和版本字段 |
| 400 | expired_card | 卡片有效期已过,换有效卡 |
| 400 | explicit_confirmation_required | 确认客户授权后传 confirmed=true,不接受字符串或数字 |
| 400 | invalid_voucher | 检查积分兑换码 |
| 400 | invalid_page / invalid_https_url | 修正流水游标或回调 URL |
| 401 | invalid_api_key | 检查 Bearer 密钥、Key 是否撤销及客户状态 |
| 402 或 409 | insufficient_credits | 兑换积分后再操作;正式确认前余额可能变化 |
| 403 | customer_disabled | 联系管理员核实客户状态 |
| 404 | preflight_not_found / order_not_found / private_card_not_found | 核对 ID 及所属客户/Key,不能跨账户查询或用卡 |
| 404 | invoice_not_ready | 账单尚未就绪;不改变充值成功,不重新付款 |
| 409 | idempotency_conflict | 同一 request_id 不能改变内容;核对原请求 |
| 409 | voucher_already_redeemed | 积分卡密已由其他客户兑换 |
| 409 | preflight_already_submitted | 查询预检关联的原订单 |
| 409 | preflight_not_adoptable | 查询原预检的 status、error_code 和 next_action |
| 409 | card_material_expired | 临时准备资料不可继续使用,不等于银行卡本身过期;先核对原订单 |
| 409 | resource_already_in_use / account_already_in_use / card_already_in_use | 原流程仍占用资源,等待清理;不建平行任务 |
| 409 | account_recently_paid | 北京时间当日已有另一笔充值确认付款,retryable=false,next_action=query_original_order。请查原订单,不自动重新付款,不计作新单成功或扣除新单积分。 |
| 409 | no_available_private_card / private_card_capacity_reached | 当前 Key 补充可用卡或管理库存;不会借用平台卡 |
| 409 | private_card_in_use / card_version_conflict | 占用结束后再操作,或刷新最新版本后提交 |
| 409 | card_limit_below_used | 次数上限不得小于已成功次数 |
| 409 | private_card_material_invalid | 卡资料不可用,联系管理员核对该 Key 的卡资料 |
| 413 | request_too_large | 减少请求体长度 |
| 415 | json_required / compressed_body_not_supported | 使用非压缩 application/json |
| 429 | rate_limited | 降频、退避并加随机间隔 |
| 429 | customer_capacity_reached | 等待已有任务释放并发名额 |
| 503 | execution_not_ready / secure_handoff_capacity | 等待服务恢复容量,保留已有任务状态 |
| 503 | open_api_not_enabled / open_api_storage_configuration_invalid / open_api_secret_not_configured | 服务配置暂不可用,联系管理员;不要密集重试 |
自助网页登录 Cookie 到期还可能返回 401 login_required,与授权 Session 失效是两回事。Bearer 对接应使用 invalid_api_key 判断接口鉴权问题。
next_action 与重试
| next_action | 接入动作 |
|---|---|
| wait | 等待并查询同一预检/订单;没有重新创建的要求 |
| submit_order | 预检 ready;只有客户明确确认付款后,才调用 POST /v1/orders |
| renew_session | 请求客户重新登录并提供新 Session;不是原 Session 盲重试 |
| cancel_renewal_and_renew_session | 已识别宽限期但未核实取消结果;请客户取消自动续费、重新登录获取新 Session。不得声称已自动取消 |
| wait_subscription_expiry | 等待当前会员到期,不自动再次充值 |
| change_channel | 当前渠道不支持;修正资料/选择后才能再发起 |
| retry_preflight | 原预检已不能复用;满足清理条件且 retryable=true 时创建新的预检 |
| wait_cleanup | 继续查询原预检/订单等待清理确认,不并行占用原账号/卡 |
| wait_result | 查询原订单或接收回调,不再次支付 |
| contact_support | 保存脱敏 ID、状态和时间,交由管理员核查 |
| none | 没有后续自动操作;成功显示成功,已结束失败按结果提示 |
retryable=false 不代表这个账号永远不能充值。Session 失效后换了新 Session、会员到期后条件改变,属于新的输入和新的业务操作。retryable=true 也不表示可以直接自动扣款:新的预检依然不付款,正式提交必须获得客户确认。
网络请求重试与业务重试必须分开:
- 创建或提交回包丢失:保留原 request_id 和原参数,查询或恢复同一逻辑请求;不要立即换 ID。
- 明确收到失败结果且 next_action=retry_preflight:等待 cleanup_acknowledged=true,核对没有未终结的 order_id,再用新 request_id 创建预检。
- 已有关联订单:订单是权威结果;review 或付款状态未知时只查原单。
- 达到客户侧设定的有限重试次数后停止;不要无限循环。429/503 先退避并保留已有任务状态。
示例:Session 失效
查询 GET /v1/preflights/pfapi_example_session,HTTP 200:
{
"id": "pfapi_example_session",
"created_at": 1789700000.0,
"expires_at": 1789700120.0,
"order_id": "",
"status": "failed",
"error_code": "SESSION_INVALID",
"customer_message": "Session 已失效,请重新登录账号后重新提交。",
"stage": "preflight",
"retryable": false,
"next_action": "renew_session",
"cleanup_acknowledged": true,
"payment_started": false,
"card_consumed": false,
"credit_state": "none"
}
程序匹配 error_code=SESSION_INVALID,给顾客显示 customer_message。这次无订单、无付款、无积分扣除;卡片是否空闲仍以卡池查询和清理确认判断。
示例:订阅未到期
{
"id": "pfapi_example_subscription",
"created_at": 1789700000.0,
"expires_at": 1789700120.0,
"order_id": "",
"status": "failed",
"error_code": "SUBSCRIPTION_NOT_EXPIRED",
"customer_message": "账号的 Plus 订阅尚未到期,请到期后重试。",
"stage": "preflight",
"retryable": false,
"next_action": "wait_subscription_expiry",
"cleanup_acknowledged": true,
"payment_started": false,
"card_consumed": false,
"credit_state": "none"
}
不要让客户反复刷新 Session、换卡或不停重试来处理 SUBSCRIPTION_NOT_EXPIRED。
示例:技术失败已经安全结束
{
"id": "pfapi_example_technical",
"created_at": 1789700000.0,
"expires_at": 1789700120.0,
"order_id": "",
"status": "failed",
"error_code": "PREFLIGHT_TECHNICAL_ERROR",
"customer_message": "预检遇到技术故障,请重新发起预检。",
"stage": "preflight",
"retryable": true,
"next_action": "retry_preflight",
"cleanup_acknowledged": true,
"payment_started": false,
"card_consumed": false,
"credit_state": "none"
}
这里允许重新预检。若同一原因的返回仍处于 cleanup_pending,则应以当前 retryable=false,next_action=wait_cleanup 为准,等待清理完成。
示例:付款结果待核对
{
"id": "ord_example_review",
"request_id": "order-example-review",
"preflight_id": "pfapi_example_review",
"status": "review",
"credit_state": "frozen",
"created_at": 1789700010.0,
"started_at": 1789700011.0,
"payment_at": 1789700014.0,
"success_at": null,
"finished_at": null,
"updated_at": 1789700030.0,
"result_code": "PAYMENT_UNCONFIRMED",
"error_code": "PAYMENT_UNCONFIRMED",
"customer_message": "付款结果仍在核对,请查询原订单,不要重复付款。",
"stage": "reconciliation",
"retryable": false,
"next_action": "wait_result",
"cleanup_acknowledged": null,
"payment_started": true,
"card_consumed": null
}
这类结果不能转换为 failed。积分仍冻结;后续以原订单的明确结果结算,不能通过另建单消除未知状态。仅仅预检异常或准备阶段字段不完整,不应被接入端自行升级成 PAYMENT_UNCONFIRMED。
兼容旧版与排障
- 旧客户端仍可读取原有 status、result_code、credit_state。新客户端用 error_code 做细分,但 status 仍是业务状态依据。
- 不认识的 error_code:原样保存安全的代码,显示 customer_message 或通用提示,遵循 status/next_action;不默认当成功,也不自行重试付款。
- 边缘网络错误、HTTP 非 JSON、GET 超时:保留已有业务状态并查询原任务,不改成 failed。
- 回调与订单查询使用同一公开订单对象;老的已生成回调可能缺少新字段,接入端应查询原订单补齐,不能拒绝所有旧消息。
- 充值 succeeded 后立即展示成功;账单未就绪或取消续费失败不能降级为失败。
- 支持排查只需 request_id、preflight_id/order_id、时间及时区、HTTP 状态、status、error_code、next_action、cleanup_acknowledged;不要发送 Session、API Key、完整卡号或 CVC。
本说明不承诺所有历史失败都能追溯具体原因。历史信息缺失会明确使用兜底码,不把推测作为 Session、订阅或付款结论。
11. 常见问题与验收
- 200是不是成功?不是,订单 status=succeeded 才是充值成功。
- review能重试付款吗?不能,未知不等于未付款。
- frozen是不是已经消费?不是,成功才 consumed。
- 缺少进度步骤是否失败?不是,事件不是完整强制序列。
- 取消续费失败会退积分吗?充值已成功则消耗1积分。
- 撤销Key订单会消失吗?不会,可让管理员发同客户新Key查询。
- 并发4保证一直能接4单吗?不是,仍受实时服务容量限制。
- 有没有测试域名?目前无公开沙箱,正式接口不可当沙箱压测。
上线前逐项检查:
- 鉴权和租户隔离;前端/日志无Key、Session、PAN、CVC明文。
- 重复兑换不重复入账,冻结/扣除/释放能与流水核对。
- 预检与确认严格分离,未点击确认不调用订单提交。
- request_id、preflight_id、expires_at、order_id持久化,刷新后可查原单。
- 超时/503/429/重复点击不产生新的付款逻辑操作。
- 根据status显示结果;review不允许再次付款;成功不被旧回调覆盖。
- 回调原始字节验签、去重、快速2xx、轮询兜底。
- 账单404不改成功;303下载不向外域携带APIKey。
- 预检120秒与接单并发限制已正确处理。
- 没有用“示例测试”为未经授权的真实付款或生产压测提供入口。
支持时提供客户ID、request_id、preflight_id/order_id、时间和时区、HTTP状态、error.code、是否收到回调即可;不要提供机密正文。