> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs.rhombus.community/llms.txt
> Use this file to discover all available pages before exploring further.

# Límites de tasa

> Comprende los límites de tasa de la API de Rhombus y crea integraciones resilientes que manejen respuestas 429 limitadas con retroceso exponencial y lógica de reintento.

<Note>
  Esta página fue traducida automáticamente. Si encuentra errores o tiene sugerencias, [contáctenos](mailto:support@rhombus.com).
</Note>

Todas las solicitudes a la API autenticadas mediante **API key** o **token OAuth** están sujetas a limitación de tasa. Los límites se aplican **por organización**: cada API key y token OAuth emitido a tu organización comparte un único presupuesto de límite de tasa. Crear credenciales adicionales no aumenta tu límite.

| Método de autenticación | Header                | Aplica a                                 |
| ----------------------- | --------------------- | ---------------------------------------- |
| API key                 | `x-auth-apikey`       | Cuentas de Developer y Partner Developer |
| Token OAuth             | `x-auth-access-token` | Aplicaciones autorizadas por OAuth       |

## Cómo funcionan los límites

Rhombus usa un algoritmo de **token bucket** (cubo de tokens). Dos valores rigen tu rendimiento:

* Una **tasa de recarga sostenida** (solicitudes por segundo): tu límite máximo en estado estable.
* Una **capacidad de ráfaga**, aproximadamente 10× la tasa de recarga de forma predeterminada: margen que absorbe picos cortos.

Las ráfagas tienen éxito de inmediato mientras el cubo tiene tokens. Una vez que el cubo se vacía, el tráfico sostenido por encima de la tasa de recarga devuelve `429` hasta que el cubo se vuelve a llenar.

Las tasas predeterminadas se aplican a todas las organizaciones. Para solicitar un límite más alto, contacta al [soporte de Rhombus](mailto:support@rhombus.com).

## Respuestas limitadas

Cuando tu solicitud es limitada por tasa, la API devuelve un estado `429` con un header `Retry-After`:

```text HTTP 429 response theme={null}
HTTP/1.1 429 Too Many Requests
Retry-After: 1
Content-Type: text/plain

Too many api requests. Enhance your calm.
```

| Detalle              | Valor                                                                                                                                |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Código de estado     | `429`                                                                                                                                |
| Header `Retry-After` | Segundos a esperar antes de reintentar. Se calcula a partir de la tasa de recarga de tu organización; siempre es al menos 1 segundo. |
| Cuerpo               | `Too many api requests. Enhance your calm.`                                                                                          |

<Warning>
  **No** reintentes de inmediato ante un `429`. Las solicitudes repetidas mientras estás limitado siguen siendo rechazadas y no reinician tu ventana de límite.
</Warning>

## Manejo de los límites de tasa

<Steps>
  <Step title="Lee el header Retry-After">
    El header `Retry-After` te indica exactamente cuántos segundos debes esperar, calculado a partir de la tasa de recarga de tu organización. Prefiere siempre este valor en lugar de retrasos codificados.
  </Step>

  <Step title="Pausa las solicitudes">
    Deja de enviar solicitudes durante el tiempo especificado en el header.
  </Step>

  <Step title="Reintenta tu solicitud">
    Después del periodo de espera, reintenta la solicitud original.
  </Step>
</Steps>

## Estrategia de reintento

Usa **retroceso exponencial con jitter** para la integración más resiliente:

```text Backoff formula theme={null}
delay = min(base_delay × 2^attempt + random_jitter, max_delay)
```

| Parámetro                       | Valor recomendado          |
| ------------------------------- | -------------------------- |
| Retraso base                    | 1 segundo                  |
| Retraso máximo                  | 60 segundos                |
| Máximo de intentos de reintento | 5–10                       |
| Jitter                          | Aleatorio de 0 a 1 segundo |

