@t402/btc
Bitcoin & Lightning Network payment mechanism for T402 payments.
Installation
npm install @t402/btc @t402/coreFor PSBT construction (optional):
npm install bitcoinjs-libOverview
The @t402/btc package enables T402 payments on Bitcoin and Lightning Network. It supports two payment schemes:
- BTC On-chain (
exact) — PSBT-based payments with on-chain settlement - Lightning Network (
lightning) — BOLT11 invoice payments with preimage verification
Key features:
- Dual scheme — on-chain for larger payments, Lightning for instant micropayments
- PSBT standard — uses BIP-174 Partially Signed Bitcoin Transactions
- BOLT11 invoices — standard Lightning payment requests with preimage proof
- Taproot support — compatible with P2TR, P2WPKH, and legacy address types
Supported Networks
| Network | CAIP-2 ID | Scheme | Settlement |
|---|---|---|---|
| BTC Mainnet | bip122:000000000019d6689c085ae165831e93 | exact | On-chain (~10 min) |
| BTC Testnet | bip122:000000000933ea01ad0ee984209779ba | exact | On-chain (~10 min) |
| Lightning Mainnet | lightning:mainnet | lightning | Instant |
| Lightning Testnet | lightning:testnet | lightning | Instant |
Quick Start
BTC On-chain
import { registerExactBtcScheme } from '@t402/btc/exact/client'
import { t402Client } from '@t402/core/client'
const client = new t402Client()
registerExactBtcScheme(client, {
signer: {
signPsbt: async (psbt) => { /* sign with wallet */ },
getAddress: () => 'bc1q...',
getPublicKey: () => '02...',
},
})
const response = await client.fetch('https://api.example.com/premium')Lightning
import { registerLightningScheme } from '@t402/btc/lightning/client'
import { t402Client } from '@t402/core/client'
const client = new t402Client()
registerLightningScheme(client, {
signer: {
payInvoice: async (bolt11) => {
const result = await lightningNode.pay(bolt11)
return { preimage: result.preimage, paymentHash: result.paymentHash }
},
getNodePubKey: () => '02...',
},
})Client Usage
BTC On-chain Client
import { registerExactBtcScheme } from '@t402/btc/exact/client'
import { t402Client } from '@t402/core/client'
const client = new t402Client()
registerExactBtcScheme(client, {
signer: {
signPsbt: async (psbt) => {
// Sign the PSBT using your Bitcoin wallet (e.g., bitcoinjs-lib)
return signedPsbt
},
getAddress: () => 'bc1q...',
getPublicKey: () => '02...',
},
})
// Create payment payload (constructs and signs PSBT)
const payload = await client.createPaymentPayload(requirements)Lightning Client
import { registerLightningScheme } from '@t402/btc/lightning/client'
import { t402Client } from '@t402/core/client'
const client = new t402Client()
registerLightningScheme(client, {
signer: {
payInvoice: async (bolt11) => {
// Pay BOLT11 invoice via your Lightning node (LND, CLN, etc.)
const result = await lndClient.payInvoice({ paymentRequest: bolt11 })
return {
preimage: result.preimage,
paymentHash: result.paymentHash,
}
},
getNodePubKey: () => '02abc...def',
},
})Server Usage
import { registerExactBtcScheme } from '@t402/btc/exact/server'
import { registerLightningScheme } from '@t402/btc/lightning/server'
import { t402ResourceServer } from '@t402/core/server'
const server = new t402ResourceServer(facilitatorClient)
// BTC on-chain
registerExactBtcScheme(server, {
schemeConfig: { payTo: 'bc1q...' },
})
// Lightning
registerLightningScheme(server, {
schemeConfig: {
generateInvoice: async (amountSats, description, expiry) => {
// Generate BOLT11 invoice via your Lightning node
const invoice = await lndClient.addInvoice({
value: amountSats,
memo: description,
expiry: expiry,
})
return {
bolt11Invoice: invoice.paymentRequest,
paymentHash: invoice.rHash,
}
},
},
})Facilitator Usage
import { registerExactBtcScheme } from '@t402/btc/exact/facilitator'
import { registerLightningScheme } from '@t402/btc/lightning/facilitator'
import { t402Facilitator } from '@t402/core/facilitator'
const facilitator = new t402Facilitator()
// BTC on-chain
registerExactBtcScheme(facilitator, {
signer: btcFacilitatorSigner,
networks: 'bip122:000000000019d6689c085ae165831e93',
})
// Lightning
registerLightningScheme(facilitator, {
signer: lnFacilitatorSigner,
networks: 'lightning:mainnet',
})PaymentRequirements
BTC On-chain
const requirements = {
scheme: 'exact',
network: 'bip122:000000000019d6689c085ae165831e93',
payTo: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
maxAmountRequired: '100000', // satoshis
maxTimeoutSeconds: 3600
}Lightning
const requirements = {
scheme: 'lightning',
network: 'lightning:mainnet',
payTo: '02abc...def', // node pubkey
maxAmountRequired: '1000', // satoshis
maxTimeoutSeconds: 300,
extra: {
bolt11Invoice: 'lnbc10u1p...',
paymentHash: 'abc123...',
}
}Payment Flow
BTC On-chain Flow
- Server returns 402 with
scheme: "exact"andnetwork: "bip122:..." - Client constructs a PSBT sending the required amount to
payTo - Client signs the PSBT with their Bitcoin wallet
- Client broadcasts the signed transaction
- Client returns the transaction hash as proof of payment
- Facilitator verifies the transaction via Bitcoin RPC
Lightning Flow
- Server returns 402 with
scheme: "lightning"and a BOLT11 invoice - Client pays the BOLT11 invoice via their Lightning node
- Client receives the payment preimage as proof of payment
- Client returns the preimage and payment hash
- Facilitator verifies the preimage matches the payment hash
Lightning payments settle instantly with cryptographic proof (preimage). BTC on-chain payments require confirmation (~10 minutes for 1 block).
Multi-SDK Examples
import { registerExactBtcScheme } from '@t402/btc/exact/client'
import { registerLightningScheme } from '@t402/btc/lightning/client'
import { t402Client } from '@t402/core/client'
const client = new t402Client()
// Register BTC on-chain
registerExactBtcScheme(client, {
signer: {
signPsbt: async (psbt) => signedPsbt,
getAddress: () => 'bc1q...',
getPublicKey: () => '02...',
},
})
// Register Lightning
registerLightningScheme(client, {
signer: {
payInvoice: async (bolt11) => ({
preimage: '...', paymentHash: '...'
}),
getNodePubKey: () => '02...',
},
})
const response = await client.fetch('https://api.example.com/premium')Example: Express Integration
import express from 'express'
import { paymentMiddleware } from '@t402/express'
const app = express()
app.use(paymentMiddleware({
'GET /api/premium': {
price: '$1.00',
network: 'lightning:mainnet',
payTo: '02abc...def',
description: 'Premium API access'
}
}))
app.get('/api/premium', (req, res) => {
res.json({ data: 'premium content' })
})
app.listen(3000)