How to handle transaction reverts and maintain accurate balances

Last updated: July 3, 2025

When working with transaction reverts in Formance, it's important to understand how they affect balances and how to maintain accurate financial statements. This article covers best practices for handling reverts and querying transactions.

Using the atEffectiveDate parameter for reverts

To maintain accurate balances when reverting transactions, use the atEffectiveDate parameter when calling the revert API:

revert?atEffectiveDate=true

This ensures that the revert transaction is created with the same date as the original transaction, preserving the correct balance calculations in your financial statements.

Querying transactions with reverts

When querying transactions, you may want to exclude both reverted transactions and their compensatory transactions. Here's an example query that achieves this:

{
    "$and": [
        {
            "$match": {
                "account": "deals:XYZ:balances:"
            }
        },
        {
            "$match": {
                "reverted": false
            }
        },
        {
            "$not": {
                "$exists": {
                    "metadata": "com.formance.spec/state/reverts"
                }
            }
        }
    ]
}

This query:

  • Matches transactions for a specific account

  • Excludes transactions marked as reverted

  • Excludes compensatory transactions (which have the "com.formance.spec/state/reverts" metadata)

Using the volumes endpoint for balance information

For performance reasons, consider using the /volumes endpoint instead of /transactions when you need balance information. The /volumes endpoint provides efficient access to account balances and can be used with parameters like pit (point in time), start-endTime, and groupBy.

Performance considerations

When querying transactions, keep these performance tips in mind:

  • Using the expand=effectiveVolumes parameter can impact performance.

  • Use specific account matching (e.g., "source" or "destination") instead of the general "account" matcher when appropriate.

  • Limit the use of metadata filters, as they can affect query performance.

By following these practices, you can maintain accurate balances and efficient queries when working with transaction reverts in Formance.

Here is a simple example revert atEffectiveDate usage

TxId | In 	| Out 	| Balance
-----------------------------
1	 |	0 	| 10000 | - 10000
2	 |	500 | 0  	| -  9500
3	 |	250	| 0		| -	 9250
4	 |	0	| 500	| -	 9750 <-- Revert - no atEffectiveDate

Statement Produced with reverts and reverted filtered out
In the example above, tx4 is the revert and tx2 is the reverted

TxId | In 	| Out 	| Balance
-----------------------------
1	 |	0 	| 10000 | - 10000
3	 |	250	| 0		| -	 9250 <-- Incorrect balance!

We would expect to have balance after tx3 impacted by the revert.
To do so, we simply need to revert, using parameter atEffectiveDate=true

TxId | In 	| Out 	| Balance
-----------------------------
1	 |	0 	| 10000 | - 10000
2	 |	500 | 0  	| -  9500
4	 |	  0 | 500  	| - 10000 (atEffectiveDate=true)
3	 |	250	| 0		| -	 9750 <-- Balance OK