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

# FAQ

> Answers to common Lerian and Midaz questions on API pagination limits, SaaS data isolation, tenant JWT scoping, and multi-organization platform configuration.

## Lerian APIs

***

This section answers common questions about Lerian's APIs. It covers general behavior, configuration, and best practices across all services.

<Accordion title="Is there a maximum number of records per page in API listings? Can I increase this limit?">
  Yes. The default maximum is **100** records per page. This limit keeps performance consistent and controls the data volume in each request. To raise it, set the `MAX_PAGINATION_LIMIT` environment variable in your deployment configuration. The API accepts larger page sizes after you restart the application.

  **Important**: A larger page size can slow response times, especially with large datasets. Test in staging before you change production.
</Accordion>

## Multi-tenancy and SaaS

***

These questions cover data isolation, tenant scoping, and how multi-tenancy works in Lerian deployments.

<AccordionGroup>
  <Accordion title="Is my data isolated from other customers in SaaS?">
    Yes. Every tenant operates on a separate database. The platform resolves your tenant from the JWT on every request and routes it to your isolated database. There is no way to access another tenant's data through the API. Learn more about [multi-tenancy](/en/multi-tenancy).
  </Accordion>

  <Accordion title="Do I need to pass a tenant ID in my API requests?">
    No. The JWT access token you receive during authentication carries your tenant context. The platform resolves it automatically. You do not need to include a tenant identifier in headers or request bodies.
  </Accordion>

  <Accordion title="Can I have multiple Organizations under a single tenant?">
    Yes. A tenant can contain multiple Organizations. Each Organization has its own Ledgers, accounts, and transactions. The platform scopes all of them to your tenant automatically.
  </Accordion>

  <Accordion title="Is the API different between SaaS and self-hosted deployments?">
    No. The API surface is identical: same endpoints, same payloads, same responses. Only one thing differs. SaaS requires authentication on every request, and your token scopes all operations to your tenant.
  </Accordion>
</AccordionGroup>

## Midaz

***

These questions cover Organizations, Ledgers, Accounts, Transactions, and more in Midaz.

### Organizations

<AccordionGroup>
  <Accordion title="Do different Organizations communicate with each other?">
    No. Each Organization operates independently and does not communicate with others.
  </Accordion>

  <Accordion title="Can I use a single license across multiple Organizations?">
    No. Each license binds to one Organization. To support multiple Organizations, acquire a separate license for each. The same rule applies to Plugins.
  </Accordion>

  <Accordion title="Can an Organization have multiple Plugins?">
    Yes. An Organization can have more than one Plugin.
  </Accordion>

  <Accordion title="Can an Organization have multiple Ledgers?">
    Yes. An Organization can manage multiple Ledgers.
  </Accordion>

  <Accordion title="Can I create transactions between a Parent Organization and a Child Organization?">
    You can create a **Parent Organization** and a **Child Organization**. Each **Organization** keeps its own Ledger and operates independently. Transactions cannot move value directly between ledgers. You orchestrate the transfer with these steps:

    <Steps>
      <Step>
        In the source ledger, create a transaction from the original account (**source**) to the asset's **external account** (distribute). This removes the value from the source ledger.
      </Step>

      <Step>
        In the destination ledger, **create a second transaction**. The **source** is now the asset's **external account**, and the destination is the receiving account (**distribute**).
      </Step>
    </Steps>

    This pattern moves value between ledgers in different Organizations in a controlled way.
  </Accordion>
</AccordionGroup>

### Ledgers

<AccordionGroup>
  <Accordion title="Do different Ledgers communicate with each other?">
    No. Ledgers do not communicate directly. Transfers between Ledgers require orchestration.
  </Accordion>

  <Accordion title="How can I make transactions between Ledgers?">
    You must orchestrate the process and move the amount through an External Account. This involves two steps:

    <Steps>
      <Step>
        Ledger A -> External Account.
      </Step>

      <Step>
        External Account -> Ledger B.
      </Step>
    </Steps>
  </Accordion>

  <Accordion title="Do I need a separate Ledger for each Plugin?">
    No. A single Ledger can support multiple Plugins. For example, one Ledger can handle both Exchange and Pix Plugins.
  </Accordion>
