Skip to main content
The TED plugin connects your operation to SPB through PSTI JD Consultores, offering a unified API to manage all bank transfer modalities.

Architectural pattern


The plugin architecture adopts the Hexagonal (Ports and Adapters) pattern combined with CQRS (Command Query Responsibility Segregation) and a Multi-Tenant design. Hexagonal architecture isolates business logic from infrastructure details such as APIs, databases, and external service clients. Communication between the core and the outside world occurs through ports (interfaces) and adapters (implementations). CQRS separates write operations (Commands) from read operations (Queries), allowing each side to be optimized independently.
┌─────────────────────────────────────────────────────────────────┐
│                        HTTP REST API                            │
│  POST /v1/transfers/initiate  |  POST /v1/transfers/process     │
│  GET  /v1/transfers/{id}      |  GET  /v1/transfers             │
│  POST /v1/transfers/{id}/cancel                                 │
└────────────────────────┬────────────────────────────────────────┘

         ┌───────────────┴───────────────┐
         │   Transfer Management         │
         │   (Commands + Queries)        │
         └───────────┬───────────────────┘

     ┌───────────────┼───────────────┬──────────────┐
     │               │               │              │
┌────▼────┐    ┌────▼────┐    ┌────▼────┐    ┌───▼────┐
│ Midaz   │    │   JD    │    │  CRM    │    │ Fees   │
│ Ledger  │    │  SPB    │    │(Midaz)  │    │(Plugin)│
│ (SDK)   │    │ (SOAP)  │    │ (HTTP)  │    │ (HTTP) │
└─────────┘    └─────────┘    └─────────┘    └────────┘

Main components


ComponentResponsibilityTechnology
Transfer ManagementOrchestrates TED OUT, TED IN, and P2P flowsGo, Hexagonal + CQRS
Validation and ComplianceApplies schedule rules, limits, and duplicate preventionRedis (atomic operations)
JD SPB AdapterCommunication with JD Consultores system via SOAP/XMLgowsdl, encoding/xml, crypto/rsa
Midaz Ledger AdapterBalance operations: validation, provisioning, and settlementmidaz-sdk-golang/v2 (gRPC/HTTP)
CRM AdapterValidates accounts and retrieves ledger informationHTTP REST client
Fees AdapterCalculates transfer feesHTTP REST client
Polling WorkerDetects new incoming transfers (TED IN)Goroutine (30s interval)
Webhook PublisherNotifies external systems about status changesHTTP POST with retries and DLQ

Two-step flow


The plugin implements a two-step flow for outgoing transfers, allowing the user to view the fee before confirming:

Step 1: Initiate

POST /v1/transfers/initiate
Calculates the fee and creates a transfer intent valid for 24 hours. What happens:
  • Validates the source account in CRM
  • Verifies operating hours
  • Detects duplicates (60-second window)
  • Calculates fee via plugin-fees
  • Returns initiationId and calculated values

Step 2: Process

POST /v1/transfers/process
Confirms the transfer and starts processing. What happens:
  • Validates usage limits (daily/monthly)
  • Verifies available balance
  • Reserves funds in Midaz (hold)
  • Sends message to SPB (TED OUT) or executes internal transfer (P2P)
  • Returns transferId and confirmation number

Transfer states


Each transfer goes through well-defined states:
CREATED → PENDING → PROCESSING → COMPLETED
                               → REJECTED (4xx from JD)
                               → FAILED (5xx/timeout)
        → CANCELLED (user cancels before processing)
StateDescription
CREATEDTransfer created, awaiting processing
PENDINGFunds reserved, awaiting SPB submission
PROCESSINGMessage sent to SPB, awaiting confirmation
COMPLETEDTransfer completed
REJECTEDRejected by SPB or recipient not found
FAILEDTechnical failure (timeout, unavailability)
CANCELLEDCancelled by user before processing
RECEIVEDTED IN detected, awaiting credit

Duplicate detection


The plugin detects duplicate transfers by comparing:
  • Source account
  • Recipient data (ISPB, branch, account)
  • Amount
If an identical transfer is sent within the configurable window (default: 60 seconds), the plugin returns error BTF-0012. Mechanism:
  • Idempotency key: SHA256(organizationId + senderAccountId + recipient + amount)
  • Storage: Redis with configurable TTL
  • Action: Reject duplicate requests with code 409 Conflict

Fees


The plugin integrates with plugin-fees for fee calculation in two directions:
OperationFee type
TED OUTCashout (debit + send)
TED INCashin (receive)
P2PConfigurable per organization
The fee is calculated at the initiation step and displayed to the user before confirmation.

Behavior in case of unavailability

ConfigurationBehavior
Fail-open (default)Continues without fee if plugin-fees unavailable
Fail-closedRejects operation if fee cannot be calculated

Multi-tenant support


The plugin was designed to operate in different deployment models, ensuring data isolation and configuration per client (tenant).

Tenant identification

The tenantId is extracted from a JWT claim and validated against the HTTP header X-Organization-Id. This dual validation ensures the tenant context is correctly propagated throughout the execution stack.

Data isolation

All database queries are filtered by organization_id, ensuring a tenant never accesses another’s data. Redis cache also uses per-tenant prefixes (tenant:{tenantId}:{key}), preventing collisions and information leakage.

Deployment models

ModelDescriptionUse caseOverhead
SaaS Multi-TenantMultiple clients sharing the same infrastructureLerian clients in managed environment~5-10ms
BYOC Single-TenantSingle client in dedicated infrastructureLarge clients with specific requirements<1ms
BYOC Multi-TenantMain client managing subsidiariesClients operating as a platform~2-5ms
Flexibility: A single codebase supports all three models through configuration, without the need for separate branches.

Per-organization configuration

Each organization has independent configuration:
  • JD SPB credentials (encrypted)
  • Own ISPB
  • Webhook URL and HMAC secret
  • Fee settings
  • Duplicate detection window
  • Data isolation mode (DATABASE, SCHEMA, SINGLE)

Observability


The plugin exposes metrics, logs, and traces for complete monitoring.

Metrics (Prometheus)

transfer_initiated_total        # Counter of initiated transfers
transfer_completed_total        # Counter of completed transfers
transfer_failed_total           # Counter of failures
transfer_duration_seconds       # Duration histogram
jd_api_latency_seconds          # JD API call latency

Structured logs

All logs follow JSON format with contextual fields:
  • tenantId: tenant identification
  • transferId: transfer identification
  • correlationId: correlation between operations
Sensitive data (CPF/CNPJ) is hashed with SHA-256.

Traces (OpenTelemetry)

Context propagation between services (Midaz, CRM, Fees, JD) for distributed tracing.

Next steps