Skip to main content
Monaco meters order entry at admission, before the matching engine:
  • Budgets are keyed to your account, not your IP or session; delegated agent sessions share the owning account’s budget.
  • Costs are counted in order items: a batch of N costs N, and is never partially admitted.
  • Two classes (order creation, risk reduction), each with a per-second and a per-minute window; a request must fit both.
  • Every account also shares a family budget (4× the account caps) with its master and sibling sub-accounts. The movement, settings-write and read budgets are tiered the same way.
  • Every other write that reaches the matching engine draws a budget of its own before it gets there: fund movements, settings writes, and the copy trading stops and closes (see Settings and copy trading writes).
  • The public authentication endpoints run before any account is known, and the public application reporting endpoints have no account at all, so both are metered per client address instead (see Authentication and Public application reads).

Current defaults

Order budgets are in items; the rest in requests. Every budget is per account except authentication and public application reads (per client address) and the WebSocket limits (per connection, or per account on each server instance). Values may be tuned per environment; the headers are authoritative for the order budgets.
ClassPublicPrivateLink
Per secondPer minutePer secondPer minute
Order creation50015,0002,00060,000
Risk reduction1,00030,0004,000120,000
The PrivateLink budgets apply to gRPC order entry from your own AWS VPC over PrivateLink. PrivateLink carries gRPC trading and WebSocket feeds but not REST. It is available on staging today, for a fixed monthly cost on request. Reach out to the Monaco team for details.
Budgets are enforced per API task, not fleet-wide, and both fleets autoscale (production: REST 1→10 tasks, gRPC 2→40), so an account spread across tasks can be admitted above the published figure. Movements, settings writes, follow stops, copy position closes, reads, and authentication return no headers; pace those by the Retry-After of a 429.

The two classes

  • reduceOnly never buys the larger budget: a reduce-only order you place draws order creation. Margin previews draw no order budget.
  • A position close costs one risk-reduction item, so spending your creation budget never stops you getting out. batch-close-all draws one item per open position it closes (an empty call draws one). The first 100 are charged before anything is sent: over budget, the whole call is refused with 429 and nothing is closed. Past 100 open positions the rest are charged 100 at a time, and those the budget does not cover are not sent: they come back in results with RATE_LIMIT_EXCEEDED, so call again after the interval.
  • Mass cancel costs one item per call: batch-cancel-all draws one item however many orders it cancels.
  • TP/SL attach costs one item per call, whether it carries a take-profit, a stop-loss, or both.
  • A batch over 100 items is rejected with 400 before any budget is drawn.

Account families

  • Every gated request must fit your account budget and the shared family budget (4×); a family-tier rejection says so in its message.
  • An account with no sub-accounts can never hit its family budget; a large family is bounded to 4× total.
  • Movements, settings writes and reads are tiered the same way: a per-account budget plus a family budget at the same multiplier, shared by the master and every sub-account.

Budget headers

Order endpoints, position closes and TP/SL attach included, return your live budget (movement, settings, copy trading, read, and authentication endpoints return none):
  • Keys are emitted lowercase; REST lookup is case-insensitive, gRPC metadata requires the lowercase form. On a 429 the headers report the class, window, and tier that denied.

When you are over budget

  • REST: 429, code RATE_LIMIT_EXCEEDED, Retry-After + details.retryAfter (seconds): a second for a spike, up to a minute for sustained overflow.
  • gRPC: RESOURCE_EXHAUSTED with a google.rpc.RetryInfo detail.
  • Honor the interval: exponential back-off with jitter, never a tight resubmit loop. Movements, settings writes, follow stops and copy position closes draw their own budgets and return the same contract.
  • Enforcement is gated. The order budgets (position closes included) and the movement budget (PitPass reward transfers and BuilderCodes payout claims included) are always measured, but reject only once order_rate_limit_enforced and movement_rate_limit_enforced respectively are turned on for the environment — both default off, and until then an over-budget request is admitted with a warn log. Stay inside the published budgets rather than waiting for a rejection to tell you.
  • A 429 is decided before the request reaches the matching engine, so nothing was applied: a throttled order, close, transfer or claim is safe to resend once the interval has passed.

