Skip to content

OTC ​

Todos los endpoints requieren Authorization: Bearer <token> y están delimitados por el tenant (clientId/x-client-id) resuelto desde OAuth.

Visión general ​

La API de OTC permite que tu tenant solicite y ejecute operaciones de compra/venta de cripto (ej.: USDT/BRL) totalmente vía API. La liquidez, el proveedor y nuestra cuenta de liquidación se resuelven por nuestro lado — nunca ves el origen, el costo ni el margen; solo el precio final aplicable a tu tenant.

Sides:

  • BUY (onramp) — compras cripto y pagas en BRL. La cripto se envía a la walletAddress que indicas.
  • SELL (offramp) — vendes cripto y recibes BRL. La cripto sale de una billetera custodial tuya (fromAddress, gestionada por nosotros); la movemos a nuestra custodia y liquidamos el BRL.

Pierna fiat — cómo se mueve el BRL ​

  • BUY (onramp): lo eliges en el request, vía paymentMethod:
    • ACCOUNT_DEBIT (por defecto) — la plataforma debita automáticamente, vía PIX, la cuenta de OTC que tienes configurada (cuenta → nuestra cuenta de liquidación). Sin QR ni pago manual. La cuenta de OTC debe estar previamente fondeada en BRL.
    • PIX_QRCODE — nosotros emitimos un cobro PIX (código QR / copia y pega) y lo devolvemos en pixIn. Lo pagas desde una cuenta del propio CNPJ de tu tenant, en cualquier banco, dentro del plazo. Ver PIX vía código QR.
  • SELL (offramp): tras la venta de la cripto, el BRL se paga vía PIX a la clave PIX de tu tenant — la clave configurada para ti por el operador Axia (por defecto) o la que indicas en pixKey. Solo pagamos claves cuyo titular sea el CNPJ de tu tenant; una clave de terceros (incluida la de un cliente final) se rechaza.

Titularidad por CNPJ. Tanto el PIX que nos pagas (BUY por QR) como el PIX que te pagamos (SELL) quedan atados al documento (CNPJ) registrado para tu tenant. Es obligatorio para usar PIX_QRCODE y para recibir el SELL por PIX — confirma con soporte que el CNPJ y la clave PIX de tu tenant están registrados.

Precio ​

  • BUY: el precio de la cotización es indicativo. El precio final se bloquea en el momento en que se confirma el PIX (con ACCOUNT_DEBIT, segundos después del débito; con PIX_QRCODE, cuando llega tu pago) — recibes la cripto al precio de ese instante.
  • SELL: la cotización (quoteId) bloquea el precio y la ejecución corre contra él.

Flujo típico:

  1. Cotizar (GET /v1/otc/quote) — precio + volumen/monto resultante (en BUY, indicativo).
  2. Solicitar la operación (POST /v1/otc/trades).
  3. Seguir (GET /v1/otc/trades/{id}) el status hasta SETTLED.

GET /v1/otc/quote ​

Devuelve el precio aplicable, el volumen/monto resultante y (en SELL) un quoteId bloqueado.

Query params:

ParamTypeRequiredDescription
coinstringYesActivo, ej.: USDT
sidestringYesBUY | SELL
modestringYesBY_FIAT (fijas el BRL) | BY_CRYPTO (fijas el volumen del activo)
amountnumberYesBRL cuando BY_FIAT; volumen del activo cuando BY_CRYPTO

Response 200 OK:

json
{
  "data": {
    "side": "BUY",
    "mode": "BY_FIAT",
    "asset": "USDT",
    "price": 5.5825,
    "clientRate": 5.5825,
    "volume": 17912.5,
    "fiatAmount": 100000,
    "quoteId": "liq-9f2c...",
    "expiresAt": "2026-06-18T12:00:30.000Z"
  }
}
FieldDescription
price / clientRatePrecio por unidad del activo (BRL) aplicable a tu tenant. En BUY es indicativo (el precio final se bloquea en la confirmación del débito).
volumeCantidad del activo
fiatAmountMonto total en BRL
quoteIdIdentificador de la cotización. En SELL, pásalo en POST /v1/otc/trades para ejecutar contra el precio bloqueado.
expiresAtInstante de expiración de la cotización bloqueada (ISO 8601).

El precio es agnóstico del proveedor: nunca ves el origen de la liquidez, el costo ni el margen.


POST /v1/otc/trades ​

Crea la operación. La ejecución es asíncrona (en segundo plano) e idempotente — sigue el status hasta SETTLED.

Headers:

HeaderValue
AuthorizationBearer <token>
Content-Typeapplication/json

Request Body (BUY — onramp):

json
{
  "asset": "USDT",
  "side": "BUY",
  "mode": "BY_FIAT",
  "amount": 100000,
  "walletAddress": "TXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "walletNetwork": "TRON"
}

Sin paymentMethod (o con ACCOUNT_DEBIT), la plataforma debita automáticamente tu cuenta de OTC vía PIX y entrega el USDT en la walletAddress — no hay pixIn/QR para pagar.

