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

# Swaps

> Convierte entre tus saldos USD, USDT, USDC, BTC, GOLD, SILVER y PLATINUM al instante, con cotización previa y a la tasa de ejecución del momento

export const EnvUrls = ({lang = "en"}) => {
  const T = {
    en: {
      test: "Test",
      live: "Live",
      hint: "Same API on both environments — build against test first, then go live by swapping the base URL and the key.",
      guide: "Environments and testing",
      href: "/en/environment-testing"
    },
    es: {
      test: "Test",
      live: "Live",
      hint: "La misma API en ambos ambientes — construye primero contra test y pasa a live cambiando la URL base y la key.",
      guide: "Entorno y pruebas",
      href: "/es/environment-testing"
    },
    zh: {
      test: "Test",
      live: "Live",
      hint: "两个环境的 API 完全一致——先在 test 环境构建，再通过切换基础 URL 和密钥上线。",
      guide: "环境与测试",
      href: "/zh/environment-testing"
    }
  };
  const t = T[lang] || T.en;
  const row = (label, url, keyPattern, badgeCls) => <div className="flex flex-wrap items-center gap-2 px-3 py-2">
      <span className={"rounded px-1.5 py-0.5 text-xs font-semibold uppercase tracking-wide " + badgeCls}>
        {label}
      </span>
      <code className="text-xs">{url}</code>
      <span className="text-xs text-gray-400 dark:text-zinc-500">·</span>
      <code className="text-xs">{keyPattern}</code>
    </div>;
  return <div className="my-4 rounded-xl border border-gray-200 dark:border-zinc-700 divide-y divide-gray-200 dark:divide-zinc-700 text-sm not-prose">
      {row(t.test, "https://cryptobank.qbank.cl/platform", "pk_test_...", "bg-amber-100 text-amber-800 dark:bg-amber-900/40 dark:text-amber-300")}
      {row(t.live, "https://api.qbank.cl/platform", "pk_...", "bg-emerald-100 text-emerald-800 dark:bg-emerald-900/40 dark:text-emerald-300")}
      <p className="px-3 py-2 text-xs text-gray-500 dark:text-zinc-400 m-0">
        {t.hint} <a href={t.href}>{t.guide} →</a>
      </p>
    </div>;
};

<EnvUrls lang="es" />

Los **swaps** convierten saldo entre tus siete activos — `USD`, `USDT`, `USDC`,
`BTC`, `GOLD`, `SILVER` y `PLATINUM` — de forma **síncrona e instantánea**, sin que la plata salga
de tu cuenta. Cualquier par funciona (también `BTC` ↔ `GOLD` directo,
y `USD` ↔ `USDT` a 1:1 exacto); el fiat local (`BOB`, `MXN`, `ARS`) aún
no es intercambiable (`invalid_pair`). La
tasa que ves en la cotización es la tasa a la que se ejecuta: **no hay
comisiones aparte** — cotizado = recibido.

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
flowchart LR
    quote["GET /v1/swaps/quote<br/>(indicativa, gratis)"] --> swapNode["POST /v1/swaps<br/>(tasa del momento)"]
    swapNode -->|"atómico en el ledger"| saldos["saldo BTC baja<br/>saldo GOLD sube"]
    swapNode --> historial["GET /v1/swaps<br/>(historial + detalle)"]
