Skip to content

Balance

Queries the bank account balance associated with the API Key.

Endpoint

GET /api/external/balance

Headers

HeaderTypeRequiredDescription
AuthorizationStringYesApiKey {client_id}:{client_secret}
X-Key-CaseStringNoSet to camelCase to receive response fields in camelCase (default is snake_case)

Example

bash
curl -X GET https://api.owem.com.br/api/external/balance \
  -H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET"

Success Response (200)

json
{
  "worked": true,
  "balance": 3000000,
  "available": 2700000,
  "pending": 300000,
  "currency": "BRL"
}
FieldTypeDescription
workedBooleantrue indicates operation success
balanceIntegerSafe balance in base units (÷ 10,000 for BRL). 3000000 = R$ 300.00
availableIntegerAvailable balance for operations in base units. 2700000 = R$ 270.00
pendingIntegerAmount held in pending transactions in base units. 300000 = R$ 30.00
currencyStringCurrency code (always BRL)

Response values in base units

All response values are integers in base units. To convert to BRL, divide by 10,000. Example: 3000000 ÷ 10,000 = R$ 300.00. Never use floating point.

Balance calculation

FieldDefinition
balanceSafe balance = min(tigerbeetle_balance, postgres_balance). If there is a TB↔PG divergence, the smaller value is used
availablebalance - pending — balance effectively available for new operations
pendingSum of pending debits in TigerBeetle (account.debits_pending)

The balance field protects against inflated balance in scenarios of temporary divergence between TigerBeetle and PostgreSQL (e.g., MED block, post-deploy reconciliation). You will never see here a value higher than what is actually available in the ledger system — always the smaller of the two systems.

What composes pending (pending debits in TigerBeetle)

Each item below is a pending transfer in TigerBeetle that reduces available until it is posted or voided:

OriginWhen it appearsWhen it is released
PIX OUT in flight (TB pending from wallet → in-transit COSIF)During sending, while awaiting BACEN confirmation (~1.6s typical)Posted on pix.payout.confirmed (settled); voided on pix.payout.failed
MED preventive block (phantom hold, code 1032)When an ACKNOWLEDGED infraction >R$1k is detected via ComplianceSyncWorkerVoided on analysis_result=DISAGREED (defense accepted); posted on AGREED (PACS.004 refund executed). See Infractions.
Quarantine (stage=5)PIX OUT without BACEN response >30min — balance stays in limboPosted/voided only after manual decision by the Owem reserve team (may take hours or D+1). See pix-lifecycle.
Other internal holdsRare — usually related to fees or specific adjustmentsDepends on the type

Situations where balance < raw TB balance

  • TB↔PG divergence: in rare cases (e.g., post-deploy remediation window, session 142 TB-PG equalization incident), balance reflects the smaller of the two systems until convergence. We never see an inflated balance; at most, it is underreported for a few minutes.

available may appear "stuck" even with growing PIX IN

If you see balance rising (inflows) but available not growing proportionally, an active MED block is very likely. Query GET /api/external/med to list the preventive blocks. Every block originates from an infraction — see Infractions for the complete flow.

Cache and consistency

The balance is computed in real time (typical latency <10ms) — there is no cache. However, in post-settlement windows (<200ms after the pix.charge.paid webhook), PostgreSQL may not yet be updated. For critical reconciliation, wait for the webhook before querying the balance.

Error Response (401)

json
{
  "worked": false,
  "errors": {
    "unauthorized": "Missing API key credentials. Use Authorization: ApiKey <client_id>:<client_secret>"
  }
}

Owem Pay Instituição de Pagamento — ISPB 37839059