Documentation

Platform fees and revenue splits

How the platform takes a cut of every gross transaction before crediting recipients.

A platform fee is the slice you keep before crediting a wallet. On a $100 sale with a 10% platform fee, the seller's wallet is credited $90 and $10 stays on the platform's books. Finance does not enforce a single fee model; it gives you the primitives — credit, debit, hold, and a fee transaction type — and you compose your splits on top.

Where fees come from

Fees are computed by your application layer (or an Automation flow), not by the Finance module itself. The module records the resulting numbers. Three patterns cover almost every case:

Net credit

The simplest. Compute fee on your side, credit the net to the seller's wallet.

const gross = order.total;        // 100.00
const fee   = gross * 0.10;        // 10.00
const net   = gross - fee;         // 90.00

// Credit only the net.
await fetch(`/finance/wallets/${sellerWalletId}/credit`, {
  method: 'POST',
  body: JSON.stringify({
    amount: net,
    type: 'earning',
    reference: order.id,
    description: `Order ${order.id} — net of 10% platform fee`,
  }),
});

The fee is implicit in the difference between the gross payment received and the net credited. Reconciliation looks at gateway_amount - wallet_credit = platform_fee.

Credit gross then debit fee

When you want the audit trail to show the gross earning explicitly:

// 1. Credit the gross.
await credit({ amount: gross, type: 'earning', reference: order.id });

// 2. Debit the platform fee.
await debit({ amount: fee, type: 'fee', reference: order.id, description: '10% platform fee' });

Two transactions per sale, but the wallet history reads cleanly: "Earned $100 / Platform fee –$10".

Multi-recipient split

For a marketplace where a single payment splits across multiple wallets — seller, affiliate, platform — credit each wallet in turn.

// $100 total: seller 70, affiliate 20, platform 10.
await credit({ walletId: sellerWallet,    amount: 70.00, type: 'earning',    reference: order.id });
await credit({ walletId: affiliateWallet, amount: 20.00, type: 'commission', reference: order.id });
// Platform's $10 is recorded on the platform's own ledger, not on a wallet.

The platform's cut typically lives outside the wallet system — on your accounting books or in a dedicated platform wallet you treat as a sink.

Fee transaction type

When debiting a wallet for a fee:

POST/finance/wallets/{walletId}/debitJWT
{
  "amount": 5.00,
  "type": "fee",
  "reference": "month-2026-04",
  "description": "Monthly account fee"
}

type: "fee" is its own bucket — separate from payout, chargeback, and adjustment — which keeps fee revenue cleanly aggregable.

Fee schedules

Three common cadences for charging fees:

CadencePattern
Per-transactionApply on every sale. Use credit gross + debit fee or net-credit.
Per-periodMonthly account fee, billed via a single type: "fee" debit on a schedule.
Per-payoutCharged when the customer requests a payout — debit type: "fee" immediately before processing the payout.

For per-period and per-payout fees, an Automation flow is the right home — schedule the debit, log the result, and surface failures.

Tiered platform fees

To vary fee % by seller tier, store the rate on the seller's record and read it before crediting:

const seller = await getCustomer(sellerId);
const rate = seller.data.platformFeeRate ?? 0.10;
const fee = gross * rate;
const net = gross - fee;

There is no built-in "fee schedule" object in Finance — keep the rate on the principal record (or in your org config) and resolve it at credit time.

Charges, captures, and refunds

The other side of the split is the inbound payment. When a customer pays $100 for an order, that gross arrives via the payment processor (typically Stripe). Finance exposes a payment-action gateway:

POST/finance/payments/chargeJWT
POST/finance/payments/authorizeJWT
POST/finance/payments/captureJWT
POST/finance/payments/refundJWT
POST/finance/payments/voidJWT

Each routes to the configured payment provider via the upstream service. The body shape depends on the provider — Stripe needs a paymentIntentId, PayPal needs an order ID. The action is recorded; the wallet is not automatically credited. Your application layer reads the gateway response and posts the corresponding wallet credits and fee debits.

Refunds

Refunds reverse both sides of the split. Credit gross + debit fee inverts to debit gross + credit fee:

// Original sale: gross 100, fee 10, net 90 to seller.
// On refund:
await refundOnGateway({ paymentRef: order.paymentRef, amount: 100.00 });

// Reverse the seller's earning.
await debit({ walletId: sellerWallet, amount: 90.00, type: 'chargeback', reference: order.id });

// Reverse the platform's fee revenue.
await credit({ walletId: platformWallet, amount: -10.00, type: 'adjustment', reference: order.id });

(Or post a fee-reversal adjustment, depending on your reporting needs.)

Reporting on fees

To compute fee revenue for a period:

  1. Read the wallet records for any platform-style sink wallet, sum credits.
  2. Or, scan all wallets and sum debits with type: "fee" over the period.

Both approaches work because fees and earnings are separate transaction types. There is no dedicated /finance/fees reporting endpoint — fees are just typed transactions.

For tax handling, treat platform fees as the platform's gross revenue and tax accordingly on your side. Finance does not compute or remit tax.