Skip to main content

Rate Limits

The SuprSonic API implements rate limiting to ensure fair usage and maintain service quality for all users. Rate limits are applied per API key and vary based on your subscription plan.

Rate Limit Tiers

PlanRequests per MinuteRequests per HourBurst Limit
Free601,00010
Pro30010,00050
Business1,20050,000100
EnterpriseCustomCustomCustom
Admin API Keys have separate, higher rate limits for system operations.

Rate Limit Headers

Every API response includes rate limit headers to help you monitor your usage:
HTTP/1.1 200 OK
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 245
X-RateLimit-Reset: 1640995200
X-RateLimit-Retry-After: 3600
HeaderDescription
X-RateLimit-LimitMaximum requests allowed per window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetTimestamp when the rate limit resets
X-RateLimit-Retry-AfterSeconds until rate limit resets

Rate Limit Exceeded Response

When you exceed your rate limit, the API returns a 429 Too Many Requests response:
{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded. Please try again later.",
    "details": {
      "limit": 300,
      "reset": 1640995200,
      "retryAfter": 3600
    }
  }
}

Best Practices

1. Monitor Rate Limit Headers

async function makeApiRequest(url, options) {
  const response = await fetch(url, options);
  
  // Check rate limit headers
  const remaining = parseInt(response.headers.get('X-RateLimit-Remaining'));
  const reset = parseInt(response.headers.get('X-RateLimit-Reset'));
  
  if (remaining < 10) {
    console.warn(`Low rate limit: ${remaining} requests remaining`);
    console.warn(`Resets at: ${new Date(reset * 1000)}`);
  }
  
  return response;
}

2. Implement Exponential Backoff

async function apiRequestWithBackoff(url, options, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      
      if (response.status === 429) {
        const retryAfter = parseInt(response.headers.get('X-RateLimit-Retry-After')) || 60;
        const delay = Math.min(retryAfter * 1000, Math.pow(2, attempt) * 1000);
        
        console.log(`Rate limited. Waiting ${delay}ms before retry ${attempt}/${maxRetries}`);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      
      return response;
      
    } catch (error) {
      if (attempt === maxRetries) throw error;
      
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

3. Batch Requests Efficiently

// Good: Batch multiple items in single request
const articles = await createArticles([
  { title: "Article 1", content: "..." },
  { title: "Article 2", content: "..." },
  { title: "Article 3", content: "..." }
]);

// Avoid: Multiple individual requests
for (const articleData of articles) {
  await createArticle(articleData); // Each call counts against rate limit
}

4. Use Pagination Wisely

// Good: Reasonable page sizes
const articles = await getArticles({ limit: 50 }); // 1 request for 50 items

// Avoid: Too many small requests
const articles = [];
for (let page = 1; page <= 50; page++) {
  const response = await getArticles({ page, limit: 1 }); // 50 requests for 50 items
  articles.push(...response.data);
}

Implementation Examples

JavaScript Rate Limiter Class

class RateLimitedClient {
  constructor(apiKey, maxRequestsPerMinute = 60) {
    this.apiKey = apiKey;
    this.maxRequests = maxRequestsPerMinute;
    this.requests = [];
    this.baseUrl = 'https://www.suprsonic.com/api/v1';
  }

  async makeRequest(endpoint, options = {}) {
    await this.enforceRateLimit();
    
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      ...options,
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json',
        ...options.headers
      }
    });

    // Track request timestamp
    this.requests.push(Date.now());

    if (response.status === 429) {
      const retryAfter = parseInt(response.headers.get('X-RateLimit-Retry-After')) || 60;
      console.warn(`Rate limited. Waiting ${retryAfter} seconds...`);
      await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
      return this.makeRequest(endpoint, options); // Retry
    }

    return response;
  }

  async enforceRateLimit() {
    const now = Date.now();
    const oneMinuteAgo = now - 60000;
    
    // Remove old requests
    this.requests = this.requests.filter(time => time > oneMinuteAgo);
    
    // If at limit, wait
    if (this.requests.length >= this.maxRequests) {
      const oldestRequest = this.requests[0];
      const waitTime = 60000 - (now - oldestRequest);
      
      if (waitTime > 0) {
        console.log(`Rate limit reached. Waiting ${waitTime}ms...`);
        await new Promise(resolve => setTimeout(resolve, waitTime));
      }
    }
  }
}

// Usage
const client = new RateLimitedClient('your-api-key', 60);
const response = await client.makeRequest('/articles');

Python Rate Limiter

import time
import requests
from collections import deque
from typing import Optional

