Skip to content

Journal OTC

Access prerequisites

  • Permission (module): viewOtc
  • License/Feature: None
  • Menu container: GENERAL → group Transaction journalsJournal OTC (/otc-journal)

What it is / when to use

This is the OTC desk (over-the-counter) of the BackOffice: it lists crypto↔fiat exchange orders (typically USDT ↔ BRL), with the exchange lock, the total charged to the client, the total at the provider, the spread (house revenue), and the internal status of each order. In addition to querying, the operator executes administrative actions on an order: force a status update, cancel, release a reserve, and — in internal mode — confirm/settle the operation.

Orders can operate in two modes:

  • ENOR — settlement via external provider (eNor). The lifecycle is driven by the polling scheduler that queries the provider.
  • INTERNALin-house settlement: the platform debits the user's payment token, credits the treasury, and pays the user in the destination token from the treasury.

Prerequisites

  • Permission: viewOtc (dual permission — CPM enum + dynamic module in DB). Mutation actions (cancel/confirm/release) are sensitive and may require re-authentication (step-up password+MFA) according to the tenant's policy; the final gating is validated at the API-Gateway.
  • License/Feature: none.
  • Dependencies on other screens: None. Orders are created from the OTC flow (PaymentManagementService). For INTERNAL mode to settle, the customerToPay configuration (treasury account) must exist.

Step by step

  1. Go to Transaction journals → Journal OTC.
  2. Check the summary cards at the top (totals for the filtered period).
  3. Apply filters: period (from/to), side (buy/sell), user ID, USDT range, and status chips (multi-select). Click Apply.
  4. Click Export CSV to download the filtered list.
  5. Click the detail icon (receipt_long) of an order to open the modal with the event timeline and administrative actions.

Summary cards

CardWhat it shows
Total ordersNumber of orders in the period.
Total USDTTotal volume in USDT.
Total BRL (client)Sum of what was charged to clients.
Total spread (BRL)House revenue in the period (delta between the client price and the provider price).
Delivered / Pending / Failed / CancelledCounts by outcome.

Filters and columns

Filter / ColumnWhat it shows / doesData source
From / ToDate window.from / to.
Side (side)client_buys_usdt (BUY) or client_sells_usdt (SELL).side.
User IDFilters by user.userId.
USDT min/maxVolume range.usdtMin / usdtMax.
Status chipsMulti-select: LOCKED, PIX_SCHEDULED, PIX_SENT, ONCHAIN_PENDING, ONCHAIN_CONFIRMED, PAYMENT_SENT, DELIVERED, CANCELLED, EXPIRED, FAILED.status[].
Date (createdAt)Order creation.createdAt.
UserOrder owner.userId.
Mode (otcMode)ENOR or INTERNAL.otcMode.
SideBUY/SELL.side.
USDTAmount traded.usdtAmount.
Exchange lock (lockedRate)Rate frozen for the client.lockedRate.
BRL clientTotal charged to the client.brlTotal.
BRL provider (eNor)Total at the provider.enorBrlTotal (falls back to brlTotal if absent).
SpreadAmount + percentage (bps/100). Empty () when zero.spreadAmount / spreadBps.
Internal statusOrder state (color by class).internalStatus.
Detail (action)Opens the order modal.openDetail(o).

Actions and modals

The detail modal (OtcOrderDetailModalComponent) shows the order, payment, settlement, and the event timeline (each event expandable with request/response JSON). Actions open a confirmation dialog with a reason field (audited) and a visual tone (blue/orange/red):

ActionWhen it appearsWhat it does on the backend
Force update (force-refresh)Whenever there is an enorOrderId.Re-queries the status at the provider (eNor) and updates the local state; if client_delivered/cancelled is returned, marks DELIVERED/CANCELLED. Useful when polling has stalled. Registers event ADMIN_FORCE_REFRESH.
Cancel (cancel)Status in LOCKED, PIX_SCHEDULED, PIX_SENT, ONCHAIN_PENDING, ONCHAIN_CONFIRMED, PAYMENT_SENT.Cancels the order at the provider and releases the user's reserve (best-effort) if there is a reserveReference. Marks CANCELLED. Event ADMIN_CANCEL.
Release reserve (release-reserve)When there is a pending reserve or status in CANCELLED/FAILED/EXPIRED.Releases the user's locked reserve (for orders with a "hanging" reserve). Event ADMIN_RELEASE_RESERVE.
Confirm trade (confirm-trade)Only INTERNAL mode and status LOCKED.Settles the order in-house: (1) commits the user's reserve to the treasury (debits the payment token, credits customerToPay); (2) pays the user in the destination token from the treasury; (3) marks DELIVERED. Event ADMIN_CONFIRM_TRADE.

All actions require confirmation and accept a reason, which is recorded as an audit event on the order.

Business rules / cautions

Confirm trade (INTERNAL) is a real and irreversible settlement

  • confirm-trade actually moves value: debits the user, credits the treasury, and pays the user in the destination token. The backend rejects the action if the order is not INTERNAL, is not LOCKED, has no reserve, or has already been delivered — precisely to prevent double settlement. Confirm the mode and status before acting.
  • ENOR orders are settled by the polling scheduler, never by confirm-trade. Do not attempt to settle an ENOR order manually here.

Attention

  • The spread is the house revenue: the delta between the price charged to the client (brlTotal) and the provider price (enorBrlTotal). This is exactly the "limit price × execution" pattern — do not mistake the spread for a calculation error.
  • Cancel already attempts to release the reserve; Release reserve is the isolated repair for reserves that remained hanging after CANCELLED/FAILED/EXPIRED.
  • EXPIRED means the exchange lock window expired before settlement.
  • Financial values: usdtAmount, lockedRate, brlTotal, spreadAmount are treated as BigNumber/high-precision strings on the backend — the UI formats them for display only. Do not reconcile by the displayed value without verifying precision.
  • Idempotency: the internal settlement steps rely on idempotent reserve/transaction references; a retry that returns E00021 ("already processed") is success.

Examples

Scenario 1 — Force update of an ENOR order stuck in PIX_SENT

An ENOR order remained PIX_SENT for hours because polling did not progress. Open the detail → Force update. The backend re-queries the provider: if client_delivered is already present, the order transitions to DELIVERED and the timeline gains the ADMIN_FORCE_REFRESH event. No value is moved — only the status is synchronized.

Scenario 2 — Settle an INTERNAL order (USDT purchase) by confirming the trade

A client purchased USDT in INTERNAL mode; the order is LOCKED with a reserve created. Open the detail → Confirm trade → enter the reason. The backend: (1) commits the user's reserve to the treasury customerToPay (debits BRL/payment token, credits the treasury); (2) pays the USDT to the user from the treasury; (3) marks DELIVERED. The timeline records ADMIN_CONFIRM_TRADE. Irreversible operation.

Scenario 3 — Cancel and release a hanging reserve

A FAILED order left a locked reserve in the user's balance. Open the detail → Release reserve → enter the reason. The backend releases the reserve (best-effort) and records ADMIN_RELEASE_RESERVE. If the order were still active, the path would be Cancel, which already releases the reserve in the same step.