Nowpay
v1.0 · StableNowPayments-compatible

Nowpay API Reference

Accept USDT payments on BSC, Polygon, Arbitrum, Optimism, and Base. Samex-api-keyauthentication as NowPayments, REST verbs, and IPN-style webhooks — drop-in compatible for most integrations.

Introduction

The Nowpay API is a RESTful HTTP API secured by anx-api-keyheader — the same convention used by NowPayments. Every response is JSON; every error follows the{ error: { code, message } }envelope.

Nowpay is purpose-built for USDT-only settlement across five EVM networks: BSC, Polygon, Arbitrum, Optimism, and Base. This narrower scope allows lower fees (from $0.10/payout), instant finality, and a single integration surface — versus NowPayments' 300+ coins.

All write endpoints support idempotency keys via theIdempotency-Keyheader (required for payouts and swaps). Real-time updates are pushed via signed webhooks and socket.io events.

Base URL
https://nowpay.finance/api/v1
Swagger UI
/api/docs

Authentication

Every request must include an API key. Nowpay accepts both common conventions — pick whichever your existing code uses:

NowPayments-stylerecommended
x-api-key: sk_live_...

Same header name as NowPayments — zero code change for migrating merchants.

Bearer (RFC 6750)
Authorization: Bearer sk_live_...

Nowpay-native. Use this if you already have a Bearer-token HTTP client.

Getting an API key

  1. Sign up at /dashboard/signup and complete KYB.
  2. Wait for admin approval (typically < 24 h). Until then, API calls return 403 kyb_required.
  3. Open Dashboard → API Keys → Generate new key.
  4. Choose scopes: invoice, payout, swap.
  5. Copy the key immediately — the full key is shown only once (prefix is stored for later identification).

Rate limiting

60 requests/min per API key (sliding window). Every response includes these headers:

response-headers
X-RateLimit-Limit:     60
X-RateLimit-Remaining: 58
X-RateLimit-Reset:      1738368240

Quick start

Create an invoice in three languages. The flow is identical in all three — POST to/api/v1/invoices, get back a checkout_url, redirect your customer.

cURL
quickstart.sh
# 1. Create an invoice
curl -X POST https://nowpay.finance/api/v1/invoices \
  -H "x-api-key: sk_live_4f3c2b1a9e8d7c6b5a4f3e2d1c0b9a8f" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "amount": "50.00",
    "network": "polygon",
    "external_id": "order_12345",
    "success_url": "https://shop.example.com/thanks"
  }'

# 2. Redirect your customer to checkout_url from the response.
# 3. Receive a webhook at your ipn_callback_url when the payment is confirmed.
JavaScript (Node 18+)
quickstart.mjs
// Node 18+ (built-in fetch). For browsers, use the same code in a <script type="module">.
const res = await fetch("https://nowpay.finance/api/v1/invoices", {
  method: "POST",
  headers: {
    "x-api-key": process.env.NOWPAY_API_KEY,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    amount: "50.00",
    network: "polygon",
    external_id: "order_12345",
    success_url: "https://shop.example.com/thanks",
  }),
});

const invoice = await res.json();
console.log(invoice.checkout_url);
// → https://nowpay.finance/i/inv_abc123
Python
quickstart.py
import requests, uuid

API_KEY = "sk_live_4f3c2b1a9e8d7c6b5a4f3e2d1c0b9a8f"

res = requests.post(
    "https://nowpay.finance/api/v1/invoices",
    headers={
        "x-api-key": API_KEY,
        "Content-Type": "application/json",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "amount": "50.00",
        "network": "polygon",
        "external_id": "order_12345",
        "success_url": "https://shop.example.com/thanks",
    },
)
res.raise_for_status()
invoice = res.json()
print(invoice["checkout_url"])
# → https://nowpay.finance/i/inv_abc123

Invoices

An invoice represents a single payment request — generated deposit address, amount, network, expiry. The customer sends USDT to the address; once the chain finality threshold is reached, the invoice flips to finished and the amount is credited to the merchant's ledger balance for that chain.

POST/api/v1/invoices≡ NowPayments POST /v1/invoice

Create an invoice

