Cómo controlar límites de uso y cuotas de una API

Introducción

Controlar los límites y las cuotas de una API exige planificar el consumo y coordinar la concurrencia. Un script puede funcionar con diez registros y fallar cuando varias tareas utilizan la misma cuenta, se acumulan pendientes o los reintentos multiplican el tráfico.

El problema no se resuelve siempre añadiendo una pausa fija. Puede existir un límite por segundo, otro por conexiones simultáneas y otro por consumo acumulado. Además, las operaciones pueden tener costes diferentes y varios procesos pueden compartir el mismo presupuesto.

Esta guía explica cómo identificar cada restricción, estimar la demanda, responder a una limitación y organizar el trabajo para no agotar la capacidad disponible. Los valores numéricos utilizados son ejemplos hipotéticos de diseño, no cuotas vigentes de un proveedor concreto.

Índice

Distinguir tasa, concurrencia, cuota y presupuesto

Antes de modificar el código, identifica qué se limita. “Podemos hacer mil llamadas” es una especificación incompleta si no dice durante qué intervalo, con qué identidad y para qué operaciones.

Restricciones diferentes que no se corrigen del mismo modo
Restricción Qué controla Respuesta de diseño
Tasa de solicitudes Peticiones durante una ventana temporal. Distribuir la carga y respetar pausas.
Concurrencia Operaciones simultáneamente en curso. Limitar trabajadores y conexiones activas.
Cuota acumulada Consumo durante un día, mes u otro periodo. Presupuestar y priorizar trabajo.
Coste por operación Unidades, puntos, bytes u otro recurso consumido. Contabilizar el peso real de cada operación.
Presupuesto económico Gasto que la empresa autoriza. Aplicar un control propio además del técnico.

No son conceptos intercambiables. Una sola petición muy costosa puede consumir gran parte del presupuesto aunque la tasa sea baja. Varias peticiones lentas pueden alcanzar la concurrencia permitida sin generar muchas solicitudes por segundo.

Como ejemplo de que existen varias dimensiones, Dataverse documenta límites de protección del servicio relacionados con número de solicitudes, tiempo de ejecución y concurrencia. Ese modelo ilustra por qué no conviene diseñar con un único contador universal.

Separa también límites impuestos por el proveedor de límites voluntarios de tu aplicación. Un presupuesto interno puede detener una tarea antes de agotar toda la cuota para reservar capacidad a operaciones más importantes.

Construir una ficha de límites por proveedor y cuenta

Lee la documentación de la operación y las condiciones del acceso contratado. Registra qué identidad comparte el límite: clave, usuario, organización, proyecto, dirección de salida u otra agrupación. No supongas que crear otra clave proporciona una cuota independiente.

Información mínima que debe quedar escrita

La ficha debería contener unidad de consumo, ventana, forma de reinicio, operaciones incluidas, cabeceras informativas y comportamiento al exceder el límite. Añade qué ocurre con las peticiones rechazadas y si una operación por lotes consume una unidad o varias.

Comprueba si los límites del entorno de pruebas coinciden con los de producción. También si las exportaciones, búsquedas complejas o cargas de ficheros tienen restricciones propias. Un límite general no sustituye los detalles del endpoint.

Guardar evidencias, no solo cifras

Conserva la referencia documental y la fecha de revisión. Si el proveedor cambia el plan o la política, podrás saber qué suposición necesita actualizarse. Las cabeceras recibidas ayudan a observar consumo, pero su nombre y significado deben interpretarse según ese servicio.

En las buenas prácticas de GitHub REST se distinguen límites primarios y secundarios y se indican respuestas específicas. No generalices sus tiempos de espera o cabeceras a otra API.

Integra esta ficha en la estrategia de integración de datos, de modo que cada nueva tarea conozca el presupuesto que ya están utilizando las existentes.

Calcular solicitudes antes de poner el proceso en marcha

Descompón la tarea en llamadas reales. Una sincronización puede requerir consultar páginas, obtener detalles, verificar existencia y escribir cambios. Si solo cuentas la consulta inicial, subestimarás el consumo.

Ejemplo de una sincronización completa

Supongamos 2.500 registros, páginas de 100 elementos y una escritura individual por registro. La lectura necesita 25 peticiones y la escritura otras 2.500: 2.525 en total, sin contar autenticación, verificaciones ni reintentos. Si repites ese trabajo cuatro veces al día, generas 10.100 peticiones diarias.

