Skip to main content

Wallet Architecture Overview

System Components

Core Services

Wallet Account Service

Manages wallet lifecycle and balance operations:

  • Account creation and activation
  • Balance queries
  • Transaction posting
  • Balance reconciliation

Auto Top-Up Worker

BullMQ worker for scheduled and threshold-based top-ups:

  • Monitors balance thresholds
  • Triggers payment collection
  • Handles failure retry logic
  • Emits outbox events for notifications

Pass Provider Service

Apple Wallet and Google Wallet integration:

  • Pass template management
  • Pass generation and signing
  • Push updates for balance changes
  • Pass analytics tracking

API Layers

Portal API

Member-facing endpoints (/portal/wallet/*):

  • GET /balance - Current balance
  • POST /top-up - Initiate manual top-up
  • GET /transactions - Transaction history
  • POST /auto-top-up - Configure auto top-up
  • GET /pass - Generate digital card

Admin API

Staff-facing endpoints (/admin/wallet/*):

  • GET /accounts - List all wallets (with filtering)
  • GET /analytics - Cohort analytics
  • POST /credit - Manual credit/debit
  • POST /reconcile - Trigger reconciliation

Webhook API

External integration endpoints:

  • Payment processor callbacks
  • Pass event webhooks
  • Subscription lifecycle events

Data Model

Primary Entities

model WalletAccount {
id String @id @default(uuid())
memberId String
tenantId String
currency String @default("ZAR")
balance Int @default(0) // cents
status WalletStatus
createdAt DateTime
updatedAt DateTime

transactions WalletTransaction[]
autoTopUp AutoTopUpConfig?
passes WalletPass[]
}

model WalletTransaction {
id String @id @default(uuid())
walletId String
type TransactionType
amount Int // cents (positive = credit)
balanceAfter Int
reference String?
description String?
merchantCode String?
postedAt DateTime
}

model AutoTopUpConfig {
id String @id @default(uuid())
walletId String @unique
enabled Boolean @default(false)
type AutoTopUpType // THRESHOLD, SCHEDULED
threshold Int? // cents
amount Int // cents
schedule String? // cron expression
mandateRef String? // stored payment method
}

Event System

Wallet uses the outbox pattern for reliable event publishing:

Transaction Posted

Insert to wallet_outbox

Outbox Poller claims entry

Process event (notifications, pass updates)

Mark entry complete

Outbox entry types:

  • transaction.posted - New transaction recorded
  • status_changed - Wallet status updated
  • auto_topup.scheduled - Auto top-up scheduled
  • auto_topup.failed - Auto top-up charge failed

Integration Points

Payment System

  • Top-up initiation → Checkout session creation
  • Webhook processing → Transaction posting
  • Mandate storage → Auto top-up execution

Notification System

  • Outbox events → Notification handlers
  • Handler → Channel resolution (email, WhatsApp, SMS, push)
  • Preference gating → Final delivery

Pass Providers

  • Apple Wallet: PKPass generation, APNS push
  • Google Wallet: Google Pay API integration
  • Balance sync: Periodic and event-driven updates

Security Considerations

Access Control

  • Portal endpoints: Member authentication + ownership check
  • Admin endpoints: Staff authentication + permission check
  • Webhook endpoints: Signature verification

Data Protection

  • All amounts stored in cents (integers)
  • Transaction history immutable
  • Audit trail for admin operations
  • PCI compliance for payment references (no raw card data)

Scaling Considerations

Performance

  • Balance queries cached with short TTL
  • Transaction history paginated
  • Analytics queries run on read replicas

Reliability

  • Outbox pattern ensures at-least-once delivery
  • Idempotent transaction posting
  • Distributed locks for auto top-up execution