> ## 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.

# TED Lerian API overview

> Concepts, a four-step integration, statuses, permissions, conventions and error families of the TED Lerian API.

TED Lerian is the interface over Lerian SPB, Lerian's own messaging connector to the STR. Your institution uses its API to send TEDs, make internal transfers, track incoming TEDs, and operate returns, queues and policy, all on top of the institution's Midaz ledger. For a TED, money leaves the account only when the STR settles. Every operation with an effect is idempotent, so you can resend after a timeout.

## Concepts

***

| Term | Meaning |
| - | - |
| TED | A transfer to another institution, settled in real time by the STR (Central Bank of Brazil). It is asynchronous: the send response never includes the settlement. |
| Internal transfer | The recipient is in your own institution. Same operation, `POST /v1/transfers`, settled immediately in the ledger (`type=INTERNAL`). |
| Source account | The debited account, sent in the `X-Account-Id` header (UUID), never in the body. It must belong to your organization. |
| ISPB / COMPE | Identifiers of the destination bank: ISPB (8 digits) or COMPE code (3 digits, for example `001`). Send one of them in `recipient`. `GET /v1/participants` converts one into the other. |
| Purpose code (`purposeCode`) | 5-digit code. TED Lerian refuses a code that is unknown, or not in force on the date of the request, in the BACEN FinlddCli Domain Dictionary. `99999` (other) requires `description`. |
| Hold | Amount plus fee blocked in the source account until settlement (`SETTLED`). Released on `REJECTED` and `CANCELLED`. |
| Operating window | The hours when the STR accepts TEDs, narrowed by the institution's cut-off and by the holiday calendar. `GET /v1/policy/window` tells you if it is open. |
| `nuop` | Unique operation number in the SPB (23 digits). It appears when the STR accepts the TED and identifies the operation in receipts and events. |
| Incoming TED | A TED that another institution sends to one of your customers. TED Lerian credits it, returns it, or opens a manual review, within the 60-minute regulatory deadline. |
| Return | Full return of an incoming TED to the sender, with an official reason (`returnCode`, CodDevTransf). |

## Integrate in four steps

***

**1. Configure the institution**

Do this with the `editor` role. Set the usage limits with `PUT /v1/policy/limits`; they are required before the first TED. For incoming TEDs, bind each ISPB with `PUT /v1/policy/ispb-bindings` to the organization and ledger where this installation credits incoming TEDs. Any other organization or ledger gets `422 TED-0002`. With the ledger and CRM integrations on, a binding also needs the organization in Midaz, the `@external/BRL` account on the ledger, and your institution's holder (the CNPJ of the organization) with an account in the CRM. A missing item gets `422 TED-0002`, and the message names it. Load the national holiday calendar of each year with `PUT /v1/policy/holidays`, before the year starts. To charge fees, create Midaz fee packages that select on the [TED Lerian posting labels](https://docs.lerian.studio/en/interfaces/ted-lerian/ted-lerian-business-rules.md#fees). Optionally, set a cut-off with `PUT /v1/policy/window`. Without a cut-off, the window follows the official STR schedule.

**2. Send the TED**

Send `X-Account-Id` (the debited account) and `X-Idempotency` (a new key for each payment). To show a fee estimate before you confirm, call `POST /v1/transfers/fee-quotes` with the same fields.

```bash theme={null}
curl -X POST "$TED_URL/v1/transfers" \
  -H "Authorization: Bearer $TED_BEARER_TOKEN" \
  -H "X-Account-Id: 0a2f4c6e-8b1d-4e3f-9a5b-7c9d1e3f5a7b" \
  -H "X-Idempotency: 9b4f1a6e-3c2d-4e5f-8a7b-6c5d4e3f2a1b" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "1500.00",
    "purposeCode": "00010",
    "description": "Supplier payment",
    "clientReference": "PED-2026-000123",
    "recipient": {
      "bankCode": "001",
      "agency": "1234",
      "bankAccount": "0001234567",
      "bankAccountType": "CACC",
      "name": "Maria da Silva",
      "document": "12345678909"
    }
  }'
```

The send returns `201` with the status the TED reached in this call, usually `SUBMITTED`.

```json theme={null}
{
  "transferId": "6f1c2b3a-4d5e-4f60-8a9b-0c1d2e3f4a5b",
  "type": "TED",
  "status": "SUBMITTED",
  "amount": "1500.00",
  "feeAmount": "3.25",
  "totalAmount": "1503.25",
  "nuop": "87654321202610220000123",
  "createdAt": "2026-10-22T13:05:12Z"
}
```

**3. Track it until settlement**

Query `GET /v1/transfers/{transferId}` until `status` reaches `SETTLED`, `REJECTED` or `CANCELLED`, or subscribe to the `transfer.*` events. On `REJECTED`, `rejection.source` and `rejection.code` tell you who refused it and why.

