The Finance module handles money owed to people who use your platform. When a customer buys a product on your storefront, when an affiliate earns a commission, when a creator gets a tip — Finance tracks the balance, holds the funds, and pays them out. It is deliberately narrower than the Banking module, which is a full banking-as-a-service stack.
What Finance owns
- Wallets — a per-recipient balance. Owned by a customer, an affiliate, or any addressable principal. Tracks available, pending, and held funds.
- Transactions — the ledger of credits and debits against each wallet. Earnings, tips, commissions, refunds, fees, payouts.
- Payouts — moving wallet funds out to a real-world destination (bank, PayPal, Venmo, Cash App, debit card, crypto).
- Payout methods — saved destinations a wallet owner has registered.
- Payment methods — the customer-side counterpart: cards on file used to take payment in. Tokenised through Stripe.
- Platform fees — the cut your platform keeps on every gross transaction before crediting the recipient.
- Payment actions —
charge,authorize,capture,refund,void,verify,cancel— routed to the configured payment provider.
Surface
Three controllers cover the module:
| Controller | Path | Audience |
|---|---|---|
PayoutController | /finance/* | Staff (User role). Wallet admin, payout approval, batch runs. |
PaymentController | /finance/payments/* | Server-to-server. Payment-action gateway (charge, refund, capture). |
FinanceClientController | /client/finance/* | Customers. Wallet self-service, payout requests, payout-method CRUD. |
/client/finance is the surface a creator dashboard or seller portal calls. /finance is what an admin console calls.
Finance vs Banking
The two modules look related but solve different problems.
| Finance | Banking | |
|---|---|---|
| Holds money? | No (logical balance only) | Yes (real bank accounts via SponsorBankProvider) |
| Issues cards? | No | Yes (virtual + physical) |
| Runs ACH/Wire/RTP? | No (delegates to providers) | Yes (direct rail integration) |
| KYC/KYB required? | No | Yes (before account activation) |
| Use case | Pay out marketplace earnings | Operate a neobank or treasury product |
If you only need to pay creators, sellers, or affiliates from gross sales, Finance is enough. If you need to hold customer deposits, issue cards, or run a regulated banking product, you want Banking.
Auth and tenancy
All endpoints require the orgid header. Staff endpoints under /finance/* are gated to RoleType.User (see payout.controller.ts). Customer-facing endpoints under /client/finance/* resolve the principal via @CurrentCustomerOrUser() and scope every read and write to customer.sk. The wallet a customer sees is always their own — even if they pass another walletId, ownership is checked before the response.
Typical flow
- 1
Create a wallet on first earning
When a customer first earns money (sale, tip, commission), call
POST /finance/wallets/get-or-createwithownerType: "customer"andownerId: <customer.sk>. Idempotent. - 2
Credit the wallet
POST /finance/wallets/:walletId/creditwithtype: "earning" | "tip" | "bonus" | "commission" | "referral" | "refund" | "adjustment"and the gross amount. Platform fees are deducted before credit, not after. - 3
Customer requests payout
The customer calls
POST /client/finance/payouts/requestfrom your dashboard. They optionally specify a savedmethodId; otherwise the default method is used. - 4
Staff approves and processes
A staff user (or automation) approves with
POST /finance/payouts/:payoutId/approve, thenPOST /finance/payouts/:payoutId/processto send the funds, thenPOST /finance/payouts/:payoutId/completeonce the external rail confirms.
The next pages walk through each of these surfaces in detail.