Límites de uso
Los límites se aplican por credencial, bajo un techo de la cuenta, y por categoría de ruta, en una ventana móvil de 60 segundos.
| Categoría | Rutas | Límite |
|---|---|---|
| Envío de mensajes | POST /messages y POST /v1/.../messages | 500 req/min |
| Subida de medios | POST /v1/.../media | 60 req/min |
| Consultas | todo lo demás (/templates, /events, otros /v1/*) | 60 req/min |
Los valores de la tabla son los predeterminados. Tu plan puede definir límites propios por categoría, y entonces valen los del plan.
Sin límite: /plans y /health.
Por clave, bajo un techo de la cuenta
Cada clave de API tiene su propio cubo, del tamaño que define el plan — y también cada
persona conectada al panel. Una integración atrapada en un bucle agota solo su propia
cuota: la clave del plugin de WordPress martilleando /v1 no deja la clave de tu ERP en
429.
Por encima de los cubos de las claves, la cuenta tiene un techo por categoría, por defecto 3 veces el límite del plan. Es lo que impide que crear más claves multiplique la cuota sin fin: con el envío en 500/min, una clave sola llega a 500 envíos por minuto, y todas las claves de la cuenta juntas, a 1.500.
El panel queda fuera de ese techo: quien está conectado gasta solo su propio cubo. Una clave en bucle puede agotar el techo de la cuenta, pero no te deja fuera del panel — que es donde encuentras y revocas esa clave.
Cabeceras de control
Cada respuesta de una ruta limitada trae el estado actual del cubo:
| Cabecera | Contenido |
|---|---|
X-RateLimit-Category | send, media o default |
X-RateLimit-Scope | El cubo descrito: key (clave de API), session (panel) o account |
X-RateLimit-Limit | Techo de ese cubo en la ventana |
X-RateLimit-Remaining | Cuánto queda |
En una respuesta exitosa, las cabeceras describen el cubo de tu credencial. En un
429, describen el cubo que rechazó — que puede ser el de la cuenta.
HTTP/1.1 201 Created
X-RateLimit-Category: send
X-RateLimit-Scope: key
X-RateLimit-Limit: 500
X-RateLimit-Remaining: 487
Vigila X-RateLimit-Remaining y baja el ritmo antes de tocar el techo — sale más barato
que tratar un 429.
Cuando se supera el límite
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Category: send
X-RateLimit-Scope: key
X-RateLimit-Limit: 500
X-RateLimit-Remaining: 0
{
"error": {
"message": "Rate limit exceeded for send requests with this credential. Try again in 12s.",
"type": "rate_limit",
"scope": "key"
}
}
El campo error.scope repite X-RateLimit-Scope. Cuando dice account, tu clave todavía
tenía cuota: fueron las otras claves de la cuenta, sumadas, las que agotaron el techo.
Repartir las llamadas entre más claves no sirve — solo esperar.
La cabecera Retry-After dice exactamente cuántos segundos esperar. Respétala —
insistir antes solo consume cuota.
Tratar el 429
async function enviar(payload, intento = 0) {
const response = await fetch('https://api.joinotify.com/messages', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JOINOTIFY_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
if (response.status === 429 && intento < 3) {
const espera = Number(response.headers.get('retry-after') ?? 5);
await new Promise((resolve) => setTimeout(resolve, espera * 1000));
return enviar(payload, intento + 1);
}
return response.json();
}
Para envíos masivos, prefiere una cola con tasa controlada (por ejemplo 8 mensajes por segundo, muy por debajo de 500/min) en lugar de disparar todo y reaccionar al error.
Los límites de Meta también cuentan
Los números de arriba son los límites de Joinotify. Por debajo, Meta impone los suyos — el límite de mensajes iniciados por la empresa en 24 horas, que varía según la calidad y el nivel de verificación de tu número.
Cuando es Meta quien rechaza, la respuesta llega como meta_error con su cuerpo original
en error.meta, y no como rate_limit.
¿Necesitas más?
Los límites son configurables por cuenta. Si tu volumen exige más, escribe a soporte con una estimación de tu pico por minuto.