Accounts

BCR FLAGS transfer365 · lbtr ·

Retail accounts from account-service. Use Use on a row to set session context for wallet and dev flows, or create a new account.

Loading accounts…

Get / Create Deposit Address POST /api/wallet/deposits/address

List Deposit Addresses GET /api/wallet/deposits/addresses

Fill in account ID and click Load

List Deposits GET /api/wallet/deposits

Get Deposit by ID GET /api/wallet/deposits/{id}

Fill in account ID and click Load

List Withdrawals GET /api/wallet/withdrawals

Get Withdrawal by ID GET /api/wallet/withdrawals/{id}

Fill in account ID and click Load

Withdrawal trace across services/databases

End-to-end evidence for one withdrawal: wallet record, Fireblocks history, transaction-service records, ledger entries, ledger balances, and account balances.

Choose a withdrawal and load full trace.

Rolling 24 hours, same as ensure_withdrawal_limit in wallet-service: statuses pending_approvalcompleted count toward the cap (failed / cancelled / rejected do not). Spent is the sum of usdt_cost (Binance USDT-equivalent notional — same numeric scale as a USD daily cap for stable pricing; not a different “currency” from USD). The daily cap is read from WITHDRAWAL_DAILY_LIMIT_USDT or WITHDRAWAL_DAILY_LIMIT_USD (must match wallet-service; if unset, 1000 — same as lib-limits).

Withdrawal limit usage GET /api/withdrawal-limit-usage

Click Load to aggregate from the wallet DB

List Swaps GET /api/wallet/swaps

Fill in account ID and click Load

Create Swap POST /api/wallet/swaps

Get Swap Quote GET /api/wallet/swaps/quote

Binance Orders GET /api/swap/orders

Click Load to fetch Binance orders (optionally filter by Swap ID)

Ledger Entries GET /api/ledger

Click Load to list ledger entries
Live Balances

Shows one row per (account, coin, reserve) that has ledger entries. Leave filter empty to include every account (e.g. operational 00000000…).

Click "Load all balances" (or set an account filter)

Transaction service — transactions table

Direct read from the transaction-service Postgres database (same rows the service persists). Use TRANSACTION_DATABASE_URL if your DB name differs from transaction_service.

Open this tab to load rows from transactions.

Project databases — tables and columns

Full schema read from configured backoffice DB connections. Column names are shown exactly as they exist in Postgres (no display formatting).

Open this tab to load full DB catalog.

Table data preview for testing

Load sample rows from any table using its real identifier names. This helps verify migrations and data shape quickly during manual testing.

Choose database/schema/table and click Load preview.

List Coins GET /api/coin/list

Get Coin GET /api/coin/get

Resolve Coin ID GET /api/coin/resolve

Resolve by Slug GET /api/coin/resolve-by-slug

Admin: Save Coin (Create or Update) POST /api/coin/admin/update

Uses name + network as key: updates existing coin when found, creates a new one when not found.

Optional fields (expand)

Create Withdrawal POST /api/wallet/withdrawals

Treasury vault (withdrawals)

Fireblocks vault withdrawals are sourced from this vault. Ledger ffffffff…ffff is the treasury ledger mirror.

Fireblocks vault ID
Treasury deposit address

On-chain address optional: set BACKOFFICE_TREASURY_DEPOSIT_ADDRESS in backoffice env (same process as FIREBLOCKS_TREASURY_VAULT_ID).

Treasury ledger account ID
Ledger balances (treasury)
Loading…
Operational account (ledger custody)

Company aggregate custody (debit-normal). Withdrawal balance checks use this ledger account.

Operational ledger account ID
Ledger balances (operational)
Loading…
Live Quote
Price (USDT/token)
USDT equivalent

Get Withdrawal Quote GET /api/wallet/withdrawals/quote

Fireblocks webhook log

Rows come from webhook_events in the wallet-service database — every payload received on POST /webhooks/fireblocks is stored for audit and replay (see wallet-service persist_webhook_event).

Open this tab to load saved webhooks.

User Management

Create passwordless users, list existing users, and manage MFA via user-service (port 50058). Dev creation uses the OTP bypass token.

