Skip to content
Idioma: Español

API para desarrolladores

Límites de peticiones: cada límite y encabezado

Actualizado el 1 de noviembre de 2026 6 min de lectura

Cuántas peticiones por minuto permite la API de LinkHarbor, qué tamaño puede tener una petición, cómo leer los encabezados y cómo gestionar bien un 429.

Para que la API sea rápida para todos, LinkHarbor limita el número de peticiones por minuto. Los límites no dependen de tu plan: no hay una cuota mensual de llamadas a la API. Este artículo recoge todos los límites y muestra cómo puede gestionarlos tu código de forma limpia.

Cómo se cuentan las peticiones

  • Cada petición cae exactamente en un bucket, por ejemplo user para las peticiones autenticadas o token para el intercambio de token
  • Se cuenta por minuto completo (UTC); el contador vuelve a cero con cada minuto nuevo
  • Según el bucket, la API cuenta por espacio de trabajo, por persona, por conexión o por dirección IP
  • Las peticiones que ya fallan en el token, el scope o el esquema (401, 403 insufficient_scope, 400, 422 validation_failed de la comprobación del esquema) no cuentan; los errores posteriores, como 403 feature_not_available, sí

Todos los límites

Bucket (X-RateLimit-Bucket)LímiteSe cuenta porSe aplica a
user600 por minutoEspacio de trabajo para los tokens de claves de API (todas las claves y herramientas de IA del espacio de trabajo juntas); persona para los inicios de sesión en el panelTodas las peticiones autenticadas a /v1 que no tienen un bucket propio
token30 por minutoDirección IPPOST /v1/token
public120 por minutoDirección IPPeticiones a la API sin autenticación, como GET /v1/plans y GET /v1/pages/available
callback120 por minutoDirección IPPOST /v1/callbacks/sale
internal120 por minutoDirección IPURL de ingesta de la integración «Custom (API)» (POST /v1/ingest/{id})
mcp120 por minutoConexión de IA (token de acceso)Servidor MCP en /mcp
oauth300 por minutoDirección IPInicio de sesión OAuth y discovery para asistentes de IA
auth30 por minutoDirección IPInicio de sesión, registro y restablecimiento de contraseña (panel y app)
refresh120 por minutoDirección IPProlongar una sesión del panel
discover60 por minutoPersona; dirección IP sin sesión iniciadaLa sección Descubrir de la app
subs_read120 por minutoPersona; dirección IP sin sesión iniciadaLeer las páginas que sigues (app)
subs_write20 por minutoPersona; dirección IP sin sesión iniciadaCambiar las páginas que sigues (app)

Un presupuesto por espacio de trabajo

Todos los tokens de claves de API del mismo espacio de trabajo comparten las 600 peticiones por minuto, da igual cuántas claves crees. Las herramientas de los asistentes de IA conectados también cuentan aquí, porque llaman a la API internamente. Por tanto, más claves no aumentan el límite. Si repartes mucha carga entre varios programas, planifica con el presupuesto compartido.

Los encabezados

X-RateLimit-Limit
El límite del bucket por minuto, por ejemplo 600.
X-RateLimit-Remaining
Cuántas peticiones quedan en el minuto actual.
X-RateLimit-Bucket
El bucket en el que cayó la petición, por ejemplo user.
Retry-After
Solo con 429 rate_limited: segundos hasta que empieza el minuto siguiente. Con api_key_locked, el tiempo de espera está en details.retry_after_sec.

Cuando se alcanza el límite

Cuando se alcanza el límite, la API responde con HTTP 429 y este cuerpo. El texto de message está en el idioma de la cuenta (consulta Formato y códigos de error), aquí en inglés; el código rate_limited no cambia:

Respuesta con 429
HTTP/1.1 429 Too Many Requests
Retry-After: 37
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
X-RateLimit-Bucket: user

{ "error": "rate_limited", "message": "Too many requests. Please try again in a moment.", "retry_after_sec": 37 }
  1. Lee Retry-After o retry_after_sec
  2. Espera al menos esos segundos, más un poco de aleatoriedad para que no todos los procesos vuelvan a empezar en el mismo momento
  3. Repite la petición unas pocas veces como mucho
  4. Si sigues recibiendo 429, reparte el trabajo en más tiempo
Node.js: guardar el token en caché y gestionar el 429
const BASE = 'https://dock.at-harbor.com';
let cached = null; // { token, expiresAt }

