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

# Build an account statement

> Turn Midaz account operations into a clear customer statement by filtering by date, direction, and route with the List Operations by Account endpoint.

This guide explains how to transform Midaz account operations into end-user account statements.

You build an account statement from Midaz account operations. Each operation is a ledger movement that links to an account, such as a credit, debit, hold, release, or overdraft event.

To build a statement, retrieve the account operations for the period. Keep the operations that affect the statement view. Then transform each operation into a row that users understand.

<Frame caption="Account balance flow">
  <img src="https://mintcdn.com/lerian-49cb71fc/SFzzdxyH5SN7w_fC/images/en/d2/account-balance-flow.svg?fit=max&auto=format&n=SFzzdxyH5SN7w_fC&q=85&s=1d9f29821d6e2e687c6d9bd8e4c5a89f" alt="Account balance flow" width="1537" height="348" data-path="images/en/d2/account-balance-flow.svg" />
</Frame>

<Steps>
  <Step title="Retrieve account operations" titleSize="h2">
    Use the [List Operations by Account](/en/reference/midaz/list-operations-by-account) endpoint to list operations for a specific account:

    ```json theme={null}
    GET /v1/organizations/{organization_id}/ledgers/{ledger_id}/accounts/{account_id}/operations
    ```
  </Step>

  <Step title="Apply query filters" titleSize="h2">
    Use query parameters to define the statement period, control pagination, and filter the operations that the endpoint returns.

    ### Required for statement queries

    | Parameter         | Description                              |
    | ----------------- | ---------------------------------------- |
    | `start_date`      | Start date of the statement period       |
    | `end_date`        | End date of the statement period         |
    | `limit`           | Number of items per page                 |
    | `sort_order=desc` | Returns the most recent operations first |

    You need these fields for this statement use case. They define the statement window and make the result predictable for users.

    ### Required for pagination

    | Parameter | Description                                |
    | --------- | ------------------------------------------ |
    | `cursor`  | Cursor returned from the previous response |

    ### Optional filters

    | Parameter          | Description                              |
    | ------------------ | ---------------------------------------- |
    | `direction=credit` | Returns only incoming operations         |
    | `direction=debit`  | Returns only outgoing operations         |
    | `type`             | Filters by operation type                |
    | `route_id`         | Filters by the operation route ID (UUID) |
    | `route_code`       | Filters by the operation route code      |

    The endpoint can return the following operation types:

    | Type        | What it means                                  |
    | ----------- | ---------------------------------------------- |
    | `CREDIT`    | Value entering the account                     |
    | `DEBIT`     | Value leaving the account                      |
    | `ON_HOLD`   | Amount temporarily locked                      |
    | `RELEASE`   | Previously locked amount released              |
    | `OVERDRAFT` | Movement related to overdraft usage            |
    | `BLOCK`     | System-generated account-block companion row   |
    | `UNBLOCK`   | System-generated account-unblock companion row |

    Use `type` to classify the accounting movement. Use `direction` to decide whether the statement shows the amount as positive or negative.

    Example request:

    ```json theme={null}
    GET /v1/organizations/org_123/ledgers/ledger_001/accounts/account_456/operations?start_date=2026-05-01&end_date=2026-05-31&limit=50&sort_order=desc
    ```
  </Step>

  <Step title="Transform operations into statement entries" titleSize="h2">
    Each object in the `items` array can become one statement row.

    ### Required for statement rendering

    | Statement field                  | Operation field          |
    | -------------------------------- | ------------------------ |
    | Date                             | `createdAt`              |
    | Description                      | `description`            |
    | Movement type                    | `type`                   |
    | Direction                        | `direction`              |
    | Amount                           | `amount.value`           |
    | Currency or asset                | `assetCode`              |
    | Balance after operation          | `balanceAfter.available` |
    | Receipt or transaction reference | `transactionId`          |

    You need these fields to render a useful statement row. The API does not require all of them. A statement without them loses meaning, traceability, or balance context.

    ### Recommended for user-friendly statements

    | Statement context | Operation field         |
    | ----------------- | ----------------------- |
    | Counterparty      | `metadata.counterparty` |
    | Document          | `metadata.document`     |
    | Pix key           | `metadata.pixKey`       |
    | End-to-end ID     | `metadata.endToEndId`   |
    | Channel           | `metadata.channel`      |
    | Category          | `metadata.category`     |

    Midaz returns the ledger movement. The integrating system should add business context in the `metadata` of each relevant `source.from[]` and `distribute.to[]` entry when it creates the transaction; metadata does not propagate from source entries to destination entries.

    Example transformation:

    ```json theme={null}
    {
      "date": "2026-05-18T14:23:11Z",
      "description": "Pix transfer received",
      "type": "CREDIT",
      "direction": "credit",
      "amount": "150.00",
      "asset": "BRL",
      "balanceAfter": "1240.55",
      "transactionId": "txn_987654",
      "metadata": {
        "counterparty": "John Doe",
        "pixKey": "john@example.com",
        "category": "Transfer"
      }
    }
    ```
  </Step>

  <Step title="Apply statement display rules" titleSize="h2">
    ### Use `direction` to determine the sign

    | Direction | Display behavior             |
    | --------- | ---------------------------- |
    | `credit`  | Display as a positive amount |
    | `debit`   | Display as a negative amount |

    <Warning>
      Do not use `type` to determine whether the value is positive or negative. The `type` field classifies the accounting movement, while `direction` defines whether the value enters or leaves the account.
    </Warning>

    ### Handle hold and release operations separately

    Do not display operations with the following types as regular settled movements:

    * `ON_HOLD`
    * `RELEASE`

    Instead:

    * `ON_HOLD` should appear as a balance hold or temporary lock
    * `RELEASE` should appear as a balance release or unlock

    ### Define a settled-operation policy

    Do not use `balanceAffected` as a settled-operation predicate. A normal `ON_HOLD` operation can set `balanceAffected` to `true` without changing the available balance. Define your statement policy explicitly from operation type and status, and show `ON_HOLD` and `RELEASE` according to the hold/release rules above.
  </Step>

  <Step title="Handle pagination" titleSize="h2">
    The endpoint splits responses into pages according to the `limit` value.

    To retrieve all operations:

    1. Read the `next_cursor` field from the response
    2. Send it as the `cursor` parameter in the next request
    3. Repeat until the response no longer returns `next_cursor`

    Example flow:

    ```text theme={null}
    Request 1
      -> returns items + next_cursor

    Request 2
      -> cursor=next_cursor
      -> returns more items + next_cursor

    Repeat until next_cursor is no longer returned
    ```
  </Step>
