Migrating from NOWPayments
ZyraPay speaks the same API. The same endpoints, the same field names, the same statuses, the same callback signature. For most integrations the migration is two lines.
- const BASE_URL = "https://api.nowpayments.io/v1";
- const API_KEY = process.env.NOWPAYMENTS_API_KEY;
+ const BASE_URL = "https://api.zyrapay.net/v1";
+ const API_KEY = process.env.ZYRAPAY_API_KEY;What stays exactly the same
The x-api-key header. The endpoint paths. Every request and response field name. The payment status vocabulary. And — the part people worry about most — the callback signature scheme.
Endpoints
| Endpoint | Notes |
|---|---|
GET /v1/status | Liveness |
GET /v1/currencies | Coins ZyraPay supports |
GET /v1/merchant/coins | Coins you have enabled |
GET /v1/min-amount | currency_from, currency_to |
GET /v1/estimate | amount, currency_from, currency_to |
POST /v1/payment | Create a payment |
GET /v1/payment/{id} | Payment status |
GET /v1/payment/ | Paginated list |
POST /v1/invoice | Hosted checkout link |
POST /v1/invoice-payment | Turn an invoice into a payment |
GET /v1/balance | Your balances |
Statuses
waiting, confirming, confirmed, sending, partially_paid, finished, failed, refunded, expired — same names, same meanings.
Callback signatures
ZyraPay signs callbacks with HMAC-SHA512 over the alphabetically sorted-key JSON body and sends it in the x-nowpayments-sig header — byte for byte what you already verify. Your existing verification code needs no changes:
const crypto = require("crypto");
function verify(body, signature, ipnSecret) {
const hmac = crypto.createHmac("sha512", ipnSecret);
hmac.update(JSON.stringify(body, Object.keys(body).sort()));
return hmac.digest("hex") === signature;
}What is different
1. Check your coins are supported
ZyraPay supports fewer coins than NOWPayments. Before cutting over, call GET /v1/currencies and confirm everything you accept is there. See Currencies & Networks. ZyraPay also supports pi, which NOWPayments does not.
2. payment_id is a string
NOWPayments returns it as a JSON number; ZyraPay returns a string of digits. If your code does parseInt(payment_id) it keeps working. If it does a strict === against a number, fix that comparison.
3. Settlement is your choice
NOWPayments always forwards to your wallet. ZyraPay does that too if you set a payout address — but if you leave it blank, we hold the balance for you instead. For NOWPayments-equivalent behaviour, set a payout address for every network you accept before going live.
4. Not yet available
Mass payouts, recurring subscriptions and sub-partner accounts are in progress. Auto conversion between coins is available where liquidity exists, otherwise payout_currency must match pay_currency. If you depend on any of these today, wait before switching.
Cutting over
- 1
Check coverage
GET /v1/currencies— is every coin you accept supported? - 2
Set payout addresses
Dashboard → Gateway → Currencies, if you want funds forwarded rather than held. - 3
Point your callback at ZyraPay
Copy your IPN secret. Your signature verification does not change. - 4
Run one real payment per coin
End to end, including the callback, before you touch production. - 5
Swap the base URL and key
Two lines, in production. - 6
Keep the old path switchable for a week
Run both and compare. Cheap insurance.
Verify it yourself
You do not have to take our word for the compatibility. Point the official NOWPayments SDK at ZyraPay and watch it work unmodified:
const { NOWPaymentsApi } = require("@nowpaymentsio/nowpayments-api-js");
// Override the SDK's base URL to point at ZyraPay, then use it normally.
const api = new NOWPaymentsApi({ apiKey: process.env.ZYRAPAY_API_KEY });
await api.getCurrencies();
await api.createPayment({
price_amount: 5,
price_currency: "usd",
pay_currency: "usdtbsc",
});Next
- Crypto Payments — the payment lifecycle in full.
- Going Live — the pre-production checklist.