TED Guide
This guide explains how to send and receive TED (Transferência Eletrônica Disponível) through the CorpX API. TED is a BACEN interbank transfer that operates in a specific window and is asynchronous by design — unlike PIX (instant) and internal transfers (same bank).
Overview
TED is an interbank transfer processed by the SPB (Brazilian Payment System), with a send window on business days (06:30–17:00) and same-day settlement when sent within the window.
| Feature | PIX | TED | Internal Transfer |
|---|---|---|---|
| Window | 24/7 | Business days 06:30–17:00 | 24/7 |
| Settlement | Instant (less than 10s) | ~30min after send | Instant |
| Banks | Any (PIX network) | Any (SPB network) | Same bank |
| Cost | Variable | Variable (higher than PIX) | Typically zero |
| Min amount | R$ 0.01 | R$ 0.01 | R$ 0.01 |
| Max amount | Configurable | No BACEN cap | Configurable |
When to use TED instead of PIX?
- Very large amounts above the PIX limit configured for the account
- Legacy systems that still require TED
- Counterparty that only accepts TED (e.g. some public agreements)
- Interbank boletos or corporate payroll in some ERPs
For day-to-day (quick payments, less than R$ 1MM, in/out of business hours), PIX is always preferable — instant, 24/7, typically cheaper.
Settlement bank MT Bank (to receive TED)
When someone wants to send a TED to you, instruct the counterparty to use these details:
| Field | Value |
|---|---|
| Bank | MT Instituição de Pagamentos S.A. |
| Compe code | 681 |
| ISPB | 50871921 |
| Account type | Payment account (inform the counterparty) |
| Branch | (your branch at MT) |
| Account number | (your account number at MT) |
| Holder CPF/CNPJ | (the account holder's document) |
Code 681 is what the counterparty enters in the "Bank" field of their app/internet banking. Don't confuse it with the ISPB (8 digits) — banks ask for the 3-digit Compe code.
When a TED arrives in your account, you receive the ted.in.received webhook (see Webhooks).
Window and timing
TED follows the BACEN window — outside it, the transaction is scheduled for the next business day.
| Window | Behavior |
|---|---|
| Business days, 06:30–17:00 | TED sent within the window settles the same business day (~30min after successful send) |
| Business days, 17:00–17:30 | Direct interbank window — does not apply to clients via PSP/MT (rejected) |
| After 17:30 on a business day | Scheduled for D+1 business day. Status stays PROCESSING on our side until settled |
| Weekend / holiday | Scheduled for the next business day. Defensive polling continues for up to 48h |
Server-side defensive polling
To ensure no TED gets "stuck" even if the settlement bank's webhook fails, the TEDOut.Workflow polls the MT statement every 1 minute for up to 48 hours. If the TED doesn't appear as settled in that period, it's marked FAILED (timeout). You always get the final consistent state via GET /v1/accounts/{accountId}/transfers/ted/{tedId} or via the ted.out.failed webhook.
Costs and limits
- TED OUT (send): fixed fee per operation — see Backoffice → Statement with
operation=FEEfilter (GET /v1/accounts/{accountId}/statement?operation=FEE) - TED IN (receive): receiving fee when applicable
- Min: R$ 0.01
- Max: no BACEN cap; CorpX allows up to the account's operational limit (configurable via Policies)
Exact fees vary by contract — check your commercial agreement.
1. Send a TED
Endpoint: POST /v1/accounts/{accountId}/ted/out
curl -X POST "https://tenant.api.corpx.com/v1/accounts/{accountId}/ted/out" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: tenant-yourcompany" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: ted-001" \
-d '{
"value": 5000.00,
"bankCode": "001",
"branch": "1234",
"account": "56789",
"accountType": "CHECKING",
"taxNumber": "12345678900",
"holderName": "JOAO DA SILVA",
"description": "Supplier payment Invoice 12345",
"identifier": "supplier-acme-2026-05"
}'
Fields
| Field | Type | Required | Description |
|---|---|---|---|
value | number | Yes | Amount in BRL (positive, max 2 decimals) |
bankCode | string | Yes | Destination bank Compe code (3 digits, e.g. 001 Banco do Brasil, 237 Bradesco, 341 Itaú). Also accepts 8-digit ISPB |
branch | string | Yes | Destination branch (digits only) |
account | string | Yes | Destination account (digits only, no final check digit) |
accountType | string | No | CHECKING (default), SAVINGS, PAYMENT, or SALARY |
taxNumber | string | Yes | CPF (11 digits) or CNPJ (14 digits) of the recipient holder |
holderName | string | Yes | Recipient's full legal name |
description | string | No | Free-form message (e.g. invoice number) |
identifier | string | No | Integrator correlation key. Auto-generated if omitted |
Response (202 Accepted)
{
"tedId": "ted-supplier-acme-2026-05",
"workflowId": "ted-out-ted-supplier-acme-2026-05",
"runId": "019e1234-...",
"idempotencyKey": "ted-001",
"identifier": "supplier-acme-2026-05",
"status": "PROCESSING",
"amount": 5000.00,
"destination": {
"bankCode": "001",
"branch": "1234",
"account": "56789",
"accountType": "CHECKING",
"taxNumber": "12345678900",
"holderName": "JOAO DA SILVA"
},
"description": "Supplier payment Invoice 12345",
"info": "TED is asynchronous — final status converges via webhook or defensive polling (48h max)."
}
The tedId is CorpX-unique (ted-{identifier}) and is the key to query status and correlate with webhooks.
2. Query status
Endpoint: GET /v1/accounts/{accountId}/transfers/ted/{tedId}
curl "https://tenant.api.corpx.com/v1/accounts/{accountId}/transfers/ted/ted-supplier-acme-2026-05" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: tenant-yourcompany"
Response (200)
{
"tedId": "ted-supplier-acme-2026-05",
"accountId": "773107de-...",
"status": "COMPLETED",
"amount": 5000.00,
"identifier": "supplier-acme-2026-05",
"description": "Supplier payment Invoice 12345",
"partnerId": "supplier-acme-2026-05",
"createdAt": "2026-05-23T09:00:00Z",
"updatedAt": "2026-05-23T09:32:15Z"
}
States
| Status | Meaning |
|---|---|
PROCESSING | TED accepted by the settlement bank; awaiting BACEN settlement |
COMPLETED | TED settled at the destination bank (terminal) |
FAILED | TED rejected, expired, or 48h timeout (terminal) |
TED Webhooks
The recommended way to track TEDs is to subscribe to webhooks — you're notified in real time without polling.
Available events
| Event | When |
|---|---|
ted.out.requested | Immediately after the POST is accepted (PROCESSING status) |
ted.out.confirmed | Settlement confirmed by the settlement bank (terminal — success) |
ted.out.failed | Settlement rejected/expired or 48h timeout (terminal — failure) |
ted.in.received | TED received in your account (originated by a third party) |
ted.payment | DEPRECATED — alias for ted.out.confirmed. Will be removed in v3.0 |
Payload ted.out.requested
{
"eventType": "ted.out.requested",
"eventId": "ted-supplier-acme-2026-05-requested",
"data": {
"tedId": "ted-supplier-acme-2026-05",
"tenantId": "tenant-yourcompany",
"accountId": "773107de-...",
"partnerId": "",
"amount": 5000.00,
"destination": {
"bankCode": "001",
"branch": "1234",
"account": "56789",
"accountType": "CHECKING",
"taxNumber": "12345678900",
"holderName": "JOAO DA SILVA"
},
"description": "Supplier payment Invoice 12345"
}
}
Payload ted.out.confirmed
{
"eventType": "ted.out.confirmed",
"eventId": "ted-supplier-acme-2026-05-confirmed",
"data": {
"tedId": "ted-supplier-acme-2026-05",
"tenantId": "tenant-yourcompany",
"accountId": "773107de-...",
"partnerId": "supplier-acme-2026-05",
"amount": 5000.00,
"destination": { ... },
"description": "Supplier payment Invoice 12345"
}
}
Payload ted.out.failed
{
"eventType": "ted.out.failed",
"eventId": "ted-supplier-acme-2026-05-failed",
"data": {
"tedId": "ted-supplier-acme-2026-05",
"tenantId": "tenant-yourcompany",
"accountId": "773107de-...",
"partnerId": "supplier-acme-2026-05",
"amount": 5000.00,
"destination": { ... },
"description": "Supplier payment Invoice 12345",
"errorReason": "invalid_bank_code",
"error": "invalid_bank_code"
}
}
Payload ted.in.received
{
"eventType": "ted.in.received",
"eventId": "ted-in-abc123def",
"data": {
"transactionId": "abc123def",
"identifier": "TED-MT-9876",
"partnerTxId": "abc123def",
"accountId": "773107de-...",
"tenantId": "tenant-yourcompany",
"amount": 1200.00,
"description": "Payment received",
"receivedAt": "2026-05-23T14:15:22Z",
"payer": {
"name": "EMPRESA XYZ LTDA",
"document": "98765432000110",
"bankCode": "237",
"bankIspb": "60746948",
"branch": "0001",
"account": "123456",
"accountNumber": "123456"
}
}
}
Dedup
Every webhook has a unique deterministic eventId. Use the eventId in your store to dedupe in case of re-delivery (happens on retries of our dispatcher when your endpoint takes long to respond 2xx).
Common errors
| HTTP code | errorCode | When |
|---|---|---|
| 400 | invalid_bank_code | bankCode is not a valid Compe (3 digits) or ISPB (8 digits) |
| 400 | invalid_tax_number | taxNumber has neither 11 (CPF) nor 14 (CNPJ) digits |
| 400 | invalid_account_type | accountType outside CHECKING|SAVINGS|PAYMENT|SALARY |
| 400 | invalid_identifier | identifier with non-ASCII chars or invalid size |
| 400 | missing_fields | value, branch, account, holderName, or taxNumber missing |
| 403 | forbidden | User has no role on the account's tenant |
| 503 | temporal_unavailable | Internal orchestrator unavailable (rare; wait and retry) |
| 503 | partner_unavailable | Settlement bank unavailable |
| 404 | not_found | tedId not found in the GET status call |
Workflow errors (final FAILED status)
errorReason | When |
|---|---|
insufficient_funds | Insufficient balance on source account |
invalid_bank_code | Destination bank does not exist in the SPB |
outside_banking_hours | TED attempt outside the settlement bank's accepted window |
bank_unreachable | Transient error at destination bank |
limit_exceeded | Operational limit reached |
timeout aguardando confirmação do parceiro (>48h) | Defensive polling expired without settlement |
Reconciliation
CorpX runs defensive polling every minute for up to 48h after sending a TED, even when the settlement bank's webhook arrives normally. This guarantees that internal state and bank's real state are always aligned.
To reconcile on your side:
- Real time: subscribe to webhooks
ted.out.{requested,confirmed,failed}andted.in.received - Point lookup:
GET /v1/accounts/{accountId}/transfers/ted/{tedId} - Statement:
GET /v1/accounts/{accountId}/statement(TEDs appear withoperation=TED) - Detailed timeline:
GET /v1/accounts/{accountId}/transactions/timeline?tedId={tedId}
ted.payment deprecation
The ted.payment event (v1 legacy catalog) is kept as an alias for ted.out.confirmed for compatibility. Both are dispatched together on the same terminal.
- New integrators: subscribe to
ted.out.confirmed(more descriptive, aligned withboleto.paid,pix.out.completed) - Legacy integrators: can keep
ted.paymentuntil v3.0 (date TBA) - Migration: unsubscribe
ted.payment+ subscribeted.out.confirmed— payloads are identical