Where the split is computed, and where halfin starts
A revenue split is a decision your platform makes, not a feature you outsource. The percentages come from your contracts — a 70/30 between platform and creator, a three-way split when a collaborator is credited, a tiered rate that changes once a creator passes a threshold. Those terms, and the rounding policy that decides who absorbs the sub-unit remainder, belong in your ledger because that is where the deal is recorded and where disputes are settled.
So the boundary is clean. Your system takes an income event and produces a list of shares: a destination wallet, an asset, and an exact amount per line. halfin takes that list and moves the money. It does not compute percentages, apply your tier rules, or decide who the collaborator is — handing it those concerns would couple your commercial terms to a payment rail, which is exactly the thing you want to keep separate.
Stated plainly: the split is yours, the settlement is halfin's. Everything below assumes you have already turned one income event into a small list of exact shares and are ready to pay them.
- Split percentages and tier rules live in your ledger, derived from your contracts.
- Rounding policy — who absorbs the sub-unit remainder — is your decision, applied before you call halfin.
- halfin receives a list of exact shares (destination, asset, amount) and pays them.
- A revenue split is just a mass payout whose lines happen to add up to one income event.
Get the arithmetic right before any money moves
The failure that quietly erodes a revenue-share ledger is rounding drift. Split an amount three ways and the naive fractions rarely divide evenly; round each share independently and the parts no longer sum to the whole, so over thousands of splits your platform either leaks fractions of a cent or over-pays them. The fix is not halfin's — it is a rule you apply in your own ledger — but it is worth stating because halfin will faithfully pay whatever amounts you submit, including a set that does not reconcile.
Two rules keep a split honest. Compute every share in the smallest unit of the asset — integer minor units, never a floating-point fraction — and make exactly one line absorb the remainder so the shares sum back to the income amount to the last unit. The platform's own cut is the natural place to put the remainder, since it is the line you control and the one a creator never queries.
halfin reinforces this at the transport layer: every amount in the payout API is a string, never a float, precisely so a 0.1 + 0.2 rounding artefact can never enter a payment. You format the exact share as a decimal string and submit it; what you computed is what settles.
| Income event | Share | Who | Note |
|---|---|---|---|
| 100.00 USDT subscription | 70.00 USDT | Creator | Contractual creator cut. |
| 100.00 USDT subscription | 30.00 USDT | Platform | Platform cut — absorbs any rounding remainder. |
| 50.00 USDT sponsored stream | 33.33 USDT | Lead creator | Two-thirds of a 50.00 split, rounded down. |
| 50.00 USDT sponsored stream | 16.67 USDT | Collaborator | Remaining third — note the shares sum to 50.00. |
Pay the split as one idempotent fan-out
Once you hold a list of exact shares, paying it is a mass payout — and a mass payout in halfin is a fan-out over the single-payout API, not a separate batch endpoint. You loop the shares and call the payout API once per line, each call carrying its own idempotency key. The unit that succeeds, fails, or retries is one payout to one destination, so a bad collaborator wallet on a three-way split is a single visible failure you re-issue, while the platform and creator lines that already paid stay untouched.
Derive each idempotency key deterministically from data you already have — an income event id plus the recipient role or id. The same logical share then always produces the same key, so if your process dies mid-split and the scheduler retries, the keys collide and no recipient is paid twice. Re-running the whole loop after a crash converges on exactly one payout per share.
Reconciliation is then a read, not a guess. You read each payout's state back through the API and confirm settlement from the payout.completed webhook your server receives — verifying the HMAC signature before you act on it. A split is settled when every one of its lines reports completed, and an income event whose shares do not all reach completed is a split you can see is incomplete rather than one you discover broken at month-end.
# A revenue split is a fan-out: one payout call per share, each with its
# own idempotency key derived from the income event id + recipient role.
# Re-running the loop after a crash is safe — colliding keys mean no
# recipient is paid twice, and the shares still sum to the income amount.
EVENT_ID="sub-evt-90217"
# shares.csv columns: role,currency,amount,destination
# creator,USDT,70.00,T...creatorWallet
# platform,USDT,30.00,T...treasuryWallet # absorbs the remainder
while IFS=, read -r role currency amount destination; do
curl -sS -X POST https://api.thehalfin.com/api/v1/payouts \
-H "X-API-Key: $HALFIN_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"currency\": \"$currency\",
\"amount\": \"$amount\",
\"destination\": \"$destination\",
\"idempotency_key\": \"split-$EVENT_ID-$role\"
}"
done < shares.csv
# Read each payout back and confirm settlement from the payout.completed
# webhook (verify the HMAC signature first). The split is settled when
# every line reports completed. See docs.thehalfin.com for the full schema.Pay a share in a different asset than you hold
Income and obligation often arrive in different assets. A creator subscribes and pays USDT on Tron; the collaborator credited on that stream is owed USDC on Solana; your platform settles its own cut in something else again. If you only ever held the income asset, a revenue split would force every recipient onto the asset your viewers happened to pay in — which is not how creator agreements read.
Balance conversion sits between the held balance and the payout. When a share is owed in an asset you do not currently hold enough of, you convert held balance into the payout asset and then pay the share out of it. Conversion is available both automatically — as part of keeping enough of each payout asset on hand — and manually, when your treasury team wants to rebalance between assets deliberately rather than reacting per split.
Sequence it so the conversion settles before the dependent payout line goes out: convert to cover the share, confirm the converted balance is available, then fan that line into the payout run alongside the lines that needed no conversion. The split as a whole still reconciles to the original income event — the shares are the same fractions; only the asset each one lands in has changed.
- Hold income in one asset, owe shares in another — conversion bridges the two.
- Convert held balance to the payout asset, confirm it settled, then pay the share.
- Conversion is automatic (keep payout assets stocked) or manual (deliberate treasury rebalancing).
- The split still reconciles to the income event; only the destination asset changes.
Revenue share next to the other payout flows
Revenue share is one shape of payout among several a creator platform runs, and it helps to see where it sits. A whole-roster earnings run pays every creator their accrued balance on a schedule; a creator-initiated withdrawal draws one creator's balance down on demand; a revenue split fans a single income event into its contractual shares. All three are the same primitive — idempotent payouts over the payout API — pointed at a different list.
What makes revenue share distinct is the constraint that the lines must sum back to a known income amount. A roster run has no such invariant — each line is whatever a creator earned — so its correctness check is per-line. A split's correctness check is also per-event: every share of one income event reaches completed, and the shares add up. Build the split so that invariant is something you can assert from the payouts' own state rather than infer from your books.
| Flow | What it pays | Correctness check |
|---|---|---|
| Revenue split | One income event fanned into platform / creator / collaborator shares. | All shares reach completed and sum to the income amount. |
| Roster earnings run | Every creator's accrued balance on a schedule. | Each line reaches completed; no per-event sum invariant. |
| Creator withdrawal | One creator drawing down available balance on demand. | The single payout reaches completed. |
| Cross-asset share | A share owed in an asset you do not hold. | Conversion settles, then the dependent payout completes. |