15 KiB
15 KiB
乐刷支付接入文档
本文根据语雀《联合收单接口文档 / 商户交易》整理,作为本项目接入乐刷扫码/简易支付的内部记录。原始文档地址: https://www.yuque.com/hayley-boppa/ws2xbg/lk89dvro0oc69f1m
接口总览
乐刷交易接口统一使用 POST,大部分能力共用网关路径:
- 测试网关:
https://t-paygate.lepass.cn/cgi-bin/lepos_pay_gateway.cgi - 生产网关:
https://paygate.leshuazf.com/cgi-bin/lepos_pay_gateway.cgi - Content-Type:
application/x-www-form-urlencoded - 金额单位:分,RMB,最小 1 分,不允许小数。
- 通信返回中的
resp_code=0只表示通信成功,业务是否成功要看result_code和status。
接口目录:
| 场景 | service / 地址 | 说明 | 本期接入 |
|---|---|---|---|
| 统一下单 | service=get_tdcode |
主扫,C 扫 B,返回二维码链接或简易支付跳转链接 | 是 |
| 条码支付 | service=upload_authcode |
被扫,B 扫 C,用户出示付款码 | 否 |
| 支付结果通知 | 商户通知 URL | 乐刷推送支付成功等结果 | 是 |
| 扫码交易结果查询 | service=query_status |
查询交易结果 | 是 |
| 扫码退款 | service=unified_refund |
发起退款,退款有效期和次数受限制 | 暂缓 |
| 扫码退款查询 | service=unified_query_refund |
查询退款状态 | 暂缓 |
| 扫码退款通知 | 商户通知 URL | 乐刷推送退款状态 | 暂缓 |
| 订单关闭 | service=close_order |
关闭未支付订单 | 暂缓 |
| 授权码查询 openid | service=query_openid |
条码/JSAPI 配套 | 暂缓 |
| 授权码查询银联 user_id | service=query_userid |
银联 JS 支付配套 | 暂缓 |
签名规则
请求、应答和通知都需要验签。当前代码只实现 MD5,SM3 先记录规则但不接入。
MD5 签名步骤:
- 取所有参与签名的参数集合
M。 - 默认过滤空值,按参数名 ASCII 升序排序。
- 按
key=value拼接为key1=value1&key2=value2,字段名和值使用原始值,不做 URL Encode。 - 末尾追加
&key=商户请求密钥。 - 对最终字符串做 MD5,结果转大写。
注意:
- 请求签名:一般不包含
sign本身。 - 应答验签:按乐刷返回参数验签,实际返回字段可能因升级增加,验签时要允许新增字段。
- 支付/退款通知验签:
error_code、leshua和sign不参与签名,其他返回字段按原样参与;空值参与签名;密钥只使用后台支付配置中乐刷提供的通知验签密钥。实测通知携带sign_type=MD5,按普通返回字段参与签名。 - 乐刷 XML 通知里的空标签也属于空值参数,必须保留并参与签名,例如
<goods_tag></goods_tag>应进入待签名串为goods_tag=。 sign_type=SM3时签名结果为 64 位;不上传sign_type默认 MD5。
统一下单
用于主扫支付,消费者主动扫码或打开简易支付收银台。本项目先接扫码/简易支付。
请求固定字段:
| 字段 | 必填 | 说明 | 本项目取值 |
|---|---|---|---|
service |
是 | 接口名 | get_tdcode |
merchant_id |
是 | 乐刷商户号 | 后台支付配置中的商户号 |
third_order_id |
是 | 商户内部订单号,同商户下唯一 | 当前使用订单号 order_no |
amount |
是 | 订单金额,单位分 | 租金 + 押金 |
pay_way |
是 | 支付类型 | 默认 ZFBZF,可配置 |
jspay_flag |
是 | 支付形态 | 默认 2 简易支付 |
nonce_str |
是 | 32 位随机字符串 | 后端生成 |
sign |
是 | 签名 | MD5 |
常用可选字段:
| 字段 | 说明 |
|---|---|
sign_type |
MD5 或 SM3,不传默认 MD5。当前只支持 MD5。 |
notify_url |
支付结果通知地址,必须是乐刷可访问的绝对路径。 |
jump_url |
简易支付前台跳转地址。文档写 jspay_flag=2 时必传,但也提示受微信支付宝限制可不传;生产建议配置。 |
client_ip |
发起交易的客户端 IP。 |
body |
商品描述,不能包含换行等特殊字符。 |
attach |
附加数据,成功后原样返回。 |
order_expiration |
订单有效期,单位秒,最大 600 秒;支付宝建议 60 的整数倍。 |
jspay_flag:
| 值 | 说明 |
|---|---|
0 |
支付宝 Native、银联 Native 扫码支付 |
1 |
微信/支付宝/银联 JSAPI |
2 |
微信、支付宝简易支付,跳转乐刷收银台 |
3 |
微信/支付宝小程序 |
pay_way:
| 值 | 说明 |
|---|---|
WXZF |
微信 |
ZFBZF |
支付宝 |
UPSMZF / UPSMPAY |
银联二维码,不同章节/回调字段可能返回不同值 |
DCPAY |
数字货币 |
下单返回重点字段:
| 字段 | 说明 |
|---|---|
resp_code |
通信状态,0 成功 |
result_code |
业务结果,0 成功 |
error_code / error_msg |
错误码和错误描述 |
merchant_id |
乐刷商户号 |
third_order_id |
商户订单号 |
leshua_order_id |
乐刷订单号 |
td_code |
二维码链接,jspay_flag=0/1/2 可能返回 |
jspay_url |
简易支付跳转地址 |
jspay_info |
JSAPI/小程序/银联 JS 支付信息 |
pay_way |
支付类型 |
sign |
返回签名 |
支付结果通知
通知采用 HTTP POST,建议使用 application/x-www-form-urlencoded 接收。支付通知可能延迟或失败,文档建议主接交易查询接口。本项目同时接通知和查单。
通知特点:
- 支付成功后乐刷一般约 30 秒推送通知。
- 通知频率示例:
0s / 15s / 30s / 1m / 4m / 34m / 64m / 94m / 124m / 184m。 - 回调处理时间要求 5 秒内。
- 乐刷可能重复通知,业务必须幂等。
- 通知成功响应必须是纯文本
000000,没有 JSON 和引号;其他响应或超时都会重试。
支付成功通知关键字段:
| 字段 | 必填 | 说明 |
|---|---|---|
sign |
是 | MD5 签名 |
sign_type |
否 | 签名类型 |
merchant_id |
是 | 乐刷商户号 |
leshua_order_id |
是 | 乐刷订单号 |
third_order_id |
是 | 商户订单号 |
amount |
是 | 订单金额,分 |
status |
是 | 订单状态 |
pay_way |
是 | 支付类型 |
pay_time |
是 | 支付时间,如 2018-08-20 19:19:19 |
bank_type |
否 | 银行类型 |
openid / sub_openid |
否 | 用户标识 |
out_transaction_id |
否 | 微信、支付宝等上游订单号 |
attach |
否 | 下单附加数据原样返回 |
trade_type |
否 | MICROPAY、NATIVE、JSAPI、SmPgPay、JSAPIQuick 等 |
channel_order_id |
否 | 通道订单号 |
settlement_amount |
否 | 实际结算金额,分 |
discount_amount |
否 | 优惠金额,分 |
通知验签规则:
error_code、sign不参与签名。- 空值参与签名。
- 使用乐刷提供的通知验签密钥。
扫码交易结果查询
查询接口用于主动确认交易状态。文档要求:除非返回明确的支付成功、支付失败、订单关闭等最终状态,其他错误或未支付状态都需要继续查询;超过一定时间未支付可调用关单。
请求字段:
| 字段 | 必填 | 说明 |
|---|---|---|
service |
是 | 固定 query_status |
merchant_id |
是 | 乐刷商户号 |
third_order_id |
二选一 | 商户订单号 |
leshua_order_id |
二选一 | 乐刷订单号,优先使用 |
nonce_str |
是 | 随机字符串 |
sign_type |
否 | 签名类型 |
sign |
是 | 签名 |
返回重点字段:
| 字段 | 说明 |
|---|---|
resp_code / result_code |
通信和业务结果 |
status |
订单状态 |
leshua_order_id |
乐刷订单号 |
third_order_id |
商户订单号 |
amount |
订单金额 |
pay_way |
支付类型 |
pay_time |
支付完成时间,成功时返回 |
refund_amount |
已退款金额 |
simple_url_flag |
1 表示简易支付 |
interm_state |
支付中间态,如 NOTPAY、USERPAYING |
退款与退款查询
本期暂不实现退款,但记录接口便于后续接入。
退款限制:
- 超过三个月或发起后超过 60 天的订单无法退款,具体以乐刷返回为准。
- 同一交易订单最多发起 50 次部分退款。
- 退款接口一般返回退款中,如需最终状态要调用退款查询。
退款请求字段:
| 字段 | 必填 | 说明 |
|---|---|---|
service |
是 | 固定 unified_refund |
merchant_id |
是 | 乐刷商户号 |
third_order_id |
二选一 | 商户订单号 |
leshua_order_id |
二选一 | 乐刷订单号,优先使用 |
merchant_refund_id |
是 | 商户退款单号,同商户下唯一,不能含 _ 等特殊字符 |
refund_amount |
是 | 退款金额,分 |
refund_type |
否 | 0 不使用余额,1 可使用余额,2 仅使用余额 |
notify_url |
否 | 退款结果通知地址 |
nonce_str |
是 | 随机字符串 |
sign |
是 | 签名 |
退款查询请求字段:
| 字段 | 必填 | 说明 |
|---|---|---|
service |
是 | 固定 unified_query_refund |
merchant_id |
是 | 乐刷商户号 |
third_order_id / leshua_order_id |
二选一 | 支付订单标识 |
merchant_refund_id / leshua_refund_id |
二选一 | 退款单标识 |
nonce_str |
是 | 随机字符串 |
sign |
是 | 签名 |
退款返回/通知重点字段:
| 字段 | 说明 |
|---|---|
status |
退款状态,见订单状态表 |
refund_amount |
退款金额 |
merchant_refund_id |
商户退款单号 |
leshua_refund_id |
乐刷退款单号 |
total_amount |
原订单总金额 |
order_balance |
退款后订单余额,退款请求返回可能有 |
refund_time |
退款成功时间 |
settlement_refund_amount |
实际退款金额 |
discount_refund_amount |
优惠退款金额 |
failure_reason |
退款失败原因 |
退款通知成功也需要返回纯文本 000000。
订单关闭
用于关闭未支付订单。本期暂不实现。
限制:
- 条码支付订单需要下单 15 秒后才允许关单。
- 统一下单订单无此 15 秒限制。
- 银联二维码不支持关单。
请求字段:
| 字段 | 必填 | 说明 |
|---|---|---|
service |
是 | 固定 close_order |
merchant_id |
是 | 乐刷商户号 |
third_order_id |
二选一 | 商户订单号 |
leshua_order_id |
二选一 | 乐刷订单号,优先使用 |
nonce_str |
是 | 随机字符串 |
sign |
是 | 签名 |
返回字段包含 status、leshua_order_id、pay_way、amount 等。
授权码相关
授权码接口主要服务条码支付、微信 JSAPI、银联 JS 支付,本期不接。
查询微信 openid:
service=query_openid- 必填:
merchant_id、auth_code、appid、nonce_str、sign - 返回:
openid、sub_openid等。
查询银联云闪付 user_id:
service=query_userid- 必填:
merchant_id、user_auth_code、nonce_str、sign - 可选/条件:
app_up_identifier - 返回:
user_id等。
状态码
扫码/异步通知常见订单状态:
| 值 | 说明 | 本项目处理 |
|---|---|---|
0 |
支付中 | paying |
2 |
支付成功 | paid,推进订单待交接 |
6 |
订单关闭 | closed |
8 |
支付失败 | failed |
10 |
退款中 | 暂按 paying/后续扩展退款状态 |
11 |
退款成功 | 暂缓 |
12 |
退款失败 | 暂缓 |
30 |
刷卡支付成功 | 当前也按支付成功处理 |
31 |
刷卡撤销成功 | 暂缓 |
32 |
刷卡退货成功 | 暂缓 |
33 |
刷卡冲正成功 | 暂缓 |
41 |
预授权成功 | 暂缓 |
43 |
预授权撤销成功 | 暂缓 |
45 |
预授权完成请求成功 | 暂缓 |
47 |
预授权完成通知成功 | 暂缓 |
49 |
预授权完成撤销成功 | 暂缓 |
常见错误码
| 错误码 | 说明 |
|---|---|
-20001 |
参数错误或无效 |
-20002 / -1002 |
无效乐刷商户号 |
-20003 |
商户订单号格式有误 |
-20004 / -4006 |
乐刷订单不存在 |
-20005 |
服务错误 |
-20006 |
验签失败 |
-20007 |
签名 Key 未配置 |
-20008 |
支付类型错误 |
-20009 |
订单金额填写有误 |
-20010 / -4027 |
系统错误/系统异常 |
-20011 |
非法参数 |
-20012 |
授权码为空 |
-20013 |
非法授权码 |
-20014 |
未知类型授权码 |
-20015 |
非法公众号支付标识 |
-20016 |
无效乐刷订单号 |
-20018 |
无效第三方订单号或乐刷订单号 |
-20019 |
订单状态不允许退款 |
-20020 |
订单未退款 |
-20023 / -5017 |
订单可退余额不足 |
-20024 |
乐刷或第三方订单号必填 1 个 |
-20025 |
乐刷或第三方退款订单号必填 1 个 |
-20026 / -1006 |
第三方订单号已存在 |
-20027 |
该订单已支付 |
-4004 |
订单正在处理中 |
-5103 |
商户退款 ID 已存在 |
-5014 |
商户无退款权限 |
-5015 |
暂不支持退款 |
-5018 |
订单退款次数超限 |
-2125 |
交易被风控拦截 |
-5035 |
下单异常,可能是通道网络、通道状态或通道商户异常,以 error_msg 为准 |
本项目接入映射
配置来源:
| 配置项 | 说明 |
|---|---|
| 后台支付配置 | 维护服务商、商户号、网关、请求签名密钥、通知验签密钥、回调地址、跳转地址、默认支付方式等业务配置。 |
PAYMENT_CONFIG_ENCRYPTION_KEY |
部署环境变量,用于加密存储后台支付配置中的敏感密钥,必须在生产环境固定且不要更换。 |
后端 API:
| API | 说明 |
|---|---|
POST /api/wallet/recharge/pay |
创建钱包充值支付单,返回扫码支付二维码链接;mock 模式会立即模拟充值成功。 |
POST /api/wallet/recharge/pay/:id/query |
查询钱包充值支付单,并主动向乐刷查单。 |
POST /api/orders/:id/pay |
订单只使用钱包余额支付,不再直接调用乐刷。 |
POST /api/payments/leshua/notify |
乐刷支付通知回调,不需要登录鉴权,成功返回 000000。 |
数据模型:
- 新增
payment_orders表保存支付单、渠道单号、支付链接、请求/响应原文、状态和支付时间。 - 乐刷支付单仅用于钱包充值,
order_id = 0,third_order_id使用payment_no。 - 渠道确认钱包充值成功后,向用户
available写入channel_recharge流水。 - 订单支付不再创建乐刷支付单,只扣用户钱包
available并转入frozen,后续结账沿用现有冻结释放/结算逻辑。
当前范围:
- 已接:钱包扫码/简易支付充值、查单、支付成功通知、mock 跑通链路;订单钱包余额支付。
- 暂缓:条码支付、JSAPI/小程序必要 openid 获取、退款、退款通知、关单、刷卡交易查询、SM3 签名。