Es una estimación hipotética bajo esas condiciones. Un endpoint por lotes, un filtro incremental o una respuesta con menos elementos pueden cambiar el resultado. Lo importante es que cada término corresponda a un paso real del proceso.

Medir el coste del sondeo

Una comprobación cada cinco minutos implica 288 consultas diarias y 8.640 en treinta días, incluso cuando no hay novedades. Aumentar a una por minuto eleva esos valores a 1.440 y 43.200. Si varios procesos hacen el mismo sondeo, el coste se multiplica.

Estos cálculos permiten preguntar qué antigüedad de dato admite realmente el negocio. La respuesta puede evitar más consumo que una optimización de código. No todo necesita una actualización inmediata.

Incluir recuperación y operación ordinaria

Reserva capacidad para reintentos razonables, conciliaciones y recuperaciones tras una parada. El objetivo no es consumir siempre el máximo, sino terminar el trabajo importante con margen. Una planificación que solo funciona sin incidencias es demasiado frágil.

La estimación debe relacionarse con el rendimiento de la automatización, separando llamadas realizadas de operaciones empresariales completadas.

Asignar presupuesto a las tareas que comparten una cuenta

Cuando varios procesos comparten cuota, controla el conjunto. Tres scripts que respetan por separado una tasa de diez peticiones pueden superar el límite de una cuenta que admite diez en total. El ámbito del contador debe coincidir con el ámbito de la restricción.

En este escenario ficticio hay una capacidad diaria de 12.000 unidades equivalentes. La distribución es una decisión interna propuesta para reservar margen, no una recomendación universal.

Ejemplo de distribución de una cuota compartida
Uso Unidades reservadas Criterio
Operaciones de clientes 6.000 Prioridad operativa.
Sincronizaciones periódicas 2.000 Trabajo programable.
Informes y consultas auxiliares 1.000 Puede aplazarse.
Recuperación y conciliación 1.500 Reserva para incidencias.
Margen no asignado 1.500 Absorber variación observada.

La suma es 12.000. No significa que cada tarea deba consumir su reserva ni que esa división esté garantizada por el proveedor. Es una política del ejecutor que puede revisarse a partir del uso real.

Hacer visibles las prioridades

Cuando queda poca capacidad, pospón primero tareas prescindibles según una regla acordada. No elimines silenciosamente una petición importante porque otra exportación agotó el presupuesto. Conserva qué trabajo se aplaza y hasta cuándo sigue siendo válido.

Evita que un único lote acapare todos los turnos. Una cola puede alternar tareas, reservar huecos y comprobar su antigüedad. Esto mantiene una relación explícita entre cuota y servicio al negocio.

Regular la tasa y la concurrencia como controles separados

Un limitador de tasa decide cuándo puede empezar la siguiente petición. Un limitador de concurrencia decide cuántas pueden permanecer activas. Ambos pueden ser necesarios.

Espaciado sencillo para un proceso secuencial

Si el contrato hipotético permite 60 solicitudes por minuto y quieres evitar ráfagas, puedes repartirlas aproximadamente a una por segundo. Es un punto de partida para un único productor y una ventana conocida, no una prueba de cumplimiento de cualquier algoritmo del proveedor.

Una pausa después de cada llamada también incorpora el tiempo de respuesta al intervalo. Si necesitas una tasa más precisa, programa el siguiente inicio con un reloj monotónico y controla igualmente los intentos fallidos.

Ventanas y ráfagas

Con una ventana fija, muchas peticiones al final de un intervalo y al comienzo del siguiente pueden concentrarse en poco tiempo. Una ventana deslizante u otro control del proveedor podría rechazarlas. Diseña para el comportamiento documentado y conserva margen cuando no conozcas todos sus detalles.

Un sistema de permisos acumulables puede permitir ráfagas controladas, pero solo debes utilizarlas si el proveedor las admite. La capacidad interna de acumular turnos no crea una autorización externa para enviar más tráfico de golpe.

Coordinar varios ejecutores

Si hay varios procesos, el contador y la reserva de turnos necesitan coordinación atómica. Puede servir un servicio de colas o un almacenamiento compartido apropiado. Un fichero que todos leen y actualizan sin exclusión puede conceder el mismo turno a varios trabajadores.

Además, limita conexiones simultáneas. Reducir la tasa no resuelve necesariamente un conjunto de peticiones lentas que mantienen ocupados todos los recursos.

Interpretar una respuesta de limitación sin reaccionar a ciegas

HTTP 429 Too Many Requests expresa una limitación de solicitudes y puede incluir información para esperar antes de repetir. No determina por sí solo qué cuota se ha agotado ni su ámbito. Lee el código de error del proveedor y las cabeceras documentadas.