Create Passwordless User

User Actions

Phone MFA (personal contact):

Register Phone on User (SMS notifications)

Sets phone_number on user-service (not account-service). Auto-verifies OTP in dev mode.

User List (from DB)

Click Load to fetch users from user_service DB.

Account Management (Admin)

BackofficeAccountService (account-service :50052) — list, inspect, lock/suspend/reset PIN on accounts.

List Accounts

Account Actions

Reset PIN

Special Accounts

Click "Load Operational & Treasury" above
Click Load Accounts above.

All Transactions (Backoffice)

BackofficeTransactionService — list, review, approve, cancel transactions. Review/Approve/Cancel require OTP (use "000000" in dev).

Click Load.

Account Transactions

Enter account ID and click Load.

Review Transaction

Approve Transaction

Cancel Transaction

Treasury & Operational

Treasury Transactions

Requires dev operator permissions. If you get "permission denied", go to and click "Grant All Permissions to Dev Operator".

Click Load.

Operational Transactions

Click Load.

BCR Institutions (config-service)

BCR participant banks for LBTR. config-service port 50060.

Click List to load institutions.

Create Institution

Get / Update Institution

Services Health

Live TCP + DB pool check for gRPC services. Ledger is a Kafka worker (process + migration + Kafka + ledger-db). Auto-refreshes every 15 s.

gRPC Services

Loading…

Databases

Loading…

Infrastructure

Loading…

Dev Operator Permissions

Grant all backoffice permissions to the dev operator (00000000-0000-0000-0000-000000000001). Required to access Treasury, Operational, and other permission-gated endpoints. Safe to run multiple times — auth-service is idempotent on grants.

Operational Flags

Kill switches for BCR payment rails. Changes are persisted to the user_service DB (global_feature_flags table) and published to Kafka topic operational.flags with key global.
Auto-refreshes every 5 seconds.

transfer365_enabled

Enables inbound/outbound Transfer365 (BCR) payments.

lbtr_enabled

Enables LBTR settlement rail (BCR Real-Time Gross Settlement).

Current state (from DB)
loading…

LBTR / BCR Mock Producer

Injects messages into Kafka to simulate the BCR network. transaction-service consumes lbtr.transfer.received and creates transactions.
Kafka broker: localhost:9093  ·  BCR REST mock: http://127.0.0.1:8088/api/bcr

① Inject Incoming Transfer (BCR → us)

Publishes to lbtr.transfer.received. transaction-service creates a new transaction and credits the account.

② Inject Status Update (BCR → us)

Publishes to lbtr.status.incoming. Simulates BCR confirming or returning a transaction.

Quick Scenarios

③ Track Resulting Transaction & All State Changes

After injecting a transfer, see the created transaction, its status progression, ledger entries (debit/credit), and account balance changes. Auto-refreshes on status inject.

Inject a transfer above — the result will appear here automatically.

④ BCR Gateway — Outgoing Instructions Received

When lbtr-service processes an outgoing payment (e.g. a LBTR transfer our users send), it calls the BCR Java gateway at POST /api/lbtr/instrucciones. In dev, the backoffice mocks that gateway — all instructions land here.

Click Refresh to load.

Transfer365 Lab

Stepper · saldos origem/destino · Externo↔eNor
De (origem) · disponível
Selecione a origem
Para (destino) · disponível
Selecione o destino
1 · Origem 2 · Valor 3 · Destino
Origem — banco externo (simulado)

Quem envia o pacs.008 para a eNor (lado BCR).

File gateway
output
processed
or
error
📤 input/ · archive
📱 Transfer365 Mobile Registration

Register an E.164 phone on the selected account and seed identity-service keys for email/SMS notifications (dev only).

No account selected — pick one from the top bar or stepper.
E.164 format, e.g. +50372145000
▾ Aguardando confirmação na rede (mock)

Tesouraria (backoffice) e envios da carteira: aprovados com saldo em reserva e pacs.008 em input/, sem resposta BCR final. Confirmar na rede arquiva o pacs.008; depois aplique a resposta no stepper (aba Avançado ou Respostas BCR).

