> ## 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 from the SFN 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 once, with the `editor` role. Set the usage limits with `PUT /v1/policy/limits`; they are required before the first TED. For incoming TEDs, set the ISPB to organization bindings with `PUT /v1/policy/ispb-bindings`. Optionally, set a cut-off with `PUT /v1/policy/window`.

**2. Send the TED**

Send `X-Account-Id` (the debited account) and `X-Idempotency` (a new key for each payment). To show the fee 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": "12345678901"
    }
  }'
```

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 and sent to the STR | Wait for settlement; cannot be cancelled |
| `PENDING_STR` | The STR keeps the entry pending | 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. `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 key stays bound to the transfer it created.
* **Duplicate protection.** `POST /v1/transfers` can refuse with `409` `TED-0014` a materially identical request sent shortly after another one, even with a different key. Query the existing transfer.
* **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`. Handle errors by `code`. `errors` lists the invalid fields of a `422`.

A `503` means the request did not take effect: retry later with the same `X-Idempotency`. There are three 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`.

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 |
| 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 or fee calculation 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; cut-off later than the official close |
| Dependencies | `TED-1000`/`TED-1010`/`TED-1012`/`TED-1020` (503), `TED-1001`/`TED-1021` (422) | Ledger, STR connector or registry unavailable or refusing the data |
| Internal | `TED-9000` (500), `TED-9002` (503) | Unexpected failure: contact support with the `X-Request-Id`; service unavailable, for example when the audit trail cannot record a policy change |

On a send, `TED-0031`, `TED-1001`, `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.