> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Best practices for TED

> Apply proven patterns when integrating TED — show fees before confirmation, handle settlement windows, and reduce customer complaints.

This guide covers the key decisions your team needs to make when integrating TED, and the best practices to ensure a reliable, compliant experience for your customers.

## Product decisions

***

These are choices your product team makes in the customer-facing experience. They directly affect customer satisfaction and support volume.

### Show the fee before the customer confirms

The two-step flow (`initiate` → `process`) is designed for this: your system receives the fee amount before any funds move. Use that window to show a clear confirmation screen:

```
Confirm transfer

Recipient: Maria Silva — Bradesco (237)

Amount:   R$ 1,000.00
Fee:          R$ 1.50
─────────────────────
Total:    R$ 1,001.50

[ Cancel ]        [ Confirm ]
```

This reduces complaints and cancellations from customers surprised by fees after the fact.

### Handle operating hours gracefully

TED OUT is available Monday–Friday, 06:30–17:00 (Brasília time). When a customer tries to initiate outside those hours, don't just surface an error — tell them when they can try again:

```
TED transfers are available Monday to Friday, 06:30 to 17:00.
Next available time: Monday at 06:30.
```

To avoid unnecessary round trips, validate operating hours on the client side before calling the API.

There's no need to maintain your own holiday list — the plugin already blocks weekends and BACEN holidays automatically. The calendar ships with a built-in seed for 2026–2028. The daily refresh job runs by default and re-applies the seed; live fetching from ANBIMA is wired in the codebase but not yet implemented.

If a transfer is rejected due to a holiday, surface that reason to the customer. Instead of replicating the calendar on the client, rely on the plugin as the source of truth to avoid inconsistencies over time.

### Communicate transfer limits before customers hit them

Show the customer's remaining daily limit in your transfer UI — before they attempt a transfer that will be rejected. For example:

```
Daily limit: R$ 50,000.00
Used today:  R$ 45,000.00
Available:    R$ 5,000.00
```

### Show confirmation receipts after completion

After a TED OUT or P2P transfer completes, display — or offer to download — a receipt with:

* Transfer date and time
* Sender and recipient details
* Amount, fee, and total
* `confirmationNumber` (your internal reference)
* `controlNumber` (JD SPB reference, for TED OUT only)

Providing this information proactively reduces "did my transfer go through?" support contacts.

### Keep customers informed in real time

Use webhooks to push transfer status updates to your UI as they happen. Don't make customers refresh or wonder if their transfer went through. See [TED webhooks](/en/midaz/plugins/ted/ted-webhooks) for setup.

## Compliance decisions

***

These are requirements that apply to your integration regardless of your product choices.

### LGPD and personal data

Transfer records contain personal data — customer names, CPF/CNPJ, and bank details. Ensure your privacy policy explicitly covers financial transaction data. Avoid logging CPF/CNPJ in plain text; mask it in interfaces as `***.***.***-00`.

A dedicated anonymization endpoint for LGPD right-to-erasure requests is planned for a future release. Until then, coordinate anonymization requests with your database administration team.

### Data retention

<Warning>
  Transfer data must be retained for **5 years** per BACEN Resolution 4.753/2019. This is not configurable and cannot be shortened.
</Warning>

| Data type           | Retention period                   |
| ------------------- | ---------------------------------- |
| Transaction records | 5 years (BACEN requirement)        |
| Application logs    | 90 days                            |
| Audit data          | 5 years (anonymized after 2 years) |

### Audit trail and reconciliation

Every transfer generates two reference numbers you must store:

| Field                | What it is                      | When to use                             |
| -------------------- | ------------------------------- | --------------------------------------- |
| `transferId`         | Internal Lerian identifier      | API lookups, support cases              |
| `confirmationNumber` | User-readable reference         | Receipts, customer communication        |
| `controlNumber`      | JD SPB reference (TED OUT only) | BACEN audit trail, regulatory reporting |

Keep both the `transferId` and `confirmationNumber` in your own records for reconciliation. For TED OUT, also store the `controlNumber`.

### Operating hours

BACEN mandates that TED operates Monday–Friday, 06:30–17:00 (Brasília time, UTC-3). This window is fixed and not configurable. Build your UX around it — see [Handle operating hours gracefully](#handle-operating-hours-gracefully) above.

<Note>
  P2P transfers are not subject to operating hour restrictions and work 24/7.
</Note>

## Integration checklist

***

Before going live, verify the following:

* [ ] **Idempotency keys on all write operations** — Send a UUID v4 `X-Idempotency` header on every call to `initiate`, `process`, and `cancel`. This prevents duplicate transfers from retries or double-clicks.
* [ ] **Webhook endpoint live before launch** — Your webhook endpoint must be deployed and reachable before you go live. Transfer events start firing immediately on the first real transaction.
* [ ] **24-hour expiry handled** — An initiated transfer expires if not confirmed within 24 hours. If your flow allows a customer to start a transfer and return later, handle the expiry case explicitly.
* [ ] **Exponential backoff on 5xx errors** — Implement retry with backoff (e.g., 2s, 4s, 8s) when the response is `503` or `500`. JD SPB unavailability surfaces as `503` with a raw JD vendor code (`TRANSPORT`, `ACE95`, …); Midaz ledger unavailability surfaces as `BTF-2000`. Do not retry immediately in a loop.
* [ ] **Operating hours validated client-side** — Check hours in the UI before calling the API. Reduces unnecessary failed API calls and gives a better customer experience.
* [ ] **Both `transferId` and `confirmationNumber` stored** — Required for reconciliation and audit. For TED OUT, also store `controlNumber`.

## Error handling

***

Use these error scenarios to map API errors to customer-friendly messages and define the correct recovery path.

| Scenario                | Customer-facing message                                                                          | Error code                            | Recoverable | Action                                 |
| ----------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------- | ----------- | -------------------------------------- |
| Outside operating hours | "TED transfers are available Monday–Friday, 06:30–17:00. Next available time: \[date/time]."     | `BTF-0010`                            | Yes         | Wait for next window                   |
| Insufficient balance    | "Your account doesn't have enough balance for this transfer."                                    | `BTF-0001`                            | Yes         | Customer adds funds or reduces amount  |
| Daily limit reached     | "You've reached your daily transfer limit of R\$ \[X]. Limit resets at midnight."                | `BTF-0011`                            | Yes         | Wait for reset                         |
| Invalid recipient       | "Destination account not found. Please check the account details and try again."                 | `BTF-0500`                            | Yes         | Customer corrects details              |
| Service unavailable     | "Transfer service is temporarily unavailable. Please try again in a few minutes."                | `TRANSPORT` (HTTP `503`, raw JD code) | Yes         | Retry with backoff                     |
| Duplicate transfer      | "An identical transfer was sent recently. If this was intentional, wait a moment and try again." | `BTF-0012`                            | Conditional | Wait for deduplication window to clear |

For the complete list of error codes and their meanings, see the [TED error list](/en/reference/midaz/plugins/ted/ted-error-list).
