> ## Índice de la documentación
> Consulta el índice completo de la documentación en: https://developer.rhombus.com/llms.txt
> Úsalo para descubrir todas las páginas disponibles antes de seguir explorando.

# Errores y códigos de estado

> Cómo informa errores la API REST de Rhombus: códigos de estado HTTP, el cuerpo de error y su errorCode, errores de autenticación y de permisos, el campo error en las respuestas 200, errores de validación y de JSON, errores del servidor y qué fallos reintentar.

> **Note**: Esta página se tradujo automáticamente. Si encuentras errores o tienes sugerencias, [escríbenos](mailto:support@rhombus.com).

La API REST informa una solicitud fallida de una de dos formas, así que revisa ambas:

1. **Un código de estado HTTP de error** cuando la solicitud no se puede procesar: JSON mal formado, un campo que falta, un problema con la credencial, un permiso denegado o un límite de tasa. El cuerpo tiene `"error": true` y un `errorCode` legible por máquina.
2. **HTTP `200` con `"error": true`** cuando la solicitud era válida pero la acción falló o se rechazó, por ejemplo un rol que no puedes asignar. El motivo está en `errorMsg`:

```json
{
  "error": true,
  "errorMsg": "User not permitted to generate an api token for the specified role"
}
```

Una solicitud tuvo éxito solo cuando el estado es `2xx` **y** `error` es `false`.

## El sobre de la respuesta

Cada respuesta JSON de la API REST incluye los mismos tres campos junto a sus datos:

| Campo        | Presente                 | Significado                                                                                                      |
| ------------ | ------------------------ | ---------------------------------------------------------------------------------------------------------------- |
| `error`      | Siempre                  | `false` si tuvo éxito, `true` si la acción falló                                                                 |
| `errorMsg`   | Cuando `error` es `true` | Un motivo legible. Regístralo y muéstralo a un operador; no lo analices, porque su texto puede cambiar           |
| `warningMsg` | Rara vez                 | La solicitud tuvo éxito, pero algo requiere atención, como un valor predeterminado que el servidor aplicó por ti |

Las respuestas de error tienen el mismo cuerpo en todos los hosts: la API REST, los hosts de medios, los handshakes de WebSocket y el servidor MCP.

Los campos con valor nulo se omiten en las respuestas, así que trata un campo ausente como nulo. Las listas vacías sí se envían.

## Códigos de estado

