# Operar con la API

> Preparar, firmar o ejecutar acciones, idempotencia y un ejemplo completo.

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

Toda operación empieza por **preparar** (*prepare*): BotRadix valida la acción contra el mercado, tu cuenta y los contratos, la simula y devuelve exactamente lo que hay que firmar o enviar. `prepare` no ejecuta nada.

## El flujo

1. `POST /orders/prepare` con una acción, sus datos y una clave de idempotencia.
2. Revisa la respuesta: `execution.ready` debe ser `true`.
3. Ejecuta según `execution.status`:

| `execution.status` | Qué hacer |
|---|---|
| `signature_ready` | Firma `execution.typed_data` (EIP-712) con la wallet y envíalo al relay. Se usa hoy para abrir y cerrar posiciones |
| `ready` | Firma y envía desde la wallet cada transacción de `execution.transactions`, en orden |
| `preflight_failed` | No se puede ejecutar ahora. `execution.reason` explica el motivo (por ejemplo `withdraw_margin_insufficient` u `oracle_unavailable`) |
| `contract_pending` | El mercado o el contrato aún no están disponibles para esta acción |

> [!WARNING]
> `prepare` responde HTTP 200 aunque la acción no se pueda ejecutar. Comprueba siempre `execution.ready` y `execution.status` antes de firmar nada.

Una acción preparada caduca: 120 segundos las de trading, 180 segundos las de colateral y 300 segundos las intenciones firmadas. Si caduca, vuelve a prepararla.

## Camino 1 — Intención firmada (abrir y cerrar posiciones)

Para `open_position`, `close_position_market` y `close_position_limit`, la respuesta trae un mensaje EIP-712 en lugar de transacciones:

- `execution.mode` es `signed_intent` y `execution.transactions` está vacío.
- Los datos tipados usan el dominio `BotradixDEX`, versión `1`, chain ID `8453`, y el router del DEX como contrato verificador.
- La wallet lo firma (una firma, no una transacción) y envías la firma al relay:

```bash
curl -X POST https://app.botradix.com/api/dex/actions/relay \
  -H "Content-Type: application/json" \
  -d '{"wallet":"0xTuWallet","intent_id":"dx_…","signature":"0x…"}'
# → {"tx_hash":"0x…","state":"submitted"}
```

El ejecutor de BotRadix envía entonces la transacción. Su coste de red se cobra en USDC de tu colateral del DEX y se muestra antes en `execution.costs`, así que la wallet no necesita ETH para estas acciones.

> [!NOTE]
> El endpoint de relay forma parte, de momento, de la API web sin versión (`/api/dex/actions/relay`). Es la forma admitida hoy de enviar intenciones firmadas.

## Camino 2 — Transacciones de la wallet

Para el resto de acciones (colateral, cambios de TP/SL, margen aislado, cancelar y reemplazar), `execution.transactions` contiene una o varias transacciones:

```json
{ "kind": "action", "from": "0xTuWallet", "to": "0x…", "data": "0x…", "value": "0x0", "deadline": 1790950518 }
```

En los depósitos puede ir primero una de `kind: "approval"` (aprobación del importe exacto del token). Fírmalas y envíalas en orden desde la misma wallet; necesitan un poco de ETH en Base para el gas.

**Depósito de USDC con permit (sin gas).** Cuando `GET /api/dex/config` indica `collateral_model.approval.permit: true`, añade `"permit": true` junto a `action` en un `add_collateral` de USDC. La respuesta trae entonces `execution.mode: "permit_deposit"` con `typed_data` EIP-2612: fírmalo con la wallet y envía `{"wallet","intent_id","signature"}` a `POST /api/dex/actions/relay`. Un ejecutor del protocolo envía el depósito y paga el gas. Sin esa marca, o para BAQ, recibes las transacciones de aprobación y depósito.

Si envías tú las transacciones, comunica el hash a `POST /api/dex/actions/receipt` (`{"wallet","intent_id","tx_hash","state"}`) para recibir sus webhooks `transaction.*`; si no, BotRadix solo conoce la operación cuando la indexa desde la cadena.

## Camino 3 — Ejecución delegada

`POST /orders/execute` envía acciones mediante un ejecutor vinculado a la clave de API (scope `trade:execute`; `orders:manage` para cancelar, reemplazar y primitivas de TP/SL). Responde `202` con `delegated.command_id`, `delegated.tx_hash` y una `status_url`; sigue su estado con `GET /executions/{command_id}`. Envía `"prepare_only": true` para validar sin enviar.