Request Body (BUY — onramp, pago por código QR):

json
{
  "asset": "USDT",
  "side": "BUY",
  "mode": "BY_FIAT",
  "amount": 100000,
  "walletAddress": "TXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "walletNetwork": "TRON",
  "paymentMethod": "PIX_QRCODE"
}

La respuesta trae pixIn con el copia y pega a pagar desde el CNPJ de tu tenant antes de pixIn.expiresAt — ver PIX vía código QR.

Request Body (SELL — offramp):

json
{
  "asset": "USDT",
  "side": "SELL",
  "mode": "BY_CRYPTO",
  "amount": 18000,
  "quoteId": "liq-9f2c...",
  "fromAddress": "TYyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
  "walletNetwork": "TRON",
  "pixKey": "[email protected]"
}
FieldTypeRequiredDescription
assetstringYesActivo negociado (ej.: USDT). También acepta coin.
sidestringYesBUY | SELL
modestringYesBY_FIAT | BY_CRYPTO
amountnumberYesBRL (BY_FIAT) o volumen (BY_CRYPTO)
walletAddressstringBUYBUY: dirección de destino que recibirá la cripto (obligatorio). SELL: no usado — indica fromAddress.
walletNetworkstringYesRed de entrega: TRON (USDT-TRC20) o ETH (USDT-ERC20). Ver Redes de entrega.
fromAddressstringSELLSELL: dirección de origen — billetera custodial de tu tenant (creada vía POST /v1/crypto/wallets), no bloqueada.
pixKeystringNo (SELL)SELL: clave PIX que recibe el BRL. El titular debe ser el CNPJ de tu tenant (verificado en el DICT al crear y de nuevo antes del pago; clave de terceros → 403). Ausente → se usa la clave PIX configurada para tu tenant; sin ella, la clave de tu cuenta de OTC registrada.
paymentMethodstringNo (BUY)BUY: ACCOUNT_DEBIT (por defecto — débito automático de tu cuenta de OTC) o PIX_QRCODE (emitimos un QR y lo pagas desde el CNPJ de tu tenant). Valor inválido → 400 INVALID_PAYMENT_METHOD. Ignorado en SELL.
quoteIdstringNoSELL: cotización bloqueada (de GET /v1/otc/quote). BUY: opcional/indicativo — el precio final se bloquea en la confirmación.
bankingAccountIdstringNoCuenta del tenant; por defecto usa la cuenta activa más reciente.

Response 200 OK:

json
{
  "data": {
    "id": "a1b2c3d4-...",
    "side": "BUY",
    "asset": "USDT",
    "quoteCurrency": "BRL",
    "volume": 17912.5,
    "unitPrice": 5.5825,
    "totalAmount": 100000,
    "walletAddress": "TXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "walletNetwork": "TRON",
    "status": "PROCESSING",
    "txHash": null,
    "createdAt": "2026-06-18T12:00:00.000Z",
    "executedAt": null
  }
}

BUY (onramp): con ACCOUNT_DEBIT la pierna fiat es un débito PIX automático de tu cuenta de OTC — no envíes nada manualmente. Con PIX_QRCODE la respuesta incluye paymentMethod: "PIX_QRCODE" y el bloque pixIn a pagar. El precio final se bloquea en la confirmación del PIX. SELL (offramp): no envías la cripto manualmente. Como la billetera de origen está bajo nuestra custodia, nosotros iniciamos la transferencia on-chain desde ella hacia nuestra custodia y seguimos con la liquidación.

Errores comunes:

HTTPMotivo
400Faltan campos / falta clientId / amount fuera de los límites de ticket / falta fromAddress en SELL
403fromAddress (SELL) no pertenece a tu tenant, o la billetera está bloqueada; PIX key refused — la pixKey (SELL) no pertenece al CNPJ de tu tenant
404Sin cotización para el activo / sin cuenta bancaria activa para el tenant
409QUOTE_EXPIRED (la cotización venció — cotiza de nuevo), SLIPPAGE_EXCEEDED (el precio salió de la tolerancia — cotiza de nuevo) o CNPJ del tenant no registrado (necesario para PIX_QRCODE)
429Límite de tasa (rate-limit) excedido

PIX vía código QR (BUY) ​

Con paymentMethod: "PIX_QRCODE", en vez de debitar tu cuenta de OTC emitimos un cobro PIX en nuestra cuenta de liquidación y devolvemos los datos para que lo pagues. La operación queda en PENDING hasta que llega el PIX.

Response 200 OK (extracto):

json
{
  "data": {
    "id": "a1b2c3d4-...",
    "side": "BUY",
    "status": "PENDING",
    "paymentMethod": "PIX_QRCODE",
    "totalAmount": 100000,
    "pixIn": {
      "emv": "00020126580014br.gov.bcb.pix...",
      "pixKey": "[email protected]",
      "transactionIdentification": "a1b2c3d4",
      "amount": 100000,
      "expiresAt": "2026-08-27T17:30:00.000Z",
      "payerDocument": "12345678000199",
      "paid": false
    }
  }
}
CampoDescripción
pixIn.emvPayload del QR (PIX copia y pega). Renderízalo como código QR o pégalo en la app del banco.
pixIn.amountMonto exacto en BRL a pagar. Un pago con otro monto no se concilia.
pixIn.expiresAtPlazo de pago. Sin PIX hasta ese instante, la operación pasa a FAILED (PIX_IN_EXPIRED).
pixIn.payerDocumentEl CNPJ que debe ser el pagador (el documento registrado para tu tenant).
pixIn.paidtrue una vez conciliado el PIX.