</Steps>

## Example statement output

After you apply filters, transform operations, and apply display rules, the final statement can look like this:

| Date       | Description                | Amount      | Balance after |
| ---------- | -------------------------- | ----------- | ------------- |
| 2026-05-18 | Pix received from John Doe | +150.00 BRL | 1,240.55 BRL  |
| 2026-05-18 | Card purchase              | -45.90 BRL  | 1,194.65 BRL  |

The API does not return a ready-made statement page. It returns ledger events that the integrating system turns into a statement experience.

## Add business context

The operations endpoint returns accounting events. A user-facing statement needs more context than the ledger movement alone.

Send business metadata in each operation's metadata when you create the transaction. Midaz stores those fields with that operation. The statement can use them later to show who, what, and why behind the movement.

* `counterparty`
* `document`
* `pixKey`
* `endToEndId`
* `channel`
* `category`

Example metadata:

```json theme={null}
"send": {
  "source": {
    "from": [{
      "accountAlias": "customer_123",
      "metadata": {
        "counterparty": "John Doe",
        "document": "12345678900",
        "pixKey": "john@example.com",
        "endToEndId": "E1234567890123456789012345678901",
        "channel": "PIX",
        "category": "Transfer"
      }
    }]
  }
}
```

This lets you display entries such as:

* "Pix received from John Doe"
* "Card purchase at Coffee Shop"
* "Transfer to Savings Account"

instead of generic accounting descriptions.

If the integrating system does not send these fields, the statement still works. It can then only display the accounting data that the operation returns.

<Tip>
  Midaz keeps the ledger consistent and auditable. The integrating system adds business context to each operation's metadata.
</Tip>
