> ## Documentation Index
> Fetch the complete documentation index at: https://docs.testnet.dev.adipredictstreet.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> Notable API and platform changes, newest first.

## 2026-10-09

* **`user_fill` carries `role`** (`maker` / `taker`): `maker` when your
  order was resting in the book, `taker` when it crossed it. It is
  missing on fills recorded before this release; treat a missing `role`
  as unknown, not as taker. See
  [`user_fill`](/api-reference/websocket/user#user_fill-vs-rest-trade-history).
* **`order_cancelled` and `order_expired` carry `originalQuantity`**,
  the order size as placed, the same value as on `order_placed`.
  `originalQuantity - remainingQty` is what had filled when the order
  ended, not a final fill total; read that from `GET /api/orders/{id}`.
  See
  [`user_orders` frames](/api-reference/websocket/user#user_orders-frames-vs-rest-order-detail).
* **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_pending` with `Retry-After: 5`, not `503`.** `POST /api/orders/cancel`
  used to answer this case `503 exchange_unavailable` (upstream
  `order_cancel_unanswered`) with no `Retry-After`, and some clients retried
  every couple of seconds through a matching-engine restart. The response is
  now `202` with `status` and `code` set to `cancel_pending`, the `orderId`, a
  `message` and `retryAfterSec`; there is no `remainingQty`, 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 after
  `Retry-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`, or `FILLED` if the order filled
  first) arrives on the `user_orders` WebSocket channel and on
  `GET /api/orders/{id}`. While the release rolls out, an older exchange node
  can still answer the same condition `503 cancel_unanswered` with
  `Retry-After: 5` and `details.orderId`; handle it the same way.
* **`cancel-batch` / `cancel-all`: `cancel_unanswered` is now
  `cancel_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](/concepts/trading/cancelling).
* **`503 shard_owner_unavailable` on every order route, `cancel-all`
  included.** 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 answers `shard_owner_unavailable` with
  `Retry-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 got `503 exchange_unavailable`, which reads as "may have been
  recorded". Nothing was attempted: repeat the same request. On `place`, `place-batch`, `cancel` and `cancel-batch` the
  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 a
  `cancel-all`. The vault split / merge / convert signatures and
  `POST /api/me/splits-merges/{opId}/unlock` answer the same code in the
  same case.
* **The exchange can now refuse an order when it is too busy.** On
  `POST /api/orders/place` this is `503 trading_temporarily_unavailable`
  with `retryable: true`. On `place-batch` only 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 same `clientOrderId`, shortly. Do not sign a
  new one. See [Error codes](/errors/codes#trading).
* **`lock_invariant` in `notCancelled` comes 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 `stage` and `group`.** `GET /api/events`,
  `GET /api/events/{slug}` and `GET /api/events/featured` return the
  event's tournament stage and group letter. They are set on match-less
  football fixtures too, where `match` is `null`, 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`.** Every `ip`-scoped bucket
  counts an IPv6 caller by its `/64` prefix instead of its full address.
  IPv4 is unchanged. See [Rate limits](/auth/rate-limits).

## 2026-09-30

* **`GET /api/events` returns at most 100 events per response** (was
  500\). A larger `limit` is served as 100 events: before, a `limit`
  from 101 to 500 returned that many events and a `limit` above 500 was
  `400 invalid_limit`. A digits-only `from`/`to` span wider than 100 is
  cut to 100 events (it was cut to 500). Pages step by the served size, so
  `page=3&limit=500` returns positions 200–299. A request without
  `page`, `limit` or a numeric `to` returns the first 100 events (was
  500\). `invalid_limit` is now returned only for a `limit` that is not
  digits or is below `1`, and no longer carries `error.details.max`.
  See [Pagination](/api-reference/pagination#events-list-pages).
* **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 numeric `from`/`to` by 500
  (`from=500&to=1000`) gets positions 500–599 and never reads 100–499.
  Send `limit=100`, walk `page=1, 2, …` until a page comes back empty,
  and de-duplicate by `id`.
* **`X-Events-Window-Capped: 100`** marks a `GET /api/events` response
  whose request asked for more than 100 events (a `limit` above `100`,
  or a digits-only `to` more than 100 past `from`) or gave no window at
  all (no `page`/`limit` and no digits-only `to`, which used to return
  up to 500 events); a `limit` or 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`/`to` now combine with `page`/`limit`**, so a date
  range longer than one page can be paged. The date must start
  `YYYY-MM-DD` (`2026-10-01`, `2026-10-01T00:00:00Z`); any other
  `from`/`to` together with `page`/`limit`, digits-only included, is
  still `400 ambiguous_pagination`.
* **Listing totals on the first page of every listing.** The first page
  of `GET /api/events` (`page=1`, `from=0`, or no `page` and no
  digits-only `from`) now carries `total`, the number of events
  matching every filter, independent of paging, and `openMarketCount` /
  `totalMarketCount`, their market counts summed. Before, only a `q`
  search carried `total`, and no response carried the two sums. Later
  pages carry none of them; with `q`, every page carries all three, plus
  `facets`. Treat them as optional: a first page whose totals cannot be
  computed in time comes without them. See
  [Pagination](/api-reference/pagination#events-list-pages).
* **Slimmer market rows on `GET /api/events`.** Each `markets[]` entry
  no longer carries `eventSlug`, `tags`, `homeCountry`, `awayCountry`,
  `sport`, `tradingMode` or `notTradableReason`. `resolutionCriteria` is
  left out too, except on long-dated crypto markets (`crypto` set, not an
  Up/Down window, `cryptoWindow` `null`), which keep it.
  `prediction` keeps only `version`, `kind`, `line`, `threshold` and
  `endsAt` (dropped: `provider`, `questionId`, `question`, `rulesText`,
  `capturedAt`), and `probabilityChange` drops `asOf` and
  `outcomes[].baselineAt`. The event fields are unchanged; the event's
  own `slug`, `tags`, `sport`, `homeCountry` and `awayCountry` replace
  the per-market copies. See [Events
  overview](/concepts/events/overview#list-rows-vs-detail).
* **`additionalSources` stays on list rows.** An earlier version of
  this entry listed it as removed; `GET /api/events` market rows still
  carry it.
* **Reading `resolutionCriteria` from 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 from
  `GET /api/events/{slug}` or `GET /api/markets/{slug}`, or in bulk from
  `GET /api/markets` (full rows, up to 500 per page). Long-dated crypto
  rows on `GET /api/events` still carry it.
* **Detail is unchanged.** `GET /api/events/{slug}` and
  `GET /api/events/featured` still return full `MarketSummaryDto` rows, as
  do `GET /api/markets` and `GET /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` (or `closed=true`), a crypto Up/Down
  day event now nests only its three latest-ending `RESOLVED` or `VOIDED`
  windows, plus any window still awaiting settlement — the same windows
  `GET /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 all `VOIDED` before they ended
  still nests all of them (its detail returns 404). Other
  events and long-dated crypto markets are unchanged, and
  `totalMarketCount` still counts every window. Read the whole day from
  `GET /api/crypto-series/{id}/windows?state=all` with `from`/`to` set to
  that UTC day. See [Crypto events](/concepts/events/overview#crypto-events).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.