Getting Started
Rate Limits
Rate limit policies for all Voisnap API endpoints, 429 response format, and exponential backoff implementation.
Rate Limits
Voisnap applies rate limiting to protect platform stability and ensure fair usage. Limits vary by endpoint category and your account plan.
Rate limit policies
| Policy | Limit | Window | Applied to |
|---|---|---|---|
auth-strict | 5 requests | 1 minute per IP | Login, MFA endpoints |
auth-lenient | 3 requests | 1 minute per IP | Password reset, account unlock |
api-standard | 120 requests | 1 minute per API key | Most REST endpoints |
api-read-heavy | 300 requests | 1 minute per API key | List/search endpoints (GET) |
api-write | 60 requests | 1 minute per API key | Create/update/delete endpoints |
webhook | 100 requests | 1 minute per tenant | Webhook delivery per tenant |
voice-hub | 10 connections | 1 minute per tenant | VoiceHub SignalR connections |
outbound-calls | 30 requests | 1 minute per API key | POST /api/v1/outbound-calls |
knowledge-base-upload | 10 requests | 1 hour per tenant | Document upload endpoint |
analytics-export | 5 requests | 1 hour per API key | CSV/PDF report exports |
Plan-based limits
Higher account tiers receive increased limits:
| Plan | api-standard | api-write | voice-hub connections/min |
|---|---|---|---|
| Starter | 60/min | 20/min | 5 |
| Professional | 120/min | 60/min | 10 |
| Business | 300/min | 120/min | 25 |
| Enterprise | Custom | Custom | Custom |
Rate limit headers
Every API response includes headers indicating your current rate limit status:
HTTP/1.1 200 OK
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1718445660
X-RateLimit-Policy: api-standard
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
X-RateLimit-Policy | Policy name applied to this request |
429 Too Many Requests
When you exceed a rate limit, the API returns HTTP 429:
{
"type": "https://docs.voisnap.ai/errors/rate-limit-exceeded",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "You have exceeded the api-standard rate limit of 120 requests per minute. Please wait before retrying.",
"traceId": "trace_01HXMN8ZPQRST",
"retryAfter": 23
}
The Retry-After header (in seconds) is always included:
HTTP/1.1 429 Too Many Requests
Retry-After: 23
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1718445660
Exponential backoff
When you receive a 429, do not immediately retry. Use exponential backoff with jitter:
import time
import random
import voisnap
from voisnap.exceptions import RateLimitError
def call_with_backoff(fn, max_retries=5, base_delay=1.0, max_delay=60.0):
"""Call fn with exponential backoff on rate limit errors."""
for attempt in range(max_retries + 1):
try:
return fn()
except RateLimitError as e:
if attempt == max_retries:
raise
# Respect Retry-After if provided
if e.retry_after:
delay = e.retry_after
else:
# Exponential backoff: 1s, 2s, 4s, 8s, 16s
delay = min(base_delay * (2 ** attempt), max_delay)
# Add jitter (±10% of delay) to avoid thundering herd
jitter = delay * 0.1 * (random.random() * 2 - 1)
sleep_time = delay + jitter
print(f"Rate limited. Retrying in {sleep_time:.2f}s (attempt {attempt + 1}/{max_retries})")
time.sleep(sleep_time)
# Usage
client = voisnap.VoisnapClient(api_key="vsnp_live_...")
agents = call_with_backoff(lambda: client.agents.list())
import { VoisnapClient, RateLimitError } from '@voisnap/sdk';
async function callWithBackoff<T>(
fn: () => Promise<T>,
maxRetries = 5,
baseDelay = 1000,
maxDelay = 60000
): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (err) {
if (!(err instanceof RateLimitError) || attempt === maxRetries) throw err;
const delay = err.retryAfter
? err.retryAfter * 1000
: Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
// Add ±10% jitter
const jitter = delay * 0.1 * (Math.random() * 2 - 1);
const sleepMs = delay + jitter;
console.log(`Rate limited. Retrying in ${(sleepMs / 1000).toFixed(2)}s (attempt ${attempt + 1}/${maxRetries})`);
await new Promise(resolve => setTimeout(resolve, sleepMs));
}
}
throw new Error('Should not reach here');
}
// Usage
const client = new VoisnapClient({ apiKey: 'vsnp_live_...' });
const agents = await callWithBackoff(() => client.agents.list());
Recommended backoff schedule
| Attempt | Delay (base) | With ±10% jitter |
|---|---|---|
| 1 | 1s | 0.9s – 1.1s |
| 2 | 2s | 1.8s – 2.2s |
| 3 | 4s | 3.6s – 4.4s |
| 4 | 8s | 7.2s – 8.8s |
| 5 | 16s | 14.4s – 17.6s |
Best practices
- Batch requests where possible. Use filter params on list endpoints instead of making many individual GET requests.
- Cache agent and number data. Agent configuration rarely changes — cache it for 5–10 minutes.
- Use webhooks instead of polling. Rather than polling for conversation completion, listen for the
SessionEndedwebhook event. - Monitor remaining headers. If
X-RateLimit-Remainingdrops below 10, slow down proactively. - Use the SDK. Both the Python and JS SDKs automatically handle 429 responses with exponential backoff out of the box.