Skip to main content
TED IN allows your institution to receive transfers originated at other banks. The plugin automatically detects incoming transfers, validates the recipient, and credits the amount to the corresponding account.

How it works


Receiving a TED is an automatic process detected by the polling worker every 30 seconds.
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  Origin bank    │────▶│    JD SPB       │────▶│   TED Plugin    │
│  sends TED      │     │  (polling 30s)  │     │   processes     │
└─────────────────┘     └─────────────────┘     └────────┬────────┘

                        ┌─────────────────┐              │
                        │    Webhook      │◀─────────────┤
                        │   (optional)    │              │
                        └─────────────────┘              │

                                                ┌─────────────────┐
                                                │  Recipient      │
                                                │  account        │
                                                │  credited       │
                                                └─────────────────┘

Detection flow

  1. Every 30 seconds, the worker queries JD’s RecebeMensagem service
  2. When finding a new STR0008R2 message that doesn’t correspond to a transfer sent by the system, it’s identified as an incoming TED
  3. The raw XML message is immediately saved in the JDIncomingMessage table (at-most-once guarantee)

Processing

  1. Creates a new Transfer entity with type TED_IN and status RECEIVED
  2. Validates if the recipient’s account exists in CRM
  3. If the recipient is valid, calculates the cashin fee (if enabled)
  4. Credits the account in Midaz through CreateCashinTransaction
  5. Updates status to COMPLETED
  6. Sends webhook notification

Timeline


T+0:     External bank sends TED

T+30s:   Polling detects message (RecebeMensagem)
         ├─ Persist in JDIncomingMessage
         └─ Status: RECEIVED

T+32s:   Validate recipient in CRM
         └─ Status: PROCESSING

T+35s:   Credit account (Midaz CreateCashinTransaction)
         └─ Status: COMPLETED

T+36s:   Webhook notification sent
SLA: < 1 minute detection → < 5 seconds processing

TED IN states


RECEIVED → PROCESSING → COMPLETED
                      → REJECTED (recipient not found)
StateDescription
RECEIVEDTransfer detected, awaiting processing
PROCESSINGValidating recipient and preparing credit
COMPLETEDAmount credited to recipient’s account
REJECTEDRecipient not found or invalid account

Query received transfers


Endpoint: GET /v1/transfers?type=TED_IN

Query parameters

ParameterTypeDescription
typeStringFilter by type (TED_IN)
statusStringFilter by status (COMPLETED, REJECTED)
startDateISO8601Period start date
endDateISO8601Period end date
pageIntegerPage number (default: 1)
pageSizeIntegerItems per page (default: 20, max: 100)

Response

{
  "transfers": [
    {
      "transferId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
      "type": "TED_IN",
      "status": "COMPLETED",
      "amount": 5000.00,
      "feeAmount": 0.00,
      "createdAt": "2026-01-21T10:15:00-03:00"
    }
  ],
  "pagination": {
    "page": 1,
    "pageSize": 20,
    "totalItems": 150,
    "totalPages": 8
  }
}

Transfer details


Endpoint: GET /v1/transfers/{transferId}

Response

{
  "transferId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
  "type": "TED_IN",
  "status": "COMPLETED",
  "sender": {
    "ispb": "60746948",
    "branch": "1234",
    "account": "567890",
    "name": "Carlos Oliveira",
    "taxId": "98765432100"
  },
  "recipient": {
    "accountId": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Empresa ABC Ltda",
    "taxId": "12345678000199"
  },
  "amount": 5000.00,
  "feeAmount": 0.00,
  "netAmount": 5000.00,
  "controlNumber": "JD20260121000042",
  "createdAt": "2026-01-21T10:15:00-03:00",
  "completedAt": "2026-01-21T10:15:05-03:00",
  "statusHistory": [
    {"status": "RECEIVED", "timestamp": "2026-01-21T10:15:00-03:00"},
    {"status": "PROCESSING", "timestamp": "2026-01-21T10:15:02-03:00"},
    {"status": "COMPLETED", "timestamp": "2026-01-21T10:15:05-03:00"}
  ]
}

Receiving fee (cashin)


The plugin can charge a fee on received transfers. Configuration is done per organization. When enabled, the fee is calculated via plugin-fees and deducted from the credited amount:
netAmount = amount - feeAmount

Example with fee

{
  "amount": 1000.00,
  "feeAmount": 2.50,
  "netAmount": 997.50
}

Recipient validation


The plugin validates the recipient using the document (CPF/CNPJ) provided in the STR0008R2 message:
  1. Queries CRM by document
  2. If found, identifies the corresponding account
  3. If not found, initiates chargeback

Rejected transfer

When the recipient is not found, a chargeback is automatically sent to the origin bank:
{
  "transferId": "d4e5f6a7-b8c9-0123-defg-456789012345",
  "type": "TED_IN",
  "status": "REJECTED",
  "amount": 3000.00,
  "sender": {
    "ispb": "60701190",
    "branch": "0001",
    "account": "123456",
    "name": "Ana Costa"
  },
  "rejectionReason": "Recipient not found: document 11122233344 not registered",
  "createdAt": "2026-01-21T11:00:00-03:00",
  "rejectedAt": "2026-01-21T11:00:03-03:00"
}

Error handling


Critical errors and their actions:
  • Recipient not found: Send chargeback to JD (STR0010R2), status=REJECTED
  • Midaz unavailable: Retry 3x → DLQ (manual intervention)
  • Duplicate: Unique constraint sequenceNumber prevents duplicate credits

Receiving webhook


Configure a webhook to be notified in real-time about received transfers.

Event: transfer.incoming

{
  "event": "transfer.incoming",
  "timestamp": "2026-01-21T10:15:05-03:00",
  "data": {
    "transferId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
    "type": "TED_IN",
    "status": "COMPLETED",
    "amount": 5000.00,
    "feeAmount": 0.00,
    "netAmount": 5000.00,
    "sender": {
      "ispb": "60746948",
      "name": "Carlos Oliveira"
    },
    "recipient": {
      "accountId": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Empresa ABC Ltda"
    }
  }
}
See more details in Webhooks.

Reconciliation


For accounting reconciliation, use the following fields:
FieldUsage
controlNumberJD SPB control number (unique per transfer)
transferIdLerian internal identifier
createdAtDetection timestamp
completedAtCredit timestamp
Transfer history is kept for 5 years, as per BACEN regulatory requirements.

Processing guarantees


The plugin implements guarantees to avoid duplicates and losses:
GuaranteeImplementation
At-most-onceMessages persisted BEFORE processing
IdempotencySame sequenceNumber is not processed twice
RetryTransient failures retried with exponential backoff
DLQPermanent failures go to dead-letter queue
CRITICAL: The message is persisted in the JDIncomingMessage table BEFORE processing, ensuring no transfer is lost in case of failure.