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

# Changelog

> API changes, deprecations, and the policy that governs them.

## Deprecation policy

When we remove or materially change a public endpoint or field:

1. **Announce the replacement** — what to use instead, with a migration example.
2. **List affected endpoints** — every route, field, or WS channel touched.
3. **Set a dated removal window** — at least 90 days from announcement for
   breaking REST changes, unless the change is a security fix.
4. **Log reversals** — if we roll back a deprecation, it is recorded here with
   the reason.

Non-breaking additions (new optional fields, new endpoints, new error codes) ship
without a deprecation window. Closed-schema endpoints reject unknown fields — do
not send fields you have not seen documented.

Subscribe via the page RSS feed (`/changelog/rss.xml` when published).

<Update
  label="2026-07-31"
  description="Cancel batch, introspection, dead-man, WS update"
  tags={["REST", "WebSocket", "Breaking"]}
  rss={{
title: "Cancel batch verb change, new introspection endpoints, dead-man, update_subscription",
description: "DELETE /v1/portfolio/orders/batch replaces POST cancel_batch; cancel-all rejects bodies; account/limits, retention, queue_position, deadman, and WS update_subscription ship."
}}
>
  ### Breaking — cancel batch verb

  Batch cancel moved off a separate POST path.

  | Before                                   | After                               |
  | ---------------------------------------- | ----------------------------------- |
  | `POST /v1/portfolio/orders/cancel_batch` | `DELETE /v1/portfolio/orders/batch` |

  Body unchanged: `{ "order_ids": ["…"] }` (≤ 20 decimal-string ids). Response is
  per-item, index-aligned; partial success is normal.

  `POST /v1/portfolio/orders/batch` remains batch **placement** only.

  **Affected:** any client still calling `…/cancel_batch`. Migrate before relying
  on production traffic — the old path is gone (no dual-write window; the route
  never had external consumers).

  ### Breaking — cancel-all empty body

  `DELETE /v1/portfolio/orders` **must** have an empty body. A non-empty body
  returns `400 unexpected_body` instead of cancelling. This prevents a misrouted
  batch-cancel (missing `/batch`) from wiping the book.

  **Affected:** `DELETE /v1/portfolio/orders` only.

  ### Round status vocabulary

  Round rows use: `trading`, `frozen`, `proposed`, `settled`, `void`. There is no
  `created` status on round objects.

  ### WebSocket channel inventory

  Live: `orderbook_delta`, `trades`, `user`, `oracle`, `rounds`.
  `ticker` is not implemented (subscribe → `wscode 4`).

  ### `exchange_active` honesty

  `GET /v1/exchange/status` always returns `exchange_active: true` in v1.
  Per-round freeze/settle is the operational pause — see
  [Pauses and rounds](/concepts/pauses-and-rounds).

  ### New introspection endpoints

  | Method | Path                                       | Purpose                               |
  | ------ | ------------------------------------------ | ------------------------------------- |
  | `GET`  | `/v1/account/limits`                       | Key scopes, rate buckets, batch cap   |
  | `GET`  | `/v1/exchange/retention`                   | Live-listing caps                     |
  | `GET`  | `/v1/portfolio/orders/{id}/queue_position` | Shares ahead                          |
  | `GET`  | `/v1/oracle/price`                         | Live reference price (now in OpenAPI) |
  | `GET`  | `/v1/rounds`, `/v1/rounds/{market_id}`     | Round history / one round             |

  ### Dead-man switch

  `POST /v1/portfolio/deadman` with `{ "timeout_ms": N }` (1000–60000) arms a
  gateway-side timer. Refresh by POSTing again. On fire: one user-wide cancel-all,
  then disarm. `DELETE /v1/portfolio/deadman` disarms without cancelling.

  This is **not** Kalshi-style order-group fill-velocity limiting — that remains
  deferred.

  ### WebSocket `update_subscription`

  ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
  { "id": 1, "cmd": "update_subscription",
    "params": { "sid": 3, "action": "get_snapshot", "market_ids": [1] } }
  ```

  Actions: `get_snapshot`, `add_markets`, `delete_markets`.

  ### 429 shape

  Rate limits answer with `details.retry_after_ms` in the error body. There is no
  `Retry-After` HTTP header.
</Update>