Una respuesta 429 no siempre significa “inténtalo dentro de un segundo”. Puede corresponder a una restricción breve o a capacidad que no estará disponible durante bastante tiempo. Si hay un límite económico agotado o una condición del contrato, repetir inmediatamente no cambia esa condición.

Interpretar Retry-After

Retry-After admite segundos o una fecha HTTP. Si recibes una fecha, necesitas un reloj correctamente ajustado y una interpretación con zona horaria. No la trates como una cantidad de segundos ni confundas otra cabecera de reinicio con el mismo formato.

Si la espera indicada supera el plazo del trabajo, aplázalo o envíalo a revisión. No recortes una espera larga a tu pausa máxima y vuelvas a llamar antes de lo solicitado por el servidor.

Aplicar la pausa al ámbito adecuado

Una pausa local en el trabajador que recibió el error puede no bastar si otros siguen enviando peticiones con la misma cuenta. El coordinador debe conocer la limitación y detener el consumo correspondiente. No bloquees necesariamente otras cuentas o proveedores que no comparten el problema.

Tras la recuperación, reanuda gradualmente. Liberar toda la cola de golpe puede recrear la misma saturación que originó la pausa.

Ejemplo: calcular una espera y decidir si cabe en el trabajo

Este código didáctico interpreta Retry-After y propone una decisión. No llama a la API, no implementa un limitador compartido y no debe utilizarse como autorización automática para repetir escrituras. Está pensado para una política de reintentos que ya haya sido validada para la operación.

La espera combina el mínimo indicado por el servidor con un retroceso aleatorio acotado. Se limita el número total de intentos. Si el tiempo disponible no alcanza, devuelve defer; si la cabecera no puede interpretarse con seguridad, devuelve review.

from __future__ import annotations

import math
import random
import re
from datetime import datetime, timezone
from email.utils import parsedate_to_datetime


def retry_after_seconds(value: str | None, now: datetime) -> int | None:
    """Devuelve segundos mínimos o None si la cabecera no existe."""
    if now.tzinfo is None:
        raise ValueError('now debe incluir zona horaria')
    if value is None:
        return None
    value = value.strip()
    if not value or len(value) > 128:
        raise ValueError('Retry-After no interpretable')
    if re.fullmatch(r'[0-9]+', value):
        return int(value)
    try:
        date = parsedate_to_datetime(value)
    except (TypeError, ValueError, OverflowError):
        raise ValueError('Retry-After no interpretable') from None
    if date is None or date.tzinfo is None:
        raise ValueError('Retry-After sin fecha y zona válidas')
    return max(0, math.ceil((date - now).total_seconds()))


def plan_retry(value: str | None, *, failed_attempt: int,
               remaining_seconds: float, now: datetime,
               max_attempts: int = 4) -> tuple[str, float | int | None]:
    """Política didáctica; no realiza llamadas ni espera por sí misma."""
    if (failed_attempt < 1 or max_attempts < 1
            or not math.isfinite(remaining_seconds)
            or remaining_seconds < 0):
        raise ValueError('Presupuesto no válido')
    if failed_attempt >= max_attempts:
        return 'stop', None
    try:
        server_wait = retry_after_seconds(value, now)
    except ValueError:
        return 'review', None  # No adivinar una fecha malformada.

    if server_wait is not None and server_wait >= remaining_seconds:
        return 'defer', server_wait  # No recortar la espera del servidor.
    cap = min(60.0, 2.0 ** min(failed_attempt, 10))
    delay = max(server_wait or 0, random.uniform(1.0, cap))
    delay += random.uniform(0.0, 1.0)
    if delay >= remaining_seconds:
        return 'defer', delay
    return 'retry', delay


if __name__ == '__main__':
    now = datetime(2026, 9, 1, 8, 0, 0, tzinfo=timezone.utc)
    assert retry_after_seconds('120', now) == 120
    assert retry_after_seconds('Tue, 01 Sep 2026 08:02:00 GMT', now) == 120
    assert plan_retry('120', failed_attempt=1, remaining_seconds=30,
                      now=now) == ('defer', 120)

max_attempts=4 representa como máximo cuatro intentos en total, no cuatro repeticiones adicionales. El contador debe mantenerse fuera de la función y persistirse si un trabajo se reprograma. De lo contrario, cada nueva ejecución podría reiniciar el presupuesto y convertir una política acotada en un bucle indefinido.

