# BRC Core API — LLM Integration Guide > BRC is a 1:1 BRL-pegged token on the Liquid Network (Bitcoin sidechain). > This file contains everything you need to integrate with the BRC API. ## Site and documentation version - **brc-site-version:** `2026-03-27` — bump this line and `` in `index.html` whenever you change public copy, API examples on the landing page, or this `llms.txt`. - The live site shows the same value in the footer (read from the meta tag). ## Base URL https://api.brctoken.xyz ## Authentication All partner endpoints require the header: X-API-Key: brc_live_... Public endpoints (/v1/health, /v1/asset-info) require no authentication. ## Endpoints ### POST /v1/deposit Request a BRL deposit (pending until PSP webhook or admin confirmation). Request: ```json { "amount": 1000, "railway": "pix" } ``` Response (200): ```json { "transaction_id": "uuid", "status": "pending", "amount": 1000, "railway": "pix", "message": "Aguardando confirmação" } ``` Errors: 400 INVALID_AMOUNT, INVALID_RAILWAY | 401 Unauthorized | 403 Forbidden --- ### POST /v1/brc-deposit-addresses Generate a **disposable** Liquid Network address to receive BRC on-chain (one address per payment / third-party checkout). After confirmed funds, the platform credits the partner’s **BRC ledger** and burns the asset in custody. Feature flag: `flow_brc_deposit_address` (403 FEATURE_DISABLED if off). Optional JSON body: ```json { "external_id": "pedido_123", "metadata": { "order_id": "abc", "user_ref": "u42" } } ``` - `external_id`: optional string, max 128 characters, **unique per partner** when set (409 RESOURCE_CONFLICT if duplicate). - `metadata`: optional JSON **object** (not a string or array at top level). Response (201): ```json { "intent_id": "550e8400-e29b-41d4-a716-446655440000", "liquid_address": "lq1qq...", "asset_id": "hex...", "status": "awaiting_funds", "external_id": "pedido_123", "expires_at": "2026-03-27T12:00:00Z", "created_at": "2026-03-27T11:00:00Z" } ``` Errors: 400 invalid json / metadata not object / external_id too long | 401 | 403 | 409 duplicate external_id | 502 elements errors --- ### GET /v1/brc-deposit-addresses/:intent_id Poll deposit status for the authenticated partner. `intent_id` is the UUID from POST. Response (200), example when complete: ```json { "intent_id": "550e8400-e29b-41d4-a716-446655440000", "liquid_address": "lq1qq...", "status": "credited", "brc_amount": 100.5, "liquid_txid_receive": "hex...", "liquid_txid_sweep": "hex...", "updated_at": "2026-03-27T11:05:00Z" } ``` `status` may be `awaiting_funds`, `processing`, `credited`, or `expired`. When `credited`, `brc_amount` and txids are set. Optional `external_id` / `metadata` echoed when present. Errors: 400 invalid intent_id | 401 | 403 | 404 NOT_FOUND --- ### GET /v1/quote?brl_amount=1000 Get a conversion quote BRL → BRC. Quote is valid for 2 minutes. Response (200): ```json { "quote_id": "uuid", "brl_amount": 1000, "brc_amount": 950, "fee": 50, "convert_fee_pct": 0.05, "convert_fee_fixed": 2.5, "valid_for_seconds": 120, "expires_at": "2026-01-01T00:02:00Z" } ``` Errors: 400 Bad Request | 401 Unauthorized | 403 Forbidden --- ### POST /v1/convert Convert BRL to BRC (mint). Requires a valid quote_id and a Liquid Network address. Request: ```json { "quote_id": "550e8400-e29b-41d4-a716-446655440000", "address": "el1qq..." } ``` Response (200): ```json { "transaction_id": "uuid", "quote_id": "uuid", "brl_debited": 1000, "brc_minted": 950, "fee": 50, "address": "el1qq...", "liquid_txid": "hex...", "brl_balance": 4000, "brc_issued": 4750, "brc_custody_balance": 4200, "status": "confirmed" } ``` Errors: 400 INVALID_AMOUNT, INVALID_ADDRESS, INVALID_QUOTE, INSUFFICIENT_BRL_BALANCE | 401 Unauthorized | 403 Forbidden | 502 Bad Gateway | 503 Service Unavailable --- ### POST /v1/withdraw Redeem BRC (burn) and receive BRL via PIX. Request: ```json { "brc_amount": 947.5 } ``` Response (200): ```json { "transaction_id": "uuid", "brc_burned": 947.5, "pix_amount": 947.5, "fee": 0, "liquid_txid": "hex...", "brc_issued": 3802.5, "brc_custody_balance": 3600, "status": "confirmed" } ``` Errors: 400 Bad Request | 401 Unauthorized | 403 Forbidden | 502 Bad Gateway | 503 Service Unavailable --- ### POST /v1/payout Request a BRL payout to a PIX key from the partner's BRL ledger balance. The request is recorded as pending; the platform sends the PIX asynchronously (queued processing). Requires sufficient BRL balance (including other pending payout requests). Feature: `flow_pix_woovi`. Request: ```json { "key": "pix@exemplo.com", "type": "EMAIL", "amount": 500 } ``` `type` is the PIX key type: `CPF`, `CNPJ`, `EMAIL`, `PHONE`, or `RANDOM`. `amount` is in BRL. Response (200): ```json { "transaction_id": "uuid", "amount": 500, "key_type": "EMAIL", "status": "pending", "message": "payout request registered; processing is asynchronous (Woovi dispatch via PAYOUT_CRON_INTERVAL_SECONDS)" } ``` **Outbound webhooks (partner `webhook_url`):** same pattern as depósito/conversão — `POST` JSON, headers `Content-Type: application/json`, `X-BRC-Event` (valor = campo `event` no corpo). Eventos de payout assíncrono: - `payout.requested` — logo após `POST /v1/payout` gravar a solicitação (`status` tipicamente `pending`; sem `correlation_id` até o cron despachar). - `payout.dispatched` — cron enviou o pagamento à Woovi e gravou `correlation_id` no registo. - `payout.confirmed` — Woovi notificou movimento confirmado (PIX liquidado). - `payout.failed` — falha com estorno no ledger; corpo pode incluir `failure_reason` (string). Ex.: meta inválida (`invalid_payout_request_meta`), erro Woovi no envio, ou evento Woovi `OPENPIX:MOVEMENT_FAILED` / `OPENPIX:MOVEMENT_REMOVED` após estorno. Campos úteis no JSON (além dos da transação): `pix_key_type`, `pix_destination_masked` (chave pedida no payout, mascarada). Em **todos** os webhooks de payout (`payout.requested`, `payout.dispatched`, `payout.confirmed`, `payout.failed`), o corpo inclui o que estiver disponível em `provider_meta` (sempre com máscaras onde aplicável): - Após o cron despachar o pagamento ao PSP (`payout.dispatched`): dados da resposta gravados em `provider_meta` (objeto interno do provedor) — no webhook aparecem com chaves neutras: `payout_provider_payment_status`, `payout_provider_payment_value_cents`, `payout_provider_destination_alias_masked`, `payout_provider_comment`, e quando a API devolver `transaction`/`destination`: `payout_pix_end_to_end_id` / `pix_end_to_end_id` (se já existir E2E), `payout_provider_transaction_correlation_id`, `payout_provider_transaction_time`, mais `payout_beneficiary_*`, `payout_bank_*`. - Após confirmação do movimento PIX (`payout.confirmed`): campos finais (`pix_end_to_end_id`, `payout_pix_end_to_end_id`, `payout_provider_tx_correlation_id`, `payout_settlement_time`, `payout_payment_status`, `payout_payment_value_cents`, beneficiário/banco mascarados, etc.) vêm de `payout_settlement` e **substituem/completam** os da fase de despacho quando houver divergência. O JSON completo permanece na BD (`payout_settlement` + metadados do PSP em `provider_meta`). `deposit.confirmed` — quando a confirmação vem do webhook Woovi `OPENPIX:CHARGE_COMPLETED`, o sistema grava `deposit_settlement` em `provider_meta` (pagador, `endToEndId`, ids da cobrança/PIX, etc., completos na BD). No POST ao parceiro entram campos **mascarados** adicionais: `deposit_charge_correlation_id`, `deposit_charge_transaction_id`, `deposit_pix_end_to_end_id`, `deposit_pix_transaction_id`, `deposit_pix_time`, `deposit_pix_value_cents`, `deposit_pix_payer_info`, `deposit_payer_name`, `deposit_payer_tax_id_masked`, `deposit_payer_tax_id_type`, `deposit_payer_email_masked`, `deposit_payer_phone_masked`. Confirmações só por admin ou `deposit-confirm` não preenchem `deposit_settlement`. **Resgate BRC (`POST /v1/withdraw`):** grava `withdraw_settlement` em `provider_meta` com `liquid_tx_id`, `liquid_address`, `brc_amount`, `fee_brc`, `confirmed_at` (prova on-chain do burn). Em `GET /v1/transactions`, `liquid_address` dentro de `withdraw_settlement` aparece **mascarada**; o restante segue visível para conciliação. Em `GET /v1/transactions`, `provider_meta` continua **redigido** para o parceiro nos ramos sensíveis (`deposit_settlement`, `payout_*`, `woovi`, etc.). Errors: 400 INVALID_AMOUNT, INSUFFICIENT_BRL_BALANCE | 401 Unauthorized | 403 Forbidden | 500 Internal Server Error --- ### GET /v1/balance Get BRL balance, net BRC issued on the platform (ledger), and BRC on the partner custody Liquid address. Response (200): ```json { "brl_balance": 5000, "brc_issued": 4750, "brc_custody_balance": 4200 } ``` --- ### GET /v1/me Get the authenticated partner's profile, including fees. Response (200): ```json { "id": "uuid", "name": "Parceiro X", "email": "contato@parceiro.com", "status": "active", "liquid_address": "el1qq...", "webhook_url": "https://parceiro.com/webhook", "brl_balance": 5000, "brc_issued": 4750, "brc_custody_balance": 4200, "fees": { "deposit_fee_pct": 0, "deposit_fee_fixed": 0, "convert_fee_pct": 0.05, "convert_fee_fixed": 2.5, "withdraw_fee_pct": 0, "withdraw_fee_fixed": 0 } } ``` --- ### GET /v1/transactions?limit=50&offset=0 List the partner's transactions. Supports pagination via limit (max 200) and offset. O campo `provider_meta` é **redigido** (sem chave PIX completa, sem PII de settlement nem dados sensíveis dentro de `woovi`); a base interna e o admin mantêm o JSON completo para operações. Response (200): ```json { "total": 42, "limit": 50, "offset": 0, "transactions": [ { "id": "uuid", "type": "convert", "status": "confirmed", "brl_amount": 1000, "brc_amount": 950, "fee_amount": 50, "railway": "pix", "liquid_address": "el1qq...", "liquid_txid": "hex...", "correlation_id": "", "provider_meta": {}, "quote_id": "uuid", "created_at": "2026-01-01T00:00:00Z", "updated_at": "2026-01-01T00:01:00Z" } ] } ``` --- ### GET /v1/health (public) Check API and elementsd node status. Response (200): ```json { "status": "ok", "elements": { "status": "ok", "network": "liquidv1", "block_height": 123456, "synced": true } } ``` Response (503 — degraded): ```json { "status": "degraded", "elements": { "status": "unavailable", "error": "connection refused" } } ``` --- ### GET /v1/asset-info (public) Get BRC asset metadata from the Elements node. Response (200): ```json { "asset_id": "hex...", "reissuance_token": "hex...", "network": "liquidv1", "node_version": "23.x", "node_block_height": 123456 } ``` ## Error Format All errors follow this envelope: ```json { "error": { "code": "ERROR_CODE", "message": "Human-readable description" } } ``` Common codes: INVALID_AMOUNT, INVALID_ADDRESS, INVALID_QUOTE, INVALID_RAILWAY, INSUFFICIENT_BRL_BALANCE, INVALID_CREDENTIALS, PARTNER_SUSPENDED ## Typical Integration Flow 1. POST /v1/deposit → deposit BRL (status: pending) 2. Wait for deposit confirmation (webhook or admin) 3. GET /v1/quote?brl_amount=X → get quote (valid 2 min) 4. POST /v1/convert → mint BRC to a Liquid address 5. POST /v1/withdraw → burn BRC and receive BRL via PIX 6. POST /v1/payout → request BRL sent to a PIX key (async / queued) 7. GET /v1/balance → check balances at any time 8. GET /v1/transactions → list transaction history ## Notes - All amounts are JSON numbers (also accepts decimal strings). - Quotes expire after 2 minutes. - PIX cash-in is instant; BRC minting on Liquid takes ~2 min finality. - Cash-out (BRC → BRL via PIX) is processed in seconds. - Liquid addresses start with "el1qq..." (confidential) or "ex1q..." (unblinded). - Contact: contato@brctoken.xyz