```bash theme={null}
curl "$TED_URL/v1/transfers/6f1c2b3a-4d5e-4f60-8a9b-0c1d2e3f4a5b" \
  -H "Authorization: Bearer $TED_BEARER_TOKEN"
```

**4. Handle incoming TEDs**

List them with `GET /v1/incoming-transfers`. The credit to the customer is automatic. Only `status=MANUAL_REVIEW` requires an operator decision (`POST /v1/incoming-transfers/{incomingTransferId}/resolve-review`), and `POST /v1/incoming-transfers/{incomingTransferId}/return` returns a TED that is already credited.

## Statuses

***

A sent TED goes through these statuses. The final statuses are `SETTLED`, `REJECTED` and `CANCELLED`.

| Status | Meaning | What to do |
| - | - | - |
| `CREATED` → `RESERVED` | Recorded; amount plus fee on hold | Wait (can be cancelled) |
| `SUBMITTED` | Accepted by the rail. The TED waits for the STR decision, or first for an approval at Lerian SPB when Lerian SPB requires one. | Wait for settlement; cannot be cancelled |
| `PENDING_STR` | The STR keeps the entry pending. If Lerian SPB does not know the TED at the daily close, it becomes `AWAITING_RECONCILIATION` and the hold stays | Wait; you can request cancellation |
| `SETTLED` | Settled; debit confirmed | Nothing. A later return appears in `returned` |
| `REJECTED` | Refused; hold released | See `rejection` |
| `CANCELLED` | Cancelled before sending, or cancellation confirmed by the STR | Nothing |
| `AWAITING_RECONCILIATION` | Outcome not confirmed; automatic reconciliation queries the rail (by default, starting at 15 minutes, up to 8 attempts) | Wait; do not resend |
| `EXHAUSTED` | Reconciliation ran out of attempts with no evidence | An operator resolves it with `POST /v1/transfers/{transferId}/unblock` |

