Rate Limits

Understanding API rate limits and how to optimize your integration.

Overview

The Heydeo 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.

💡 Tip: All API responses include rate limit headers to help you track your usage.

Rate Limit Tiers

PlanRequests/MinuteRequests/HourDaily Limit
Free101001,000
Starter601,00010,000
Professional3005,000100,000
EnterpriseCustomCustomCustom

Rate Limit Headers

Every API response includes these headers:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the current window
X-RateLimit-RemainingRemaining requests in the current window
X-RateLimit-ResetUnix timestamp when the rate limit resets
Retry-AfterSeconds to wait before retrying (only on 429 errors)

Example Response

HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1701525600

{
  "data": [...]
}

Handling Rate Limits

When you exceed the rate limit, the API returns a 429 Too Many Requests response:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1701525600
Retry-After: 30

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Please retry after 30 seconds.",
    "retry_after": 30
  }
}

JavaScript Example

async function makeRequestWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      
      // Log rate limit info
      console.log('Rate limit:', {
        limit: response.headers.get('X-RateLimit-Limit'),
        remaining: response.headers.get('X-RateLimit-Remaining'),
        reset: response.headers.get('X-RateLimit-Reset')
      });
      
      if (response.status === 429) {
        const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
        console.log(`Rate limited. Waiting ${retryAfter} seconds...`);
        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
        continue;
      }
      
      return await response.json();
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
    }
  }
}

Python Example

import time
import requests
from typing import Dict, Any

def make_request_with_retry(
    url: str,
    headers: Dict[str, str],
    max_retries: int = 3
) -> Any:
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)
        
        # Log rate limit info
        print(f"Rate limit: {response.headers.get('X-RateLimit-Remaining')}/{response.headers.get('X-RateLimit-Limit')}")
        
        if response.status_code == 429:
            retry_after = int(response.headers.get('Retry-After', 60))
            print(f"Rate limited. Waiting {retry_after} seconds...")
            time.sleep(retry_after)
            continue
        
        response.raise_for_status()
        return response.json()
    
    raise Exception("Max retries exceeded")

Best Practices

  • 📊 Monitor rate limit headers - Check remaining requests before making calls
  • 🔄 Implement exponential backoff - Wait progressively longer between retries
  • 💾 Cache responses - Reduce API calls by caching frequently accessed data
  • 📦 Batch requests - Use bulk endpoints when available to reduce request count
  • ⏱️ Respect Retry-After - Always wait the specified time before retrying
  • 🎯 Use webhooks - Receive push notifications instead of polling
  • 📈 Upgrade when needed - Consider a higher tier if limits are constraining

Rate Limit Strategies

Token Bucket Algorithm

Heydeo uses the token bucket algorithm for rate limiting. This allows for short bursts of traffic while maintaining an average rate over time.

Request Queuing

Consider implementing a client-side queue for managing API requests:

class RateLimitedQueue {
  constructor(requestsPerMinute) {
    this.queue = [];
    this.processing = false;
    this.interval = 60000 / requestsPerMinute;
  }

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

  async process() {
    if (this.processing || this.queue.length === 0) return;
    
    this.processing = true;
    const { requestFn, resolve, reject } = this.queue.shift();
    
    try {
      const result = await requestFn();
      resolve(result);
    } catch (error) {
      reject(error);
    }
    
    setTimeout(() => {
      this.processing = false;
      this.process();
    }, this.interval);
  }
}

// Usage
const queue = new RateLimitedQueue(60); // 60 requests per minute
const result = await queue.add(() => fetch('https://api.heydeo.ai/v1/shipments'));

Checking Your Usage

Get your current rate limit status:

GET https://api.heydeo.ai/v1/rate-limit

Response:
{
  "limit": 60,
  "remaining": 45,
  "reset": 1701525600,
  "period": "minute"
}

Enterprise Plans

Need higher rate limits? Enterprise plans offer custom rate limits tailored to your needs:

  • Custom request limits (up to 1000+ requests/minute)
  • Dedicated API endpoints
  • Priority support with guaranteed response times
  • SLA guarantees
  • Dedicated account manager
Contact sales for enterprise pricing →

Frequently Asked Questions

Are rate limits per API key or per account?

Rate limits are applied per API key. If you need more capacity, you can create multiple API keys or upgrade your plan.

Do webhook deliveries count against rate limits?

No, webhook deliveries from Heydeo to your endpoint do not count against your API rate limits.

What happens if I consistently exceed rate limits?

Consistent rate limit violations may result in temporary throttling or account review. We recommend upgrading to a higher tier if you regularly hit limits.

Can I request a temporary rate limit increase?

Yes, contact support at support@heydeo.ai with your use case.