Skip to content

OTC

All endpoints require Authorization: Bearer <token> and are scoped to the tenant (clientId) resolved from OAuth.

Overview

The OTC API lets your tenant request and execute crypto buy/sell trades (e.g. USDT/BRL) entirely via API. A single call quotes, records and executes the operation.

How execution works:

  • Fiat leg: your bank account (registered in the BaaS, resolved by your clientId) moves the BRL with our settlement account.
  • Crypto leg: crypto goes to/from the wallet address you provide in the request.
  • Pricing: the price already reflects what applies to your tenant — you only specify what to trade.

Sides:

  • BUY — you buy crypto and pay in BRL. The crypto is sent to the provided walletAddress.
  • SELL — you sell crypto and receive BRL. Crypto leaves your custody and BRL is credited to your account.

Typical flow:

  1. Quote (GET /v1/otc/quote) — optional, to show price/volume to the user.
  2. Request the trade (POST /v1/otc/trades) — quote + create + execute.
  3. Track (GET /v1/otc/trades/{id}) the status until SETTLED.

GET /v1/otc/quote

Returns the applicable price and resulting volume/amount. Persists nothing.

Query params:

ParamTypeRequiredDescription
coinstringYesAsset, e.g. USDT
sidestringYesBUY | SELL
modestringYesBY_FIAT (you fix the BRL) | BY_CRYPTO (you fix the asset volume)
amountnumberYesBRL when BY_FIAT; asset volume when BY_CRYPTO

Response 200 OK:

json
{
  "data": {
    "side": "BUY",
    "mode": "BY_FIAT",
    "asset": "USDT",
    "price": 5.5825,
    "volume": 17912.5,
    "fiatAmount": 100000
  }
}
FieldDescription
pricePrice per asset unit (BRL) that will be applied
volumeAsset quantity
fiatAmountTotal amount in BRL

POST /v1/otc/trades

Quotes, records and executes the trade. The source bank account is your tenant's; the wallet is the one provided here.

Headers:

HeaderValue
AuthorizationBearer <token>
Content-Typeapplication/json

Request Body:

json
{
  "asset": "USDT",
  "side": "BUY",
  "mode": "BY_FIAT",
  "amount": 100000,
  "walletAddress": "TXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "walletNetwork": "TRON"
}
FieldTypeRequiredDescription
assetstringYesTraded asset (e.g. USDT). coin is also accepted.
sidestringYesBUY | SELL
modestringYesBY_FIAT | BY_CRYPTO
amountnumberYesBRL (BY_FIAT) or volume (BY_CRYPTO)
walletAddressstringYesCrypto address (destination on BUY, origin on SELL)
walletNetworkstringYesTRON | EVM | POLYGON | ETHEREUM
bankingAccountIdstringNoTenant account; defaults to the latest active account

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-10T12:00:00.000Z",
    "executedAt": null
  }
}

Execution is asynchronous and idempotent: track status until SETTLED.

Common errors: 400 (missing fields / missing clientId), 404 (no quotation for the asset / no active bank account for the tenant).


GET /v1/otc/trades

Lists your tenant's trades (only those originated by your clientId).

Query params: limit, offset (optional).

Response 200 OK: array of trades (same shape as POST).


GET /v1/otc/trades/{id}

Trade detail. Returns 404 if the trade does not belong to your tenant.

Response 200 OK:

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

Trade states (status)

StatusMeaning
PENDINGReceived, not started yet
PROCESSINGIn progress (fiat and/or crypto settlement under way)
SETTLEDDone
FAILEDFailed
CANCELLEDCancelled

When status is SETTLED on a BUY, the txHash field carries the on-chain transaction hash of the crypto delivery.