Examples/Fintech
Wallet and payments ledger (example)
A mobile wallet with P2P transfers, card top-ups and bank payouts. Every movement posts to a double-entry ledger in Postgres; a transactional outbox feeds Kafka, merchant webhooks and a daily reconciliation against settlement files. Replace any part with how your own system works.
Scale: 1.5M wallets; 80 transfers/s at peak; daily settlement files
Select a component to see what it is responsible for and which state it owns.
- 1Mobile wallet → Payments API: Send money
- 2Payments API → Risk service: Risk check
- 3Payments API → Ledger service: Post entries
- 4Ledger service → Postgres: Write journal
- 5Payments API → Card processor: Charge card
- 6Card processor → Payments API: Processor webhooks
- 7Payments API → Bank partner: Send payout
- 8Outbox relay → Postgres: Read outbox
- 9Outbox relay → Kafka: Publish entries
- 10Webhook worker → Kafka: Consume events
- 11Webhook worker → Merchant endpoints: Deliver webhooks
- 12Reconciliation job → Settlement files: Read settlement files
- 13Reconciliation job → Postgres: Compare with journal
- Request / response
- Asynchronous
- Bulk data
Select a part to trace its flows.
- Request / response
- Asynchronous
- Bulk data
Parts 13
Flows 13
- 1Mobile wallet → Payments APISend moneyRequest / response
- 2Payments API → Risk serviceRisk checkRequest / response
- 3Payments API → Ledger servicePost entriesRequest / response
- 4Ledger service → PostgresWrite journalRequest / response
- 5Payments API → Card processorCharge cardRequest / response
- 6Card processor → Payments APIProcessor webhooksAsynchronous
- 7Payments API → Bank partnerSend payoutRequest / response
- 8Outbox relay → PostgresRead outboxRequest / response
- 9Outbox relay → KafkaPublish entriesAsynchronous
- 10Webhook worker → KafkaConsume eventsRequest / response
- 11Webhook worker → Merchant endpointsDeliver webhooksAsynchronous
- 12Reconciliation job → Settlement filesRead settlement filesBulk data
- 13Reconciliation job → PostgresCompare with journalRequest / response
Invariants 4
Every journal transaction sums to zero
Posting function inserts all legs and checks SUM(amount) = 0 before commit; a deferred constraint trigger rejects unbalanced transactions.
Kept by
A wallet balance never goes negative
SELECT … FOR UPDATE on the account row, check, then post in the same transaction.
Kept by
A retried transfer posts once
Idempotency-Key stored with request hash and response in the posting transaction; a replay returns the stored response; a different body with the same key is rejected.
Kept by
Ledger matches settlement files daily
Unique constraint on journal_entries(external_ref) makes each settlement line match at most one entry; the daily job writes mismatches to an exceptions queue for operations.
Kept by