使用原来的 request_id 和完全相同的订单参数重试。不要因为连接超时就生成新请求键。在 NotPanel 上,重试会返回原订单并带有 replayed: true;如果第一次请求根本没有到达,则会创建订单。
客户只购买了一次。如果请求发给面板后响应丢失,下一步应找回这次购买的结果,而不是把未知结果当作再次购买的理由。
超时后存在三种可能
- 请求没有到达,订单尚未被接受。
- 订单已被接受,但响应丢失了。
- 请求在连接中断时已到达;用相同 request_id 重试即可确定发生的是上面哪一种情况。
超时无法区分这些情况。HTTP 本身不会让创建订单的 POST 自动变得可安全重试;保护来自 API 的具体约定。参见 RFC 9110, §9.2.2.
NotPanel 如何识别重试
request_id 是可选字段,不能为空,最长 128 个字符。idempotency_key 是兼容别名;同时提供时,以 request_id 为准。重试应保留相同账户、请求键及全部订单参数。已接受的订单会返回原订单 ID;用相同键发送不同参数会被拒绝。
不提供这两个字段时,NotPanel 会对同一账户的相同 add 请求提供 60 秒保护:在此时间内重复发送会返回第一个订单,而不会创建第二个。较晚的重试不应依赖这个短窗口。
这个窗口也会合并两次有意提交的相同购买。如需立即创建两个独立订单,请为每笔新购买分配不同的 request_id。不要为了绕过未知结果而更换请求键。
超时后保留原来的 request_id。
使用相同请求键和不变的订单详情重试。
保存重试返回的原订单 ID。
发送前先保存购买标识
假设购买编号 8427 有一个订单行。在第一次网络请求前保存 request_id 和完整参数。下方为使用占位符和换行的示意请求;实际表单应正常编码。仅在确实要创建付费订单时发送真实参数。
POST https://notpanel.com/api/v3
Content-Type: application/x-www-form-urlencoded
key=YOUR_API_KEY
&action=add
&service=YOUR_SERVICE_ID
&link=YOUR_TARGET_URL
&quantity=YOUR_VALID_QUANTITY
&request_id=checkout-8427-line-1超时后,使用 checkout-8427-line-1 重发相同服务、目标、数量和可选字段,应用重启后也一样。收到订单 ID 后将其保存到该购买记录,再通过 status 查询。request_id 标识下单请求,不能替代 status 所需的订单 ID。如需按 request_id 查找订单,请使用 order_details。
根据完整响应决定下一步
- 超时、连接中断或结果不明
- 保留原请求键和参数。限制重试次数、间隔重试,并遵守 Retry-After。次数耗尽后仍应保留未解决记录。
- INTERNAL_ERROR、API_DISABLED 或 ORDER_PLACEMENT_PAUSED(retryable: true)
- 等待(如有 Retry-After 请遵守),然后用相同 request_id 发送相同的 add。你会得到原订单,或仅一个新订单。不要换键创建替代订单。
- REQUEST_ID_CONFLICT
- 比对已保存的参数。用原参数找回原订单;只有明确的新购买才使用新键。
- 参数、认证或请求频率错误
- 读取 error_code 和 retryable,修正参数或凭据并遵守等待时间。不要对所有错误无限自动重试。
接收客户订单前测试恢复流程
先在自己的测试环境使用模拟 API,不需要真实购买或特殊的 NotPanel 测试密钥。
- 模拟订单已接受但响应丢失,确认重试键和参数完全相同。
- 在两次尝试之间重启客户端,确认能恢复已保存的请求标识。
- 先返回可重试的 500 或 503,再返回带 replayed: true 的重放结果,确认只保存一个订单 ID。
- 模拟请求键冲突或不可重试的校验错误,确认自动重试停止。
- 为两笔有意提交的相同购买分配不同键。后续如需真实测试,只提交确实需要的订单,并核对订单和钱包记录。
常见问题
超时是否代表扣款两次?
不是。它只表示应用没有收到可用响应。在判定重复扣款前,应核对找回的订单和钱包记录。
NotPanel 强制要求 request_id 吗?
不要求。request_id 和 idempotency_key 都是可选字段。未提供时,同一账户的相同 add 有 60 秒保护。显式请求键让应用为每笔购买指定身份。
每次重试都应该生成新键吗?
不应该。第一次尝试前保存一个键,在订单参数不变的情况下重复使用。只有新购买才分配新键。
能用 request_id 查找订单吗?
可以,使用 order_details:用相同 request_id 发送 action=order_details,无需重发 add 即可获得订单及其编号。如果没有创建订单,会返回 ORDER_NOT_FOUND。status 操作本身仍需要订单编号。
继续阅读: API 集成指南 · Webhook 与状态轮询 · 错误参考.



