Skip to main content

快速开始

对接流程

  1. 创建支付应用 → 获取 Payment ID 和 Secret Key
  2. 用户下单 → 调用发起支付接口
  3. 跳转支付 → 用户在 NodeLoc 登录并支付
  4. 接收回调 → 浏览器跳转到你的回调地址
  5. 查询状态(可选)→ 主动查询支付结果
  6. 转账给其他用户(可选)→ 调用转账接口将申请人的积分转给指定用户

创建支付应用

访问管理页面

创建支付应用需要白银会员 (TL1) 及以上,新应用需管理员审批后方可使用。

填写应用信息

保存密钥

创建成功后会显示:
  • Payment ID: pay_xxxxxxxxxxxxxxxxxx
  • Secret Key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Secret Key 只显示一次,请立即保存!

发起支付

API 接口

请求参数

签名算法

  1. 准备参数: amount, description, order_id
  2. 按键名排序: 字母顺序排列参数
  3. 拼接字符串: 格式 key1=value1&key2=value2&key3=value3
  4. 计算密钥: token_hash = SHA256(your_token) // 你的 token 是 tk_xxx 格式
  5. 生成签名: signature = HMAC-SHA256(token_hash, param_string)
重要:
  • your_token 是申请时获得的 token(格式:tk_xxx...
  • token_hash 是 token 的 SHA256 哈希(64位十六进制字符串)
  • 不要直接用 token 作为 HMAC 密钥!
签名参数示例

响应数据

成功时返回:

跳转支付

将用户重定向到响应中的 payment_url,用户会:
  1. 自动跳转到登录页(如未登录)
  2. 登录后返回支付页面
  3. 确认订单并完成支付
  4. 支付成功后跳转到你的回调地址

处理回调

回调方式

重要:这是浏览器 GET 跳转,不是服务器 POST 请求!
支付成功后,用户浏览器会跳转到你设置的回调地址,所有参数以查询字符串形式传递。

回调参数(URL 查询参数)

回调 URL 示例

验证签名

必须验证签名,防止伪造请求!
验证步骤:
  1. 提取签名参数: 从 URL 中获取 signature
  2. 提取其他参数: 所有参数除了 signature 本身
  3. 按键名排序: 字母顺序排列
  4. 拼接字符串: 格式 key1=value1&key2=value2...
  5. 计算签名: HMAC-SHA256(secret_key, param_string)
  6. 比对签名: 计算出的签名与接收到的签名必须完全一致
签名参数示例

处理订单

验证签名通过后:
  • 检查幂等性: 确保订单未被重复处理
  • 验证金额: 确认 amount 与订单金额一致
  • 更新订单状态: 标记为已支付
  • 执行业务逻辑: 发货、开通服务等
  • 显示确认页面: 向用户展示支付成功信息

查询状态

如果回调失败或需要主动确认支付状态,可以使用查询接口。

API 接口

请求参数

签名算法

与发起支付相同:
  1. 参数:transaction_id
  2. 拼接:transaction_id=txn_xxx
  3. 签名:HMAC-SHA256(secret_key, param_string)

响应数据

交易状态

建议使用场景

  • 定时任务检查待支付订单状态
  • 用户主动查询订单状态
  • 回调失败后的补救措施

用户转账

当前支付应用申请人的积分转账给指定的 NodeLoc 用户。常用于外部网站发放奖励、抽奖派发、佣金结算等场景。
转出方固定为申请该 Payment 应用的用户,无法转出其他人的积分。 请确保申请人账户中有足够的积分(含手续费)。

API 接口

请求参数

由于用户身份在 NodeLoc 之外,to_user_idto_username 必须同时正确并指向同一个用户,否则请求会被拒绝(防止用户名变更或写错导致转错账户)。

手续费规则

手续费根据**申请人的信任等级(Trust Level)**自动计算,费率沿用 discourse-points-service 的设置: 同时遵循 TL 对应的 points_transfer_min_amount_tl{0..4} / points_transfer_max_amount_tl{0..4} 限额。 计算公式:

签名算法

  1. 准备参数: to_user_id, to_username, amount, order_id
  2. 按键名字母顺序排序
  3. 拼接字符串: key1=value1&key2=value2&...
  4. 计算签名: 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_idto_username 来自可信来源
  • ✅ 切勿仅凭用户名转账,必须同时校验 ID

7. 日志记录

  • ✅ 记录所有支付/转账相关操作
  • ✅ 记录所有回调请求(包括签名验证失败的)

常见问题

检查以下几点:
  1. 参数是否按键名字母顺序排序
  2. 参数拼接格式是否为 key=value&key=value
  3. Secret Key 是否正确
  4. 验证时是否排除了 signature 参数本身
  5. 字符编码是否一致(UTF-8)
可能原因:
  1. 回调 URL 设置错误
  2. 用户关闭了浏览器窗口
  3. 网络问题导致跳转失败
解决方案:使用查询接口定期检查订单状态
开发环境测试:
  1. 使用 ngrok 等工具暴露本地服务器
  2. 在 NodeLoc 创建测试应用
  3. 设置回调 URL 为 ngrok 地址
  4. 创建小金额订单测试
目前不支持自动退款,需要联系管理员手动处理。
是的,默认 30 分钟未支付会自动过期。
可以,只要你提供的 to_user_idto_username 同时正确并指向同一个 NodeLoc 用户。 转出方固定是申请该 Payment 应用的用户,无法用此接口转出其他人的积分。
手续费按申请人当前的信任等级(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 插件等)都能直接用。

对接参数

签名规则与易支付一致:取所有非空参数,剔除 signsign_type,按参数名 ASCII 升序排列,拼成 k1=v1&k2=v2,用商户私钥做 SHA256WithRSA 签名后 base64。NodeLoc 的响应和回调用平台私钥同样方式签名,请用平台公钥验签。所有请求都要带 10 位秒级 timestamp,与服务器时间相差超过 5 分钟会被拒绝。

接口一览

参数名、返回字段与易支付文档相同,以下几点不同:
  • money 是你自己货币的金额(例如 "9.90" 元),NodeLoc 按应用设置的汇率换算成能量向买家收取(默认汇率 100 时 9.90 元 = 990 能量),四舍五入到整数,不足 1 能量会被拒绝。回调和查询里的 money 原样返回你传的金额;商户信息里的余额和收入也按汇率折成货币。平台手续费按站点设置从商户到账的能量中扣除。
  • type 随便传(alipaywxpay 或留空),只会原样回传;methoddevice 被忽略,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 签名:非空参数剔除 signsign_type,按参数名 ASCII 升序拼成 a=b&c=d(值不做 URL 编码),末尾直接拼接商户密钥后取 MD5 小写。V1 订单支付后的异步通知和同步跳转参数为 pidtrade_noout_trade_notypenamemoneytrade_statusparamsignsign_type=MD5,同样用商户密钥验签,异步通知请返回 success 同一个应用可以同时接 V1 和 V2:请求里 sign_type=RSA 走 V2 验签,否则按 V1 的 MD5 处理。

支付结果通知

买家支付成功后:
  1. 异步通知:NodeLoc 以 GET 请求你的 notify_url,参数为 pidtrade_noout_trade_noapi_trade_notypetrade_status=TRADE_SUCCESSaddtimeendtimenamemoneyparambuyertimestampsignsign_type。你的服务器验签后需返回字符串 success;否则会在 1 分钟、5 分钟、30 分钟、2 小时、12 小时后重试,共 5 次。
  2. 同步跳转:买家浏览器被带回 return_url,带同样的参数。
务必验证 sign 并检查 trade_status 是否为 TRADE_SUCCESS;将来可能增加回调字段,验签时请把所有非空参数都算进去。
祝对接顺利! 🚀