快速开始
对接流程
- 创建支付应用 → 获取 Payment ID 和 Secret Key
- 用户下单 → 调用发起支付接口
- 跳转支付 → 用户在 NodeLoc 登录并支付
- 接收回调 → 浏览器跳转到你的回调地址
- 查询状态(可选)→ 主动查询支付结果
- 转账给其他用户(可选)→ 调用转账接口将申请人的积分转给指定用户
创建支付应用
访问管理页面
创建支付应用需要白银会员 (TL1) 及以上,新应用需管理员审批后方可使用。
填写应用信息
保存密钥
创建成功后会显示:- Payment ID:
pay_xxxxxxxxxxxxxxxxxx - Secret Key:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
发起支付
API 接口
请求参数
签名算法
- 准备参数:
amount,description,order_id - 按键名排序: 字母顺序排列参数
- 拼接字符串: 格式
key1=value1&key2=value2&key3=value3 - 计算密钥:
token_hash = SHA256(your_token)// 你的 token 是 tk_xxx 格式 - 生成签名:
signature = HMAC-SHA256(token_hash, param_string)
your_token是申请时获得的 token(格式:tk_xxx...)token_hash是 token 的 SHA256 哈希(64位十六进制字符串)- 不要直接用 token 作为 HMAC 密钥!
响应数据
成功时返回:跳转支付
将用户重定向到响应中的payment_url,用户会:
- 自动跳转到登录页(如未登录)
- 登录后返回支付页面
- 确认订单并完成支付
- 支付成功后跳转到你的回调地址
处理回调
回调方式
支付成功后,用户浏览器会跳转到你设置的回调地址,所有参数以查询字符串形式传递。回调参数(URL 查询参数)
回调 URL 示例
验证签名
验证步骤:- 提取签名参数: 从 URL 中获取
signature - 提取其他参数: 所有参数除了
signature本身 - 按键名排序: 字母顺序排列
- 拼接字符串: 格式
key1=value1&key2=value2... - 计算签名:
HMAC-SHA256(secret_key, param_string) - 比对签名: 计算出的签名与接收到的签名必须完全一致
处理订单
验证签名通过后:- ✅ 检查幂等性: 确保订单未被重复处理
- ✅ 验证金额: 确认
amount与订单金额一致 - ✅ 更新订单状态: 标记为已支付
- ✅ 执行业务逻辑: 发货、开通服务等
- ✅ 显示确认页面: 向用户展示支付成功信息
查询状态
如果回调失败或需要主动确认支付状态,可以使用查询接口。API 接口
请求参数
签名算法
与发起支付相同:- 参数:
transaction_id - 拼接:
transaction_id=txn_xxx - 签名:
HMAC-SHA256(secret_key, param_string)
响应数据
交易状态
建议使用场景
- 定时任务检查待支付订单状态
- 用户主动查询订单状态
- 回调失败后的补救措施
用户转账
将当前支付应用申请人的积分转账给指定的 NodeLoc 用户。常用于外部网站发放奖励、抽奖派发、佣金结算等场景。API 接口
请求参数
手续费规则
手续费根据**申请人的信任等级(Trust Level)**自动计算,费率沿用discourse-points-service 的设置:
同时遵循 TL 对应的
points_transfer_min_amount_tl{0..4} / points_transfer_max_amount_tl{0..4} 限额。
计算公式:
签名算法
- 准备参数:
to_user_id,to_username,amount,order_id - 按键名字母顺序排序
- 拼接字符串:
key1=value1&key2=value2&... - 计算签名:
HMAC-SHA256(token_hash, param_string)token_hash = SHA256(your_token),与发起支付一致
幂等性
- 相同
payment_id+order_id的转账被视为同一笔。 - 若该订单已
completed,会直接返回原结果(不会重复扣款)。 - 若该订单存在但状态不是
completed,请求会被拒绝。
响应数据
成功时(200 OK):
400 / 401):
常见错误
建议使用场景
- 外部站点向 NodeLoc 用户发放奖励
- 抽奖、活动派奖
- 佣金、分润结算
- 收单后回灌积分到指定用户
安全建议
1. 保护密钥
- ❌ 不要硬编码在代码中
- ✅ 使用环境变量或密钥管理服务
2. 使用 HTTPS
- ✅ 生产环境必须使用 HTTPS
- ✅ 回调 URL 必须是 HTTPS 地址
3. 验证签名
- ✅ 所有回调请求必须验证签名
- ✅ 签名不匹配时拒绝请求
4. 防止重复处理
- ✅ 检查订单状态,防止重复处理
- ✅ 转账时使用唯一
order_id保证幂等 - ✅ 使用数据库事务确保原子性
5. 验证金额
- ✅ 验证回调金额与订单金额一致
- ✅ 金额不匹配时记录日志并告警
6. 验证收款人
- ✅ 转账前确认
to_user_id与to_username来自可信来源 - ✅ 切勿仅凭用户名转账,必须同时校验 ID
7. 日志记录
- ✅ 记录所有支付/转账相关操作
- ✅ 记录所有回调请求(包括签名验证失败的)
常见问题
Q: 签名验证失败?
Q: 签名验证失败?
检查以下几点:
- 参数是否按键名字母顺序排序
- 参数拼接格式是否为
key=value&key=value - Secret Key 是否正确
- 验证时是否排除了
signature参数本身 - 字符编码是否一致(UTF-8)
Q: 回调没有收到?
Q: 回调没有收到?
可能原因:
- 回调 URL 设置错误
- 用户关闭了浏览器窗口
- 网络问题导致跳转失败
Q: 如何测试?
Q: 如何测试?
开发环境测试:
- 使用 ngrok 等工具暴露本地服务器
- 在 NodeLoc 创建测试应用
- 设置回调 URL 为 ngrok 地址
- 创建小金额订单测试
Q: 支持退款吗?
Q: 支持退款吗?
目前不支持自动退款,需要联系管理员手动处理。
Q: 订单会过期吗?
Q: 订单会过期吗?
是的,默认 30 分钟未支付会自动过期。
Q: 转账可以转给任意用户吗?
Q: 转账可以转给任意用户吗?
可以,只要你提供的
to_user_id 和 to_username 同时正确并指向同一个 NodeLoc 用户。 转出方固定是申请该 Payment 应用的用户,无法用此接口转出其他人的积分。Q: 转账手续费是多少?
Q: 转账手续费是多少?
手续费按申请人当前的信任等级(TL0~TL4)计算,对应站点设置
points_transfer_fee_rate_tl0 ~ points_transfer_fee_rate_tl4。 申请人扣减 amount + fee,接收方到账 amount。API 参考
发起支付
- URL:
POST /payment/pay/:payment_id/process - 认证: 签名验证
- 请求:
amount,description,order_id,signature - 响应:
payment_url,transaction_id,status,amount
查询状态
- URL:
POST /payment/query/:payment_id - 认证: 签名验证
- 请求:
transaction_id,signature - 响应: 完整交易信息(见上文)
用户转账
- URL:
POST /payment/transfer/:payment_id - 认证: 签名验证
- 转出方: 固定为 Payment 应用申请人
- 请求:
to_user_id,to_username,amount,order_id,signature - 响应:
transaction_id,order_id,status,amount,fee,total_deduction,from_user_id,from_username,to_user_id,to_username,paid_at
支付回调
- 方式: 浏览器 GET 跳转
- URL: 你设置的
callback_url - 认证: 签名验证
- 参数:
transaction_id,external_reference,amount,platform_fee,merchant_points,status,paid_at,signature
易支付兼容接口(V2,RSA 签名)
如果你的系统已经对接过易支付(码上付)这类网关,不用再按上面的 HMAC 接口重写:NodeLoc 直接提供一套易支付 V2 协议的接口,把网关地址换成 NodeLoc、货币换成能量即可。任何支持易支付的程序(商城、发卡、WHMCS 插件等)都能直接用。对接参数
签名规则与易支付一致:取所有非空参数,剔除
sign 和 sign_type,按参数名 ASCII 升序排列,拼成 k1=v1&k2=v2,用商户私钥做 SHA256WithRSA 签名后 base64。NodeLoc 的响应和回调用平台私钥同样方式签名,请用平台公钥验签。所有请求都要带 10 位秒级 timestamp,与服务器时间相差超过 5 分钟会被拒绝。
接口一览
参数名、返回字段与易支付文档相同,以下几点不同:
money是你自己货币的金额(例如"9.90"元),NodeLoc 按应用设置的汇率换算成能量向买家收取(默认汇率 100 时 9.90 元 = 990 能量),四舍五入到整数,不足 1 能量会被拒绝。回调和查询里的money原样返回你传的金额;商户信息里的余额和收入也按汇率折成货币。平台手续费按站点设置从商户到账的能量中扣除。type随便传(alipay、wxpay或留空),只会原样回传;method、device被忽略,pay_type固定返回jump。- 同一个
out_trade_no重复下单会拿到同一个trade_no;已支付的订单再次下单返回code: 1。 - 查询接口的
buyer是付款用户的 NodeLoc 用户名。
V1 旧版接口(MD5 签名)
很多程序(发卡、商城、WHMCS 网关插件等)走的是易支付 V1 协议:submit.php / mapi.php / api.php,用”商户密钥 KEY”做 MD5 签名,没有时间戳。NodeLoc 同样提供,网关地址仍是 https://www.nodeloc.com/payment/api,商户密钥在应用卡片的”商户密钥 KEY(易支付 V1 / MD5)“一栏,可随时重置。
MD5 签名:非空参数剔除
sign、sign_type,按参数名 ASCII 升序拼成 a=b&c=d(值不做 URL 编码),末尾直接拼接商户密钥后取 MD5 小写。V1 订单支付后的异步通知和同步跳转参数为 pid、trade_no、out_trade_no、type、name、money、trade_status、param、sign、sign_type=MD5,同样用商户密钥验签,异步通知请返回 success。
同一个应用可以同时接 V1 和 V2:请求里 sign_type=RSA 走 V2 验签,否则按 V1 的 MD5 处理。
支付结果通知
买家支付成功后:- 异步通知:NodeLoc 以 GET 请求你的
notify_url,参数为pid、trade_no、out_trade_no、api_trade_no、type、trade_status=TRADE_SUCCESS、addtime、endtime、name、money、param、buyer、timestamp、sign、sign_type。你的服务器验签后需返回字符串success;否则会在 1 分钟、5 分钟、30 分钟、2 小时、12 小时后重试,共 5 次。 - 同步跳转:买家浏览器被带回
return_url,带同样的参数。
sign 并检查 trade_status 是否为 TRADE_SUCCESS;将来可能增加回调字段,验签时请把所有非空参数都算进去。
祝对接顺利! 🚀
