Every time money moves in OwnPay - a customer pays, a gateway deducts fees, a refund is issued - the system records it as a pair of balanced journal entries. This is double-entry bookkeeping, the same method used by accounting software and banks. It means you can always trace where money came from and where it went, and the total debits always equal the total credits.
How double-entry works in OwnPay
When a $100 payment completes through Stripe (with a $2.90 gateway fee), OwnPay creates four ledger entries across three accounts:
The net effect: $100.00 credit = $97.10 debit + $2.90 debit. The books balance to zero.
Account types
OwnPay uses standard GAAP account categories:
Balance calculation
All monetary math uses PHP’s bcmath extension - never floating-point arithmetic. Balances are validated at 4-decimal precision using bccomp().
Never manually update the op_ledger_accounts.balance column. Always use LedgerService - direct SQL edits will cause reconciliation mismatches.
Double-post prevention
OwnPay guards against recording the same payment twice. Before inserting ledger entries, the system acquires a row lock:
If a matching row exists, the operation is skipped. This runs inside a database transaction, so concurrent requests are serialized safely.
Brand isolation
Ledger accounts are scoped to a merchant_id (brand). Brand A’s cash balance is completely independent of Brand B’s. The repository enforces this at the query level:
Reconciliation
You can verify your ledger balances against gateway settlements at any time. OwnPay includes a CLI reconciliation command:
This compares OwnPay’s recorded transactions against the gateway’s reported totals and flags any discrepancies. For the GUI-based version, see the Balance Verification page in the admin dashboard.
Related pages