Creates a payment invoice for the requested amount on the requested chain. Nowpay generates an HD-derived deposit address (BIP44 m/44'/60'/0'/0/<index>), queues an invoice.waiting webhook, and returns the hosted checkout URL your customer can be redirected to. The deposit address is unique per invoice — never reused.

ParameterTypeRequiredDescription
amountstringyesUSDT amount (e.g. "50.00"). Numeric string — never a JS number.
networkstringyesOne of: bsc, polygon, arbitrum, optimism, base.
external_idstringnoMerchant-internal order ID for reconciliation.
success_urlstringnoRedirect URL after successful payment.
cancel_urlstringnoRedirect URL after cancellation/timeout.
metadataobjectnoArbitrary JSON metadata stored with the invoice.
Request example
request.sh
curl -X POST https://nowpay.finance/api/v1/invoices \
  -H "x-api-key: sk_live_4f3c2b1a9e8d7c6b5a4f3e2d1c0b9a8f" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e" \
  -d '{
    "amount": "50.00",
    "network": "polygon",
    "external_id": "order_12345",
    "success_url": "https://shop.example.com/thanks",
    "cancel_url": "https://shop.example.com/cart"
  }'
Response example
response.json
{
  "id": "inv_abc123",
  "status": "waiting",
  "address": "0x7d5a3f9c2b1e8a4d6f0c2b5a7e9d1f3c4b2a8e6d",
  "amount": "50.00",
  "network": "polygon",
  "expires_at": "2026-01-01T12:00:00.000Z",
  "checkout_url": "https://nowpay.finance/i/inv_abc123"
}
Error codes
CodeStatusDescription
invalid_amount400amount missing or not a positive numeric string.
invalid_network400network is not a supported chain code.
network_inactive400chain exists in config but is not active.
idempotency_conflict409Idempotency-Key reused with a different body.
GET/api/v1/invoices?id={id}≡ NowPayments GET /v1/invoice/{id}

Get invoice by ID

Returns the current state of a single invoice — including the deposit address, paid amount (which may differ from the requested amount if the customer over/underpaid), and the on-chain transaction hash once confirmed.

ParameterTypeRequiredDescription
idstringyesInvoice ID returned by POST /api/v1/invoices.
Request example
request.sh
curl https://nowpay.finance/api/v1/invoices?id=inv_abc123 \
  -H "x-api-key: sk_live_4f3c2b1a9e8d7c6b5a4f3e2d1c0b9a8f"
Response example
response.json
{
  "id": "inv_abc123",
  "status": "finished",
  "amount": "50.00",
  "paidAmount": "50.00",
  "network": "polygon",
  "address": "0x7d5a3f9c2b1e8a4d6f0c2b5a7e9d1f3c4b2a8e6d",
  "expiresAt": "2026-01-01T12:00:00.000Z",
  "overpaid": false,
  "createdAt": "2026-01-01T11:00:00.000Z",
  "externalId": "order_12345"
}
Error codes
CodeStatusDescription
not_found404No invoice with that ID belongs to this merchant.
GET/api/v1/invoices?limit=50&cursor={cursor}≡ NowPayments GET /v1/invoice

List invoices

Returns a paginated list of the merchant's invoices, newest first. Use the `next_cursor` from the previous response to fetch the next page. When `next_cursor` is `null`, you've reached the end.

ParameterTypeRequiredDescription
limitintegernoPage size. Default 50, max 100.
cursorstringnoOpaque cursor from `next_cursor` of the previous page.
statusstringnoFilter by status: waiting | confirming | finished | expired | refunded.
Request example
request.sh
curl "https://nowpay.finance/api/v1/invoices?limit=10&status=finished" \
  -H "x-api-key: sk_live_4f3c2b1a9e8d7c6b5a4f3e2d1c0b9a8f"
Response example
response.json
{
  "data": [
    {
      "id": "inv_abc123",
      "externalId": "order_12345",
      "amount": "50.00",
      "status": "finished",
      "network": "polygon",
      "address": "0x7d5a3f9c2b1e8a4d6f0c2b5a7e9d1f3c4b2a8e6d",
      "createdAt": "2026-01-01T11:00:00.000Z",
      "expiresAt": "2026-01-01T12:00:00.000Z"
    }
  ],
  "next_cursor": null
}

Payouts