</AccordionGroup>

### Assets

<AccordionGroup>
  <Accordion title="Can an Asset be linked to multiple Accounts?">
    No. Each Asset links to a single Account. Each Asset also links to an External Account. Midaz creates that External Account automatically when you create the Asset.
  </Accordion>

  <Accordion title="What types of Assets can I use?">
    Midaz supports several Asset types:

    * *currency*: Traditional fiat currencies like BRL, USD, and EUR.
    * *fiat*: An alternative type for fiat currencies; like `currency`, the Asset code must follow ISO 4217.
    * *crypto*: Digital assets such as BTC, ETH, and other cryptocurrencies.
    * *commodities*: Tangible goods like gold, soybean, and oil.
    * *others*: Custom Assets, including loyalty points and tokenized securities.
  </Accordion>
</AccordionGroup>

### Portfolios

<Accordion title="How does a Portfolio work?">
  A **Portfolio** groups accounts that belong to the same entity (**CPF/CNPJ**). For example, one CPF with two different `segment_id` values has two matching `account_id` values. You create a Portfolio for that CPF to link both accounts under one structure. This makes related accounts easier to find and manage.
</Accordion>

### Accounts

<AccordionGroup>
  <Accordion title="Can an Account be associated with multiple Assets?">
    No. Each Account links to a single Asset. You cannot change this link.
  </Accordion>

  <Accordion title="What is an External Account?">
    An External Account receives funds from outside the Ledger. It brings money into the system.
  </Accordion>

  <Accordion title="How can I create an External Account?">
    Midaz creates an **External Account** automatically when you create an Asset. This External Account backs all transactions that move in and out of the Ledger.
  </Accordion>

  <Accordion title="Can an Account be linked to several Segments?">
    No. Each account (`account_id`) links to only one Segment (`segment_id`).
  </Accordion>

  <Accordion title="Is there a limit to how many Accounts I can create in Midaz?">
    No. You can create as many Accounts as you need. Midaz sets no limit on the number of Accounts.
  </Accordion>

  <Accordion title="What is the process for adding funds to an account or performing a cash-in using money coming from outside the Ledger (Midaz) environment?">
    The balance top-up process works as follows:

    1. When you create an Asset (for example, BRL) in the Midaz Ledger, Midaz also creates an External Account for that Asset.
    2. This External Account mirrors the balances the institution holds outside Midaz. Those balances can sit in a PI account, a settlement account, a reserve account, or a traditional bank or payment account.
    3. To deposit funds from outside the Midaz Ledger into a user account, follow these steps:
       * Create a transaction with the External Account as the source and the target accounts as the destination.
       * Midaz debits the External Account by the amount (so it becomes negative) and credits the destination accounts by the values in the transaction payload.
  </Accordion>
</AccordionGroup>

### Transactions

<AccordionGroup>
  <Accordion title="What is the minimum structure of a Transaction?">
    A Transaction must have at least two Operations. For example, a transfer of R\$ 100 from Account A to Account B has two operations:

    * **Operation 1:** Debit R\$ 100 from Account A.
    * **Operation 2:** Credit R\$ 100 to Account B.
  </Accordion>

  <Accordion title="Is it possible to generate a PDF transfer receipt containing the details of a completed transaction?">
    Lerian gives clients several ways to access transaction receipts:

    1. **Via APIs** — Retrieve transaction data through the APIs, then generate a visual receipt in any format you choose.
    2. **With the Reporter** — Extract transaction data and create custom visual receipts.
    3. **Through the Console** — Access transaction data directly in the Lerian Console.
  </Accordion>
</AccordionGroup>

### Entities

<Accordion title="How can I create an Entity?">
  The Entity (`entity_id`) accepts external IDs. Midaz enforces no validation on this field. You can use the IDs that already exist in your database and integrate them into your system.
