PRODUCTION API · V1 · 2026-08-24
聚合支付网关
商户接入文档
统一接入支付、退款、订阅、代付与日报。平台只支持标准两位小数币种,交易金额使用分制整数,所有业务结果以订单查询或异步通知为准。
https://onlobo.com/gateway/v1data.status,并通过查询或异步通知确认最终结果。SECURITY
签名鉴权
除公开文档和健康检查外,所有 /gateway/v1/** 请求均须携带下列四个鉴权头。API Secret 由商户在商户后台自行创建、查看和切换;切换后旧 Secret 继续有效 10 分钟。
| 请求头 | 要求 |
|---|---|
X-Merchant-Id | 平台商户雪花 ID 的十进制字符串 |
X-Timestamp | UTC Unix 秒,允许与服务器相差 5 分钟 |
X-Nonce | 16–128 位字母、数字、下划线或短横线;10 分钟内不可重复 |
X-Signature | v1= + 小写十六进制 HMAC-SHA256 |
Idempotency-Key 不是全局鉴权头,只在创建支付、退款、代付、订阅和取消订阅等写接口中必传,最长 128 字符。带 JSON 请求体时使用标准 Content-Type: application/json;查询与下载接口不需要幂等头。
开户后取得 Merchant ID 和商户后台账号。登录商户后台后自行创建 API Secret 和 Webhook Secret;Merchant ID 用于定位当前启用的 API Secret,API Secret 用于请求签名,Webhook Secret 只用于验证网关异步通知,二者不可混用。
签名原文
UPPERCASE_HTTP_METHOD + "\n" +
requestTarget + "\n" +
timestamp + "\n" +
nonce + "\n" +
lowercase_hex_sha256(rawBody)
requestTarget 是原始路径与原始查询字符串,例如 /gateway/v1/payments?page=1&pageSize=50。查询参数顺序和编码必须与实际发送的 URL 完全一致。
signature = "v1=" + lowercase_hex(
HMAC_SHA256(apiSecret, canonicalText)
)
GET 请求的原始请求体为空字节数组,其 SHA-256 固定为 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855。JSON 请求必须针对实际发送的 UTF-8 原始字节签名,禁止重新排序字段后再计算。
CONTRACT
幂等与统一响应
幂等范围是“商户 + 操作类型 + Idempotency-Key”。相同 Key 和相同请求返回首次结果;请求内容不同返回 1004。
{
"code": 200,
"message": "Success",
"data": {},
"requestId": "req_..."
}
code=200表示接口处理成功,不表示支付成功;支付结果读取data.status。- 错误响应的
data为null。 - 请求体最大 1 MB,超出返回 HTTP 413 /
1007。 - 只支持 ISO 默认精度为两位小数的币种;金额按分传整数,例如 12.34 传
1234。
第一层响应码
| code | message | 含义 |
|---|---|---|
200 | Success | 接口处理成功;交易结果仍读取 data.status |
1001–1007 | Request / resource error | 请求、校验、资源、幂等、状态、方法或请求体错误;完整取值见“错误码” |
1101–1108 | Authentication / authorization error | 认证、凭据、时间戳、Nonce、重放、签名或权限错误;完整取值见“错误码” |
1202 | Callback URL error | 回调地址无效 |
2001 | Payment order not found | 支付订单不存在 |
2101–2105 | Risk / permission error | 金额、日限额、交易权限或风控并发冲突 |
3001–3002 | Provider error | 渠道不可用或结果暂时无法确认 |
4001 | Invalid provider webhook signature | 上游通知签名无效 |
9001 | Internal server error | 平台内部错误 |
PAYMENTS
支付
/payments创建支付使用后台绑定的渠道支付参数创建支付。请求必须携带签名请求头和 Idempotency-Key。金额只接受整数分,商户订单号在当前商户范围内必须唯一。直连卡资料与收银台资料二选一,不允许商户指定渠道。
请求字段
| 字段 | 类型 | 是否必传 | 规则与说明 |
|---|---|---|---|
merchantOrderNo | string | 必传 | 商户订单号,1–128 位;在当前商户范围内唯一。该值只用于商户与网关对账,不会直接作为上游订单号。 |
currency | string | 必传 | 三位 ISO 4217 大写币种编码,例如 USD。只支持平台已启用且默认精度为两位小数的币种。 |
amount | integer(int64) | 必传 | 支付金额,必须大于 0,单位为分。例如 1234 表示 12.34 USD,禁止传小数或主币单位字符串。 |
paymentMethod | string | 必传 | 后台已绑定并启用的支付方式编码;直连卡资料只允许 CARD,收银台资料须匹配绑定渠道实际支持方式。 |
customerEmail | string | 必传 | 客户邮箱,最长 320 位;网关会去除首尾空格并转为小写。渠道需要购物者标识时,网关以该值同时生成渠道 shopper_email 与 shopper_id,商户无需重复提交。 |
notifyUrl | string | 非必传 | 本订单的成功异步通知地址,最长 2048 位,必须为 HTTPS。存在时只投递该地址;缺省时回退商户默认 Webhook;两者都没有则拒绝创建。 |
returnUrl | string | 非必传 | 客户浏览器完成 3DS 后的 HTTPS 返回地址,最长 2048 位,网关自动拼接;商户域名报备只记录事实,不参与交易准入。不提交时商户可收到响应后自行拼接。仅用于浏览器回跳,不表示支付成功。 |
paymentMethodData | object | 二选一 | 网关统一直连 CARD 资料,字段见下表。与 checkoutData 必须且只能提交一个非空对象。Elanlink 使用此资料。 |
checkoutData | object | 二选一 | FuturePay 收银台业务资料:productName(必填,最长255)、productDetail(必填,最长1024)、origin(必填,最长255)、countryCode(必填,两位大写国家编码)。不传卡号、渠道密钥或任意 metadata,不使用占位商品。资料类型与实际绑定不符时,下单前拒绝。 |
paymentMethodData 字段
| 字段 | 类型 | 是否必传 | 规则与说明 |
|---|---|---|---|
firstName | string | 必传 | 持卡人名字,1–100 位。 |
lastName | string | 必传 | 持卡人姓氏,1–100 位。 |
cardNumber | string | 必传 | 卡号,12–23 位数字,可包含空格;网关收到后会移除空格。仅用于本次上游请求,不落库、不写日志。 |
expirationYear | string | 必传 | 四位到期年份,例如 2029。 |
expirationMonth | string | 必传 | 两位到期月份,范围 01–12。 |
securityCode | string | 必传 | 3–4 位卡安全码。仅用于本次上游请求,绝不落库、缓存或记录日志。 |
shopperIp | string | 非必传 | 付款客户公网 IP,最长 45 位;建议直连交易传递。 |
shopperPhone | string | 非必传 | 付款客户电话,最长 64 位,建议包含国际区号。 |
billingCountry | string | 非必传 | 账单国家,两位 ISO 3166-1 alpha-2 编码,例如 US;网关会转为大写。 |
billingState | string | 非必传 | 账单州/省,最长 128 位。 |
billingCity | string | 非必传 | 账单城市,最长 128 位。 |
billingAddress | string | 非必传 | 账单详细地址,最长 512 位。 |
billingPostalCode | string | 非必传 | 账单邮政编码,最长 32 位。 |
os | string | 非必传 | 客户操作系统,最长 64 位,用于风控或 3DS。 |
browser | string | 非必传 | 浏览器或 User-Agent 信息,最长 512 位。 |
browserLanguage | string | 非必传 | 浏览器语言,最长 32 位,例如 en-US。 |
timeZone | string | 非必传 | 客户端时区信息,最长 16 位。 |
resolution | string | 非必传 | 屏幕分辨率,最长 32 位,例如 1920x1080。 |
challengeWindowSize | string | 非必传 | 3DS Challenge 窗口规格,最长 8 位。 |
sessionId | string | 非必传 | 商户侧客户会话编号,最长 128 位;不得包含卡号或安全码。 |
请求示例
{
"merchantOrderNo": "ORDER-20260820-001",
"currency": "USD",
"amount": 1234,
"paymentMethod": "CARD",
"customerEmail": "ada\u0040example.com",
"notifyUrl": "https://merchant.example.com/api/payment/notify",
"returnUrl": "https://merchant.example.com/payment/return",
"paymentMethodData": {
"firstName": "Ada",
"lastName": "Lovelace",
"cardNumber": "CARD_NUMBER",
"expirationYear": "2029",
"expirationMonth": "08",
"securityCode": "CVV",
"billingCountry": "US"
}
}
当前仅开放 Elanlink 直连 CARD。下游只提交网关统一字段;渠道字段名、渠道商户号、渠道通知地址、签名、token_flag 和其他渠道常量均由网关生成。网关不会向上游传递 payment_method。
当前支付方式与渠道支付参数由超级后台一对一绑定。下游不能指定渠道,也不能提交 channelCode 或 channelSelectionMode。
merchantId、channelCode、channelSelectionMode、providerCode、metadata 及任何上游渠道专属字段。请求出现未定义字段会被拒绝。创建支付与支付查询响应字段
按平台订单号、商户订单号查询及支付列表中的每个订单使用同一字段结构。订阅订单的 subscriptionCycleNo 对应通知的 data.cycleNo;失败期也可查,订阅期链接口按真实期数正序返回,不因失败中断。
| 字段 | 类型 | 说明 |
|---|---|---|
paymentNo | string | 网关支付订单号,全局唯一;后续查询和退款使用该字段。 |
merchantOrderNo | string | 商户创建支付时提交的订单号。 |
subscriptionNo | string/null | 平台订阅唯一编号,订阅创建时预生成,每期查询及通知一致;普通支付为空。存在编号不代表首期已成功。 |
amount | integer | 订单原始金额,单位为分。 |
feeAmount | integer | 商户手续费,单位为分。 |
netAmount | integer | 商户净额,单位为分;与手续费之和严格等于订单金额。 |
currency | string | 订单币种。 |
paymentMethod | string | 实际支付方式,当前为 CARD。 |
status | integer | 平台支付状态码;只有 5 表示支付成功。 |
refundState | integer | 退款汇总状态:20 未退款、21 部分退款、22 全额退款。 |
refundedAmount | integer | 已确认成功的累计退款金额,单位为分。 |
channelCode | string | 网关实际使用的渠道编码,只读说明字段,不能在请求中指定。 |
providerCode | string | 实际执行请求的 Adapter 编码,只读说明字段。 |
providerTransactionId | string/null | 上游交易号;上游尚未返回时为 null。 |
failureCode | string/null | 明确失败且上游返回原因时的失败码;否则为 null。 |
failureMessage | string/null | 明确失败且上游返回原因时的安全失败描述;否则为 null。 |
failureSolution | string/null | 上游返回的安全处理建议;未返回时为 null。 |
resultSource | integer | 平台结果来源编号。 |
notificationStatus | integer | 商户通知生命周期:1 表示尚未生成投递任务;完整编号见“业务状态码”。 |
issueUrl | string / null | 3DS 浏览器跳转地址,直接 GET 打开;3DS 时与 nextAction.url 完全一致,无 3DS 时为 null。不参与支付状态判断,不是请求中的 returnUrl。 |
nextAction | object | 为已接入商户保留 type、url、parameters;不再返回 method 属性。3DS 直接 GET 打开 url,新接入建议读取同级 issueUrl。不判断或驱动任何业务。 |
aggregateVersion | integer | 订单聚合版本,用于识别异步事件先后关系。 |
createdAt | string | 创建时间,东八区 yyyy-MM-dd HH:mm:ss。 |
paidAt | string/null | 支付成功时间:渠道有精确时间则使用渠道时间,没有则取首次确认成功时的当前时间并保存;未成功为空。查询和重发不重新取时,历史空值不回填。 |
subscriptionCycleNo | integer/null | 订阅期数:首期为 1,首次续订为 2,与成功通知 data.cycleNo 相同;普通支付为 null。查询不会猜测或重新编号。 |
subscriptionPeriodStart | string/null | 本期已保存的平台账期开始(含);普通支付、首期未成功时为空。 |
subscriptionPeriodEnd | string/null | 本期已保存的平台账期结束(不含);失败续订仍保留账期。下一期开始等于上一期结束。 |
completedAt | string/null | 已保存的结果完成时间:上游精确时间或首次确认终态时的平台时间;未记录时为 null,不是本次查询时间。所有时间固定东八区 yyyy-MM-dd HH:mm:ss。 |
创建支付响应示例
{
"code": 200,
"message": "Success",
"data": {
"paymentNo": "P84000000000000001",
"merchantOrderNo": "ORDER-20260820-001",
"amount": 1234,
"feeAmount": 20,
"netAmount": 1214,
"currency": "USD",
"paymentMethod": "CARD",
"status": 3,
"refundState": 20,
"refundedAmount": 0,
"channelCode": "ELANLINK",
"providerCode": "ELANLINK",
"providerTransactionId": null,
"failureCode": null,
"failureMessage": null,
"failureSolution": null,
"resultSource": 4,
"notificationStatus": 1,
"issueUrl": null,
"nextAction": {
"type": 1,
"url": null,
"parameters": {}
},
"aggregateVersion": 1,
"createdAt": "2026-08-21 15:30:00",
"paidAt": null
},
"requestId": "req_..."
}
/payments/{paymentNo}查询支付/payments?merchantOrderNo=...按商户订单号查询支付列表查询参数
| 参数 | 是否必传 | 说明 |
|---|---|---|
merchantOrderNo | 非必传 | 商户订单号。传入时执行当前商户范围内的精确查询并返回单个订单,不使用分页。 |
status | 非必传 | 支付状态。未传表示不按状态过滤。 |
page | 非必传 | 列表页码,从 1 开始,默认 1。按商户订单号精确查询时忽略。 |
pageSize | 非必传 | 每页数量,范围 1–200,默认 50。按商户订单号精确查询时忽略。 |
1 已创建3 处理中5 成功6 失败7 已取消8 已过期当前 Elanlink 仅开放直连,不返回 FORM_POST 或 IFRAME 托管页动作。HTTP 成功且同步响应包含非空 issuer_url 时,创建结果为 3(处理中),在 data 内同时返回 issueUrl 和 THREE_DS nextAction,两处地址完全一致。浏览器直接 GET 打开,不构造 POST 表单。nextAction 保留 type、url、parameters,不再输出 method;后续支付结果仍只由渠道异步通知或平台主动查单确认,地址字段不参与状态迁移。
3DS 过渡响应字段示例(data 内,非完整订单)
{
"issueUrl": "https://issuer.example/3ds?order_no=P...",
"nextAction": {
"type": 7,
"url": "https://issuer.example/3ds?order_no=P...",
"parameters": {}
}
}
以上地址仅为格式示例。实际返回地址中的 notify_url、return_url 等参数必须完整保留;没有传 returnUrl 的商户可自行补充 return_url。浏览器返回页不代表支付成功。
REFUNDS
退款
/payments/{paymentNo}/refunds创建退款{
"merchantRefundNo": "REFUND-20260820-001",
"amount": 500,
"reason": "Customer request"
}
/refunds?page=1&pageSize=50退款列表/refunds/{refundNo}退款详情退款必须引用当前商户的真实原支付订单,固定使用原支付保存的渠道支付参数 ID 与配置版本;支付参数停用后禁止新退款。退款收费和渠道成本在本次退款创建时固化,预占本金加手续费。累计成功退款与处理中退款本金不得超过可退款金额。
退款响应字段
创建和详情返回 data 对象;列表返回同结构的 data 数组。金额均为整数分,时间为东八区 yyyy-MM-dd HH:mm:ss。
| 字段 | 说明 |
|---|---|
refundNo | 平台退款号 |
merchantRefundNo | 商户退款单号 |
paymentNo | 原平台支付订单号 |
amount | 退款本金(分) |
feeRatePpm | 本次退款商户比例费率(ppm) |
fixedFeeAmount | 本次退款固定费用(分) |
merchantFeeAmount | 本次商户退款手续费(分) |
merchantTotalDebitAmount | 商户扣款总额:本金加手续费(分) |
currency | 交易币种 |
status | 退款状态,5 为成功 |
providerRefundId | 上游退款号,未取得为空 |
createdAt | 创建时间 |
succeededAt | 成功时间,未成功为空 |
SUBSCRIPTIONS
订阅
/subscriptions创建订阅创建上游管理的自动续订。请求必须携带签名请求头和 Idempotency-Key。平台不维护商品、订阅包或价格版本;商户在每次创建时实时提交金额和周期条款。
请求字段
| 字段 | 类型 | 是否必传 | 规则与说明 |
|---|---|---|---|
merchantOrderNo | string | 必传 | 首期正式支付订单的商户订单号,1–128 位,在当前商户范围内唯一。 |
customerEmail | string | 必传 | 客户邮箱,最长 320 位;会转为小写保存并支持精确查询。渠道需要购物者标识时,网关以该值生成渠道 shopper_id,商户无需重复提交。 |
currency | string | 必传 | 三位 ISO 4217 大写币种编码,平台统一按两位小数处理。 |
amount | integer | 必传 | 正整数分金额,例如 999 表示 9.99。标准模式用于每一期;首期优惠模式用于从首期开始的每个优惠期。 |
recurringAmount | integer | 必传 | 预售首期或优惠期结束后的常规正整数分金额。无预售的标准模式必须与 amount 相等;有预售时首期可独立定价;首期优惠模式必须大于 amount。 |
pricingMode | integer | 必传 | 1 标准订阅,2 首期优惠。计价方式与预售相互独立。 |
discountCycles | integer | 必传 | 从首期开始连续享受优惠的期数。标准模式固定为 0;首期优惠模式必须至少为 1,有限订阅时不能超过总期数。 |
contractStart | string(date) | 非必传 | 预售条款,格式 yyyy-MM-dd。首期一次性区间在该日结束,常规周期从该日开始;只能有一个预售首期,可与标准计价或首期优惠组合。功能开关关闭时,携带该字段的请求会被明确拒绝。 |
planCode | string | 必传 | 周期单位枚举,只允许 DAY、WEEK、MONTH、YEAR;它不是商品或套餐编码。 |
intervalCount | integer | 必传 | 正整数,表示每多少个周期单位扣费一次。提交上游前按当前时间预检日期范围,计算结果不得超出 1000–9999 年。 |
totalCycles | integer | 必传 | 包含首期在内的总扣费次数;0 固定表示永久续订。有限期预检最后一期边界,永久订阅只检查单期;无效组合同步拒绝,不创建交易或通知数据。 |
paymentMethod | string | 必传 | 支付方式。当前唯一允许值为 CARD。 |
notifyUrl | string | 非必传 | 订阅成功事件的通知地址,最长 2048 位,必须为 HTTPS。存在时只使用该地址;缺省时回退商户默认 Webhook;两者都没有则拒绝创建。 |
returnUrl | string | 非必传 | 首期支付发生 3DS 时的客户浏览器 HTTPS 返回地址,最长 2048 位,网关自动拼接;商户域名报备只记录事实,不参与交易准入。不提交时商户可自行拼接。不能用该页面判断订阅生效。 |
paymentMethodData | object | 必传 | 网关统一的直连卡支付资料,完整字段见下表。订阅支付与单次支付使用同一套卡资料契约。 |
paymentMethodData 字段
| 字段 | 类型 | 是否必传 | 规则与说明 |
|---|---|---|---|
firstName | string | 必传 | 持卡人名字,1–100 位。 |
lastName | string | 必传 | 持卡人姓氏,1–100 位。 |
cardNumber | string | 必传 | 卡号,12–23 位数字,可包含空格;网关收到后会移除空格。仅用于本次上游请求,不落库、不写日志。 |
expirationYear | string | 必传 | 四位到期年份,例如 2029。 |
expirationMonth | string | 必传 | 两位到期月份,范围 01–12。 |
securityCode | string | 必传 | 3–4 位卡安全码。仅用于本次上游请求,绝不落库、缓存或记录日志。 |
shopperIp | string | 非必传 | 付款客户公网 IP,最长 45 位;建议直连交易传递。 |
shopperPhone | string | 非必传 | 付款客户电话,最长 64 位,建议包含国际区号。 |
billingCountry | string | 非必传 | 账单国家,两位 ISO 3166-1 alpha-2 编码,例如 US;网关会转为大写。 |
billingState | string | 非必传 | 账单州/省,最长 128 位。 |
billingCity | string | 非必传 | 账单城市,最长 128 位。 |
billingAddress | string | 非必传 | 账单详细地址,最长 512 位。 |
billingPostalCode | string | 非必传 | 账单邮政编码,最长 32 位。 |
os | string | 非必传 | 客户操作系统,最长 64 位,用于风控或 3DS。 |
browser | string | 非必传 | 浏览器或 User-Agent 信息,最长 512 位。 |
browserLanguage | string | 非必传 | 浏览器语言,最长 32 位,例如 en-US。 |
timeZone | string | 非必传 | 客户端时区信息,最长 16 位。 |
resolution | string | 非必传 | 屏幕分辨率,最长 32 位,例如 1920x1080。 |
challengeWindowSize | string | 非必传 | 3DS Challenge 窗口规格,最长 8 位。 |
sessionId | string | 非必传 | 商户侧客户会话编号,最长 128 位;不得包含卡号或安全码。 |
请求示例
{
"merchantOrderNo": "ORDER-20260820-001",
"customerEmail": "customer\u0040example.com",
"currency": "USD",
"amount": 999,
"recurringAmount": 2999,
"pricingMode": 2,
"discountCycles": 3,
"planCode": "MONTH",
"intervalCount": 1,
"totalCycles": 0,
"paymentMethod": "CARD",
"notifyUrl": "https://merchant.example.com/api/subscription/notify",
"returnUrl": "https://merchant.example.com/subscription/return",
"paymentMethodData": {
"firstName": "Ada",
"lastName": "Lovelace",
"cardNumber": "CARD_NUMBER",
"expirationYear": "2029",
"expirationMonth": "08",
"securityCode": "CVV",
"billingCountry": "US"
}
}
当前订阅只走直连。Elanlink 接受 DAY、WEEK、MONTH、YEAR;平台映射为上游 interval,并将 totalCycles 映射为 billing_cycle。首期优惠时,上游外层 amount 使用优惠期实扣金额,订阅字符串中的 contract_amount 使用优惠结束后的标准金额,discountCycles 映射为 promotion_cycle。预售时 contractStart 映射为上游 contract_start;它是独立条款,因此可与首期优惠同时提交。Elanlink 要求的 shopper_id 由网关使用规范化后的 customerEmail 生成。首期和每次续期都是独立正式支付订单;优惠期内沿用冻结的优惠金额,超过优惠期后使用冻结的标准金额。
interval、intervalUnit、billingCycle、contract、contractName、contractAmount、商品或套餐编号、channelCode、providerCode 及任何上游签名字段。创建订阅同步响应
subscriptionNo 在请求校验通过、首期支付订单落库时预生成,早于上游调用,不依赖渠道订阅 ID。订单已创建后,无论同步支付状态为处理中或失败,都保留并返回这个编号;同一幂等请求重放返回原编号,不重复生成。首订成功和各期续订通知均使用同一个 subscriptionNo,期数由 cycleNo 区分。校验失败且未创建订单时,不返回订阅号。
同步响应使用标准支付对象,只表示首期正式支付订单的当前状态。平台在创建首期支付订单时生成唯一 subscriptionNo,保存到支付订单并同步返回;该编号只用于结果关联,不表示订阅已经生效。只有上游异步通知或主动查单明确确认首期成功后,平台才创建订阅管理数据,并通过 subscription.activated 异步通知确认生效。上游同步成功响应不能直接激活订阅。
创建订阅响应示例
{
"code": 200,
"message": "Success",
"data": {
"paymentNo": "P84000000000000003",
"merchantOrderNo": "ORDER-20260820-001",
"orderInitiator": 1,
"subscriptionNo": "8c8de29c90ac4866b2067cb442b6f229",
"amount": 2999,
"feeAmount": 0,
"netAmount": 2999,
"currency": "USD",
"paymentMethod": "CARD",
"status": 3,
"providerCode": "ELANLINK",
"providerTransactionId": null,
"issueUrl": null,
"nextAction": {
"type": 1,
"url": null,
"parameters": {}
},
"resultSource": 4,
"createdAt": "2026-08-21 15:30:00"
},
"requestId": "req_..."
}
/subscriptions/{subscriptionNo}订阅详情/subscriptions/{subscriptionNo}/payments完整支付链/subscriptions?customerEmail=...组合查询/subscriptions/{subscriptionNo}/cancel取消订阅(必须传 Idempotency-Key)订阅查询参数
| 参数 | 是否必传 | 说明 |
|---|---|---|
subscriptionNo | 非必传 | 按网关订阅号精确查询。 |
customerEmail | 非必传 | 按规范化邮箱精确查询,不做模糊匹配。 |
effectiveStatus | 非必传 | 按生效状态筛选:9 生效中,8 已到期。 |
renewalStatus | 非必传 | 按续存状态筛选:9 续存,7 已取消,11 已自然完成。 |
page | 非必传 | 页码,从 1 开始,默认 1。 |
pageSize | 非必传 | 每页数量,范围 1–200,默认 50。 |
订阅关系与扣费结果分开:续存中 renewalStatus=9 的订阅保持 effectiveStatus=9,单期扣费失败不会取消或终止订阅,也不代表失败期已支付。取消或自然完成后,才按实际已支付账期的开始和结束判断生效状态。
当期扣费结果(订阅管理响应)
“当期”是已存在的最大明确期数,不按当前时间预测下一期。没有新一期通知就保持原结果;失败不重试扣款,历史失败订单完整保留。
| 字段 | 类型 | 说明 |
|---|---|---|
currentPaymentNo | string / null | 当期正式支付订单号。 |
currentCycleNo | integer / null | 已存在最大明确期数。 |
merchantId / initialMerchantOrderNo / initialPaymentNo | string | 所属商户号、商户首订订单号、平台首订订单号,固定关联真实首期订单。 |
initialProviderTransactionId / providerSubscriptionId | string / null | 直接上游首订订单号和订阅号。 |
processorCode / initialProcessorTransactionId / processorSubscriptionId | string / null | 上上游机构及首订、订阅编号,未知时为空,不代填、不自动切换渠道。 |
maskedCardNumber | string / null | 脱敏支付卡号,最多前六后四,中间星号;缺失时为空。档案不保存收费、通知地址或渠道支付参数。 |
subscriptionStart / subscriptionEnd | string / null | 整个档案的生效区间。开始取首期已固化账期;有限结束按首期锚点和限定期数计算,永久续存的结束为 null。取消只终止续存,结束取已支付期限,不取取消时间。缺少原始锚点时不编造日期。 |
activePeriodNo / activePeriodStart / activePeriodEnd | integer / string / null | 查询时刻所在的真实期号及区间,左闭右开;没有对应实际期时三个字段都为 null。续存中的失败期也可为当前期,不代表已支付;不与最大已收到期次混用。 |
currentPaymentStatus | integer / null | 该期支付状态,复用支付状态码:5 成功、6 失败。无数据为空,不推定失败。 |
currentPaymentFailureCode | string / null | 该期失败码,无则为空。 |
currentPaymentFailureMessage | string / null | 该期失败原因,无则为空。 |
currentPaymentPeriodStart / currentPaymentPeriodEnd | string / null | 该期已保存的开始/结束时间,固定东八区 yyyy-MM-dd HH:mm:ss;不表示未来扣款安排。 |
currentPeriodStart / expiresAt | string | 最大已存在明确期次的开始/结束时间。失败期也会推进这组真实期链边界,可用于核查下一期通知是否缺失;它不代表该期已支付,也不直接决定生效状态。 |
支付链接口返回该订阅的每一期正式支付订单,包括扣款失败的期数。subscriptionCycleNo 是上游明确提供的真实期数,缺失时网关不会猜测或补造。续订必须先找到精确上一期;上一期缺失时异步重试,不跳期处理。
平台账期从首期明确支付成功开始计时。每期订单保存 subscriptionPeriodStart(含)与 subscriptionPeriodEnd(不含),下一期开始等于上一期结束;月和年始终以首期日期为锚点,避免月底漂移。失败续订仍有账期,但不延长已支付有效期;通知迟到或重复不会移动账期。首期未成功和普通支付的这两个字段为空。账期由平台管理,不代表渠道返回的扣款排程。
订阅支付订单字段
| 字段 | 类型 | 说明 |
|---|---|---|
paymentNo | string | 该期网关支付订单号,全局唯一。 |
merchantOrderNo | string | 该期内部订单引用。 |
orderInitiator | integer | 1 表示商户发起首期;2 表示上游续订通知触发。 |
subscriptionNo | string | 所属网关订阅号,也是订阅管理数据唯一 ID。 |
subscriptionCycleNo | integer | 上游明确提供或确认的真实期数,从 1 开始;网关不会猜测缺失期数。 |
subscriptionPeriodStart | string / null | 本期平台账期开始,东八区 yyyy-MM-dd HH:mm:ss;包含此时刻。首期未成功时为空。 |
subscriptionPeriodEnd | string / null | 本期平台账期结束,东八区 yyyy-MM-dd HH:mm:ss;不包含此时刻,也是下一期开始。失败续订同样保留此值。 |
amount | integer | 该期金额,单位为分。 |
feeAmount | integer | 该期商户手续费,单位为分。 |
netAmount | integer | 该期商户净额,单位为分。 |
currency | string | 该期币种。 |
paymentMethod | string | 该期支付方式。 |
status | integer | 支付订单状态。扣款失败仍完整保留为 6。 |
providerCode | string | 处理该期支付的渠道 Adapter 编码。 |
providerSubscriptionId | string/null | 首订确认的渠道订阅关联值。Elanlink 为 recurring_id。 |
providerTransactionId | string/null | 该期上游交易号。 |
providerEventId | string/null | 确认该期当前结果的稳定上游事件号。 |
providerStatus | string/null | 渠道返回的综合状态原值。 |
providerOrderStatus | string/null | 该期扣款状态原值,不与订阅状态混用。 |
providerRecurringStatus | string/null | 上游订阅状态原值。 |
providerDeductionDate | string/null | 上游明确返回的该期扣款日期。 |
providerContractName | string/null | 上游返回的原始合同名称,仅作为渠道证据展示。 |
failureCode | string/null | 该期扣款失败码。 |
failureMessage | string/null | 该期安全失败描述。 |
failureSolution | string/null | 上游返回的安全处理建议。 |
resultSource | integer | 平台结果来源编号。 |
notificationStatus | integer | 本期商户通知生命周期;尚未生成投递任务时为 1,完整取值见“业务状态码”。 |
attemptedAt | string/null | 实际发起扣款或收到扣款结果的时间。 |
completedAt | string/null | 该期已保存的结果完成时间(上游精确时间或首次确认终态时的平台时间),与支付查询一致;未记录时为 null。失败期也返回已有时间,不用查询时间补造。 |
createdAt | string | 该期支付订单创建时间。 |
paidAt | string/null | 该期成功时间:渠道时间优先,无精确渠道时间时取首次确认成功的当前时间并固定。未成功为空,后续查询不改写。 |
PAYOUTS
代付
/payouts创建代付/payouts?page=1&pageSize=50代付列表/payouts/{payoutNo}查询代付/payouts/{payoutNo}/query主动查询上游请求字段
请求须携带商户签名和 Idempotency-Key。使用后台绑定的唯一代付参数;商户不能指定渠道。支付方式和收款资料须满足已启用渠道能力。
| 字段 | 规则 |
|---|---|
merchantPayoutNo | 必填,商户内唯一,最长 128 字符。 |
amount | 必填,正整数分;按渠道代付单笔范围及商户独立代付日限额校验,不占用收款额度。 |
currency | 必填,三位币种代码,必须在绑定参数支持币种内。 |
paymentMethod | 必填,最长 64 字符,使用后台启用的支付方式编码。 |
recipientType | 必填,从 1 开始的收款方类型;按已启用渠道契约提供。 |
recipientName | 必填,收款人名称,最长 128 字符。 |
recipientCountry | 必填,两位国家代码。 |
recipientDetails | 必填,1–64 项字符串键值;键最长 64 字符,值最长 2048 字符。完整收款资料仅用于本次上游调用;银行账户、IBAN、路由号等持久化前替换为 *,不提供恢复原值的接口。 |
purpose | 可选,用途,最长 500 字符。 |
notifyUrl | 可选,HTTPS 订单通知地址,最长 2048 字符。未提供时使用唯一启用的默认 Webhook;两者都没有时拒绝创建。 |
提交前原子预占本金加手续费。币种账户缺失时按零余额进入建账流程;余额不足则回滚,不发起上游代付。成功扣减冻结资金,明确失败、取消或关闭释放;未知结果保持冻结并查单确认。
代付响应字段
创建和详情返回 data 对象;列表返回同结构的 data 数组。金额均为整数分,时间为东八区 yyyy-MM-dd HH:mm:ss。
| 字段 | 说明 |
|---|---|
payoutNo | 平台代付号 |
merchantPayoutNo | 商户代付单号 |
amount | 代付本金(分) |
feeAmount | 商户代付手续费(分) |
totalDebitAmount | 商户扣款总额:本金加手续费(分) |
currency | 交易币种 |
paymentMethod | 支付方式 |
channelCode | 渠道编码 |
providerPayoutId | 上游代付号,未取得为空 |
status | 代付状态,5 为成功 |
resultSource | 结果来源整数码 |
recipientAccountMask | 平台生成的固定掩码 *,不属于请求字段 |
createdAt | 创建时间 |
paidAt | 成功时间,未成功为空 |
FUNDS
资金流水
/funds/ledger?page=1&pageSize=50查询当前商户资金流水资金流水由支付、退款、代付或人工调整产生,只读返回。每条包含 entryNo、businessType、businessNo、entryType、有符号整数分 changeAmount、currency 和 occurredAt。接口只返回当前已认证商户自己的资金流水;渠道支付参数余额及其变化记录属于内部运营数据,不通过商户 API 暴露。不同币种不得直接汇总。
REPORTS
每日交易报表
/daily-reports?from=2026-08-01&to=2026-08-20&status=3查询日报/daily-reports/{yyyy-MM-dd}/download下载 Excel每天 01:00(Asia/Shanghai)生成前一日数据;即使没有交易也会生成空报表。下载接口不接受临时维度筛选。
列表可传 from、to(yyyy-MM-dd)、status、page、pageSize,默认第 1 页、每页 20 条,最多 200 条。成功响应 data 为 {items, page, pageSize, total},不是直接返回数组。
| items 字段 | 说明 |
|---|---|
summaryNo、reportDate | 报表编号、报表日期 |
paymentCount、paymentSuccessCount、paymentFailedCount | 支付总笔数、成功笔数、失败笔数 |
refundCount、refundSuccessCount | 退款总笔数、成功笔数 |
payoutCount、payoutSuccessCount、payoutFailedCount | 代付总笔数、成功笔数、失败笔数 |
fileName、fileSize、fileHash、rowCount | 文件名、字节数、文件摘要、明细行数 |
status、generatedAt、downloadUrl | 报表状态、生成时间、下载地址;下载失败不能当作空报表 |
currencies | 按币种分列的金额汇总,全部为整数分;包括支付/退款/代付金额、手续费、人工增减和净变动。完整字段见 OpenAPI 的 DailyCurrencySummary,不得跨币种相加。 |
WEBHOOK
商户异步通知
只有支付或订阅扣款明确成功后才投递。请求提供 notifyUrl 时只使用该地址;未提供时回退商户默认 Webhook;两者都没有则交易创建失败。处理中、需要客户端动作、失败和未知结果都不产生下游支付状态通知。
商户回调响应体去除首尾空白后必须精确等于 SUCCESS,否则视为失败并进入延迟重试。不要仅依赖 HTTP 状态码。
首期订阅成功事件类型为 subscription.activated,其 data 携带创建响应中已经返回的平台 subscriptionNo、首期 paymentNo 和 cycleNo=1,用于确认该订阅已经生效;续订成功事件为 subscription.renewed。两类成功事件的 data 还包含 subscriptionPeriodStart、subscriptionPeriodEnd,与对应订单查询结果一致。失败期保留在查询链中但不投递失败通知。
订阅支付通知字段(首订与续订相同)
| 字段路径 | 类型 | 必有 | 说明 |
|---|---|---|---|
data.subscriptionNo | string | 是 | 平台订阅唯一 UUID,与创建响应中的订阅号一致;不是期数或渠道订阅号。 |
data.paymentNo | string | 是 | 本期正式支付订单号,每一期不同。 |
data.cycleNo | integer | 是 | 实际期数:首期为 1,第一次续订为 2,依次递增。中间一期失败时不重新编号;第 2 期失败、第 3 期成功,通知仍为 3。字段在 data 内,不在顶层。 |
data.subscriptionPeriodStart | string | 是 | 本期平台账期开始,包含此时刻,下一期开始等于本期结束。 |
data.subscriptionPeriodEnd | string | 是 | 本期平台账期结束,不包含此时刻。重发不会重算。 |
data.amount | integer / int64 | 是 | 本期实际支付金额,单位为分,100 表示 1.00;不是累计金额。 |
data.currency | string | 是 | 本期支付币种,例如 USD。 |
data.status | integer | 是 | 本期支付状态,成功为 5;不是订阅续存或生效状态。 |
data.paidAt | string/null | 是 | 本期已保存的成功时间:渠道有精确时间则取渠道时间,没有则取首次确认成功的当前时间。不是投递时间,重试和手动重发保持原值;历史空值不回填。 |
occurredAt | string | 是 | 商户事件建立时间,在顶层;不是本次投递时间。重试、手动重发保持原值。 |
上述业务时间统一使用东八区 yyyy-MM-dd HH:mm:ss。以下为第 2 期成功通知的格式示例,并非真实交易记录。既有历史事件保留原始内容;新增字段不会通过重发补写到历史报文。
{
"eventId": "evt_example_subscription_cycle",
"merchantId": "83946179674509312",
"eventType": "subscription.renewed",
"aggregateType": "PAYMENT",
"aggregateId": "P12345678901234567",
"aggregateVersion": 2,
"data": {
"subscriptionNo": "0123456789abcdef0123456789abcdef",
"paymentNo": "P12345678901234567",
"cycleNo": 2,
"subscriptionPeriodStart": "2026-08-28 10:00:00",
"subscriptionPeriodEnd": "2026-08-29 10:00:00",
"amount": 100,
"currency": "USD",
"status": 5,
"paidAt": "2026-08-28 10:00:03"
},
"occurredAt": "2026-08-28 10:00:04"
}
单次支付成功通知示例
{
"eventId": "evt_...",
"merchantId": "83946179674509312",
"eventType": "payment.succeeded",
"aggregateType": "PAYMENT",
"aggregateId": "P...",
"aggregateVersion": 2,
"data": {
"paymentNo": "P...",
"status": 5,
"amount": 1234,
"currency": "USD"
},
"occurredAt": "2026-08-20 13:00:00"
}
| 请求头 | 说明 |
|---|---|
X-Gateway-Event-Id | 稳定事件编号,用于业务幂等 |
X-Gateway-Timestamp | 签名时的 Unix 秒 |
X-Gateway-Signature | 64 位小写十六进制 HMAC-SHA256 |
signedText = X-Gateway-Timestamp + "." + rawRequestBody
expected = lowercase_hex(
HMAC_SHA256(webhookSecret, signedText)
)
Webhook Secret 是商户级单一凭据,不属于某个 URL,也不发送 Secret 版本。商户后台允许保存多条默认地址,但同一时间只启用一条;订单传入 notifyUrl 时仍只投递该订单地址。新增或切换地址不会改变 Secret;商户生成新的 Webhook Secret 后,旧 Secret 继续用于通知签名 10 分钟,随后自动使用新 Secret。
这 10 分钟内不允许再次轮转 Webhook Secret;后台显示剩余时间并禁用轮转操作,服务端也会拒绝并发或绕过页面的再次轮转。请在过渡期结束前部署新 Secret,并在过渡期同时接受新旧签名。该限制不改变 API Secret 的独立凭据有效期规则。
验签必须使用收到的 UTF-8 原始请求体。首次失败后依次延迟 1、5、15、30、60、360、1440 分钟重试,总计最多投递 8 次。
BUSINESS STATUS
业务状态码
平台状态使用同一套全局编号:同一个数字在任何业务中含义完全一致,不需要的编号直接留空。商户 API、Webhook、商户后台和超级后台的内部状态字段统一返回整数编号。英文状态仅作为文档语义名称展示,不作为接口值。0 只可作为查询条件中的“全部/未指定”,永远不是真实业务状态。
| 平台编号 | 英文值 | 中文描述 | 适用范围 |
|---|---|---|---|
1 | CREATED | 已创建 | 支付、退款、代付、通知聚合 |
2 | PENDING | 等待处理 | 通知任务、Inbox、日报、对账批次 |
3 | PROCESSING | 处理中 | 支付、退款、代付、任务、日报、对账批次 |
4 | RETRYING | 等待重试 | 可恢复的异步任务 |
5 | SUCCEEDED | 成功 | 支付、退款、代付、任务、日报、对账批次 |
6 | FAILED | 失败 | 支付、退款、代付、任务、日报、对账批次 |
7 | CANCELLED | 已取消 | 支付、退款、代付、订阅、任务 |
8 | EXPIRED | 已过期 | 支付等有有效期的业务 |
9 | ACTIVE | 有效 | 订阅 |
11 | CLOSED | 已关闭 | 代付人工关闭、有限期订阅自然结束 |
12 | ENABLED | 启用 | 可启停资源和能力 |
13 | DISABLED | 停用 | 可启停资源和能力 |
14 | DRAFT | 草稿 | 配置版本 |
15 | PUBLISHED | 已发布 | 配置版本 |
16 | HISTORICAL | 历史版本 | 配置版本 |
17 | OPEN | 待处理 | 对账差异 |
18 | RESOLVED | 已解决 | 对账差异 |
19 | IGNORED | 已忽略 | 对账差异 |
20 | NOT_REFUNDED | 未退款 | 支付订单退款汇总 |
21 | PARTIALLY_REFUNDED | 部分退款 | 支付订单退款汇总 |
22 | FULLY_REFUNDED | 全额退款 | 支付订单退款汇总 |
23 | NORMAL | 正常 | 商户运行模式 |
24 | STOPPED | 停止使用 | 商户运行模式 |
25 | RECEIVE_ONLY | 只能收款,不允许退款或代付 | 商户运行模式 |
26 | PAYOUT_ONLY | 只能代付,不允许收款或退款 | 商户运行模式 |
27 | PORTAL_ONLY | 仅商户后台 | 商户运行模式 |
28 | API_READ_ONLY | API 只读 | 商户运行模式 |
各商户 API 字段允许值
| 字段 | 允许值 | 判定说明 |
|---|---|---|
支付订单 status | 1、3、5、6、7、8 | 只有 5 表示支付成功 |
退款订单 status | 1、3、5、6、7 | 只有 5 表示退款成功 |
代付订单 status | 1、3、5、6、7、11 | 只有 5 表示代付成功 |
订阅 effectiveStatus | 8、9 | 9 生效中;8 已到期 |
订阅 renewalStatus | 7、9、11 | 9 续存;7 已取消;11 有限期订阅已自然完成 |
商户通知 notificationStatus | 1、2、3、4、5、6、7 | 1 表示尚未生成投递任务;只有 5 表示商户已正确响应 SUCCESS |
支付退款汇总 refundState | 20、21、22 | 分别表示未退款、部分退款和全额退款 |
日报 status | 2、3、5、6 | 直接返回平台整数编号:等待处理、处理中、成功、失败;查询条件 0 表示全部 |
providerStatus、providerOrderStatus、providerRecurringStatus 是上游渠道原始字符串,只作为证据展示。它们不属于平台状态码,不能跨渠道比较,也不能用于判断平台业务成功。RESPONSE CODES
第一层响应码
code=200 只表示本次 API 请求处理成功。非 200 表示接口处理失败,data 为 null;交易结果仍必须读取业务对象的 status。
| code | HTTP | message | 中文描述 |
|---|---|---|---|
200 | 200 | Success | 接口处理成功,不代表交易成功 |
1001 | 400 | Invalid request | 请求内容或业务参数无效 |
1002 | 400 | Request validation failed | 请求字段校验失败 |
1003 | 404 | Resource not found | 资源不存在 |
1004 | 409 | Idempotency conflict | 幂等键与首次请求内容冲突 |
1005 | 409 | Resource state conflict | 当前资源状态不允许该操作 |
1006 | 405 | Method not allowed | HTTP 方法不允许 |
1007 | 413 | Request body is too large | 请求体超过大小限制 |
1101 | 401 | Authentication required | 缺少认证信息 |
1102 | 401 | Invalid merchant credential | 商户凭据无效 |
1103 | 401 | Invalid request timestamp | 请求时间戳格式无效 |
1104 | 401 | Request timestamp expired | 请求时间戳已过期 |
1105 | 401 | Invalid request nonce | Nonce 格式无效 |
1106 | 401 | Replay request detected | 检测到重复请求 |
1107 | 401 | Invalid request signature | 请求签名无效 |
1108 | 403 | Access denied | 当前身份没有接口或页面访问权限 |
1202 | 400 | Invalid callback URL | 回调地址不是有效 HTTPS URL |
1203 | 409 | Credential rotation is still in progress | Webhook Secret 尚在过渡期,暂不能再次轮转 |
2001 | 404 | Payment order not found | 支付订单不存在 |
2101 | 422 | Transaction amount is outside the allowed range | 交易金额超出允许范围 |
2102 | 422 | Daily transaction count limit exceeded | 超过每日交易笔数限制 |
2103 | 422 | Daily transaction amount limit exceeded | 超过每日交易金额限制 |
2104 | 403 | Transaction is not allowed | 商户当前状态或能力不允许交易 |
2105 | 409 | Risk usage update conflict | 风控用量并发更新冲突 |
3001 | 503 | Payment provider is unavailable | 支付渠道不可用 |
3002 | 202 | Payment provider result is unknown | 上游结果暂时无法确认 |
4001 | 401 | Invalid provider webhook signature | 上游通知签名无效 |
9001 | 500 | Internal server error | 平台内部错误 |
9002 | 500 | Report file is missing or unreadable | 已发布报表文件缺失或不可读,需恢复原文件,仍记录异常事件。 |