Fee policies
Set the price of each fee you charge — for every account of your users or customers, a program, an account holder or a single account.
A fee policy is the pricing rule behind a fee: it says how much to charge for one kind of fee and whom the price applies to. You keep a general price for every account of your users or customers and override it wherever you need — a program with its own plan, an enterprise client with negotiated terms, a single account you want to exempt. When a fee is charged, Mono picks the most specific policy that covers the account and applies it.
Policies replace the need to ask Mono every time your pricing changes. You create, adjust, skip (pause) and remove them through the API, and you can always check which policy an account ends up with — and why.
Policies only price the fees you charge your users. The fees Mono charges you follow your commercial terms and are visible, but not editable, in the fees listing.
Before you start
You will need:
- A Core API key with the
feesscope (fees:readonlyis enough to read policies and fees). - Core fee policies enabled for you as a tenant. Mono enables them and creates your base policies — one per fee type in use — when you onboard.
- To know your programs, account holders and accounts by their identifiers (
pro_,acch_,lacc_): they are what a policy targets.
Anatomy of a policy
| Field | What it is |
|---|---|
fee_type | The kind of fee it prices: bank_transfer, payin, account_to_account_fx… See Fee types. |
target_type + target_id | Whom it applies to (the target): every account of your users or customers (tenant), a program, an account_holder or an account, and which one. |
strategies | The price, per currency: the rules to evaluate and the calculation to fall back to. See How the price is calculated. |
processing_type, processing_subtype | How the fee lands in the ledger, among the options the fee type allows. See Fee types and their processing. |
summary, transaction_description | A description for you, and the description your users see on the fee's transaction. |
skip | Skips (pauses) the policy without deleting it: Mono ignores it and the next less specific one applies. |
Who a policy applies to
A policy targets one of four levels. From the least to the most specific:
tenant— the base or global policy. It covers every account of your users or customers and is the price of last resort.program— every account in a program.account_holder— every account of a single account holder: one of your users or customers.account— a single subaccount.
When a fee is charged on an account, Mono looks at the policies of that fee type that cover the account — its own, its holder's, its program's and the base or global one (tenant) — and applies the most specific one that is not skipped or paused:
tenant the base or global policy — always exists, default price
└── program overrides it for every account of the program
└── account_holder overrides both for every account of the holder
└── account overrides everything for this account onlyThree rules complete the picture:
- Only one active policy per fee type and target. To change the price of a program, a holder or an account that already has a policy, update it; creating a second one is rejected.
- The base policy always exists. Mono creates your base or global (
tenant) policies. You can update them, but not create, skip (pause) or delete them — they guarantee every fee has a price. - A policy only covers the currencies it includes. If an account's currency is not among the policy's
strategies, that policy does not apply to it and the next less specific one does.
Which currencies a policy must cover
The currencies in strategies must stay within the ones the target supports:
| Target | Currencies the strategies may cover |
|---|---|
tenant | Exactly every currency your programs support — no more, no less. |
program | Any subset of the program's currencies. |
account_holder | Any subset of the currencies of the holder's accounts. |
account | Exactly the account's currency. |
A program or account_holder policy can therefore price only one currency and leave the others to the base policy — useful when a plan differs in COP but not in USD.
Seeing which policy applies
GET /v1/ledger/accounts/{account_id}/fees/policies lists, for a subaccount, every policy that bears on it, grouped by fee type and ordered from the most to the least specific, with applied: true on the one that wins. Skipped (paused) policies appear with applied: false, so you can see why a policy is not taking effect. Use it after creating or skipping a policy to confirm the result.
How the price is calculated
Each currency in strategies has its own strategy: an ordered list of rules (rules) and a default calculation (default_calculation). Mono evaluates the rules in order and uses the calculation of the first one whose conditions all hold; if none matches, it uses the default calculation. A strategy with no rules always uses the default calculation, which is the simplest way to set a flat price.
Calculation
A calculation is a fixed amount plus a percentage of the amount of the operation:
| Field | Meaning |
|---|---|
fixed | Fixed part, in the smallest unit of the currency. 900000 in COP is 9.000,00. |
percentage | Variable part, as a decimal fraction sent as a string. "0.004" is 0.4%. |
percentage_mode | open (default): no limit. capped: the variable part never exceeds percentage_limit. floored: it is never below it. |
percentage_limit | The cap or floor, in the smallest unit. Required for capped and floored, absent for open. |
Both parts are always explicit — send 0 and "0" for the parts you do not charge — so a fee is never priced at zero by omission.
For example, on a COP payout of 2.000.000,00, a calculation with fixed: 90000, percentage: "0.004", percentage_mode: "capped" and percentage_limit: 500000 charges 900,00 fixed plus 8.000,00 variable (0.4%); with a larger payout, the variable part would stop growing at 5.000,00.
Rules and conditions
A rule applies its calculation when all of its conditions hold. Conditions compare a property of the operation — its method, its amount, its currency, a metadata field of the account — against a value or another property. This is how you price a payout rail differently, give a discount above an amount or exempt accounts tagged in a certain way. The full list of operators and of the properties each fee type can look at lives in Conditions.
Fee types and their processing
Each fee type allows specific values of processing_type and processing_subtype for the fees you charge:
| Fee type | processing_type | processing_subtype | Notes |
|---|---|---|---|
bank_transfer | inline | add_posting | The fee rides on the payout's transaction. |
bank_transfer_gmf | inline | add_posting | The GMF pass-through, priced as a percentage. |
payin | inline | add_posting | Deducted from what is credited to the subaccount. |
account_to_account_fx | inline | add_posting | The fixed conversion charge, in the source currency. |
account_to_account_fx_spread | inline | upcharge | The margin, embedded in the exchange rate. |
Managing policies
| Action | Endpoint |
|---|---|
| Create one or many policies | POST /v1/core/fees/policies |
| List your policies | GET /v1/core/fees/policies |
| Get a policy | GET /v1/core/fees/policies/{id} |
| Update a policy | PATCH /v1/core/fees/policies/{id} |
| Delete a policy | DELETE /v1/core/fees/policies/{id} |
| See which policies apply to an account | GET /v1/ledger/accounts/{account_id}/fees/policies |
A few things to know about each operation:
- Creating. Send the policies under
policies, always a list (up to 50). The batch is atomic: if one policy is rejected, none is created, and the error'spathpoints at the item and field that failed —/policies/1/strategies/COPreads "the COP strategy of the second policy". A new policy never starts out skipped (paused). - Updating. Only the fields you send change.
strategiesis replaced as a whole, so send every currency the policy must keep; removing a currency is sending the map without it.fee_type,target_typeandtarget_idare immutable — to move a policy, delete it and create a new one. Changes apply to the fees charged from then on; fees already charged keep their price. - Skipping or pausing.
skip: trueskips (pauses) a policy: the next less specific one takes over until you setskipback tofalse. Base policies cannot be skipped. - Deleting. The policy stops applying and disappears from the listings, and its target and fee type are free for a new policy. Base policies cannot be deleted. Fees already charged keep referencing the deleted policy.
Example: a special price for one program
A program of premium users pays a lower payout fee, and nothing at all for ACH payouts:
{
"policies": [
{
"fee_type": "bank_transfer",
"summary": "Premium program — bank transfer fee",
"transaction_description": "Transfer fee",
"target_type": "program",
"target_id": "pro_3rbnHF9AtEBSyyfqZAmnii",
"processing_type": "inline",
"processing_subtype": "add_posting",
"strategies": {
"COP": {
"rules": [
{
"summary": "ACH payouts are free",
"conditions": [
{
"operator": "equal",
"left": { "property": "method" },
"right": { "value": "co_ach" }
}
],
"calculation": { "fixed": 0, "percentage": "0" }
}
],
"default_calculation": { "fixed": 300000, "percentage": "0" }
}
}
}
]
}From then on, every COP payout from an account of that program costs 3.000,00 — except ACH payouts, which cost nothing — while accounts in your other programs keep the price of your base policy.
Errors
Business errors come with an error_code and, when they concern one item of a batch, a path locating it:
| Code | HTTP | When |
|---|---|---|
fee_policy_not_found | 404 | The policy does not exist, is not yours or was deleted. |
fee_policy_already_exists | 409 | The target already has an active policy for that fee type. Update it instead. |
fee_policies_duplicated | 422 | Two policies of the batch have the same target and fee type. |
tenant_fee_policy_cannot_be_created | 422 | target_type: tenant is not allowed on creation — the base policies are set up by Mono. |
fee_policy_target_not_found | 422 | The target_id does not exist or does not belong to you. |
fee_policy_unsupported_processing_type | 422 | The processing_type is not among the ones the fee type allows. |
fee_policy_unsupported_processing_subtype | 422 | The processing_subtype is not among the ones the fee type allows for that processing type. |
fee_policy_invalid_strategy_currencies | 422 | The currencies of strategies do not match what the target supports. |
fee_policy_invalid_strategy | 422 | A rule, condition or calculation is invalid for the fee type — an unknown property, incompatible operands, a percentage limit that does not match its mode. |
tenant_fee_policy_cannot_be_skipped | 422 | skip: true on a base policy. |
tenant_fee_policy_cannot_be_deleted | 422 | Deleting a base policy. |
fee_policy_target_type_required | 422 | Listing with target_id but without target_type. |
Next steps
- Conditions — every operator and property available to your rules.
- Fees — what happens once a policy has priced a fee.
- Fees API reference — request and response payloads in full.