Sandbox version
For experimental use only. Proceed with caution.
Tutorials
Subscribe to Account Events
Listen for transactions affecting a specific XRPL account in real time, with reconnect-safe subscription bookkeeping.

This tutorial builds a small worker that watches one or more accounts for incoming transactions and prints a summary. It's the foundation for things like payment notifications, audit logs, and on-chain webhook relays.

1. Scaffold the worker
##
TypeScript
import { Client } from 'xrpl'

const client = new Client('wss://honeycluster.io')

const WATCH: string[] = [
  'rExampleAccountAddressXXXXXXXXXXX',
]

async function main() {
  await client.connect()
  await subscribe(WATCH)

  client.on('transaction', handleTransaction)

  // Re-subscribe after automatic reconnection.
  client.on('connected', () => subscribe(WATCH))
}

main().catch((err) => {
  console.error(err)
  process.exit(1)
})
2. Wire the subscribe helper
##
TypeScript
async function subscribe(accounts: string[]) {
  if (accounts.length === 0) return
  await client.request({ command: 'subscribe', accounts })
  console.log(`watching ${accounts.length} account(s)`)
}

Keeping subscribe as a standalone function means the connected listener can re-send the subscription after reconnects — the upstream doesn't persist subscriptions across connection drops.

3. Handle incoming transactions
##
TypeScript
function handleTransaction(event: any) {
  const tx = event.transaction
  if (!tx) return

  const amount =
    typeof tx.Amount === 'string' ? `${Number(tx.Amount) / 1_000_000} XRP` : tx.Amount

  console.log(
    new Date(event.engine_result_code ? Date.now() : Date.now()).toISOString(),
    tx.TransactionType,
    tx.Account,
    '→',
    'Destination' in tx ? tx.Destination : '—',
    amount ?? ''
  )
}
4. Add and remove accounts dynamically
##

A production worker rarely watches a fixed list. Expose an HTTP endpoint (or a queue consumer) that calls subscribe / unsubscribe to mutate the active set:

TypeScript
const watched = new Set<string>(WATCH)

async function watch(address: string) {
  if (watched.has(address)) return
  watched.add(address)
  await client.request({ command: 'subscribe', accounts: [address] })
}

async function unwatch(address: string) {
  if (!watched.delete(address)) return
  await client.request({ command: 'unsubscribe', accounts: [address] })
}

Persist watched to Redis or Postgres if the worker needs to survive pod restarts — on recovery, re-hydrate the set and resubscribe before processing new events.

5. Graceful shutdown
##
TypeScript
process.on('SIGTERM', async () => {
  await client.disconnect()
  process.exit(0)
})

Disconnecting cleanly emits a close frame upstream so regional-proxy resources are freed immediately, and lets downstream monitoring systems distinguish graceful shutdowns from crashes.