API Limits and Constraints
Understand the current limits and constraints for the LigueLead API to optimize your integration and plan for scale.
🚦 Rate Limits
Current Limits
| Environment | Requests | Reset Period | Scope |
|---|---|---|---|
| Production | 600,000 requests | Per minute | Per API token |
| All Endpoints | Applies globally | 60 seconds | Sliding window |
| Concurrent Limit | 10,000 concurrent | Simultaneous | Per API token |
Important: Rate limits apply per API token. Exceeding these limits returns
429 Too Many Requests.
Rate Limit Headers
Every API response includes rate limit information:
HTTP/1.1 202 Accepted
X-RateLimit-Limit: 600000
X-RateLimit-Remaining: 599950
X-RateLimit-Reset: 1640995260
Content-Type: application/json📱 Phone Number Limits
Message Recipients
| Operation | Limit | Environment | Notes |
|---|---|---|---|
| Production | 10,000 numbers | Per request | Recommended for batch operations |
| Rate Consideration | 600,000 requests/minute | All environments | High throughput available |
Phone Number Format Support
Accepted Formats: All Brazilian phone number formats are supported
| Format | Example | Description |
|---|---|---|
| National | 11999999999 | 11 digits, recommended format |
| International | +5511999999999 | With country code prefix |
| DDI | 5511999999999 | 13 digits with country code |
Length Requirements:
- National: Exactly 11 digits
- International: 14 characters (including +55)
- DDI: Exactly 13 digits
Best Practice: Use national format (11 digits) for optimal compatibility and processing speed.
📁 File Upload Limits
Audio Files (Voice Messages)
| Specification | Limit | Recommended | Notes |
|---|---|---|---|
| File Size | 50 MB maximum | 5-10 MB | Faster upload and processing |
| Duration | No specific limit | Under 2 minutes | Better engagement rates |
Supported Audio Formats
| Format | Extension | Supported | Compatibility |
|---|---|---|---|
| MP3 | .mp3 | ✅ Supported | Universal compatibility |
| WAV | .wav | ✅ Supported | High quality, larger files |
| AAC | .aac | ❌ Not supported | Use MP3 or WAV instead |
| M4A | .m4a | ❌ Not supported | Use MP3 or WAV instead |
Important: Only MP3 and WAV formats are supported — other formats are rejected. The file's actual contents are checked against its extension: uploading a file whose bytes clearly belong to the other format (for example a WAV renamed to
.mp3) is rejected with415 Unsupported Media Type. Any file that is not decodable audio is rejected while it is being processed.
File Management
Audio File Deletion:
- No endpoint available for deleting uploaded audio files
- Files are retained permanently in your account storage
- Contact support if you need assistance with file management
Audio Optimization Tips
# Convert to supported format with FFmpeg
ffmpeg -i input.aac -f mp3 output.mp3 # Convert AAC to MP3
ffmpeg -i input.m4a -f wav output.wav # Convert M4A to WAV
# Optimize MP3 file
ffmpeg -i input.wav \
-ar 16000 \ # Sample rate: 16kHz
-ab 128k \ # Bit rate: 128kbps
-ac 1 \ # Mono channel
-f mp3 \ # MP3 format
output.mp3
# Check file info
ffprobe -v quiet -show_entries format=duration,size,bit_rate input.mp3💬 Message Content Limits
SMS Messages
LigueLead currently supports SMS Short only:
| Specification | Limit | Billing | Notes |
|---|---|---|---|
| Maximum Length | 1,600 characters | Variable billing | SMS Short format only |
| First SMS Part | Up to 160 characters | 1 SMS credit | Standard SMS length |
| Additional Parts | Every 152 characters | 1 SMS credit each | Auto-split for longer messages |
| Character Encoding | UTF-8 | Included | Full emoji and special character support |
| Language Support | Portuguese, English | Optimized | Optimized for Brazilian Portuguese |
SMS Billing Examples
Message: "Hello! Welcome to LigueLead API." → 33 chars = 1 credit
Message: "🎉 Promoção especial! 50% de desconto hoje!" → 44 chars = 1 credit
Message: 160 characters exactly → 160 chars = 1 credit
Message: 161 characters → 161 chars = 2 credits
Message: 312 characters (161 + 151) → 312 chars = 3 credits
Message: 1,600 characters maximum → 1,600 chars = ~11 credits
Voice Message Metadata
| Field | Limit | Purpose |
|---|---|---|
| Audio Title | 255 characters | File identification in uploads |
| Campaign Title | 255 characters | Campaign identification |
| Group Title | 255 characters | Group organization |
⏱️ Processing & Timeout Limits
Expected Processing Times
| Operation | Expected Time | Maximum Time | Notes |
|---|---|---|---|
| SMS Delivery | Information pending | Information pending | Depends on carrier network |
| Voice Delivery | Information pending | Information pending | Depends on file size and network |
| File Upload | 30 seconds - 2 minutes | 5 minutes | Depends on file size |
| API Response | < 2 seconds | 30 seconds | For standard requests |
Note: Delivery time information is being collected and will be updated soon with accurate metrics.
🔄 Retry Strategies & Error Handling
Recommended Retry Logic
import time
import random
from typing import Optional
class APIRetryHandler:
"""Robust retry handler for LigueLead API calls."""
def __init__(self, max_retries: int = 3, base_delay: float = 1.0):
self.max_retries = max_retries
self.base_delay = base_delay
def exponential_backoff(self, attempt: int) -> float:
"""Calculate delay with exponential backoff and jitter."""
delay = self.base_delay * (2 ** attempt)
jitter = random.uniform(0.1, 0.3) * delay
return delay + jitter
async def retry_request(self, request_func, *args, **kwargs):
"""Execute request with retry logic."""
last_exception = None
for attempt in range(self.max_retries + 1):
try:
response = await request_func(*args, **kwargs)
# Handle rate limiting
if response.status_code == 429:
if attempt < self.max_retries:
print(f"Rate limit hit, waiting 60 seconds... (attempt {attempt + 1})")
await asyncio.sleep(60)
continue
else:
raise Exception("Rate limit exceeded after max retries")
# Handle server errors (5xx)
elif 500 <= response.status_code < 600:
if attempt < self.max_retries:
delay = self.exponential_backoff(attempt)
print(f"Server error, retrying in {delay:.1f}s... (attempt {attempt + 1})")
await asyncio.sleep(delay)
continue
else:
raise Exception(f"Server error after {self.max_retries} retries")
# Success or client error (don't retry client errors)
return response
except Exception as e:
last_exception = e
if attempt < self.max_retries:
delay = self.exponential_backoff(attempt)
print(f"Request failed, retrying in {delay:.1f}s... (attempt {attempt + 1})")
await asyncio.sleep(delay)
else:
break
raise last_exception
# Usage
retry_handler = APIRetryHandler(max_retries=3)
response = await retry_handler.retry_request(api_call_function, data)📊 Concurrent Operations
Simultaneous Request Limits
| Operation Type | Recommended Limit | Hard Limit | Notes |
|---|---|---|---|
| File Uploads | 1000 concurrent | 10000 concurrent | Prevents system overload |
| Message Sending | 1000 concurrent | 10000 concurrent | Balance speed vs stability |
Concurrency Best Practices
import asyncio
import aiohttp
from asyncio import Semaphore
class ConcurrentAPIClient:
"""Manage concurrent API operations efficiently."""
def __init__(self, upload_limit: int = 3, send_limit: int = 5):
self.upload_semaphore = Semaphore(upload_limit)
self.send_semaphore = Semaphore(send_limit)
async def upload_audio_file(self, session, file_path, title):
"""Upload audio file with concurrency control."""
async with self.upload_semaphore:
# Your upload logic here
return await self._do_upload(session, file_path, title)
async def send_voice_message(self, session, voice_id, phones, title):
"""Send voice message with concurrency control."""
async with self.send_semaphore:
# Your send logic here
return await self._do_send(session, voice_id, phones, title)
async def batch_operations(self, operations):
"""Execute multiple operations concurrently."""
async with aiohttp.ClientSession() as session:
tasks = []
for op in operations:
if op['type'] == 'upload':
task = self.upload_audio_file(session, op['file'], op['title'])
elif op['type'] == 'send':
task = self.send_voice_message(session, op['voice_id'], op['phones'], op['title'])
tasks.append(task)
results = await asyncio.gather(*tasks, return_exceptions=True)
return results💾 Storage & Account Limits
Apps
| Resource | Limit | Notes |
|---|---|---|
| Active Apps per Client | 50 apps | Removing an app frees its slot immediately |
| App Name | 1–255 characters | Must be unique among your active apps |
Both limits apply only to active apps, so removing an app frees its slot and makes its name available for reuse. Creating an app above either limit returns 409 Conflict. See Managing Apps Programmatically to manage apps through the API.
Audio File Storage
| Resource | Limit | Notes |
|---|---|---|
| Storage per Account | 10 GB | Contact support for additional storage |
| Active Files | 1,000 files | Older files may be archived automatically |
| File Retention | 1 year | Files deleted after 365 days of inactivity |
| Upload History | 6 months | Upload logs retained for support purposes |
🚀 Optimization Best Practices
1. Efficient Batch Operations
Good Practice: Combine multiple recipients in single requests
# ✅ Efficient: Single request with multiple recipients
payload = {
"title": "Monthly Newsletter",
"message": "Check out our latest updates!",
"phones": ["11999999999", "21888888888", "31777777777"] # Up to 10k numbers
}Avoid: Multiple single-recipient requests
# ❌ Inefficient: Multiple requests for individual recipients
for phone in phones:
payload = {"message": "Hello", "phones": [phone]} # Wastes rate limit2. Audio File Reuse Strategy
class AudioFileManager:
"""Optimize audio file usage and storage."""
def __init__(self):
self.uploaded_files = {} # Cache uploaded file IDs
def upload_once_use_many(self, file_path, title, api_token, app_id):
"""Upload audio file once and reuse across campaigns."""
# Check if already uploaded
file_key = f"{title}_{hash(file_path)}"
if file_key in self.uploaded_files:
print(f"♻️ Reusing existing upload: {self.uploaded_files[file_key]}")
return self.uploaded_files[file_key]
# Upload new file
with open(file_path, 'rb') as audio_file:
files = {'file': audio_file}
data = {'title': title}
headers = {'api-token': api_token, 'app-id': app_id}
response = requests.post(
"https://api.liguelead.com.br/v1/voice/uploads",
headers=headers,
files=files,
data=data
)
if response.status_code == 201:
voice_id = response.json()['data']['id']
self.uploaded_files[file_key] = voice_id
print(f"✅ New upload successful: {voice_id}")
return voice_id
else:
raise Exception(f"Upload failed: {response.text}")
# Usage
audio_manager = AudioFileManager()
# Upload once
voice_id = audio_manager.upload_once_use_many(
"promo.mp3",
"Black Friday Promotion",
api_token,
app_id
)
# Use in multiple campaigns
campaigns = [
{"title": "VIP Customers", "phones": vip_numbers},
{"title": "Regular Customers", "phones": regular_numbers},
{"title": "New Prospects", "phones": prospect_numbers}
]
for campaign in campaigns:
send_voice_message(voice_id, campaign["phones"], campaign["title"])3. Rate Limit Optimization
import time
from collections import deque
class RateLimitManager:
"""Smart rate limit management to maximize throughput."""
def __init__(self, limit_per_minute: int = 600000):
self.limit = limit_per_minute
self.requests = deque()
def can_make_request(self) -> bool:
"""Check if we can make a request without hitting rate limit."""
now = time.time()
# Remove requests older than 1 minute
while self.requests and self.requests[0] <= now - 60:
self.requests.popleft()
return len(self.requests) < self.limit
def wait_for_slot(self):
"""Wait until we can make a request."""
while not self.can_make_request():
time.sleep(1)
def record_request(self):
"""Record that a request was made."""
self.requests.append(time.time())
def make_controlled_request(self, request_func, *args, **kwargs):
"""Make request with automatic rate limiting."""
self.wait_for_slot()
result = request_func(*args, **kwargs)
self.record_request()
return result
# Usage
rate_manager = RateLimitManager()
for campaign in large_campaign_list:
response = rate_manager.make_controlled_request(
send_sms_message,
campaign_data
)📈 Scaling Considerations
High-Volume Usage
When your integration needs exceed current limits:
Contact Support for:
- Higher Rate Limits: Custom limits for enterprise usage
- Dedicated Infrastructure: Isolated resources for large-scale operations
- Custom Integration: Tailored solutions for specific requirements
- Priority Support: Faster response times and dedicated assistance
🆘 Support & Escalation
When to Contact Support
Immediate Support Needed:
- Hitting rate limits regularly
- File upload failures
- Authentication issues
- Unexpected API behavior
Planning Support:
- Volume exceeding 500,000 daily API calls
- Storage approaching 8 GB
- Need for custom integrations
- Enterprise-level requirements
What to Include in Support Requests
-
Account Information
- API token (last 4 characters only)
- App ID
- Account email
-
Technical Details
- Current usage patterns
- Expected volume increase
- Specific limits being hit
- Error messages or response codes
-
Business Context
- Use case description
- Timeline requirements
- Integration complexity
Contact Methods
- Client Area: areadocliente.liguelead.app.br
- Priority Support: Available for enterprise customers
- Documentation: Always check latest docs first
🔮 Future Improvements
Planned Enhancements
Rate Limits:
- Burst allowances for peak usage
- Different limits by endpoint type
- Real-time usage dashboards
File Management:
- Automatic compression options
- CDN delivery for faster uploads
- Bulk file operations
Monitoring:
- Usage analytics and reports
- Predictive limit warnings
- Custom alerting systems
Enterprise Features:
- Dedicated API endpoints
- Custom rate limit profiles
- Advanced monitoring tools
- 24/7 premium support
Ready to scale? Contact our support team to discuss your requirements and find the right solution for your integration needs!
Updated about 22 hours ago
