Rate Limiting
La API de MasLeads implementa límites de velocidad para garantizar un servicio estable y justo para todos los usuarios.
Límites por Defecto
Los siguientes son los valores por defecto. Pueden variar según tu plan contratado.
| Tipo de Límite | Valor por defecto | Alcance |
|---|---|---|
| Requests por minuto | 300 | Por empresa |
| Jobs concurrentes | 10 | Por empresa |
| Leads por job | 100 | Por request |
| Burst máximo | 50 | Requests instantáneos |
Nota: Estos límites son configurables según el plan contratado. Contacta con nuestro equipo comercial si necesitas valores diferentes.
¿Qué significa "por empresa"?
Los límites se aplican a nivel de empresa, no de API Key individual. Si tienes 5 API Keys activas, todas comparten el mismo límite.
┌─────────────────────────┐
│ Empresa: Acme Inc │
│ Límite compartido │
└───────────┬─────────────┘
│
┌─────────────────────┼─────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ API Key │ │ API Key │ │ API Key │
│ (Prod) │ │ (Dev) │ │ (Test) │
└───────────┘ └───────────┘ └───────────┘
│ │ │
└─────────────────────┴─────────────────────┘
│
Comparten el límite de req/min
Respuesta de Rate Limit
Cuando se excede el límite, la API responde con 429 Too Many Requests:
{
"error": "rate_limit_exceeded",
"message": "Too many requests. Please retry after 32 seconds.",
"retry_after": 32
}
Headers de Rate Limit
Cada respuesta incluye headers informativos:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1704710460
Retry-After: 32
| Header | Descripción |
|---|---|
X-RateLimit-Limit |
Límite total por minuto |
X-RateLimit-Remaining |
Requests restantes en la ventana actual |
X-RateLimit-Reset |
Timestamp Unix cuando se resetea el límite |
Retry-After |
Segundos a esperar (solo en respuestas 429) |
Límite de Jobs Concurrentes
Además del rate limit de requests, hay un límite de jobs procesándose simultáneamente (por defecto 10):
{
"error": "max_concurrent_jobs_exceeded",
"message": "Maximum concurrent jobs reached. Wait for existing jobs to complete."
}
Cómo manejar el límite de jobs
def create_job_with_retry(leads):
while True:
try:
return api.create_job(leads)
except ConcurrentJobsLimitError:
# Esperar a que termine algún job
time.sleep(30)
continue
Implementar Backoff Exponencial
Cuando recibas un 429, usa backoff exponencial:
Python
import time
import random
def make_request_with_retry(request_func, max_retries=5):
"""
Ejecuta request con retry y backoff exponencial.
"""
for attempt in range(max_retries):
try:
response = request_func()
return response
except RateLimitError as e:
if attempt == max_retries - 1:
raise
# Usar retry_after si está disponible
wait_time = e.retry_after if e.retry_after else (2 ** attempt)
# Añadir jitter para evitar thundering herd
jitter = random.uniform(0, 1)
total_wait = wait_time + jitter
print(f"Rate limited. Waiting {total_wait:.1f}s...")
time.sleep(total_wait)
JavaScript
async function makeRequestWithRetry(requestFn, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await requestFn();
} catch (error) {
if (error.status !== 429 || attempt === maxRetries - 1) {
throw error;
}
const retryAfter = error.headers?.['retry-after'] || Math.pow(2, attempt);
const jitter = Math.random();
const waitTime = (parseFloat(retryAfter) + jitter) * 1000;
console.log(`Rate limited. Waiting ${waitTime/1000}s...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
}
}
Estrategias para Evitar Rate Limits
1. Usar Batching
En lugar de muchos requests pequeños, agrupa leads en jobs más grandes:
# ❌ Malo: 100 requests
for lead in leads:
enrich_single_lead(lead)
# ✅ Bueno: 1 request con 100 leads
enrich_leads_batch(leads[:100])
2. Implementar Cola de Requests
from queue import Queue
from threading import Thread
import time
class RateLimitedClient:
def __init__(self, requests_per_minute=300):
self.queue = Queue()
self.interval = 60 / requests_per_minute # ~0.2 segundos
self.worker = Thread(target=self._process_queue, daemon=True)
self.worker.start()
def _process_queue(self):
while True:
request_func, callback = self.queue.get()
try:
result = request_func()
callback(result, None)
except Exception as e:
callback(None, e)
time.sleep(self.interval)
def enqueue(self, request_func, callback):
self.queue.put((request_func, callback))
3. Monitorear los Headers
class APIClient:
def __init__(self):
self.remaining_requests = 300
def make_request(self, endpoint, **kwargs):
# Verificar antes de hacer request
if self.remaining_requests < 10:
time.sleep(5) # Esperar proactivamente
response = requests.get(endpoint, **kwargs)
# Actualizar contador
self.remaining_requests = int(
response.headers.get('X-RateLimit-Remaining', 300)
)
return response
4. Usar Webhooks
Webhooks no cuentan contra el rate limit de requests. Al recibir la notificación de job completado, solo necesitas 1 request para obtener resultados:
# Con polling: muchos requests
while job.status != 'completed': # Puede ser 30+ requests
job = get_job_status(job_id)
time.sleep(2)
# Con webhook: 0 requests de polling
# Solo 1 request cuando llega el webhook
results = get_job_results(job_id)
Límites Personalizados
Si necesitas límites diferentes a los valores por defecto, contacta con nuestro equipo comercial para discutir las opciones disponibles según tu plan.
| Parámetro | Valor por defecto | Personalizable |
|---|---|---|
| Requests/minuto | 300 | Sí, según plan |
| Jobs concurrentes | 10 | Sí, según plan |
| Leads/job | 100 | Sí, según plan |
FAQ
¿Los webhooks cuentan contra el rate limit?
No. Los webhooks son requests salientes de MasLeads a tu servidor. No afectan tu límite de requests entrantes.
¿Qué pasa si excedo el límite constantemente?
- Tus requests serán rechazados con 429
- No hay penalización adicional
- Puedes seguir intentando después del tiempo indicado en
Retry-After
¿El límite se resetea exactamente al minuto?
Usamos un algoritmo de ventana deslizante, no una ventana fija. Esto significa que no hay un "reset" exacto, sino que los requests antiguos van "expirando" gradualmente.
Anterior: ← Webhooks | Siguiente: Créditos y Facturación →