Concepts
BSV for web developers
Wallets, identity keys, signatures, BRCs and networks, explained by mapping each one to something you already know from web development.
You don't need to know how a blockchain works to use create-bsv-app. You do need five ideas, because they replace things you'd normally build yourself: user accounts, passwords and sessions.
The cheat sheet#
| You know | In a BSV app | Where it lives |
|---|---|---|
| User ID | identity key, a public key like 02ab… |
the user's wallet |
| Password | a signature from the user's wallet | never sent, never stored |
| "Sign in with Google" | "Connect wallet" | useWallet() |
| Session cookie | a proof per request, or your own JWT after login | signedFetch(), login() |
| Server API key | the server's own identity key | SERVER_PRIVATE_KEY |
| Stripe checkout | a transaction the wallet creates | wallet.createAction() (not in the scaffold yet) |
Wallets#
A wallet is an app the user installs, such as BSV Browser (opens in a new tab). It holds their private keys and asks them before doing anything with those keys. Your app never sees a private key. It asks the wallet to sign, encrypt or pay, and the wallet decides whether to.
BRC-100 is the standard interface between apps and wallets, and @bsv/sdk exposes it as WalletInterface. Any BRC-100 wallet works with your app, on desktop or on a phone (paired by QR code).
Identity keys#
When a user connects, you get their identity key: a public key, 66 hex characters starting with 02 or 03. It's stable for that wallet, it's unique, and nobody else can produce signatures for it. In practice it's your user ID.
Signatures vs transactions#
This one trips people up:
- A signature proves "the owner of key X approved this exact message". It's free, instant, works offline and touches no blockchain. Wallet login and signed requests are signatures. That's why the scaffold costs nothing to run.
- A transaction moves coins and gets broadcast to the network. It costs a fee (on BSV, a tiny fraction of a cent) and is permanent. The scaffold doesn't create transactions yet. That's your next step.
Your first payment#
When you're ready, the connected wallet can create transactions. The user approves each one in their wallet:
import { class P2PKHP2PKH, type WalletInterface } from '@bsv/sdk'
/** Ask the user's wallet to send `satoshis` to a BSV address. The wallet shows an approval prompt. */
export async function function pay(wallet: WalletInterface, address: string, satoshis: number): Promise<string | undefined>pay (wallet: WalletInterfacewallet: WalletInterface, address: stringaddress: string, satoshis: numbersatoshis: number): interface Promise<T>Promise<string | undefined> {
const { const txid: string | undefinedtxid } = await wallet: WalletInterfacewallet.WalletInterface.createAction: (args: CreateActionArgs, originator?: OriginatorDomainNameStringUnder250Bytes) => Promise<CreateActionResult>createAction({
CreateActionArgs.description: stringdescription: 'Tip the author',
CreateActionArgs.outputs?: CreateActionOutput[] | undefinedoutputs: [{
CreateActionOutput.lockingScript: stringlockingScript: new new P2PKH(): P2PKHP2PKH().P2PKH.lock(pubkeyhash: string | number[]): LockingScriptlock(address: stringaddress).Script.toHex(): stringtoHex(),
CreateActionOutput.satoshis: numbersatoshis,
CreateActionOutput.outputDescription: stringoutputDescription: 'Tip for the author'
}]
})
return const txid: string | undefinedtxid
}const { wallet } = useWallet()
if (wallet) await pay(wallet, recipientAddress, 1000) // 1000 satoshisThis type-checks against the @bsv/sdk version the scaffold installs. Try it on testnet first, with a testnet address and test coins from the BSV Faucet (opens in a new tab) (sign in, paste a testnet address, up to 10 million satoshis a day). Descriptions must be 5–50 characters, or the wallet rejects the action.
Key derivation, briefly#
A wallet doesn't sign everything with one key. For each purpose it derives a fresh key pair from the identity key, a protocol, a key ID and a counterparty (BRC-42 and BRC-43). That's how a login proof made for your server can't be replayed against another server: the counterparty is part of the key. The testing guide proves it with a test.
Networks#
| Network | --network |
Coins | Use it for |
|---|---|---|---|
| Testnet | test (default) |
free, worthless, from the BSV Faucet (opens in a new tab) | building and testing |
| Teratestnet | ttn |
free, worthless | testing against Teranode, BSV's new node software |
| Mainnet | main |
real | production |
Signatures work the same everywhere. The network only matters once you create transactions.
BRCs you will meet#
BRCs ("BSV Request for Comments") are BSV's open standards, published in the BRCs repository (opens in a new tab).
| BRC | What it is | Where you'll see it |
|---|---|---|
| BRC-100 | the app ↔ wallet interface | WalletInterface, WalletClient |
| BRC-103 | mutual authentication between peers | @bsv/auth proofs |
| BRC-42 / 43 | key derivation, protocol IDs and counterparties | every signature |
| BRC-52 | identity certificates (verified attributes on top of a key) | a future step for KYC-style needs |
| BRC-102 | deployment info (deployment-info.json) |
the BRC-102 example starters |
Overlays#
Several complete examples (Pollr, Postboard, MetaMarket and others) use overlay services: small servers that watch for transactions matching a topic and index them so apps can look them up. You don't need overlays for login or signed requests. They become relevant when your app's data lives on chain.