Carregando…
Pipeline
Run receive or send — steps appear here
▸ Scenarios (one-click flows)
INCOMING
OUTGOING
IDENTITY
▸ PACS message tester

Dry run — valida XSD (mesma regra do transfer365-service); nada é gravado em output/

▸ Advanced tools

Transfer365 Mock Producer

Injects messages into Kafka to simulate the Transfer365 network. transaction-service consumes transfer365.received and creates transactions.
Kafka broker: localhost:9093

Inject Received Transfer (transfer365.received)

Simulates Transfer365 sending an incoming payment. transaction-service will process and credit the account.

Inject Status Update (transfer365.received.status)

Updates the transaction status in transaction-service via Kafka.

Expected behaviour: transfer365-service will log an error for mock-injected transactions because they bypass its internal file engine (redb has no record). This is harmless — transaction-service correctly processes the status update.

Quick Scenarios

③ Track Resulting Transaction & All State Changes

After injecting a transfer above, see the transaction created, its current status, ledger entries, and account balance. Auto-refreshes when you inject a status update.

Inject a transfer above — the result will appear here automatically.

Simulador de transferências

Ferramenta de testes (não é o sistema real do cliente). Serve para simular pagamentos que chegam do banco ou que a eNor envia, e ver se tudo foi processado certo.

Caminho recomendado: aba Simulador (batch BCR) · testes manuais em Fazer um teste · checklist em Relatórios de teste.

Resumo: quantos pagamentos estão em cada etapa. Número grande = quantidade de arquivos. Use Atualizar no topo.

Aguardando processar
Acabaram de chegar
Já processados
Tudo certo
Com erro
Não deu para processar
Saída para o banco
Quando a eNor envia ao banco

Últimos arquivos:

Simulador BCR unificado — cria transações reais (depósito + reserva + operacional), aplica respostas BCR (pacs.002 / pacs.004) e gera relatório pass/fail para todos os cenários da matriz. Pré-requisitos: stack local (transfer365-service, Kafka, transaction/ledger-service), seed dev, T365_APP_DIR igual no console e no serviço.

Depósito disponível
Depósito reservado
Depósito total
Atualizado
Ledger global (diagnóstico avançado)
Pool em circulação
Reserva espelho (global)
Saldo bruto ledger

Não é saldo da conta. Conta operacional global (00000000-…) é débito-normal: saldo bruto negativo = fundos já implantados nas contas (esperado após top-ups e liquidações). Reserva espelho acompanha o depósito reservado da conta origem.

Depósito = account_balances (igual ao header/Lab). Disponível + reservado = total.

Configuração

Progresso

Pronto


                  
Executar caso a caso Um caso de cada vez — valida configuração antes de correr
A carregar matriz…
Relatório
Execute a matriz para ver resultados.

Plano de cobertura Transfer365 — lista todos os cenários que devem ser executados para validar o simulador (inbound, outbound, BCR, fila pendente, regressões). Marque o status de cada execução e exporte o checklist (JSON, CSV, Markdown ou PDF). O Transfer365 Lab continua a gravar a sessão com XML; use a aba Simulador para batch automático ou marque manualmente aqui.

Clique « Atualizar matriz » para carregar o plano de testes.
Como usar: receber (esquerda) ou enviar (direita) — pills 1 · 2 · 3, como no Transfer365 Lab.

Receber (banco → eNor)

Crédito inbound (pacs.008 simulado).

1 · Conta 2 · Valor
Conta que recebe

Conta eNor que será creditada.

Enviar (eNor → destino)

Obrigatório: dry run lib-transfer-validate antes do envio real.

Dry run (lib-transfer-validate)Ainda não validado.
1 · Origem 2 · Destino 3 · Valor
Origem

Conta eNor que envia (reserva saldo).

Ainda não há mensagens. Rode um dos testes acima.

Pedido e resposta

Situação: aguardando teste

1. Chegou aqui
2. Resposta

XML manual na aba .

