Skip to content

Rate Limits y Throttling

Resumen rápido

Amazon SP-API limita el número de peticiones que puedes hacer usando el algoritmo token bucket. Cada API tiene dos parámetros: rate (peticiones por segundo que se reponen) y burst (máximo acumulable). Si superas el burst, recibirás un error 429 QuotaExceeded. La clave es respetar los límites para evitar baneos y diseñar el código para funcionar dentro de ellos en lugar de ignorarlos.


Conceptos importantes

  • Rate limit: El número de tokens (peticiones) por segundo que se recargan en el bucket. Si haces peticiones a esta tasa exacta, nunca serás bloqueado.
  • Burst: El tamaño máximo del bucket. Puedes acumular hasta este número de peticiones y lanzarlas rápidamente al inicio.
  • Token bucket algorithm: Algoritmo estándar de control de flujo. El bucket se llena a la tasa rate hasta un máximo de burst. Cada petición consume un token.
  • QuotaExceeded: El error 429 que recibes cuando el bucket está vacío.
  • x-amz-rate-limit-limit: Header HTTP que Amazon devuelve en cada respuesta con tu límite real actual. Más fiable que los valores documentados porque refleja si Amazon te ha subido el límite dinámicamente.
  • Dynamic usage plans: Amazon puede subir o bajar tus límites automáticamente según el histórico de uso de tu app. Si haces muchas peticiones de forma consistente, Amazon puede triplicar tu rate.
  • NextToken: Token de paginación que devuelven las APIs cuando hay más de 100 resultados. Debes hacer una petición por página, lo que consume tokens del bucket.

Cómo funciona

El algoritmo token bucket explicado

Bucket capacidad = burst (ej. 20 tokens)
Tasa de recarga = rate (ej. 0.0167 tokens/seg = 1 token/60 seg)

Estado inicial: bucket lleno (20 tokens)

→ Hago 20 peticiones rápidas → bucket vacío
→ Siguiente petición → ERROR 429 (QuotaExceeded)
→ Espero 60 segundos → el bucket tiene 1 token
→ Puedo hacer 1 petición más
→ Espero 60 segundos más → 1 token más
...

Rate limits de las APIs principales

APIOperaciónRate (req/s)Burst
OrdersGetOrders0.0167 (1/min)20
OrdersGetOrder0.530
OrdersGetOrderItems0.530
Catalog ItemsSearchCatalogItems25
Catalog ItemsGetCatalogItem22
ReportsCreateReport0.016715
ReportsGetReport215
ListingspatchListingsItem510
NotificationscreateDestination15

Estos valores son los predeterminados. El header x-amz-rate-limit-limit te da tu valor real.


Pasos prácticos

Leer el rate limit real desde el header de respuesta

python
import requests

def make_api_request(access_token: str, url: str, params: dict) -> dict:
    response = requests.get(
        url,
        headers={"x-amz-access-token": access_token},
        params=params,
    )

    # Leer el rate limit real desde el header
    rate_limit = response.headers.get("x-amz-rate-limit-limit")
    if rate_limit:
        print(f"Tu rate limit actual: {rate_limit} req/s")

    if response.status_code == 429:
        print("Rate limit excedido (QuotaExceeded). Esperando...")
        # El header Retry-After puede indicar cuántos segundos esperar
        retry_after = response.headers.get("Retry-After", "60")
        return {"error": "throttled", "retry_after": int(retry_after)}

    response.raise_for_status()
    return response.json()

Rate limiter básico en Python (siguiendo el modelo de Amazon)

python
import threading
import time


class RateLimiter:
    """
    Implementa el token bucket algorithm de Amazon SP-API.
    tokens_per_second: el valor del campo 'rate' de la documentación
    capacity: el valor del campo 'burst' de la documentación
    """

    def __init__(self, tokens_per_second: float, capacity: int):
        self.tokens_per_second = tokens_per_second
        self.capacity = capacity
        self.tokens = float(capacity)
        self.last_refill = time.time()
        self.lock = threading.Lock()

    def _refill(self):
        now = time.time()
        elapsed = now - self.last_refill
        tokens_to_add = elapsed * self.tokens_per_second
        self.tokens = min(self.capacity, self.tokens + tokens_to_add)
        self.last_refill = now

    def acquire(self):
        """Espera hasta que haya un token disponible."""
        while True:
            with self.lock:
                self._refill()
                if self.tokens >= 1:
                    self.tokens -= 1
                    return
            wait_time = 1.0 / self.tokens_per_second
            time.sleep(wait_time)


