Skip to content

Ledger

What is the ledger?

The ledger is an immutable, append-only log of every payment attempt made through PQSafe AgentPay. It records:

  • The envelope used (hash, not full content)
  • The payment request (amount, recipient, rail)
  • The outcome (settled, failed, pending)
  • The ML-DSA-65 signature fingerprint
  • Timestamps

The ledger is the primary audit mechanism for autonomous agent payments.

Ledger record structure

interface LedgerRecord {
// Identity
id: string // UUID v4
envelopeId: string // From signed envelope
agentId: string // From envelope
// Payment
amount: number
currency: string
recipient: string
rail: string
// Outcome
status: 'settled' | 'pending' | 'failed' | 'rejected'
txId?: string // Rail transaction ID (when settled)
failureReason?: string
// Cryptographic anchoring
envelopeHash: string // SHA-256 of canonical envelope JSON
sigFingerprint: string // First 16 bytes of ML-DSA-65 signature
// Timestamps
submittedAt: Date
settledAt?: Date
// Chain anchor (optional — Sprint 3)
arbitrumTxHash?: string
}

Writing to the ledger

The SDK writes to the ledger automatically when you call executeAgentPayment(). You can also write manually:

import { buildLedgerRecord, submitToLedger } from '@pqsafe/agent-pay'
const record = buildLedgerRecord(signedEnvelope, paymentResult)
const entry = await submitToLedger(record)
console.log('Ledger entry ID:', entry.id)
console.log('Hash:', entry.hash) // Hash chain — each entry includes hash of previous
console.log('Sequence:', entry.sequence)

Hash chain integrity

Each ledger entry includes the hash of the previous entry, forming a chain:

entry[0]: hash = H(content[0])
entry[1]: hash = H(content[1] + entry[0].hash)
entry[2]: hash = H(content[2] + entry[1].hash)

Tampering with any entry invalidates all subsequent hashes. You can verify the chain:

import { verifyLedgerChain } from '@pqsafe/agent-pay'
const entries = await getLedgerEntries({ agentId: 'my-agent' })
const isIntact = verifyLedgerChain(entries)
console.log('Chain intact:', isIntact) // true

On-chain anchoring (Arbitrum)

For high-value payments or regulatory compliance, PQSafe can anchor ledger entries on Arbitrum:

import { commitEnvelopeToArbitrum } from '@pqsafe/agent-pay'
const { txHash } = await commitEnvelopeToArbitrum(signedEnvelope, {
rpcUrl: process.env.ARBITRUM_RPC_URL!,
privateKey: process.env.WALLET_PRIVATE_KEY!,
})
console.log('On-chain proof:', txHash)

Querying the ledger

import { getLedgerEntries } from '@pqsafe/agent-pay'
const entries = await getLedgerEntries({
agentId: 'procurement-agent',
fromDate: new Date('2026-01-01'),
status: 'settled',
limit: 100,
})
const total = entries.reduce((sum, e) => sum + e.amount, 0)
console.log(`Total settled: $${total}`)