async function getToken() {
  if (cached && Date.now() < cached.expiresAt - 60_000) return cached.token;
  const res = await fetch(BASE + '/v1/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      key_id: process.env.LH_KEY_ID,
      key_secret: process.env.LH_KEY_SECRET,
    }),
  });
  if (!res.ok) throw new Error('Token exchange failed: HTTP ' + res.status);
  const data = await res.json();
  cached = { token: data.token, expiresAt: Date.now() + data.expires_in * 1000 };
  return cached.token;
}

async function lh(method, path, body, attempt = 0) {
  const headers = { Authorization: 'Bearer ' + (await getToken()) };
  if (body !== undefined) headers['Content-Type'] = 'application/json';

  const res = await fetch(BASE + path, {
    method,
    headers,
    body: body === undefined ? undefined : JSON.stringify(body),
  });

  if (res.status === 429 && attempt < 3) {
    const wait = Number(res.headers.get('Retry-After') ?? 5);
    await new Promise((r) => setTimeout(r, (wait + Math.random() * 2) * 1000));
    return lh(method, path, body, attempt + 1);
  }
  if (res.status === 401 && attempt === 0) {
    cached = null; // token caducado: un intento más con un token nuevo
    return lh(method, path, body, attempt + 1);
  }
  const data = await res.json().catch(() => null);
  if (!res.ok) throw new Error((data && data.error) + ' (HTTP ' + res.status + ')');
  return data;
}

// Ejemplo: const { items } = await lh('GET', '/v1/pages');

Consejos para grandes volúmenes de datos

  • Guarda el token en caché y renuévalo solo poco antes de que caduque a los 15 minutos
  • Vigila X-RateLimit-Remaining y ve más despacio cuando quede poco
  • Envía las peticiones una tras otra en lugar de por decenas de conexiones en paralelo
  • Carga las listas una vez y fíltralas localmente en lugar de consultar cada página por separado
  • Reparte las sincronizaciones grandes en varios minutos
  • Repite los errores 5xx con pausas cada vez más largas, pero no los errores 4xx

Otros límites

QuéLímiteRespuesta
Inicios de sesión fallidosBloqueo tras 5, 10 y 20 intentos fallidos por dirección de correo e IP: 60 segundos, 5 minutos, 30 minutos429 account_locked
Envíos de formularios10 por hora y dirección IP, sumando todos los formularios429 form_rate_limited

Los intentos fallidos en el intercambio de token bloquean temporalmente la clave y la IP; consulta Claves de API y tokens. Las notificaciones push solo se envían en el panel; sus límites se explican en Seguidores y notificaciones push.

Los límites de contenido de tu plan (páginas, enlaces, bloques, enlaces cortos, etc.) no son límites de peticiones, sino topes fijos. Están en Comparativa de planes.

Tamaño de la petición

Cada cuerpo se mide antes de que la API lo lea. El tamaño permitido depende del endpoint:

EndpointsCuerpo máximo
Inicio de sesión, registro y las demás llamadas sin autenticación bajo /v1/auth, POST /v1/token, POST /v1/oauth/exchange, los endpoints OAuth para asistentes de IA bajo /oauth y su consentimiento, POST /v1/ingest/{id}, el checkout del bloque Apoyar, las llamadas de suscripción de la app (seguir, colecciones, dispositivos push), cambiar de espacio de trabajo, POST /v1/auth/logout-all, eliminar una cuenta, configurar la autenticación en dos pasos, aceptar una invitación, activar el programa de referidos y el paso de vuelta al conectar una integración64 KB
Todos los demás endpoints JSON, incluido el envío de un formulario en una página1 MB
POST /v1/webhooks/{id}/verify-signature y el servidor MCP en /mcp2 MB
Subidas de archivos (POST /v1/assets y POST /v1/pages/{id}/uploads, multipart/form-data)11 MB para toda la petición, el archivo en sí como máximo 10 MB

Si el cuerpo es mayor, la API responde con 413 request_too_large; details.max_bytes y details.max_kb indican el límite. Un archivo demasiado grande en una subida provoca 413 payload_too_large. Los endpoints sin cuerpo, como las llamadas DELETE, no aceptan cuerpo o solo {}.

Respuesta con 413
HTTP/1.1 413 Payload Too Large

{ "error": "request_too_large", "message": "…", "details": { "max_bytes": 65536, "max_kb": 64 }, "request_id": "…" }

También hay límites dentro del cuerpo: cada texto tiene una longitud máxima, cada lista un número máximo de entradas, y los campos desconocidos se rechazan. Los valores de cada endpoint están en la referencia de la API. Una infracción provoca 422 validation_failed, y details indica el campo, la regla y el límite. La ruta y la query string de una petición pueden medir juntas como máximo 16 KB.

¿No has encontrado nada?

Cuéntanos qué necesitas y nuestro equipo de soporte te ayudará personalmente.

Contactar con soporte