TRENDDocs
Guides

Rate limits and errors

What each route costs against its limit, what a 429 looks like, and every error the API returns.

Rate limits

Every route has a class, and each class has its own bucket per client address. The class of every operation is in the reference as x-rate-limit-class. A signed-in session draws from a larger bucket than an anonymous address, and there is a ceiling above both.

These are the proposed numbers per anonymous address, per minute, with the burst each bucket allows:

ClassRequests per minuteBurstUsed by
cheapRead600120Cached or single-row reads: launches, one launch, trades, chart, stats, transaction status
expensiveRead6020Chain scans, searches and aggregates: holders, search, wallet routes
quote12030POST /v1/trades/quote
build3010POST /v1/trades/build, POST /v1/transactions/submit
create10 per hour5POST /v1/launches/build-create
preview6020POST /v1/launches/preview

GET /healthz is not limited. The realtime stream has its own caps (realtime).

Dev observes, it does not refuse yet

On dev the limiter is in observe mode: requests are classified and counted, and none is refused. Treat the numbers above as the contract to write to, because enforcement is switched on after the counts are read. They are proposed values and may change before that.

A 429

{ "error": "Too many requests. Try again in 3 seconds.", "code": "rateLimited", "class": "quote", "retryAfter": 3 }

The response carries a Retry-After header and Cache-Control: no-store. Wait that long, then retry. A refused request never reaches its handler. If the shared counter is briefly unavailable, creation routes answer 503 with code: "limitsUnavailable" and a retryAfter; reads, quotes and builds keep working on a per-server bucket.

Behind a proxy, the limiter counts the client address the edge reports, so two people behind two proxies are two buckets. A forged forwarding header does not buy a new bucket.

Errors

Every refusal is a JSON object with a sentence in error. Some carry a code and fields you can act on.

StatusMeansDo
400Malformed. Usually a number where a base-unit string was required, or a repeated query parameter (code=badParam).Fix the request.
403Where the relay is restricted (on mainnet, which is not live yet), it sends only transactions this API built.Build the trade again.
404No such launch, quote, mint or signature.Look it up again.
409The launch is not in a state that accepts this.Read status. retryWhenMigrated: true means wait. opensAt is when a market opens.
410The quote expired.Quote again and build at once.
422Well formed, and cannot be satisfied. The message names the binding limit.Read it and adjust. retryWithNewQuote: true means quote again.
429Rate limited.Wait retryAfter seconds.
503A chain read failed upstream, or the relay is unavailable.Retry once, with a pause.

A 422 deserves real handling and not a generic "transaction failed". It carries the numbers: an amount below the minimum names that minimum and the decimals; a market that has not opened gives opensAt; a trade that cannot be expressed in one transaction is refused before a signature is requested, never after.

Error bodies never carry SQL, a stack, a hostname or a secret.

On this page