The pricing object inside ServicePricingDto determines the fee amount. Its priceType field selects the computation strategy.
Choose a strategy: fee is always the same → FIXED; fee varies by form field values → DYNAMIC; fee needs a formula or lookup table → PRICE_LOGIC.
| Field | Type | Description |
|---|---|---|
priceType |
"FIXED" | "DYNAMIC" | "PRICE_LOGIC" |
Computation strategy |
baseValue |
number | null | Fee amount (FIXED only) |
baseCurrency |
"RWF" | "USD" | null |
Currency; set on the block for FIXED and PRICE_LOGIC, or per condition for DYNAMIC |
dynamicConditions |
DynamicConditionDto[] | Condition-to-amount mappings (DYNAMIC only) |
priceLogicCode |
string | null | Server-side PriceLogic code (PRICE_LOGIC only) |
formulaCode |
string | null | Targets a specific formula within the PriceLogic; omit to use the active formula (PRICE_LOGIC only) |
priceParameterMapping |
{ [paramCode]: fieldKey } | null |
Maps parameter codes to form field keys (PRICE_LOGIC only) |
repetitiveComponentKey |
string | null | Repeater field key; used with valueBasedOnRepetitiveComponent |
valueBasedOnRepetitiveComponent |
boolean | When true, multiplies the resolved fee by the number of items in the repeater |
A static fee that never changes.
{
"priceType": "FIXED",
"baseValue": 20000,
"baseCurrency": "RWF",
"dynamicConditions": []
}
The fee varies based on form field values. Entries in dynamicConditions are evaluated in order; the first entry whose conditions all match applies. If no entry matches, the fee is not resolved — always ensure conditions cover every possible case, or place a catch-all entry with an empty conditions array at the end.
| Field | Type | Description |
|---|---|---|
value |
number | null | Hardcoded fee amount |
valueAttribute |
string | null | Form field key whose value becomes the fee |
valueFormula |
string | null | JSONata expression whose result becomes the fee |
currency |
"RWF" | "USD" |
Currency for this entry |
conditions |
ConditionDto[] | All must match for this entry to apply |
Set exactly one of value, valueAttribute, or valueFormula per entry; leave the others null.
An empty or null conditions array always evaluates to true — the entry unconditionally matches. Place such an entry last as a catch-all.
Two formats are supported:
Legacy format — field-by-field comparison:
| Field | Type | Description |
|---|---|---|
attribute |
string | Form field key to evaluate |
attributeType |
"STRING" | "NUMBER" | "DATE" |
How to interpret the field value |
comparator |
"EQ" | "NEQ" | "GT" | "LT" | "GTE" | "LTE" | "CONTAINS" |
Comparison operator |
value |
string | Target value (always a string; parsed by attributeType) |
JSONata format — a single-entry array with a jsonata key; the expression must evaluate to a truthy value for the entry to match:
"conditions": [{ "jsonata": "<boolean expression>" }]
A hardcoded amount per matching condition. Use when the fee is a fixed constant for each option.
{
"priceType": "DYNAMIC",
"baseValue": null,
"baseCurrency": null,
"dynamicConditions": [
{
"value": 15000,
"valueAttribute": null,
"conditions": [
{
"attribute": "POLICY_TYPE",
"comparator": "EQ",
"value": "Classic",
"attributeType": "STRING"
}
],
"currency": "RWF"
},
{
"value": 30000,
"valueAttribute": null,
"conditions": [
{
"attribute": "POLICY_TYPE",
"comparator": "EQ",
"value": "Premium",
"attributeType": "STRING"
}
],
"currency": "RWF"
}
]
}
The fee is read from a form field. Use when the form computes or displays the total before submission — a calculated field or a user-entered amount.
{
"priceType": "DYNAMIC",
"baseValue": null,
"baseCurrency": null,
"dynamicConditions": [
{
"value": null,
"valueAttribute": "AMOUNT_TO_PAY",
"conditions": [
{
"attribute": "AMOUNT_TO_PAY",
"comparator": "NEQ",
"value": "0",
"attributeType": "NUMBER"
}
],
"currency": "RWF"
}
]
}
The fee is computed by an inline JSONata expression. Use when the fee requires arithmetic across multiple fields but is too simple to warrant a full PRICE_LOGIC object.
{
"priceType": "DYNAMIC",
"baseValue": null,
"baseCurrency": null,
"dynamicConditions": [
{
"value": null,
"valueAttribute": null,
"valueFormula": "QUANTITY * UNIT_PRICE",
"conditions": [],
"currency": "RWF"
}
]
}
When every repeater row costs the same flat amount, set valueBasedOnRepetitiveComponent: true and provide repetitiveComponentKey. The system multiplies the resolved amount by the row count.
{
"priceType": "DYNAMIC",
"baseValue": null,
"baseCurrency": null,
"dynamicConditions": [
{
"value": 5000,
"valueAttribute": null,
"conditions": [],
"currency": "RWF"
}
],
"valueBasedOnRepetitiveComponent": true,
"repetitiveComponentKey": "BENEFICIARIES"
}
Delegates fee computation to a server-side PriceLogic object identified by priceLogicCode. Use when the calculation requires multi-variable formulas, lookup tables, or repeater aggregation that conditions alone cannot express.
{
"priceType": "PRICE_LOGIC",
"baseValue": null,
"baseCurrency": "RWF",
"priceLogicCode": "RFA_RFA_PLANTING_MATERIALS_PRICING_LOGIC_UNIFIED",
"priceParameterMapping": {
"RFA_RFA_PLANTING_MATERIALS_PRICING_LOGIC_UNIFIED_SEED_DETAILS_REPEATER": "SEED_DETAILS_REPEATER",
"RFA_RFA_PLANTING_MATERIALS_PRICING_LOGIC_UNIFIED_WHAT_ARE_YOU_LOOKING_FOR": "WHAT_ARE_YOU_LOOKING_FOR"
},
"repetitiveComponentKey": null,
"valueBasedOnRepetitiveComponent": false
}
A PriceLogic object lives on the server and has three parts:
PriceLogic — the top-level container, identified by a unique code.
PriceParameter — the declared inputs the formula needs. Each has a code, name, and paramType (NUMBER, TEXT, BOOLEAN, DATE). Note: the string type is TEXT, not STRING. Parameters are referenced inside the formula by their full code.
PriceFormula — a JSONata expression attached to the PriceLogic. Parameters are available as top-level variables addressed by their full parameter code.
A PriceLogic can have multiple formulas. Set formulaCode to the exact code of the formula to use. Omit it (or set null) to use the currently active formula. When the PriceLogic has only one formula, this field is not needed.
Maps each parameter's full code to the form field key that provides its value at runtime:
"priceParameterMapping": {
"<PARAMETER_CODE>": "<FORM_FIELD_KEY>"
}
The key is the parameter's exact code. The value is the form field key whose submitted value is injected into the formula under that name.
Parameters appear as bare top-level variables in the expression. A formula computing fee from a plan tier and quantity:
(
$prices := {"Basic": 5000, "Standard": 15000, "Premium": 30000};
$unit := $lookup($prices, TIER_PARAM_CODE);
($unit ? $unit : 0) * QUANTITY_PARAM_CODE
)
For repeater aggregation, pass the repeater's JSON as a STRING parameter. Deserialize it with $eval() and map over the rows:
(
$unitPrices := {"Type A": 1000, "Type B": 2000};
$rows := $eval(REPEATER_PARAM_CODE);
$totals := $rows.(
$p := $lookup($unitPrices, ITEM_TYPE);
($p ? $p : 0) * QUANTITY
);
$reduce($totals, function($acc, $val) { $acc + $val }, 0)
)
Use $reduce instead of $sum — it handles single-item lists and empty repeaters correctly where $sum does not.
BULK_CHILD_SUM is used on parent services in the bulk payment pattern. The master bill amount is the sum of all child application fees — no baseValue or conditions are needed on the parent. See Bulk Payment for the full workflow.