# Rate Limits

> Límites de uso de la API de Plazbot por workspace

Fuente: https://developers.plazbot.com/sdk/rate-limits/

La API de Plazbot aplica un límite de uso por workspace para garantizar la estabilidad de la plataforma. El límite usa un modelo **token bucket**: permite rafagas cortas y castiga solo el uso sostenido por encima del límite.

## Límites

| Recurso | Límite |
|---------|--------|
| API REST (todas las rutas) | **120 requests por minuto por workspace**, con rafaga adicional de hasta 40 requests |
| Webhooks entrantes de workers (`POST /api/worker/webhook/{nombre}`) | 100 requests por minuto por webhook |

El límite se comparte entre todas las integraciones que usan el mismo workspace (SDK, API REST directa, MCP, workers).

## Headers de respuesta

Cada respuesta de la API incluye headers informativos para que tu integración pueda autorregularse:

| Header | Descripción |
|--------|-------------|
| `X-RateLimit-Limit` | Límite de requests por minuto del workspace. |
| `X-RateLimit-Remaining` | Requests disponibles en este momento (incluye la rafaga). |

## Respuesta al exceder el límite

Cuando el límite se excede, la API responde `429 Too Many Requests` con el header `Retry-After` (segundos a esperar antes de reintentar):

```json
{
"success": false,
"code": 429,
"errorCode": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit excedido. Máximo 120 requests por minuto por workspace."
}
```

## Buenas prácticas

- **Respeta `Retry-After`**: al recibir un `429`, espera los segundos indicados antes de reintentar. No reintentes en loop inmediato.
- **Usa backoff exponencial** en procesos batch: si un `429` se repite, duplica la espera en cada reintento.
- **Página con `pageSize=100`**: para recorrer contactos usa el tamaño de página máximo y minimiza la cantidad de llamadas (ver [Contactos - Paginación](https://developers.plazbot.com/sdk/contact)).
- **Cachea lo que no cambia**: variables del workspace, etiquetas y fases cambian poco; no las consultes en cada request.

## Ejemplo de manejo de 429

```ts
async function callWithRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
for (let attempt = 0; ; attempt++) {
  try {
    return await fn();
  } catch (error: any) {
    const status = error?.response?.status;
    if (status !== 429 || attempt >= maxRetries) throw error;

    const retryAfter = Number(error.response.headers["retry-after"] ?? 5);
    await new Promise((r) => setTimeout(r, retryAfter * 1000 * (attempt + 1)));
  }
}
}
```
