2026-10-09
user_fillcarriesrole(maker/taker):makerwhen your order was resting in the book,takerwhen it crossed it. It is missing on fills recorded before this release; treat a missingroleas unknown, not as taker. Seeuser_fill.order_cancelledandorder_expiredcarryoriginalQuantity, the order size as placed, the same value as onorder_placed.originalQuantity - remainingQtyis what had filled when the order ended, not a final fill total; read that fromGET /api/orders/{id}. Seeuser_ordersframes.- Backend v2.9.22, live on production today, changes how order requests fail during an exchange restart. The items below cover it.
- A recorded cancel with no recorded answer yet is
202 cancel_pendingwithRetry-After: 5, not503.POST /api/orders/cancelused to answer this case503 exchange_unavailable(upstreamorder_cancel_unanswered) with noRetry-After, and some clients retried every couple of seconds through a matching-engine restart. The response is now202withstatusandcodeset tocancel_pending, theorderId, amessageandretryAfterSec; there is noremainingQty, because the order can still fill until the cancel lands. There is no recorded answer yet, so the order may still be open. Send the same cancel again afterRetry-After: it is safe, cannot cancel twice, and completes the cancel as soon as the engine answers. The platform also completes it on its own, more slowly. The final status (CANCELLED, orFILLEDif the order filled first) arrives on theuser_ordersWebSocket channel and onGET /api/orders/{id}. While the release rolls out, an older exchange node can still answer the same condition503 cancel_unansweredwithRetry-After: 5anddetails.orderId; handle it the same way. cancel-batch/cancel-all:cancel_unansweredis nowcancel_pending. Same condition and the same action: cancel the ids named this way again after a few seconds, with a single cancel or a cancel-batch of exactly those ids (not another cancel-all, which is a new sweep that also cancels orders placed since), and re-read the order. See Cancelling orders.503 shard_owner_unavailableon every order route,cancel-allincluded. When the exchange node that serves your account is restarting or being taken over and refuses a request before recording anything, every order route now answersshard_owner_unavailablewithRetry-After: 2. Before, a cancel, cancel-batch or cancel-all refused this way by a node that was shutting down or still taking the account over got503 exchange_unavailable, which reads as “may have been recorded”. Nothing was attempted: repeat the same request. Onplace,place-batch,cancelandcancel-batchthe platform first re-sends the request itself for up to about 6 seconds, so most restarts no longer reach you at all. It never re-sends acancel-all. The vault split / merge / convert signatures andPOST /api/me/splits-merges/{opId}/unlockanswer the same code in the same case.- The exchange can now refuse an order when it is too busy. On
POST /api/orders/placethis is503 trading_temporarily_unavailablewithretryable: true. Onplace-batchonly that entry is refused:success: false,code: journal_intent_not_durable,details.retryable: true, and the other entries keep their results. Nothing was admitted for the refused order, so resend the same signed order unchanged, under the sameclientOrderId, shortly. Do not sign a new one. See Error codes. lock_invariantinnotCancelledcomes only from older exchange nodes. Current nodes record the bookkeeping mismatch and cancel the order. The docs said it “typically clears on its own”.- Events carry
stageandgroup.GET /api/events,GET /api/events/{slug}andGET /api/events/featuredreturn the event’s tournament stage and group letter. They are set on match-less football fixtures too, wherematchisnull, and they are the values?stage=and?group=now filter on, so those filters also match match-less fixtures. - IPv6 callers are rate-limited per
/64. Everyip-scoped bucket counts an IPv6 caller by its/64prefix instead of its full address. IPv4 is unchanged. See Rate limits.
2026-09-30
GET /api/eventsreturns at most 100 events per response (was 500). A largerlimitis served as 100 events: before, alimitfrom 101 to 500 returned that many events and alimitabove 500 was400 invalid_limit. A digits-onlyfrom/tospan wider than 100 is cut to 100 events (it was cut to 500). Pages step by the served size, sopage=3&limit=500returns positions 200–299. A request withoutpage,limitor a numerictoreturns the first 100 events (was 500).invalid_limitis now returned only for alimitthat is not digits or is below1, and no longer carrieserror.details.max. See Pagination.- Migrating from
limit=500. Nothing errors, but every response now holds at most 100 events. A client that reads one 500-event page, or stops paging when a page is shorter than 500, now sees only the first 100 events. A client that steps a numericfrom/toby 500 (from=500&to=1000) gets positions 500–599 and never reads 100–499. Sendlimit=100, walkpage=1, 2, …until a page comes back empty, and de-duplicate byid. X-Events-Window-Capped: 100marks aGET /api/eventsresponse whose request asked for more than 100 events (alimitabove100, or a digits-onlytomore than 100 pastfrom) or gave no window at all (nopage/limitand no digits-onlyto, which used to return up to 500 events); alimitor digits-only span of 100 or less never carries it. It describes the request, not the list: it does not mean more events follow, so keep paging until a page comes back empty.- ISO-8601
from/tonow combine withpage/limit, so a date range longer than one page can be paged. The date must startYYYY-MM-DD(2026-10-01,2026-10-01T00:00:00Z); any otherfrom/totogether withpage/limit, digits-only included, is still400 ambiguous_pagination. - Listing totals on the first page of every listing. The first page
of
GET /api/events(page=1,from=0, or nopageand no digits-onlyfrom) now carriestotal, the number of events matching every filter, independent of paging, andopenMarketCount/totalMarketCount, their market counts summed. Before, only aqsearch carriedtotal, and no response carried the two sums. Later pages carry none of them; withq, every page carries all three, plusfacets. Treat them as optional: a first page whose totals cannot be computed in time comes without them. See Pagination. - Slimmer market rows on
GET /api/events. Eachmarkets[]entry no longer carrieseventSlug,tags,homeCountry,awayCountry,sport,tradingModeornotTradableReason.resolutionCriteriais left out too, except on long-dated crypto markets (cryptoset, not an Up/Down window,cryptoWindownull), which keep it.predictionkeeps onlyversion,kind,line,thresholdandendsAt(dropped:provider,questionId,question,rulesText,capturedAt), andprobabilityChangedropsasOfandoutcomes[].baselineAt. The event fields are unchanged; the event’s ownslug,tags,sport,homeCountryandawayCountryreplace the per-market copies. See Events overview. additionalSourcesstays on list rows. An earlier version of this entry listed it as removed;GET /api/eventsmarket rows still carry it.- Reading
resolutionCriteriafrom the list? Unlike the fields above, it was in the published schema: list rows were documented as the full market row. It is now an optional key of the list row (EventListMarketDto), present only on long-dated crypto markets: a client generated from the schema, or a strict validator, must accept a row without it. Read it fromGET /api/events/{slug}orGET /api/markets/{slug}, or in bulk fromGET /api/markets(full rows, up to 500 per page). Long-dated crypto rows onGET /api/eventsstill carry it. - Detail is unchanged.
GET /api/events/{slug}andGET /api/events/featuredstill return fullMarketSummaryDtorows, as doGET /api/marketsandGET /api/markets/{slug}. Read those when you need a dropped field. - Closed Up/Down days nest at most three settled windows. On
GET /api/events?status=closed(orclosed=true), a crypto Up/Down day event now nests only its three latest-endingRESOLVEDorVOIDEDwindows, plus any window still awaiting settlement — the same windowsGET /api/events/{slug}already returned. Before, it nested every settled window of the day (up to 288 on a 5-minute series). One exception: a day whose windows were allVOIDEDbefore they ended still nests all of them (its detail returns 404). Other events and long-dated crypto markets are unchanged, andtotalMarketCountstill counts every window. Read the whole day fromGET /api/crypto-series/{id}/windows?state=allwithfrom/toset to that UTC day. See Crypto events.