<Tabs>
  <Tab title="Python">
    ```python retry_with_backoff.py theme={null}
    import time
    import random
    import requests

    def call_api(url, headers, payload, max_retries=5):
        for attempt in range(max_retries):
            response = requests.post(url, headers=headers, json=payload)

            if response.status_code == 200:
                return response.json()

            if response.status_code == 429:
                wait = int(response.headers.get("Retry-After", 60))
                time.sleep(wait)
                continue

            if response.status_code >= 500:
                delay = min(1 * (2 ** attempt) + random.random(), 60)
                time.sleep(delay)
                continue

            # Los errores 4xx (distintos de 429) no se pueden reintentar
            response.raise_for_status()

        raise Exception("Max retries exceeded")

    # Uso
    result = call_api(
        url="https://api2.rhombussystems.com/api/camera/getMinimalCameraStateList",
        headers={
            "x-auth-scheme": "api-token",
            "x-auth-apikey": "YOUR_API_KEY",
            "Content-Type": "application/json"
        },
        payload={}
    )
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript retryWithBackoff.js theme={null}
    async function callApi(url, headers, payload, maxRetries = 5) {
      for (let attempt = 0; attempt < maxRetries; attempt++) {
        const response = await fetch(url, {
          method: "POST",
          headers: { "Content-Type": "application/json", ...headers },
          body: JSON.stringify(payload),
        });

        if (response.ok) {
          return await response.json();
        }

        if (response.status === 429) {
          const wait = parseInt(response.headers.get("Retry-After") || "60", 10);
          await new Promise((r) => setTimeout(r, wait * 1000));
          continue;
        }

        if (response.status >= 500) {
          const delay = Math.min(1 * 2 ** attempt + Math.random(), 60);
          await new Promise((r) => setTimeout(r, delay * 1000));
          continue;
        }

        // Los errores 4xx (distintos de 429) no se pueden reintentar
        throw new Error(`Request failed: ${response.status} ${response.statusText}`);
      }

      throw new Error("Max retries exceeded");
    }

    // Uso
    const result = await callApi(
      "https://api2.rhombussystems.com/api/camera/getMinimalCameraStateList",
      {
        "x-auth-scheme": "api-token",
        "x-auth-apikey": "YOUR_API_KEY",
      },
      {}
    );
    ```
  </Tab>

  <Tab title="cURL">
    ```bash retry_loop.sh theme={null}
    #!/bin/bash
    URL="https://api2.rhombussystems.com/api/camera/getMinimalCameraStateList"
    API_KEY="YOUR_API_KEY"
    MAX_RETRIES=5

    for attempt in $(seq 0 $((MAX_RETRIES - 1))); do
      HTTP_CODE=$(curl -s -o /tmp/response.json -D /tmp/response.headers -w "%{http_code}" \
        -X POST "$URL" \
        -H "Content-Type: application/json" \
        -H "x-auth-scheme: api-token" \
        -H "x-auth-apikey: $API_KEY" \
        -d '{}')

      if [ "$HTTP_CODE" -eq 200 ]; then
        cat /tmp/response.json
        exit 0
      elif [ "$HTTP_CODE" -eq 429 ]; then
        RETRY_AFTER=$(awk 'tolower($1) == "retry-after:" { gsub(/[^0-9]/, "", $2); print $2; exit }' /tmp/response.headers)
        : "${RETRY_AFTER:=60}"
        echo "Rate limited. Waiting ${RETRY_AFTER} seconds..." >&2
        sleep "$RETRY_AFTER"
      elif [ "$HTTP_CODE" -ge 500 ]; then
        DELAY=$(echo "1 * 2^$attempt" | bc)
        [ "$DELAY" -gt 60 ] && DELAY=60
        echo "Server error ($HTTP_CODE). Retrying in ${DELAY}s..." >&2
        sleep "$DELAY"
      else
        echo "Client error ($HTTP_CODE). Not retrying." >&2
        cat /tmp/response.json >&2
        exit 1
      fi
    done

    echo "Max retries exceeded." >&2
    exit 1
    ```
  </Tab>
</Tabs>

## Cuándo reintentar

| Respuesta      | Acción                                                              |
| -------------- | ------------------------------------------------------------------- |
| `200–299`      | Éxito: no se necesita reintentar                                    |
| `429`          | Espera los segundos de `Retry-After` y luego reintenta              |
| `5xx`          | Error transitorio del servidor: reintenta con retroceso exponencial |
| `4xx` (no 429) | Error del cliente: corrige la solicitud, no reintentes              |

<Info>
  El sistema de limitación de tasa es **fail-open** (a prueba de fallos abierto). Si el servicio de límite de tasa o su almacén de respaldo no está disponible, tu solicitud se deja pasar. No dependas de este comportamiento: diseña siempre tu integración para respetar los límites.
</Info>

## Qué cambió

<Note>
  Las mejoras recientes del limitador de tasa ya están activas:

  * Los límites ahora se agrupan entre todas las credenciales de una organización. Distribuir el tráfico entre varias API keys ya no aumenta el rendimiento.
  * Ahora se permiten ráfagas cortas por encima de tu tasa sostenida.
  * `Retry-After` refleja el tiempo de espera real calculado a partir de tu tasa de recarga, en lugar de un valor fijo de 60 segundos.
</Note>

## Throttling de notificaciones de alertas

Las notificaciones de alertas (distintas de los límites de tasa de la API) tienen un **intervalo mínimo** configurable entre alertas consecutivas del mismo tipo para un dispositivo dado. Esto evita la fatiga por alertas debida a eventos de alta frecuencia como la detección de movimiento.

| Intervalo                      | Segundos |
| ------------------------------ | -------- |
| 1 minuto                       | 60       |
| 2 minutos                      | 120      |
| **5 minutos (predeterminado)** | 300      |
| 10 minutos                     | 600      |
| 20 minutos                     | 1200     |
| 30 minutos                     | 1800     |
| 1 hora                         | 3600     |

Configura esto por política y por tipo de actividad. Durante la ventana de retroceso, las alertas duplicadas para el mismo dispositivo y tipo de actividad se suprimen del lado del servidor.

<Tip>
  Las alertas con **nueva información de identidad** —como un rostro reconocido distinto o una placa de matrícula— omiten el retroceso y se entregan de inmediato, incluso dentro de la ventana de supresión.
</Tip>