</Accordion>

### Idempotency

<AccordionGroup>
  <Accordion title="What happens if I don't send an idempotency key?">
    Midaz treats the request as new every time. Retries can then create duplicate operations.
  </Accordion>

  <Accordion title="Can I reuse an idempotency key across endpoints?">
    No. Scope each key to a single operation and endpoint.
  </Accordion>

  <Accordion title="What happens if I change the TTL on a retry?">
    Midaz uses only the TTL from the first request. A later change has no effect.
  </Accordion>

  <Accordion title="Will the replayed response always be identical?">
    Yes. For a completed request, Midaz returns the same result it stored from the first request. It also sets the `X-Idempotency-Replayed` header to `true`.
  </Accordion>

  <Accordion title="What's the default TTL if I don't send X-TTL?">
    The default TTL is **300 seconds** (5 minutes). Send the `X-TTL` header to set a custom value in seconds.
  </Accordion>
</AccordionGroup>

### Accounting in Midaz

<Accordion title="How can I reflect my own Chart of Accounts in Midaz?">
  Midaz lets you mirror your organization's official **Chart of Accounts** in the platform. You configure two core features:

  * [Account Types](/en/midaz/accounts) — Create the logical categories from your chart, such as Assets, Liabilities, Revenue, and Expenses. Assign them to accounts in your ledger. When you enable the Account Types feature, the `type` field in the Accounts API becomes mandatory and must match a registered value.
  * [Accounting Routes](/en/midaz/transaction-routing-entities) — Use Operation Routes to validate each leg of a transaction. For example, a debit must come from an account of type `user_wallet`. Use Accounting Routes (the `transactionRoute` resource in the API) to define complete transaction patterns that match your accounting logic.

  Account Types and Accounting Routes together enforce your accounting rules at the ledger level. Midaz validates and categorizes every transaction against your Chart of Accounts. You do not hardcode rules in your business logic.
</Accordion>

## Plugins

***

Plugins extend Midaz with integration and process orchestration. They provide abstractions so you can focus on your business model instead of system logic outside your domain.

The questions below cover how plugins work, how you deploy them, and the options available.

<AccordionGroup>
  <Accordion title="What are Plugins?">
    Plugins are technologies that integrate into the Midaz ledger. They simplify process integration and orchestration. They provide abstractions so clients can focus on their business model. Clients do not build or manage system logic outside their domain.
  </Accordion>

  <Accordion title="Can plugins be used without Midaz?">
    No. Plugins operate only with Midaz. They provide specific abstractions and orchestrate transactions based on the ledger structure.
  </Accordion>

  <Accordion title="How are plugins distributed?">
    After you contract a plugin, Lerian provides and installs it in your infrastructure (on-premise model), next to your Midaz instance. Applications connect to each plugin according to its function.
  </Accordion>

  <Accordion title="What plugin options does Lerian offer?">
    Lerian provides two types of plugins, grouped by origin:

    * **Native Plugins:** Lerian develops and integrates these plugins into the Midaz ledger. Lerian provides full support for them.
    * **Marketplace Plugins:** Lerian's partners create these plugins for specific market niches. Lerian helps integrate them into Midaz. The partners provide and support them directly.
  </Accordion>
</AccordionGroup>

## Fees Engine

***

These questions cover Fees Engine. Fees Engine is a licensed Midaz capability that runs inside the unified ledger process.

### General Concepts

