Guías
Límites de uso
Cuántas peticiones por minuto admite cada clave, las cabeceras X-RateLimit, qué pasa al superar el límite (429 y Retry-After) y cómo reintentar bien.
Última revisión: 1 de octubre de 2026
Límite por clave
Cada clave de API tiene un límite de peticiones por minuto. Por defecto son 60 peticiones por minuto, y se puede ajustar por clave según tu volumen: si lo necesitas, pídenos que lo subamos y dinos para qué.
- El límite va por clave, no por IP ni por organización: si tienes dos claves, cada una tiene el suyo.
- Se cuenta en ventanas de un minuto de reloj: el contador vuelve a cero al empezar cada minuto.
- Cuentan todas las peticiones con una clave válida y el ámbito necesario, también las que acaban en error de validación. Las rechazadas con
401o403no cuentan. - Los webhooks que te enviamos no cuentan: no son peticiones tuyas.
Cabeceras
Todas las respuestas autenticadas llevan:
| Cabecera | Significado |
|---|---|
X-RateLimit-Limit | Peticiones por minuto que admite tu clave. |
X-RateLimit-Remaining | Peticiones que te quedan en el minuto en curso. |
HTTP/1.1 200 OK
X-Serad-Environment: production
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57Al superar el límite
Si te pasas, la API responde 429 Too Many Requests con la cabecera Retry-After (segundos hasta que empieza el siguiente minuto) y un cuerpo RFC 9457:
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 23
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
{
"type": "/errors/provider-api/rate-limited",
"title": "Demasiadas peticiones",
"status": 429,
"detail": "Se ha superado el límite de la clave de API. Reintenta en 23 s",
"instance": "/api/integrations/v1/visits",
"timestamp": "2026-10-01T09:10:37.000Z"
}La petición rechazada no se ha ejecutado: si era un alta, no se ha creado el aviso. Espera lo que dice Retry-After y repítela (con la misma Idempotency-Key).
Estrategia de reintento
No todos los errores se reintentan. La regla:
| Respuesta | ¿Reintentar? | Cómo |
|---|---|---|
429 | Sí | Espera exactamente Retry-After segundos. |
500, 502, 503, 504, error de red, tiempo agotado | Sí | Espera exponencial con variación aleatoria: 1 s, 2 s, 4 s, 8 s… hasta un máximo (por ejemplo, 5 intentos o 1 minuto). |
409 idempotency-in-progress | Sí | Unos segundos, con la misma Idempotency-Key. |
400, 401, 403, 404, 409 (resto) | No | Es un error de la petición: corrígelo. Reintentar daría lo mismo. |
Y siempre:
- Reintenta las altas con la misma
Idempotency-Key(idempotencia), o podrías crear avisos duplicados. - Añade una variación aleatoria (jitter) a las esperas: si muchos procesos tuyos fallan a la vez, que no reintenten todos en el mismo segundo.
- Pon un tope. Si después de los reintentos sigue fallando, registra el error, avisa a una persona y, si el aviso es urgente, que llame a la centralita (+34 611 673 280).
// Reintento con espera exponencial, jitter y respeto a Retry-After.
async function seradFetch(url: string, init: RequestInit, maxAttempts = 5): Promise<Response> {
for (let attempt = 1; ; attempt++) {
let response: Response | null = null;
try {
response = await fetch(url, { ...init, signal: AbortSignal.timeout(15_000) });
} catch {
// Error de red o tiempo agotado: se reintenta abajo.
}
const retryable = !response || response.status === 429 || response.status >= 500;
if (!retryable || attempt >= maxAttempts) {
if (!response) throw new Error('La API de Salud en Ruta no responde');
return response;
}
const retryAfter = Number(response?.headers.get('Retry-After'));
const backoff = Math.min(60_000, 1000 * 2 ** (attempt - 1));
const waitMs = response?.status === 429 && retryAfter > 0 ? retryAfter * 1000 : backoff * (0.5 + Math.random());
await new Promise((resolve) => setTimeout(resolve, waitMs));
}
}¿Falta algo o algo no cuadra con lo que ves? Escribe al equipo técnico: info@saludenruta.es.