Edge escalation

  • An IP that keeps flooding after repeated 429s is edge-blocked five minutes; again within ten minutes, an hour. The public REST and gRPC paths also share a per-IP volume guard, sized above what one account family can legitimately send under the published budgets above (not above whatever fan-out across API tasks may admit). Counters are per IP (and per Cloudflare data center) across every public environment host, so a flood against one environment blocks that address on the others too. PrivateLink traffic never passes the edge.
  • An edge block is a 429 with details.reason (edge_429_flood / edge_request_flood) and details.retryAfter, but no Retry-After header; gRPC sees a non-OK transport status (typically UNAVAILABLE or UNKNOWN), so treat those as throttling too. Blocks don’t shorten while you retry into them.

Resting-order caps

Separately from the rate windows, the matching engine caps how many orders one account keeps resting on the book:
  • A rest-capable order (a LIMIT that is not IOC/FOK) past a cap is rejected with 400 / INVALID_ARGUMENT, code ORDER_CAP_EXCEEDED; the message names the binding scope (market or account).
  • This is a book-state guard, not a rate limit: nothing to wait out. Fills and cancels free slots immediately.
  • MARKET and IOC/FOK orders never rest, so they are always exempt; you can always take liquidity to get out.
  • Replaces are exempt: a replace frees its own slot, so repricing at the cap always works.
  • batch-cancel-all is exempt from these resting-order caps and is the fastest way to free many slots. It is not unlimited overall: it still matches at most 20,000 orders — see Other limits.
  • Conditional (TP/SL) and TWAP orders keep their own dedicated caps and do not count here until they trigger onto the book.

Settings and copy trading writes

These writes each send one command to the matching engine and spend none of the order or movement budgets, so they have small per-account budgets of their own:
  • The settings burst covers following the most leaders one account may follow, one after another. Past it, pace writes at one per second.
  • The three budgets are separate. Edits never spend the stop budget and closes never spend it either, so you can always stop every follow you hold in a row.
  • Sub-accounts share a family settings-write budget (4×) with their master. Registering and following are master-account writes, and a master’s writes count toward that family budget too.
  • Enforced from the first request. Unlike the order, movement, read and authentication budgets, these have no warn-only phase: past the budget REST returns 429 with Retry-After (and details.retryAfter) and gRPC returns RESOURCE_EXHAUSTED with a google.rpc.RetryInfo detail. No budget headers are returned.
  • A request refused before the budget is reached — a delegated agent session, or a sub-account registering as a lead trader or following — spends nothing.

Reads

Every authenticated read costs one request from a per-account read budget:
  • Counts: signed REST GETs, the POST previews under /api/v1/margin/…/simulate-order-risk and POST /api/v1/copy-trading/follows/preview, and every gRPC Get* / List* / Simulate* plus CopyTradingService/PreviewFollow. Doesn’t: writes, public market data, the public application reporting endpoints (see Public application reads).
  • Delegated sessions share the owner’s budget; sub-accounts have their own read budget and share a family read budget (4×) with their master, so a family polling in parallel is bounded like one owner.
  • Over budget: same 429 / RESOURCE_EXHAUSTED contract, no headers, interval typically one second.
  • Enforcement is gated. Like the order, movement and authentication budgets, this one ships warn-only: until read_rate_limit_enforced is turned on for the environment — it defaults off — the limiter measures every read but admits an over-budget one with a warn log and returns no 429. Stay inside the published budget rather than waiting for a rejection to tell you.