An incoming TED goes from `RECEIVED` (decision in progress) to `CREDITED` (credited to the customer), `RECORDED` (the institution's own account, final), `RETURN_REQUESTED` (TED Lerian cannot credit it) or `MANUAL_REVIEW` (waits for an operator; see `reviewReason`). It goes from `RETURN_REQUESTED` to `RETURNED` when it is returned. `reviewReason` appears only while the status is `MANUAL_REVIEW`; the timeline keeps the earlier reasons. A failed operator reversal puts the TED in `MANUAL_REVIEW`. `LEDGER_REVERT_REFUSED` means the ledger refused it and the credit stays. `LEDGER_REVERT_INDETERMINATE` means the outcome is unknown and the credit may be reversed. `slaDeadlineAt` is the 60-minute regulatory deadline from interbank settlement.

## Authentication and permissions

***

Every call, except the public health probes, sends `Authorization: Bearer <token>` issued by Access Manager. The default roles are `editor` (every operation), `operator` (every operation except the policy and ISPB binding writes) and `viewer` (reads, except the reconciliation reads).

| Operations | Permission |
| - | - |
| `POST /v1/transfers`, `POST /v1/transfers/fee-quotes` | `transfers:create` |
| `GET /v1/transfers` and its sub-resources | `transfers:read` |
| `POST /v1/transfers/{transferId}/cancel` · `POST /v1/transfers/{transferId}/unblock` | `transfers:cancel` · `transfers:unblock` |
| `GET /v1/incoming-transfers` and its sub-resources | `incoming-transfers:read` |
| `POST /v1/incoming-transfers/{incomingTransferId}/return` · `POST /v1/incoming-transfers/{incomingTransferId}/resolve-review` | `incoming-transfers:return` · `incoming-transfers:resolve-review` |
| `GET /v1/reconciliation/*` · `POST /v1/reconciliation/reviews/{reviewId}/resolve`, `POST /v1/reconciliation/held-returns/{heldReturnId}/close` · `POST /v1/reconciliation/runs` | `reconciliation:read` · `reconciliation:resolve` · `reconciliation:create` |
| `GET /v1/operations/*` | `dashboard:read` |
| `GET` and `PUT` on `/v1/policy/window` and `/v1/policy/limits`, `PUT /v1/policy/holidays` | `policy-config:read` / `policy-config:write` |
| `GET` and `PUT` on `/v1/policy/ispb-bindings` | `policy-ispb-bindings:read` / `policy-ispb-bindings:write` |
| `GET /v1/participants` | `participants:read` |

Without the permission, or with a product license that is not valid for the organization: `403` `TED-0071`. Missing or invalid token: `401` `TED-0070`.

## Conventions

***

* **Tenant.** Never from the path, query or body.
* **Amounts.** Decimal strings in BRL with two decimal places (`"1500.00"`), never JSON numbers.
* **Dates.** RFC 3339 in UTC (`2026-10-22T13:05:12Z`); days as `YYYY-MM-DD`. The operating window uses the institution's time zone (`America/Sao_Paulo`).
* **Idempotency.** Every operation with an effect requires `X-Idempotency` (1 to 128 ASCII characters; use a UUID). The same key with the same body returns the original response with `X-Idempotency-Replayed: true` and no new effect. A different body returns `422` `TED-0012`. If the first request is still processing, you get `409` `TED-0013` (retry after `Retry-After`). The replay lasts `X-TTL` seconds (default 300). On `POST /v1/transfers`, the same key with the same request also replays after `X-TTL`: the answer is `201` with `X-Idempotency-Replayed: true` and the transfer in its current state. A new key on a return or a review decision that is already applied returns `409` `TED-0060`.
* **Duplicate protection.** `POST /v1/transfers` can refuse with `409` `TED-0014` a materially identical request with a new key, sent shortly after another one. Query the existing transfer. To retry a request, send the same key.
* **Pagination.** Lists return `items`, `limit`, `next_cursor` and `prev_cursor`. Ask for up to `limit=100` (default 20) and follow `next_cursor` until it is `null`. The cursor is opaque.
* **Correlation.** Send `X-Request-Id` (UUID) or receive a generated one. It comes back in every response and identifies the call for support.
* **Events.** Each transition is published as a CloudEvent with `ce-type` `studio.lerian.br-ted.<resource>.<event>`: `transfer.*`, `incoming_transfer.*` and `incoming_return.*`. Delivery is at least once; deduplicate by `ce-id`.
* **Environments.** The base URL is per installation (BYOC or Lerian Cloud), and Lerian provides it.

## Errors

***

Every error is `application/problem+json` (RFC 9457) with a stable `code`, and `type` ends with that code. Handle errors by `code`. `errors` lists the invalid fields of a `422`. Malformed JSON gets `400` `TED-0001`, and a field or parameter outside the declared schema gets `422` `TED-0002`.

A `503` means the request did not take effect: retry later with the same `X-Idempotency`. These are the exceptions:

* `TED-1000`: the ledger did not confirm the result, and the operation can already be in the ledger. Read the status of the resource before you act again.
* `TED-0080` on a send: the transfer can already exist. Look for it with `GET /v1/transfers` before you send it again.
* `TED-1010` on a cancellation: the answer of the STR connector is unknown, and the cancellation request stays recorded. Retry with the same `X-Idempotency` and the same `reason`.
* `TED-1010` on a return of an incoming TED: the answer of the STR is unknown. Any credit is already reversed. The return stays requested until reconciliation or manual review. Read the status of the TED before you act again.
* `TED-1012` on a cancellation: the rail of your institution does not cancel a pending entry. A retry gets the same answer, and the TED follows its STR outcome.
* `TED-0022` for a date whose year has no holiday calendar: load the year with `PUT /v1/policy/holidays`. A retry alone does not help.

A rate-limited call returns `429` with `Retry-After`: handle it by status and wait that long before you retry.

| Family | Codes | When |
| - | - | - |
| Request | `TED-0001` (400), `TED-0002` to `TED-0007` (422) | Malformed JSON; invalid field, purpose code, bank or document (check digits included) |
| Headers and idempotency | `TED-0008` (400), `TED-0009` (403), `TED-0011` (400), `TED-0012` (422), `TED-0013`/`TED-0014` (409) | `X-Account-Id` missing or from another organization; `X-Idempotency` missing, reused or still processing; duplicate request |
| Policy | `TED-0020`/`TED-0021`/`TED-0030` (422), `TED-0022`/`TED-0040` (503) | Outside the window; non-business day; limit; window undetermined or holiday year not loaded; fee estimate unavailable |
| Status | `TED-0060`/`TED-0061`/`TED-0062`/`TED-0067` (409), `TED-0063` to `TED-0066` (422) | Action not compatible with the status; cannot be cancelled; cannot be returned; held return still carried by a transfer; invalid return or evidence |
| Access | `TED-0070` (401), `TED-0071` (403) | Token; permission or license |
| Configuration | `TED-0080` (503), `TED-0081` (422) | Institution missing required configuration, or a fee package that takes a fee from the amount sent; cut-off later than the official close |
| Dependencies | `TED-1000`/`TED-1010`/`TED-1012`/`TED-1020` (503), `TED-1001`/`TED-1011`/`TED-1021` (422) | Ledger, STR connector or registry unavailable or refusing the data |
| Internal | `TED-9000` (500) | Unexpected failure: contact support with the `X-Request-Id` |
| Generic | `TED-9002` (503), `TED-9003` (413), `TED-9004` (other 4xx, such as 405 and 415) | A refusal with no specific code, identified by the status. For example, `TED-9002` when the audit trail cannot record a policy change |

On a send, `TED-0031`, `TED-1001`, `TED-1010`, `TED-1011` and `TED-1013` never arrive as an error response. They arrive in `rejection.code` of a transfer in status `REJECTED`, in the `201` response or in a later query.

The [error list](https://docs.lerian.studio/en/reference/interfaces/ted-lerian/ted-lerian-error-list.md) gives each code with its cause and fix.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.