Rate Limits#
API rate limits, usage-based pricing, and platform-specific quotas.
API Rate Limits#
Rate limits are set per API key. Every key defaults to 100 requests/minute. You can set a custom rate limit (between 1 and 1,000 requests/minute) when creating or updating a key in the console under Settings → API Keys.
If you need more sustained throughput than a single key allows, contact us.
Pricing#
Pricing is usage-based, and there are no plans or tiers:
| Metric | Price |
|---|---|
| API calls | $0.01 per call |
| Storage | $1.00 per GB/month |
Every account receives a $10 free usage credit each month (roughly 1,000 API calls), effectively a free tier for development and small projects. For volume pricing or SLAs, contact us.
Rate Limit Headers#
Every response to an API-key request includes rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1705318260| Header | Description |
|---|---|
X-RateLimit-Limit | Max requests per minute for this key |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Rate Limit Response#
When rate limited:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
"error": "Rate limit exceeded",
"limit": 100,
"window": "1 minute"
}Platform Rate Limits#
Each messaging platform has its own rate limits:
WhatsApp Business#
| Tier | Messages/Day | How to Upgrade |
|---|---|---|
| Tier 1 | 1,000 | Start here |
| Tier 2 | 10,000 | Good quality |
| Tier 3 | 100,000 | Sustained quality |
| Tier 4 | Unlimited | High volume |
Quality Score: Affects tier progression
- User responses
- Block rate
- Spam reports
Instagram#
| Scope | Limit |
|---|---|
| Per user | 250 messages/24 hours |
| API calls | 200/user/hour |
Facebook Messenger#
| Scope | Limit |
|---|---|
| Per recipient | 250 messages/24 hours |
| API calls | 200/user/hour |
| Batch | 1000 messages/batch |
Telegram#
| Scope | Limit |
|---|---|
| Private chats | ~30 messages/second |
| Groups | Varies by size |
| Bot API | 30 requests/second |
| Bulk notifications | 25-30/second |
Slack#
| Scope | Limit |
|---|---|
| Web API | 1 request/second (tier 1-4) |
| Posting messages | 1/channel/second |
| Events API | No explicit limit |
Discord#
| Scope | Limit |
|---|---|
| Per channel | 5 messages/5 seconds |
| Per user DM | 5 messages/5 seconds |
| Global | Varies by endpoint |
SMS (Twilio)#
| Number Type | Limit |
|---|---|
| Long code | 1 message/second |
| Toll-free | 3 messages/second |
| Short code | 100 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 resetPlatform-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 += 1Best 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. Batch Where Possible#
Combine multiple operations into a single GraphQL request. One request with several fields costs one API call against your rate limit.
4. Monitor Usage#
Track the X-RateLimit-Remaining header to anticipate limit issues, and watch your usage in the console.
5. Plan for Spikes#
Account for traffic spikes in your rate limit strategy. Use separate API keys per service so a burst from one workload doesn’t starve the others.
6. Raise Per-Key Limits When Needed#
Set a higher rateLimitPerMinute on keys that legitimately need it (up to 1,000). For anything beyond that, contact us.
Webhook Rate Limits#
Delivery Rate#
Outeract delivers webhooks as fast as your server accepts them. If your server is slow:
- Webhooks queue up
- Delivery may be delayed
- 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