Skip to main content

Limits

Three different kinds of limit, and they fail differently. Knowing which one you hit tells you what to do about it.

KindBounded byWaiting helps?
Throughput — how fastYour tier's rate classYes
Per transaction — how bigAdmission policyNo: change the transaction
Volume — how much per monthYour plan's capNo: buy more

Rate classes​

Your tier carries a rate class, and the class is part of what you bought — it is stored on chain, not in a configuration file we can quietly change.

ClassUsed byRelay Units/s, sustained / burstGas/s per shard · burstMax gas limit per transactionRelay Units/h
1Starter1 / 1520 M · 200 M100 M300
2Builder5 / 2550 M · 600 M600 M600
3Growth, Agent Pro20 / 60100 M · 1,000 M600 M1,500
4Scale50 / 150150 M · 1,500 M600 M3,000
5Enterprise, Agent Fleet100 / 300200 M · 2,000 M600 M6,000
6Agent Metered2 / 1520 M · 200 M100 M300

These are launch values; they are published in the pricing document with a policy version and read from the chain as getRateClasses(). The backend's own configuration must be at or below the on-chain table — it can tighten during an incident without an owner transaction, and can never loosen beyond what the chain says.

DimensionError
Relay Units per secondRATE_LIMITED
Gas per second, per shardGAS_BUDGET_EXCEEDED
Relay Units per hourHOURLY_BURN_EXCEEDED
Above the class gas limitGAS_LIMIT_TOO_HIGH — permanent, not a rate limit

All limits are per account, never per sender. A sponsor key may impose tighter limits of its own on top.

Note that the burst capacity is never below the largest single transaction the class allows — 15 units for classes 1 and 6, 25 for classes 2 to 5. A bucket that could not admit a transaction the class permits would be a permanent, invisible refusal.

There is also a platform-wide admission budget. When it binds, you get RATE_LIMITED with details.scope = "platform" and there will be an incident: that one is ours, not yours.

Per-transaction ceilings​

LimitRuleError
Gas priceBetween the network minimum and twice itGAS_PRICE_OUT_OF_RANGE, with details.bound = min or max
Gas limit, lowerAt least the cost of moving the transactionGAS_LIMIT_TOO_LOW
Gas limit, upperThe class ceiling aboveGAS_LIMIT_TOO_HIGH
Data4,096 bytes on a self-serve accountDATA_TOO_LARGE
Over-provisioned gasWith simulation on, headroom above the simulated cost is boundedGAS_OVERPROVISIONED
Deploys and upgradesAllow-listed per accountDEPLOY_NOT_ALLOWED
Sender's balanceMust cover any value the transaction movesINSUFFICIENT_SENDER_BALANCE
Version and optionsAccepted forms only; the guarded bit is fineTX_VERSION_UNSUPPORTED, TX_OPTIONS_UNSUPPORTED
Unknown transaction membersRefusedUNSUPPORTED_TX_FIELD
Variant setsRefused outrightVARIANTS_NOT_SUPPORTED

The balance check deserves a word: a relayed transaction that fails because the sender cannot pay its own value still costs the relayer the whole fee. Checking it before co-signing is not paternalism; it is the difference between your mistake costing you one Relay Unit and costing us a fee for nothing.

In flight​

LimitValueError
Non-terminal intents per sender64TOO_MANY_IN_FLIGHT
Assignments10/s per IP; 2/s with a burst of 10 per senderRATE_LIMITED
Free-flow transactions in flight per sender1FREE_FLOW_BUSY
Free flag relays10 per 24 h, 30 per 30 days, per accountFREE_FLOW_BARRED

The free-flow limits cover the calls CoRelayer pays for on your behalf — buying a plan, setting flags, removing senders. They are generous enough to manage an account and tight enough that the free list is not a free relay service.

Request limits outside the relay path​

Route classKeyLimit
Public cached reads — pricing, relayers, status, incidents, network, account mirrors, intent statusIP20 req/s, burst 60
GET /v1/relay/{id}/eventsIP20 concurrent streams
POST /v1/quote, POST /v1/validateIP / account2 req/s per IP, 5 req/s per authenticated account
The prepare routesIP2 req/s, burst 10
x402 purchase routesIP / payer1 req/s per IP, 6 per minute per payer
Private readsaccount, by class5 / 10 / 20 / 40 / 80 / 10 req/s, burst ×4
GET /v1/streamaccount, by class2 / 3 / 5 / 10 / 20 / 2 concurrent streams; 5 per IP
Writes on keys, webhooks, notificationsaccount1 req/s, burst 5

quote and validate are limited tightly because validate can trigger a chain simulation — it is the most expensive public call on the API and the most useful, so it is protected rather than removed.

Sizes​

Request body131,072 bytes → PAYLOAD_TOO_LARGE
Transaction data4,096 bytes self-serve; more only by allow-list
Idempotency key16 to 128 visible ASCII characters
Purchase reference (ref)32 bytes
API keys per account10
relay_batch over MCP16 transactions
Page size1 to 200, default 50

Reading your own limits​

curl -sS https://api.co-relayer.com/v1/pricing
curl -sS https://api.co-relayer.com/v1/account/$ME/quota

Rate-limited responses carry RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset; a 429 carries Retry-After and details.retryAfterMs.

With one exception, which is the most important line on this page: QUOTA_EXHAUSTED is a 429 with no Retry-After, because waiting does not help. Buying does.

When a limit is the wrong limit​

If you are hitting a rate class repeatedly while your monthly cap is barely touched, the cap is not your constraint — the class is. Moving up a tier buys throughput as well as volume, and for bursty workloads that is usually the real reason to do it. (Tiers · Tiers for agents)