---
title: "Record every money movement in an · Agent Wranglers"
url: https://agentwranglers.se/playbook/payments/payment-events-and-reconciliation/payment-ledger
updated: 2026-10-20
licence: "All rights reserved"
---

# Record every money movement in an append-only ledger

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Required
- Chapter: [Payment events and reconciliation](https://agentwranglers.se/playbook/payments/payment-events-and-reconciliation)
- Rule: Write each charge, refund, fee, dispute and payout as a new ledger row with the provider's object ID, and never update or delete a row.
- How: Each row holds the time, type, signed amount in minor units, currency, order ID and provider object ID. A unique constraint on the provider ID stops double entries. Corrections are new rows that reverse old ones. Balances are sums of rows. Give the app's database role only INSERT and SELECT on the ledger.
- Check: As the app role, run an UPDATE and a DELETE on the ledger. Both fail with permission denied. For every order, the sum of its charge and refund rows equals the paid amount minus refunds on the order.

Example:

```sql
CREATE TABLE ledger_entries (
  id           bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  occurred_at  timestamptz NOT NULL,
  entry_type   text NOT NULL CHECK (entry_type IN ('charge', 'refund', 'fee', 'dispute', 'dispute_reversal', 'payout', 'adjustment')),
  amount_minor bigint NOT NULL,
  currency     char(3) NOT NULL,
  order_id     text,
  provider_id  text NOT NULL UNIQUE
);
GRANT SELECT, INSERT ON ledger_entries TO app_role;
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers payments playbook: https://agentwranglers.se/playbook/payments/payment-events-and-reconciliation/payment-ledger`.

- Previous: [Sweep for missed events every hour](https://agentwranglers.se/playbook/payments/payment-events-and-reconciliation/missed-event-sweep)
- Next: [Reconcile every payout](https://agentwranglers.se/playbook/payments/payment-events-and-reconciliation/payout-reconciliation)
- [Payment events and reconciliation](https://agentwranglers.se/playbook/payments/payment-events-and-reconciliation)
