Overview
Polar’s financial architecture is split across two distinct entities:| Entity | Table | Purpose | Required? |
|---|---|---|---|
Account | accounts | Financial ledger — holds all transactions for an entity | Mandatory — every org has exactly one |
PayoutAccount | payout_accounts | Payout configuration — holds Stripe Connect or manual bank details | Optional — created when the merchant is ready to receive payouts |
- Transaction history is never lost when a merchant changes their payout processor.
- Multiple organisations can share a single
PayoutAccount(e.g. a company with several Polar orgs pointing to one Stripe Connect account). - Accounts are created immediately on org creation — no held balances, no pending state.
Account Model
server/polar/models/account.py · table accounts
The Account is a pure financial ledger. It has no Stripe credentials and no payout configuration. Its only job is to track money flowing in and out.
Key fields
Fee calculation
settings.PLATFORM_FEE_BASIS_POINTS / settings.PLATFORM_FEE_FIXED when the per-account overrides are None.
Credit balance
credit_balance is not the merchant’s earned revenue balance. It tracks promotional fee credits explicitly granted by Polar (manually by an admin, or via a campaign). Each credit is stored as an AccountCredit row; credit_balance is a denormalized running sum for fast reads.
Credits are consumed against platform fees at payment time (not at payout):
Credits are reduced in two cases:
- Applied to a fee —
account.reduce_credit_balance(amount_applied)after consumingAccountCreditrows - Revoked by admin —
account.reduce_credit_balance(credit.amount)immediately
reduce_credit_balance(amount) subtracts min(amount, credit_balance), flooring at zero.
PayoutAccount Model
server/polar/models/payout_account.py · table payout_accounts
The PayoutAccount holds all payout processor configuration. It is decoupled from the financial ledger so it can be swapped independently.
Types
| Type | Description |
|---|---|
stripe | Stripe Connect Express account |
manual | Backoffice-managed; always considered payout-ready |
Key fields
Payout readiness
is_payouts_enabled=True.
Organization Relationships
server/polar/models/organization.py
unique=True on account_id enforces the 1-to-1 constraint at the DB level. payout_account_id has no unique constraint — multiple orgs can share a single PayoutAccount.
Transaction Model
server/polar/models/transaction.py · table transactions
account_id IS NOT NULL→ transaction belongs to a specific merchantAccountaccount_id IS NULL→ transaction is Polar’s own (e.g. collected fees, outgoing transfers)
payment, processor_fee, refund, refund_reversal, dispute, dispute_reversal, balance, payout, payout_reversal
The future goal is to extend Account to represent customers and Polar subsidiaries too, enabling the full money trail to be traced in a single table:
Payout Model
server/polar/models/payout.py · table payouts
A Payout links both entities, representing the transfer of funds from the merchant’s ledger to their payout processor.

