API compatible NOWPayments

Ouvrir dans ChatGPTOuvrir dans Claude

Les chemins, l’en-tête x-api-key, les champs de requête et de réponse, les statuts et la signature IPN x-nowpayments-sig suivent la documentation de NOWPayments : le code existant n’a donc généralement besoin que d’une nouvelle URL de base, d’une nouvelle API key et d’un nouvel IPN secret. Vous venez d’ailleurs ? Consultez l’aperçu de la migration.

Dessous, c’est une facture blockwallets ordinaire : les adresses de réception sont les vôtres, la page de paiement est notre caisse hébergée, et un paiement ne compte qu’une fois confirmé on-chain et recoupé avec un second nœud. Ci-dessous : trois étapes, puis ce que chaque API prend en charge et en quoi elle diffère de l’originale — les paramètres que nous n’implémentons pas renvoient une erreur au lieu d’être ignorés en silence.

Trois étapes

  1. Obtenez un compte marchand (demandez-le sur la page d’accueil) et ajoutez vos domaines dans « Domaines du site web », sous « Développeurs › Intégration et clés » du tableau de bord. Les URL de callback (ipn_callback_url) et de redirection (success_url / cancel_url / redirect_url) doivent se trouver sur ces domaines ou sur le domaine de votre URL de callback — une clé divulguée ne peut pas rediriger les webhooks ailleurs.
  2. Générez des identifiants compatibles dans le tableau de bord marchand, sous « Développeurs › Intégration et clés », un jeu pour live et un pour test : NOWPayments reçoit une API key + IPN secret, Coinbase Commerce une API key + webhook shared secret. Ils ne sont affichés qu’une fois ; nous ne conservons que des hashs / du texte chiffré.
  3. Pointez votre code vers l’URL de base ci-dessous et utilisez les nouvelles clés. Lancez d’abord sur les testnets avec les identifiants de test, puis passez en live.
AvantAprèsEn-tête d’authentificationSignature du webhook
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();

Endpoints pris en charge

EndpointRemarques
GET /status{"message":"OK"}, aucune clé nécessaire
GET /currencies · /merchant/coins · /full-currenciesCryptos que vous pouvez accepter en ce moment (tickers ci-dessous) ; fixed_rate est ignoré
GET /min-amount · GET /estimateMinimums et estimations ; prix en USD uniquement (USDT / USDC comptent 1:1)
POST /paymentCrée un paiement ; renvoie pay_address / pay_amount immédiatement (marque blanche)
POST /invoiceCrée une facture (invoice) ; invoice_url est notre caisse hébergée où le client choisit crypto et réseau
POST /invoice-paymentChoisit la crypto d’une facture (invoice), renvoie le paiement
GET /payment/:idStatut du paiement
GET /payment/Liste : limit (1–500) / page / orderBy / dateFrom / dateTo / invoiceId ; sortBy uniquement created_at
POST /authLa liste n’a besoin que de x-api-key, sans JWT ; cet endpoint renvoie un jeton factice non vérifié pour que le code « se connecter, puis lister » continue de fonctionner (e-mail / mot de passe ne sont pas vérifiés)

Non disponibles : payouts, conversions, sous-partenaires en garde, abonnements, update-merchant-estimate, paiements en monnaie fiat. Ces chemins renvoient 404.

Callbacks IPN

Quand un paiement atteint un statut final, nous envoyons un POST à l’ipn_callback_url donnée à la création, avec x-nowpayments-sig = HMAC-SHA512(IPN secret, le JSON trié récursivement par clé) — exactement le code de vérification de NOWPayments. Le corps que nous envoyons est déjà un JSON compact et trié, donc un HMAC sur le corps brut fonctionne aussi (et c’est le choix le plus sûr en PHP / Python, dont le ré-encodage des très petits décimaux peut différer de JS). Les callbacks en échec sont réessayés après 1 min, 5 min, 30 min, … — 8 tentatives en tout.

Node.js
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)
PHP
$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_statusQuandIPN envoyé
waitingEn attente de paiement (y compris une facture (invoice) sans crypto choisie)—
confirmingPaiement vu on-chain, en attente de confirmations— (visible lors d’une requête)
finishedPayé (y compris avec un trop-perçu ; actually_paid est ce qui est arrivé)✓
partially_paidInsuffisant : le client peut encore compléter à la même adresse avant l’expiration (envoyé une fois au premier paiement insuffisant), et de nouveau s’il manque encore quelque chose à l’expiration✓
expiredExpiré sans paiement✓
refundedVous avez remboursé la totalité du paiement depuis le tableau de bord et il a été envoyé— (visible lors d’une requête)

confirmed, sending et failed n’apparaissent jamais : une fois confirmé, c’est finished et crédité sur votre solde ; rien n’est transféré.

Tickers des cryptos

CryptoRéseaupay_currencynetworkMinimum
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

Différences avec NOWPayments

Mode test

Les charges et paiements créés avec des identifiants de test fonctionnent sur le testnet de chaque chaîne et leurs webhooks sont signés avec l’IPN secret / shared secret de test — totalement séparés du live : une clé de test ne voit pas les paiements live.

Tout le reste (caisse, confirmations, réseaux et minimums, remboursements) fonctionne comme dans la documentation principale.