<AccordionGroup>
  <Accordion title="What is Fees Engine?">
    Fees Engine is part of **Midaz**. It runs in the Midaz ledger process to calculate fees for financial transactions. Configure and deploy it with Midaz. Learn more in the [Fees Engine overview](/en/midaz/fees/fees-engine-overview). It works across three main domains:

    * **Fee Packages (`/v1/packages`):** defines charging rules per transaction (flat fee, percentage, or whichever is greater).
    * **Billing Packages (`/v1/billing-packages`):** defines periodic charges based on transaction volume or account maintenance.
    * **Calculation and Estimation (`/v1/fees` and `/v1/estimates`):** endpoints for calculating fees in real time or simulating before confirming.
  </Accordion>

  <Accordion title="How does Fees Engine fit into the Lerian ecosystem?">
    Fees Engine runs inside the Midaz ledger process. When a configured fee package applies, Midaz incorporates its fee calculations into the transaction. It uses ledger query use cases rather than an external HTTP connection to Midaz.
  </Accordion>

  <Accordion title="What do I need to send in every request to Fees Engine?">
    Every request requires the `X-Organization-Id` header with your Organization ID in Midaz. This header scopes the request to an Organization. It is specific to Fees Engine, not a tenant identifier. The platform still resolves your tenant context automatically from the JWT. When the authentication plugin is active, you also send a Bearer token in the `Authorization` header.

    ```
    X-Organization-Id: <your-organization-id>
    Authorization: Bearer <your-token>
    ```
  </Accordion>

  <Accordion title="What database does Fees Engine use for storage?">
    Fees Engine uses **MongoDB** for storage. Deletions follow the **soft-delete** pattern. Fees Engine does not remove records physically. It marks them with `deletedAt` instead. A deleted record does not appear in listings, but you can still audit it.
  </Accordion>

  <Accordion title="What is the minimum Midaz version required to use Fees Engine?">
    You need **Midaz v3.6.0** or higher. Fees Engine depends on Transaction module APIs that Midaz added in v3.6.0. Earlier Midaz versions do not work with Fees Engine.
  </Accordion>
</AccordionGroup>

### Fee Packages

<AccordionGroup>
  <Accordion title="What is a Fee Package?">
    A Fee Package (`Package`) is a set of charging rules under one `feeGroupLabel`. Each package links to an **Organization + Ledger**, and optionally to a **Segment**. A package can contain several fees (`Fee` objects), each with its own calculation logic. Learn more about [Fee Packages](/en/midaz/fees/using-fee-engine).
  </Accordion>

  <Accordion title="How do I create a Fee Package?">
    Send a `POST /v1/packages` with the following body. See the [Create Package API reference](/en/reference/midaz/plugins/fees-engine/create-package) for full details.

    ```json theme={null}
    {
      "feeGroupLabel": "Digital Account Fees",
      "ledgerId": "ldg_abc123",
      "segmentId": "seg_xyz456",
      "minimumAmount": "100.00",
      "maximumAmount": "50000.00",
      "transactionRoute": "PIX",
      "enable": true,
      "waivedAccounts": ["exempt-account-1", "exempt-account-2"],
      "fees": {
        "admin_fee": {
          "feeLabel": "Administrative Fee",
          "calculationModel": {
            "applicationRule": "percentual",
            "calculations": [
              { "type": "percentage", "value": "1.50" }
            ]
          },
          "referenceAmount": "originalAmount",
          "priority": 1,
          "isDeductibleFrom": true,
          "creditAccount": "fee-revenue-account"
        }
      }
    }
    ```
  </Accordion>

  <Accordion title="Can a package be temporarily disabled?">
    Yes. Set the `enable` field to `false` when you create or update the package. Fees Engine skips a disabled package during fee calculation, even when the transaction context matches its scope.
  </Accordion>

  <Accordion title="How does the package scope work (minimumAmount / maximumAmount)?">
    Fees Engine applies the package only to transactions whose value falls within the `[minimumAmount, maximumAmount]` range. If the transaction value falls outside this range, Fees Engine ignores the package.

    **Example:** A package with `minimumAmount: 100` and `maximumAmount: 5000` charges fees only on transactions between 100 and 5,000.

    <Note>If you do not set `maximumAmount`, the package can apply without an upper limit. Check the validation rules for your version.</Note>
  </Accordion>

  <Accordion title="Can I filter a package by transaction route?">
    Yes. Set the `transactionRoute` field in the package. Fees Engine then considers the package only for transactions with that route, such as `"PIX"`, `"TED"`, or `"BOLETO"`.
  </Accordion>

  <Accordion title="What are waivedAccounts?">
    These are account aliases that the package **exempts** from fees. If the sender or recipient of a transaction is an account in `waivedAccounts`, Fees Engine does not apply the package fees to it.

    ```json theme={null}
    "waivedAccounts": ["vip-account", "employee-account"]
    ```

    This package does not charge any transaction that comes from or goes to these accounts.
  </Accordion>

  <Accordion title="Do listing endpoints have pagination?">
    Yes. The listing endpoints (`GET /v1/packages`, `GET /v1/billing-packages`) support the `limit` and `page` query parameters for pagination.

    ```
    GET /v1/packages?limit=20&page=2
    ```
  </Accordion>
