NOWPayments uyumlu API
Yollar, x-api-key başlığı, istek ve yanıt alanları, durumlar ve x-nowpayments-sig IPN imzası NOWPayments dokümanlarını izler; bu yüzden mevcut kod genellikle yalnızca yeni bir temel URL, API key ve IPN secret ister. Başka bir yerden mi geliyorsunuz? Geçişe genel bakışa bakın.
Altta düzenli bir blockwallets faturası vardır: alım adresleri sizindir, ödeme sayfası bizim barındırdığımız ödeme sayfasıdır ve bir ödeme ancak zincirde onaylanıp ikinci bir node ile çapraz kontrol edildiğinde sayılır. Aşağıda: üç adım, ardından her API'nin neyi desteklediği ve orijinalinden nasıl farklı olduğu — uygulamadığımız parametreler sessizce yok sayılmak yerine hata döndürür.
Üç adım
- Bir satıcı hesabı edinin (ana sayfadan başvurun) ve panelde “Geliştiriciler › Entegrasyon ve anahtarlar” sayfasındaki “Web sitesi alan adları” altına alan adlarınızı ekleyin. Callback URL'leri (
ipn_callback_url) ve yönlendirme URL'leri (success_url/cancel_url/redirect_url) bu alan adlarında ya da callback URL'nizin alan adında olmalıdır — sızan bir anahtar webhook'ları başka yere yönlendiremez. - Satıcı panelinde “Geliştiriciler › Entegrasyon ve anahtarlar” altında uyumlu kimlik bilgileri oluşturun; canlı için bir, test için bir takım: NOWPayments için bir API key + IPN secret, Coinbase Commerce için bir API key + webhook shared secret. Bir kez gösterilirler; biz yalnızca hash / şifreli metin saklarız.
- Kodunuzu aşağıdaki temel URL'ye yönlendirin ve yeni anahtarları kullanın. Önce test kimlik bilgileriyle testnet'lerde çalıştırın, sonra canlıya geçin.
| Önce | Sonra | Kimlik doğrulama başlığı | Webhook imzası |
|---|---|---|---|
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();Desteklenen endpoint'ler
| Endpoint | Notlar |
|---|---|
GET /status | {"message":"OK"}, anahtar gerekmez |
GET /currencies · /merchant/coins · /full-currencies | Şu anda kabul edebileceğiniz coin'ler (kodlar aşağıda); fixed_rate yok sayılır |
GET /min-amount · GET /estimate | Asgari tutarlar ve tahminler; yalnızca USD fiyatlandırma (USDT / USDC 1:1 sayılır) |
POST /payment | Ödeme oluşturur; hemen pay_address / pay_amount döndürür (white-label) |
POST /invoice | Fatura (invoice) oluşturur; invoice_url, müşterinin coin ve ağ seçtiği, bizim barındırdığımız ödeme sayfasıdır |
POST /invoice-payment | Bir fatura için coin seçer, ödemeyi döndürür |
GET /payment/:id | Ödeme durumu |
GET /payment/ | Liste: limit (1–500) / page / orderBy / dateFrom / dateTo / invoiceId; sortBy yalnızca created_at |
POST /auth | Liste yalnızca x-api-key ister, JWT gerekmez; bu endpoint doğrulanmayan bir yer tutucu token döndürür, böylece “giriş yap, sonra listele” kodu çalışmaya devam eder (e-posta / parola denetlenmez) |
Mevcut değil: ödemeler (payout), dönüşümler, saklama alt ortakları, abonelikler, update-merchant-estimate, fiat ödemeler. Bu yollar 404 döndürür.
IPN callback'leri
Bir ödeme son duruma ulaştığında oluşturma sırasında verilen ipn_callback_url adresine POST'larız; x-nowpayments-sig = HMAC-SHA512(IPN secret, anahtarlara göre özyinelemeli sıralanmış JSON) — tam olarak NOWPayments'ın doğrulama kodu. Gönderdiğimiz gövde zaten sıralı, sıkıştırılmış JSON'dur; bu yüzden ham gövde üzerinden HMAC de çalışır (ve çok küçük ondalıkları yeniden kodlaması JS'ten farklı olabilen PHP / Python'da en güvenli seçimdir). Başarısız callback'ler 1 dk, 5 dk, 30 dk, … sonra yeniden denenir — toplam 8 deneme.
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 | Ne zaman | Gönderilen IPN |
|---|---|---|
waiting | Ödeme bekleniyor (henüz coin seçilmemiş bir fatura da dahil) | — |
confirming | Ödeme zincirde görüldü, onaylar bekleniyor | — (sorguladığınızda görünür) |
finished | Ödendi (fazla ödenmiş dahil; actually_paid gelen tutardır) | ✓ |
partially_paid | Eksik: müşteri süre dolmadan aynı adrese tamamlayabilir (ilk eksik ödemede bir kez gönderilir), süre dolduğunda hâlâ eksikse yine gönderilir | ✓ |
expired | Ödenmeden süresi doldu | ✓ |
refunded | Ödemenin tamamını panelden iade ettiniz ve gönderildi | — (sorguladığınızda görünür) |
confirmed, sending ve failed hiç görünmez: onaylandığında finished olur ve bakiyenize yatırılır; hiçbir şey başka yere iletilmez.
Coin kodları
| Coin | Ağ | pay_currency | network | Asgari |
|---|---|---|---|---|
| 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'tan farklar
price_currencyyalnızcausdolabilir (ayrıca 1:1usdt/usdc); diğer fiat para birimleri 400 döndürür.pay_amount(sabit bir kripto tutarı),payout_address/payout_currency/payout_extra_idvecustomer_emaildesteklenmez ve 400 döndürür.is_fixed_ratekabul edilir ama etkisi yoktur: kuru her zaman sabitleriz (BTC / LTC vb. birkaç borsanın medyan fiyatıyla, 30 dakika).is_fee_paid_by_usertrue ise platform ücretipay_amount'a eklenir (platform ücreti 1%, hacim arttıkça düşer; bkz. fiyatlar).- Ödemeler en fazla 12 saat geçerlidir (NOWPayments: 7 gün).
partially_paid_urlsaklanır ve geri döndürülür, ancak ödeme sayfası oraya yönlendirmez. payment_id10 haneli bir sayıdır;/invoiceile oluşturulan faturalarda ödemeninpayment_iddeğeri faturaiddeğerine eşittir ve bir faturanın tam olarak bir ödemesi vardır (parent_payment_idile yeniden yatırma yok).- Yalnızca son durum ve
partially_paidIPN'leri gönderilir (yukarıdaki tablo),waiting/confirmingolanlar gönderilmez;fee.serviceFeeplatform ücretidir (alınan tutar × faturanın oluşturulduğu andaki oran, standart 1%), diğer ücretler 0'dır.
Test modu
Test kimlik bilgileriyle oluşturulan charge'lar ve ödemeler her zincirin testnet'inde çalışır ve webhook'ları test IPN secret / shared secret ile imzalanır — canlıdan tamamen ayrıdır: bir test anahtarı canlı ödemeleri göremez.
Geri kalan her şey (ödeme sayfası, onaylar, ağlar ve asgari tutarlar, iadeler) ana dokümanlardaki gibi çalışır.