# HTTP — overview

Production base URL: `https://production.mosaiq.0d.finance`.

REST endpoints under `/v1` return `{ status, data, server_time_ms }`. On success
`status` is `"ok"`; on a request-level failure `status` is `"error"` and
`data` is `{ code, msg }`. Successful `POST /v1/exchange` responses also include
`server_receive_time_ms`; request-level errors do not.
Responses are sent with `Cache-Control: no-store`.

Errors shared by every endpoint: an unknown path returns HTTP `404`
`not_found`, a wrong method `405 method_not_allowed`, a missing or
ill-typed query parameter `400 invalid_query`, and an unexpected failure
`500 internal_error`.

## Unauthenticated endpoints

| Endpoint | Description |
| -------- | ----------- |
| [`GET /v1/fees`](/api/fees) | Effective venue and Mosaiq fee rates. |
| [`GET /v1/clearinghouseState`](/api/clearinghouse-state) | Account state snapshot for a `user`. |
| [`GET /v1/openOrders`](/api/open-orders) | Live open-order snapshot for a `user`. |
| [`GET /v1/userFills`](/api/user-fills) | Confirmed fills, oldest first for WebSocket gap recovery or newest first for history views. |
| [`GET /v1/userFunding`](/api/user-funding) | Settled funding paid or received by a `user`. |
| [`GET /v1/portfolioHistory`](/api/portfolio-history) | Account value, cash and net deposits of a `user` over time. |
| [`GET /v1/liabilities`](/api/liabilities) | What Mosaiq owes its clients, for the proof of reserves. |
| [`GET /v1/points`](/api/points) | Venue points that a `user` earned, per period. |

## Authenticated endpoints

Trading requests use an API key. Key management, funding status, and
withdrawals use a Para JWT. The first Para-authenticated request creates the
Mosaiq account if the wallet is allowlisted.

```http
Authorization: Bearer <api-key or para-jwt>
```

| Endpoint | Auth | Description |
| -------- | ---- | ----------- |
| [`POST /v1/exchange`](/api/exchange) | API key (Para JWT for `withdraw`, either for `deposit`) | Place, modify, cancel, mass cancel, deposit and withdrawal requests. |
| [`GET /v1/rateLimits`](/api/rate-limits) | API key | Current usage and remaining capacity of your exchange request budget. |
| [`GET /v1/apiKeys`](/api/api-key) | Para JWT | The 20 most recent API keys with their status. |
| [`POST /v1/apiKeys`](/api/api-key) | Para JWT | Create an API key that expires at a chosen time up to 365 days away, 30 days by default. |
| [`DELETE /v1/apiKeys/{keyId}`](/api/api-key) | Para JWT | Revoke the named API key if it is still the wallet's unrevoked key. |
| [`GET /v1/funding`](/api/funding) | Para JWT | Recent deposit and withdrawal requests. |
| [`POST /v1/invitations/redeem`](#redeem-an-invitation) | Para JWT | Approve a wallet using an invitation. |

## Redeem an invitation

`POST /v1/invitations/redeem` accepts a Para JWT and a JSON body
`{ "code": "<invitation-code>" }`. The wallet does not need prior approval.
Send `X-Tessera-Wallet` when the JWT contains several EVM wallets.

Success returns HTTP `200` with
`data: { "activated": true, "alreadyApproved": false }`. Redemption approves
the wallet and creates its account. An already-approved wallet receives
`alreadyApproved: true` without consuming the supplied code.

| HTTP | Code | Meaning |
| --- | --- | --- |
| `404` | `invitation_not_found` | Invalid code. |
| `410` | `invitation_expired`, `invitation_disabled` | Code expired or was disabled. |
| `409` | `invitation_already_used` | Code was redeemed by another wallet. |
| `403` | `wallet_revoked` | Wallet access was revoked. |
| `429` | `rate_limited` | Redemption or HTTP budget exceeded. |

The default redemption budget is 5 requests per minute per wallet, separate
from the exchange budget. See the shared
[Para token and wallet-selection errors](/api/api-key#errors).

## Rate limits

| Limit | Value | Applies to |
| ----- | ----- | ---------- |
| HTTP requests | `600`/minute/IP | Every HTTP request, including WebSocket upgrades. |
| Exchange requests | `120`/minute/user | `POST /v1/exchange` and write WebSocket frames. One request or frame counts once regardless of batch size. Deposit and withdrawal actions count; `/v1/apiKeys` and `/v1/funding` do not. |
| API key creation | `10`/hour/wallet | `POST /v1/apiKeys`. Revoking a key does not count. |

Approved high-throughput users may receive a higher exchange budget. WebSocket
connection and message limits are listed on the
[user-data WebSocket](/api/websocket#rate-limits) page.

Budgets are token buckets: capacity refills continuously and a burst may spend
the whole budget at once. An exceeded limit returns HTTP `429` with
code `rate_limited`.

Use [`GET /v1/rateLimits`](/api/rate-limits) to read your exchange budget's
current usage and remaining capacity.

## Busy server

`GET /v1/userFills`, `GET /v1/userFunding`, `GET /v1/portfolioHistory`, and
`GET /v1/points` read the database on every request. The server runs a fixed
number of these reads at the same time, shared by all clients. A request that
waits too long for a free slot returns HTTP `503` with code
`public_reads_busy`.

This is load shedding by the server. It does not mean that you exceeded a rate
limit. The request still counts toward the HTTP limit of 600 requests per
minute per IP, so retry with exponential backoff and jitter.

```json
{
  "status": "error",
  "data": {
    "code": "public_reads_busy",
    "msg": "server is busy with other reads; retry with backoff"
  },
  "server_time_ms": 1790085600000
}
```