Mensagens XML: mesmo fluxo em pills que Fazer um teste — inbound grava em output/ (XSD); outbound simula resposta do banco (pacs.002/004). Envio eNor (initiate/confirm) só na aba Fazer um teste com lib-transfer-validate.

Inbound — banco → eNor

Passos 1→2→3 · validação XSD (não é lib-transfer-validate).

1 · Modelo 2 · XML 3 · Enviar
1 · Modelo

Escolha o tipo e preencha os campos; depois gere o XML.

Outbound — resposta do banco

Passos 1→2→3 · após envio eNor na aba Fazer um teste.

Envio eNor: use — dry run lib-transfer-validate + initiate/confirm. Esta aba só simula a resposta do banco (pacs.002/004).
1 · Atalho 2 · Modelo 3 · XML
1 · Atalho

Resposta do banco sem colar XML (cenário + MsgId).

Pedido e resposta

Situação: aguardando

1. Chegou
2. Resposta

Configure o que o BCR devolve ao eNor: pacs.002 (grupo ou liquidação), pacs.004 (devolução) ou atalho Kafka. Os XML gerados vão para output/. No fluxo tesouraria/carteira pendente, use Avançado (confirmar na rede → stepper abaixo da fila).

1 · Tipo 2 · Parâmetros 3 · Aplicar
Tipo de resposta

Escolha o formato ISO ou um preset nomeado.

Para backend / API externa: o simulador T365 no console expõe os mesmos fluxos via HTTP. Em produção a sua API chama transaction-service (gRPC) com sessão real; em dev use estas rotas do console (cargo run -p consolelocalhost:8088).

1 · Catálogo de bancos (bank_code)

O bank_code no validate/initiate é o id desta lista — não o BIC.

curl -sS "$BASE/api/institutions" | jq .

2 · Dry run — lib-transfer-validate (obrigatório antes do envio)

Equivalente ao botão « Validar transferência » / Passo 1 do E2E. Substitua ACCOUNT_UUID, conta destino e bank_code.

curl -sS -X POST "$BASE/api/discovery/transfer/validate" \
  -H "Content-Type: application/json" \
  -d '{
  "account_id": "ACCOUNT_UUID",
  "coin_id": "00000000-0000-0000-0000-000000000000",
  "amount": 10000,
  "counterpart_type": "external",
  "name": "Beneficiary Test",
  "customer_type": 1,
  "account_type": 2,
  "account_number": "1010000007",
  "bank_code": 6,
  "document": "041234567"
}' | jq .

3 · Initiate + confirm (envio real no ledger)

Mesmo body do validate + description e channel. Guarde transaction_id da resposta do initiate.

curl -sS -X POST "$BASE/api/discovery/transfer/initiate" \
  -H "Content-Type: application/json" \
  -d '{
  "account_id": "ACCOUNT_UUID",
  "coin_id": "00000000-0000-0000-0000-000000000000",
  "amount": 10000,
  "counterpart_type": "external",
  "name": "Beneficiary Test",
  "customer_type": 1,
  "account_type": 2,
  "account_number": "1010000007",
  "bank_code": 6,
  "document": "041234567",
  "description": "curl test outbound",
  "channel": 1
}' | jq .
curl -sS -X POST "$BASE/api/discovery/transfer/confirm" \
  -H "Content-Type: application/json" \
  -d '{
  "account_id": "ACCOUNT_UUID",
  "transaction_id": "TX_UUID_FROM_INITIATE"
}' | jq .

4 · File gateway — injetar XML (BCR → eNor)

Validação XSD: /api/simulator/t365/validate. Envio: /api/simulator/t365/submit (grava em output/).

curl -sS -X POST "$BASE/api/simulator/t365/validate" \
  -H "Content-Type: application/json" \
  -d '{"xml":"<Document xmlns=\"urn:iso:std:iso:20022:tech:xsd:pacs.008.001.07\">...</Document>"}' | jq .
curl -sS -X POST "$BASE/api/simulator/t365/submit" \
  -H "Content-Type: application/json" \
  -d '{"xml":"...","processing_mode":"ift","dry_run":false}' | jq .