Antes de comenzar el siguiente intento, comprueba de nuevo el plazo restante y reserva tiempo para ejecutarlo. Que la espera quepa no demuestra que también quepa la llamada. Si necesitas un plazo absoluto, el ejecutor debe poder cancelar o posponer el trabajo.

La aleatoriedad reduce coincidencias entre clientes, pero no coordina cuotas por sí sola. Tampoco reemplaza las instrucciones específicas del proveedor cuando no existe Retry-After.

Evitar que la recuperación multiplique el problema

Los reintentos consumen capacidad y pueden prolongar una saturación. Cuenta cada intento en tus métricas y en el limitador local, aunque el proveedor aplique su propia regla de facturación o cuota. El tráfico rechazado también ejerce presión sobre el sistema.

Una sola política responsable

Si el cliente HTTP reintenta tres veces, el adaptador otras tres y el ejecutor vuelve a lanzar el trabajo, la demanda puede crecer de una forma que no aparece en la configuración de ninguna capa aislada. Decide dónde se controla la repetición y documenta las demás capas.

Introduce límites por operación y por trabajo. También un estado visible para tareas que han agotado su recuperación automática. El objetivo no es reintentar hasta que desaparezca la alerta, sino conseguir un resultado verificable sin perder el control del consumo.

Idempotencia antes de repetir escrituras

Un pedido que perdió su respuesta puede existir en el destino. Antes de repetir, utiliza las garantías documentadas de la operación, una clave de idempotencia admitida o una consulta de conciliación. Reutilizar una clave para una operación distinta también sería un error.

Los fundamentos se recogen en la semántica HTTP de los métodos idempotentes. La decisión concreta de recuperación sigue necesitando el contrato del proveedor y la lógica empresarial.

La práctica encaja con evitar que una automatización se convierta en un problema: una recuperación mal diseñada puede costar más que el fallo inicial.

Reducir solicitudes innecesarias sin perder información

Una vez medido el consumo, identifica qué llamadas no aportan un resultado nuevo. Reducir demanda suele ser más sostenible que aumentar trabajadores para procesar el mismo exceso.

Solicitar solo cambios cuando el contrato lo permita

Los filtros por modificación o mecanismos de seguimiento de cambios pueden evitar descargar todo el histórico. Debes conocer sus garantías: precisión temporal, elementos eliminados, orden, caducidad del cursor y posibilidad de cambios simultáneos.

No avances una marca de progreso antes de guardar o controlar duraderamente lo descargado. Si utilizas un pequeño solapamiento para evitar pérdidas en límites temporales, combina ese solapamiento con deduplicación y una identidad estable.

Usar caché con una antigüedad aceptable

Define qué datos pueden reutilizarse, durante cuánto tiempo y cómo se invalidan. La clave de caché debe incluir parámetros y ámbito de acceso relevantes. No compartas por error respuestas privadas entre clientes o cuentas.

Una consulta condicional puede reducir transferencia, pero no garantiza reducir cuota en todos los servicios. Comprueba cómo contabiliza el proveedor una respuesta sin cambios. No des por hecho que una respuesta 304 es siempre gratuita.

Evaluar webhooks y operaciones por lotes

Un webhook puede evitar sondeos continuos, pero requiere autenticación, control de duplicados y recuperación de eventos omitidos. Una petición por lotes puede reducir viajes de red, aunque el proveedor siga cobrando o contabilizando cada elemento. Revisa el resultado individual de las operaciones.

Para comprender el intercambio por eventos, puedes ampliar con el uso de webhooks; para reducir consultas redundantes entre fuentes, con la integración ordenada de fuentes de datos.

Gestionar acumulación de trabajo y recuperación tras una parada

Si el ritmo de llegada supera al de procesamiento, la cola crece aunque cada petición respete el límite. Debes observar cuántas tareas esperan y qué antigüedad tienen, no solo si el cliente recibe respuestas.

Calcular capacidad efectiva

En un ejemplo hipotético, llegan 80 operaciones por minuto y el sistema puede completar 60. La cola aumenta en 20 por minuto mientras esa diferencia se mantenga. Ninguna política de reintentos corrige el desequilibrio; necesitas reducir demanda, ampliar capacidad autorizada o aceptar mayor demora.

Después de una parada, calcula cuánto tiempo necesitarás para vaciar pendientes sin bloquear trabajo nuevo. Reserva una parte de la capacidad para la recuperación y comprueba que la información antigua sigue siendo válida antes de enviarla.

Consolidar solo cuando la semántica lo permita

