Payment Checkout & Ledger Service  ·  View 12 of 24  ·  Data

Ledger and Payment Data Model

Twelve entities, and the one unique constraint that makes posting exactly-once without coordination.

Editable source SVG draw.io All views
merchant merchant_id PK risk_tier hold_period_days payout_schedule settlement_account payment_intent payment_id PK merchant_id FK idempotency_key UQ amount_minor int currency state expires_at payment_attempt attempt_id PK payment_id FK provider_id FK policy_version result enum provider_code provider_ref provider provider_id PK rail enum supports_void bool supports_inquiry bool fee_schedule payout payout_id PK merchant_id FK instruction_key UQ amount_minor state bank_ref payment_event event_id PK payment_id FK seq int monotonic type source enum payload_ref dispute dispute_id PK attempt_id FK payment_id FK reason_code state liability enum settlement_line line_id PK provider_id FK provider_ref amount_minor match_state enum txn_id FK null refund refund_id PK payment_id FK amount_minor state reverses_txn_id FK ledger_transaction txn_id PK event_id UQ natural key posting_rule_version booked_at period ledger_entry entry_id PK txn_id FK account_id FK amount_minor signed currency sum per txn = 0 account account_id PK owner_type enum owner_id class enum currency 1 : N 1 : N 1 : N 1 : N 1 : N 1 : 0..N 1 : N 1 : 0..1 1 : 2..N 1 : N reverses Ledger and Payment Data Model ledger_transaction.event_id is unique: the event's identity is the natural key, which is what makes posting exactly-once. Foreign keys carry the links the view does not draw — every object holds payment_id. v 1.0 · owner Payments Platform Architecture · date 2026-10

The load-bearing constraint

  • `ledger_transaction.event_id` is unique. The event's own identity is the natural key of the transaction, so replaying the log cannot double-post and the poster needs no distributed coordination (ADR-03).
  • `ledger_entry.amount_minor` is a signed integer and the entries of a transaction sum to zero, enforced at write time (ADR-02).

Decisions

  • `payment_attempt` carries `policy_version` and the raw `provider_code` alongside the normalised result — the reproducibility requirement from ADR-06.
  • `refund` references `reverses_txn_id`: a refund is a new transaction pointing at the original, never a reduction of it.
  • `settlement_line.txn_id` is nullable. A line with no transaction is the break, and it is a row rather than a gap (ADR-07).

Not drawn

  • Foreign keys carry the links the diagram does not draw — every object holds `payment_id`.
  • The account tree, posting-rule versions, FX rates and the operator audit log are omitted; they are reference and evidence rather than payment structure.