@bsv/402-pay
BRC-121 HTTP 402 Payment Required handler for client and server. Client-side: auto-pays 402 responses. Server-side: middleware/validation for accepting BSV micropayments over HTTP.
Install
bash
npm install @bsv/402-payQuick start
typescript
// ===== SERVER SIDE =====
import express from 'express'
import { createPaymentMiddleware } from '@bsv/402-pay/server'
const app = express()
app.use('/articles/:slug', createPaymentMiddleware({
wallet,
calculatePrice: (path) => {
if (path.includes('/premium/')) return 1000
return undefined
}
}))
app.get('/articles/:slug', (req, res) => {
if (req.payment) {
res.json({ article: 'Paid content here', paidBy: req.payment.senderIdentityKey })
} else {
res.json({ article: 'Free content' })
}
})
// ===== CLIENT SIDE =====
import { create402Fetch } from '@bsv/402-pay/client'
const fetch402 = create402Fetch({
wallet,
cacheTimeoutMs: 30 * 60 * 1000
})
const response = await fetch402('https://example.com/articles/foo')
const article = await response.json()
console.log(article)What it provides
Server
- createPaymentMiddleware — Express middleware for automatic 402 handling
- validatePayment — Validate incoming payment headers
- send402 — Send 402 response with payment request headers
Client
- create402Fetch — Fetch wrapper that auto-handles 402 responses
- constructPaymentHeaders — Build payment headers manually
- clearCache — Clear cached paid content
Types & Constants
- PaymentMiddlewareOptions — Middleware configuration
- PaymentResult — Parsed payment with
satoshisPaid,senderIdentityKey, andtxid - PaymentHeaders — Five required headers (BEEF, SENDER, NONCE, TIME, VOUT)
- HEADERS — Header names enum
- BRC29_PROTOCOL_ID — Protocol ID for payment key derivation
Common patterns
Server low-level API
typescript
import express from 'express'
import { validatePayment, send402 } from '@bsv/402-pay/server'
const app = express()
app.get('/premium', async (req, res) => {
const price = 100
const result = await validatePayment(req, wallet, price)
if (!result || !result.accepted) {
send402(res, serverIdentityKey, price)
return
}
res.json({
content: 'Premium stuff',
tx: result.txid,
paidBy: result.senderIdentityKey
})
})Client manual headers
typescript
import { constructPaymentHeaders } from '@bsv/402-pay/client'
const headers = await constructPaymentHeaders(
wallet,
'https://example.com/articles/foo',
100, // 100 sats
serverPublicKey
)
const res = await fetch('https://example.com/articles/foo', { headers })Client with cache management
typescript
const fetch402 = create402Fetch({
wallet,
cacheTimeoutMs: 30 * 60 * 1000 // Cache for 30 minutes
})
// Make requests — auto-pays 402s with caching
const response = await fetch402('https://api.example.com/content')
const data = await response.json()
// Clear cache between sessions
fetch402.clearCache()Key concepts
- 402 Payment Required — HTTP status code for micropayments (BRC-121)
- Server Headers (402 response) —
x-bsv-sats,x-bsv-serverfor payment request - Client Headers (payment request) — BEEF, sender, nonce, time, vout for payment proof
- Replay Protection — Timestamp freshness (30 seconds) + transaction uniqueness
- Key Derivation — BRC-29 using server identity key + nonce + timestamp
- Caching — Client caches paid content per URL to avoid re-payment
- P2PKH Script — Payment always P2PKH:
OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG
When to use this
- Building clients that interact with paid APIs
- Creating applications that need to pay for content on-demand
- Implementing automatic payment for API access
- Building smart clients that handle 402 gracefully
- Testing payment-gated services
- Monetizing APIs with micropayments
When NOT to use this
- Routes that already require BRC-31 HTTP auth — use
@bsv/payment-express-middlewarewith@bsv/auth-express-middleware - Manual payment control needed — don't use auto-handler
- Subscription-based access — use authentication instead
- Large bulk payments — use dedicated payment processing
Spec conformance
- BRC-121 — HTTP 402 Payment Required micropayments
- BRC-29 — Key derivation (payment pubkey via nonce + timestamp)
- BRC-42 — Public key derivation
- BRC-100 — Wallet interface
- P2PKH — Standard Bitcoin SV locking script
- BEEF — Transaction proof format
Common pitfalls
- Timestamp must be fresh — If
x-bsv-timeis >30 seconds old, payment is rejected - Server identity key required — Server must send its identity public key in 402 response
- Transaction uniqueness — Replaying same BEEF twice is rejected; nonce must be different
- Cache timeout too long — If cached, same content served without payment check
- BEEF must be valid — Malformed or invalid BEEF transaction is rejected
- Wallet not available — Client-side
create402Fetchrequires working WalletClient - calculatePrice undefined — If returns undefined, payment is skipped (content is free)
- Server clock skew — If clocks differ by >30 seconds, payment fails; use NTP
Related packages
- @bsv/payment-express-middleware — Server-side payment gating with Express
- @bsv/auth-express-middleware — HTTP authentication (often paired with 402)
- @bsv/sdk — WalletClient, PublicKey, Utils for payment construction