class RateLimitedClient:
    def __init__(self, api_key: str, max_requests_per_minute: int = 60):
        self.api_key = api_key
        self.max_requests = max_requests_per_minute
        self.requests = deque()
        self.base_url = "https://www.suprsonic.com/api/v1"
        self.session = requests.Session()
        self.session.headers.update({
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        })

    def _enforce_rate_limit(self):
        """Enforce rate limit before making request."""
        now = time.time()
        minute_ago = now - 60
        
        # Remove old requests
        while self.requests and self.requests[0] <= minute_ago:
            self.requests.popleft()
        
        # If at limit, wait
        if len(self.requests) >= self.max_requests:
            sleep_time = 60 - (now - self.requests[0])
            if sleep_time > 0:
                print(f"Rate limit reached. Sleeping for {sleep_time:.2f} seconds...")
                time.sleep(sleep_time)

    def make_request(self, endpoint: str, method: str = "GET", **kwargs):
        """Make a rate-limited API request."""
        self._enforce_rate_limit()
        
        url = f"{self.base_url}{endpoint}"
        response = self.session.request(method, url, **kwargs)
        
        # Track request
        self.requests.append(time.time())
        
        if response.status_code == 429:
            retry_after = int(response.headers.get('X-RateLimit-Retry-After', 60))
            print(f"Rate limited. Waiting {retry_after} seconds...")
            time.sleep(retry_after)
            return self.make_request(endpoint, method, **kwargs)  # Retry
        
        return response

# Usage
client = RateLimitedClient("your-api-key", max_requests_per_minute=60)
response = client.make_request("/articles")

Advanced Strategies

1. Request Queuing

class QueuedApiClient {
  constructor(apiKey, requestsPerSecond = 1) {
    this.apiKey = apiKey;
    this.interval = 1000 / requestsPerSecond;
    this.queue = [];
    this.processing = false;
  }

  async request(endpoint, options) {
    return new Promise((resolve, reject) => {
      this.queue.push({ endpoint, options, resolve, reject });
      this.processQueue();
    });
  }

  async processQueue() {
    if (this.processing || this.queue.length === 0) return;
    
    this.processing = true;
    
    while (this.queue.length > 0) {
      const { endpoint, options, resolve, reject } = this.queue.shift();
      
      try {
        const response = await fetch(`https://www.suprsonic.com/api/v1${endpoint}`, {
          ...options,
          headers: {
            'Authorization': `Bearer ${this.apiKey}`,
            ...options?.headers
          }
        });
        
        resolve(response);
      } catch (error) {
        reject(error);
      }
      
      // Wait before processing next request
      if (this.queue.length > 0) {
        await new Promise(resolve => setTimeout(resolve, this.interval));
      }
    }
    
    this.processing = false;
  }
}

2. Distributed Rate Limiting

For applications with multiple instances, consider using Redis for shared rate limiting:
const redis = require('redis');
const client = redis.createClient();

async function isRateLimited(apiKey, limit = 60) {
  const key = `rate_limit:${apiKey}`;
  const current = await client.incr(key);
  
  if (current === 1) {
    await client.expire(key, 60); // 1 minute window
  }
  
  return current > limit;
}

// Usage in your API client
if (await isRateLimited('your-api-key')) {
  throw new Error('Rate limit exceeded');
}

Monitoring and Alerts

Track Rate Limit Usage

class MonitoredApiClient {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.stats = {
      requests: 0,
      rateLimited: 0,
      lastReset: Date.now()
    };
  }

  async makeRequest(endpoint, options) {
    this.stats.requests++;
    
            const response = await fetch(`https://www.suprsonic.com/api/v1${endpoint}`, {
      ...options,
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        ...options?.headers
      }
    });

    if (response.status === 429) {
      this.stats.rateLimited++;
      console.warn(`Rate limited! Total rate limits: ${this.stats.rateLimited}`);
    }

    // Log usage every hour
    if (Date.now() - this.stats.lastReset > 3600000) {
      console.log(`Hourly stats: ${this.stats.requests} requests, ${this.stats.rateLimited} rate limits`);
      this.stats = { requests: 0, rateLimited: 0, lastReset: Date.now() };
    }

    return response;
  }
}

Enterprise Solutions

For high-volume applications, consider:
  • Dedicated API Keys: Higher rate limits for production environments
  • Custom Rate Limits: Tailored limits based on your usage patterns
  • Priority Support: Faster response for rate limit adjustments
  • Multiple API Keys: Distribute load across multiple keys with proper rotation
Contact our enterprise team to discuss custom rate limiting solutions for your specific needs.