A payout sends USDT from your merchant balance to a beneficiary address. The payout saga is:lock → sign/broadcast → confirm. Funds are locked the moment you POST. If the amount is below your autoApproveLimit(default 100 USDT), broadcast happens automatically. Above that, an admin must approve — and above 1,000 USDT the admin must complete a 2FA challenge.

POST/api/v1/payouts≡ NowPayments POST /v1/payout

Create a payout

Requests a USDT payout to a beneficiary address. The Idempotency-Key header is **required** — without it, the request is rejected with 400. Funds are locked immediately via a double-entry ledger transaction. If the amount is at or below the merchant's `autoApproveLimit` (default 100 USDT), the payout saga runs automatically. Otherwise it enters `pending_review` and an admin must approve (with 2FA for amounts above the 1,000 USDT threshold).

ParameterTypeRequiredDescription
amountstringyesUSDT to send (e.g. "100.00"). Must be ≥ chain.min_payout.
networkstringyesbsc | polygon | arbitrum | optimism | base.
addressstringyesBeneficiary EVM address (0x...). Must be whitelisted if require_whitelist is on.
Idempotency-KeyheaderyesReplay-safe key (UUIDv4). Required.
Request example
request.sh
curl -X POST https://nowpay.finance/api/v1/payouts \
  -H "x-api-key: sk_live_4f3c2b1a9e8d7c6b5a4f3e2d1c0b9a8f" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: c0a1b2c3-d4e5-6f7a-8b9c-0d1e2f3a4b5c" \
  -d '{
    "amount": "100.00",
    "network": "polygon",
    "address": "0xRecipientAddress"
  }'
Response example
response.json
{
  "id": "po_xyz789",
  "status": "approved",
  "fee_network": "0.5029",
  "gas_estimate_usdt": "0.0023",
  "gas_charged_usdt": "0.0029",
  "platform_fee_usdt": "0.50",
  "amount": "100.00",
  "network": "polygon",
  "address": "0xRecipientAddress",
  "created_at": "2026-01-01T12:30:00.000Z"
}
Error codes
CodeStatusDescription
missing_idempotency_key400Idempotency-Key header is required for payouts.
below_minimum400amount is below chain.min_payout (e.g. < 1 USDT on polygon).
invalid_address400Not a valid EVM address.
address_not_whitelisted403require_whitelist is on and this address is not whitelisted.
emergency_stop_active403Payouts are frozen for this account. Contact support.
insufficient_balance_polygon409Not enough available USDT on that chain (includes fee breakdown).
daily_limit_exceeded409Sum of today's payouts exceeds dailyLimit.
payouts_frozen409Reconciliation detected a divergence — payouts are globally frozen.
GET/api/v1/payouts/estimate?network={code}&amount={amount}≡ NowPayments GET /v1/estimated-price

Estimate payout fees

Previews the fee breakdown before committing to a payout. Gas prices are cached for 30 s; the +20% padding absorbs drift between this call and the subsequent POST /api/v1/payouts. Use this to show a transparent fee breakdown to your end-user.

ParameterTypeRequiredDescription
networkstringyesChain code (bsc, polygon, etc.).
amountstringyesUSDT amount (e.g. "100.50").
Request example
request.sh
curl "https://nowpay.finance/api/v1/payouts/estimate?network=polygon&amount=100.00" \
  -H "x-api-key: sk_live_4f3c2b1a9e8d7c6b5a4f3e2d1c0b9a8f"
Response example
response.json
{
  "network": "polygon",
  "amount": "100.00",
  "gas_estimate_usdt": "0.0023",
  "gas_charged_usdt": "0.0029",
  "platform_fee_usdt": "0.50",
  "fee_network_total": "0.5029",
  "total_debited": "100.5029",
  "beneficiary_receives": "100.00",
  "meta": {
    "gas_token": "POL",
    "gas_token_amount": "0.000003",
    "gas_price_wei": "50000000",
    "gas_units": "60000",
    "padding_bps": 2000,
    "markup_bps": 500,
    "payout_fee_fixed": "0.50",
    "payout_fee_bps": 0,
    "gas_price_cached": true,
    "token_price_cached": true,
    "token_price_fallback": false
  }
}
GET/api/v1/payouts?status={status}&limit=50≡ NowPayments GET /v1/payout

List payouts

Returns the merchant's payouts (newest first).

