Conditions
The operators and properties your fee rules can use to decide when a price applies.
A condition is a yes-or-no question a fee rule asks about the operation being charged: is this payout going through ACH? Is the amount above a threshold? Is the account tagged as VIP? A rule applies its price only when every one of its conditions answers yes. Conditions are how a single fee policy prices different situations differently, instead of needing one policy per case.
Every condition compares an operand — a property of the operation, or a constant value you write — with another, through an operator. This page is the reference of the operators available and of the properties each kind of fee can look at.
Anatomy of a condition
{
"operator": "greater_equal_than",
"left": { "property": "source_amount" },
"right": { "value": 100000000 },
"negated": false
}| Field | Meaning |
|---|---|
operator | The comparison to make. See Operators. |
left | The first operand. Usually a property of the operation. |
right | The second operand. Required by every operator except is_null. |
negated | Inverts the result. false by default: a negated equal means "is different from". |
An operand is one of:
- A property:
{ "property": "method" }— the value is read from the operation when the fee is charged. Some properties take arguments:{ "property": "account.metadata", "args": { "name": "plan" } }. - A constant:
{ "value": "co_ach" }— a string, an integer, a boolean, or a list of them. Decimals travel as strings ("0.5").
At least one side of a condition must be a property — comparing two constants would always give the same answer.
Operators
| Operator | Reads as | Operands |
|---|---|---|
equal | left is equal to right | Any two compatible operands. An integer and a decimal compare as numbers. |
greater_than | left is greater than right | Two numbers. |
greater_equal_than | left is greater than or equal to right | Two numbers. |
less_than | left is less than right | Two numbers. |
less_equal_than | left is less than or equal to right | Two numbers. |
in | left is one of the values in right | left is a single value; right is a list of values of the same kind ({ "value": ["co_ach", "co_transfiya"] }). |
is_null | left has no value | Only left, and it must be a property that can be empty. No right. |
Two details to keep in mind:
- When a property involved in a numeric comparison is empty (
null), the condition is false. Useis_nullif you need to react to the absence of a value. - Operands must be compatible: comparing an amount with a text, or a string with a list of numbers, is rejected when the policy is created (
fee_policy_invalid_strategy), not silently ignored later.
Properties
Which properties a rule can use depends on the fee type: each one is triggered by a kind of operation — its main entity — and can also look at the entities related to it. A property of the main entity is referenced by its name (method); a property of a related entity by entity.property (account.name, account_holder.type).
Amounts are in the smallest unit of their currency (1234 is 12,34), currency codes follow ISO 4217 (COP, USD) and country codes ISO 3166-1 alpha-2 (CO).
Payouts — bank_transfer, bank_transfer_gmf
Main entity: the payout. Related: the source account and its account holder.
| Property | Type | Meaning |
|---|---|---|
method | string | The payout method, for example co_ach, co_transfiya, co_mono_turbo, co_breb. |
source_currency_code | string | The currency of the source account. |
source_amount | number or null | The amount debited from the source account, in its smallest unit. |
target_currency_code | string | The currency of the destination. |
target_amount | number or null | The amount delivered to the destination, in its smallest unit. |
target_country_code | string | The country of the destination account. |
Payins — payin
Main entity: the payin. Related: the credited account (the subaccount) and its account holder.
| Property | Type | Meaning |
|---|---|---|
method | string | The payin method, for example co_breb. |
merchant_currency_code | string | The currency of the merchant amount — the template's currency. |
merchant_amount | number or null | The merchant-facing amount of the payment, in its smallest unit. |
subaccount_currency_code | string | The currency of the credited subaccount. |
subaccount_amount | number or null | The amount credited to the subaccount, in its smallest unit. |
Transfers between subaccounts — account_to_account_fx, account_to_account_fx_spread
Main entity: the subaccount operation (the transfer). Related: the source account and its account holder.
| Property | Type | Meaning |
|---|---|---|
operation_type | string | The kind of transfer: account_to_account_fx when currencies differ. |
source_currency_code | string | The currency of the source subaccount. |
source_amount | number or null | The amount debited from the source subaccount, in its smallest unit. |
target_currency_code | string | The currency of the destination subaccount. |
target_amount | number or null | The amount credited to the destination subaccount, in its smallest unit. |
metadata | string or null | A field of the transfer's metadata. Takes args: { "key": "<field>" }. |
Related entities: account and account holder
Available to every fee type above, prefixed with account. or account_holder.:
| Property | Type | Meaning |
|---|---|---|
account.name | string or null | The name you gave the account. |
account.metadata | string or null | A field of the account's metadata. Takes args: { "name": "<field>" }. |
account_holder.type | string | self when the holder is your own company, third_party when it is one of your users or customers. |
account_holder.metadata | string or null | A field of the account holder's metadata. Takes args: { "name": "<field>" }. |
Metadata is the most flexible hook: tag your accounts or holders with a plan, a segment or a tier when you create them, and price on it without touching the policy every time a user changes plan.
Examples
Each example is one rule inside the strategy of a currency. If the operation does not meet the rule's conditions, the rule does not apply and the price is decided by the next rule or, when none matches, by the strategy's default_calculation.
Free ACH payouts — the rule applies when the method is exactly co_ach; any other method pays the default_calculation:
{
"conditions": [
{ "operator": "equal", "left": { "property": "method" }, "right": { "value": "co_ach" } }
],
"calculation": { "fixed": 0, "percentage": "0" }
}A cheaper rate for large payouts — at or above 1.000.000,00 COP. This example shows the whole strategy, with the default_calculation that charges when the rule does not apply:
{
"rules": [
{
"summary": "Reduced rate from 1.000.000,00 COP",
"conditions": [
{
"operator": "greater_equal_than",
"left": { "property": "source_amount" },
"right": { "value": 100000000 }
}
],
"calculation": { "fixed": 150000, "percentage": "0" }
}
],
"default_calculation": { "fixed": 300000, "percentage": "0" }
}A payout of 1.500.000,00 COP meets the condition and pays 1.500,00; one of 800.000,00 COP does not, so it pays the 3.000,00 of the default_calculation.
Instant rails cost more — any of two methods; the rest pay the default_calculation:
{
"conditions": [
{
"operator": "in",
"left": { "property": "method" },
"right": { "value": ["co_transfiya", "co_breb"] }
}
],
"calculation": { "fixed": 500000, "percentage": "0" }
}Exempt VIP accounts — the account was created with metadata.plan = "vip"; every other account pays the default_calculation:
{
"conditions": [
{
"operator": "equal",
"left": { "property": "account.metadata", "args": { "name": "plan" } },
"right": { "value": "vip" }
}
],
"calculation": { "fixed": 0, "percentage": "0" }
}Untagged accounts pay a surcharge — the metadata field is absent; tagged accounts pay the default_calculation:
{
"conditions": [
{
"operator": "is_null",
"left": { "property": "account.metadata", "args": { "name": "plan" } }
}
],
"calculation": { "fixed": 200000, "percentage": "0.01" }
}Rules are evaluated in order and the first match wins, so put the most specific rules first and let default_calculation handle everything else.
Next steps
- Fee policies — where these rules live, and how policies are resolved.
- Fees — the fee types and what each one is charged for.
- Create fee policies — the full request schema.