Reglas:

  • El PIX tiene que salir de una cuenta del CNPJ en payerDocument (cualquier banco). Un PIX pagado por otro documento se rechaza: la operación pasa a FAILED (PIX_IN_PAYER_MISMATCH), no se entrega cripto y el monto lo devuelve manualmente nuestro equipo — contacta a soporte.
  • Paga el monto exacto y dentro del plazo. pixIn también aparece en GET /v1/otc/trades/{id} mientras la operación está pendiente.
  • En cuanto se confirma el PIX, se bloquea el precio y la ejecución sigue normalmente (PROCESSING → SETTLED); usa los webhooks otc.trade.settled / otc.trade.failed o el polling.

GET /v1/otc/trades ​

Lista las operaciones de tu tenant (solo las originadas por tu clientId).

Query params: limit, offset (opcionales).

Response 200 OK: array de operaciones (mismo shape que el POST).


GET /v1/otc/trades/{id} ​

Detalle de la operación. Devuelve 404 si la operación no pertenece a tu tenant.

Response 200 OK:

json
{
  "data": {
    "id": "a1b2c3d4-...",
    "side": "SELL",
    "asset": "USDT",
    "totalAmount": 100000,
    "walletAddress": "TXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "walletNetwork": "TRON",
    "status": "SETTLED",
    "txHash": "0xabc...",
    "createdAt": "2026-06-18T12:00:00.000Z",
    "executedAt": "2026-06-18T12:03:00.000Z"
  }
}

Estados de la operación (status) ​

StatusSignificado
PENDINGRecibido, aún no iniciado
PROCESSINGEn procesamiento (débito fiat y/o liquidación cripto en curso)
SETTLEDCompletado
FAILEDFalló
CANCELLEDCancelado

Los estados son neutros por diseño — sigues el macro-estado de la operación sin ver cómo se originó la liquidez. Cuando el status es SETTLED, txHash trae el hash on-chain (envío de cripto en BUY; transferencia de custodia en SELL).

Webhooks (alternativa al polling): en lugar de consultar GET /v1/otc/trades/{id} hasta SETTLED, puedes suscribirte a los eventos otc.trade.settled y otc.trade.failed y recibir la operación final por push. Consulta Webhooks.


Redes de entrega ​

El USDT puede entregarse en dos redes, seleccionadas mediante el campo walletNetwork del trade:

RedwalletNetworkFormato de direcciónEjemplo
TRON (TRC-20)TRONBase58, empieza con T, 34 caracteresTXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Ethereum (ERC-20)ETH (o ETHEREUM)Hex, empieza con 0x, 40 caracteres0xAbC1230000000000000000000000000000000000

Validación de dirección. La walletAddress (BUY) / fromAddress (SELL) se valida contra la red antes de cualquier movimiento: una dirección de otra red (ej.: una T... en una entrega Ethereum, o una 0x... en una entrega TRON) o una dirección malformada se rechaza con 400. Esto protege contra la pérdida de fondos por entrega en la red equivocada.

Costo por red. La red Ethereum tiene un costo de red (gas) mayor y variable; el precio final aplicable a tu tenant ya refleja la red elegida. La confirmación on-chain en Ethereum también puede tardar más que en TRON.

Las redes aceptadas son TRON y Ethereum. Cualquier otra red devuelve 400.


Whitelist de retiro (BUY) ​

Por defecto, una orden BUY entrega la cripto a la walletAddress indicada en la solicitud. Opcionalmente, puedes restringir la entrega solo a direcciones previamente registradas: activa la whitelist y registra las direcciones permitidas. Mientras esté activada, un BUY a una dirección fuera de la lista se rechaza con 403. La whitelist no aplica al SELL (cuya dirección es tu billetera custodial de origen).

Todos los endpoints están acotados a tu tenant (clientId del OAuth). El toggle también puede activarse/desactivarse por el operador de Axia.

GET /v1/otc/whitelist/settings ​

Devuelve { "enabled": true|false }.

PUT /v1/otc/whitelist/settings ​

Activa/desactiva la whitelist. Body: { "enabled": true }.

GET /v1/otc/whitelist ​

Lista las direcciones registradas: [{ "id", "network", "address", "label" }].

POST /v1/otc/whitelist ​

Registra una dirección. Body: { "network": "TRON", "address": "T...", "label": "Tesorería" }. La address se valida por red (TRON/EVM). Una dirección ya registrada devuelve 409.

DELETE /v1/otc/whitelist/{id} ​

Elimina una dirección de tu whitelist.