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

# Account plans

> Assign a fee plan to an account, with a free quota per fee and calendar month, and charge its service fees.

An **account plan** is a set of fees that you assign to an account. Each fee has a free quota: a number of units in each calendar month that cost nothing. An account plan has two kinds of fees:

* **Transaction fees** apply to the `/v2` transactions that the account sends.
* **Service fees** apply when you charge a service to the account, for example a paper statement. You charge them with a [fee charge](#service-fees-and-fee-charges).

You create account plans and assign them through the API. Each account has at most one active account plan.

## Account plans and fee packages

***

An account plan and a [fee package](https://docs.lerian.studio/en/products/midaz/fees/fees-engine-overview.md#fee-packages) are different entities.

* An account with an active account plan pays the fees of its plan on the `/v2` transactions it sends. On those transactions, a fee package never charges that account, also when no fee of the plan matches. Then the account pays no fee.
* A fee package does not charge the fee legs that an account plan adds.

| | Fee packages | Account plans |
| - | - | - |
| **Selects** | Transactions, by route, segment, metadata, and amount | The accounts that you assign to the plan |
| **Free quota** | No | Yes, per fee and calendar month |
| **Service fees** | No | Yes, through fee charges |
| **Deductible fees** | Yes (`isDeductibleFrom`) | No |
| **Deferrable fees** | Yes (`deferrable`) | No |
| **Rounding** | Yes (`rounding`) | No |

## Create an account plan

***

Create a plan with [Create an account plan](https://docs.lerian.studio/en/reference/products/midaz/v2/create-an-account-plan.md). The plan has these fields:

* `label`: the name of the plan. Two plans of a ledger that are not deleted cannot have the same label (`0543`).
* `description`: optional.
* `enable`: `true` lets you assign the plan to accounts.
* `timezone`: the IANA timezone that the plan counts its months in. The default is `America/Sao_Paulo`.
* `fees`: at least one fee, by fee key. A fee key starts with a lowercase letter, followed by ASCII letters and digits only (`^[a-z][a-zA-Z0-9]*$`).

Each fee has these fields:

* `feeLabel`: the name of the fee.
* `trigger`: what makes the fee apply. See [Triggers](#triggers).
* `calculationModel`: `flatFee`, `percentual`, or `maxBetweenTypes`, as in a [fee package](https://docs.lerian.studio/en/products/midaz/fees/fee-engine-calculation.md#fee-calculation-rules). A service fee accepts only `flatFee` (`0555`).
* `creditAccount`: the alias of the ledger account that receives the fee. Midaz checks that the account exists when you create or update the plan.
* `accounting`: the `transactionRoute`, `operationRouteFrom`, and `operationRouteTo` of the fee. See [Accounting routes](#accounting-routes).
* `freeQuota`: the number of free units per month. The default is `0`.
* `period`: only `monthly`, the default.
* `referenceAmount`: only `originalAmount`, the default.

### Triggers

A trigger with `type: transaction` takes these fields:

* `direction`: required. The only value is `sent`: the fee applies to the account that sends the transaction.
* `schemes`: the transaction schemes that the fee matches, for example `TED` or `PIX`.
* `metadata`: optional pairs that the transaction metadata must all carry. A pair matches only a string metadata value that is equal to it.

A trigger with `type: service` takes only `serviceCode`, for example `PAPER_STATEMENT`.

Midaz stores schemes and service codes trimmed and in upper case. Each one has 1 to 50 letters, digits, underscores, or hyphens. One code cannot be the scheme of a fee and the service code of another fee of the plan (`0558`).

### Accounting routes

The rules depend on whether the ledger validates accounting routes (`accounting.validateRoutes` in the [ledger settings](https://docs.lerian.studio/en/products/midaz/ledgers.md)):

| Rule | Ledger without route validation | Ledger with route validation |
| - | - | - |
| Transaction fee | Lists at least one scheme (`0556`). | A fee without schemes matches every scheme of its transaction route. |
| `accounting` | Optional. | Required on every fee, with a `transactionRoute` (`0547`) that exists (`0105`) and both operation routes (`0557`). |
| Operation routes | Not checked. | Both are linked to the transaction route of the fee. On a transaction fee, both are optional links (`optionalOperationRoutes`) (`0557`). |

Two transaction fees of a plan with the same `metadata` cannot select the same transactions (`0544`). On a ledger without route validation, they cannot share a scheme. On a ledger with route validation, they cannot share a transaction route and a scheme, and a fee without schemes takes every scheme of its route. Two service fees cannot share a service code (`0544`).

If you turn on route validation after you create a plan, give every fee a transaction route and both operation routes first. A fee without a transaction route refuses each transaction that it would match with `0547`, and each fee charge that names it.

## Versions

***

The fees of a plan live in versions. A version never changes.

* The create makes version 1, in effect from the instant of the create.
* An [update](https://docs.lerian.studio/en/reference/products/midaz/v2/update-an-account-plan.md) that sends `fees` makes a new version with the full resulting set of fees.
* `effectiveFrom` sets the instant that the new version applies from, in RFC 3339. The default is the instant of the request. It cannot be before the `effectiveFrom` of the latest version (`0553`). Send it only with `fees`.
* `label`, `description`, `enable`, and `timezone` change the plan, not a version.

In the `fees` of an update:

* An entry with the key of a stored fee changes the fields it sends and keeps the others. `trigger`, `calculationModel`, and `accounting` change as a whole.
* An empty entry (`{}`) deletes that fee.
* An entry with a new key adds a fee, with every required field.
* The new version starts from the fees of the latest version. It keeps at least one fee.

When two updates create a version of the same plan at the same time, one of them gets `0559` and creates no version. Read the plan again and send the update again.

[Get an account plan](https://docs.lerian.studio/en/reference/products/midaz/v2/get-an-account-plan.md) returns the version in effect at the instant of the request. `currentVersion` is the highest version created, which can start later. [List the versions of an account plan](https://docs.lerian.studio/en/reference/products/midaz/v2/list-the-versions-of-an-account-plan.md) returns every version.

## Assign a plan to an account

***

[Assign an account plan to an account](https://docs.lerian.studio/en/reference/products/midaz/v2/assign-an-account-plan-to-an-account.md) sends the `accountPlanId` of the plan.

* The plan must belong to the ledger, exist, and be enabled (`0545`).
* If the account has an active assignment of another plan, it ends at the instant that the new assignment starts, in one step.
* If the account already has the same plan, Midaz returns the active assignment and changes nothing.
* When another assignment of the same account runs at the same time, Midaz can answer `0560` and change nothing. Send the request again.

[Get the account plan assignment of an account](https://docs.lerian.studio/en/reference/products/midaz/v2/get-the-account-plan-assignment-of-an-account.md) returns the active assignment, or `null`, and the history of the account. [List the accounts assigned to an account plan](https://docs.lerian.studio/en/reference/products/midaz/v2/list-the-accounts-assigned-to-an-account-plan.md) returns the active assignments of a plan.

[End the account plan assignment of an account](https://docs.lerian.studio/en/reference/products/midaz/v2/end-the-account-plan-assignment-of-an-account.md) ends the active assignment. The fee packages then apply to the account again. An account without an active assignment answers `0554`.

### Disable or delete a plan

* A disabled plan (`enable: false`) cannot be assigned. It keeps charging the accounts that it already has.
* Midaz refuses to delete a plan that is assigned to an account (`0546`). End its assignments first.
* When you delete an account, Midaz ends its active assignment. The history of the account stays readable.

## How a plan charges a transaction

***

Midaz applies account plans to these `/v2` transactions: direct, hold, block, unblock, and each item of a batch. A `/v1` transaction, an annotation, a revert, and a transaction that skips fees with `skip.fees` do not use account plans.

Midaz takes one decision for each source account of the transaction that has an active plan, except `@external` accounts. It takes one decision per account, also when the account sends from several balances.

### Matching

The fees of the version in effect are matched against the transaction:

* On a ledger without route validation, a transaction fee matches when its `schemes` contain the `scheme` of the transaction. A transaction without `scheme` matches no fee.
* On a ledger with route validation, a transaction fee matches when its `transactionRoute` is the `routeId` of the transaction and its `schemes` are empty or contain the `scheme` of the transaction.
* In both cases, the transaction metadata must carry every `metadata` pair of the fee.
* When several fees match, the fee with the most `metadata` pairs applies. When two or more fees have that number of pairs, Midaz refuses the transaction with `0548`.

### Outcome

The decision has one of these outcomes:

| Outcome | What happens |
| - | - |
| `quota` | A fee matched, and the unit is inside the free quota. The account pays no fee. |
| `charged` | A fee matched, and the unit is past the free quota. Midaz adds the fee on top of what the account sends and credits it to `creditAccount`. |
| `no_match` | No fee matched. The account pays no fee, and no unit is counted. |

Midaz calculates a charged fee on the amount that the account sends in the transaction. On a ledger with route validation, the fee legs use the operation routes of the fee.

The create response has `accountPlanFees`, with one item for each account that has an active plan: `accountId`, `accountAlias`, `accountPlanId`, `accountPlanVersion`, `feeKey`, `outcome`, `unit`, `freeQuota`, and `amount`. Only the create responses return it. Reads, commits, cancels, and reverts do not. The transaction metadata keys `packageAppliedID`, `feeApplied`, and `feeExemption` describe fee packages only.

### Holds, cancels, and reverts

* A hold counts the unit when you create it. The commit counts nothing.
* A cancel or a revert gives the unit back only in the same month of the plan. The revert also reverses the fee legs.

## Free quota

***

A unit is one decision with the outcome `quota` or `charged`, or one service code of a fee charge with the same outcomes.

* Midaz counts units per account, fee key, and calendar month in the plan timezone.
* The count belongs to the account and the fee key, not to the plan. An account that moves to another plan with the same fee key keeps its count for the month.
* A transaction fee counts each scheme separately. On a ledger with route validation, a fee without schemes has one count for every scheme of its route. A service fee has one count.
* When you change a fee, its count stays. A fee with a new key starts at zero.
* The month is the month in which Midaz processes the transaction, not its `transactionDate`.

## Service fees and fee charges

***

[Charge service fees to an account](https://docs.lerian.studio/en/reference/products/midaz/v2/charge-service-fees-to-an-account.md) sends `serviceCodes`, with 1 to 100 codes, and an optional `description` and `metadata`. The request needs the `X-Idempotency` header (`0552`).

Each code in the list is one unit. Its outcome is one of these:

* `quota`: the unit is inside the free quota of its fee. It costs nothing.
* `charged`: the unit is past the free quota. It costs the flat amount of the fee.
* `not_covered`: the plan of the account has no service fee for the code, or the account has no active plan. It costs nothing and counts no unit.

Midaz refuses the request before it charges anything when:

* No account plan of the ledger has a service fee for a code (`0549`).
* A code belongs only to transaction fees (`0550`).
* On a ledger with route validation, the fees of the codes have different transaction routes (`0551`), or a fee has no transaction route (`0547`).

Midaz posts the charged units as one fee transaction in the asset of the account. It debits the account and credits the `creditAccount` of each fee. On a ledger with route validation, the transaction uses the transaction route and the operation routes of the fees. The `description` and `metadata` of the charge go to the fee transaction. No fee package, account plan, or Tracer validation applies to the fee transaction. When Midaz refuses the fee transaction, for example for insufficient funds, it refuses the charge with the same error and counts no unit.

A charge without a charged unit has no fee transaction, and its `feeTransactionIds` is empty. Nothing undoes that charge, and its units stay counted.

* A retry with the same key and the same body returns the recorded charge with the `X-Idempotency-Replayed` header. A different body with the same key answers `0084`. Keys are unique per account.
* To undo a charge, revert its fee transaction. A revert in the same month gives back every unit of the charge.
* The fee transaction has no reference to its charge. `feeTransactionIds` on the charge links them.

[List the fee charges of an account](https://docs.lerian.studio/en/reference/products/midaz/v2/list-the-fee-charges-of-an-account.md) returns the newest charge first, and `period` (`YYYY-MM`) filters it. [Get a fee charge of an account](https://docs.lerian.studio/en/reference/products/midaz/v2/get-a-fee-charge-of-an-account.md) returns one charge.

## Usage

***

[Get the account plan usage of an account](https://docs.lerian.studio/en/reference/products/midaz/v2/get-the-account-plan-usage-of-an-account.md) returns the units of the account in one month. `period` (`YYYY-MM`, in the plan timezone) selects the month. The default is the current month. A future or malformed `period` answers `0082`, and an account without an active plan answers `0554`.

The response has one item for each count of each fee: `feeKey`, `trigger`, `period`, `freeQuota`, `used`, `remaining`, and `charged`. `trigger` is a key for the count: read `feeKey` instead of parsing it. `remaining` is never negative.

The usage lists the fees and free quotas of the version in effect now, also for a past month. For reconciliation, use the `accountPlanFees` of the create responses and the fee charges.

## Estimates and events

***

* A [fee estimate](https://docs.lerian.studio/en/reference/products/midaz/v2/estimate-fee-calculation.md) prices the fee package that you name. It does not read account plan assignments.
* The `fee_charge.applied` event covers fee packages only. An account plan fee or a fee charge does not emit it.

## Permissions

***

The routes use these Midaz permission resources:

| Resource | Action | Use |
| - | - | - |
| `account-plans` | `get` | Read plans, versions, assigned accounts, assignments, and usage. |
| `account-plans` | `post` | Create a plan. |
| `account-plans` | `patch` | Update a plan. |
| `account-plans` | `put` | Assign a plan to an account. |
| `account-plans` | `delete` | Delete a plan, or end the assignment of an account. |
| `fee-charges` | `get` | Read fee charges. |
| `fee-charges` | `post` | Charge service fees. |

## Next steps

***

> [card] [Using account plans](https://docs.lerian.studio/en/products/midaz/fees/using-account-plans.md)
>
> Create a plan, assign it, and charge fees step by step.

> [card] [Midaz error list](https://docs.lerian.studio/en/reference/products/midaz/error-list.md)
>
> See the codes from `0543` to `0560`.


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