</AccordionGroup>

### Calculation Models

<AccordionGroup>
  <Accordion title="What calculation models are available?">
    The `applicationRule` field inside `calculationModel` defines how Fees Engine calculates the fee. See [Calculation Models](/en/midaz/fees/fee-engine-calculation) for full details. There are three options:

    | Rule              | Description                                                         |
    | ----------------- | ------------------------------------------------------------------- |
    | `flatFee`         | Fixed-amount fee                                                    |
    | `percentual`      | Percentage fee based on the reference amount                        |
    | `maxBetweenTypes` | Calculates both flat and percentage; applies the **greater** result |
  </Accordion>

  <Accordion title="How do I configure a flat fee (flatFee)?">
    Use exactly **1 calculation** of type `flat`:

    ```json theme={null}
    "calculationModel": {
      "applicationRule": "flatFee",
      "calculations": [
        { "type": "flat", "value": "5.00" }
      ]
    }
    ```

    This charges a fixed 5.00 regardless of the transaction amount.
  </Accordion>

  <Accordion title="How do I configure a percentage fee (percentual)?">
    Use exactly **1 calculation** of type `percentage`:

    ```json theme={null}
    "calculationModel": {
      "applicationRule": "percentual",
      "calculations": [
        { "type": "percentage", "value": "2.50" }
      ]
    }
    ```

    This charges 2.5% of the transaction's reference amount.
  </Accordion>

  <Accordion title="How does maxBetweenTypes work?">
    `maxBetweenTypes` requires **2 or more calculations** that combine `flat` and `percentage`. Fees Engine calculates both and applies the **greater result**.

    **Example:** Minimum fee of 3.00 or 1% of the value — whichever is greater:

    ```json theme={null}
    "calculationModel": {
      "applicationRule": "maxBetweenTypes",
      "calculations": [
        { "type": "flat", "value": "3.00" },
        { "type": "percentage", "value": "1.00" }
      ]
    }
    ```

    For a 200 transaction: 1% = 2.00 vs. 3.00 flat → charges **3.00**.
    For a 500 transaction: 1% = 5.00 vs. 3.00 flat → charges **5.00**.
  </Accordion>

  <Accordion title="Can I mix multiple percentages in maxBetweenTypes?">
    Yes. You can include any combination of `flat` and `percentage`. Fees Engine evaluates all of them and applies the greatest. Note that `flatFee` and `percentual` require exactly 1 calculation. Only `maxBetweenTypes` accepts 2 or more.
  </Accordion>
</AccordionGroup>

### Important Fields

