The REST API enforces a per-key sliding-window quota. When a key exceeds it, the next request returnsDocumentation Index
Fetch the complete documentation index at: https://docs.kash.bot/llms.txt
Use this file to discover all available pages before exploring further.
429 RATE_LIMIT_EXCEEDED with Retry-After and X-RateLimit-* headers so you can back off cleanly.
Per-tier defaults
| Tier | Rate limit (req/min) | Daily spend cap | Per-trade cap | High-value confirm gate |
|---|---|---|---|---|
free | 60 | 1,000 USDC | 500 USDC | none |
developer | 300 | 10,000 USDC | 2,500 USDC | none |
enterprise | Custom (admin-set) | 100,000 USDC | 25,000 USDC | 25,000 USDC |
mm | Custom (admin-set) | 1,000,000 USDC | 50,000 USDC | 50,000 USDC |
- Rate limit — HTTP requests per minute, sliding window. Hit this and you get
429 RATE_LIMIT_EXCEEDED. - Daily spend cap — rolling 24h aggregate USDC volume per key. Hit this and you get
409 SPENDING_LIMIT_EXCEEDEDwithextensions.cap = "daily_volume". Sells and close-position intents do NOT draw against this cap. - Per-trade cap — single-trade USDC amount. Hit this and you get
409 SPENDING_LIMIT_EXCEEDEDwithextensions.cap = "per_trade". - High-value confirm gate — for tiers that have one, any trade ≥ this amount returns
202 Acceptedwith aconfirmationToken; you thenPOST /v1/trades/{id}/confirmto actually execute. Two-step flow lets you catch a runaway bot before it commits a six-figure trade.
user_id, not per individual key. If a single user holds two keys, HTTP requests across both share the quota — so issuing extra keys doesn’t multiply your throughput. The spending caps, however, are per key — each key gets its own daily allotment.
Each user can hold at most 5 active keys at a time (revoked keys don’t count). This guards against quota-pooling abuse patterns.
Why these caps exist
The caps are not punitive. Five concrete reasons:- Blast radius on key compromise. API keys leak — committed to git, dumped in error reports, laptop stolen. The cap bounds the loss between leak-time and revoke-time.
- Runaway-bot circuit breaker. A trading loop misfires (off-by-one in your sizing, retry storm on a timeout, missing dedup on a webhook). The cap is a hard stop you cannot disable from inside your own code.
- AMM stability. Kash markets use a Pythagorean AMM with thin per-outcome liquidity. A trade consuming more than ~5% of available liquidity moves the price substantially. Per-trade caps protect the AMM curve for everyone.
- Compliance ladder. Higher daily volumes implicitly require enhanced KYC, ToS attestation, and sanctions screening. The tier names map to that ladder.
- Delegation guardrails. API keys are a scoped delegation against the user’s Privy-managed smart account — Kash never holds the keys or the funds, but for the duration of the delegation a leaked key (or a runaway bot) can move balance up to whatever the smart account holds. Caps bound that blast radius. The user can revoke any key at any time; the cap is the runtime safety net while it’s active.
@kashdao/protocol-sdk) is the right product — you sign and submit every transaction yourself with your own signer/RPC/bundler, and bear the full operational risk. Both paths are non-custodial; this one just removes the platform-side guardrails along with the platform-side orchestration.
Response headers (every response)
Every response —200, 4xx, 429 — carries the live state of your bucket:
X-RateLimit-Limit— your configured quota for the window.X-RateLimit-Remaining— how many requests you can still send before the window resets.X-RateLimit-Reset— Unix epoch seconds whenRemainingrefills back toLimit.
429.
Hitting the limit
When you exceed the quota:Retry-After (seconds). The TypeScript SDK does this automatically with exponential backoff and jitter.
Algorithm
The rate limiter uses a sliding window for read paths (markets, portfolio, account, traces, webhooks list) and a token bucket for write paths (POST /v1/trades, POST /v1/trades/{id}/confirm).
- Sliding window — smooth, no burst. Best for sustained polling.
- Token bucket — allows short bursts (capacity = limit; refill = limit/60 per second). Best for human-driven actions.
user:{userId}.
Per-route rate limit policies
Most endpoints share the per-key tier quota. A few are tighter:| Endpoint pattern | Algorithm | Notes |
|---|---|---|
GET /v1/markets*, GET /v1/portfolio* | sliding-window | Standard tier quota. |
GET /v1/markets/{id}/quote | sliding-window | Standard tier quota; backed by RPC. |
POST /v1/trades, POST /v1/trades/{id}/confirm | token-bucket | Tighter — write paths cost more. |
POST /v1/webhooks/events/{id}/redeliver | token-bucket | Replay amplification cap (max 5 redeliveries per event). |
Best practices
- Read your headers. Cheaper than retry-after-rejection. Aim to keep
X-RateLimit-Remainingabove 10% ofX-RateLimit-Limitunder steady-state load. - Use ETags on read paths. A
304 Not Modifieddoesn’t count toward your quota — see ETags. - Use the SDK. It handles
Retry-After, exponential backoff, jitter, and idempotency-safe retries automatically. - Distribute across keys carefully. Rate-limit quota is per-
user_id, so multiple keys for the same user don’t help with HTTP throughput. (Spending caps ARE per-key.) If you need higher throughput, the upgrade path is below. - Don’t hammer the quote endpoint. Quotes are RPC-heavy. Cache results client-side for the freshness window your strategy can tolerate (typically 5–15s).
Kill switches
Independent from rate limiting, every route has an ops-controlled kill switch. When triggered (rare — usually during chain RPC degradation), the route returns:503 ROUTE_DISABLED like Retry-After — back off and retry. Most kill switches are toggled off within minutes.
How to upgrade your tier
HittingRATE_LIMIT_EXCEEDED or SPENDING_LIMIT_EXCEEDED repeatedly during normal operation means you’ve outgrown your tier — that’s the signal to upgrade. Today, every tier above free is provisioned manually:
free→developer(5× rate limit, 10× spending caps): email [email protected] with your account email and a one-line description of your use case. Self-serve via Stripe is on the roadmap; until it ships we provision developer-tier keys on a case-by-case basis.- Anywhere →
enterprise(25k/trade, custom rate limit): contact sales. Custom pricing based on volume commitment. - Anywhere →
mm(50k/trade, full counterparty terms): contact partnerships. KYB, ToS attestation, and possibly escrow arrangements — this is a relationship, not a pricing tier.
enterprise and mm tiers can override any of the four axes per-key as part of the contract — a key can have a different daily_spend_limit_usdc, per_trade_limit_usdc, or high_value_trade_threshold_usdc than the tier default.
Telemetry
Your per-key telemetry — including 24hrateLimitRejections count — is exposed via GET /v1/account/usage. If you’re seeing unexpected 429s, that’s the first place to check.
Next
Errors
The full RFC 7807 error format and code catalog.
ETags
If-None-Match short-circuits — free quota for unchanged data.