Reference@t402/btc

@t402/btc

Bitcoin & Lightning Network payment mechanism for T402 payments.

Installation

npm install @t402/btc @t402/core

For PSBT construction (optional):

npm install bitcoinjs-lib

Overview

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

NetworkCAIP-2 IDSchemeSettlement
BTC Mainnetbip122:000000000019d6689c085ae165831e93exactOn-chain (~10 min)
BTC Testnetbip122:000000000933ea01ad0ee984209779baexactOn-chain (~10 min)
Lightning Mainnetlightning:mainnetlightningInstant
Lightning Testnetlightning:testnetlightningInstant

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

  1. Server returns 402 with scheme: "exact" and network: "bip122:..."
  2. Client constructs a PSBT sending the required amount to payTo
  3. Client signs the PSBT with their Bitcoin wallet
  4. Client broadcasts the signed transaction
  5. Client returns the transaction hash as proof of payment
  6. Facilitator verifies the transaction via Bitcoin RPC

Lightning Flow

  1. Server returns 402 with scheme: "lightning" and a BOLT11 invoice
  2. Client pays the BOLT11 invoice via their Lightning node
  3. Client receives the payment preimage as proof of payment
  4. Client returns the preimage and payment hash
  5. 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)

Additional Resources