ParameterTypeRequiredDescription
statusstringnopending_review | approved | broadcasting | sent | failed | rejected.
limitintegernoDefault 50, max 100.
Request example
request.sh
curl "https://nowpay.finance/api/v1/payouts?status=sent" \
  -H "x-api-key: sk_live_4f3c2b1a9e8d7c6b5a4f3e2d1c0b9a8f"
Response example
response.json
{
  "data": [
    {
      "id": "po_xyz789",
      "status": "sent",
      "amount": "100.00",
      "fee_network": "0.5029",
      "network": "polygon",
      "address": "0xRecipientAddress",
      "txid": "0xdef456...",
      "created_at": "2026-01-01T12:30:00.000Z",
      "sent_at": "2026-01-01T12:30:45.000Z",
      "error": null
    }
  ]
}

Balance

Nowpay uses a double-entry ledger. Each chain has its own balance bucket — BSC USDT and Polygon USDT are not fungible. To move between them, usePOST /api/v1/swaps.

GET/api/v1/balance≡ NowPayments GET /v1/balance

Get merchant balance

Returns the merchant's available and locked USDT balances. Nowpay uses a per-chain ledger — BSC USDT and Polygon USDT are NOT fungible. To move between chains, use POST /api/v1/swaps.

Request example
request.sh
curl https://nowpay.finance/api/v1/balance \
  -H "x-api-key: sk_live_4f3c2b1a9e8d7c6b5a4f3e2d1c0b9a8f"
Response example
response.json
{
  "total": "1250.00",
  "locked": "100.00",
  "by_network": {
    "bsc": "250.00",
    "polygon": "1000.00"
  },
  "by_network_locked": {
    "bsc": "0",
    "polygon": "100.00"
  }
}

Networks

Lists the supported EVM chains with their USDT contract addresses, finality thresholds, and payout fee configuration. Use this to populate a chain picker in your checkout UI.

GET/api/v1/networks≡ NowPayments GET /v1/currencies

List supported networks

Returns all active EVM chains, their USDT contract addresses, confirmation thresholds, and per-chain payout fee configuration. Use this to populate a chain picker in your checkout UI.

Request example
request.sh
curl https://nowpay.finance/api/v1/networks \
  -H "x-api-key: sk_live_4f3c2b1a9e8d7c6b5a4f3e2d1c0b9a8f"
Response example
response.json
{
  "networks": [
    {
      "code": "bsc",
      "name": "BNB Smart Chain",
      "chain_id": 56,
      "usdt_contract": "0x55d398326f99059fF775485246999027B3197955",
      "decimals": 18,
      "gas_token": "BNB",
      "confirmations": 12,
      "finality_strategy": "block_count",
      "is_premium": false,
      "payout_fee_fixed": "0.50",
      "payout_fee_bps": 0,
      "min_payout": "1.00",
      "hot_wallet_treshold": "5000.00"
    },
    {
      "code": "polygon",
      "name": "Polygon PoS",
      "chain_id": 137,
      "usdt_contract": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
      "decimals": 6,
      "gas_token": "POL",
      "confirmations": 10,
      "finality_strategy": "block_count",
      "is_premium": false,
      "payout_fee_fixed": "0.50",
      "payout_fee_bps": 0,
      "min_payout": "1.00",
      "hot_wallet_treshold": "5000.00"
    }
  ]
}

Swaps

Cross-chain USDT swaps are ledger-only (no on-chain DEX). 0.5% fee (50 bps). Subject to a liquidity guard — the destination treasury hot wallet must hold sufficient USDT.

POST/api/v1/swaps

Cross-chain USDT swap

Converts USDT from one chain to another via a ledger-only transfer (no on-chain DEX). Subject to a 0.5% swap fee (50 bps) and a liquidity guard — the destination chain treasury hot wallet must hold sufficient USDT. Idempotency-Key header is **required**. NowPayments has no direct equivalent (it treats each coin as independent).

