Documentation

Everything you need to accept Bitcoin, Ethereum, BNB Smart Chain and Tron payments with NasrPay - from your first sign-in to your first withdrawal.

Overview

NasrPay is a non-custodial crypto payment gateway. It derives a unique receiving address for every invoice from an extended public key (xpub/zpub) - it never holds a master seed or private key. Your account has its own balance, its own payout address, and its own withdrawal history; the underlying wallet is operated by the platform, but what you're owed and where it goes is entirely yours to control.

There are two ways to get paid: a checkout link you send a customer (recommended for real integrations - you specify an amount in USD and NasrPay handles the crypto conversion, address, and QR code), or a manually created invoice from your dashboard when you already know the exact chain, currency and amount. Either way, it happens under one of your merchants - a business profile with its own code, so invoices for different businesses never mix (more below).

1. Create your account

  1. Open the dashboard

    Go to /admin.html on your NasrPay domain.

  2. Sign in with Google

    There's no separate password to set. Your first sign-in creates your account automatically - no approval step, no card required.

  3. You're in

    You'll land on My Account, with an empty balance and no invoices yet. One more step - creating a merchant - and you can accept your first payment.

2. Create a merchant

A merchant is one of your businesses - its own name, its own invoices, and its own code. Run two stores? Create two merchants. Invoice creation authenticates with that code, not your dashboard session - the same way a Stripe secret key works, scoped to one business at a time instead of your whole account.

  1. Open My Merchants

    On the My Account tab, give it a name and click Create merchant.

  2. Save the code it shows you

    It's shown once, in full - copy it somewhere safe. NasrPay only ever stores a hash of it, the same way a password is stored, so it can't be shown again.

  3. Use it to create invoices and checkouts

    Send it as an X-Merchant-Code header (see the next two sections) or paste it into the dashboard's Create Invoice form.

Compromised or retiring a business? Rotate a merchant's code from the same screen to issue a new one immediately (the old one stops working right away), or disable the merchant entirely without deleting its invoice history.

4. Accept a payment: dashboard invoices

Useful for one-off requests, invoicing, or testing - when you already know exactly which chain, currency and amount you want to be paid.

  1. Open Create Invoice

    On the My Account tab of your dashboard.

  2. Fill in the form

    The merchant code of the business this invoice is for (see Create a merchant), order ID, chain, network (mainnet for real funds), currency, and the exact amount you're expecting - plus an optional callback URL and expiry.

  3. Share the address

    The invoice appears in the table below the form with its derived address. Send that address (and amount) to whoever's paying you, however you like.

5. Invoice statuses

Every invoice - whether created manually or through a checkout link - moves through the same states.

StatusMeaning
pendingWaiting for a payment to appear on-chain.
partialSome funds have arrived, but not yet enough to confirm.
underpaidA payment arrived and confirmed, but materially short of the expected amount - not auto-credited.
confirmedPaid the expected amount (within a small tolerance) and confirmed on-chain. Credited to your balance.
overpaidPaid more than expected. Still credited - the excess is yours too.
expiredNothing arrived before the invoice's expiry (2 hours, by default).
failedThe gateway couldn't generate or verify this invoice.

A slightly wrong amount isn't silently accepted or rejected - it's left as underpaid/overpaid so nothing is credited on a mismatch without a clear record of what actually happened.

6. Getting paid out

  1. Watch your balance

    My Balance shows confirmed funds credited to your account, per chain and currency, as invoices get paid.

  2. Set a payout address

    Under My Payout Addresses, add the address each chain's withdrawals should go to. One address per chain - it covers every currency on that chain (e.g. one Ethereum address receives both ETH and USDT payouts).

  3. Request a withdrawal

    Click Withdraw next to a balance, enter an amount up to what you're owed, and confirm. If the platform has a commission rate configured, it's shown before you confirm and deducted from the amount you receive - never added on top.

  4. Wait for it to process

    Withdrawals are signed and broadcast by the platform operator's offline signer, not automatically - status moves from pending to completed (with a transaction hash) or failed (refunded back to your balance).

7. Supported chains & currencies

ChainCurrenciesDerivationConfirmations required
BitcoinBTCm/84'/0'/0'/0/i (native SegWit)2
EthereumETH, USDT, USDCm/44'/60'/0'/0/i12
BNB Smart ChainBNB, USDTm/44'/60'/0'/0/i15
TronTRX, USDTm/44'/195'/0'/0/i19

Ethereum and BNB Smart Chain share the same derivation path and the same account key, since both are EVM chains - your Ethereum address and BNB Smart Chain address for the same invoice index are identical.

8. Webhooks

If an invoice (created directly or through a checkout) has a callbackUrl, NasrPay POSTs its current state there every time it changes - most usefully, the moment it's confirmed.

POST <your callbackUrl>
{
  "event": "invoice.updated",
  "invoice": { "id": "...", "status": "confirmed", "...": "..." },
  "timestamp": 1758556800000
}

