# Errores, límites y versionado

> Formato de errores, límites de uso, cabeceras y política de versionado.

Source: https://docs.botradix.com/es/api-errors/

## Formato de error

Todos los errores de `/api/dex/v1` tienen la misma forma JSON y un código HTTP acorde:

```json
{
  "success": false,
  "error": {
    "schema_version": "botradix-dex-error-v1",
    "code": "SCOPE_NOT_ALLOWED",
    "message": "…",
    "retryable": false,
    "details": {},
    "request_id": "dxr_…"
  },
  "request_id": "dxr_…",
  "api_version": "v1",
  "api_schema_revision": "botradix-dex-api-v1.1"
}
```

Usa `error.code` en tu lógica (los mensajes pueden cambiar) y guarda `request_id` si contactas con soporte. `retryable: true` indica que la misma petición puede funcionar más tarde.

## Errores habituales

| HTTP | Código | Significado |
|---|---|---|
| 400 | (códigos de validación) | Falta un campo, tiene un formato incorrecto o está fuera de rango. `prepare` valida el cuerpo antes que la clave |
| 400 | `IDEMPOTENCY_KEY_REQUIRED` | `/orders/prepare` necesita una clave de idempotencia válida |
| 401 | `API_KEY_REQUIRED` | No se envió clave de API |
| 401 | `API_KEY_INVALID` | La clave tiene un formato incorrecto o no es válida |
| 401 | `API_KEY_INACTIVE` | La clave está revocada o caducada |
| 403 | `SCOPE_NOT_ALLOWED` | La clave no tiene el scope que exige el endpoint o la acción |
| 403 | `IP_NOT_ALLOWED` | La IP de la petición no está en la lista permitida de la clave |
| 403 | `delegated_executor_binding_required` | La ejecución delegada necesita un ejecutor vinculado a la clave |
| 409 | `IDEMPOTENCY_KEY_CONFLICT` | La clave de idempotencia se usó con otros datos en las últimas 24 horas |
| 409 | `DUPLICATE_CLIENT_ORDER_ID` | El `client_order_id` se usó con otros datos |
| 409 | `active_api_key_limit_reached` | La wallet ya tiene 10 claves activas |
| 429 | `RATE_LIMITED` | Se superó un límite de la clave |
| 503 | `REALTIME_STREAM_ASYNC_WORKER_REQUIRED` | El stream SSE no está activado en este servicio |

## Códigos de la versión 2.2

| Código | Significado | Qué hacer |
|---|---|---|
| `COMMITTED_EXECUTOR_REQUIRED` | En un mercado con reglas de riesgo V2, abrir, ampliar o invertir por la ruta delegada se ejecuta comprometido con un precio observado después de tu orden, y solo un ejecutor del protocolo puede hacerlo. Tu ejecutor no lo es | Usa el ejecutor de BotRadix vinculado a tu clave |
| `INVERT_NEEDS_AGENT` | En un mercado con reglas de riesgo V2, la inversión no puede enviarse como transacción directa de la wallet | Actívala con tu clave de trading (o por la ruta delegada con un ejecutor del protocolo) |
| `INTENT_CREATED_AT_BEFORE_RECEPTION` | La hora de compromiso de la orden es anterior a su recepción en el servicio (margen de 2 s); no se envía nada | Prepárala de nuevo |
| `WALLET_MARGIN_NEEDS_AGENT` | Un mercado de tu cuenta cruzada tiene la sesión cerrada: el margen aislado sale de tu wallet, firmado por tu wallet o cofirmado por tu wallet junto a tu clave de trading. "Margen +" necesita la clave de trading | Activa la clave de trading y repite |
| `WALLET_MARGIN_NEEDS_WALLET_SIGNATURE` | El margen desde tu wallet necesita la firma de tu wallet para esta operación; una sesión de trading no puede traerlo | Repite la operación y fírmala con tu wallet (o usa tu clave de trading, con la cofirma de tu wallet) |
| `WALLET_COSIGN_REQUIRED` | Falta la cofirma de tu wallet para el margen desde tu wallet | Confirma de nuevo y firma con tu wallet |
| `WALLET_COSIGN_SIGNATURE_INVALID` | La cofirma no corresponde a esta wallet o a esta operación; no se ha movido nada | Prepárala de nuevo; si se repite, escribe a [support@botradix.com](mailto:support@botradix.com) |
| `WALLET_COSIGN_INVALID` | La cofirma preparada no coincide con la operación; no se ha movido nada | Prepárala de nuevo |
| `WALLET_MARGIN_BALANCE_REQUIRED` | Con esa sesión cerrada, tu wallet no tiene USDC suficiente para el margen (y, en una apertura, las comisiones máximas y, en una orden limitada o stop, la fianza). `details.wallet_margin_usdc` indica el importe | Añade USDC a tu wallet o espera a que reabra la sesión |
| `LIQUIDITY_CAPACITY` (también en `/orders/execute`) | El vault rechaza el riesgo: su cupo para este mercado y dirección está lleno, o una orden que se suma a una posición con take profit respaldado lo superaría (la vista previa no siempre lo anticipa). Desde la v2.2 la vía delegada lo responde con HTTP 400 en lugar de un `503` con `VAULT_CAPACITY`; `details.max_open_usdc` da el cupo cuando se puede estimar | Prueba el lado contrario, un importe menor o más tarde |

