NAWA enforces per-minute rate limits on each API key to ensure fair usage and platform stability.
Tier table
| Tier | Requests/min | How you get it |
|---|
| Free | 10 | Free keys (nawa_test_sk_) |
| Growth | 120 | Live keys (nawa_live_sk_) with credits |
| Enterprise | 300 | Contact sales@trynawa.com |
| Enterprise+ | 1,000 | Contact sales@trynawa.com |
Free keys are rate-limited to 10 requests/minute and have a hard cap of 100 lifetime requests. Live keys start at the Growth tier (120/min). Enterprise tiers are available on request — contact sales@trynawa.com.
Every API response includes rate limit headers:
| Header | Description | Example |
|---|
X-RateLimit-Limit | Maximum requests allowed per minute for your tier | 120 |
X-RateLimit-Remaining | Requests remaining in the current window | 42 |
X-RateLimit-Reset | When the current window resets (RFC 3339) | 2025-01-15T12:01:00Z |
On 429 responses, additional headers are included:
| Header | Description | Example |
|---|
Retry-After | Seconds to wait before retrying | 8 |
X-NAWA-RateLimit-Reason | Which limit was hit | minute_limit or sandbox_exhausted |
Semantic cache and rate limits
Semantic cache hits (X-NAWA-Cache: HIT) do not count toward your rate limits. If you’re classifying similar comments repeatedly, caching effectively increases your throughput.
Handling 429 errors
Use exponential backoff with jitter to retry rate-limited requests:
async function classifyWithRetry(
nawa: Nawa,
params: ClassifyParams,
maxRetries = 3
) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const { data, error } = await nawa.classify(params)
if (!error) return data
if (error.type === 'rate_limit_error' && attempt < maxRetries) {
const baseDelay = Math.pow(2, attempt) * 1000
const jitter = Math.random() * 1000
await new Promise(resolve => setTimeout(resolve, baseDelay + jitter))
continue
}
throw error
}
}
Do not retry in a tight loop without backoff. This will extend your rate limit window and may result in longer delays.