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

# Limits and errors

> Every published limit with its scope, and the verbatim error strings, what each one means, and which ones are ours to fix.

This is the page to keep open during an incident.

<Info>
  Prerequisites: [Authentication](/authentication) and
  [Firms, participants and accounts](/identity) — most entries below
  resolve to one of those two sections or to a limit on this page. Limits are enforced per firm, so
  every process sharing your Client ID shares one budget.
</Info>

<Info>
  **API reference:** <a href="https://docs.polymarket.us/trader-guide/rate-limits" target="_blank" rel="noreferrer">Rate limits</a> · <a href="https://docs.polymarket.us/streaming-endpoints/error-handling" target="_blank" rel="noreferrer">Stream error handling</a>. Opens on the public documentation site in a new tab.
  Where it disagrees with this page, this page is authoritative for the partner surface.
</Info>

## Rate limits

<Note>
  **If you are an IB, this differs.**
  The **ledger CSV limit is what your reporting work hits first and hardest**, so size your
  export design against it before anything else — see [Reporting pack](/regulatory#reporting-pack).
  You also do not have FIX on the partner surface, so FIX session tiers do not apply to you
  whatever you have heard in a commercial conversation.
</Note>

Every limit we can state is in this section, with its scope. **This is the canonical source:** other pages quote a limit where it is relevant to what they are doing, and any number you find elsewhere in this space should agree with the row here. If one does not, this section wins — tell us, because the other page is wrong.

A limit without a scope is worse than no limit, because you size your fleet against it and then share it. Read the **Scope** column on every row before you size anything.

### REST

| Limit       | Unit               | Scope                                               | Error you get                | Preprod vs prod        |
| ----------- | ------------------ | --------------------------------------------------- | ---------------------------- | ---------------------- |
| 100 req/sec | one-minute average | **Per firm**, across every REST endpoint            | `429` carrying `Retry-After` | `VERIFY` **\[VERIFY]** |
| 20 req/sec  | per second         | **Per IP**, public (unauthenticated) endpoints only | `429` carrying `Retry-After` | `VERIFY` **\[VERIFY]** |
| \~5/min     | per minute         | **Per firm** — ledger CSV downloads                 | `VERIFY` **\[VERIFY]**       | `VERIFY`               |

### Per-endpoint query limits

These sit **below** the firm-wide REST ceiling: you can be inside 100 req/sec and still be limited here.

| Endpoint           | Limit | Unit    | Scope        | Preprod vs prod |
| ------------------ | ----- | ------- | ------------ | --------------- |
| `GetTradeStats`    | 60    | req/min | Per endpoint | `VERIFY`        |
| `ListInstruments`  | 6     | req/min | Per endpoint | `VERIFY`        |
| `ListSymbols`      | 6     | req/min | Per endpoint | `VERIFY`        |
| `GetOrderBook`     | 12    | req/min | Per endpoint | `VERIFY`        |
| `GetBBO`           | 12    | req/min | Per endpoint | `VERIFY`        |
| `SearchOrders`     | 12    | req/min | Per endpoint | `VERIFY`        |
| `SearchExecutions` | 12    | req/min | Per endpoint | `VERIFY`        |
| `SearchTrades`     | 12    | req/min | Per endpoint | `VERIFY`        |

<Warning>
  **Whether these per-endpoint budgets are per firm or per credential is not published.**

  Size against the pessimistic reading — one shared budget per firm — until your integration lead
  confirms otherwise.
</Warning>

<Note>
  The legacy summary table states "0.5–60 req/min" for query endpoints. **Nothing is documented at
  0.5/min.** The lowest real value is 6/min. If you built a 2-minute polling interval to respect a
  0.5/min figure, you are throttling yourself for no reason.
</Note>

### gRPC

| Limit                        | Unit                      | Scope                                                 | Error you get                                                               | Preprod vs prod |
| ---------------------------- | ------------------------- | ----------------------------------------------------- | --------------------------------------------------------------------------- | --------------- |
| 250 requests                 | per 60 s                  | **Per firm**, unary calls                             | `{"code":8,...}` — see [the endpoint rung](#the-undocumented-endpoint-rung) | `VERIFY`        |
| 100 messages/sec             | per second                | **Per firm**, ingress                                 | `VERIFY` **\[VERIFY]**                                                      | `VERIFY`        |
| Egress                       | —                         | Unlimited                                             | —                                                                           | Same            |
| 20 concurrent streams        | concurrent                | **Per firm**, across all gRPC subscriptions           | `VERIFY` **\[VERIFY]**                                                      | `VERIFY`        |
| ≤1000 instruments            | per stream                | **Per market-data stream**                            | `VERIFY`                                                                    | `VERIFY`        |
| `StreamRFQEvents` 1 open/sec | per second                | Stream establishment on that RPC                      | `VERIFY`                                                                    | `VERIFY`        |
| 50,000 messages              | per 60 s                  | `stream_message_rate_limit` — **scope not published** | `VERIFY`                                                                    | `VERIFY`        |
| 5 seconds                    | latency stopgap on orders | Orders                                                | Not a rejection; added latency                                              | `VERIFY`        |

<Warning>
  **The scope of the 50,000 / 60 s stream message limit is not published.**

  Do not plan a fan-out against it.
</Warning>

<Note>
  **20 concurrent streams is correct; the "10-connection limit" on the legacy streaming page is a
  leftover.** Both numbers appear on the same page today.

  Two consequences worth designing around: the **balance-ledger stream is per-account and counts
  against the 20**, so it cannot be run per participant, and passing an empty `symbols` list
  subscribes to every instrument, which collides with the 1000-per-stream cap. One partner ran 7,372
  subscriptions before being told the cap and had to re-architect in production.
</Note>

<Note>
  `/institutional/introduction` claims streaming has "No rate limiting concerns". That contradicts the
  100 msg/sec ingress cap above. There are rate limiting concerns.
</Note>

### The undocumented endpoint rung

There is a third rung below the firm and endpoint budgets above, and it was unknown even to our own support until a partner surfaced it. It returns a gRPC `code 8` with the delay in the message:

```json theme={null}
{"code":8,"message":"rate limit exceeded for /polymarket.v1.PositionAPI/ListAccountBalances (rung \"endpoint\"); retry after 126ms"}
```

Parse the `retry after` value from the message and wait at least that long. The rung name (`"endpoint"`) tells you the budget you hit, so log the full string.

<Warning>
  **The per-endpoint gRPC budgets behind this rung are not published.**

  Treat the message as the only source of the delay.
</Warning>

### Transfers

<Warning>
  **The `Transfer` rate limit is being confirmed and we are not publishing a number.**

  Three different figures are live in our own material today, including one that is a **global
  ceiling shared across all partners** rather than a per-firm budget. The difference matters: a
  shared ceiling means another partner's traffic can throttle yours, and you cannot size around it.

  Until this is settled: serialize your transfers, retry on failure with backoff, and tell your
  integration lead your required transfer rate so it can be sized against the real value.
</Warning>

### Not published yet

These are genuinely undocumented. They are listed here so you do not spend a day looking for them.

| Surface                                                                 | Status                                                                   |
| ----------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| KYC endpoints                                                           | No limit published **\[VERIFY]**                                         |
| `CreateVendorOrder`                                                     | No limit published **\[VERIFY]**                                         |
| `GetFundingAccountBalance`                                              | Guidance is "poll at modest rates" and nothing numeric **\[VERIFY]**     |
| Whether establishing or reconnecting a stream consumes the unary budget | Unanswered **\[VERIFY]**                                                 |
| Your own tier                                                           | **No self-service view exists.** Ask your integration lead **\[VERIFY]** |

<Note>
  `/trader-guide/order-management` promises per-operation order, cancel and modify limits. **Those
  limits do not exist** on the rate-limits page. Do not build against them.
</Note>

<Note>
  Retail limits (20 req/sec per API key) and institutional limits (100 req/sec per firm) sit on two
  unlabelled legacy pages, which reads as a 5× discrepancy. They are **two different products**. Yours
  is the institutional one — see [Environments and endpoints](/environments).
</Note>

### Backoff

1. **On `429`, honour `Retry-After`.** It is on the response. Do not retry sooner.
2. **On gRPC `code 8`, use the `retry after` value in the message** as your floor.
3. **Add jitter.** Every process under your Client ID shares one budget, so a fixed backoff makes your fleet retry in lockstep and re-hit the limit together.
4. **Cap concurrency, do not just retry.** The firm-wide REST budget is a one-minute average, so a burst that clears retries can still put you over the minute.
5. **Never re-mint a token in response to a rate limit.** `429` and `code 8` are not auth failures, and the token mint is itself a request.
6. **Never retry `CreateVendorOrder` with a new `idempotency_key`.** A new key is a new order, not a retry. Recovery is a byte-identical resubmit with the same key — see [Order lifecycle](/outcomes#order-outcomes).

<Note>
  **`Global Rate Limit Exceeded` does not arrive as an HTTP or gRPC error.** It comes back as an
  **execution-report rejection** on your order flow, so your HTTP layer sees success. Handle it in
  your execution-report consumer, not in your retry middleware. See [Error catalog](#error-catalog).
</Note>

## Error catalog

<Note>
  **If you are an IB, this differs.**
  Two failures are IB-only. **`HTTP 400` naming the participant type** on the administrative
  create path comes from a casing defect — see
  [Naming and record requirements](/regulatory#naming-and-record-requirements) for the canonical
  casing per path. And **onboarding that stalls with no error returned to you** is a DCO
  clearing-member ID used where a DCM firm name belongs; quote all three identity strings when
  you report it.
</Note>

A limit you hit above arrives as one of the strings below. Look the verbatim string up here before you retry. Several of these are not errors in your code, and three of them get worse if you retry naively.

Match on the **message string**, not on the status code alone. `PERMISSION_DENIED` and `403` are each raised for several distinct causes — a missing scope grant, a missing `x-participant-id`, `x-participant-id` sent on a firm-scoped call, and a firm entitlement that is not in place — and the code alone does not tell you which.

### Authentication and entitlements

| Error                                                                     | What it means                                                                             | What you do                                                                                                         |
| ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `PERMISSION_DENIED`, message names a missing required scope **\[VERIFY]** | The scope is not granted on your client, or your token was minted before the grant landed | Re-mint once. If it still fails, ask for the grant — [Scopes](/authentication#scopes-and-entitlements)              |
| `PERMISSION_DENIED` with no further detail                                | One of three causes: missing scope, missing `x-participant-id`, or a firm entitlement     | Run the three-test diagnostic on [Scopes](/authentication#scopes-and-entitlements)                                  |
| `PermissionDenied: method not permitted` (gRPC reflection)                | Server reflection is entitlement-gated                                                    | Generate stubs from the bundle — [Protos and SDKs](/environments#protos-and-sdks) — or ask for the reflection grant |
| `403 method not permitted` on `CheckoutAPI` / Aeropay                     | Those surfaces are **not entitled for ISVs**, by design                                   | Use wire deposits. Do not retry                                                                                     |
| `403`, message reports authorization denied **\[VERIFY]**                 | Token valid, the call is not permitted for this caller                                    | Check the header rule for that call first, then ask for the grant list                                              |
| `403 no ISV adapter found for ISV ID` **\[VERIFY]**                       | A server-side provisioning step for your firm is incomplete                               | **Ours.** Open a ticket with your firm names and the environment. Retrying will not help                            |
| `401` on every call, \~3 minutes after minting                            | A hardcoded 180-second token lifetime with no buffer                                      | Honour `expires_in` minus 30 s — [Authentication](/authentication)                                                  |
| `401` with valid preprod credentials against production                   | Keys, Client IDs and tokens are per environment                                           | Use the production pair                                                                                             |

### Identity and headers

| Error                                                                                                 | What it means                                                                                                                                               | What you do                                                                                                                                                                       |
| ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CROSS_ISV_PARTICIPANT_IMPERSONATION_ATTEMPT` (raised after `validateParticipantFirmOwnership` fails) | The firm segment of your `x-participant-id` is not your participant firm — usually built from `GET /v1/whoami`, which returns your **clearing-member** firm | Stop sending it. Use the `participantId` from `kyc.approved`, unmodified. Tell us in Slack, because this writes a CRITICAL security log against your firm — [Identity](/identity) |
| `INVALID_ARGUMENT` naming `participant_id` **\[VERIFY]**                                              | The participant ID is malformed — constructed, truncated, or carrying the wrong firm prefix                                                                 | Send the stored value verbatim; never assemble one                                                                                                                                |
| `403` on positions, reports, drop copy or the balance-ledger stream                                   | `x-participant-id` missing. Both stream surfaces are account-scoped, and the legacy examples build metadata with only `authorization`                       | Add the header                                                                                                                                                                    |
| `PERMISSION_DENIED` on a `CashMovementService` call                                                   | `x-participant-id` sent on a firm-scoped call                                                                                                               | Remove the header                                                                                                                                                                 |
| `invalid user` from `GET /v1/accounts?user=<participant>`                                             | Known gap: the parameter does not accept a participant ID that works in `x-participant-id`                                                                  | Use the `provisionedAccount` you captured at onboarding                                                                                                                           |
| `InvalidArgument: invalid account` from `GetAccountBalance`                                           | You passed a **participant clearing account**; the call succeeds for a firm account                                                                         | Known gap. Partners read the newest balance-ledger entry's `afterBalance` instead                                                                                                 |

### Rate-limit errors

| Error                                                                                                                                  | What it means                                                                                                    | What you do                                                    |
| -------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
| `429` with `Retry-After`                                                                                                               | A REST budget: 100 req/sec per firm, a per-endpoint budget as low as 6/min, or 20/sec per IP on public endpoints | Honour `Retry-After` with jitter — [Rate limits](#rate-limits) |
| `{"code":8,"message":"rate limit exceeded for /polymarket.v1.PositionAPI/ListAccountBalances (rung \"endpoint\"); retry after 126ms"}` | The undocumented per-endpoint gRPC rung. The rung name and the delay are both in the message                     | Wait at least the stated delay. Log the full string            |
| `Global Rate Limit Exceeded`                                                                                                           | **Arrives as an execution-report rejection, not an HTTP or gRPC error.** Your transport layer sees success       | Handle it in your execution-report consumer                    |

### Orders

| Error                                                                                                | What it means                                                                                                                                   | What you do                                                                                                                   |
| ---------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `InvalidArgument: order.time_in_force must be TIME_IN_FORCE_FILL_OR_KILL`                            | `CreateVendorOrder` accepts limit orders with `TIME_IN_FORCE_FILL_OR_KILL` and nothing else. Other values are rejected outright, not downgraded | Send `TIME_IN_FORCE_FILL_OR_KILL`                                                                                             |
| `ALREADY_EXISTS` on a resubmit                                                                       | The `idempotency_key` matched but the body differed. **This is the guard working**, not a fault                                                 | Resubmit byte-identically, or investigate why your body changed                                                               |
| gRPC `OK` with `status = REJECTED`                                                                   | An **exchange-level** rejection. It is not delivered as a gRPC error                                                                            | Branch on `VendorOrderStatus`, not on the gRPC status                                                                         |
| gRPC `OK` with `status = PENDING`                                                                    | **Indeterminate, not queued.** We could not confirm a terminal outcome, so the order state is genuinely unknown to us                           | Resubmit with the **same `idempotency_key`** and a byte-identical body. **Never mint a new key** — that places a second order |
| `OrderState` `EXPIRED(9)`                                                                            | A fill-or-kill order that never crossed. **Not a rejection, and it carries no reason by design**                                                | Expect this as your most common outcome in a thin book. Do not treat it as an error                                           |
| Missing `clord_id` rejection                                                                         | `order.clord_id` is **required** by the runtime on `CreateVendorOrder`. `PreviewOrder` ignores it                                               | Always set `clord_id`. Reflection advertised a schema without it for a period                                                 |
| `14 UNAVAILABLE`, message mentions participant token expiry and a violated reservation **\[VERIFY]** | The prefunding reservation behind the order could not be honoured                                                                               | Do not mint a new `idempotency_key`. Resubmit identically, and report it if it repeats                                        |

Order outcome handling in full is on [Order lifecycle](/outcomes#order-outcomes).

### Funding and cash movement

| Error                                                         | What it means                                                                                                                                                                                                                                                                                                          | What you do                                                                                                                      |
| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `NOT_FOUND: customer relationship claim failed`               | The customer relationship is established **server-side by KYC**, and there is no claim or link RPC in the protos to fix it from your side. Three root causes seen: a shared test SSN across users, an incomplete server-side setup step, and a half-provisioned firm that can read the pool but move nothing out of it | Check for SSN reuse first. If your SSNs are distinct, it is **ours** — open a ticket with the participant ID and the environment |
| A terminally-rejected transfer replays its rejection on retry | **A terminally-rejected `idempotency_key` replays its stored rejection.** An identical retry does not make a fresh attempt                                                                                                                                                                                             | Fix the cause, then use a **new** `idempotency_key`                                                                              |
| Status `AMBIGUOUS` on a cash movement                         | A non-terminal, non-confirmed outcome                                                                                                                                                                                                                                                                                  | Do not re-send. **\[VERIFY]** The `CashMovementStatus` enum and `rejection_reason` values are not defined anywhere; ask in Slack |
| Transfer rejected for decimal places                          | Transfers accept at most **2 decimal places**, while balances carry more (`172.395`, `1377.57275` observed)                                                                                                                                                                                                            | Round to 2 dp. There is no sanctioned handling for the residue                                                                   |

### Streams and transport

| Error                                               | What it means                                                                                                                                                                                                                                                                          | What you do                                                                                                                                                              |
| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `13 INTERNAL: Subscription manager revoked session` | The session is keyed on **caller identity** — token subject plus participant header — not on the accounts or symbols you requested. **\[VERIFY]** — what that keying does to a second subscription under the same identity is not published, so do not assume the two evict each other | Known workaround: pass an **explicit list of markets** on `CreateOrderSubscription`, which has no symbol cap on that path. Nine partners investigated this independently |
| `SocketError: other side closed`                    | The ALB's **10-minute** timeout closed the connection. gRPC streams bypass the API Gateway's 30-second idle timeout, so this is the next timeout out                                                                                                                                   | Reconnect and resume. Persist `resume_token` where the stream populates one                                                                                              |
| `RST_STREAM` **\[VERIFY]**                          | An HTTP/2 stream reset. We have not published the conditions that produce it                                                                                                                                                                                                           | Reconnect with backoff. Report it with timestamps if it is frequent                                                                                                      |
| `504`                                               | More than 30 seconds at the edge                                                                                                                                                                                                                                                       | For `POST /v1/report/trades/search`, add a symbol filter — see the next section                                                                                          |
| Missed messages after a reconnect                   | At-least-once delivery with snapshot-then-delta on subscribe. Only drop copy and position-change populate `resume_token`; instrument-state-change **declares it and never populates it**, and market data has no resume field at all                                                   | Dedupe on redelivery; do not use instrument-state-change as a replay source                                                                                              |

### KYC and provisioning

| Error                                                                                                                       | What it means                                                                                                                       | What you do                                                                                                                              |
| --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `{"code": 9, "message": "user already provisioned with a different SSN"}` returned as **HTTP 400** (not the documented 409) | One SSN maps to exactly one exchange account platform-wide. This user's SSN is already bound elsewhere                              | If it is a shared test SSN, stop and raise it — unpicking needs **manual database cleanup by us**. There is no re-KYC or PII-update path |
| `{"code":12,"message":"unknown service connamara.ep3.v1beta1.KYCAPI"}`                                                      | The service is not reachable on that target. Seen in preprod                                                                        | **Ours.** Report the environment and the full service name                                                                               |
| `decision: ACCEPT`, `status: CLOSED`, empty `participantId`                                                                 | Observed when a DocV session expires un-submitted. **This is a bug**, not a state to code against                                   | **Ours.** Report it; do not enable trading for that user                                                                                 |
| Empty `participantId` on an `ACCEPT`                                                                                        | Provisioning is still running. Gaps from \~500 ms to **26 minutes** observed                                                        | Wait for the `kyc.approved` webhook before enabling trading                                                                              |
| `subStatus` of `"In Review"`                                                                                                | A real value that is **not in the documented set** (`none` / `docv_required` / `pending`)                                           | Handle unknown `subStatus` values without throwing. Treat `decision`, `status` and `subStatus` as informational, not control flow        |
| `HTTP 400` naming the participant type                                                                                      | Casing defect: one path validates ISV **uppercase** and compares case-sensitively, while adopt and provision endpoints lowercase it | Try the other casing and report it. `introducing_broker` is unaffected                                                                   |

### Reference data and reports

| Error                                    | What it means                                                                                                                                                  | What you do                                                                   |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `InvalidArgument: field not allowed`     | You used `field_filter`, which validates against a fixed column allowlist that **excludes `update_time` and `create_time`**                                    | Use `where_clause` for any time cursor                                        |
| `Aborted` / `409` on a ledger query      | You requested a suppressed `LedgerEntryType`. Twelve internal types are not on the allowlist (`NETTING`, `GIVE_UP`, `INTEREST`, `SETTLEMENT_FEE`, …)           | Request only allowlisted types                                                |
| `504` on `POST /v1/report/trades/search` | Unfiltered, this call hits the 30-second CloudFront timeout about **two thirds** of the time. The same call with a symbol filter returns in \~130 ms, reliably | Always pass a symbol filter. There is no bulk-export path or async report job |
| `404` while paginating reports           | EOF behaviour on `nextPageToken` is a known defect                                                                                                             | Stop on an empty page rather than on a `404`                                  |

### Platform

| Error                                                                                                                       | What it means                                                                                                               | What you do                                                                         |
| --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `ResourceExhausted` with `market data snapshot admission rejected: heap_pressure heap_inuse=… soft_limit=… reject_pct=0.95` | A market-data snapshot admission guard. **This guard is wrong in every environment** — preprod is only where it was noticed | **Ours.** Retry with backoff and report it. There is nothing to change on your side |

### These are ours — open a ticket

Retrying will not fix any of these. Post in your shared Slack channel, tag the Polymarket side, and say whether it moves money.

* `403 no ISV adapter found for ISV ID` **\[VERIFY]** — incomplete provisioning of your firm.
* `NOT_FOUND: customer relationship claim failed` **when your SSNs are distinct** — an incomplete server-side setup step or a half-provisioned firm.
* `{"code": 9, "message": "user already provisioned with a different SSN"}` — needs manual database cleanup by us.
* `{"code":12,"message":"unknown service connamara.ep3.v1beta1.KYCAPI"}` — service not reachable.
* `13 INTERNAL: Subscription manager revoked session` — apply the explicit-market-list workaround, then report it.
* `ResourceExhausted … heap_pressure` — a guard that is wrong in every environment.
* `decision: ACCEPT` with `status: CLOSED` and an empty `participantId` — a bug.
* `HTTP 400` on the participant type — a casing defect on our side.

## What can go wrong

| Where       | Symptom                                                    | Cause                                                     | What you do                                                       |
| ----------- | ---------------------------------------------------------- | --------------------------------------------------------- | ----------------------------------------------------------------- |
| Rate limits | `429` at well under 100 req/sec                            | A per-endpoint budget (6–60/min), not the firm ceiling    | Check the per-endpoint table; slow that endpoint specifically     |
| Rate limits | `code 8` naming `rung "endpoint"`                          | The undocumented endpoint rung                            | Wait the stated delay; log the full message                       |
| Rate limits | Rate limits appear at random across your fleet             | One firm budget shared by every process on your Client ID | Centralize the call path or coordinate a client-side limiter      |
| Rate limits | Streams fail to open at 21 subscriptions                   | 20 concurrent streams per firm                            | Consolidate; the balance-ledger stream counts against the same 20 |
| Rate limits | Orders rejected in the execution report with no HTTP error | `Global Rate Limit Exceeded`                              | Handle it in the execution-report path                            |
| Rate limits | Transfers throttle unpredictably                           | A ceiling that may be shared across all partners          | Serialize and back off; report your required rate                 |

The verbatim string for each of these, and for every other error on the ISV surface, is in [Error catalog](#error-catalog).

<Snippet file="support.mdx" />

## Next

[KYC flow](/kyc)
