Remittance Getting Started
This guide introduces the remittance subsystem and shows how to wire a maker and taker together using RemittanceManager, CommsLayer, and a module such as Brc29RemittanceModule. Identity verification is manager-managed, not module-managed, and it is always acknowledged before proceeding.
Concepts
- RemittanceManager orchestrates threads, identity exchange, transport, and receipts.
- RemittanceModule builds/accepts settlement artifacts for a specific payment method.
- CommsLayer delivers protocol envelopes (store-and-forward and/or live).
- IdentityLayer handles certificate requests, responses, and acknowledgment.
- ThreadHandle gives you waiters (
waitForState,waitForSettlement,waitForReceipt) for streaming or async flows.
Sequence: Invoice to Receipt
sequenceDiagram
participant Maker
participant Comms
participant Taker
Maker->>Comms: invoice envelope
Comms->>Taker: invoice envelope
Taker->>Taker: build settlement via module
Taker->>Comms: settlement envelope
Comms->>Maker: settlement envelope
Maker->>Maker: accept settlement via module
Maker->>Comms: receipt envelope (optional)
Comms->>Taker: receipt envelope
Sequence: Identity Exchange (when enabled)
sequenceDiagram
participant Initiator
participant Comms
participant Counterparty
Initiator->>Comms: identityVerificationRequest
Comms->>Counterparty: identityVerificationRequest
Counterparty->>Comms: identityVerificationResponse
Comms->>Initiator: identityVerificationResponse
Initiator->>Comms: identityVerificationAcknowledgment
Comms->>Counterparty: identityVerificationAcknowledgment
Identity acknowledgment is required before invoicing/settlement proceeds when configured.
Basic Setup
import { WalletClient, RemittanceManager, Brc29RemittanceModule } from '@bsv/sdk'
import { MessageBoxClient, MessageBoxAdapter } from '@bsv/message-box-client'
const wallet = new WalletClient('auto', 'localhost')
const messageBoxClient = new MessageBoxClient({
walletClient: wallet
})
const commsLayer = new MessageBoxAdapter(messageBoxClient)
const brc29Module = new Brc29RemittanceModule()
const manager = new RemittanceManager(
{
messageBox: 'direct_payment_test',
remittanceModules: [brc29Module],
options: {
receiptProvided: false, // Disable receipting
autoIssueReceipt: false,
invoiceExpirySeconds: 3600
},
logger: console
},
wallet,
commsLayer
)
await manager.init()
Sending the Payment (unsolicited settlement)
const threadHandle = await manager.sendUnsolicitedSettlement(
recipient,
{
moduleId: 'brc29.p2pkh',
option: {
amountSatoshis: amountSats,
payee: recipient
},
note: `Direct payment test - ${amountSats} sats`
}
)
Receiving the Payment (unsolicited settlement)
// Payment will automatically be internalized when threads are synced.
await testSyncThreads(manager)
Event Hooks
Use onEvent or the per-event events callbacks to react to each step.
const manager = new RemittanceManager(
{
remittanceModules: [new Brc29RemittanceModule()],
events: {
onStateChanged: (event) => console.log('state', event.previous, '->', event.next),
onSettlementReceived: (event) => console.log('settlement', event.settlement)
}
},
walletInterface,
commsLayer
)
State Machine and Auditing
Threads follow the RemittanceThreadState state machine, and every transition is recorded in thread.stateLog. Use REMITTANCE_STATE_TRANSITIONS to validate transitions or to build a visualizer.
const thread = manager.getThreadOrThrow(threadId)
console.log(thread.state)
console.log(thread.stateLog)
Live / Streaming Mode
If your CommsLayer supports listenForLiveMessages, call:
This keeps state current while you use ThreadHandle.waitForState to await transitions.