```

## 1. Cotiza (opcional, gratis)

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl "https://api.qbank.cl/platform/v1/swaps/quote?from_asset=USDT&to_asset=BTC&amount=1000" \
  -H "Authorization: Bearer <token>"
```

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "from_asset": "USDT",
  "to_asset": "BTC",
  "from_amount": "1000.000000",
  "to_amount": "0.01568419",
  "rate": "0.00001568",
  "indicative": true
}
```

La cotización es **indicativa**: el swap se ejecuta a la tasa del momento
del `POST` (los precios de BTC y GOLD se mueven). Para pares entre
stablecoins (`USDT` ↔ `USDC`) la tasa es estable.

## 2. Ejecuta el swap

<CodeGroup>
  ```bash USDT → BTC theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.qbank.cl/platform/v1/swaps \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "from_asset": "USDT",
      "to_asset": "BTC",
      "amount": "1000",
      "idempotency_key": "swap-2026-07-10-a"
    }'
  ```

  ```bash BTC → GOLD (directo) theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.qbank.cl/platform/v1/swaps \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "from_asset": "BTC",
      "to_asset": "GOLD",
      "amount": "0.01",
      "idempotency_key": "swap-2026-07-10-b"
    }'
  ```

  ```bash USDT → USDC theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.qbank.cl/platform/v1/swaps \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "from_asset": "USDT",
      "to_asset": "USDC",
      "amount": "500",
      "idempotency_key": "swap-2026-07-10-c"
    }'
  ```
</CodeGroup>

`amount` va en la moneda de **origen** (`from_asset`), con hasta sus
decimales (6 para USDT/USDC/GOLD/SILVER/PLATINUM, 8 para BTC).

Respuesta `201` — el swap es síncrono, tu saldo cambia al instante:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "swap_id": "8a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
  "account_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
  "from_asset": "USDT",
  "to_asset": "BTC",
  "from_amount": "1000.000000",
  "to_amount": "0.01568419",
  "rate": "0.00001568",
  "status": "completed",
  "idempotency_key": "swap-2026-07-10-a",
  "created_at": "2026-07-10T15:00:00Z"
}
```

Replay con la misma `idempotency_key` → `200` con el swap original y
`idempotency_hit: true` — **jamás se re-ejecuta**.

## 3. Consulta e historial

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Historial con paginación, fechas y filtro por moneda (matchea ambas puntas)
curl "https://api.qbank.cl/platform/v1/swaps?from=2026-07-01&to=2026-07-10&asset=BTC&page=1&page_size=50" \
  -H "Authorization: Bearer <token>"

# Detalle
curl https://api.qbank.cl/platform/v1/swaps/{swap_id} \
  -H "Authorization: Bearer <token>"