<AccordionGroup>
  <Accordion title="What is referenceAmount and how does it affect calculation?">
    The `referenceAmount` defines **which value** Fees Engine calculates the fee on:

    * `originalAmount`: the original transaction value, **before** any fees.
    * `afterFeesAmount`: the transaction value **after** higher-priority fees apply.

    <Note>The fee with `priority: 1` runs first, so it **must** use `originalAmount`. No prior fees exist to consider.</Note>
  </Accordion>

  <Accordion title="What is isDeductibleFrom and when should I use it?">
    When `isDeductibleFrom: true`, Fees Engine deducts the fee from the amount the sender sends. The recipient receives the discounted amount, and the sender pays extra to cover the charge.

    When `false`, Fees Engine charges the fee **separately**. The sender sends the full amount, and Fees Engine debits the fee apart.

    **Constraints:**

    * `isDeductibleFrom: true` requires `referenceAmount: originalAmount`
    * If the type is `percentage`: the value cannot exceed 100
    * If the type is `flat`: the value cannot exceed the package's `minimumAmount`
  </Accordion>

  <Accordion title="How does the priority field work?">
    The `priority` defines the **execution order** of fees within a package. Fees Engine runs lower values first.

    * `priority: 1` → executed first (must use `originalAmount`)
    * `priority: 2` → executed after, can use `afterFeesAmount`

    Use priorities to chain fees. For example, run an administrative fee on the original amount. Then run an IOF fee on the amount after the administrative fee.
  </Accordion>

  <Accordion title="What is creditAccount?">
    It is the alias of the ledger account that receives the fee revenue. Each fee can have a different `creditAccount`. This helps when different fees belong to different cost centers.

    ```json theme={null}
    "creditAccount": "admin-fee-revenue-account"
    ```
  </Accordion>

  <Accordion title="What are routeFrom and routeTo inside a fee?">
    These fields define the routes of the **accounting legs** that the fee charge generates. They are optional. They let you track the origin and destination of fee movements in the ledger.
  </Accordion>
</AccordionGroup>

### Billing Packages

<AccordionGroup>
  <Accordion title="What are Billing Packages?">
    Billing Packages are **periodic** charge packages, independent of per-transaction fee calculation. See [Billing Package examples](/en/midaz/fees/billing-package-examples) for use cases. There are two types:

    * **`volume`:** charges based on the **number of transactions** in a period, with tiered pricing.
    * **`maintenance`:** charges a **fixed fee per account** in a given scope.
  </Accordion>

  <Accordion title="When should I use volume billing?">
    Use volume billing to charge clients by the **number of processed transactions**. This is a common model for payment platforms with volume-based pricing. You define price tiers that apply as volume grows.

    ```json theme={null}
    {
      "type": "volume",
      "eventFilter": {
        "transactionRoute": "PIX",
        "status": "approved"
      },
      "pricingModel": "tiered",
      "tiers": [
        { "minQuantity": 0, "maxQuantity": 1000, "unitPrice": "0.50" },
        { "minQuantity": 1001, "unitPrice": "0.30" }
      ],
      "assetCode": "BRL",
      "debitAccountAlias": "client-account",
      "creditAccountAlias": "volume-revenue-account"
    }
    ```

    <Note>The last tier must be **unbounded** (no `maxQuantity`). There must be no gaps or overlaps between tiers.</Note>
  </Accordion>

  <Accordion title="When should I use maintenance billing?">
    Use maintenance billing to charge a **fixed periodic fee per account**. For example, charge a monthly fee per active account. You specify the scope (`segmentId`, `portfolioId`, or `aliases`) and the fee amount.

    ```json theme={null}
    {
      "type": "maintenance",
      "feeAmount": "15.00",
      "assetCode": "BRL",
      "maintenanceCreditAccount": "maintenance-revenue-account",
      "accountTarget": {
        "segmentId": "seg_premium_clients"
      }
    }
    ```

    <Note>`accountTarget` must have exactly **one** of the three fields: `segmentId`, `portfolioId`, or `aliases` (maximum 100 aliases).</Note>
  </Accordion>

  <Accordion title="How do tiers work in volume billing?">
    Tiers define the **unit price per tier** as volume increases. The rules are:

    1. Must be **contiguous** — no gaps between tiers (`minQuantity` of the next = `maxQuantity` of the previous + 1).
    2. Must not **overlap**.
    3. The **last tier must be unbounded** (no `maxQuantity`).

    **Example of correct tiers:**

    ```json theme={null}
    "tiers": [
      { "minQuantity": 0, "maxQuantity": 500, "unitPrice": "0.80" },
      { "minQuantity": 501, "maxQuantity": 2000, "unitPrice": "0.60" },
      { "minQuantity": 2001, "unitPrice": "0.40" }
    ]
    ```
  </Accordion>

  <Accordion title="What is freeQuota?">
    It is a **free allowance**. Fees Engine does not charge a set number of transactions before tiers apply. This helps pricing models with a minimum included volume.

    **Example:** `freeQuota: 100` means Fees Engine does not charge the first 100 transactions in the period.
  </Accordion>

  <Accordion title="What are discountTiers?">
    These are discount tiers for volume billing. They reduce the charged amount based on extra criteria. They complement the logic of the main `tiers`.
  </Accordion>

  <Accordion title="What is countMode in volume billing?">
    It defines **how Fees Engine counts transactions**:

    * `perRoute`: counts transactions by route (e.g., total approved Pix).
    * `perAccount`: counts transactions per individual account.
  </Accordion>