5 · Resposta do banco (pacs.002) após outbound T365

curl -sS -X POST "$BASE/api/simulator/t365/respond" \
  -H "Content-Type: application/json" \
  -d '{"scenario":"liquidate","original_msg_id":"MSGID_FROM_INPUT","amount":10000}' | jq .

Variável BASE (copiar/colar no terminal)

export BASE="http://localhost:8088"

Erro « Invalid bank code »? O bank_code não existe no catálogo ou config-service está parado. Confira com o passo 1. Conta origem: UUID em GET /api/accounts (aba Accounts) — o console cria sessão dev automaticamente para discovery.

Só para técnicos: formulários detalhados para criar cada tipo de mensagem bancária. Se não tiver certeza, use a aba Fazer um teste.

Aguardando confirmação na rede (mock)

Transferências outgoing aprovadas com saldo em reserva e pacs.008 em input/, mas ainda sem resposta BCR final. Passo 1: Confirmar na rede (arquiva o pacs.008). Passo 2: escolha a resposta no stepper abaixo (liquidação, RJCT, ACCP, etc.) e Aplicar resposta.

Carregando…
Tipo de mensagem:

Lista de arquivos que o sistema guardou durante os testes. Pode clicar para ver o conteúdo ou apagar pastas antigas.

Lista de arquivos

Clique em « Atualizar tela » no topo para carregar a lista.
📋

Registo do sistema (técnicos)

Últimas linhas do diário interno — útil se algo falhou e a equipa técnica pedir detalhe.

Aperte « Carregar registo » para ver.
📡

Passos do pagamento

Mostra, passo a passo, se o dinheiro foi creditado e confirmado. Atualiza sozinha após um teste.

Faça um teste na aba « Fazer um teste » — os passos aparecem aqui automaticamente.

Detalhe da conta e do saldo

Depois de simular um pagamento recebido, informe o número da conta (ou deixe preencher sozinho) e aperte « Ver detalhes » para ver transação e saldo.

Simule um pagamento recebido — a conta credora preenche-se e o rasto aparece aqui.

BCR Gateway Mock

This backoffice replaces the external Java lbtr-gateway app. lbtr-service calls POST /api/bcr/lbtr/instrucciones here when processing outgoing payments. Click ↓ JSON on any row to download the exact payload sent to the gateway.

Loading…
BCR Test Environment Reference (from docs/BCR_CONTEXT.md — for lbtr-gateway Java app, not this mock)

SOAP Endpoints (test)

Instrucciones lbtrdes.bcr.gob.sv/lbtr-ws/InstruccionServiceSoapHttpPort
Lote lbtrdes.bcr.gob.sv/lbtr-ws/LoteServiceSoapHttpPort
SPM (T365) lbtrdes.bcr.gob.sv/lbtr-ws/ServicioPagoServiceSoapHttpPort
Server IP 192.168.11.56
Notif server notificacioneslbtrdes.bcr.gob.sv (192.168.11.69)

⚠ BCR internal network only — VPN / dedicated line required

WS-Security & Certificates

Protocol SOAP/WSDL Document/Wrapped
Security OASIS WS-Security V1.2 · X.509
Policy Wssp1.2-2007-Wss1.1-X509-Basic256Sha256
Keystore lbtrcliente.jks (pw: lbtrcliente)
Truststore lbtrcliente_truststore.jks
Key alias lbtrcliente

TraceableReference format (25 chars)

YYYYMMDD{entity:03}{correlative:05}{internal_ref:09}

Entity 089 = our participant. Date must match today — BCR rejects mismatches.
Auto-generated in LBTR mock above. Implemented in lib-bcr::lbtr::types::TraceableReference.

Full specs → docs/BCR_CONTEXT.md in repo · Also see dev/console/TEAM_REVIEW_BACKLOG.md §8

Create Internal Transfer

Transfer between two eNor accounts via transaction-service gRPC — InitiateTransferConfirmTransfer. The recipient is resolved by transfer key (phone, email, or account UUID) via the identity/keys service.

💳 Sender
🎯 Recipient
💰 Amount & Coin

External Transfer (Outbound)

