沙箱支付过期后未收到 notify,是否需要配置其他接口?
明确结论
沙箱订单过期后没有收到 notify,不一定是配置出了问题。许多支付系统只会在支付成功、退款等状态发生变化时发送异步通知,订单超时自动失效时未必会通知。沙箱和正式环境的通知机制也可能存在差异。
一般不需要在 pay 接口中额外设置“过期通知”参数。即使接口支持 notify_url,这个字段通常也只是用来指定支付结果的通知地址,并不表示所有订单状态变化都会触发回调。
是否支持过期通知,要以当前支付产品及接口版本的官方文档为准。
为什么收不到过期通知
可能的原因包括:
- 支付平台没有将“订单过期”定义为通知事件。
notify_url只用于通知支付成功或交易结果。- 沙箱环境仅模拟了部分通知场景。
- 订单已经超过商户设置的有效期,但平台侧尚未将其关闭。
- 通知地址无法从公网访问,或者 HTTPS、证书、响应格式不符合平台要求。
- 平台已经发送通知,但商户接口没有及时返回规定的成功响应。平台重试后,业务系统仍未正确记录通知。
还要注意,前端支付页面显示已过期,不代表支付平台会在同一时刻把订单状态改为关闭。
建议的处理方式
1. 确认 notify_url 的用途
检查 pay 请求是否要求传入类似字段:
{
"notify_url": "https://example.com/payment/notify"
}
实际字段名可能是 notify_url、notifyUrl 或其他形式,具体以 API 文档为准。不要添加接口没有定义的参数。
还需要确认文档是否明确说明:
- 哪些交易状态会发送通知;
- 订单超时或关闭是否属于通知事件;
- 沙箱环境是否支持该事件;
- 通知失败后如何重试;
- 接收方需要返回什么响应。
2. 主动查询订单状态
如果平台不保证发送过期通知,商户系统应通过订单查询接口确认状态,不能只依赖异步回调更新订单。
下面是一个通用示例。接口地址和字段仅用于展示结构,使用时需要替换为支付平台的实际定义:
async function queryPaymentStatus(orderId) {
const response = await fetch(
`https://sandbox.example.com/api/payments/${encodeURIComponent(orderId)}`,
{
method: "GET",
headers: {
Authorization: `Bearer ${process.env.PAYMENT_API_KEY}`,
Accept: "application/json"
}
}
);
if (!response.ok) {
throw new Error(`Query payment failed: ${response.status}`);
}
const payment = await response.json();
if (payment.status === "PAID") {
await markOrderAsPaid(orderId);
} else if (
payment.status === "EXPIRED" ||
payment.status === "CLOSED" ||
payment.status === "CANCELLED"
) {
await markOrderAsClosed(orderId);
}
return payment;
}
PAID、EXPIRED、CLOSED 和 CANCELLED 是常见的状态名称,目标平台不一定使用这些值。
3. 在本地设置超时检查任务
创建支付订单时,可以保存平台订单号和预计过期时间。定时扫描已经超过有效期、状态仍为“待支付”的订单,再调用支付查询接口核实状态。
SELECT id, payment_order_id
FROM orders
WHERE status = 'PENDING'
AND expires_at <= CURRENT_TIMESTAMP;
订单最终状态应以支付平台的查询结果为准。不要因为本地时间已经到期,就直接把订单认定为付款失败。
4. 必要时调用关单接口
在部分平台中,“过期时间”只是限制用户继续支付,并不会自动把订单状态改为关闭。这种情况下,可能需要主动调用关单接口:
async function closeExpiredPayment(paymentOrderId) {
const response = await fetch(
`https://sandbox.example.com/api/payments/${encodeURIComponent(paymentOrderId)}/close`,
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PAYMENT_API_KEY}`,
"Content-Type": "application/json"
}
}
);
if (!response.ok) {
throw new Error(`Close payment failed: ${response.status}`);
}
return response.json();
}
平台是否允许主动关单、关单后是否发送通知,以及对已支付订单调用关单接口时会如何处理,都要按照实际接口规则判断。
回调接口还需要检查什么
即使订单过期不会触发通知,也要检查现有回调配置是否正常:
notify_url必须能被支付平台从公网访问。- 不要使用
localhost、内网 IP 或已经失效的临时测试地址。 - 检查请求签名和平台证书的验证逻辑。
- 保存原始通知内容及请求头,方便排查问题。
- 回调处理需要具备幂等性,防止重复通知造成重复入账。
- 收到通知后,按平台要求返回成功响应。
- 对支付成功等重要状态,最好再调用查询接口确认。
推荐的订单状态同步策略
更稳妥的做法是配合使用以下三种机制:
- 通过异步通知及时更新支付结果。
- 通过主动查询补偿通知丢失或未覆盖过期状态的情况。
- 通过定时任务处理长期停留在待支付状态的订单。
因此,沙箱订单过期后没有收到 notify,可以先按可能的正常行为排查。首先确认官方文档是否明确支持“过期/关闭通知”。如果文档没有作出保证,就使用订单查询接口和定时任务处理,不要继续猜测或在 pay 接口中添加未经定义的参数。
备注:内容仅供参考。