Si una tarea representa “publicar el estado actual de este producto”, puede ser posible sustituir varias actualizaciones pendientes por la más reciente. Si representa hechos independientes, como movimientos que deben conservarse, esa consolidación perdería información. La decisión depende del proceso, no de la comodidad de la cola.

También puede caducar una tarea. Una consulta necesaria para una decisión inmediata puede dejar de ser útil horas después. Registra su vencimiento y el motivo de descarte; no ejecutes indefinidamente trabajo que ya no sirve.

Esta gestión forma parte de crear procesos repetibles y robustos: el funcionamiento correcto incluye cómo se absorben interrupciones y acumulaciones.

Supervisar consumo y probar el comportamiento cerca del límite

El panel debe mostrar consumo por proveedor y cuenta, cuota restante cuando se conozca, intentos por operación, esperas introducidas y antigüedad de pendientes. Separa la cifra estimada por tu ejecutor de la observada en el proveedor.

Una discrepancia puede deberse a otros consumidores de la misma cuenta, a operaciones con pesos distintos o a reglas de cómputo que no has modelado. No ajustes el contador a mano sin comprender la diferencia.

Probar sin agotar la cuota real

Simula respuestas 429, fechas de espera, ausencia de cabeceras y recuperación posterior. Comprueba que el sistema no reintenta antes de tiempo, que detiene el conjunto de trabajadores afectados y que conserva el número de intentos al reprogramar.

Incluye un reinicio del proceso, una cola con tareas caducadas y dos productores que solicitan el último turno simultáneamente. Estas pruebas detectan fallos que una demostración con un único script no muestra.

Crear alertas relacionadas con decisiones

No existe un porcentaje universal de cuota que deba disparar una alarma. Define umbrales según el consumo previsto y el tiempo que resta del periodo. Haber utilizado el 70 % puede ser normal al final del ciclo y preocupante al principio.

Documenta la acción: reducir consultas auxiliares, revisar duplicados, posponer un lote o gestionar una ampliación autorizada. Evita recurrir a cuentas adicionales para eludir restricciones del proveedor. La capacidad debe ampliarse por los mecanismos que este permita.

Preguntas frecuentes

¿Añadir sleep a un script basta para respetar los límites?

Puede servir en un caso secuencial sencillo, pero no coordina otros procesos ni controla necesariamente concurrencia o cuota mensual. Debe responder al ámbito y a la ventana documentados por el proveedor.

¿Qué hago si Retry-After indica más tiempo del que puedo esperar?

Aplaza el trabajo de forma duradera o envíalo a revisión. No reduzcas la espera a un valor menor para volver a llamar antes. Conserva el estado y el presupuesto de intentos al reprogramar.

¿Una respuesta 429 significa siempre que se ha agotado la cuota mensual?

No. Puede corresponder a una restricción de tasa u otra política. Revisa el error y las cabeceras específicas del servicio para distinguir una pausa breve de una condición que requiere otra acción.

¿Los lotes cuentan como una sola llamada?

No hay una regla universal. Pueden reducir solicitudes de red y, al mismo tiempo, consumir unidades por cada operación interna. Verifica también límites de tamaño, tiempo de ejecución y resultados parciales.

¿Una caché elimina la necesidad de controlar cuotas?

No. Reduce algunas consultas, pero hay actualizaciones, fallos de caché y otros consumidores de la cuenta. Además, su diseño debe respetar el ámbito de acceso y la antigüedad admisible de los datos.

¿Cómo diferencio el límite del proveedor de mi presupuesto interno?

El proveedor define qué acepta y cómo mide el consumo. Tu presupuesto interno define cuánto autorizas a cada tarea antes de posponerla o revisarla. Debes controlar ambos sin asumir que uno sustituye al otro.

Conclusión

Controlar cuotas y límites de una API consiste en relacionar demanda, capacidad y prioridad. Primero identifica qué recurso se limita y quién lo comparte; después calcula el consumo, coordina ejecutores y prepara una política de espera y recuperación que no multiplique los intentos.

Una integración bien dimensionada no busca utilizar siempre el máximo permitido. Busca completar el trabajo relevante, conservar margen para incidencias y hacer visible qué se aplaza cuando la capacidad no alcanza.

Desarrollar criterio para dimensionar el consumo de APIs

El control de cuotas combina programación, planificación de capacidad, colas y análisis de procesos. Para estudiar estas competencias con una base estructurada, consulta los programas de formación de ESTUDIO METADATOS, basados en cursos y másteres online, y valora su relación con los sistemas que quieres aprender a construir.

Ver programas de formación relacionados

Written by