The three simulate-order-risk previews and the copy trading follow preview (POST /api/v1/copy-trading/follows/preview, gRPC PreviewFollow) also draw a second, dedicated preview budget, one budget for all four, keyed on your account family like the other budgets on this page: delegated sessions share the owner’s budget, and sub-accounts share a family budget with their master. A preview runs inside the matching engine on a lane every user shares, so one client sweeping sizes can starve every other order form; the engine also gives each account family a share of that lane, and all four previews draw on the same share (a refusal there is a 503 / UNAVAILABLE to retry). This budget is measured today and ships warn-only: until order_risk_preview_rate_limit_enforced is turned on for the environment — it defaults off — an over-budget preview is admitted with a warn log. Once enforced, REST returns 429 with Retry-After (and details.retryAfter) and gRPC returns RESOURCE_EXHAUSTED with a google.rpc.RetryInfo detail; its values will be published here when enforcement turns on. Debounce order-form previews (the reference UI waits 500 ms and cancels an in-flight preview when the size changes) and never poll them. Prefer the WebSocket streams for anything you would otherwise poll; events cost no read budget.

WebSocket connections

Each server instance enforces these on its own connections; they are not shared across instances. Values may be tuned per environment. The default burst covers the full subscription cap plus headroom for an Authenticate and a few Pings, so adding a full subscription set one channel per Subscribe frame on an open connection stays within budget.
  • A channel past the subscription cap gets an Error frame with code SUBSCRIPTION_LIMIT naming that channel; the connection and its other subscriptions stay open.
  • An authentication past the connection cap gets an Error frame with code CONNECTION_LIMIT, and that connection closes. Close a connection you no longer need before opening another.
  • A channel string may be at most 128 characters of printable ASCII, excluding " and \; others get INVALID_SUBSCRIPTION.
  • The first frame past the frame or byte budget gets an Error frame with code MESSAGE_RATE_LIMIT; the connection then closes with 1008. Batch channels into few Subscribe frames and slow down before reconnecting. See Inbound message rate.

Authentication

POST /api/v1/auth/challenge and POST /api/v1/auth/verify (gRPC AuthService/Challenge and Verify) run before any account exists, so they are metered per client address (the connecting IP as Cloudflare sees it), not per account:
  • The two endpoints share one budget per address: 60 requests/min sustained, burst 120. A login (one challenge plus one verify) costs two; a scripted loop is held to one request per second.
  • Over budget: the same contract as above (REST 429 with Retry-After and details.retryAfter; gRPC RESOURCE_EXHAUSTED with a google.rpc.RetryInfo detail), decided before the signature is examined; a throttled request is never reported as an authentication failure.
  • Enforcement is gated. This budget ships warn-only: until auth_rate_limit_enforced is turned on for the environment — it defaults off — an over-budget request is admitted with a warn log and no 429 is returned. Stay inside the published budget rather than waiting for a rejection to tell you.
  • Every other authenticated call is unaffected. Keep a session alive with POST /api/v1/auth/refresh instead of re-authenticating, and reuse one session across your processes.
  • PrivateLink access carries no client address and is not metered here.

Public application reads

GET /api/v1/applications/{orders,users,movements,balances,stats} (gRPC ApplicationsService/ListAppOrders, ListAppUsers, ListAppMovements, ListAppBalances, GetAppStats) are public and select their application by clientId, so they are metered per client address (the connecting IP as Cloudflare sees it):
  • All five share one budget per address: 60 requests/min sustained, burst 120.
  • Over budget: REST 429 with Retry-After and details.retryAfter; gRPC RESOURCE_EXHAUSTED with a google.rpc.RetryInfo detail.
  • Always enforced. Unlike the budgets above, this one has no warn-only phase.
  • Walk a listing with the largest pageSize you can use (up to 1000) rather than many small pages.
  • PrivateLink access carries no client address and is not metered here.

Other limits

  • Batches take at most 100 items; cancel-all matches at most 20,000 orders; both reject with 400 and change no order (an over-cap cancel-all still costs its one item). See Batch Create.
  • New deposit-address registrations share a service-wide admission limit; re-registering an existing address is never limited. See Registered Deposit Addresses.
  • Trader code edits are bounded per rolling hour. See Trader Codes.
  • The testnet faucet enforces a daily quota per wallet and app. See Faucet.