```

En tu historial de movimientos (`GET /v1/movements`) y en la
[cartola](/es/guides/statement) el swap aparece como `swap_out` en la moneda
de origen y `swap_in` en la de destino, cada uno cuadrando en su sección.

## Reglas y límites

* **Misma cuenta**: la plata nunca sale de tu cuenta — solo cambia de
  moneda. Por eso no pide OTP.
* **Cualquier par** entre `USDT`, `USDC`, `BTC` y `GOLD` (origen ≠ destino).
* **Tasa de ejecución del momento**: para BTC y GOLD se usa el precio de
  ejecución en vivo; si el precio no está disponible o está desactualizado,
  el swap se rechaza con `503 pricing_unavailable` (nunca se ejecuta con un
  precio viejo).
* **Límites para monedas volátiles** (BTC/GOLD/SILVER/PLATINUM, compartidos con payouts y
  compras con tarjeta): tope por operación y tope de volumen por cuenta en
  24 h móviles (`GET /v1/settlement` muestra los tuyos). USDT ↔ USDC no
  tiene límite.
* Requiere tu [verificación de identidad](/es/guides/kyc) aprobada y el
  servicio `swaps` habilitado.

### Protección de precio BTC

Para swaps BTC de USD 1.000 o más, CBPay compara la referencia de ejecución
con el libro de mercado antes del swap. Si la divergencia supera el umbral
configurado, responde `422 guard_diverged`; espera la convergencia o divide la
operación y reintenta con la misma `idempotency_key`. Si el mercado no está
disponible temporalmente, el swap puede continuar con una alerta operativa y
siguen aplicando las protecciones del precio de ejecución. Esta protección no
aplica a conversiones internas de checkout/payin ni a flujos OTC.

## Errores

| HTTP | `error` | Causa | Solución |
| - | - | - | - |
| 400 | `invalid_asset` | Moneda fuera de USDT/USDC/BTC/GOLD/SILVER/PLATINUM | Revisa `from_asset`/`to_asset` |
| 400 | `invalid_pair` | Origen y destino son la misma moneda | Elige monedas distintas |
| 400 | `invalid_amount` | Monto inválido o demasiados decimales | Respeta los decimales de la moneda origen |
| 400 | `amount_too_small` | El monto no alcanza ni la unidad mínima del destino | Sube el monto |
| 400 | `swap_asset_disabled` | Una de las monedas está deshabilitada para tu organización | Contacta a tu operador |
| 400 | `idempotency_key_required` | Falta la clave de idempotencia | Envíala en el body o header |
| 402 | `insufficient_funds` | Saldo insuficiente en la moneda origen | Fondea o baja el monto |
| 403 | `verification_required` / `service_disabled` | Cuenta sin verificar o servicio apagado | Completa tu onboarding / contacta a tu operador |
| 422 | `settlement_limit_exceeded` | El swap supera el tope por operación de monedas volátiles | Divide la operación |
| 422 | `settlement_daily_limit_exceeded` | Superaste tu volumen 24 h en monedas volátiles | Reintenta más tarde |
| 422 | `guard_diverged` | La referencia BTC superó el umbral de divergencia pre-trade | Espera la convergencia o divide la operación; reintenta con la misma idempotency key |
| 503 | `pricing_unavailable` | Precio de ejecución no disponible o viejo | Reintenta en unos minutos |

## Preguntas frecuentes

<AccordionGroup>
  <Accordion title="¿Por qué la tasa del swap difiere del precio de mercado que veo en otros lados?">
    La tasa cotizada es la tasa **de ejecución** de tu cuenta: incluye el costo
    de proveer la conversión instantánea y garantizada (liquidez inmediata, sin
    slippage, sin salir de tu cuenta). Es la misma filosofía de las tasas de
    payouts y payins: lo cotizado es exactamente lo que recibes, sin comisiones
    sorpresa después.
  </Accordion>

  <Accordion title="¿La cotización del quote está garantizada?">
    No — es indicativa. BTC y GOLD se mueven, así que la ejecución usa el
    precio del momento del POST. Entre stablecoins (USDT ↔ USDC) la diferencia
    es imperceptible. Si necesitas certeza absoluta del monto recibido, revisa
    el `to_amount` de la respuesta del swap (esa es la cifra final, ya
    acreditada).
  </Accordion>

  <Accordion title="¿Puedo deshacer un swap?">
    No hay "deshacer": un swap ejecutado es final (tu saldo ya cambió). Puedes
    hacer el swap inverso cuando quieras, a la tasa vigente de ese momento.
  </Accordion>

  <Accordion title="¿Por qué mi swap BTC→GOLD fue rechazado por límite si era mi primer swap del día?">
    Los límites de monedas volátiles son compartidos entre swaps, payouts
    pagados desde BTC/GOLD/SILVER/PLATINUM y compras con tarjeta desde BTC/GOLD/SILVER/PLATINUM — todos suman
    al mismo volumen de 24 h móviles de tu cuenta. Consulta tus topes en
    `GET /v1/settlement`.
  </Accordion>

  <Accordion title="¿Qué gano teniendo saldo en GOLD o BTC?">
    GOLD representa gramos de oro fino y BTC bitcoin: exposición al precio del
    activo sin salir del ecosistema. Puedes pagar payouts, comisiones y compras
    con tarjeta directo desde esos saldos (settlement multi-asset), y volver a
    USDT/USDC cuando quieras con un swap.
  </Accordion>
</AccordionGroup>

## USD como activo principal del ledger

Las cuentas usan `USD` como valor predeterminado de `settlement_asset` y
`payin_settlement_asset`; cámbialo cuando quieras con `PUT /v1/settlement`.
Las operaciones en vuelo nunca se vuelven a cotizar.

Los montos del ledger en USD usan centavos (dos decimales). Los créditos y
d débitos directos, las comisiones y los flujos de payout, checkout, POS y
tarjetas usan USD solo cuando el campo de activo de ese flujo lo acepta. Los
swaps entre USD y USDT usan paridad 1:1 y no consultan un oráculo FX. BOB,
MXN y ARS siguen siendo activos fiat separados del ledger; en v1 el pricing
de money-out para esos activos sigue no disponible.

Un payin acreditado directamente a una cuenta USD-principal expone
`credit_asset: USD` y el monto fiat acreditado en centavos; `usdt_credited`
sigue siendo el equivalente USD para reportes. El hold de una controversia
sigue el activo acreditado: los créditos USD usan `hold_asset: USD`. `disputed` y `held` usan las
unidades del activo retenido; `disputed_usdt` y `held_usdt` son equivalentes
normalizados.

El swap puede tener una cobertura interna de back-office. Esto no cambia el
request ni la respuesta de `POST /v1/swaps`, la tasa de ejecución ni el
contrato del ledger de la cuenta.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.