</AccordionGroup>

### Fee Calculation and Estimation

<AccordionGroup>
  <Accordion title="What is the difference between /v1/fees and /v1/estimates?">
    | Endpoint             | When to use                                                                                                                                                                                                                                             |
    | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `POST /v1/fees`      | Calculate the **actual** fee of an ongoing transaction. See the [Calculate Fees API reference](/en/reference/midaz/plugins/fees-engine/calculate-fees). The system automatically finds applicable packages based on ledger, segment, route, and amount. |
    | `POST /v1/estimates` | **Simulate** the fee of a specific package before confirming the transaction. Useful for showing end users the cost before execution. See the [Simulate Fees API reference](/en/reference/midaz/plugins/fees-engine/simulate-fees).                     |
  </Accordion>

  <Accordion title="How does /v1/fees work?">
    The endpoint receives the transaction data. The system **automatically finds** the applicable packages. It considers:

    * `ledgerId` — required
    * `segmentId` — optional
    * `transactionRoute` — optional
    * Transaction value — compared with the package's `minimumAmount`/`maximumAmount`

    Fees Engine calculates and returns fees from all matching packages.
  </Accordion>

  <Accordion title="How does /v1/estimates work?">
    The `/v1/estimates` endpoint simulates the fee of a **specific package** (`packageId`). You do not need an actual transaction. It works well for:

    * Show the estimated cost to the user before confirmation.
    * Test configurations of newly created packages.
    * Build fee simulators in your product.
  </Accordion>

  <Accordion title="Can I use /v1/estimates in production to show fees to end users?">
    Yes. `/v1/estimates` is a read-only endpoint. It does not alter state or register transactions. It is safe to use in UX flows to show the cost before confirmation.
  </Accordion>

  <Accordion title="How do I calculate billing?">
    After you configure Billing Packages, call this endpoint:

    ```
    POST /v1/billing/calculate
    ```

    This endpoint processes the configured rules and generates the charges for the period. See the [Calculate Billing API reference](/en/reference/midaz/plugins/fees-engine/calculate-billing).
  </Accordion>
</AccordionGroup>

### Common Errors

