支付结果通知
支付成功或失败后,Velora 会向你在 创建交易 时传入的 notifyUrl 发送 POST 请求,Body 为 JSON。商户需在服务端实现该接口,并完成验签与业务处理。
回调时机
- 订单成功/失败
同一笔订单可能因重试机制被多次推送,商户端必须做 幂等处理。
回调推送规则
- 返回
2xx即视为成功并结束推送。 - 返回非
2xx、请求超时、网络异常或签名生成异常时会进入重试。 - 达到重试最大次数会停止发起回调推送。
次数与间隔
当前最多尝试 8 次(含首次请求),采用以 15s 为基准的指数退避策略,重试间隔从 15s 逐步增长到约 16min,仅重试的累计等待时间约为 31 分 45 秒。
典型等待间隔如下(仅供参考,实际以系统为准):
- 第 1 次失败后:15s
- 第 2 次失败后:30s
- 第 3 次失败后:60s
- 第 4 次失败后:120s
- 第 5 次失败后:240s
- 第 6 次失败后:480s
- 第 7 次失败后:960s(约 16min)
请求说明
- 请求方式:
POST - Content-Type:
application/json - Body:JSON,见下方参数说明
签名验证
为确保回调请求来源可信且未被篡改,商户服务端应对回调做签名验证。签名验证的算法与发起交易请求的算法是一致的。
签名算法与请求头定义可参考 接入准备。
回调 Headers
| Header | 类型 | 说明 |
|---|---|---|
X-Signature | string | 回调签名,格式为 sha256=<hex> |
X-Timestamp | string | Unix 秒级时间戳 |
Content-Type | string | 固定为 application/json |
X-Merchant-Id | string | 商户 ID |
X-Transaction-Id | string | 平台交易号(支付单号) |
Headers 示例
json
{
"X-Signature": "sha256=e94f6d2853a5e7f702214e5e0292e45cbb486b9e41f610166313568683bf5805",
"X-Timestamp": "1774948696",
"Content-Type": "application/json",
"X-Merchant-Id": "M1770606222033126",
"X-Transaction-Id": "payin_20260331171813721136740"
}回调参数
回调 Body 为 JSON,结构为 result(支付结果)与 data(订单数据)。仅当 result.code === "S0000" 且 data.status === "Success" 时表示支付成功。
result 对象
| 字段 | 类型 | 说明 |
|---|---|---|
code | string | 返回码(成功/失败标识) |
msg | string | 返回信息说明 |
data 对象
| 字段 | 类型 | 长度 / 限制 | 必返 | 说明 |
|---|---|---|---|---|
paymentId | string | / | 是 | Velora 平台支付单号 |
merchantOrderId | string | / | 否 | 商户订单号 |
psp | string | / | 否 | 实际承接订单的 PSP 标识 |
channelOrderId | string | / | 否 | PSP / 渠道侧订单号 |
status | string | / | 是 | 当前支付状态,详见 订单状态说明 |
amount | object | / | 否 | 金额,见下表 |
paymentMethod | object | / | 否 | 支付方式,见下表 |
createdAt | string | / | 否 | 创建时间 |
updatedAt | string | / | 否 | 更新时间 |
data.amount 对象
| 字段 | 类型 | 长度 / 限制 | 必返 | 说明 |
|---|---|---|---|---|
value | string | / | 是(随 amount 出现) | 金额(字符串格式,如 "29.00") |
currency | string | / | 是(随 amount 出现) | 币种 |
data.paymentMethod 对象
| 字段 | 类型 | 长度 / 限制 | 必返 | 说明 |
|---|---|---|---|---|
type | string | / | 否 | 支付方式类型 |
paymentBrand | string | / | 否 | 支付品牌 |
回调示例
json
{
"result": {
"code": "S0000",
"msg": "Payment query successfully"
},
"data": {
"paymentId": "payin_20260331145719282948882",
"merchantOrderId": "ORDER_20260331_145711_1LOQON",
"psp": "gcash_partner",
"channelOrderId": "GCASH20260331145719282948882",
"status": "Success",
"amount": {
"value": "29.00",
"currency": "PHP"
},
"paymentMethod": {
"type": "e-wallet",
"paymentBrand": "gcash"
},
"createdAt": "2026-03-31T14:57:19+08:00",
"updatedAt": "2026-03-31T15:00:12+08:00"
}
}加密货币回调返回结构说明
加密货币收款场景下,支付结果通知的返回结构与普通支付相比,主要区别在于 paymentMethod 中会额外返回 crypto 对象,用于描述链上交易信息。
data.paymentMethod.crypto 对象
| 字段 | 类型 | 必返 | 说明 |
|---|---|---|---|
chain | string | 是 | 链类型,如 ETH、BSC、TRON |
fromAddress | string | 是 | 用户发起转账的钱包地址 |
toAddress | string | 是 | 商户收款钱包地址 |
logIndex | string | 是 | 链上事件日志索引 |
txHash | string | 是 | 链上交易哈希 |
加密货币回调响应示例
提示:商户不需要严格使用该回调返回的全部字段数据,可以基于 crypto 字段的 JSON 结构实现自身通用业务信息处理。
商户必须对 txHash + logIndex 做唯一性检查,避免同一笔链上事件被重复处理。
json
{
"result": {
"code": "S0000",
"msg": "Payment query successfully"
},
"data": {
"psp": "cryptopay",
"status": "Success",
"paymentId": "payin_20260528104200903337225",
"channelOrderId": "0xd9ca31dd9f6f12077fd3525acb6706de610ae0c2c30315300e51f74f0cbd91b6_0",
"channelMerchantOrderId": "0xd9ca31dd9f6f12077fd3525acb6706de610ae0c2c30315300e51f74f0cbd91b6_0",
"merchantOrderId": "0xd9ca31dd9f6f12077fd3525acb6706de610ae0c2c30315300e51f74f0cbd91b6",
"amount": {
"value": "1.36000",
"currency": "USDT"
},
"paymentMethod": {
"type": "crypto",
"paymentBrand": "BSC",
"crypto": {
"chain": "BSC",
"fromAddress": "0x38c9e15b7a28038f74290187e2747954ee507411",
"toAddress": "0x8be0f2577b0018844ff19b675f387cc36605f1b7",
"logIndex": "0",
"txHash": "0xd9ca31dd9f6f12077fd3525acb6706de610ae0c2c30315300e51f74f0cbd91b6"
}
},
"createdAt": "2026-05-28T10:42:00+08:00",
"updatedAt": "2026-05-28T10:42:00+08:00"
}
}商户响应要求
商户完成业务处理后,必须返回 HTTP Status Code 2xx;若返回非 2xx,平台将视为处理失败并发起重试。
处理流程建议
- 解析 Body,按需按平台约定做验签(若有),不通过则返回 400,不执行业务逻辑。
- 幂等:用
data.merchantOrderId(或data.paymentId)查本地是否已处理,已处理则直接返回 200。 - 业务逻辑:根据
result.code与data.status处理回调结果。仅当result.code === "S0000"且data.status === "Success"时视为支付成功,再执行成功后的业务处理。 - 返回 200,避免重复推送。
安全建议
- 仅在服务端处理回调,不要依赖前端或不可信请求。
- 校验金额、商户订单号与本地订单一致,防止篡改。