Rate Limits
Understand and handle API rate limits
nodestash uses a two-tier rate limiting system: daily limits and per-second burst limits. Both are enforced per workspace.
Rate Limit Tiers
| Plan | Daily Limit | Burst Limit | Price |
|---|---|---|---|
| Free | 1,000 requests | 5 req/s | $0 |
| Starter | 25,000 requests | 25 req/s | — |
| Pro | 250,000 requests | 50 req/s | — |
| Scale | 2,000,000 requests | 200 req/s | — |
| Enterprise | Unlimited | 500 req/s | Custom |
Daily limits reset at midnight UTC.
Response Headers
Every API response includes rate limit information:
| Header | Description | Example |
|---|---|---|
X-RateLimit-Limit | Daily request limit | 1000 |
X-RateLimit-Remaining | Remaining daily requests | 742 |
X-RateLimit-Reset | Unix timestamp when daily limit resets | 1706140800 |
X-RateLimit-Burst-Limit | Per-second burst limit | 5 |
X-RateLimit-Burst-Remaining | Remaining burst capacity | 3 |
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 742
X-RateLimit-Reset: 1706140800
X-RateLimit-Burst-Limit: 5
X-RateLimit-Burst-Remaining: 3
X-Request-Id: req_abc123def456ghi789jkl012Handling 429 Responses
When you exceed a rate limit, the API returns a 429 Too Many Requests response with a Retry-After header:
{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Per-second burst limit of 5 requests exceeded for the Free plan.",
"retry_after": 1,
"upgrade_url": "https://nodestash.io/pricing"
},
"meta": {
"request_id": "req_abc123def456ghi789jkl012"
}
}Implementing Retry Logic
# Check for 429 and use Retry-After header
response=$(curl -s -w "\n%{http_code}" \
https://api.nodestash.io/v1/contacts \
-H "Authorization: Bearer $NODESTASH_API_KEY")
status=$(echo "$response" | tail -1)
if [ "$status" = "429" ]; then
retry_after=$(echo "$response" | head -1 | jq -r '.error.retry_after')
echo "Rate limited. Retrying in ${retry_after}s..."
sleep "$retry_after"
fi// The SDK handles retries automatically.
// Configure max retries when initializing:
const client = new NodeStash({
apiKey: 'nds_live_...',
maxRetries: 3, // default: 3
})
// The SDK will:
// 1. Respect Retry-After headers
// 2. Fall back to exponential backoff
// 3. Retry up to maxRetries times
// 4. Throw RateLimitError if all retries fail
try {
const contacts = await client.contacts.list()
} catch (error) {
if (error instanceof RateLimitError) {
console.log(`Rate limited after all retries. Wait ${error.retryAfter}s`)
}
}SDK Auto-Retry Behavior
The TypeScript SDK automatically retries rate-limited requests with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 1,000 ms (or Retry-After value) |
| 2nd retry | 2,000 ms |
| 3rd retry | 4,000 ms |
The maximum backoff is capped at 10 seconds. After exhausting all retries, the SDK throws a RateLimitError.
Best Practices
- Monitor headers — track
X-RateLimit-Remainingto avoid hitting limits - Use bulk operations — where possible, batch your requests
- Cache responses — reduce redundant API calls
- Implement backoff — use exponential backoff on 429 responses (the SDK does this automatically)
- Upgrade your plan — if you consistently hit limits, consider upgrading