Payout account
Every seller that wants to receive funds needs a PayoutAccount. This account is the central entity that links a seller to their financial balance and to an external payment provider (e.g. Stripe Connect).Account lifecycle
| Status | Description |
|---|---|
PENDING | Account created, awaiting provider onboarding |
ACTIVE | Fully onboarded, can receive payouts |
RESTRICTED | Provider has flagged the account (e.g. missing KYC) |
REJECTED | Provider rejected the account |
Onboarding
When a payout account is created, an Onboarding record is attached to it. This stores provider-specific data needed for identity verification or account setup (e.g. Stripe Connect onboarding links). The onboarding data is merged with the account data before being sent to the provider.Payout account creation uses idempotency keys to prevent duplicate accounts if the request is retried.
Balance tracking
Each payout account maintains a PayoutBalance per currency. The balance is updated automatically when transactions are added or removed. Balances are stored with dual precision:balance— Display value for UIraw_balance— High-precision value (string with 20-digit precision) for accurate financial calculations
BigNumber arithmetic to avoid floating-point errors.
Transactions
A PayoutTransaction represents a credit or debit against a seller’s payout account. Transactions are the building blocks of the balance — every balance change is backed by a transaction record. Each transaction stores:| Field | Description |
|---|---|
amount | The transaction amount |
currency_code | Currency of the transaction |
reference | Type of source (e.g. "order") |
reference_id | ID of the source entity |
Balance updates use
SERIALIZABLE transaction isolation to prevent race conditions when multiple orders are credited simultaneously.The payout pipeline
Crediting an order
When an order is completed, thecreditOrderToPayoutAccountWorkflow calculates the seller’s earnings and credits their account:
- Fetch order — Loads the order with its items, commission lines, and seller’s payout account
- Validate account — Confirms the seller has a linked payout account
- Calculate net earnings — Sums commission amounts across all items and subtracts from the order total:
- Create transaction — Records a
PayoutTransactionwithreference: "order"pointing to the order ID - Update balance — Adds the transaction amount to the seller’s
PayoutBalancefor that currency
Processing payouts
TheprocessPayoutWorkflow handles webhook events from the external payment provider. It uses conditional branching to update the correct entity:
Account events:
account.activated→ Status set toACTIVEaccount.restricted→ Status set toRESTRICTEDaccount.rejected→ Status set toREJECTED
payout.processing→ Status set toPROCESSINGpayout.paid→ Status set toPAIDpayout.failed→ Status set toFAILEDpayout.canceled→ Status set toCANCELED
Payout validation
Before a payout is initiated, the system validates:- The account status is
ACTIVE - The account has sufficient balance in the requested currency
Data model overview
Provider abstraction
The payout module is provider-agnostic. APayoutProviderService acts as a bridge to the external payment processor. It delegates all external operations — creating accounts, processing payouts, parsing webhooks — to a pluggable provider implementation.
The module expects exactly one payout provider to be registered. Provider-specific data is stored in the data JSON fields on accounts, payouts, and onboarding records.