# Límites

> Cuántas llamadas por minuto y por mes admite cada plan, qué responde la API al llegar al límite y cómo manejarlo.

La API tiene dos tipos de límites:

- **Topes por minuto**: frenan ráfagas, por ejemplo un script en un bucle. Se liberan solos en un minuto.
- **Cupos mensuales**: cuánto puedes usar en el mes. Se renuevan el **día 1 de cada mes**, a las 00:00 de Argentina.

Los dos se cuentan **por cuenta**: todas tus claves de API suman juntas.

## Por plan

<Note>
  La API y los webhooks están en los planes **Escala** y **Enterprise**. Mira [Planes y facturación](/guias/cuenta/planes).
</Note>

### Topes por minuto

| | Escala | Enterprise |
| --- | --- | --- |
| Solicitudes a la API (todas las rutas) | 300 | 1.200 |
| Mensajes con `POST /messages` | 60 | 300 |

El tope de mensajes es además del general: un `POST /messages` cuenta para los dos.

### Cupos mensuales y máximos

| | Escala | Enterprise |
| --- | --- | --- |
| Llamadas a la API por mes | 300.000 | Sin límite |
| Entregas de webhooks por mes | 500.000 | Sin límite |
| Claves de API vigentes | 10 | 50 |
| URLs de webhooks | 5 | 25 |

