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?

  1. Tus requests serán rechazados con 429
  2. No hay penalización adicional
  3. 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 →