Skip to main content
Every authenticated route is rate-limited per minute. When you exceed the limit, the request is refused with 429 RATE_LIMIT_EXCEEDED, a Retry-After header and the X-RateLimit-* headers, so you can back off cleanly.

Limits set by your key’s tier

Your key’s tier sets its limits. Read the live values from the X-RateLimit-* headers and from the bodies of 409 and 429 refusals rather than hard-coding them. A tier sets four independent limits:
  • Request rate. Requests per minute. Exceeding it returns 429 RATE_LIMIT_EXCEEDED.
  • Per-trade cap. The USDC amount of one trade. A larger trade is refused at once with 409 SPENDING_LIMIT_EXCEEDED.
  • Daily spend cap. Total USDC bought through the key since 00:00 UTC. This is checked after the trade is accepted: a buy that would exceed it moves to rejected and fires a trade.rejected webhook. Sells do not count against it.
  • High-value confirmation. On tiers that have one, a trade at or above the threshold returns 202 Accepted with confirmation: { token, expiresAt }. Release it before expiresAt with POST /v1/trades/{id}/confirm. This gives your system a chance to stop a runaway bot before it commits a large trade.
There is also a cap on unfinished trades per account: a new trade while the account already has its tier’s maximum in flight is refused with 429 TRADE_IN_FLIGHT_LIMIT_EXCEEDED and a short Retry-After.

Who shares a quota

  • The request rate is counted per user, across every key that user holds, so extra keys do not add throughput. Each key is also counted on its own, with the same limit.
  • Spending caps are per key.
  • Read routes and write routes draw from separate budgets, each at the tier’s per-minute limit:
    • Read routes (every GET) use a sliding window: smooth, with no bursting.
    • Write routes (every rate-limited POST) use a token bucket: its capacity equals the limit and it refills continuously, so short bursts are allowed.
The endpoint reference shows each route’s class.

Response headers

Every rate-limited response, successful or not, carries the state of the budget closest to running out:
  • X-RateLimit-Limit: the per-minute limit.
  • X-RateLimit-Remaining: requests left before you are refused.
  • X-RateLimit-Reset: Unix time in seconds when the budget is full again.
Pace yourself from these rather than waiting for a 429.

Hitting the limit

Retry-After is computed for your bucket: the seconds until it admits another request. Always honour it. The TypeScript SDK does this automatically. If the rate limiter itself is briefly unavailable, requests are refused with 503 RATE_LIMIT_UNAVAILABLE and a short Retry-After. That is not a quota event; retry it.

Temporarily disabled routes

Separately from rate limiting, an individual route can be temporarily unavailable, returning 503 ROUTE_DISABLED with a Retry-After header. API trade writes can also be temporarily unavailable, returning 503 API_TRADE_PROCESSING_HALTED with a Retry-After header on trade creation and confirmation while reads keep working. Back off and retry in both cases.

Best practices

  • Read the headers and keep X-RateLimit-Remaining comfortably above zero under steady load.
  • Use conditional requests for polling. A 304 Not Modified still counts as a request, but it is cheap. See ETags.
  • Prefer webhooks to polling trade status.
  • Cache quotes briefly. Quote responses carry a short Cache-Control max-age.
  • Use the SDK. It honours Retry-After with exponential backoff and jitter, and sends an idempotency key on writes so retries are safe.

Upgrading your tier

Repeated RATE_LIMIT_EXCEEDED or SPENDING_LIMIT_EXCEEDED during normal operation means you have outgrown your tier:
  • free → developer: request it from the info button in the Kash web app → Feedback, with a one-line description of your use case.
  • enterprise: ask from the info button in the Kash web app → Feedback, or in Discord.
  • mm: ask from the info button in the Kash web app → Feedback, or in Discord.

Telemetry

GET /v1/account/usage (scope auth:manage) reports the calling key’s rate-limit rejections over the last 24 hours, among other figures:

Next

Errors

The RFC 7807 error format and code catalogue.

ETags

Conditional requests for cheap polling.