NOWPayments-kompatible API
Pfade, der Header x-api-key, Request- und Response-Felder, Status und die IPN-Signatur x-nowpayments-sig folgen der Dokumentation von NOWPayments, sodass vorhandener Code meist nur eine neue Base-URL, einen neuen API key und ein neues IPN secret braucht. Sie kommen von woanders? Siehe die Migrationsübersicht.
Darunter liegt eine ganz normale blockwallets-Rechnung: Die Empfangsadressen gehören Ihnen, die Zahlungsseite ist unser gehosteter Checkout, und eine Zahlung zählt erst, wenn sie on-chain bestätigt und gegen einen zweiten Node geprüft wurde. Unten: drei Schritte, dann was jede API unterstützt und wie sie sich vom Original unterscheidet – Parameter, die wir nicht umsetzen, liefern einen Fehler, statt stillschweigend ignoriert zu werden.
Drei Schritte
- Besorgen Sie sich ein Händlerkonto (auf der Startseite beantragen) und tragen Sie im Dashboard unter „Entwickler › Integration & Keys“ bei „Website-Domains“ Ihre Domains ein. Callback-URLs (
ipn_callback_url) und Weiterleitungs-URLs (success_url/cancel_url/redirect_url) müssen auf diesen Domains oder der Domain Ihrer Callback-URL liegen – ein geleakter Schlüssel kann Webhooks so nicht woandershin lenken. - Erzeugen Sie kompatible Zugangsdaten im Händler-Dashboard unter „Entwickler › Integration & Keys“, je einen Satz für Live und für Test: NOWPayments erhält einen API key + IPN secret, Coinbase Commerce einen API key + Webhook shared secret. Sie werden nur einmal angezeigt; wir speichern nur Hashes / Chiffretext.
- Richten Sie Ihren Code auf die untenstehende Base-URL und nutzen Sie die neuen Schlüssel. Testen Sie zuerst mit den Test-Zugangsdaten auf Testnets und wechseln Sie dann auf Live.
| Vorher | Nachher | Auth-Header | Webhook-Signatur |
|---|---|---|---|
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();Unterstützte Endpoints
| Endpoint | Hinweise |
|---|---|
GET /status | {"message":"OK"}, kein Schlüssel nötig |
GET /currencies · /merchant/coins · /full-currencies | Coins, die Sie derzeit annehmen können (Kürzel unten); fixed_rate wird ignoriert |
GET /min-amount · GET /estimate | Mindestbeträge und Schätzungen; nur Preise in USD (USDT / USDC zählen 1:1) |
POST /payment | Zahlung erstellen; liefert pay_address / pay_amount sofort (White Label) |
POST /invoice | Rechnung erstellen; invoice_url ist unser gehosteter Checkout, in dem der Kunde Coin und Netzwerk wählt |
POST /invoice-payment | Coin für eine Rechnung wählen, liefert die Zahlung |
GET /payment/:id | Zahlungsstatus |
GET /payment/ | Liste: limit (1–500) / page / orderBy / dateFrom / dateTo / invoiceId; sortBy nur created_at |
POST /auth | Die Liste braucht nur x-api-key, kein JWT; dieser Endpoint liefert ein ungeprüftes Platzhalter-Token, damit Code nach dem Muster „anmelden, dann auflisten“ weiterläuft (E-Mail / Passwort werden nicht geprüft) |
Nicht verfügbar: Payouts, Conversions, Custody-Sub-Partner, Abonnements, update-merchant-estimate, Fiat-Zahlungen. Diese Pfade liefern 404.
IPN-Callbacks
Erreicht eine Zahlung einen Endstatus, senden wir ein POST an die beim Erstellen angegebene ipn_callback_url, mit x-nowpayments-sig = HMAC-SHA512(IPN secret, das rekursiv nach Schlüsseln sortierte JSON) – exakt der Prüfcode von NOWPayments. Der gesendete Body ist bereits sortiertes, kompaktes JSON, ein HMAC über den Rohtext funktioniert also ebenfalls (und ist in PHP / Python die sicherste Wahl, da deren erneutes Kodieren sehr kleiner Dezimalzahlen von JS abweichen kann). Fehlgeschlagene Callbacks werden nach 1 Min., 5 Min., 30 Min., … wiederholt – insgesamt 8 Versuche.
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 | Wann | Gesendete IPN |
|---|---|---|
waiting | Wartet auf Zahlung (auch eine Rechnung, bei der noch kein Coin gewählt wurde) | — |
confirming | Zahlung on-chain gesehen, wartet auf Bestätigungen | — (bei Abfrage sichtbar) |
finished | Bezahlt (auch überzahlt; actually_paid ist das tatsächlich Eingegangene) | ✓ |
partially_paid | Zu wenig: Der Kunde kann vor Ablauf an dieselbe Adresse nachzahlen (einmal bei der ersten Unterzahlung gesendet) und nochmals, wenn es bei Ablauf noch fehlt | ✓ |
expired | Unbezahlt abgelaufen | ✓ |
refunded | Sie haben die gesamte Zahlung im Dashboard erstattet und sie wurde gesendet | — (bei Abfrage sichtbar) |
confirmed, sending und failed erscheinen nie: Nach der Bestätigung ist es finished und wird Ihrem Guthaben gutgeschrieben; nichts wird weitergeleitet.
Währungskürzel
| Coin | Netzwerk | pay_currency | network | Minimum |
|---|---|---|---|---|
| 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 |
Unterschiede zu NOWPayments
price_currencyist nurusd(plususdt/usdczu 1:1); andere Fiat-Währungen liefern 400.pay_amount(ein fester Krypto-Betrag),payout_address/payout_currency/payout_extra_idundcustomer_emailwerden nicht unterstützt und liefern 400.is_fixed_ratewird akzeptiert, hat aber keine Wirkung: Wir fixieren den Kurs immer (BTC / LTC usw. zum Median mehrerer Börsen, für 30 Minuten). Beiis_fee_paid_by_usertrue wird die Plattformgebühr zupay_amountaddiert (die Plattformgebühr beträgt 1%, bei höherem Volumen weniger; siehe Preise).- Zahlungen sind bis zu 12 Stunden gültig (NOWPayments: 7 Tage).
partially_paid_urlwird gespeichert und zurückgegeben, aber der Checkout leitet nicht dorthin weiter. payment_idist eine 10-stellige Zahl; bei mit/invoiceerstellten Rechnungen entspricht diepayment_idder Zahlung deridder Rechnung, und eine Rechnung hat genau eine Zahlung (keine erneuten Einzahlungen perparent_payment_id).- Gesendet werden nur IPNs für Endstatus und
partially_paid(Tabelle oben), keine fürwaiting/confirming;fee.serviceFeeist die Plattformgebühr (der erhaltene Betrag × der Satz bei Erstellung der Rechnung, Standard 1%), andere Gebühren sind 0.
Testmodus
Mit Test-Zugangsdaten erstellte Charges und Zahlungen laufen im Testnet der jeweiligen Chain, und ihre Webhooks werden mit dem Test-IPN-secret / shared secret signiert – völlig getrennt von Live: Ein Test-Schlüssel sieht keine Live-Zahlungen.
Alles Übrige (Checkout, Bestätigungen, Netzwerke und Mindestbeträge, Erstattungen) funktioniert wie in der Hauptdokumentation.