Errores y límites
Toda respuesta que no sea 2xx usa el mismo envelope. El request_id coincide con la cabecera X-Request-ID, y es lo que hace rastreable un fallo concreto.
El envelope
{
"error": {
"code": "not_found",
"message": "Resource not found",
"request_id": "b3f1c2a4-..."
}
}Los errores de validación devuelven 422 con code "validation_error". El message enumera los campos que fallan, en formato campo: motivo.
{
"error": {
"code": "validation_error",
"message": "body.email: value is not a valid email address; body.name: field required",
"request_id": "b3f1c2a4-..."
}
}| Estado | Código | Cuándo sale |
|---|---|---|
| 401 | unauthorized | Token ausente, inválido o caducado. |
| 403 | forbidden | Autenticado, pero sin permiso para esa acción. |
| 404 | not_found | No existe, o no eres miembro de su organización. |
| 409 | conflict | Conflicto de estado: por ejemplo, un valor único repetido. |
| 422 | validation_error | El cuerpo o los parámetros no pasan la validación. |
| 429 | too_many_requests | Se pasó el límite. Reintenta más tarde. |
Límites de uso
El límite es fail-open: si el servicio que los cuenta no está disponible, la petición no se bloquea — prevalece la disponibilidad. Aun así, diseña tus clientes para reintentar con espera exponencial ante un 429, y evita las ráfagas que no hacen falta.
Cupos de las llamadas con token
Además del techo por IP, las llamadas hechas con un token (o por OAuth desde un asistente) cuentan en cupos propios, por persona y por organización. Son los valores por defecto del servidor.
| Cupo | Límite | Se cuenta por |
|---|---|---|
| Lecturas | 120 por minuto | actor y persona, en cada organización |
| Escrituras | 20 por minuto | actor y persona, en cada organización |
| Operaciones financieras que modifican | 5 por hora | actor y persona, en cada organización |
| Toda la organización | 600 lecturas, 120 escrituras por minuto y 30 financieras por hora | todos los agentes de la organización juntos |
| Techo global de agentes | 300 peticiones por minuto | persona, en todas sus organizaciones |
| Apertura de streams (SSE) | 60 por minuto | persona, agente o IP |
Acuñar más tokens no da más cupo: se cuenta también por la persona. Estas cifras se ajustan con carga real, así que no las hardcodees: lee la cabecera Retry-After.
Qué hacer ante un 429
Un 429 trae la cabecera Retry-After con los segundos que faltan para que quepa otra petición. Espera ese tiempo, no una ventana entera a ciegas, y reintenta unas pocas veces. La API no envía cabeceras X-RateLimit-*: el aviso es el propio 429.
async function llamar(url, token, intentos = 4) {
for (let i = 0; i < intentos; i++) {
const r = await fetch(url, { headers: { Authorization: `Bearer ${token}` } });
if (r.status !== 429) return r;
const espera = Number(r.headers.get('Retry-After')) || 2 ** i;
await new Promise((ok) => setTimeout(ok, espera * 1000));
}
throw new Error('Sigue limitado tras varios intentos');
}