ParameterTypeRequiredDescription
from_networkstringyesSource chain (e.g. "bsc").
to_networkstringyesDestination chain (must differ from from_network).
amountstringyesUSDT to swap (e.g. "100.00").
Idempotency-KeyheaderyesReplay-safe key (UUIDv4).
Request example
request.sh
curl -X POST https://nowpay.finance/api/v1/swaps \
  -H "x-api-key: sk_live_4f3c2b1a9e8d7c6b5a4f3e2d1c0b9a8f" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7e8f9a0b-1c2d-3e4f-5a6b-7c8d9e0f1a2b" \
  -d '{
    "from_network": "bsc",
    "to_network": "polygon",
    "amount": "100.00"
  }'
Response example
response.json
{
  "id": "sw_abc12345",
  "fee": "0.50",
  "status": "done",
  "from_network": "bsc",
  "to_network": "polygon",
  "amount": "100.00"
}
Error codes
CodeStatusDescription
missing_idempotency_key400Idempotency-Key header is required for swaps.
same_network400from_network and to_network must differ.
insufficient_balance_bsc409Not enough USDT on the source chain.

Webhooks

Nowpay delivers event notifications to the URL you register in the merchant dashboard (Webhooks tab). Each delivery includes:

HeaderDescription
X-SignatureHMAC-SHA256(rawBody, secret). Hex. Nowpay-native.
x-nowpayments-sigHMAC-SHA512(rawBody, secret). Hex. NowPayments-compatible.
X-TimestampUnix seconds at send time. Anti-replay: reject if |now - X-Timestamp| > 300.
X-EventEvent name (e.g. invoice.finished).

Event types

invoice.waiting
invoice.confirming
invoice.finished
invoice.expired
deposit.credited
payout.pending_review
payout.approved
payout.broadcasting
payout.sent
payout.failed
swap.done
treasury.gas_low

Example payload

webhook-payload.json
{
  "event": "invoice.finished",
  "data": {
    "invoiceId": "inv_abc123",
    "merchantId": "mer_xyz",
    "network": "polygon",
    "amount": "50.00",
    "address": "0x7d5a3f9c2b1e8a4d6f0c2b5a7e9d1f3c4b2a8e6d",
    "paid_amount": "50.00",
    "txid": "0xabc123def456...",
    "overpaid": false
  },
  "timestamp": "2026-01-01T12:05:30.000Z"
}

Retry policy

Failed deliveries (non-2xx or network error) are retried with exponential backoff:

retry-schedule
1m → 10m → 1h → 6h → 24h  (5 attempts total)

Signature verification (Node.js)

verify-webhook.ts
import crypto from "node:crypto"

/**
 * Verify an incoming Nowpay webhook signature.
 *
 * Nowpay sends TWO signatures on every webhook delivery — both computed
 * over the EXACT raw body bytes (do NOT re-serialize JSON, key order matters):
 *   - X-Signature:        HMAC-SHA256(rawBody, secret).toString("hex")
 *   - x-nowpayments-sig:  HMAC-SHA512(rawBody, secret).toString("hex")
 *
 * Merchants migrating from NowPayments can keep their existing
 * x-nowpayments-sig verification code verbatim.
 *
 * Anti-replay: X-Timestamp (Unix seconds) — reject if older than 5 minutes.
 */
export function verifyNowpayWebhook({
  rawBody,
  headers,
  secret,
}: {
  rawBody: string
  headers: Record<string, string | undefined>
  secret: string
}): boolean {
  // 1. Anti-replay: reject timestamps older than 5 minutes
  const ts = Number(headers["x-timestamp"])
  if (!ts || Math.abs(Date.now() / 1000 - ts) > 300) {
    return false
  }

  // 2. Verify EITHER signature (Nowpay-native OR NowPayments-compatible)
  const expectedSha256 = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex")

  const expectedSha512 = crypto
    .createHmac("sha512", secret)
    .update(rawBody)
    .digest("hex")

  const sigA = headers["x-signature"] ?? ""
  const sigB = headers["x-nowpayments-sig"] ?? ""

  return (
    crypto.timingSafeEqual(Buffer.from(sigA), Buffer.from(expectedSha256)) ||
    crypto.timingSafeEqual(Buffer.from(sigB), Buffer.from(expectedSha512))
  )
}

Signature verification (Python)

verify_webhook.py
import hmac, hashlib, time

