Understand rate limiting and optimize for high-volume usage
Understand rate limit information in response headers
Every API response includes rate limit information in the headers:
HTTP/1.1 200 OK X-RateLimit-Limit: 300 # Total requests allowed per window X-RateLimit-Remaining: 245 # Requests remaining in current window X-RateLimit-Reset: 1731585600 # Unix timestamp when limit resets X-RateLimit-Window: 60 # Window size in seconds Retry-After: 35 # Seconds to wait (only on 429 responses)
WAVE uses a sliding window algorithm, not a fixed window. This means your rate limit is calculated based on a rolling 60-second period, providing smoother rate limiting without sudden resets.
Each tier includes burst allowance (2x the per-minute limit) for handling short-term traffic spikes. Sustained high traffic will still be rate limited.
Proper retry strategies for rate-limited requests
429 Too Many Requests response with a Retry-After header indicating when to retry.async function makeRequestWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, options);
// Check rate limit headers
const remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0');
const limit = parseInt(response.headers.get('X-RateLimit-Limit') || '1');
// Log warning if approaching limit
if (remaining < limit * 0.1) {
console.warn(`Rate limit warning: ${remaining}/${limit} requests remaining`);
}
// Handle rate limit
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
if (attempt < maxRetries) {
console.log(`Rate limited. Retrying after ${retryAfter}s...`);
await sleep(retryAfter * 1000);
continue;
} else {
throw new Error('Max retries exceeded');
}
}
// Success
if (response.ok) {
return await response.json();
}
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
} catch (error) {
if (attempt === maxRetries) throw error;
// Exponential backoff for other errors
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
await sleep(delay);
}
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Usage
const data = await makeRequestWithRetry('https://api.wave.inc/v1/streams', {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
});Monthly quotas and overage handling
Track your current usage against quotas using the billing API:
GET https://api.wave.inc/v1/billing/usage
{
"period_start": "2025-11-01T00:00:00Z",
"period_end": "2025-11-30T23:59:59Z",
"usage": {
"streaming_minutes": 45320,
"storage_gb": 87.5,
"bandwidth_gb": 450.2,
"api_requests": 1245000
},
"quotas": {
"streaming_minutes": 100000,
"storage_gb": 100,
"bandwidth_gb": 1000,
"api_requests": null // null = unlimited
},
"usage_percentage": {
"streaming_minutes": 45.32,
"storage_gb": 87.5,
"bandwidth_gb": 45.02
},
"overage_charges": 12.50
}When you exceed monthly quotas:
You'll receive webhook notifications at 80% and 95% of quotas.