Reference
API reference
Every endpoint, in one place, checked against what the build actually serves.
Two surfaces
| Surface | Auth | What it is for |
|---|---|---|
/api/v1/* | Operator key + scope | The partner contract. Opaque contract ids, exact money, keyset cursors, no venue named anywhere. |
/api/* | None | The public catalogue and the public demo. It powers a page anyone can open; it is not a contract. |
They are different routes with different rules rather than one route with a flag. Adding auth to the public surface would break the demo; leaving it off the partner surface would make an operator's orders placeable by anyone who learns a player id.
Authorization: Bearer pk_test_... # or sk_live_... in production
X-Parity-User: your-own-player-id # on every quote and order
Content-Type: application/jsonA machine-readable OpenAPI 3.1 document covering every path on this page is at /openapi.json.
Catalogue
/api/v1/eventsAPI keymarkets:read. category, sort, dir, search, tradable, closesAfter, closesBefore, limit (1-100, default 25), cursor. An unrecognised filter value is a 400, not a silently unfiltered catalogue./api/v1/events/{id}API key{id} is an event id or its slug. Scope markets:read./api/v1/categoriesAPI key?category= accepts, with live event counts. Scope markets:read./api/v1/images/{id}No auth{id} is the event id. Unauthenticated, because it is a URL a browser loads from an <img> tag./api/v1/stream/pricesNo auth?contracts= is a comma-separated list of opaque ctr_… ids. No API key ever, because a browser cannot hold one. Every frame is normalised, names no venue and is not user-specific. An embed session token in Authorization: Embed <token> is optional and decides one thing: whose offering policy filters the feed before delivery. A token that is presented and refused closes the connection rather than downgrading it to anonymous. One connection per page; Parity multiplexes the venue side, so a thousand viewers of one contract cost one upstream subscription. Never render a price without reading tradeable.Embed
/api/v1/embed-sessionsAPI keymarkets:read, quotes:write and orders:write together, because a session can browse, quote and order, so the key that mints one must be able to do all three itself. Body: externalUserId (required), returnOrigin, ttlSeconds (60-3600, default 900), locale, region, theme. The token is returned once. Send it as Authorization: Embed <token>; a token in a query string is refused outright. Full walkthrough on Parity Embed.Trading
/api/v1/quotesAPI keyquotes:write. Exactly one of stake (sizes a BUY) or contracts (sizes a SELL). Requires X-Parity-User./api/v1/ordersAPI keyorders:write. Idempotent on clientOrderId: 201 on creation, 200 with idempotentReplay: true on a replay. Requires X-Parity-User./api/v1/ordersAPI keyorders:read. externalUserId, clientOrderId (with externalUserId), status, since, until, limit (1-200, default 50), cursor. Returns orders, count, nextCursor and hasMore, and does not carry settlementState: use it to find the orderId, then read that order. ?status= is not validated, so an unknown value returns an empty page rather than a 400./api/v1/orders/{id}API keysettlementState and transmissionState. Scope orders:read. ?fills=true includes the individual executions, and that exact spelling is what is matched: ?fills=1 and ?fills=TRUE do not enable it. This is the only route that returns settlementState. The list route below does not, so a recovery polls this one./api/v1/orders/{id}/confirm-reserveAPI keyorders:write. Idempotent: the same call twice yields one executable order and a 200, never a conflict. Until it is made, a recorded order is reserve_pending and cannot execute./api/v1/orders/{id}/cancelAPI keyorders:write. Issued exactly once: a second call replays the same cancellationId and the same releaseAmount. Refused with 409 for any order whose transmissionState is not not_transmitted.Positions
/api/v1/positionsAPI keypositions:read. externalUserId, status, limit (1-200, default 50), cursor./api/v1/positions/{id}API keypositionId. Scope positions:read.Settlement and reconciliation
/api/v1/settlementsAPI keysettlements:read. externalUserId, outcome, settledFrom, settledTo, limit (1-500, default 100), cursor./api/v1/settlements/positionsAPI keysettledAt. Superseded by /api/v1/settlements, which its own response says in supersededBy: this one pages with no tiebreaker, and settlements written in one transaction share a timestamp exactly./api/v1/reconciliationAPI keyledger:read. Optional from./api/v1/reconciliation/feedAPI keyledger:read. cursor, type (repeatable), externalUserId, limit (1-500, default 100).Customers
/api/v1/users/{id}/jurisdictionAPI keyorders:write. Body: country (ISO 3166-1 alpha-2, required) and optionally subdivision (the part of an ISO 3166-2 code after the hyphen, or null for country level). You ran the KYC and hold the licence, so the assertion is yours; Parity does not authenticate your end users and does not geolocate them. It changes nothing until jurisdiction enforcement is switched on for your account, so you can populate assertions first and enforce after. A country that is not two letters is 400 invalid_jurisdiction./api/v1/users/{id}/limitsAPI keyorders:write. Returns three objects: account (what you set on this customer), operator(the ceiling over every account you hold) and effective (what the quote and order seams will enforce, with the rung that decided each figure named). Read effective. The account rung can only ever TIGHTEN the operator rung, never loosen it, so an account ceiling set above the operator ceiling has no effect at all, and a caller reading only its own write would believe it had raised a limit it had not raised./api/v1/users/{id}/limitsAPI keyorders:write. Body: maxWagerMinor caps ONE wager; periodStakeMinor with periodHours caps total stake across a rolling window. The pair travels together, because a stake ceiling with no window is not a rule anybody can enforce and a window with no ceiling bounds nothing, so the half-written form is 400 invalid_request. Amounts are exact integers of minor units. Send null at a field to withdraw the opinion at this rung. The reply is the same shape as the GET./api/v1/users/{id}/limitsAPI keyeffective: a 200 here does not mean the customer is now unlimited. Scope orders:write./api/v1/users/{id}/jurisdictionAPI keymarkets:read.These two work in live mode
They are the only /api/v1/users/{id}/* paths that do. The balance and movement reads below are gated to sandbox tenants; a jurisdiction assertion is production machinery and is how enforcement is fed.
Sandbox only
Every path in this section answers 403 sandbox_only in live mode
They model a per-user balance held by Parity, which exists so an integration can be learned against simulated money. A live operator owns its customers' cash ledger, so there is nothing here for it to read. The live contract is operatorMoney, operatorExitMoney and settlementCredit.
/api/v1/users/{id}/balanceAPI keyledger:read. Optional currency./api/v1/users/{id}/ledgerAPI keyledger:read. limit (1-200, default 50), cursor./api/v1/funding/supported-assetsAPI keyfunding:write. symbol, symbols, chainId./api/v1/funding/deposit-addressAPI keyfunding:write. 201 on success./api/v1/funding/deposits/{id}API keyfunding:write. ?sync=false skips the bridge poll./api/v1/sandbox/scenariosAPI keyorders:write; GET lists what is armed under orders:read. It drives the real order code rather than a simulation of it. A scenario fires once and expires after an hour. See Sandbox./api/v1/sandbox/resolutionsAPI keyWIN, LOSS or VOID, relative to the position's own side. Scope settlements:read. It names a position, never a market, because resolving a market would settle every other operator's positions on it. Asking twice is idempotent; asking for a different resolution is 409 resolution_conflict.Public: no credentials
These power the public site and the public demo. They are useful to read and they are not the partner contract: they carry no operator scoping, and the ones that take no key carry no commitment about their shape either. They name contracts by the same opaque ctr_… id /api/v1 uses, and they never name a liquidity pool.
/api/eventsNo auth/api/events/{key}API keyrange is 1d, 1w, 1m or all. Needs a key with markets:read: it is addressed by an internal grouping key and has no first-party reader, so it is not a public surface any more. Use GET /api/v1/events/{id}./api/marketsNo auth/api/markets/{id}No auth/api/markets/quotes?ids=…No auth/api/healthNo auth503 only when the database is down./api/demo/quotesNo auth/api/demo/ordersNo authDo not integrate against /api/demo/* or /api/*
The demo exists so the public page exercises the production path rather than a parallel implementation of it. It is unauthenticated, its identity model is not yours, and it is not a contract. The public catalogue is likewise a website feed: partners read /api/v1/events.
Conventions that hold everywhere
- Auth.
Authorization: Bearer <key>on every/api/v1/*request except/api/v1/images/{id}and/api/v1/stream/prices. Scope is checked before the rate limit is consumed, so a scope mistake never arrives disguised as a429on the retry. - Identity.
X-Parity-Usercarries your id for the player. Parity never authenticates end users and stores only that opaque value. A write path creates a user on first use; a read never does. - Idempotency.
clientOrderIdon orders, enforced by a unique index on (operator, user, clientOrderId) rather than by a check in a handler. Retrying is the correct response to a timeout. - Money. Exact decimal strings inside
operatorMoney,operatorExitMoneyand a settlement. Numbers elsewhere are for display. Contract prices are 0-1, and sub-cent prices are real. - Cursors. Keyset, not offset. Loop on
nextCursor; a last page legitimately has none. Every paged feed refuses a malformed cursor with400 invalid_cursorrather than restarting at page one. A cursor that decodes cleanly and names a row that has since gone is a different case, and three feeds still answer it with page one. See Errors. - Errors. A JSON body with a machine-readable
error. Branch on the code, never on the message. - Rate limits. Two per-minute counters: one per key, one per operator across every key it holds.
RateLimit-Limit,RateLimit-RemainingandRateLimit-Resetreport the key and are on most responses rather than all of them.POST /api/v1/quotesandPOST /api/v1/ordersanswer without them. See Rate limits. - Timestamps. ISO-8601, UTC, always as strings.
- Sourcing. A contract is a
ctr_…id, and no response on this surface names a venue. The last exception was the deprecatedGET /api/v1/settlements/positions, which published avenueListingIdcarrying the source's name and its own id for the contract. It now publishescontractIdlike everything else. Webhook payloads are narrowed the same way.
Scopes
| Scope | Reaches |
|---|---|
markets:read | events, events/{id}, categories, GET users/{id}/jurisdiction |
quotes:write | quotes |
orders:write | POST orders, POST orders/{id}/confirm-reserve, POST orders/{id}/cancel, PUT users/{id}/jurisdiction, and the sandbox scenario control |
orders:read | GET orders, orders/{id}, and the sandbox scenario list |
positions:read | positions, positions/{id} |
settlements:read | settlements, settlements/positions, and the sandbox resolution control |
ledger:read | reconciliation, reconciliation/feed, and the sandbox balance and ledger |
funding:write | all three funding routes, including the two reads |