Send from an eNor account to an external bank via InitiateTransferConfirmTransfer. Confirm triggers ledger debit → outbox → Transfer365/LBTR routing.

① Sender — eNor Account
② Recipient — External Bank
③ Amount & Coin

Quick Setup — Transfer365 ready

Creates a passwordless user, verifies email, opens a CHECKING account (SV) — and optionally a SAVINGS account to test multiple account_type values. Funds USD (00000000-0000-0000-0000-000000000000), runs KYC, and pre-fills Transfer365 / External Transfer fields. Leave email blank to auto-generate a unique address.

Setup Parameters

Run the setup to see results.

WhatsApp / BCR onboarding (E2E)

Stepped wizard aligned with bcr-bot onboarding: KYC → Accept contract → Create PIN. Step 4 uses AcceptContract (creates the bank account). Uses whatsapp-service gRPC via console JWT. See docs/adr/ADR-0349.md.

Loading config…

Test hygiene (RUN_MODE=dev on whatsapp-service)

{}

Signup Web

Join eNor Securities in a few simple steps.

Carregando…

Step 1 of 3

Create account

Enter your email to receive a verification code.

Choose a password

Create a strong password for your account.

    Almost there

    Enter your name and accept the terms to finish.

    Account created!

    Complete onboarding below (KYC + PIN), same as the web dashboard.

    Ferramentas de desenvolvedor

    Crédito de saldo (dev): informe account_id ou telefone.


    Swap / Transfer365 via customer-web (/api/web/*) — requer sessão ativa acima.

    Swap

    Transfer365

    Counterpart (external bank recipient)

    {}

    Fund Treasury Deposit Account

    Credits the backoffice deposit-account ledger mirror (ffffffff-ffff-ffff-ffff-ffffffffffff) via Kafka ledger.transactions. Same balance shown at ops-web /admin/banking/deposit-account. Dev-only; requires ledger-service and account-service running.

    Current balance

    Open this view to load…

    Add Balance (AccountTestService)

    Directly credit an account without going through the full transfer flow. Dev-only service, not available in production.

    After adding balance

    Verify the balance was credited in the account service DB:

    QR Code Testing (QrCodeService on transaction-service)

    Generate QR

    Get QR Details

    Scan / Initiate Payment

    Outbox Health

    Shows pending entries in each service's outbox table — a non-zero count means Kafka is behind or blocked.

    Loading…

    Scheduled Payments (TransactionService)

    Enter an account ID and click Load.

    KYC Management (UserService)

    Get and set KYC levels for users. Requires a valid user session (user_id + auth-service running).

    Get KYC Level

    Finish KYC (Complete onboarding)

    Permission Profiles (BackofficePermissionService on auth-service)

    Click Reload.

    Create Profile

    Assign / Remove Profile from User

    Contract Management (BackofficeComplianceService on compliance-service)

    Click List Contracts.

    Upload Contract PDF

    Select a PDF file — it will be base64 encoded and uploaded.

    Activate Contract Version

    Sets this contract as the current active version users must accept.

    🔗 Fireblocks Webhook Simulator

    Sends a properly HMAC-signed Fireblocks webhook to wallet-service. Set FIREBLOCKS_WEBHOOK_SECRET env var in both services to match.

    🕵️ Multi-Service Tracer

    One UUID — full picture across transactions, ledger, deposits, withdrawals, accounts, and swaps.

    🔐 Session Manager

    🛡 Permission Debugger

    Check if a user is authorized for a specific permission.

    ⚖️ Balance Reconciliation

    Compares account-service reported balances vs. sum of ledger entries for an account.

    📦 Migration Status

    Shows applied migrations per service DB.

    💸 Internal Transfer Flow

    Preview → Initiate → Confirm a transfer on behalf of any account. Server mints a dev session automatically.

    📡 Kafka Activity Monitor

    Shows the 10 most recently updated rows in each service's core tables — a proxy for live Kafka activity.

    📜 Service Log Viewer

    Tails the last N lines from /tmp/<service>.log

    Request Log Click any row to expand request/response · method · status · path · latency