This page is a complete reference for all template tags, filters, and operators available in Reporter. For an introduction to templates and placeholders, see What is Reporter.
Building templates
Common blocks
{% for <item> in <list> %}
...
{% endfor %}
- Loop with explicit schema
{% for order in external_db:sales.orders %}
{{ order.id }} - {{ order.total }}
{% endfor %}
{% if value_a == value_b %}
...
{% endif %}
{% with <object> as <alias> %}
...
{% endwith %}
{{ field_name | floatformat:2 }} --> renders 123.45
Conditional blocks
| Block | Description | Example |
|---|
| If | Runs block if condition is true | {% if condition %}...{% endif %} |
| If-else | Runs one block if true, another if false | {% if condition %}...{% else %}...{% endif %} |
| If-else-if | Allows multiple checks | {% if a %}...{% elif b %}...{% else %}...{% endif %} |
| Equal | Checks if two values are equal | {% if a == b %} |
| Not equal | Checks if two values are different | {% if a != b %} |
| Greater than | Checks if a is greater than b | {% if a > b %} |
| Less than | Checks if a is less than b | {% if a < b %} |
| Greater than or equal | Checks if a is greater than or equal to b | {% if a >= b %} |
| Less than or equal | Checks if a is less than or equal to b | {% if a <= b %} |
| And | Returns true if both conditions true | {% if a and b %} |
| Or | Returns true if at least one true | {% if a or b %} |
| Not | Inverts Boolean result | {% if not a %} |
sum_by — Sums numeric values from a field across all items in a collection.
{% sum_by <collection> by <field> %}
{% sum_by <collection> by <field> if <condition> %}
Example:
<Sum>
{% sum_by transaction.operation by "amount" if accountAlias != "@external/BRL" %}
</Sum>
count_by — Counts the number of items in a collection.
{% count_by <collection> %}
{% count_by <collection> if <condition> %}
Example:
<Count>
{% count_by transaction.operation if accountAlias != "@external/BRL" %}
</Count>
avg_by — Calculates the average of numeric values in a field.
{% avg_by <collection> by <field> %}
{% avg_by <collection> by <field> if <condition> %}
min_by — Finds the minimum numeric value in a field.
{% min_by <collection> by <field> %}
{% min_by <collection> by <field> if <condition> %}
max_by — Finds the maximum numeric value in a field.
{% max_by <collection> by <field> %}
{% max_by <collection> by <field> if <condition> %}
All aggregation tags use decimal precision to avoid floating-point rounding errors. Missing or non-numeric fields are skipped. Returns 0 if no items match.
Date and time tag
date_time — Outputs the current date and time formatted according to the provided format string. Time is generated in UTC.
{% date_time "<format>" %}
Format codes:
| Code | Meaning | Example |
|---|
YYYY | 4-digit year | 2025 |
MM | 2-digit month | 01-12 |
dd | 2-digit day | 01-31 |
HH | 2-digit hour (24h) | 00-23 |
mm | 2-digit minute | 00-59 |
ss | 2-digit second | 00-59 |
Examples:
{% date_time "YYYY-MM-dd" %} --> 2025-02-06
{% date_time "dd/MM/YYYY HH:mm:ss" %} --> 06/02/2025 14:30:45
Arithmetic tag
calc — Evaluates mathematical expressions with support for variables from the template context.
Supported operators:
| Operator | Description | Precedence |
|---|
** | Exponentiation | Highest (right-to-left) |
* / | Multiplication, division | Middle |
+ - | Addition, subtraction | Lowest |
( ) | Parentheses | Override precedence |
Examples:
{% calc 100 + 50 %} --> 150
{% calc balance.available * 0.5 %} --> calculated value
{% calc (balance.available + 1.2) * balance.on_hold - balance.available / 2 %}
Variables that cannot be resolved default to 0. Division by zero produces an error.
Financial aggregation tag
aggregate_balance — Groups items by a field, selects the most recent entry per account within each group, and sums the balances. Useful for regulatory reports that require the latest balance per account grouped by category.
{% aggregate_balance <collection> by "<balance_field>" group_by "<group_field>" order_by "<date_field>" [if <condition>] as <result_var> %}
The result is stored in a variable you can iterate over:
{% aggregate_balance accounts by "balance" group_by "cosif_code" order_by "created_at" as balances %}
{% for b in balances %}
{{ b.group_value }}: {{ b.balance }} ({{ b.count }} accounts)
{% endfor %}
Each result item contains:
| Field | Type | Description |
|---|
group_value | string | The value from the group_by field |
balance | decimal | Sum of latest balances per account in the group |
count | integer | Number of accounts in the group |
Maximum collection size: 100,000 items. Results are sorted by group_value.
counter — Increments a named counter by 1. Produces no output. Counters are scoped per render.
{% counter "<counter_name>" %}
counter_show — Displays the sum of one or more named counters.
{% counter_show "<name1>" %}
{% counter_show "<name1>" "<name2>" "<name3>" %}
Example:
{% for tx in ledger.transactions %}
{% counter tx.type %}
{% endfor %}
Total credits: {% counter_show "credit" %}
Total debits: {% counter_show "debit" %}
Combined: {% counter_show "credit" "debit" %}
Filters reference
percent_of
Calculates the percentage of a value relative to a total. Returns a formatted string with 2 decimal places.
{{ value | percent_of: total }}
Example: if category.amount = "6.00" and total.expenses = "20.00":
{{ category.amount | percent_of: total.expenses }} --> 30.00%
strip_zeros
Removes trailing zeros from a numeric value without rounding.
{{ number | strip_zeros }}
Examples:
{{ "100.50000" | strip_zeros }} --> 100.5
{{ "100.00" | strip_zeros }} --> 100
{{ "99.990" | strip_zeros }} --> 99.99
slice
Extracts a substring using start and end indices (0-based).
{{ string | slice:"start:end" }}
Examples:
{{ "hello" | slice:"0:3" }} --> hel
{{ "12345" | slice:"1:4" }} --> 234
replace
Replaces all occurrences of a search string with a replacement string. Format: "search:replacement".
{{ string | replace:"search:replacement" }}
Examples:
{{ "01310-100" | replace:"-:" }} --> 01310100 (removes hyphens)
{{ "1234.56" | replace:".:," }} --> 1234,56 (dot to comma)
{{ "12.345.678/0001-99" | replace:".:" }} --> 12345678/0001-99
where
Filters an array of objects by field equality. Supports nested fields via dot notation.
{{ array | where:"field:value" }}
Examples:
{{ holders | where:"state:SP" }}
{{ holders | where:"address.state:SP" }}
Use inside loops:
{% for holder in holders|where:"state:SP" %}
{{ holder.name }}
{% endfor %}
sum (filter)
Sums numeric values from a field across all items in an array. Uses decimal precision.
{{ array | sum:"field" }}
Examples:
{{ operations | sum:"amount" }}
{{ items | sum:"price.value" }}
count (filter)
Counts elements in an array where a field matches a value. Supports nested fields.
{{ array | count:"field:value" }}
Examples:
{{ operations | count:"nat_oper:6" }}
{{ holders | count:"address.state:SP" }}
contains
Checks if one value is partially included in another. Useful when data includes dynamic prefixes or suffixes.
{% if contains(source_field, target_field) %}
Example:
- Source:
0#@external/BRL
- Target:
@external/BRL
Returns true because @external/BRL exists within the source value.
Operators and filters summary
| Name | Type | Description |
|---|
sum_by | Tag | Sum values by field with optional filter |
count_by | Tag | Count items with optional filter |
avg_by | Tag | Calculate average by field |
min_by | Tag | Find minimum value |
max_by | Tag | Find maximum value |
date_time | Tag | Format current date/time |
calc | Tag | Evaluate arithmetic expressions |
aggregate_balance | Tag | Grouped financial balance aggregation |
counter | Tag | Increment a named counter |
counter_show | Tag | Display counter value(s) |
percent_of | Filter | Calculate percentage |
strip_zeros | Filter | Remove trailing zeros |
slice | Filter | Extract substring |
replace | Filter | String replacement |
where | Filter | Filter array by field value |
sum | Filter | Sum array field values |
count | Filter | Count matching items |
contains | Function | Partial string match |
floatformat | Filter | Format decimal places |
Advanced filtering
When generating a report, you can pass filters in the request body to narrow the data. Filters follow a structure of datasource > table > field:
Single schema (default):
{
"templateId": "00000000-0000-0000-0000-000000000000",
"filters": {
"midaz_onboarding": {
"account": {
"id": { "eq": ["123", "456"] },
"createdAt": { "between": ["2023-01-01", "2023-01-31"] },
"status": { "in": ["active", "pending"] }
}
}
}
}
Multi-schema (explicit schema.table key):
{
"templateId": "00000000-0000-0000-0000-000000000000",
"filters": {
"external_db": {
"sales.orders": {
"total": { "gt": [100] },
"created_at": { "gte": ["2025-01-01"] }
},
"finance.invoices": {
"status": { "eq": ["paid"] }
}
}
}
}
Supported operators:
| Operator | Description | Example |
|---|
eq | Equal to | { "eq": ["active", "pending"] } |
gt | Greater than | { "gt": [100] } |
gte | Greater than or equal to | { "gte": ["2025-06-01"] } |
lt | Less than | { "lt": [1000] } |
lte | Less than or equal to | { "lte": ["2025-06-30"] } |
between | Value falls within a range | { "between": [100, 1000] } |
in | Value is within a list | { "in": ["active", "pending"] } |
nin | Value is not within a list | { "nin": ["deleted", "archived"] } |