Voisnap Docs
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

PolicyLimitWindowApplied to
auth-strict5 requests1 minute per IPLogin, MFA endpoints
auth-lenient3 requests1 minute per IPPassword reset, account unlock
api-standard120 requests1 minute per API keyMost REST endpoints
api-read-heavy300 requests1 minute per API keyList/search endpoints (GET)
api-write60 requests1 minute per API keyCreate/update/delete endpoints
webhook100 requests1 minute per tenantWebhook delivery per tenant
voice-hub10 connections1 minute per tenantVoiceHub SignalR connections
outbound-calls30 requests1 minute per API keyPOST /api/v1/outbound-calls
knowledge-base-upload10 requests1 hour per tenantDocument upload endpoint
analytics-export5 requests1 hour per API keyCSV/PDF report exports

Plan-based limits

Higher account tiers receive increased limits:

Planapi-standardapi-writevoice-hub connections/min
Starter60/min20/min5
Professional120/min60/min10
Business300/min120/min25
EnterpriseCustomCustomCustom

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
HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp when the window resets
X-RateLimit-PolicyPolicy 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());
AttemptDelay (base)With ±10% jitter
11s0.9s – 1.1s
22s1.8s – 2.2s
34s3.6s – 4.4s
48s7.2s – 8.8s
516s14.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 SessionEnded webhook event.
  • Monitor remaining headers. If X-RateLimit-Remaining drops 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.

On this page