> For the complete documentation index, see [llms.txt](https://docs.nexus.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nexus.xyz/api-reference/guides/known-gaps.md).

# Known Gaps

Gaps and inconsistencies in the API contract, flagged rather than filled.

**This page is a list of things the contract does not say.** The endpoint pages in the Reference section are generated from `openapi.json` and describe exactly what the contract declares — no more. Where the contract is silent, ambiguous, or internally inconsistent, that is recorded here instead of being papered over with plausible prose.

Read it before building against an operation whose behaviour you are inferring rather than reading.

Each item names the surface it belongs to. Nothing here is a roadmap commitment; these are observations about the contract as it stands.

**Baseline verified against spec `0.9.78`, and every entry below is re-checked on each spec bump** by `.github/scripts/known_gaps_check.py`. Each entry registers a predicate against the contract in `known-gaps-assertions.json`; when a predicate stops holding, the gap has been filled and CI fails until the entry is removed. Entries that assert something about prose rather than structure are marked hand-verified and carry the spec version they were last read against, which the same gate requires to keep up.

A gap list that is itself stale is worse than no gap list, and between `0.9.27` and `0.9.63` this one had become that: eight entries were wrong, three of them describing gaps the contract had already closed. That is why the checking is now mechanical rather than a promise to re-read.

## Trading

* **Batch limits.** No maximum batch length is declared for `POST /orders/batch`, and the contract does not say how a batch is weighted against the rate limit (one request, or one per element).
* **`reduce_only`.** Declared as a boolean with no description. Its interaction with the conditional and trailing order types is unspecified.
* **`PreviewResponse` field semantics.** The eight fields are typed but carry no descriptions in the contract.
* **Trigger direction.** "Adverse" and "favorable" are not formally defined per `side` for the stop and take-profit families.
* **Time-in-force × conditional types.** The contract does not state which `time_in_force` values are valid for the six conditional order types (for example `PostOnly` on a `StopMarket`).
* **Amendability.** Beyond "liquidation orders are not amendable", the contract does not say whether conditional or trailing orders can be amended, or whether an amend may change `time_in_force`.
* **`stop_price` removal.** Marked deprecated with no stated removal version or date.

## Positions

* **`leverage` is permanently `null` today.** The contract states it is "currently always `null`" with `leverage_error: "margin_state_not_mirrored"`, and gives no target for populating it. Clients cannot read per-position leverage from this surface.
* **No per-market filter on closed positions.** `GET /positions/closed` accepts only `limit` and `cursor`; there is no way to scope the query to a single market. Neither `market_id` nor `symbol` is accepted — the response field was renamed to `symbol` at `0.9.74` and the parameter was never there under either name.
* **Retention window unstated.** `funding_paid` is documented as "bounded by the funding history the indexer retains", but no retention period is given. Cursor pagination on this surface is no longer part of this gap: `GET /positions/closed` documents a 200-record retained window on `limit`.
* **`429` missing on closed positions.** `GET /positions/closed` and its `/api/v1` twin declare only `200` and `401`; the `429` response the other position operation declares is absent from the contract even though the same rate-limit layer applies.
* **Cross-margin only.** `initialMargin` is defined "under the engine's cross-margin model", and the contract notes isolated/custom margin allocations are not mirrored by the indexer — so an isolated-margin position's true allocation is not readable here.
* **No open-position count or total.** The response is a bare array with no envelope and no pagination on `GET /positions`, so there is no documented bound on how many positions a single response may carry.

## Account

* **`direction` is not enumerated.** `POST /account/margin` declares no request schema at all. Its example shows `"direction": "add"`, and the summary and `400` description imply removal is supported, but the contract never states the value for removal. Nor does it name the field types or mark any field required.
* **Two operations declare no request schema.** `POST /account/deposit` and `POST /account/margin` carry request examples only, so clients generated from the contract get untyped request bodies for both. Their responses are typed (`DepositResponse`, `AdjustMarginResponse`); it is the request side that is undeclared.
* **Two overlapping deposit paths.** `POST /account/deposit` and `POST /deposits` both deposit collateral and both return `DepositResponse`, and the contract does not say which to prefer or how they differ operationally. The responses agreeing makes the choice harder to reason about rather than easier: there is not even a difference in the returned shape to tell them apart by.
* **Status vocabularies disagree.** `Withdrawal.status` is `pending` / `settled` / `failed`; `FundsEntry.status` is `pending` / `submitted` / `confirmed` / `failed`. The same lifecycle is named two ways and cut into a different number of stages, so no total mapping exists between them: `submitted` has no counterpart on `Withdrawal`, and `settled` has none on `FundsEntry`.
* **Rate-limit tier casing is inconsistent.** `RateLimitStatus.tier` is documented lowercase (`pro`, `marketmaker`, `unlimited`); the `429` body example returns `"tier": "Pro"`; the admin tier-management operations use `MarketMaker` and `Pro`. The contract does not state a canonical casing.
* **`429` coverage is uneven.** Several operations that are subject to the same rate-limit layer declare only `200` and `401` — both equity-history operations, both order-history operations, both cancel-on-disconnect GETs and PUTs, `GET /withdrawals`, `GET /deposits`, `POST /deposits`, `GET /orders/{order_id}`, and both rate-limit-status operations.
* **Retention windows are a record count, not a duration.** Each operation now states the size of its retained window — 1,000 fills, 500 order-history records, 200 closed positions, 720 equity points, 10,000 trades — but no operation says how far back in time that reaches, so a client cannot tell whether a walk covers a week or a year. `volume_30d` undercounting is no longer part of this gap: `volume_30d_estimated` states which guarantee applies.
* **`limit` maximums are lower than the prose in two places.** `GET /withdrawals` and `GET /deposits` both cap `limit` at 100 with a default of 100, so the parameter can only reduce the page — there is no way to page past 100 records (neither operation accepts a `cursor`).
* **`EquityPoint.equity` is a JSON number.** Every other monetary field in this tag is a lossless decimal string. The contract itself notes the mismatch against `PortfolioPoint.equity` and tells clients to compare by decimal value, but the float representation remains on the wire.
* **`early_access_allowed` is present-or-absent, not true-or-false.** The contract says it appears "only when the early-access gate is active" without stating what governs the gate or what its absence means for a caller.
* **No per-account tier or discount program.** `AccountFees.tier` is always `base`, `discounts` is always empty, and `FeeDiscount` has no defined properties. Per-market effective rates for markets represented in the currently retained fill buffer ship in `markets`; absence is not lifetime-trading evidence. Callers still must treat `schedule` as an open string and distinguish `per_market`, `reference`, and the zero-valued `unknown` sentinel.
* **`Position.leverage` is permanently `null` today** on every response that embeds a position (`AccountSummary`, `AccountState`), with `leverage_error: "margin_state_not_mirrored"`. See [`GET /positions`](/api-reference/positions/fetch-positions.md).

## Admin

* **Tier names are not enumerated.** No schema, no `enum`, no list. Only `MarketMaker` appears as an example here, and `pro` / `marketmaker` / `unlimited` appear prose-only in the `RateLimitStatus` description. An operator cannot learn the valid set from the contract.
* **Casing is inconsistent across the contract.** These operations use `MarketMaker` and `Pro`; `RateLimitStatus.tier` is documented lowercase (`pro`, `marketmaker`, `unlimited`); the shared `429` body example returns `"tier": "Pro"`. The contract does not state which casing is canonical or whether the comparison is case-insensitive.
* **No request schemas, and one response with none.** None of the three operations declares a request schema, so clients generated from the contract get untyped request bodies throughout. `GET` and `PUT /admin/tiers` do declare `200` response schemas; `DELETE /admin/tiers/{address}` does not.
* **`404 Address not in allowlist` on delete, but no allowlist elsewhere.** `DELETE /admin/tiers/{address}` returns `404` when the address is "not in allowlist", while `PUT /admin/tiers` documents no allowlist precondition and `GET /admin/tiers` describes its result as "overrides". The relationship between the override store and an allowlist is unstated.
* **No `401`, no rate limiting declared.** These operations declare only `200`, `403`, and (on delete) `404`. There is no documented behaviour for a malformed `Authorization` header distinct from a wrong secret, and no rate-limit response — a bearer secret with no declared throttle.
* **No audit trail on the surface.** Nothing in the contract exposes who set a tier or when. `GET /admin/tiers` returns the current state only.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.nexus.xyz/api-reference/guides/known-gaps.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