def verify_nowpay_webhook(raw_body: bytes, headers: dict, secret: str) -> bool:
    """Verify an incoming Nowpay webhook signature.

    Nowpay sends two signatures on every delivery — both HMAC of the exact
    raw body bytes (do NOT re-serialize JSON). Merchants migrating from
    NowPayments can keep their existing x-nowpayments-sig verification code.
    """
    # 1. Anti-replay: reject timestamps older than 5 minutes
    ts = int(headers.get("x-timestamp", "0"))
    if abs(time.time() - ts) > 300:
        return False

    # 2. Verify EITHER signature
    expected_sha256 = hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    expected_sha512 = hmac.new(
        secret.encode(), raw_body, hashlib.sha512
    ).hexdigest()

    sig_a = headers.get("x-signature", "")
    sig_b = headers.get("x-nowpayments-sig", "")

    return (
        hmac.compare_digest(sig_a, expected_sha256)
        or hmac.compare_digest(sig_b, expected_sha512)
    )

Errors

All errors use the same envelope:

error-envelope.json
{
  "error": {
    "code": "invalid_amount",
    "message": "amount must be a numeric string"
  }
}
HTTP statusMeaning
200 / 201 / 202Success (OK / Created / Accepted).
400Bad request — invalid body, missing required field.
401Missing or invalid API key.
403Insufficient scope, KYB not approved, address not whitelisted, or emergency stop active.
404Resource not found (or doesn't belong to this merchant).
409Conflict — insufficient balance, daily limit exceeded, payouts frozen, or idempotency-key reuse with different body.
429Rate limit exceeded. See X-RateLimit-Reset and Retry-After headers.
500Internal error — retry with backoff. If persistent, contact support.

Migrating from NowPayments

Nowpay was designed so a NowPayments merchant can migrate in an afternoon. Below is the field-by-field mapping. The two big changes: (1) Nowpay uses plural endpoint paths(/api/v1/invoices vs NowPayments'/v1/invoice), and (2) Nowpay requires anIdempotency-Key header on payouts and swaps.

NowPaymentsNowpayNote
x-api-keyx-api-keySame header name. ✅ zero change.
POST /v1/invoicePOST /api/v1/invoicesAdd /api prefix + pluralize.
price_amountamountString (NowPayments accepts number — we require string for decimal precision).
price_currency— (always usd)Nowpay only settles in USDT — no concept of fiat price.
pay_currencynetworkUse chain code: bsc | polygon | arbitrum | optimism | base.
order_idexternal_idSame purpose — merchant-internal order ID.
ipn_callback_url— (configured in dashboard)Nowpay uses the dashboard-registered webhook URL; per-invoice override is on the roadmap.
pay_addressaddressSame HD-derived deposit address. Just renamed.
x-nowpayments-sig (SHA-512)x-nowpayments-sig (SHA-512)Same header + algorithm — Nowpay also emits X-Signature (SHA-256) as native.
300+ coinsUSDT onlyScope reduction — much lower fees, faster finality.
No idempotencyIdempotency-Key requiredFor payouts & swaps. Strongly recommended for invoices.

Before / after

migration-diff.sh
# Before (NowPayments):
curl -X POST https://api.nowpayments.io/v1/invoice \
  -H "x-api-key: $NOWPAYMENTS_KEY" \
  -d '{"price_amount": 50, "price_currency": "usd", "pay_currency": "usdt"}'

# After (Nowpay) — same auth header, same JSON shape philosophy:
curl -X POST https://nowpay.finance/api/v1/invoices \
  -H "x-api-key: $NOWPAY_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"amount": "50.00", "network": "polygon"}'
What's the same
  • Auth header name (x-api-key)
  • REST verbs (POST/GET)
  • JSON request/response
  • IPN webhook pattern
  • Hosted checkout page concept
  • Error envelope shape
  • Webhook signature algorithm (HMAC-SHA512 via x-nowpayments-sig)
What's different
  • Endpoint paths pluralized + /api prefix
  • USDT-only (5 EVM networks vs 300+ coins)
  • Field names: amount/network vs price_amount/pay_currency
  • Per-chain ledger balances (BSC USDT ≠ Polygon USDT)
  • Idempotency-Key required on payouts + swaps
  • 2FA on large payouts (admin approval flow)
  • Webhook URL is dashboard-configured (not per-invoice)
Ready to integrate?

Open the interactive Swagger UI to send real test requests against your sandbox account, or download the OpenAPI 3.0 spec to generate a client in any language.