# Ejemplo de uso: Orders API (rate=0.0167, burst=20)
orders_limiter = RateLimiter(tokens_per_second=0.0167, capacity=20)

def get_orders_with_rate_limit(access_token: str, endpoint: str, marketplace_id: str):
    all_orders = []
    next_token = None
    page = 0

    while True:
        orders_limiter.acquire()  # Esperar hasta tener un token disponible

        params = {"MarketplaceIds": marketplace_id}
        if next_token:
            params["NextToken"] = next_token
        else:
            params["CreatedAfter"] = "2024-01-01T00:00:00Z"

        response = requests.get(
            f"{endpoint}/orders/v0/orders",
            headers={"x-amz-access-token": access_token},
            params=params,
        )
        response.raise_for_status()
        data = response.json().get("payload", {})

        orders = data.get("Orders", [])
        all_orders.extend(orders)
        page += 1
        print(f"Página {page}: {len(orders)} pedidos obtenidos")

        next_token = data.get("NextToken")
        if not next_token:
            break

    return all_orders

Retry con backoff exponencial

python
import time
import random

def request_with_retry(func, max_retries: int = 3, *args, **kwargs):
    """Reintenta en caso de throttling con backoff exponencial."""
    for attempt in range(max_retries):
        try:
            return func(*args, **kwargs)
        except requests.exceptions.HTTPError as e:
            if e.response.status_code == 429:
                wait = (2 ** attempt) + random.uniform(0, 1)
                print(f"Throttled. Reintentando en {wait:.1f}s (intento {attempt + 1})")
                time.sleep(wait)
            else:
                raise
    raise Exception(f"Máximo de reintentos alcanzado ({max_retries})")

Estrategias de optimización

EstrategiaReducción de llamadas
Usar Notifications API en lugar de pollingHasta 100x menos
Usar Reports API en lugar de Get repetitivoHasta 50x menos
SearchCatalogItems (20 items/llamada) en lugar de GetCatalogItem20x menos
Usar ORDER_CHANGE en lugar de sondear Orders APIMiles de llamadas menos
Programar llamadas por la noche (menos tráfico)Mejor respuesta

Errores comunes

  • Hardcodear los rate limits: Los valores de la documentación son los mínimos garantizados. Tu app puede tener valores más altos (o más bajos). Lee siempre el header x-amz-rate-limit-limit.
  • No manejar el 429: Si no capturas este error, tu app fallará silenciosamente o lanzará excepciones no controladas.
  • Hacer polling agresivo: Bucles que consultan la API cada pocos segundos consumen el burst rápidamente y terminan bloqueados.
  • Abusar demasiado: Amazon puede penalizarte o incluso banearte si haces demasiadas peticiones que superan límites de forma continuada.
  • Confundir rate y burst: rate es la velocidad de recarga. burst es cuánto puedes hacer de golpe.

Qué debo saber antes de programarlo

  • Para obtener órdenes de historial (cientos de páginas con NextToken), el rate de GetOrders (1 req/min) es muy lento. Es mejor usar Reports API (GET_FLAT_FILE_ALL_ORDERS_DATA_BY_ORDER_DATE_GENERAL) que te da todo en un solo archivo.
  • Si tu app tiene muchos clientes (SaaS), cada cliente tiene sus propias credenciales y sus propios rate limits. No compartes quota entre clientes.
  • Un patrón de producción sólido: cola de trabajos + worker que respeta el rate limiter. Nunca llames a la API directo desde una petición HTTP al usuario final.

Pendiente de revisar

  • ¿Amazon penaliza o banea por exceder el throttle repetidamente, o solo devuelve 429?
  • ¿El dynamic usage plan se aplica por aplicación o por cuenta de vendedor?
  • ¿Cómo funcionan exactamente los rate limits en apps con múltiples cuentas de vendedor (SaaS)?

Documentación basada en más de 40 tutoriales sobre Amazon SP-API. Actualizada a junio de 2026.