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

# Errores

> Códigos de error estables y cómo reaccionar a cada uno.

Todas las respuestas de error tienen este shape:

```json theme={null}
{
  "error": "code_estable",
  "message": "Descripción humana corta.",
  "request_id": "f0c0a9d2-8b1e-4d8a-9c2f-6e5b7a1d2c3b"
}
```

* **`error`** — código estable. Programa contra este campo, no contra `message` ni el HTTP status (a veces compartimos status entre causas distintas).
* **`message`** — texto corto para mostrar a un humano o loggear.
* **`request_id`** — UUID de la petición. Si reportas un problema, mándanos este valor — con eso ubicamos qué pasó en segundos.

Algunas respuestas (gate fallido) incluyen campos extras:

```json theme={null}
{
  "error": "payment_required",
  "message": "Account is not in good standing.",
  "primary_reason": "wallet",
  "reasons": ["wallet"],
  "request_id": "..."
}
```

## Catálogo

| HTTP | `error`                   | Causa típica                                                           | Qué hacer                                                                             |
| ---- | ------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| 400  | `invalid_json`            | El body no es JSON válido.                                             | Revisa el `Content-Type` y el body.                                                   |
| 400  | `invalid_body`            | Campos faltantes o con tipo equivocado.                                | El `message` te dice qué campo. Corrige y reenvía.                                    |
| 400  | `invalid_idempotency_key` | `Idempotency-Key` con caracteres prohibidos o más de 255 chars.        | Usa solo ASCII imprimible. UUID v4 es la opción más segura.                           |
| 401  | `unauthorized`            | API key faltante, mal formada, inválida o revocada.                    | Revisa el header `Authorization`. Si la key fue revocada, crea una nueva.             |
| 402  | `payment_required`        | Wallet sin saldo o suscripción no activa.                              | Recargar wallet o regularizar suscripción. Verifica el campo `primary_reason`.        |
| 403  | `agent_not_found`         | El `agent_id` no existe O existe pero no pertenece a tu cuenta.        | Verifica que el ID es correcto y que la key pertenece al mismo cliente que el agente. |
| 409  | `idempotency_conflict`    | `Idempotency-Key` reusado con un body distinto.                        | Genera una nueva key o reusa exactamente el mismo body de la primera petición.        |
| 422  | `agent_disabled`          | El agente está pausado (manualmente o por sistema).                    | Reactiva el agente desde el portal.                                                   |
| 429  | `rate_limit_exceeded`     | Demasiadas peticiones por segundo.                                     | Implementa exponential backoff. Lee [Rate Limits](/rate-limits).                      |
| 500  | `internal_error`          | Error inesperado de nuestro lado.                                      | Reintenta después de unos segundos. Si persiste, contáctanos con el `request_id`.     |
| 502  | `upstream_unreachable`    | No pudimos contactar al proveedor de telefonía.                        | Reintenta con backoff. Si persiste, escríbenos.                                       |
| 502  | `upstream_error`          | El proveedor rechazó la llamada (ej. número inválido para esa cuenta). | Revisa el número y permisos del agente. El `message` puede dar más contexto.          |
| 503  | `service_unavailable`     | Configuración faltante o degradación temporal.                         | Reintenta. Si persiste, contáctanos.                                                  |

## Razones de denegación (`primary_reason`)

Cuando el HTTP status es `402` o `422`, el campo `primary_reason` te dice por qué:

| Valor                  | Significa                                    |
| ---------------------- | -------------------------------------------- |
| `wallet`               | Saldo insuficiente. Recarga desde el portal. |
| `sub:canceled`         | Suscripción cancelada.                       |
| `sub:past_due`         | Pago atrasado.                               |
| `sub:unpaid`           | Pago no procesado.                           |
| `agent:pausado`        | Agente pausado manualmente.                  |
| `agent:sin_configurar` | Agente aún no terminó setup.                 |
| `denied`               | Otro motivo (revisa `reasons`).              |

## Buenas prácticas para manejar errores

<AccordionGroup>
  <Accordion title="Programa contra `error`, no contra `message`" icon="code">
    El campo `message` puede mejorar de redacción. El `error` es el contrato — no cambia.
  </Accordion>

  <Accordion title="Loggea siempre el `request_id`" icon="receipt">
    Es lo que te pedimos cuando reportas un bug. Sin ese ID nos cuesta minutos a horas encontrar la petición.
  </Accordion>

  <Accordion title="Reintenta solo `5xx` y `429`" icon="repeat">
    Los errores `4xx` (excepto `429`) son responsabilidad del cliente — reintentar no los va a arreglar.
  </Accordion>

  <Accordion title="Backoff exponencial con jitter" icon="hourglass">
    Para `429` y `5xx`, espera 1s, 2s, 4s, 8s con un poco de aleatoriedad para no sincronizar reintentos.
  </Accordion>
</AccordionGroup>
