Ir al contenido

Límites de uso

Límite Valor
Peticiones por API key 300 por minuto
Peticiones por cuenta (sumando todas sus keys) 600 por minuto
Escrituras (POST y PATCH) por API key 60 por minuto

Las ventanas son de un minuto y empiezan con la primera petición. Si superas cualquiera de los tres, la respuesta es 429 RATE_LIMITED.

Estos valores pueden ajustarse con el tiempo: en vez de fijarlos en tu código, guíate por los headers de cada respuesta.

Las respuestas a peticiones autenticadas traen:

Header Qué dice
RateLimit-Limit El límite que aplica (normalmente, el de tu key).
RateLimit-Remaining Cuántas peticiones te quedan en la ventana actual.
RateLimit-Reset Segundos hasta que la ventana se reinicia.
Retry-After Solo en un 429: segundos que debes esperar antes de reintentar.

Cuando el 429 lo causa el límite de la cuenta o el de escrituras, los headers RateLimit-* de esa respuesta describen ese límite. El cuerpo del error trae también retry_after.

{
"error": {
"code": "RATE_LIMITED",
"message": "Superaste 60 escrituras por minuto con esta key. Espera y reintenta.",
"retry_after": 23,
"request_id": "req_…"
}
}
  • Ante un 429, espera lo que indica Retry-After y reintenta. No reintentes antes: seguirás recibiendo 429.
  • Para 500 y errores de red, usa espera exponencial con variación aleatoria (por ejemplo 1 s, 2 s, 4 s, 8 s… con ±20 % al azar) y un máximo de intentos.
  • Si reintentas un POST, usa el mismo Idempotency-Key.
  • Si importas muchos datos, reparte las escrituras: 60 por minuto son una por segundo.
  • Prefiere los webhooks y la sincronización incremental a consultar lo mismo cada pocos segundos.
// Node.js 20+ — retry with Retry-After and exponential backoff (sketch)
async function posdataFetch(url, options = {}, attempt = 0) {
const res = await fetch(url, options);
if (res.status !== 429 && res.status < 500) return res;
if (attempt >= 5) return res;
const retryAfter = Number(res.headers.get('Retry-After'));
const backoff = 1000 * 2 ** attempt * (0.8 + Math.random() * 0.4);
const waitMs = Number.isFinite(retryAfter) && retryAfter > 0 ? retryAfter * 1000 : backoff;
await new Promise((resolve) => setTimeout(resolve, waitMs));
// Same options → same Idempotency-Key on POST retries.
return posdataFetch(url, options, attempt + 1);
}