Rate Limits
La API de FactuLink implementa rate limiting para garantizar un servicio estable y justo para todos los usuarios. Los límites se aplican por API Key y se miden en peticiones por minuto.
Límite por defecto
El límite por defecto es de 100 peticiones por minuto por API Key. Este límite aplica al plan Starter y puede variar según tu plan.
Headers de respuesta
Cada respuesta de la API incluye headers que te indican el estado actual de tu límite:
| Header | Descripción | Ejemplo |
|---|---|---|
X-RateLimit-Limit | Máximo de peticiones permitidas por minuto | 100 |
X-RateLimit-Remaining | Peticiones restantes en la ventana actual | 87 |
X-RateLimit-Reset | Timestamp Unix cuando se reinicia la ventana | 1743854460 |
Retry-After | Segundos para esperar antes de reintentar (solo en respuestas 429) | 23 |
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1743854460
Content-Type: application/jsonLímites por plan
| Plan | Peticiones/minuto | Ideal para |
|---|---|---|
| Sandbox | 60/min | Desarrollo y pruebas |
| Starter | 100/min | Pequeños negocios, pocas facturas al mes |
| Pro | 300/min | Medianas empresas, integraciones activas |
| Enterprise | 1,000+/min | Alto volumen, personalizable según necesidad |
Para aumentar tu límite, contacta a ventas o actualiza tu plan desde el dashboard.
Respuesta 429: Too Many Requests
Cuando excedes el límite, la API responde con un 429 e incluye el header Retry-After que indica cuántos segundos debes esperar:
/api/v1/cfdis429{
"error": {
"code": "HTTP_429",
"message": "Has excedido el límite de peticiones. Espera antes de reintentar.",
"details": [
{
"field": "rate_limit",
"issue": "100 peticiones por minuto excedidas. Reintenta en 23 segundos."
}
]
},
"path": "/api/v1/cfdis",
"timestamp": "2026-04-05T12:00:00Z"
}Buenas prácticas
Exponential backoff
Cuando recibas un 429, no reintentes inmediatamente. Usa exponential backoff con jitter:
async function fetchWithBackoff(url, options, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) return response;
if (attempt === maxRetries) throw new Error("Rate limit: reintentos agotados");
const retryAfter = response.headers.get("Retry-After");
const baseDelay = retryAfter ? parseInt(retryAfter) * 1000 : 2 ** attempt * 1000;
const jitter = Math.random() * 1000;
await new Promise((resolve) => setTimeout(resolve, baseDelay + jitter));
}
}Cachea respuestas
Evita peticiones repetidas cacheando datos que no cambian frecuentemente:
- Catálogos del SAT — cambian cada 1-2 meses. Cachéalos localmente.
- Datos de clientes — cachéalos por al menos 5 minutos.
- CFDIs ya timbrados — son inmutables una vez timbrados. Cachéalos indefinidamente.
Reduce peticiones innecesarias
Cuando necesites consultar múltiples recursos, usa filtros y paginación en lugar de hacer una petición por recurso:
| En lugar de… | Usa… |
|---|---|
100 consultas GET /api/v1/cfdis/:id | 1 petición GET /api/v1/cfdis?limit=100 con filtros |
Monitorea tus headers
Revisa X-RateLimit-Remaining en cada respuesta. Si se acerca a 0, reduce la velocidad de tus peticiones antes de recibir un 429.