Skip to main content

Overview

Polar’s financial architecture is split across two distinct entities: This separation means:
  • 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

Falls back to 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 feeaccount.reduce_credit_balance(amount_applied) after consuming AccountCredit rows
  • Revoked by adminaccount.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

Key fields

Payout readiness

Manual accounts are always ready. Stripe accounts require 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 merchant Account
  • account_id IS NULL → transaction is Polar’s own (e.g. collected fees, outgoing transfers)
Transaction types: 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.