Money
The money contract
You own your customers’ cash ledger. Predicta 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 | Predicta | 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
Predicta 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
}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.
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, predictaFee, 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 Predicta 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 Predicta 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 — except 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 Predicta'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 Predicta as a custodian of its players' funds, which Predicta 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 — the register you credit from, and how to consume it exactly once.
- Reconciliation — the verdict, and the fact stream your own books can be rebuilt from.
- Ledger (sandbox) — the chart of accounts, the movement types and the immutability rules.
- Bridge — how value reaches the collateral asset, and the custody models.
Custody
Not approved for customer custody
This build takes no custody of customer funds. The funding path targets a test treasury wallet, and nothing in this documentation should be read as an approval to hold a member of the public's money.
Custody structure, per-user versus omnibus accounts, and the regulatory perimeter around them are commercial and legal questions settled per deployment — not by an API contract.

