Rate Limits#

API rate limits and platform-specific quotas.

API Rate Limits#

By Plan#

PlanRequests/minuteRequests/dayBurst
Free6010,00010
Pro600100,000100
Business3,000500,000500
Enterprise6,000+Custom1,000

Rate Limit Headers#

Every response includes rate limit headers:

X-RateLimit-Limit: 600
X-RateLimit-Remaining: 599
X-RateLimit-Reset: 1705318260
HeaderDescription
X-RateLimit-LimitMax requests per window
X-RateLimit-RemainingRequests remaining
X-RateLimit-ResetUnix timestamp when limit resets

Rate Limit Response#

When rate limited:

HTTP/1.1 429 Too Many Requests
Retry-After: 60

{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded",
    "details": {
      "limit": 600,
      "reset_at": "2024-01-15T10:31:00Z"
    }
  }
}

Platform Rate Limits#

Each messaging platform has its own rate limits:

WhatsApp Business#

TierMessages/DayHow to Upgrade
Tier 11,000Start here
Tier 210,000Good quality
Tier 3100,000Sustained quality
Tier 4UnlimitedHigh volume

Quality Score: Affects tier progression

  • User responses
  • Block rate
  • Spam reports

Instagram#

ScopeLimit
Per user250 messages/24 hours
API calls200/user/hour

Facebook Messenger#

ScopeLimit
Per recipient250 messages/24 hours
API calls200/user/hour
Batch1000 messages/batch

Telegram#

ScopeLimit
Private chats~30 messages/second
GroupsVaries by size
Bot API30 requests/second
Bulk notifications25-30/second

Slack#

ScopeLimit
Web API1 request/second (tier 1-4)
Posting messages1/channel/second
Events APINo explicit limit

Discord#

ScopeLimit
Per channel5 messages/5 seconds
Per user DM5 messages/5 seconds
GlobalVaries by endpoint

SMS (Twilio)#

Number TypeLimit
Long code1 message/second
Toll-free3 messages/second
Short code100 messages/second

Handling Rate Limits#

Exponential Backoff#

import time
import random

def send_with_backoff(send_func, max_retries=5):
    for attempt in range(max_retries):
        try:
            return send_func()
        except RateLimitError as e:
            if attempt == max_retries - 1:
                raise

            # Exponential backoff with jitter
            delay = (2 ** attempt) + random.uniform(0, 1)
            time.sleep(delay)

Request Queuing#

For high-volume messaging:

import asyncio
from collections import deque

class RateLimitedQueue:
    def __init__(self, rate_per_second: float = 1.0):
        self.queue = deque()
        self.rate = rate_per_second
        self.last_request = 0

    async def enqueue(self, request):
        self.queue.append(request)
        await self._process()

    async def _process(self):
        while self.queue:
            now = time.time()
            wait_time = (1 / self.rate) - (now - self.last_request)

            if wait_time > 0:
                await asyncio.sleep(wait_time)

            request = self.queue.popleft()
            self.last_request = time.time()

            try:
                await request.execute()
            except RateLimitError:
                self.queue.appendleft(request)
                await asyncio.sleep(60)  # Wait for reset

Platform-Specific Handling#

class PlatformRateLimiter:
    LIMITS = {
        "whatsapp": {"per_second": 80, "daily": 1000},
        "telegram": {"per_second": 30},
        "slack": {"per_second": 1},
        "sms": {"per_second": 1},
    }

    def __init__(self, platform: str):
        self.limits = self.LIMITS.get(platform, {})
        self.window_start = time.time()
        self.request_count = 0

    def can_send(self) -> bool:
        now = time.time()

        # Reset window if needed
        if now - self.window_start >= 1:
            self.window_start = now
            self.request_count = 0

        # Check rate
        per_second = self.limits.get("per_second", float("inf"))
        return self.request_count < per_second

    def record_request(self):
        self.request_count += 1

Best Practices#

1. Respect Limits#

Always check rate limit headers and wait appropriately.

2. Implement Queuing#

Queue messages during high-volume periods instead of hitting limits.

3. Use Batch APIs#

Where available, batch multiple operations in one request.

4. Monitor Usage#

Track your API usage to anticipate limit issues:

query UsageStats {
  application {
    usage {
      messagesThisMonth
      apiCallsToday
    }
  }
}

5. Plan for Spikes#

Account for traffic spikes in your rate limit strategy.

6. Upgrade When Needed#

Contact sales for higher limits on Enterprise plans.

Webhook Rate Limits#

Delivery Rate#

Outeract delivers webhooks as fast as your server accepts them. If your server is slow:

  1. Webhooks queue up
  2. Delivery may be delayed
  3. Eventually, oldest events may be dropped

Recommendation#

Return 200 OK immediately and process asynchronously:

@app.post("/webhook")
async def webhook(request: Request, background_tasks: BackgroundTasks):
    body = await request.json()
    background_tasks.add_task(process_webhook, body)
    return {"received": True}  # Return immediately

Monitoring Rate Limits#

Check Current Usage#

query RateLimitStatus {
  rateLimitStatus {
    limit
    remaining
    resetAt
    percentUsed
  }
}

Set Up Alerts#

Configure alerts when approaching limits:

  • 80% usage warning
  • 95% critical alert
  • Rate limit hit notification