Límites de tasa (rate limits)
El límite es por API key, por minuto. Cada respuesta autenticada
—incluidas las 4xx de scope o validación— te dice exactamente cuánto te queda y cuándo se
reinicia, así que no tienes que adivinar.
Headers en cada respuesta
Mandamos dos formatos juntos para máxima compatibilidad: el trío clásico y el par del draft IETF, más el entorno.
HTTP/1.1 200 OK
RateLimit-Limit: 120
RateLimit-Remaining: 118
RateLimit-Reset: 42
RateLimit: "default";r=118;t=42
RateLimit-Policy: "default";q=120;w=60
AllSign-Environment: live
| Header | Qué es |
|---|---|
RateLimit-Limit | Techo de peticiones en la ventana. |
RateLimit-Remaining | Cuántas te quedan en la ventana actual. |
RateLimit-Reset | Segundos-delta hasta el reinicio (NO epoch). 42 = "en 42 s". |
RateLimit | Header draft IETF combinado: r = remaining, t = segundos al reinicio. El techo viaja en RateLimit-Policy. |
RateLimit-Policy | La política: "default";q=120;w=60 = cuota 120 por ventana de 60 s. |
AllSign-Environment | live, test o dev. |
El 429
Si te pasas del límite recibes 429 RATE_LIMITED (problem+json). Trae el header
Retry-After y además el campo retryAfter en el cuerpo — ambos en
segundos, y ambos iguales a RateLimit-Reset. No tienes que parsear headers si prefieres leer el
body.
HTTP/1.1 429 Too Many Requests
Retry-After: 42
RateLimit-Reset: 42
Content-Type: application/problem+json
{
"type": "https://developers.allsign.io/errors#RATE_LIMITED",
"title": "Rate limited",
"status": 429,
"code": "RATE_LIMITED",
"retryAfter": 42,
"requestId": "req_..."
}
El 429 es seguro de reintentar (idempotency-safe): la petición no se
procesó, así que reintentar no duplica nada. Aun así, para POST combina el reintento con tu
Idempotency-Key como red de seguridad.
Reintentar con backoff
El patrón correcto: al ver 429, espera lo que diga Retry-After
(equivale a RateLimit-Reset) y reintenta; si no viniera, cae a un backoff exponencial.
async function requestWithRetry(doRequest, { maxRetries = 5 } = {}) {
for (let attempt = 0; ; attempt++) {
const res = await doRequest();
if (res.status !== 429 || attempt >= maxRetries) return res;
// Confía en el servidor: espera lo que dice Retry-After (== RateLimit-Reset).
const wait = Number(res.headers.get("Retry-After")) || 2 ** attempt;
await new Promise((r) => setTimeout(r, wait * 1000));
}
}
import time
def request_with_retry(do_request, max_retries=5):
for attempt in range(max_retries + 1):
resp = do_request()
if resp.status_code != 429 or attempt == max_retries:
return resp
wait = int(resp.headers.get("Retry-After", 2 ** attempt))
time.sleep(wait)
Diferencia con v2
Si vienes de v2, tres cosas cambiaron en los headers de rate limit:
| v2 | v3 |
|---|---|
X-RateLimit-Reset | RateLimit-Reset |
Reset = epoch (timestamp Unix) | Reset = segundos-delta (cuántos segundos faltan) |
Prefijo X- en todos | Se cae el prefijo X- (RFC 6648) |