Money
The money contract
You own your customers’ cash ledger. Parity never holds a player’s funds. It returns the exact amounts to reserve, debit, release and credit against your own books.
Who holds what
| Step | Who does it | From which field |
|---|---|---|
| Reserve the stake | You | operatorMoney.authorizationAmount on the quote |
| Debit what actually filled | You | operatorMoney.actualDebit on the order |
| Hand back what did not | You | operatorMoney.releaseAmount on the order |
| Charge the platform fee | Parity | Already inside the debit: platformFee |
| Credit an exit | You | operatorExitMoney.sellProceeds |
| Credit a winner | You | operatorMoney.settlementCredit |
| Refund a void | You | operatorMoney.voidCredit |
Apply these amounts. Never recompute one.
The moment an integration multiplies a price by a quantity to work out what to debit, there are two answers to one question and only one of them is in our ledger. They will agree for months and then disagree by a cent on a position built from several fills, and nobody will be able to say which is right.
The two identities
authorizationAmount = actualDebit + releaseAmount
actualDebit = tradeAmount + platformFee + venueFeeThese are equalities, not tolerances. Every figure is an exact integer of minor units on our side: actualDebit is the sum of its parts rather than an independently rounded number, and releaseAmount is a subtraction rather than an independently derived remainder. There is no arrangement of prices that makes them drift, so a response that breaks one has been altered in transit and must not be booked.
Why the release exists
Parity takes its fee off the top of the stake rather than adding it on: a $50 stake at 120bps wagers $49.40. So the gross cash the player commits is exactly what you authorize, and a fully filled order releases nothing.
A partial fill is the case the contract exists for. The venue takes less cash than the stake covered, tradeAmount is the notional actually spent, and the difference is money you are holding that must go back. An operator that only ever debits the full stake silently keeps it.
{
"authorizationAmount": "25.00", // you reserved this
"actualDebit": "12.30", // take this
"releaseAmount": "12.70", // give this back
"tradeAmount": "12.00",
"platformFee": "0.30",
"venueFee": "0.00",
"venueFeeKnown": false
}Read that example twice. An operator that debits "25.00" here has kept $12.70 of a customer's money, the books still balance on its own side, and nothing in any later response ever mentions it. That is the failure this whole page exists to prevent, and it is silent.
Rehearse it. A sandbox will not produce one on its own.
The simulated venue has no book to run out of, so a partial fill never happens by accident in the sandbox. Arm one deliberately with POST /api/v1/sandbox/scenarios and put a real order through it, then check that your wallet released the remainder. See Sandbox.
venueFeeKnown: false means the zero is a placeholder, not a fact. No live venue publishes a taker fee we can read, and the quote row stores null rather than 0 precisely so “we do not know” stays distinguishable from “there is none”. The identity still needs a number for it, so it reports as zero and says so here rather than asserting something we do not have.
An exit credits. It never debits.
On a sell, operatorMoney is null and operatorExitMoney is populated. That nullability is the point of the field rather than an oversight: an exit that came back carrying an authorizationAmount would have a wallet applying the contract as written debit the player for selling their own position.
{
"action": "sell",
"operatorMoney": null,
"operatorExitMoney": {
"sellProceeds": "12.20", // credit this. ALREADY NET
"platformFee": "0.15",
"venueFee": "0.00",
"venueFeeKnown": false
}
}The fees are reported beside the proceeds so you can show what the round trip cost, not so you can subtract them. Subtracting again is the double charge this shape exists to prevent. A round trip is two transactions and carries two fees.
The exit has an identity of its own, and it is an assertion, never a derivation:
sellProceeds = notional - platformFee - venueFeenotional on the exit is the gross contract value before any fee. The subtraction happens once, on our side, in exact minor units. Check it if you want the reassurance; credit sellProceeds either way.
One payout, two names
{ "settlementCredit": "17.15", "voidCredit": "0.00" } // won
{ "settlementCredit": "0.00", "voidCredit": "0.00" } // lost
{ "settlementCredit": "0.00", "voidCredit": "25.00" } // void, fee includedA settlementCredit is winnings and a voidCredit is a refund of everything the player committed, fee included. Operators book those differently (one is revenue against a wager, the other reverses one) and collapsing them into a single “payout” would push that distinction back onto you, to be re-derived from an outcome string.
Amounts are exact decimal strings
Every figure inside operatorMoney, operatorExitMoney and a settlement is a string. A JSON number cannot carry an exact cent past a certain size and, worse, looks like it can. A client that parses 12.30 as a float has left the exact world before its own ledger sees the figure.
import { toMinorUnits, addDecimal } from '@/sdk';
toMinorUnits(order.operatorMoney!.actualDebit); // 1230n, exact
addDecimal(debit, release) === authorization; // the identity, in your own codeThe float fields beside them (stake, notional, platformFee, averagePrice, executionPrice) are for display. Prices are genuinely real numbers and 0.71 is an honest approximation of a market's view; the moment a price becomes an amount somebody is charged, it crosses into the exact world and stops being divisible.
What Parity will and will not refuse
- A stake is refused for reasons of price and freshness only. There is no
422 insufficient_balanceon this API and you should not write a handler expecting one. - That is not because Parity cannot see a balance. It is because the balance that matters is yours. You decide what a player may stake, before you ask us for a price.
- The safe ordering is: reserve on your side, submit with a
clientOrderIdderived from that reservation, and release on anything other than a success, with one exception: an unresolved order, where you hold. See Orders.
The sandbox balance, and why it is not this
Sandbox only: 403 sandbox_only in live mode
GET /api/v1/users/{id}/balance and GET /api/v1/users/{id}/ledger return real derived figures from Parity's own double-entry books, and they exist so an integration can be learned against simulated money: a stake to spend, and somewhere to watch it move.
They are not the production integration path, and in live mode they answer 403 sandbox_only rather than returning a figure that invites the misreading. A live operator that read a balance from there would be treating Parity as a custodian of its players' funds, which Parity is not, and would eventually reconcile its own books against a number describing something else.
The accounting model behind them is worth understanding anyway, because the sandbox posts every movement exactly as production does. See Ledger.
The rest of the money model
- Settlement is the register you credit from, and how to consume it exactly once.
- Reconciliation is the verdict, and the fact stream your own books can be rebuilt from.
- Ledger (sandbox) is the chart of accounts, the movement types and the immutability rules.
- Bridge covers how value reaches the collateral asset, and the custody models.
Custody
Your customers' cash sits on your books, under your licence, in your ledger. Parity holds none of it, which is why this whole page is a set of instructions rather than a balance: nothing here asks you to move money to Parity and wait for it to come back.
The custody structure behind the collateral asset itself, per-user versus omnibus accounts, is a deployment decision taken with people rather than through an API. The two models and what each one implies are on Bridge.

