# Boleto Management API

A boleto is Brazil's bank-issued payment slip: you register a charge with a bank, the bank returns a barcode and a digitable line, and your payer settles it at any bank, ATM or app. Registering one normally means integrating with each bank separately — different authentication, different field names, different notions of what a "paid" boleto looks like.

The Boleto Management API is one uniform interface over all of them. You register a charge once, in one shape, and we translate it to whichever institution your customer banks with.

<Callout variant="warning" title="BETA">
This API is in BETA. Inter Empresas is available today; see [Supported institutions](#supported-institutions) for what is live and what is coming.
</Callout>

## How it fits together

Two objects. A **Boleto Connection** holds the credentials that let us act at an institution on your customer's behalf, and it is created once. Every **Boleto** is then issued against that connection.

```mermaid
graph LR
  subgraph Once per customer
    A[Item<br/>bank account connected] --> B[Boleto Connection]
    A2[Raw credentials] --> B
  end
  subgraph Many times
    B --> C[Boleto #1]
    B --> D[Boleto #2]
    B --> E[Boleto #3]
  end
```

You can create a connection from an existing [Item](/docs/connect-widget/introduction) — the same object you already use for data — or by [sending credentials directly](/reference/boleto-connection-create) when there is no Item to reuse.

## The lifecycle of a boleto

A boleto starts `OPEN` and moves in one direction. `PAID` and `CANCELLED` are terminal: nothing leaves them, and a boleto never returns to `OPEN`.

```mermaid
stateDiagram-v2
  [*] --> OPEN: created
  OPEN --> PAID: payer settles it
  OPEN --> OVERDUE: due date passes
  OPEN --> CANCELLED: you cancel it
  OVERDUE --> PAID: paid late
  OVERDUE --> PROTESTED: sent to protest
  OVERDUE --> CANCELLED: you cancel it
  PROTESTED --> PAID: settled after protest
  PROTESTED --> CANCELLED: you cancel it
  PAID --> [*]
  CANCELLED --> [*]
```

| Status | What it means |
|---|---|
| `OPEN` | Registered at the bank and payable. |
| `PAID` | Settled. `amountPaid` and `paymentOrigin` are filled in. |
| `OVERDUE` | Past its due date and still payable — most banks accept late payment. |
| `CANCELLED` | Withdrawn by you. It can no longer be paid. |
| `PROTESTED` | Sent to protest after going unpaid. Still settleable. |

<Callout variant="info" title="Partial payments">
`amountPaid` is what the payer actually paid, and it can differ from `amount` — a payer may settle a boleto with a discount, or with a fine and interest applied after the due date. Always reconcile against `amountPaid`, never against the amount you requested.
</Callout>

## The end-to-end flow

Issuing a boleto is a single call. Learning that it was paid is a webhook — you do not poll.

```mermaid
sequenceDiagram
  autonumber
  participant You as Your system
  participant Pluggy
  participant Bank
  actor Payer

  You->>Pluggy: POST /boletos
  Pluggy->>Bank: register the charge
  Bank-->>Pluggy: nossoNumero, barcode, digitable line
  Pluggy-->>You: 201 { id, status: OPEN, ... }

  Note over You,Payer: you deliver the boleto however you like

  Payer->>Bank: pays the boleto
  Bank->>Pluggy: settlement notification
  Pluggy->>You: webhook boleto/updated
  You->>Pluggy: GET /boletos/{id}
  Pluggy-->>You: { status: PAID, amountPaid, paymentOrigin }
```

The webhook tells you *that* something changed, not *what*. It carries the boleto's id, and you fetch the boleto to see its new state. That keeps the notification small and means a webhook you receive twice is harmless.

## Getting started

<StepList>
<Step title="Get an API key">
Call [POST /auth](/reference/auth-create) with your application's credentials.

```json
{
  "clientId": "{YOUR-CLIENT-ID}",
  "clientSecret": "{YOUR-CLIENT-SECRET}"
}
```
</Step>

<Step title="Create a Boleto Connection">
From an existing Item, with [POST /boleto-connections/from-item](/reference/boleto-connection-create-from-item):

```json
{
  "itemId": "{YOUR-ITEM-ID}"
}
```

The response carries the id you will issue against:

```json
{
  "id": "dc3537ad-13b4-4770-b248-e4578983899c",
  "connectorId": 225,
  "createdAt": "2023-01-01T00:00:00.000Z",
  "updatedAt": "2023-01-01T00:00:00.000Z"
}
```
</Step>

<Step title="Issue a boleto">
[POST /boletos](/reference/boleto-create). `amount` is in reais, `dueDate` is `YYYY-MM-DD`:

```json
{
  "boletoConnectionId": "{YOUR-BOLETO-CONNECTION-ID}",
  "boleto": {
    "seuNumero": "1234567891",
    "amount": 2.5,
    "dueDate": "2025-03-01",
    "payer": {
      "taxNumber": "1234567890",
      "name": "Example name",
      "addressState": "SP",
      "addressZipCode": "01239030",
      "addressCity": "Não informado",
      "addressStreet": "Não informado"
    }
  }
}
```

`seuNumero` is *your* reference for the charge — an invoice number, an order id. It comes back on every read and on the settlement notification, so use something you can reconcile against.
</Step>

<Step title="Deliver it to your payer">
The response includes everything a payer needs:

```json
{
  "id": "158b9f04-acf0-4a9b-8f0c-a87feb9f19b3",
  "boletoConnectionId": "91d4d8d8-8477-423e-9888-0bbbde2da64a",
  "amount": 2.5,
  "status": "OPEN",
  "seuNumero": "1234567891",
  "dueDate": "2025-03-01",
  "pixQr": "00020126490014br.gov.bcb.pix0108dict-key...",
  "digitableLine": "01120001161117012359902128847071234570777000110",
  "nossoNumero": "10000004701",
  "barcode": "01120001161117012359902128847071234570",
  "amountPaid": null,
  "paymentOrigin": null
}
```

`digitableLine` is the 47-digit number a payer types into their banking app, `barcode` is what a scanner reads, and `pixQr` is a PIX payload for the same charge — most banks now issue boletos payable either way.
</Step>

<Step title="Listen for the payment">
Subscribe to `boleto/updated` in [webhooks](/docs/developer-tools/webhooks-ref) and you will receive:

```json
{
  "boletoId": "158b9f04-acf0-4a9b-8f0c-a87feb9f19b3",
  "eventId": "71e0b4db-4e8c-401d-8ad8-5ab3ecd1f3d0",
  "event": "boleto/updated"
}
```

Then [GET /boletos/{id}](/reference/boleto-get). A settled boleto reads:

```json
{
  "id": "158b9f04-acf0-4a9b-8f0c-a87feb9f19b3",
  "status": "PAID",
  "amount": 2.5,
  "amountPaid": 2.5,
  "paymentOrigin": "PIX",
  "seuNumero": "1234567891"
}
```
</Step>
</StepList>

You can withdraw an unpaid boleto at any time with [POST /boletos/{id}/cancel](/reference/boleto-cancel).

## Supported institutions

Inter Empresas is available today; Bradesco and the Sandbox connector are being built. Which institutions are live, how each one authorises a connection, and the behaviours worth knowing per bank are kept in one place: [Coverage](/docs/boleto/coverage).

## Before you go live

- **Reconcile on `amountPaid`, not `amount`.** Fines, interest and discounts mean they differ.
- **Treat webhooks as at-least-once.** The same `boletoId` can arrive twice; `eventId` identifies the delivery if you want to deduplicate.
- **Store `seuNumero` on your side.** It is your only link between a boleto and whatever it is paying for.
- **Do not parse `nossoNumero` for meaning.** Its format is the bank's and differs between institutions.