Bitcoin
Accept BTC to fresh addresses derived from your zpub. NoHoldPay watches the chain - no seed phrase, no custody.
Networks
| Mainnet | Testnet4 | |
|---|---|---|
| Chain key | BTC | BTC_TESTNET |
| Wallet key | zpub | vpub |
| Address format | bc1q... | tb1q... |
| Confirmations | 6 | 2 |
| Min invoice | $1.00 | $0.10 |
| Payment window | 60 minutes | 60 minutes |
| Late-grace revival | 12 hours | 12 hours |
Wallet setup
Use a wallet that can export an account-level native SegWit public key and raise its gap limit.
| Wallet | Best for | Notes |
|---|---|---|
| Sparrow Wallet | Most merchants | Best default for live BTC, testnet4, and hardware wallets. |
| Electrum | Lightweight desktop setup | Console command to raise the gap limit. |
| Bitcoin Core | Full-node merchants | Advanced setup. Use this if you already run a node. |
| Specter Desktop | Hardware wallet or multisig | Advanced - node and hardware-wallet users. |
Hardware wallets work best through Sparrow, Electrum, or Specter. NoHoldPay needs your account-level zpub or vpub, not a wallet receive address.
Accepting more than one coin? Hodlall exports a BTC zpub (and Litecoin, XRP, Monero, and more) from one app, so you maintain fewer wallets. See Choosing your wallets for the full strategy.
What to paste
| Mode | Chain | Paste this | Do not paste |
|---|---|---|---|
| Live | BTC | Account-level zpub | Seed phrase, private key, xpriv, receive address, ypub (wrapped SegWit) |
| Test | BTC_TESTNET | Account-level vpub | Seed phrase, private key, xpriv, receive address, a mainnet zpub |
A plain xpub (live) or tpub (test) from the same Native SegWit (BIP-84) account also works. NoHoldPay asks you to affirm it is a Native SegWit account and to paste your wallet's first receiving address, then derives that address itself and saves the wallet only if the two match. A zpub/vpub skips that step because its prefix already proves the script type. Wrapped-SegWit ypub/upub keys are not accepted.
One wallet per chain
Bitcoin uses a single xpub per chain and derives a fresh address per payment, so multi-wallet sharding does not apply. Adding a second BTC (or BTC_TESTNET) wallet on the same account returns HD_CHAIN_SINGLE_WALLET (422). To switch xpubs, retire the existing wallet first.
One account key per NoHoldPay account. An account key can only be bound to one NoHoldPay account at a time. Two accounts on the same key derive byte-identical addresses at the same derivation index, so one customer payment could be credited against an order in each. The second bind is rejected when you add the wallet. If you run more than one account, use a separate account key for each. Retiring a wallet releases its key, so moving your business to a different account still works.
Live setup (Sparrow)
100. Use 500 or higher for high-volume.Open the wallet settings and copy the account-level public key - it must start with zpub.
Screenshot
Sparrow wallet Settings tab showing the account-level zpub
add image at public/images/guides/btc-sparrow-zpub.png
BTC -> paste the zpub.Create a small live payment. Compare the generated bc1q... address with your wallet before
accepting real orders.
Test setup (Sparrow)
vpub.BTC_TESTNET -> paste the vpub.Fund the wallet, create a payment with a test API key, pay it, and wait for 2 confirmations.
Testnet4 faucets:
- coinfaucet.eu
- testnet.help
- mempool.space (GitHub auth)
Address verification
The first generated address must match the one your wallet shows at the same derivation path:
| Mode | External receive path | Address |
|---|---|---|
Live BTC | m/84'/0'/0'/0/index | bc1q... |
Test BTC_TESTNET | m/84'/1'/0'/0/index | tb1q... |
Gap filler
Bitcoin wallets stop scanning after a run of unused addresses (the "gap limit"). Unpaid checkout pages create unused addresses, so your wallet may miss later paid addresses until its gap is filled.
NoHoldPay watches every generated address for the full payment window plus the 12-hour late-grace period - its detection is never gap-limited. Gap filler only helps your own wallet discover those addresses.
Rule: if your wallet supports raising the gap limit, raise it before launch (100 low-volume, 500+ high-volume). If the dashboard warns the gap is at risk and you can't raise the limit, use gap filler.
Fixing a gap
| Option | What happens | Cost |
|---|---|---|
| Do it yourself | Build a multi-output send across the dust outputs from your wallet. | Miner fee from your wallet. |
| NoHoldPay handles it | NoHoldPay signs and broadcasts the gap-filler transaction. | Dust + miner fee + small service fee, deducted from Prepaid Credit. |
For platform-handled gap-filler, the BTC miner fee is pass-through (no markup). RBF bumps charge only the extra miner fee.
Not supported
- Lightning payments
- Legacy
1...addresses - Wrapped SegWit
3...addresses - Testnet3 (deprecated - use testnet4)
- Custodial or exchange deposit wallets
Recovery
Your Bitcoin seed phrase remains the recovery tool. NoHoldPay only stores your public key - it cannot spend BTC.
If your wallet does not show a paid address:
- Raise the wallet gap limit.
- Rescan or restore the wallet.
- Use the Recovery Kit for your xpub and derivation path. For a specific payment, the address index and transaction hash are on that payment's detail page, and the dashboard's Wallets -> Recovery guide can export them for the whole wallet.
- Use gap filler only when your wallet still can't discover the address.
Common errors
| Code | HTTP | When |
|---|---|---|
VALIDATION_ERROR (variant mismatch) | 422 | The pasted key is wrapped-SegWit (ypub/upub), a wrong-network key (a mainnet zpub on BTC_TESTNET, or vice versa), or a plain xpub pasted without affirming Native SegWit. Re-export as native SegWit, or affirm the plain xpub and paste your first receiving address (see Wallet setup). |
FIRST_ADDRESS_REQUIRED | 422 | You affirmed a plain xpub/tpub as Native SegWit but did not include your wallet's first receiving address. Paste it so NoHoldPay can confirm the key. |
FIRST_ADDRESS_MISMATCH | 422 | The first address NoHoldPay derived does not match the one you pasted. Make sure you copied your wallet's first receiving address for a Native SegWit (BIP-84) account. |
HD_CHAIN_SINGLE_WALLET | 422 | You already have an active wallet on this chain. Bitcoin caps at one wallet per chain. Retire the existing one first if you want to switch xpubs. |
INVOICE_BELOW_CHAIN_MINIMUM | 422 | The invoice is below the minimum on every chain the payment could offer (BTC's minimum is $1.00 USD, $0.10 on BTC_TESTNET). If at least one other enabled chain meets its minimum, the payment succeeds and the BTC option is silently omitted from checkout instead. The error message quotes the lowest minimum among the blocked chains, which may not be BTC's. |
WALLET_ADDRESS_COLLISION | 409 | Two wallets derived the same address. Sharing one account key across NoHoldPay accounts is now rejected when the wallet is added, so this only appears for a pair bound before that check existed. Rotate one of the wallets to a fresh xpub. |
WALLET_XPUB_ALREADY_BOUND | 422 | This account key is already bound to a NoHoldPay account on this chain. Two accounts on one key derive identical addresses, so a payment could be credited to the wrong order. Use a separate key, or retire the wallet holding it. |
GAP_BELOW_MINIMUM | 400 | You called gap-filler-plan but the gap is already below the action threshold. No fill needed. |
BUMP_TOO_SOON | 429 | Gap-filler RBF bump requested within 30 seconds of the previous one. Wait, then retry. |
CLAIM_NOT_SUPPORTED_FOR_CHAIN | 422 | Customer pasted a tx hash on a BTC checkout. Bitcoin uses watcher polling and does not need a manual claim path. |