| Estado                    | Cuerpo                                                                                               | Significado                                                                                                                                                                                     | ¿Reintentar?                                                                                                                          |
| ------------------------- | ---------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `200` con `"error": true` | `{"error":true,"errorMsg":"…", …}`                                                                   | La acción falló o se rechazó                                                                                                                                                                    | No; actúa según `errorMsg`                                                                                                            |
| `400`                     | `{"msg":"Invalid Json", …}`                                                                          | El cuerpo no es JSON válido                                                                                                                                                                     | No                                                                                                                                    |
| `400`                     | `{"msg":"JSON doesn't match expected object structure", …}`                                          | Un campo tiene el tipo equivocado, un valor de enum no se reconoce o (en algunas operaciones) el cuerpo trae un campo que la operación no acepta                                                | No                                                                                                                                    |
| `400`                     | `{"msg":"Request missing required field", …}` o `{"error":true,"errorMsg":"[Error: [campo]: …]", …}` | Falta un campo obligatorio o un valor está fuera de rango. El mensaje nombra el campo                                                                                                           | No                                                                                                                                    |
| `400`                     | `{"errorCode":"INVALID_AUTH_ORG", …}`                                                                | El encabezado `x-auth-org` está mal formado                                                                                                                                                     | No                                                                                                                                    |
| `401`                     | `{"errorCode":"UNAUTHENTICATED", …}` u otro código de credencial                                     | La credencial falta, está mal formada, es desconocida, venció o fue revocada                                                                                                                    | No; consulta [Errores de autenticación y de permisos](https://developer.rhombus.com/es/errors#errores-de-autenticación-y-de-permisos) |
| `403`                     | `{"errorCode":"PERMISSION_REQUIRED", …}` u otro código de permiso                                    | La credencial es válida, pero no tiene permiso para hacer esto                                                                                                                                  | No; consulta [Errores de autenticación y de permisos](https://developer.rhombus.com/es/errors#errores-de-autenticación-y-de-permisos) |
| `404`                     | `{"msg":"Not Found", …}`                                                                             | La ruta `/api` no existe (`NOT_FOUND`; las rutas distinguen mayúsculas y minúsculas, así que una ruta con mayúsculas incorrectas también recibe `404`), o algo que la operación busca no existe | No                                                                                                                                    |
| `405`                     | `{"errorCode":"METHOD_NOT_ALLOWED", …}`                                                              | La ruta no acepta este método HTTP                                                                                                                                                              | No                                                                                                                                    |
| `415`                     | `{"errorCode":"UNSUPPORTED_MEDIA_TYPE", …}`                                                          | El `Content-Type` de la solicitud no es uno que la operación acepte                                                                                                                             | No                                                                                                                                    |
| `429`                     | `{"errorCode":"RATE_LIMITED", …}` o un `errorMsg` que nombra las cámaras                             | El límite de tasa de tu organización o un límite por cámara para clips y fotogramas                                                                                                             | Sí, después de `Retry-After`; consulta [Límites de tasa](https://developer.rhombus.com/es/rate-limits)                                |
| `500`                     | `{"msg":"…", …}`                                                                                     | Un error inesperado del servidor                                                                                                                                                                | Sí, unas pocas veces con espera exponencial                                                                                           |
| `503`                     | `{"errorCode":"SERVICE_UNAVAILABLE", …}`                                                             | Rhombus no pudo comprobar la credencial en ese momento                                                                                                                                          | Sí, con espera exponencial                                                                                                            |
| `502`, `503`, `504`       | Varía                                                                                                | Un problema temporal de la puerta de enlace o de disponibilidad                                                                                                                                 | Sí, con espera exponencial                                                                                                            |

La mayoría de los rechazos llegan como `200` con `"error": true`; solo algunas operaciones responden `404`. Maneja ambos casos.

## Errores de autenticación y de permisos

`401` significa que Rhombus no pudo establecer quién llama. `403` significa que sí pudo, y que ese llamador no tiene permiso para hacer esto. Ninguno tiene éxito si lo repites sin cambios: corrige la credencial, el rol o la solicitud. El único caso que se reintenta es una credencial vencida, después de renovarla.

| Estado | `errorCode`                    | Causa                                                                                                                                             |
| ------ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `401`  | `UNAUTHENTICATED`              | No se presentó ninguna credencial                                                                                                                 |
| `401`  | `INVALID_CREDENTIAL`           | La credencial está mal formada o no se reconoce, incluida una clave de API eliminada o un token federado revocado                                 |
| `401`  | `CREDENTIAL_EXPIRED`           | La credencial venció. Renueva el token de acceso OAuth, emite un nuevo token federado o reemplaza la clave de API, y reintenta                    |
| `401`  | `CREDENTIAL_REVOKED`           | Se revocó la autorización de OAuth detrás del access token                                                                                        |
| `401`  | `CERTIFICATE_MISMATCH`         | El certificado de cliente no pertenece a la clave de API (`Client certificate does not match the api key`)                                        |
| `403`  | `PERMISSION_REQUIRED`          | El rol de la credencial, o los scopes de un token de acceso OAuth, no permiten esta operación o este dispositivo                                  |
| `403`  | `PARTNER_CLIENT_ACCESS_DENIED` | La credencial de partner no puede actuar en la organización indicada en `x-auth-org`                                                              |
| `403`  | `DOMAIN_NOT_ALLOWED`           | Un token federado emitido con un `domain` llegó desde otro sitio: el `Origin` de la solicitud, o su `Referer` cuando no hay `Origin`, no coincide |
| `403`  | `DEVICE_SCOPE_MISMATCH`        | Un token federado limitado a un dispositivo se usó para otro dispositivo o para una solicitud que no está ligada a su dispositivo                 |

**Scope de OAuth faltante.** Cuando a un token de acceso OAuth le falta el scope que necesita una operación, el `403` nombra el scope en un encabezado `WWW-Authenticate`. Pide ese scope cuando el usuario inicia sesión ([Iniciar sesión con Rhombus](https://developer.rhombus.com/es/oauth-authentication)):

```text Scope faltante
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope", scope="physical"
```

**Enlaces compartidos protegidos con contraseña.** Una solicitud a un enlace compartido protegido con contraseña sin la contraseña correcta recibe `401` con `WWW-Authenticate: Basic`.

[Autenticación](https://developer.rhombus.com/es/authentication#cómo-interpretar-los-errores-de-autenticación) indica qué revisar para cada tipo de credencial.

## Cuerpos de solicitud

- **Envía `POST` con `Content-Type: application/json`** y un objeto JSON, `{}` cuando la operación no recibe parámetros.
- **Los nombres de campo distinguen mayúsculas y minúsculas, y la mayoría de las operaciones ignoran los campos que no reconocen.** Un campo mal escrito o con mayúsculas incorrectas se descarta sin error, así que un filtro que parece no tener efecto suele ser un error de escritura. Copia los nombres de campo de la [referencia de la API](https://developer.rhombus.com/api-reference/overview) (en inglés).
- **Los valores de enum distinguen mayúsculas y minúsculas.** Un valor no reconocido normalmente se rechaza con `400`, pero algunos campos lo sustituyen por su valor predeterminado, así que un error de escritura puede cambiar una configuración. Envía los valores exactamente como los lista la referencia.
- **Las marcas de tiempo son milisegundos de época Unix** en los campos que terminan en `Ms`. Los campos que terminan en `Sec`, `Secs` o `Seconds` están en segundos.
- **Los mensajes de validación usan los nombres de campo del servidor**, que pueden llevar un guion bajo inicial: `[Error: [_targetUuid]: unexpected null value for required field]` se refiere a `targetUuid`.

## Reintentos y espera exponencial

Reintenta solo lo que puede tener éxito sin cambios:

| Respuesta                                                                      | Acción                                                                              |
| ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
| `2xx` con `"error": false`                                                     | Éxito                                                                               |
| `2xx` con `"error": true`                                                      | No reintentes sin cambios; corrige la solicitud o los datos que describe `errorMsg` |
| `400`, `401`, `403`, `404`, `405`, `415`                                       | No reintentes; corrige la solicitud, la credencial o el rol                         |
| `401` con `CREDENTIAL_EXPIRED`                                                 | Renueva la credencial y reintenta                                                   |
| `429`                                                                          | Espera los segundos de `Retry-After` y reintenta                                    |
| `500`, `502`, `503`, `504`, un tiempo de espera agotado o una conexión cortada | Reintenta con espera exponencial y jitter                                           |

Cómo esperar:

- **Limitación (`429`)**: el servidor indica cuánto esperar en `Retry-After`, tanto para el [límite de tu organización](https://developer.rhombus.com/es/rate-limits) como para los [límites por cámara](https://developer.rhombus.com/es/rate-limits#límites-por-cámara-para-clips-y-fotogramas) de clips y fotogramas. Espera al menos ese tiempo, más un poco de jitter aleatorio para que muchos procesos no reintenten en el mismo instante. Reintentar antes de tiempo con una cámara limitada alarga su siguiente espera.
- **Fallos temporales (`5xx`, errores de red)**: espera de forma exponencial con jitter completo: un tiempo aleatorio entre 0 y `min(60 s, 1 s × 2^intento)`.
- **Limita cada ciclo de reintentos** con un número máximo de intentos (unos 5) y un presupuesto de tiempo, y después informa el fallo con su estado, `errorCode`, `errorMsg` y `txid`.
- **Comprueba antes de repetir una escritura.** Si una solicitud que crea algo (un clip, una clave, un usuario) agotó el tiempo o falló con un `5xx`, puede haber tenido éxito igualmente; busca el resultado antes de enviarla de nuevo para no crear un duplicado.
- **Comparte el presupuesto.** Todas las claves y tokens de tu organización consumen el mismo límite de tasa, así que muchos procesos reintentando a la vez cuentan juntos; reparte las tareas programadas en lugar de iniciarlas todas en el mismo minuto.

Un cliente que sigue estas reglas:

```python Python
import random
import time

import requests

RETRYABLE = {429, 500, 502, 503, 504}

session = requests.Session()
session.headers.update({"x-auth-scheme": "api-token", "x-auth-apikey": "YOUR_API_KEY"})

def call(url, body, attempts=5, base=1.0, cap=60.0, budget=120.0):
    """POST to the Rhombus API, retrying throttling and temporary failures."""
    deadline = time.monotonic() + budget
    for attempt in range(attempts):
        try:
            response = session.post(url, json=body, timeout=30)
        except (requests.ConnectionError, requests.Timeout):
            response = None  # network trouble: retry like a 5xx
        if response is not None and response.status_code not in RETRYABLE:
            response.raise_for_status()  # other 4xx: fix the request, don't retry
            data = response.json()
            if data.get("error"):
                raise RuntimeError(data.get("errorMsg"))  # refused: don't retry unchanged
            return data
        if response is not None and response.status_code == 429:
            delay = float(response.headers.get("Retry-After", "1")) + random.uniform(0, 1)
        else:
            delay = random.uniform(0, min(cap, base * 2 ** attempt))
        if attempt == attempts - 1 or time.monotonic() + delay > deadline:
            break
        time.sleep(delay)
    raise RuntimeError(f"gave up after {attempt + 1} attempts: {url}")
```

```javascript JavaScript
const RETRYABLE = new Set([429, 500, 502, 503, 504]);
const headers = { "x-auth-scheme": "api-token", "x-auth-apikey": "YOUR_API_KEY", "Content-Type": "application/json" };
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

export async function call(url, body, { attempts = 5, baseMs = 1000, capMs = 60000, budgetMs = 120000 } = {}) {
  const deadline = Date.now() + budgetMs;
  for (let attempt = 0; attempt < attempts; attempt++) {
    let response;
    try {
      response = await fetch(url, { method: "POST", headers, body: JSON.stringify(body), signal: AbortSignal.timeout(30000) });
    } catch {
      response = undefined; // network trouble: retry like a 5xx
    }
    if (response && !RETRYABLE.has(response.status)) {
      if (!response.ok) throw new Error(`HTTP ${response.status}`); // other 4xx: fix the request
      const data = await response.json();
      if (data.error) throw new Error(data.errorMsg); // refused: don't retry unchanged
      return data;
    }
    const delay =
      response?.status === 429
        ? Number(response.headers.get("Retry-After") ?? 1) * 1000 + Math.random() * 1000
        : Math.random() * Math.min(capMs, baseMs * 2 ** attempt);
    if (attempt === attempts - 1 || Date.now() + delay > deadline) break;
    await sleep(delay);
  }
  throw new Error(`gave up: ${url}`);
}
```

## Contactar al soporte

Cuando un error persiste, escribe a <support@rhombus.com> con:

- La ruta de la operación y la hora de la solicitud, con su zona horaria.
- Tu región (EE. UU. o UE).
- El código de estado y el cuerpo, incluidos `errorCode` y `errorMsg`.
- El ID de la solicitud: `txid` en el cuerpo del error, que también se envía como encabezado de respuesta `x-rhombus-txid`.

Nunca envíes tu clave de API, tus tokens OAuth ni tus tokens federados.