<AccordionGroup>
  <Accordion title="&#x22;Priority 1 must use originalAmount&#x22; — what does this mean?">
    The fee with `priority: 1` must have `referenceAmount: "originalAmount"`. It is the first fee to run, so no prior fees exist to base the calculation on.

    **Fix:**

    ```json theme={null}
    {
      "priority": 1,
      "referenceAmount": "originalAmount"
    }
    ```
  </Accordion>

  <Accordion title="&#x22;isDeductibleFrom requires originalAmount&#x22; — how to fix?">
    Fees with `isDeductibleFrom: true` can only use `referenceAmount: "originalAmount"`. Update the field:

    ```json theme={null}
    {
      "isDeductibleFrom": true,
      "referenceAmount": "originalAmount"
    }
    ```
  </Accordion>

  <Accordion title="&#x22;Flat fee value cannot exceed minimumAmount&#x22; — why?">
    When `isDeductibleFrom: true` and the type is `flat`, the fee value cannot exceed the package's `minimumAmount`. This prevents a fee that is larger than the minimum transaction value.

    **Example:** If `minimumAmount: 100`, the flat fee cannot exceed 100.
  </Accordion>

  <Accordion title="&#x22;Percentage value cannot exceed 100&#x22; — when does this occur?">
    This error occurs when `isDeductibleFrom: true`, the type is `percentage`, and the value is above 100. A deductible percentage fee of 100% would zero out the transaction. Values above 100 are invalid.
  </Accordion>

  <Accordion title="&#x22;Tiers must be contiguous&#x22; — how to fix?">
    Volume billing tiers must cover all ranges without gaps. Check that the `minQuantity` of each tier is exactly `maxQuantity + 1` of the previous tier.

    ```json theme={null}
    // ❌ Wrong — gap between 500 and 600
    { "minQuantity": 0, "maxQuantity": 500, "unitPrice": "0.80" },
    { "minQuantity": 600, "unitPrice": "0.40" }

    // ✅ Correct
    { "minQuantity": 0, "maxQuantity": 500, "unitPrice": "0.80" },
    { "minQuantity": 501, "unitPrice": "0.40" }
    ```
  </Accordion>

  <Accordion title="&#x22;Last tier must be unbounded&#x22; — what does this mean?">
    The last tier in volume billing must have **no upper limit** (no `maxQuantity`). This keeps a price on transactions above the highest defined range.
  </Accordion>

  <Accordion title="&#x22;accountTarget must have exactly one of: segmentId, portfolioId, aliases&#x22;">
    In maintenance billing, the `accountTarget` field accepts only **one** of the three options. Do not combine fields:

    ```json theme={null}
    // ❌ Wrong
    "accountTarget": {
      "segmentId": "seg_abc",
      "portfolioId": "port_xyz"
    }

    // ✅ Correct
    "accountTarget": {
      "segmentId": "seg_abc"
    }
    ```
  </Accordion>

  <Accordion title="Is there a limit on aliases in accountTarget?">
    Yes. The `aliases` field accepts a maximum of **100 aliases** per maintenance Billing Package.
  </Accordion>

  <Accordion title="&#x22;flatFee requires exactly 1 calculation of type flat&#x22;">
    The `applicationRule: "flatFee"` accepts exactly 1 calculation, and it must be of type `flat`. Do not use `percentage` with `flatFee`.

    ```json theme={null}
    // ✅ Correct
    "calculationModel": {
      "applicationRule": "flatFee",
      "calculations": [{ "type": "flat", "value": "10.00" }]
    }
    ```
  </Accordion>

  <Accordion title="&#x22;percentual requires exactly 1 calculation of type percentage&#x22;">
    Like `flatFee`, the `applicationRule: "percentual"` accepts exactly 1 calculation of type `percentage`.
  </Accordion>

  <Accordion title="&#x22;maxBetweenTypes requires 2 or more calculations&#x22;">
    `maxBetweenTypes` requires at least 2 calculations to work — it needs values to compare. Provide at least one `flat` and one `percentage`.
  </Accordion>

  <Accordion title="The package is not being applied to the transaction — what should I check?">
    Diagnostic checklist — see also [Best Practices](/en/midaz/fees/fees-engine-best-practices):

    * **`enable`:** is the package active (`enable: true`)?
    * **`ledgerId`:** is the package linked to the correct ledger?
    * **`minimumAmount` / `maximumAmount`:** is the transaction value within the range?
    * **`transactionRoute`:** if the package has `transactionRoute`, does the transaction use the same route?
    * **`segmentId`:** if the package is scoped to a segment, does the account belong to it?
    * **`waivedAccounts`:** is the account listed as exempt?
  </Accordion>

  <Accordion title="Can a deleted record be recovered?">
    Fees Engine soft-deletes records. It marks them with `deletedAt` and does not remove them from the database. The API does not expose restoration endpoints by default. Contact the Lerian team if you need to recover a deleted record. For a full list of error codes, see the [Error Codes reference](/en/reference/midaz/plugins/fees-engine/fee-engine-error-list).
  </Accordion>
</AccordionGroup>
