Lifecycle
Settlement
A settlement record is an instruction: this position closed, this is what to credit. It is computed once, on Predicta’s side, so that two systems are never doing the same arithmetic.
The settlement register
/api/v1/settlementsAPI keysettlements:read.| Parameter | Notes |
|---|---|
externalUserId | Your own id for the customer. An id that has never traded is 404 unknown_user, not an empty page. |
outcome | won, lost or void. |
settledFrom / settledTo | ISO-8601, inclusive. |
limit | 1–500, default 100. |
cursor | Opaque. Echo nextCursor from the previous page. |
curl -s "$PREDICTA_BASE/api/v1/settlements?externalUserId=user-4471&outcome=won&limit=100" \
-H "Authorization: Bearer $PREDICTA_KEY"{
"settlements": [
{
"id": "stl_…", // stable. Safe as the idempotency key for a credit.
"positionId": "pos_…",
"externalUserId": "user-4471", // YOUR id, never a Predicta uuid
"side": "YES",
"resolution": "YES", // YES | NO | VOID, as resolved upstream
"outcome": "won", // won | lost | void, for this position
"contracts": 68.6111,
"realisedPnl": 18.61, // THIS settlement's
"lifetimeRealisedPnl": 18.61, // the position's running total
"settledAt": "2026-08-21T18:02:11.004Z",
"operatorMoney": {
"currency": "USD",
"settlementCredit": "68.61", // CREDIT THIS
"voidCredit": "0.00"
},
"cursor": "…"
}
],
"nextCursor": "…",
"hasMore": false
}realisedPnl is this settlement’s, not the position’s lifetime
The two differ whenever a position was partly exited before it resolved. Reporting the lifetime figure under a per-settlement name overstates the period, so both are published and each is named for what it is. Sum realisedPnl for a period; lifetimeRealisedPnl is the position's running total.
Exactly one credit is non-zero
| outcome | settlementCredit | voidCredit |
|---|---|---|
won | $1.00 × contracts, rounded down to the cent. | 0.00 |
lost | 0.00 | 0.00 — a loss zeroes both. Nothing to credit. |
void | 0.00 | Everything the player committed, including the platform fee. |
A void refunds the commission as well as the stake. Predicta did not provide the market, so it does not keep the fee: quietly retaining it would be a new commercial term introduced by a backend decision. The two fields are separate rather than one signed amount because a refund and a win are different postings in an operator's books.
A contract settles at exactly $1.00 or exactly $0.00. There is no third case: a market that resolved 99% certain did not resolve.
Consuming it safely
- Key your credit on the settlement's
id— it is stable and it is what makes re-processing a no-op.positionIdworks equally well and is what the webhook keys on, so a partner using both never processes the same fact twice. - Advance your stored cursor only after the batch is applied. Reading does not consume: the same cursor returns the same page, so a consumer that crashes mid-batch re-reads rather than skips.
- The register is scoped to your operator inside the query, not filtered afterwards. Another partner's settlements are not reachable by guessing a cursor.
hasMore: falsemeans caught up. Poll on the order of once a minute; settlements are not high-frequency events.
for await (const s of predicta.iterateSettlements({ settledFrom: lastRun })) {
// s.operatorMoney.settlementCredit and .voidCredit are exact Decimal strings.
await ledger.creditOnce(s.id, s.externalUserId, s.operatorMoney);
}The older feed
/api/v1/settlements/positionsAPI keysupersededBy: "/api/v1/settlements".It pages on settledAt with no tiebreaker — and settlements written in one transaction share a timestamp exactly — so it can drop or repeat rows at a page boundary. It is left working rather than removed because it is already a published contract, but new integrations should use the register above: same records, keyset cursor on a monotonic sequence, no gap.
Why you cannot be paid twice
Three layers, each of which would be sufficient alone:
- The position row is locked for update inside the settlement transaction, so two concurrent sweeps serialise rather than both reading it as open.
- Only a position still marked open is considered.
- The settlement insert carries a unique index on
positionId. If it inserts nothing, no credit is computed, no status is written and no event is emitted.
The third is the one that holds if the others are ever wrong, because it is a database constraint rather than a branch in application code.
Voids and amendments
Upstream sources sometimes change a published result. Predicta handles that by refusing to pretend it did not happen, and by refusing to act unilaterally.
| Situation | What Predicta does |
|---|---|
| A contract resolves normally | Positions settle against that contract’s own resolution, and no other. A grouped listing elsewhere settles independently and is permitted to disagree. |
| A contract closes with no published result | It is reported as determined, never guessed. Nothing settles. |
| A resolution changes after positions settled | The contract moves to needs_review, which stops anything further from settling against either value, and a market.resolution_changed event names the affected positions. |
An amendment is a notification, not an instruction
Predicta never reverses a settlement, adjusts a figure or rewrites a settlement row. Money that left your ledger on the strength of a published outcome is not clawed back by a background job: the source may be correcting a mistake, or making one. You receive the exact list of affected positions and the decision is yours.
Proving the period balances
The register answers “what settled”. To check that every money fact of a period agrees — trial balance, cash statement, venue agreement, and the individual findings when it does not — read Reconciliation. Its feed carries position.settled alongside every fill, fee and collateral movement, totally ordered and resumable, which is the stream to build a nightly close on.
The public market feed
GET /api/settlements is unauthenticated and publishes market outcomes: one row per resolved contract, with no reference to who held what. It is the right feed only if you run your own book against Predicta's resolutions. If Predicta recorded the positions, use the register above — working out who held what from a market outcome is precisely the arithmetic that must not be performed in two places.