Every delivery carries an X-Webhook-Signature header - sha256=<hex>, an HMAC-SHA256 of the raw request body. Verify it before trusting the payload:

Node.js
const crypto = require("crypto");
const expected = "sha256=" + crypto
  .createHmac("sha256", YOUR_SIGNING_SECRET)
  .update(rawRequestBody)
  .digest("hex");
if (expected !== req.headers["x-webhook-signature"]) {
  throw new Error("Signature mismatch");
}

A failed delivery (your endpoint down, timing out, or returning a non-2xx) retries automatically on the next payment check, up to 10 attempts. You can always fall back to polling GET /admin/api/invoices/:id instead of relying on webhooks alone.

9. API reference

/admin/api/* endpoints require your session cookie (set after signing in with Google) - this is the dashboard's own API, for viewing and managing your account. /api/merchant/* endpoints authenticate with a merchant's own code (the X-Merchant-Code header) instead - this is what your backend calls to actually create an invoice or checkout. /api/checkout/* is public - the unguessable checkout id is the only credential, the same trust model as any hosted checkout link.

Your account (session)

EndpointPurpose
GET /admin/api/meYour account and permissions.
GET /admin/api/balancesYour confirmed balance, per chain/currency.
GET /admin/api/ledgerEvery credit/debit that produced your current balance.

Merchants (session)

EndpointPurpose
POST /admin/api/merchantsCreate a business; returns its code once, in the response only.
GET /admin/api/merchantsList your businesses (name, code prefix, active status - never the full code).
POST /admin/api/merchants/:id/rotateIssue a new code, invalidating the old one immediately.
POST /admin/api/merchants/:id/deactivateDisable a merchant's code without deleting its invoice history.
POST /admin/api/merchants/:id/activateRe-enable a disabled merchant.

Invoices

EndpointAuthPurpose
POST /api/merchant/invoicesMerchant codeCreate an invoice with an exact chain/currency/amount.
GET /admin/api/invoicesSessionList your invoices, optionally filtered with ?merchantId=.
GET /admin/api/invoices/:idSessionOne invoice's current status.
POST /admin/api/invoices/:id/checkSessionForce an immediate on-chain check (otherwise checked every 5 minutes automatically).

Checkouts

EndpointAuthPurpose
POST /api/merchant/checkoutsMerchant codeCreate a USD-denominated checkout; returns payUrl.
GET /admin/api/checkouts/:idSessionLook up one of your own checkouts.
GET /api/checkout/:idCheckout idPublic status - what pay-select.html/pay-invoice.html read.
POST /api/checkout/:id/selectCheckout idPayer picks a chain/currency; creates the invoice.
POST /api/checkout/:id/checkCheckout idForces an immediate on-chain check for this checkout's invoice.

Payouts

EndpointPurpose
GET /admin/api/payout-addressesYour saved payout address per chain.
PUT /admin/api/payout-addresses/:chainSet or replace one.
POST /admin/api/withdrawalsRequest a withdrawal from your balance.
GET /admin/api/withdrawalsYour withdrawal history.
POST /admin/api/withdrawals/:id/cancelCancel a still-pending withdrawal.

10. For platform operators

This section is for whoever runs the NasrPay deployment itself, not for a regular signed-in user - most people using NasrPay to get paid can skip it.

The operator's dashboard account (the one matching SUPER_ADMIN_EMAIL) has an extra Admin tab to:

  • Set the platform's xpub/zpub/EVM/TRON extended public keys under Wallet Settings (or generate a fresh HD wallet under Wallet Generator - the mnemonic never leaves your browser).
  • Set a commission rate under Wallet Settings, taken from withdrawals only, never from invoices.
  • Review Platform Balances (total owed across every user) and Generated Addresses (where funds are actually sitting).
  • Grant other users scoped admin access under Users, without making them a second super-admin.
  • Sign and broadcast pending withdrawals offline using tools/withdrawal-signer.mjs, which is the only place a private key ever exists.

11. FAQ

How long until a payment confirms?

As soon as the chain's required confirmation count is reached (2 for Bitcoin, 12 for Ethereum, 15 for BNB Smart Chain, 19 for Tron) and the amount matches within tolerance. Checkout pages poll every minute; uncreated-invoice checks otherwise run every 5 minutes.

What if my customer sends the wrong amount?

A small difference still confirms automatically. A materially short or long payment is marked underpaid or overpaid instead of being silently credited or dropped - see Invoice statuses.

Who actually holds the funds?

Whoever holds the private key matching the platform's extended public key - never NasrPay's server. Your balance is a ledger of what you're owed from that wallet, paid out to the address you choose.

Can I test this without real money?

Yes - create a manual invoice with Network set to Testnet. Testnet invoices run the same detection pipeline but never credit your real balance.