NOWPayments 兼容接口

路径、x-api-key 请求头、请求 / 应答字段、状态和 x-nowpayments-sig IPN 签名都照 NOWPayments 官方文档,现有代码通常只要换基础地址、API key 和 IPN secret。从别家迁过来?看迁移总览。

底层就是 blockwallets 的账单:收款地址是你自己的,付款页是我们的收银台,到账后链上确认、再找第二家节点核对一遍才算付款成功。下面先讲三步接入,再分别列出两家的支持范围和与官方接口的差异——没实现的参数会明确报错,不会悄悄忽略。

三步接入

  1. 开通商户(首页申请),在商户后台「开发者 › 接入与密钥」的「网站域名」里填上你的域名。回调地址(ipn_callback_url)和跳转地址(success_url / cancel_url / redirect_url)只接受这些域名和回调地址的域名——即使密钥泄露,也没法把回调指到别处。
  2. 在商户后台「开发者 › 接入与密钥」页生成兼容凭据(live 和 test 各一套):NOWPayments 是 API key + IPN secret,Coinbase Commerce 是 API key + webhook shared secret。密钥只显示一次,我们这边只存哈希 / 密文。
  3. 把代码里的 base URL 换成下面的地址,换上新密钥。先用 test 凭据在测试网走一遍,再换 live。
原来换成鉴权头回调签名
https://api.nowpayments.io/v1https://blockwallets.io/nowpayments/v1x-api-keyx-nowpayments-sig(HMAC-SHA512)

NOWPayments

JavaScript
- const NP = "https://api.nowpayments.io/v1";
+ const NP = "https://blockwallets.io/nowpayments/v1";

const res = await fetch(`${NP}/payment`, {
  method: "POST",
  headers: { "x-api-key": process.env.NOWPAYMENTS_API_KEY, "content-type": "application/json" },
  body: JSON.stringify({
    price_amount: 49.9, price_currency: "usd", pay_currency: "usdttrc20",
    order_id: "A-1001", order_description: "Pro plan",
    ipn_callback_url: "https://shop.example/ipn/nowpayments",
  }),
});
const { payment_id, pay_address, pay_amount } = await res.json();

支持的接口

接口说明
GET /status{"message":"OK"},不要密钥
GET /currencies · /merchant/coins · /full-currencies当前可收的币(ticker 见下表);fixed_rate 参数忽略
GET /min-amount · GET /estimate最低金额与估价;只认 USD 计价(USDT / USDC 按 1:1)
POST /payment建付款,直接返回 pay_address / pay_amount(你自己展示收款信息)
POST /invoice建账单,invoice_url 是我们的收银台,付款人在里面选币种和网络
POST /invoice-payment给账单定币种,返回付款
GET /payment/:id查付款状态
GET /payment/付款列表:limit(1–500)/ page / orderBy / dateFrom / dateTo / invoiceId,sortBy 只支持 created_at
POST /auth列表只看 x-api-key,不需要 JWT;这里回一个不校验的占位 token,让原来先登录再查列表的代码照常跑(不校验邮箱密码)

没有:出金(payout)、换汇(conversion)、托管子账户(sub-partner)、订阅(subscriptions)、update-merchant-estimate、法币付款。这些路径返回 404。

IPN 回调

状态变到终态时,我们 POST 到建单时给的 ipn_callback_url,头 x-nowpayments-sig = HMAC-SHA512(IPN secret, 按 key 递归排序后的 JSON),和 NOWPayments 的验签代码完全一样。我们发出的 body 本身就是排好序的紧凑 JSON,所以直接对原始 body 算 HMAC 也对(PHP / Python 遇到很小的小数时重新编码可能和 JS 不一致,对原始 body 算最稳)。回调失败按 1 分钟、5 分钟、30 分钟……重试,共 8 次。

Node.js
import crypto from "node:crypto";

// 和 NOWPayments 文档的写法一样(我们发出的 body 本身已经排好序,直接对原始 body 算也对)
function sortObject(obj) {
  return Object.keys(obj).sort().reduce((r, k) => {
    r[k] = obj[k] && typeof obj[k] === "object" ? sortObject(obj[k]) : obj[k];
    return r;
  }, {});
}
function verifyIpn(params, sig, ipnSecret) {
  const hmac = crypto.createHmac("sha512", ipnSecret).update(JSON.stringify(sortObject(params))).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(hmac), Buffer.from(sig || ""));
}
// verifyIpn(req.body, req.headers["x-nowpayments-sig"], process.env.NOWPAYMENTS_IPN_SECRET)
PHP
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
tksort($data);  // NOWPayments 文档里的递归 ksort
$hmac = hash_hmac('sha512', json_encode($data, JSON_UNESCAPED_SLASHES), trim($ipnSecret));
$ok = hash_equals($hmac, $_SERVER['HTTP_X_NOWPAYMENTS_SIG'] ?? '');
payment_status什么时候发 IPN
waiting等待付款(账单还没选币也是它)—
confirming链上见到付款,在等确认—(查单能看到)
finished已收款(含多付;actually_paid 是实收)✓
partially_paid收到的不够:到期前用户还能往同一地址补转(第一次少付时发一次),到期仍不够再发一次✓
expired到期没付✓
refunded你在商户后台整单退款、已退出—(查单能看到)

不会出现 confirmed、sending、failed:我们确认完就直接是 finished,钱记进你的余额,不再转发。

币种 ticker

币种网络pay_currencynetwork最低金额
USDTTRONusdttrc20trx$1
USDTBNB Chainusdtbsc usdtbep20bsc$1
USDCBNB Chainusdcbsc usdcbep20bsc$1
USDTEthereumusdterc20eth$5
USDCEthereumusdc usdcerc20eth$5
USDCBaseusdcbasebase$1
USDTPolygonusdtmatic usdtpolygonmatic$1
USDCPolygonusdcmatic usdcpolygonmatic$1
USDTArbitrumusdtarbarbitrum$1
USDCArbitrumusdcarbarbitrum$1
USDTOptimismusdtopop$1
USDCOptimismusdcopop$1
USDTAvalancheusdtarc20 usdtavax / usdtavaxcavaxc$1
USDCAvalancheusdcarc20 usdcavax / usdcavaxcavaxc$1
USDTX Layerusdtxlayerxlayer$1
USDCX Layerusdcxlayerxlayer$1
USD1BNB Chainusd1bscbsc$1
FDUSDBNB Chainfdusdbscbsc$1
DAIEthereumdai daierc20eth$5
DAIArbitrumdaiarbarbitrum$1
DAIBasedaibasebase$1
BTCBitcoinbtcbtc$5
LTCLitecoinltcltc$1
DOGEDogecoindogedoge$1
BCHBitcoin Cashbchbch$1
TRXTRONtrxtrx$1
BNBBNB Chainbnbbsc bnbbsc$1
ETHEthereumetheth$5
ETHBaseethbasebase$1
ETHArbitrumetharbarbitrum$1
ETHOptimismethopop$1
POLPolygonmaticmainnet pol / polmainnet / maticmatic$1
AVAXAvalancheavaxc avaxavaxc$1
OKBX Layerokbxlayerxlayer$1
USDTSolanausdtsolsol$1
USDCSolanausdcsolsol$1
SOLSolanasolsol$1
USDTTONusdttonton$1
TONTONtonton$1

与 NOWPayments 的差异

测试模式

test 凭据建的单走各链的测试网,回调用 test 的 IPN secret / shared secret 签名,和 live 完全隔离:test 的 key 查不到 live 的单。

其余细节(收银台、确认数、网络与最低金额、退款)和 主文档 一样。