Skip to main content

Rate Limits

The Voicy API enforces rate limits to ensure fair usage and protect service stability.

Limits by Plan

PlanRequests/minuteConcurrent callsMax call duration
Standard601030 minutes
Enterprise60010060 minutes

Rate Limit Headers

Rate limit information is included in response headers:
HeaderDescription
X-RateLimit-LimitMaximum requests per minute
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when the limit resets

Handling Rate Limits

When you exceed the rate limit, you’ll receive a 429 Too Many Requests response:
{
  "error": "Rate limit exceeded. Please retry after 30 seconds."
}

Best Practices

When you receive a 429 response, wait before retrying:
async function requestWithBackoff(fn, maxRetries = 5) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.status === 429 && i < maxRetries - 1) {
        const waitTime = Math.pow(2, i) * 1000; // 1s, 2s, 4s, 8s, 16s
        await new Promise(r => setTimeout(r, waitTime));
        continue;
      }
      throw error;
    }
  }
}
Monitor your usage by checking the response headers:
const response = await fetch('https://api.voicy.co/v1/list-calls', {
  headers: { 'Authorization': `Bearer ${apiKey}` },
});

const remaining = response.headers.get('X-RateLimit-Remaining');
const resetTime = response.headers.get('X-RateLimit-Reset');

if (parseInt(remaining) < 10) {
  console.warn(`Only ${remaining} requests remaining until ${new Date(resetTime * 1000)}`);
}
For bulk operations, implement a request queue:
class RateLimitedQueue {
  constructor(requestsPerMinute = 60) {
    this.queue = [];
    this.interval = 60000 / requestsPerMinute;
    this.processing = false;
  }

  async add(fn) {
    return new Promise((resolve, reject) => {
      this.queue.push({ fn, resolve, reject });
      this.process();
    });
  }

  async process() {
    if (this.processing || this.queue.length === 0) return;
    this.processing = true;

    while (this.queue.length > 0) {
      const { fn, resolve, reject } = this.queue.shift();
      try {
        resolve(await fn());
      } catch (error) {
        reject(error);
      }
      await new Promise(r => setTimeout(r, this.interval));
    }

    this.processing = false;
  }
}

Concurrent Call Limits

The concurrent call limit applies to active calls (calls in initiated, ringing, or in_progress status). If you try to create a call when at the limit:
{
  "error": "Concurrent call limit reached. Please wait for existing calls to complete."
}

Increasing Limits

Need higher limits? Contact us at [email protected] to discuss Enterprise plans.