- **Llamadas a la API**: cada solicitud a `https://app.eltick.com/api/v1` con una clave válida, salga bien o mal. Las que se rechazan por el tope por minuto no cuentan. Las llamadas al [webhook entrante de una automatización](/guias/automatizaciones/integraciones#webhook-entrante) también cuentan y comparten el tope por minuto.
- **Entregas de webhooks**: cada evento que te mandamos a cada URL. Si un evento va a dos URLs, cuenta dos. Los reintentos de una misma entrega no suman.
- Las claves revocadas no cuentan. Si llegas al máximo de claves o de URLs, crear una nueva responde `402`: revoca o borra las que no uses.

Cuánto usaste de cada cupo lo ves en **Ajustes › Plan y uso**. El contador puede ir hasta medio minuto atrasado.

### Automatizaciones y MCP

Las automatizaciones y la conexión con Claude y ChatGPT tienen sus propios límites:

| | Prueba gratis | Crecimiento | Escala | Enterprise |
| --- | --- | --- | --- | --- |
| Pasos de automatizaciones por mes | 2.000 | 25.000 | 200.000 | Sin límite |
| Solicitudes HTTP de automatizaciones por mes | 200 | 5.000 | 50.000 | Sin límite |
| Apps de IA conectadas (MCP) | 3 | 10 | 25 | Sin límite |
| Herramientas del MCP por minuto, por app | 20 | 30 | 60 | 120 |

El detalle de las automatizaciones está en [Automatizaciones › Planes y límites](/guias/automatizaciones/introduccion#planes-y-limites).

## Qué pasa al llegar al límite

La API responde `429 Too Many Requests`. Hay tres casos:

<Tabs>
  <Tab title="Tope por minuto">
    ```http
    HTTP/1.1 429 Too Many Requests
    Retry-After: 60
    X-RateLimit-Limit: 300
    ```

    ```json
    { "error": "Superaste el tope de solicitudes por minuto de tu plan. Esperá un minuto." }
    ```

    Con `POST /messages`, si lo que se pasó es el tope de mensajes:

    ```json
    { "error": "Superaste el tope de mensajes por minuto de tu plan. Esperá un minuto." }
    ```

    - `Retry-After`: cuántos segundos esperar antes de volver a intentar.
    - `X-RateLimit-Limit`: el tope por minuto que se aplicó.

    **Qué hacer:** espera y reintenta. No se pierde nada: la solicitud rechazada no hizo nada.
  </Tab>
  <Tab title="Cupo mensual">
    ```json
    {
      "error": "Usaste las 300.000 llamadas a la API de este mes. Se renueva el 1° del mes, o pasate a Enterprise.",
      "cause": {
        "type": "upgrade",
        "reason": "limit",
        "resource": "apiCalls",
        "plan": "escala",
        "limit": 300000,
        "used": 300000,
        "suggested": "enterprise"
      }
    }
    ```

    Lo reconoces porque trae `cause.type: "upgrade"`, igual que los errores `402`. No trae `Retry-After`: reintentar no sirve hasta el día 1 o hasta cambiar de plan.

    **Qué hacer:** deja de reintentar, avisa a quien administra la cuenta y guarda lo pendiente para mandarlo después.
  </Tab>
  <Tab title="Claves inválidas">
    Si desde una misma IP llegan más de 20 solicitudes por minuto con claves inválidas, esa IP queda bloqueada un minuto, incluso para las claves válidas:

    ```json
    { "error": "Demasiados intentos con claves inválidas. Esperá un minuto." }
    ```

    **Qué hacer:** revisa que tu sistema no esté usando una clave revocada o mal copiada. Mira [Autenticación](/api/autenticacion).
  </Tab>
</Tabs>

### Webhooks

Cuando se usan todas las entregas de webhooks del mes, **los eventos siguientes no se encolan y no se mandan**, ni siquiera después, cuando se renueva el cupo. Si dependes de los webhooks, revisa el uso en **Ajustes › Plan y uso** y cambia de plan antes de llegar al límite.

Un evento cuyo `data` pesa más de 256 KB llega recortado, con esta forma:

```json
{
  "id": "01a0d4a6-…",
  "event": "automation.completed",
  "createdAt": "2026-09-25T14:03:11.000Z",
  "data": { "truncated": true, "id": null, "size": 301442 }
}
```

Si te pasa, consulta lo que necesites con la API.

### MCP

Si una app de IA conectada se pasa de su tope por minuto, el servidor MCP responde `429` con un error JSON-RPC (`code: -32000`) y el mismo `Retry-After: 60`.

## Buenas prácticas

<AccordionGroup>
  <Accordion title="Reintenta con espera creciente" icon="timer">
    Ante un `429` por tope por minuto (o un `500`), espera lo que diga `Retry-After` y, si vuelve a pasar, cada vez un poco más.

    ```javascript
    async function llamar(url, opciones, intentos = 5) {
      for (let i = 0; i < intentos; i++) {
        const res = await fetch(url, opciones)
        if (res.status !== 429 && res.status < 500) return res

        const cuerpo = await res.clone().json().catch(() => ({}))
        // Cupo mensual agotado: reintentar no sirve
        if (cuerpo.cause?.type === "upgrade") return res

        const espera = Number(res.headers.get("retry-after") ?? 1) * 1000
        await new Promise((r) => setTimeout(r, espera * 2 ** i + Math.random() * 1000))
      }
      throw new Error("La API sigue respondiendo 429 o 5xx")
    }
    ```

    <Warning>
      No reintentes a ciegas un `POST /messages` que falló por timeout o error de red: el mensaje pudo haber salido. Mira [Reintentos seguros](/api/errores#reintentos-seguros).
    </Warning>
  </Accordion>
  <Accordion title="Reparte los envíos en el tiempo" icon="gauge">
    Si tienes que mandar muchos mensajes por la API, no los mandes todos juntos: mantente debajo del tope (por ejemplo, 1 por segundo en Escala). Para envíos masivos a una lista, usa una [campaña](/guias/campanas/crear): va en tandas que cuidan la calidad de tu número y no cuenta en los límites de la API.
  </Accordion>
  <Accordion title="Agrupa y guarda en caché" icon="layers">
    - Usa `limit=200` al [paginar](/api/paginacion): son menos llamadas que con páginas chicas.
    - Guarda en tu sistema lo que casi no cambia, como las plantillas (`GET /templates`) o los datos de la cuenta (`GET /me`).
    - No uses la API para preguntar cada tanto si algo cambió: suscríbete a los [webhooks](/api/webhooks/introduccion).
  </Accordion>
  <Accordion title="Una sola cola para toda la cuenta" icon="list-ordered">
    Los topes son por cuenta, no por clave. Si varios sistemas usan la API de la misma cuenta, reparte el tope entre ellos, o manda todo por una cola en común.
  </Accordion>
</AccordionGroup>

<Note>
  Los topes por minuto son aproximados: se cuentan por región y en ventanas de un minuto. No calcules al límite exacto; deja margen.
</Note>
