Skip to content

Transaction Service

The Transaction Service (transaction_service) manages financial transfers across the STR (Sistema de Transferencia de Reservas), LPI (Liquidacao por Prioridade Intradiaria), TED (Transferencia Eletronica Disponivel), and DOC (Documento de Credito) settlement systems.

Port: 4005

Responsibilities

  • Process STR real-time gross settlement transfers
  • Handle LPI intraday priority-based settlement
  • Manage TED same-day electronic funds transfers
  • Process DOC next-business-day credit transfers
  • Enforce settlement window rules and operating hours
  • Maintain transaction state machines with full audit trails
  • Perform balance checks and liquidity validation

Transaction State Machine

Every transaction follows a well-defined state machine:

                 +----------+
                 |  created |
                 +----+-----+
                      |
                +-----v------+
                |  validating |
                +-----+------+
                      |
              +-------+--------+
              |                |
        +-----v-----+   +-----v------+
        |  rejected  |   |  submitted |
        +-----------+   +-----+------+
                              |
                        +-----v------+
                        | processing |
                        +-----+------+
                              |
                    +---------+---------+
                    |                   |
              +-----v-----+      +-----v------+
              |  settled   |      |   failed   |
              +-----------+      +-----+------+
                                       |
                                 +-----v------+
                                 |  retrying   |
                                 +------------+

STR Transfers

STR is BACEN's RTGS system for high-value, time-critical transfers. Each STR transfer is settled individually in real time against the institution's reserve account at BACEN.

Creating an STR Transfer

bash
POST /api/v1/transactions/str
Authorization: Bearer <token>
Content-Type: application/json

{
  "sender_ispb": "12345678",
  "receiver_ispb": "87654321",
  "amount": "5000000.00",
  "purpose_code": "1",
  "reference": "PAGTO-2026-001",
  "scheduled_time": null
}

STR Operating Rules

RuleValue
Operating hours06:30 - 17:30 BRT
Minimum amountR$ 0.01
Maximum amountNo limit (subject to balance)
SettlementReal-time (LBTR)
FinalityIrrevocable upon R3 confirmation
elixir
defmodule TransactionService.STR do
  @operating_start ~T[06:30:00]
  @operating_end ~T[17:30:00]

  def create_transfer(params) do
    with :ok <- validate_operating_hours(),
         :ok <- validate_ispb(params.sender_ispb),
         :ok <- validate_ispb(params.receiver_ispb),
         :ok <- validate_amount(params.amount),
         {:ok, tx} <- persist_transaction(params),
         {:ok, _} <- submit_to_bacen(tx) do
      {:ok, tx}
    end
  end

  defp validate_operating_hours do
    now = DateTime.now!("America/Sao_Paulo") |> DateTime.to_time()

    if Time.compare(now, @operating_start) in [:gt, :eq] and
       Time.compare(now, @operating_end) in [:lt, :eq] do
      :ok
    else
      {:error, :outside_operating_hours}
    end
  end
end

TED Transfers

TED enables same-day electronic funds transfers between different financial institutions. TED transfers are settled through STR in real time.

Creating a TED Transfer

bash
POST /api/v1/transactions/ted
Authorization: Bearer <token>
Content-Type: application/json

{
  "sender_ispb": "12345678",
  "receiver_ispb": "87654321",
  "amount": "15000.00",
  "sender_account": "00012345",
  "sender_branch": "0001",
  "sender_name": "Empresa ABC Ltda",
  "sender_document": "12345678000190",
  "receiver_account": "00098765",
  "receiver_branch": "0002",
  "receiver_name": "Empresa XYZ S.A.",
  "receiver_document": "98765432000110",
  "purpose": "payment"
}

TED Response

json
{
  "data": {
    "id": "tx_01HQXYZ123456",
    "type": "TED",
    "status": "submitted",
    "amount": "15000.00",
    "sender_ispb": "12345678",
    "receiver_ispb": "87654321",
    "nuop": "123456782026011500042",
    "created_at": "2026-01-15T10:30:00-03:00",
    "bacen_status": "awaiting_r2",
    "estimated_settlement": "2026-01-15T10:30:05-03:00"
  }
}

DOC Transfers

DOC processes credit transfers settled on the next business day (D+1) through the LDL deferred net settlement system.

bash
POST /api/v1/transactions/doc
Authorization: Bearer <token>
Content-Type: application/json

{
  "sender_ispb": "12345678",
  "receiver_ispb": "87654321",
  "amount": "4500.00",
  "sender_account": "00012345",
  "receiver_account": "00098765",
  "settlement_date": "2026-01-16"
}

Balance and Statement Queries

STR Balance

bash
GET /api/v1/str/balance
Authorization: Bearer <token>

# Response
{
  "data": {
    "ispb": "12345678",
    "available_balance": "125000000.00",
    "blocked_balance": "5000000.00",
    "total_balance": "130000000.00",
    "currency": "BRL",
    "as_of": "2026-01-15T10:30:00-03:00"
  }
}

Transaction Statement

bash
GET /api/v1/str/statement?date=2026-01-15&page=1&page_size=50
Authorization: Bearer <token>

# Response
{
  "data": {
    "date": "2026-01-15",
    "opening_balance": "120000000.00",
    "closing_balance": "125000000.00",
    "entries": [
      {
        "nuop": "123456782026011500001",
        "type": "STR",
        "direction": "credit",
        "amount": "10000000.00",
        "counterparty_ispb": "11111111",
        "settled_at": "2026-01-15T08:15:00-03:00"
      }
    ],
    "pagination": {
      "page": 1,
      "page_size": 50,
      "total_entries": 127,
      "total_pages": 3
    }
  }
}

Transaction Cancellation

Transactions may be cancelled before final settlement (before R3 is received):

bash
POST /api/v1/transactions/tx_01HQXYZ123456/cancel
Authorization: Bearer <token>
Content-Type: application/json

{
  "reason": "Duplicate transaction",
  "reason_code": "DUP"
}

Cancellation is subject to the transaction's current state and BACEN's cancellation rules for each system.

Database Schema

sql
CREATE TABLE transactions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  type VARCHAR(3) NOT NULL CHECK (type IN ('STR', 'LPI', 'TED', 'DOC')),
  status VARCHAR(20) NOT NULL DEFAULT 'created',
  nuop VARCHAR(20) UNIQUE,
  sender_ispb VARCHAR(8) NOT NULL,
  receiver_ispb VARCHAR(8) NOT NULL,
  amount DECIMAL(18, 2) NOT NULL CHECK (amount > 0),
  purpose_code VARCHAR(4),
  reference VARCHAR(100),
  bacen_status VARCHAR(20),
  r1_received_at TIMESTAMPTZ,
  r2_received_at TIMESTAMPTZ,
  r3_received_at TIMESTAMPTZ,
  settled_at TIMESTAMPTZ,
  failed_at TIMESTAMPTZ,
  failure_reason TEXT,
  tenant_id UUID NOT NULL,
  created_by UUID NOT NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_transactions_tenant ON transactions (tenant_id, created_at DESC);
CREATE INDEX idx_transactions_nuop ON transactions (nuop) WHERE nuop IS NOT NULL;
CREATE INDEX idx_transactions_status ON transactions (status) WHERE status NOT IN ('settled', 'failed');

Health Check

bash
curl http://localhost:4005/health
# {"status": "ok", "database": "connected", "pending_transactions": 12}

Plataforma de Integracao BACEN/SPB