ChainsBitcoin & Lightning

Bitcoin & Lightning

Guide for integrating T402 with Bitcoin on-chain (PSBT) and Lightning Network (BOLT11) payments.

Overview

T402 supports Bitcoin through two payment methods:

MethodNetwork IDPayloadSettlementBest For
On-chain (PSBT)bip122:000000000019d6689c085ae165831e93Signed PSBT~10 min (1 confirmation)Larger payments
Lightning (BOLT11)lightning:mainnetPreimageInstant (~seconds)Micropayments

Network Identifiers

Bitcoin uses BIP-122 chain genesis block hashes as CAIP-2 identifiers:

NetworkCAIP-2 ID
BTC Mainnetbip122:000000000019d6689c085ae165831e93
BTC Testnetbip122:000000000933ea01ad0ee984209779ba
Lightning Mainnetlightning:mainnet
Lightning Testnetlightning:testnet

On-Chain (PSBT)

Bitcoin on-chain payments use BIP-174 Partially Signed Bitcoin Transactions (PSBT). The client creates and signs a PSBT, the facilitator verifies the outputs and broadcasts it.

Payment Flow

  1. Server returns 402 with network: "bip122:000000000019d6689c085ae165831e93" and payTo (Bitcoin address)
  2. Client builds a PSBT with the required output (payTo address + amount in satoshis)
  3. Client signs the PSBT and submits it as the payment payload
  4. Facilitator verifies the PSBT outputs match requirements
  5. Facilitator finalizes and broadcasts the transaction
  6. Facilitator waits for confirmation and returns the txid

Supported Address Types

  • P2WPKH (bc1q…) — Native SegWit
  • P2TR (bc1p…) — Taproot
  • P2PKH (1…) — Legacy
  • P2SH (3…) — Script Hash

Dust Limit

The minimum payment amount is 546 satoshis (Bitcoin dust limit). Payments below this threshold are rejected.

Integration

import { ExactBtcScheme } from '@t402/btc/exact/client';
import { registerExactBtcScheme } from '@t402/btc/exact/server';
 
// Client — sign PSBTs
const btcClient = new ExactBtcScheme(btcSigner);
client.register('bip122:000000000019d6689c085ae165831e93', btcClient);
 
// Server — accept BTC payments
registerExactBtcScheme(server, {});

Signer Interface

Clients implement the ClientBtcSigner interface to sign PSBTs:

type ClientBtcSigner interface {
    // SignPsbt signs a PSBT and returns the base64-encoded signed PSBT
    SignPsbt(psbt string) (string, error)
 
    // GetAddress returns the signer's Bitcoin address
    GetAddress() string
 
    // GetPublicKey returns the signer's public key as hex
    GetPublicKey() string
}

Facilitators implement FacilitatorBtcSigner to verify and broadcast:

type FacilitatorBtcSigner interface {
    GetAddresses() []string
    VerifyPsbt(ctx context.Context, signedPsbt, expectedPayTo, expectedAmount string) (valid bool, reason string, payer string, err error)
    BroadcastPsbt(ctx context.Context, signedPsbt string) (txID string, err error)
    WaitForConfirmation(ctx context.Context, txID string, confirmations int) (confirmed bool, blockHash string, confs int, err error)
}

Lightning Network (BOLT11)

Lightning payments use BOLT11 invoices. The server provides a BOLT11 invoice, the client pays it and returns the preimage as proof of payment.

Payment Flow

  1. Server returns 402 with network: "lightning:mainnet" and a BOLT11 invoice in extra.bolt11Invoice
  2. Client pays the BOLT11 invoice via their Lightning node
  3. Client receives the preimage and payment hash
  4. Client submits preimage + payment hash as the payment payload
  5. Facilitator looks up the payment hash to verify settlement
  6. Payment confirmed instantly

Integration

import { LightningScheme } from '@t402/btc/lightning/client';
import { registerLightningScheme } from '@t402/btc/lightning/server';
 
// Client — pay BOLT11 invoices
const lnClient = new LightningScheme(lightningSigner);
client.register('lightning:mainnet', lnClient);
 
// Server — generate BOLT11 invoices
registerLightningScheme(server, { invoiceGenerator });

Lightning Signer Interface

type ClientLightningSigner interface {
    // PayInvoice pays a BOLT11 invoice and returns the preimage and payment hash
    PayInvoice(bolt11 string) (preimage string, paymentHash string, err error)
 
    // GetNodePubKey returns the Lightning node's public key as hex
    GetNodePubKey() string
}

BOLT11 Invoice Formats

PrefixNetwork
lnbcBitcoin Mainnet
lntbBitcoin Testnet
lnbcrtBitcoin Regtest

Payload Types

PSBT Payload

{
  "t402Version": 2,
  "payload": {
    "signedPsbt": "cHNidP8BAH..."
  },
  "accepted": {
    "scheme": "exact",
    "network": "bip122:000000000019d6689c085ae165831e93",
    "asset": "BTC",
    "amount": "100000",
    "payTo": "bc1q..."
  }
}

Lightning Payload

{
  "t402Version": 2,
  "payload": {
    "paymentHash": "abc123...",
    "preimage": "def456...",
    "bolt11Invoice": "lnbc10u1p..."
  },
  "accepted": {
    "scheme": "exact",
    "network": "lightning:mainnet",
    "asset": "BTC",
    "amount": "10000",
    "payTo": "02abc..."
  }
}

SDK Support

SDKOn-chain (PSBT)Lightning (BOLT11)
TypeScript (@t402/btc)Client, Server, FacilitatorClient, Server, Facilitator
Go (mechanisms/btc)Client, Server, FacilitatorClient
Python (schemes.btc)Client, Server, FacilitatorClient, Server
Java (io.t402.schemes.btc)Client, Server, FacilitatorClient, Facilitator

Server-Side Route Configuration

Go Server with Bitcoin

routes := t402http.RoutesConfig{
    "GET /api/data": {
        Accepts: t402http.PaymentOptions{
            {Scheme: "exact", PayTo: "bc1q...", Price: "10000", Network: btc.BtcMainnetCAIP2},
        },
        Description: "Data endpoint accepting BTC",
        MimeType:    "application/json",
    },
}
⚠️

Bitcoin amounts are specified in satoshis (1 BTC = 100,000,000 satoshis). The minimum payment amount is 546 satoshis (dust limit).

Accepting Both BTC and EVM

routes := t402http.RoutesConfig{
    "GET /api/data": {
        Accepts: t402http.PaymentOptions{
            {Scheme: "exact", PayTo: "bc1q...", Price: "10000", Network: btc.BtcMainnetCAIP2},
            {Scheme: "exact", PayTo: "0x...", Price: "$0.01", Network: "eip155:8453"},
        },
    },
}