NOWPayments 互換 API
パス、x-api-key ヘッダー、リクエストとレスポンスのフィールド、ステータス、x-nowpayments-sig の IPN 署名は NOWPayments のドキュメントに従うため、既存のコードは通常、新しいベース URL、API key、IPN secret を用意するだけで動きます。ほかのサービスからの移行ですか?移行の概要をご覧ください。
内部では通常の blockwallets の請求です。受取アドレスはあなたのもの、決済ページは当社のホスト型決済ページで、支払いはオンチェーンで承認され、2つ目のノードでも照合されて初めて有効になります。以下では、3つのステップに続けて、各 API の対応範囲と元のサービスとの違いを説明します。実装していないパラメーターは、黙って無視されることなくエラーを返します。
3つのステップ
- 加盟店アカウントを取得し(トップページから申し込み)、管理画面「開発者 › 連携とキー」の「サイトのドメイン」にドメインを追加します。コールバック URL(
ipn_callback_url)とリダイレクト URL(success_url/cancel_url/redirect_url)は、これらのドメイン上、またはコールバック URL のドメイン上である必要があります。キーが漏えいしても、Webhook を別の場所に向けることはできません。 - 加盟店管理画面の「開発者 › 連携とキー」で互換の認証情報を発行します。本番用とテスト用が1組ずつあり、NOWPayments は API key + IPN secret、Coinbase Commerce は API key + webhook shared secret です。表示は一度だけで、当社にはハッシュ / 暗号文だけを保存します。
- コードを下記のベース URL に向け、新しいキーを使います。まずテスト用の認証情報でテストネット上で動かし、そのあと本番に切り替えてください。
| 移行前 | 移行後 | 認証ヘッダー | Webhook 署名 |
|---|---|---|---|
https://api.nowpayments.io/v1 | https://blockwallets.io/nowpayments/v1 | x-api-key | x-nowpayments-sig(HMAC-SHA512) |
NOWPayments
- 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 | 現在受け付けられる通貨(ティッカーは下記)。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 は不要です。この呼び出しは検証されないプレースホルダーのトークンを返すので、「ログインしてから一覧」というコードもそのまま動きます(メールアドレス / パスワードは検証しません) |
非対応:払い出し、換算、カストディのサブパートナー、サブスクリプション、update-merchant-estimate、法定通貨での決済。これらのパスは 404 を返します。
IPN コールバック
決済が最終ステータスになると、作成時に指定された ipn_callback_url に POST します。x-nowpayments-sig = HMAC-SHA512(IPN secret, キーで再帰的に並べ替えた JSON) で、NOWPayments の検証コードとまったく同じです。送信するボディはすでに並べ替え済みのコンパクトな JSON なので、生のボディに対する HMAC でも検証できます(PHP / Python では、非常に小さい小数の再エンコードが JS と異なることがあるため、こちらが最も安全です)。失敗したコールバックは 1 分後、5 分後、30 分後、…と再試行し、合計 8 回です。
import crypto from "node:crypto";
// Same as the NOWPayments docs (our body is already sorted, so hashing the raw body works too)
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)$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
tksort($data); // the recursive ksort from the NOWPayments docs
$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 | 不足:期限前なら、お客様は同じアドレスに追加で送金できます(最初の不足時に1回送信)。期限になってもなお不足している場合は、もう一度送信します | ✓ |
expired | 未払いのまま期限切れ | ✓ |
refunded | 管理画面から決済の全額を返金し、送金済み | —(照会すると確認できます) |
confirmed、sending、failed は送信されません。承認されると finished になって残高に計上され、転送は行いません。
通貨ティッカー
| 通貨 | ネットワーク | pay_currency | network | 最低額 |
|---|---|---|---|---|
| USDT | TRON | usdttrc20 | trx | $1 |
| USDT | BNB Chain | usdtbsc usdtbep20 | bsc | $1 |
| USDC | BNB Chain | usdcbsc usdcbep20 | bsc | $1 |
| USDT | Ethereum | usdterc20 | eth | $5 |
| USDC | Ethereum | usdc usdcerc20 | eth | $5 |
| USDC | Base | usdcbase | base | $1 |
| USDT | Polygon | usdtmatic usdtpolygon | matic | $1 |
| USDC | Polygon | usdcmatic usdcpolygon | matic | $1 |
| USDT | Arbitrum | usdtarb | arbitrum | $1 |
| USDC | Arbitrum | usdcarb | arbitrum | $1 |
| USDT | Optimism | usdtop | op | $1 |
| USDC | Optimism | usdcop | op | $1 |
| USDT | Avalanche | usdtarc20 usdtavax / usdtavaxc | avaxc | $1 |
| USDC | Avalanche | usdcarc20 usdcavax / usdcavaxc | avaxc | $1 |
| USDT | X Layer | usdtxlayer | xlayer | $1 |
| USDC | X Layer | usdcxlayer | xlayer | $1 |
| USD1 | BNB Chain | usd1bsc | bsc | $1 |
| FDUSD | BNB Chain | fdusdbsc | bsc | $1 |
| DAI | Ethereum | dai daierc20 | eth | $5 |
| DAI | Arbitrum | daiarb | arbitrum | $1 |
| DAI | Base | daibase | base | $1 |
| BTC | Bitcoin | btc | btc | $5 |
| LTC | Litecoin | ltc | ltc | $1 |
| DOGE | Dogecoin | doge | doge | $1 |
| BCH | Bitcoin Cash | bch | bch | $1 |
| TRX | TRON | trx | trx | $1 |
| BNB | BNB Chain | bnbbsc bnb | bsc | $1 |
| ETH | Ethereum | eth | eth | $5 |
| ETH | Base | ethbase | base | $1 |
| ETH | Arbitrum | etharb | arbitrum | $1 |
| ETH | Optimism | ethop | op | $1 |
| POL | Polygon | maticmainnet pol / polmainnet / matic | matic | $1 |
| AVAX | Avalanche | avaxc avax | avaxc | $1 |
| OKB | X Layer | okbxlayer | xlayer | $1 |
| USDT | Solana | usdtsol | sol | $1 |
| USDC | Solana | usdcsol | sol | $1 |
| SOL | Solana | sol | sol | $1 |
| USDT | TON | usdtton | ton | $1 |
| TON | TON | ton | ton | $1 |
NOWPayments との相違点
price_currencyはusdのみ(加えて 1:1 のusdt/usdc)。ほかの法定通貨は 400 を返します。pay_amount(暗号資産の固定額)、payout_address/payout_currency/payout_extra_id、customer_emailには対応しておらず、400 を返します。is_fixed_rateは受け付けますが効果はありません。レートは常に固定します(BTC / LTC などは複数の取引所の中央値で、30 分間)。is_fee_paid_by_userが true の場合、プラットフォーム手数料がpay_amountに上乗せされます(プラットフォーム手数料は 1%、取扱高が増えると下がります。料金を参照)。- 決済の有効期間は最長 12 時間です(NOWPayments は 7 日)。
partially_paid_urlは保存されてそのまま返されますが、決済ページはそこへリダイレクトしません。 payment_idは 10 桁の数字です。/invoiceで作成したインボイスでは、決済のpayment_idがインボイスのidと同じで、インボイスにはちょうど1件の決済があります(parent_payment_idによる再入金はありません)。- 送信されるのは最終ステータスと
partially_paidの IPN のみです(上の表)。waiting/confirmingは送信しません。fee.serviceFeeはプラットフォーム手数料(受取額 × 請求作成時の料率、標準 1%)で、ほかの手数料は 0 です。
テストモード
テスト用の認証情報で作成したチャージと決済は各チェーンのテストネットで動き、その Webhook はテスト用の IPN secret / shared secret で署名されます。本番とは完全に分離されており、テスト用のキーから本番の決済は見えません。
そのほか(決済ページ、承認、ネットワークと最低額、返金)はメインのドキュメントのとおりに動作します。