Español
Referencia API
Límites de Tasa

Límites de Tasa

Entiende los límites de tasa de la API y cómo manejarlos.

Vista General

Los límites de tasa protegen la API del abuso y aseguran disponibilidad justa para todos los usuarios.

Límites Predeterminados

Tipo de EndpointLímiteVentana
API General100 solicitudesPor minuto
Endpoints de Escritura30 solicitudesPor minuto
API Pública60 solicitudesPor minuto
Webhooks10 solicitudesPor minuto

Los límites aplican por clave API o sesión de usuario.

Headers de Respuesta

Cada respuesta de API incluye headers de límite de tasa:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995200
HeaderDescripción
X-RateLimit-LimitSolicitudes máximas por ventana
X-RateLimit-RemainingSolicitudes restantes
X-RateLimit-ResetTimestamp Unix cuando se resetea el límite

Respuesta de Límite Excedido

Cuando se excede el límite de tasa:

HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json
 
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Límite de tasa excedido. Intenta de nuevo en 60 segundos.",
    "details": {
      "retryAfter": 60,
      "limit": 100,
      "remaining": 0,
      "resetAt": "2026-01-23T12:00:00Z"
    }
  }
}

Mejores Prácticas

1. Monitorea los Headers

async function fetchWithRateLimit(url: string) {
  const response = await fetch(url, {
    headers: { 'Authorization': 'Bearer sk_live_xxx' }
  });
 
  const remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0');
  const resetAt = parseInt(response.headers.get('X-RateLimit-Reset') || '0');
 
  if (remaining < 10) {
    console.warn(`Límite de tasa bajo: ${remaining} solicitudes restantes`);
  }
 
  return response;
}

2. Implementa Backoff Exponencial

async function fetchWithRetry(
  url: string,
  options: RequestInit = {},
  maxRetries = 3
): Promise<Response> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);
 
    if (response.status === 429) {
      const retryAfter = parseInt(
        response.headers.get('Retry-After') || '60'
      );
      const delay = Math.min(
        retryAfter * 1000,
        Math.pow(2, attempt) * 1000
      );
 
      console.log(`Límite de tasa alcanzado, reintentando en ${delay}ms`);
      await sleep(delay);
      continue;
    }
 
    return response;
  }
 
  throw new Error('Máximo de reintentos excedido');
}
 
function sleep(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}

3. Agrupa Solicitudes

En lugar de múltiples solicitudes individuales:

// ❌ Malo - Múltiples solicitudes
for (const id of componentIds) {
  await fetch(`/api/v1/components/${id}`);
}
 
// ✅ Bueno - Solicitud única con filtro
const response = await fetch('/api/v1/components?ids=' + componentIds.join(','));

4. Usa Webhooks para Actualizaciones

En lugar de polling:

// ❌ Malo - Polling frecuente
setInterval(async () => {
  const incidents = await fetch('/api/v1/incidents');
}, 5000);
 
// ✅ Bueno - Suscripción a webhooks
// Configura un webhook para recibir actualizaciones push

5. Cachea Respuestas

const cache = new Map<string, { data: any; expiresAt: number }>();
 
async function fetchWithCache(url: string, ttlMs = 60000) {
  const cached = cache.get(url);
  if (cached && cached.expiresAt > Date.now()) {
    return cached.data;
  }
 
  const response = await fetch(url);
  const data = await response.json();
 
  cache.set(url, {
    data,
    expiresAt: Date.now() + ttlMs
  });
 
  return data;
}

Límites por Tipo de Recurso

Algunos endpoints tienen límites específicos:

RecursoLímite de CreaciónLímite de Lectura
Componentes10/min100/min
Incidentes10/min100/min
Suscriptores50/min100/min
Notificaciones100/min100/min

Incremento de Límites

Para límites más altos:

  1. Plan Enterprise: Límites personalizados disponibles
  2. Contacta Soporte: Incrementos temporales para migraciones
  3. Optimiza Uso: Revisa patrones de solicitudes
⚠️

Los abusos repetidos de límites de tasa pueden resultar en bloqueos temporales de IP.

Cola de Solicitudes

Implementa una cola para respetar límites:

class RateLimitedQueue {
  private queue: Array<() => Promise<any>> = [];
  private processing = false;
  private lastRequestTime = 0;
  private minInterval = 600; // ms entre solicitudes (100/min)
 
  async add<T>(fn: () => Promise<T>): Promise<T> {
    return new Promise((resolve, reject) => {
      this.queue.push(async () => {
        try {
          const result = await fn();
          resolve(result);
        } catch (error) {
          reject(error);
        }
      });
      this.process();
    });
  }
 
  private async process() {
    if (this.processing) return;
    this.processing = true;
 
    while (this.queue.length > 0) {
      const now = Date.now();
      const waitTime = this.minInterval - (now - this.lastRequestTime);
 
      if (waitTime > 0) {
        await sleep(waitTime);
      }
 
      const fn = this.queue.shift();
      if (fn) {
        this.lastRequestTime = Date.now();
        await fn();
      }
    }
 
    this.processing = false;
  }
}
 
// Uso
const queue = new RateLimitedQueue();
 
const results = await Promise.all(
  componentIds.map(id =>
    queue.add(() => fetch(`/api/v1/components/${id}`))
  )
);

Documentación Relacionada