Acepta, entre otras, `open_position`, `batch` (de 1 a 32 acciones), `open_market`, `create_limit`, `create_stop`, `increase`, `reduce`, `close`, `cancel`, `replace`, `set_tp`, `clear_tp`, `set_sl`, `clear_sl`, `invert` e `isolated_manage`. Si la clave no tiene un ejecutor vinculado, la API responde `403 delegated_executor_binding_required`.

## Idempotencia

`/orders/prepare` exige una clave de idempotencia, que se toma (en este orden) de la cabecera `Idempotency-Key`, de `payload.idempotency_key` o de `payload.client_order_id`. Debe cumplir `^[A-Za-z0-9._:-]{8,128}$`.

- Las claves se asocian a wallet, acción y clave, y se recuerdan 24 horas.
- La misma clave con los mismos datos devuelve la preparación original (`idempotent_replay: true`).
- La misma clave con datos distintos devuelve `409 IDEMPOTENCY_KEY_CONFLICT`; un `client_order_id` reutilizado con datos distintos devuelve `409 DUPLICATE_CLIENT_ORDER_ID`.
- La petición se compara con lo que enviaste (`payload`, más `permit` en los depósitos), en todas las acciones, también `open_position`. Los datos se validan antes de buscar la clave, así que un reintento con el mercado desfasado o movido devuelve ese error de validación. Una preparación repetida puede haber caducado: revisa `expires_at_ms`.

`/orders/execute` lee la clave solo de `payload.idempotency_key` o `payload.client_order_id` y sigue las mismas reglas: la misma clave con los mismos datos repite la respuesta original, y con datos distintos devuelve `409 IDEMPOTENCY_KEY_CONFLICT`.

## Datos de `open_position`

| Campo | Reglas |
|---|---|
| `pair_id` | `id` del mercado en `/markets` |
| `side` | `long` o `short` |
| `order_type` | `market` (por defecto), `limit` o `stop` |
| `margin_mode` | `cross` (por defecto) o `isolated` |
| `leverage` | Entero desde 1 hasta el máximo del mercado (ver [Apalancamiento y margen](https://docs.botradix.com/es/margin/)) |
| `order_value_usdc` | Tamaño de la posición (nocional) en USDC, hasta 6 decimales, dentro del mínimo y máximo del mercado |
| `reference_price` | Obligatorio en órdenes de mercado. Se rechaza con `PRICE_DEVIATION_EXCEEDED` si se aleja más de un 1,5 % del precio del servidor, o con `MARKET_DATA_STALE` si los precios tienen más de 8 segundos |
| `max_slippage_bps` | Obligatorio en órdenes de mercado, de 1 a 1000 (del 0,01 % al 10 %) |
| `limit_price` / `trigger_price` | Obligatorio en órdenes límite / stop |
| `time_in_force` | `gtc`, `ioc` o `fok`; las órdenes de mercado son siempre `ioc` |
| `rest_if_unfilled` | Solo mercado: deja la parte no ejecutada como orden límite |
| `post_only` | Solo órdenes límite |
| `take_profit`, `stop_loss` | Opcionales; deben estar en el lado correcto del precio de entrada |
| `client_order_id` | Hasta 96 caracteres; se genera si no se envía |

## Ejemplo

```bash
curl -X POST https://app.botradix.com/api/dex/v1/orders/prepare \
  -H "X-BotRadix-API-Key: $BOTRADIX_API_KEY" \
  -H "Idempotency-Key: mm01-2026-10-02-0001" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "open_position",
    "payload": {
      "pair_id": 1,
      "side": "long",
      "order_type": "market",
      "margin_mode": "cross",
      "order_value_usdc": "100",
      "leverage": 5,
      "reference_price": "2500.00",
      "max_slippage_bps": 50,
      "client_order_id": "mm01-2026-10-02-0001"
    }
  }'
```

La respuesta contiene `intent_id`, los datos normalizados en `payload`, `execution` (estado, datos tipados o transacciones, simulación, costes y plazo) y `expires_at_ms`.

## Después de ejecutar

- `GET /transactions` lista tus intenciones y su estado en cadena.
- `GET /native/executions/{tx_hash}` indica la finalidad: `PENDING`, `PENDING_FINALITY` (menos de 8 confirmaciones), `REVERTED` o `FINAL`.
- Los [webhooks](https://docs.botradix.com/es/api-realtime/) avisan de cambios en órdenes, posiciones, colateral y transacciones.
