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
-
Open the dashboard
Go to
/admin.htmlon your NasrPay domain. -
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.
-
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.
-
Open My Merchants
On the My Account tab, give it a name and click Create merchant.
-
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.
-
Use it to create invoices and checkouts
Send it as an
X-Merchant-Codeheader (see the next two sections) or paste it into the dashboard's Create Invoice form.
3. Accept a payment: checkout links
This is the integration path: your own backend creates a checkout for a dollar amount, sends the customer to a NasrPay-hosted page, and the customer picks how they want to pay. You never touch a crypto price or an address yourself.
-
Create a checkout from your backend
Call the API below with the USD amount, your own order id, and the code from the merchant this sale belongs to (see Create a merchant) as an
X-Merchant-Codeheader. No session, no cookie - this is meant to be called from a server.curl -X POST https://nasrpay.com/api/merchant/checkouts \ -H "Content-Type: application/json" \ -H "X-Merchant-Code: mch_..." \ -d '{ "orderId": "order-1042", "amountUsd": "49.00", "callbackUrl": "https://yourapp.com/webhooks/nasrpay" }'
{ "checkout": { "id": "c1a2...", "amountUsd": "49.00", "status": "awaiting_selection", "...": "..." }, "payUrl": "https://nasrpay.com/pay/c1a2..." } -
Send the customer to
payUrlRedirect the customer there right after checkout, the same way you'd redirect to a hosted Stripe or PayPal page.
-
The customer picks a network and currency
They see the amount in USD and choose from Bitcoin, Ethereum (ETH/USDT/USDC), BNB Smart Chain (BNB/USDT) or Tron (TRX/USDT).
-
NasrPay generates the invoice
The instant they choose, NasrPay converts the USD amount to the exact crypto amount at the live price, derives a fresh address, and shows a QR code, the address, and a 2-hour countdown. The page checks for payment automatically every minute.
-
You find out it's paid
Either your
callbackUrlgets a webhook (see Webhooks), or you pollGET /admin/api/checkouts/:idand readcheckout.invoice.status.
curl command above with a merchant code from Create a merchant.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.
-
Open Create Invoice
On the My Account tab of your dashboard.
-
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.
-
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.
| Status | Meaning |
|---|---|
| pending | Waiting for a payment to appear on-chain. |
| partial | Some funds have arrived, but not yet enough to confirm. |
| underpaid | A payment arrived and confirmed, but materially short of the expected amount - not auto-credited. |
| confirmed | Paid the expected amount (within a small tolerance) and confirmed on-chain. Credited to your balance. |
| overpaid | Paid more than expected. Still credited - the excess is yours too. |
| expired | Nothing arrived before the invoice's expiry (2 hours, by default). |
| failed | The 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
-
Watch your balance
My Balance shows confirmed funds credited to your account, per chain and currency, as invoices get paid.
-
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).
-
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.
-
Wait for it to process
Withdrawals are signed and broadcast by the platform operator's offline signer, not automatically - status moves from
pendingtocompleted(with a transaction hash) orfailed(refunded back to your balance).
7. Supported chains & currencies
| Chain | Currencies | Derivation | Confirmations required |
|---|---|---|---|
| Bitcoin | BTC | m/84'/0'/0'/0/i (native SegWit) | 2 |
| Ethereum | ETH, USDT, USDC | m/44'/60'/0'/0/i | 12 |
| BNB Smart Chain | BNB, USDT | m/44'/60'/0'/0/i | 15 |
| Tron | TRX, USDT | m/44'/195'/0'/0/i | 19 |
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.
{
"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:
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)
| Endpoint | Purpose |
|---|---|
GET /admin/api/me | Your account and permissions. |
GET /admin/api/balances | Your confirmed balance, per chain/currency. |
GET /admin/api/ledger | Every credit/debit that produced your current balance. |
Merchants (session)
| Endpoint | Purpose |
|---|---|
POST /admin/api/merchants | Create a business; returns its code once, in the response only. |
GET /admin/api/merchants | List your businesses (name, code prefix, active status - never the full code). |
POST /admin/api/merchants/:id/rotate | Issue a new code, invalidating the old one immediately. |
POST /admin/api/merchants/:id/deactivate | Disable a merchant's code without deleting its invoice history. |
POST /admin/api/merchants/:id/activate | Re-enable a disabled merchant. |
Invoices
| Endpoint | Auth | Purpose |
|---|---|---|
POST /api/merchant/invoices | Merchant code | Create an invoice with an exact chain/currency/amount. |
GET /admin/api/invoices | Session | List your invoices, optionally filtered with ?merchantId=. |
GET /admin/api/invoices/:id | Session | One invoice's current status. |
POST /admin/api/invoices/:id/check | Session | Force an immediate on-chain check (otherwise checked every 5 minutes automatically). |
Checkouts
| Endpoint | Auth | Purpose |
|---|---|---|
POST /api/merchant/checkouts | Merchant code | Create a USD-denominated checkout; returns payUrl. |
GET /admin/api/checkouts/:id | Session | Look up one of your own checkouts. |
GET /api/checkout/:id | Checkout id | Public status - what pay-select.html/pay-invoice.html read. |
POST /api/checkout/:id/select | Checkout id | Payer picks a chain/currency; creates the invoice. |
POST /api/checkout/:id/check | Checkout id | Forces an immediate on-chain check for this checkout's invoice. |
Payouts
| Endpoint | Purpose |
|---|---|
GET /admin/api/payout-addresses | Your saved payout address per chain. |
PUT /admin/api/payout-addresses/:chain | Set or replace one. |
POST /admin/api/withdrawals | Request a withdrawal from your balance. |
GET /admin/api/withdrawals | Your withdrawal history. |
POST /admin/api/withdrawals/:id/cancel | Cancel 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.