Al invertir junto a una posición neta del lado contrario con la misma clave, la respuesta puede devolver el id de esa neta: no hay `DexPositionOpened`, sino `DexPositionChanged` de la neta.

## Por qué una acción preparada no se puede ejecutar

Cuando `prepare` funciona pero `execution.ready` es `false`, `execution.reason` lo explica:

| Motivo | Significado |
|---|---|
| `withdraw_margin_insufficient` | El retiro dejaría muy poco margen libre. Retira menos o cierra posiciones |
| `oracle_unavailable` | Ahora mismo no hay un precio de mercado actual en cadena; inténtalo de nuevo en unos instantes |
| `funding_unavailable` / `funding_stale` | Hay que actualizar el funding del mercado antes de abrir posiciones nuevas |
| `market_session_closed` | El mercado está fuera de su sesión de negociación |
| `price_out_of_bounds` | El precio se movió más allá de tu deslizamiento permitido; vuelve a preparar |
| `price_tick_rejected` | El precio no coincide con el tick size del mercado |
| `contract_limits_rejected` | La orden supera un límite del contrato (tamaño, apalancamiento) o ha caducado |
| `vault_capacity_unavailable` | Ahora mismo no hay capacidad de liquidez suficiente para esta posición |
| `market_risk_paused` | Las posiciones nuevas están pausadas en este mercado |
| `market_not_bound` / `dex_not_operational` | El mercado aún no está habilitado para operar |
| `invalid_take_profit` / `invalid_stop_loss` | El TP o el SL están en el lado equivocado del precio actual |
| `intent_expired` | La preparación caducó; vuelve a preparar |
| `simulation_unavailable` | La simulación previa no pudo ejecutarse; vuelve a preparar en un momento |
| `contract_preflight_failed` | El contrato rechazaría la acción en las condiciones actuales |

## Límites de uso

Cada clave de API tiene sus propios límites, contados en ventanas de 60 segundos:

| Límite | Por defecto |
|---|---|
| Todas las peticiones | 3.600 por minuto |
| `/orders/prepare` | 900 por minuto y 40 por segundo |
| Lecturas de cuenta (`/account`, `/positions…`, `/orders…`, `/collateral`, `/transactions`, `/trades`, `/orders/execute`) | 3.000 por minuto |
| `/candles` | 900 por minuto |

Las `quotas` propias de una clave se pueden fijar al crearla o rotarla, hasta estos máximos por minuto: peticiones 30.000, órdenes 12.000, ráfaga 1.000, lecturas de cuenta 20.000 y lecturas históricas 12.000.

Además de los límites por clave, el borde de red admite hasta 100 peticiones por segundo por IP (ráfagas de 200) y 60 por segundo por clave de API (ráfagas de 120). Esos rechazos son respuestas `429` simples, sin el cuerpo JSON.

Las respuestas incluyen `X-RateLimit-Limit`, `X-RateLimit-Remaining` y `X-RateLimit-Reset` (hora Unix en segundos en la que se reinicia la ventana) para el límite general de la clave. Las respuestas `429` no llevan `Retry-After`: espera de forma exponencial con algo de aleatoriedad (por ejemplo 1, 2, 4, 8 segundos).

## Reintentos

- Reintenta ante `429`, ante `5xx` y cuando `error.retryable` sea `true`, con espera exponencial.
- Reutiliza la misma clave de idempotencia, con los mismos datos, al reintentar un `prepare` o un `execute`, para que una respuesta perdida no cree una segunda preparación ni una segunda orden.
- Nunca reintentes a ciegas una transacción ya enviada: consulta antes `/transactions` o `/native/executions/{tx_hash}`.

## Cabeceras de respuesta

| Cabecera | Valor |
|---|---|
| `X-BotRadix-API-Version` | `v1` |
| `X-BotRadix-API-Schema` | `botradix-dex-api-v1.1` |
| `X-Request-ID` | Tu ID de petición, o uno generado por el servidor (`dxr_…`) |
| `Cache-Control` | `no-store` |

## Política de versionado

- `/api/dex/v1` es el contrato estable de integración. En v1 se pueden añadir campos y endpoints nuevos sin aviso; tu cliente debe ignorar los campos que no conozca.
- Los cambios que romperían integraciones existentes se publican en una versión nueva.
- `GET /meta` devuelve la revisión de esquema y las capacidades actuales.
- Los endpoints sin versión que usa el terminal web (`/api/dex/…` sin `v1`) pueden cambiar en cualquier momento.
