Aliquot
Payments

Ledger and splits

How a payment is cut into seller, partner, platform markup and the 0.50 % fee, and how every unit is booked.

Last updated Oct 27, 2026

The fee waterfall

computeFees() (domain/fee-engine.ts) is the only place where amounts are split. It works in the token's integer base units (bigint), never floats, and POST /api/v1/crypto/quote returns exactly what it computes. Every component is a percentage of the base amount (the invoice's USD price), rounded down:

processing fee = base × 50 bps   (CRYPTO_PLATFORM_FEE_BPS, per-org override possible)
markup         = base × markup_percent        (the platform's own cut, 0–20 %)
partner_i      = base × splits[i].percent
fee_payer CUSTOMER: total = base + processing fee + markup;  seller net = base − Σ partners
fee_payer MERCHANT: total = base;                            seller net = base − fee − markup − Σ partners
invariant: seller net + Σ partners + markup + processing fee = total   (the seller absorbs rounding)

The minimum invoice is 1.00 USD; USD maps 1 : 1 to the stablecoin.

Worked example: 90 / 10 / 2 / 0.50

A 100.00 USD license sold by Halden Type on the platform, with Kerning Weekly (a partner) taking 10 %, a 2 % platform markup, and the buyer paying the fees:

{ "amount": "100.00", "fee_payer": "CUSTOMER", "markup_percent": 2,
  "merchant": "halden_type", "splits": [{ "account": "kerning_weekly", "percent": 10 }] }
WhoAmount
Halden Type (seller net)90.00
Kerning Weekly (partner)10.00
Platform markup2.00
Aliquot processing fee (0.50 %)0.50
Buyer pays (total)102.50 USDT

Once the transfer is confirmed, one balanced ledger transaction (invoice:<id>:settlement) books it:

AccountDebitCredit
ASSET:ONCHAIN_CUSTODY:POLYGON_AMOY:USDT102.50
LIABILITY:MERCHANT_SETTLEMENT:<halden_type>:POLYGON_AMOY:USDT90.00
LIABILITY:PARTNER_PAYABLE:<kerning_weekly>:POLYGON_AMOY:USDT10.00
LIABILITY:PARTNER_PAYABLE:<platform>:POLYGON_AMOY:USDT2.00
REVENUE:PLATFORM_PROCESSING_FEE:POLYGON_AMOY:USDT0.50

The checkout's receipt draws the same cut as the split bar (seller · markup · fee; partner shares are not shown to the buyer), and the dashboard's invoice Ledger tab shows these lines with a "Balanced" check. With fee_payer: "MERCHANT" the buyer pays 100.00 and the fee and markup come out of the seller's 90.00 share instead (87.50 net).

An overpayment adds a credit to LIABILITY:REFUND_ESCROW:<invoice> for the excess; see Refunds.

Ledger rules

  • Account code = TYPE:NAME[:holder]:NETWORK:CURRENCY. Every network and token has its own accounts, so balances never mix chains or coins; gas is booked in the native coin (EXPENSE:ONCHAIN_GAS:…:POL).
  • Balances change only through postings built by the factories in domain/ledger.ts (settlement, escrow, sweep, payout lock / complete / release, refund, operator funding). Each has a deterministic idempotency key; re-posting it is a safe replay.
  • The database enforces the books: debits equal credits per transaction, network and currency (a deferred trigger checked at commit), journal rows are append-only, and an account balance can never go below zero (CHECK). An overdraft rolls the whole posting back and surfaces as 409 INSUFFICIENT_BALANCE.
  • The ledger has no foreign keys to organizations: the books must survive a tenant's deletion. Reads are always filtered by organization.

Where the money is on chain

The deposit address receives the payment. The worker's sweep job (every 15 s) moves confirmed deposits to the hot wallet (index 0), topping up the deposit with native gas first; the ledger moves ONCHAIN_CUSTODY → HOT_WALLET and books the gas. Payouts and refunds are sent from the hot wallet, never above its on-chain balance minus sends that are not mined yet.

Read endpoints: GET /api/v1/crypto/balances?mode= (available and locked per account × network × token), GET /api/v1/crypto/ledger/transactions, GET /api/v1/crypto/ledger/accounts, GET /api/v1/crypto/overview.

On this page