Skip to main content

Bitcoin

Slugbtc
Address formatNative segwit (P2WPKH), bc1q…
Account pathm/84'/0'/0' (BIP-84)
Cloud storeszpub
DerivationM/0/{i} — public, no Edge required
Confirmations1, 2 and 3 — a webhook at each
TokensNone. Native BTC only
Explorerhttps://mempool.space/tx/{txid} · https://mempool.space/address/{address}

Addresses

Native segwit, one per customer, issued once and kept.

{ "chain": "btc",
"address": "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu",
"derivationPath": "m/84'/0'/0'/0/0" }

That address is what the published BIP-39 test vector derives at index 0 — useful for confirming your Edge's derivation is correct. See Installation.

Native segwit rather than legacy P2PKH or wrapped P2SH: it is cheaper to spend from (witness data is discounted in the fee calculation), it is universally supported by senders in 2026, and it produces the bc1q prefix your customers now expect. Nothing here issues a Taproot bc1p address; if a sender insists on one, they cannot pay you, but that is not a case that occurs in practice.

The confirmation ladder

Bitcoin is the only chain here with more than one threshold, and deposit_confirmed fires three times for one deposit:

ConfirmationsEvents you receivethreshold
1deposit_detected and deposit_confirmed1
2deposit_confirmed2
3deposit_confirmed3

Read threshold from the payload to know which one you have. Three is settlement-safe for most values; many fintechs credit small amounts at 1 and hold larger ones to 3, which is exactly why the ladder exists rather than a single figure.

Each threshold fires exactly once, tracked in a bitmask, so a reorg-and-replay cannot re-fire one that already fired.

Do not key your ledger credit on event.id alone

Three events, three ids, one deposit. If your credit is per event you credit three times. Dedupe events on event.id, and key the credit on (txid, outputIndex). See Idempotency.

Fees

fee = estimatedVBytes × satPerVbyte
Field
satPerVbyteThe current rate for the target confirmation window
estimatedVBytesTransaction size estimate. Depends on UTXO selection
inputCountHow many UTXOs the build expects to spend
outputCountDestination plus change

The fee comes out of the inputs being spent. sum(inputs) − sum(outputs) is the fee, so Bitcoin cannot have the INSUFFICIENT_GAS problem the EVM chains have — there is no separate gas asset. A send that leaves nothing for the fee gets INSUFFICIENT_FUNDS.

estimatedVBytes is genuinely an estimate. It moves with how many UTXOs the build selects, which depends on what has arrived at that address. Do not present a fee to a customer as final unless you are prepared to absorb the difference.

UTXO consolidation

An address that has received many small deposits holds many small UTXOs, and spending from it requires including several of them — each adding about 68 vBytes. A withdrawal from such an address costs more than the same withdrawal from an address with one large UTXO, sometimes several times more.

This is the one Bitcoin-specific reason to sweep even when you otherwise would not: consolidating during a low-fee period is materially cheaper than paying the input premium on every future withdrawal.

Sweeping twenty addresses in one transaction with twenty inputs is far cheaper than twenty separate transactions. It also proves, on-chain and forever, that those twenty addresses are controlled by the same entity.

Whether that matters is a decision about your customers, not a technical one. It cannot be undone. Decide deliberately rather than by picking whichever code was easier to write. See Sweeps.

Reorgs

Bitcoin's reorg risk is what the three-threshold ladder is calibrated against. A one-block reorg is routine; a three-block reorg has not happened outside of a consensus incident.

If a block containing a detected deposit is orphaned, the transaction returns to pending and the count resets. Any threshold not previously fired fires again when reached. A reversal after threshold 3 is a genuine incident — see Incident response.

No tokens

Bitcoin support is native BTC only. Ordinals, BRC-20, Runes and Lightning are all out of scope, and a deposit involving them is not detected as a token deposit — an inscription's associated sats appear as an ordinary BTC deposit of that amount, which for a fintech's purposes is the correct reading.

Operational notes

  • Balances and UTXOs are address-indexed lookups, which is what deposit monitoring needs and what a plain node RPC cannot answer. Ziklag operates that infrastructure. If balances return 503 CHAIN_UNAVAILABLE while derivation keeps working, that is ours to fix — see Incident response.
  • zpub, not xpub. Cloud stores the BIP-84 form. If you import your mnemonic into a wallet to verify, point it at m/84'/0'/0' — the same seed at m/44'/0'/0' derives entirely different addresses, which look wrong but are not.
  • Dust limits. A send below about 294 satoshi to a segwit output is rejected by the network as dust. It surfaces as 422 CHAIN_REJECTED with the node's reason.
  • Mempool congestion shows up as satPerVbyte climbing and confirmations taking much longer than ten minutes. There is nothing to fix; there is something to tell your customers.