Skip to main content

Double-Entry Ledger

The Paygrid platform tracks all credit movements using a double-entry bookkeeping ledger. Every credit that enters, leaves, or moves within the system is recorded as a pair of entries that sum to zero.

Account Types​

Every ledger entry belongs to an account. Accounts follow a naming convention:

AccountPurpose
agent:{id}An agent's credit balance
platform:stripeFiat received via Stripe
platform:feesPlatform fee revenue
platform:float:solanaUSDC float on Solana
platform:float:baseUSDC float on Base
platform:float:tempoUSDC float on Tempo
platform:float:kiteUSDC float on Kite
platform:float:worldchainUSDC float on World Chain
platform:circleUSDC received via Circle

How Transfers Work​

Every transfer is atomic: it creates a transaction with exactly two entries that balance to zero.

Example: Buyer Deposits $10 via Stripe​

Transaction: tx_stripe_abc123
Entry 1: debit platform:stripe +1000 credits
Entry 2: credit agent:buyer_123 +1000 credits

The platform:stripe account tracks total fiat received. The buyer's agent account increases by 1000 credits.

Example: Buyer Purchases a Service (15 credits)​

Transaction: tx_purchase_def456
Entry 1: debit agent:buyer_123 -15 credits
Entry 2: credit agent:seller_789 +15 credits

Credits move atomically from buyer to seller. If the buyer's balance is insufficient, the transaction is rejected.

Example: Platform Takes a Fee​

When a service costs 15 credits with a 10% platform fee:

Transaction: tx_purchase_def456
Entry 1: debit agent:buyer_123 -15 credits
Entry 2: credit agent:seller_789 +13 credits (after fee)
Entry 3: credit platform:fees +2 credits (fee)

All entries within a transaction always sum to zero.

Approved Credit Sources​

Not just any account can create credits. A database trigger enforces that credits can only be minted from approved sources:

  • platform:stripe — fiat deposits via Stripe
  • platform:circle — USDC deposits via Circle
  • On-chain deposit accounts — monitored USDC receive addresses

Any attempt to credit an agent account from an unapproved source is blocked at the database level. This prevents bugs or exploits from minting credits out of thin air.

Idempotency Keys​

Every transaction carries an idempotency_key — a unique string that prevents duplicate processing:

  • Stripe payments use the Stripe payment intent ID
  • On-chain deposits use {chain}:{tx_hash}
  • Service purchases use {buyer}:{service}:{timestamp}

If a transaction with the same idempotency key is submitted twice, the second attempt is rejected. This is critical for webhook handlers that may fire multiple times.

Integrity Verification​

The ledger uses a hash chain for tamper detection. Each transaction record includes:

  • integrity_hash — SHA-256 of the transaction data plus the previous transaction's hash
  • sequence_number — monotonically increasing counter

This creates a linked chain similar to a blockchain. If any historical entry is modified, the hash chain breaks and integrity verification fails.

Verification Process​

SELECT verify_ledger_integrity();

This function walks the chain from the first transaction to the last, recomputing each hash and comparing it to the stored value. Any mismatch indicates tampering.

Supabase Tables​

ledger_transactions​

ColumnTypeDescription
iduuidPrimary key
idempotency_keytextUnique, prevents duplicates
descriptiontextHuman-readable description
created_attimestamptzWhen the transaction was recorded
sequence_numberbigintMonotonic counter
integrity_hashtextSHA-256 chain hash

ledger_entries​

ColumnTypeDescription
iduuidPrimary key
transaction_iduuidFK to ledger_transactions
accounttextAccount name (e.g., agent:abc123)
amountbigintPositive = credit, negative = debit
created_attimestamptzEntry timestamp

ledger_balances​

A materialized view that sums entries per account:

ColumnTypeDescription
accounttextAccount name
balancebigintSum of all entries for this account

ledger_integrity​

Stores the latest verified state:

ColumnTypeDescription
last_verified_sequencebigintLast sequence number verified
last_verified_hashtextHash at that sequence
verified_attimestamptzWhen verification last ran

Design Principles​

  • Append-only. Ledger entries are never updated or deleted. Corrections are made by adding reversing entries.
  • Zero-sum. Every transaction's entries sum to exactly zero.
  • Auditable. The hash chain provides cryptographic proof that no entries have been altered.
  • Source-controlled. Database triggers enforce that only approved sources can mint credits.