Verify Prior Ledger States
How to verify prior ledger states
Immutability is one of the most important guarantees from a ledger.
At Modern Treasury, we guarantee immutability by keeping track of the historical changes whenever a Ledger object is updated, which is backed by a series of immutable event logs. In this guide we will walk through how to verify prior ledger states by auditing historical changes to a Ledger object.
Ledger Transaction History
Ledger Transactions record money movements between Ledger Accounts. Throughout the life cycle of a Ledger Transaction, each modification generates a new Ledger Transaction Version with an incremental version number starting from zero.
A Ledger Transaction can be updated when the status is pending
, but once it transitions to the final status posted
or archived
, it can no longer be changed.
Ledger Entries of a pending Ledger Transaction can also be updated. In order to guarantee immutability, the old Ledger Entries are discarded while new Ledger Entries are created. The Ledger Transaction Version object not only stores the top level Transaction attributes like description
, status
, metadata
, it also captures the historical Ledger Entry values when the change happened.
Querying Ledger Transaction Versions
The Versions of a Ledger Transaction can be retrieved by sending a request to the List Ledger Transaction Versions endpoint:
curl --request GET \
--url https://app.moderntreasury.com/api/ledger_transactions/d376dd4e-1c4f-4ba2-9b13-db63c04471e0/versions
The API response contains a list of historical values of the Ledger Transaction, sorted by version
in descending order. Each Version also includes the Ledger Entries attached to the Transaction at the time when the Version was created:
[
{
"id": "b3ea66d8-ffa9-44e6-96d2-591cdb998a5e",
"ledger_transaction_id": "d376dd4e-1c4f-4ba2-9b13-db63c04471e0",
"object": "ledger_transaction_version",
"ledgerable_type": null,
"ledgerable_id": null,
"ledger_id": "a9d970da-207e-43da-b4d6-6e9ae01ba2cc",
"description": "Restaurant bill",
"status": "posted",
"ledger_entries": [
{
"id": "0bbdf6db-2378-449f-b731-0409c14f270c",
"object": "ledger_entry",
"amount": 5000,
"direction": "credit",
"status": "posted",
"ledger_account_id": "063da2e3-4a37-4abf-8626-57d25bd6d441",
"ledger_account_currency": "USD",
"ledger_account_currency_exponent": 2,
"ledger_account_lock_version": 5,
"ledger_transaction_id": "d376dd4e-1c4f-4ba2-9b13-db63c04471e0",
"resulting_ledger_account_balances": null,
"live_mode": true,
"created_at": "2022-10-15T16:58:51Z",
"updated_at": "2022-10-15T16:58:51Z"
},
{
"id": "5f6a2fe9-502c-439a-a475-2af09b8836ef",
"object": "ledger_entry",
"amount": 5000,
"direction": "debit",
"status": "posted",
"ledger_account_id": "f1c7e474-e6d5-4741-9f76-04510c8b6d7a",
"ledger_account_currency": "USD",
"ledger_account_currency_exponent": 2,
"ledger_account_lock_version": 5,
"ledger_transaction_id": "d376dd4e-1c4f-4ba2-9b13-db63c04471e0",
"resulting_ledger_account_balances": null,
"live_mode": true,
"created_at": "2022-10-15T16:58:51Z",
"updated_at": "2022-10-15T16:58:51Z"
}
],
"posted_at": "2022-10-15T16:58:51Z",
"effective_at": "2022-09-30T16:58:51Z",
"metadata": {},
"live_mode": true,
"created_at": "2022-10-15T16:58:51Z",
"version": 10
},
...
]
Versions can be queried by their created_at timestamps. For example, to find the Ledger Transaction changes between 9am and 6pm UTC on Oct 21st, you would add query parameters created_at[gte]=2022-10-21T09:00:00Z&created_at[lte]=2022-10-21T18:00:00Z
:
curl --request GET \
--url https://app.moderntreasury.com/api/ledger_transactions/d376dd4e-1c4f-4ba2-9b13-db63c04471e0/versions&created_at[gte]=2022-10-21T09:00:00Z&created_at[lte]=2022-10-21T18:00:00Z
Versions can also be queried by a version number range. For example, if you’d like to see what a Ledger Transaction looked like when it was first created, you would add query parameter version[eq]=0
:
curl --request GET \
--url https://app.moderntreasury.com/api/ledger_transactions/d376dd4e-1c4f-4ba2-9b13-db63c04471e0/versions&version[eq]=0
Ledger Account Balance History
A Ledger Account has a lock_version
field which increments when the pending or posted balance of the Ledger Account changes. Note that you can add Ledger Entries to a Ledger Account with an arbitrary or past effective_at
timestamp, but the lock_version
of the Ledger Account will always increment upward upon updating the account.
Querying Ledger Entries
In order to find out which Ledger Entry contributed to a certain Ledger Account lock_version
, you can send a request to the List Ledger Entries endpoint with ledger_account_id
and ledger_account_lock_version
query parameters.
As mentioned earlier, in order to guarantee immutability, previous Ledger Entries are replaced with the new ones upon editing, which is why we pass an extra query parameter, show_deleted=true
:
curl --request GET \
--url 'https://app.moderntreasury.com/api/ledger_entries?ledger_account_id=063da2e3-4a37-4abf-8626-57d25bd6d441&ledger_account_lock_version=5&show_deleted=true'
The API response contains the Ledger Entries of the ledger_account_lock_version
:
[
{
"id": "b5cecf80-93ff-4e2a-8f37-fa5687a14837",
"object": "ledger_entry",
"live_mode": true,
"amount": 6000,
"direction": "credit",
"ledger_account_id": "063da2e3-4a37-4abf-8626-57d25bd6d441",
"ledger_account_currency": "USD",
"ledger_account_currency_exponent": 2,
"ledger_account_lock_version": 5,
"ledger_transaction_id": "d376dd4e-1c4f-4ba2-9b13-db63c04471e0",
"discarded_at": "2022-10-12T17:32:22Z",
"created_at": "2022-10-11T19:40:59Z",
"updated_at": "2022-10-12T17:32:22Z"
}
]
Querying Account Balance
When a Ledger Entry with an effective_at
timestamp is added to a Ledger Account, it affects the balance on and after the effective_at
timestamp.
For example, at 6pm UTC on Oct 1st, some Ledger Entries are added with a backdated effective_at
of September 30th 6pm UTC. On Oct 15th, you decide to check if the balances as of September 30th have changed. You would send a request to the Get Ledger Account endpoint with a query parameter balances[effective_at]
:
curl --request GET \
--url https://app.moderntreasury.com/api/ledger_accounts/09fa6c2e-ab3e-42c8-86dd-6afbe7ef05ae?balances%5Beffective_at%5D=2022-09-30T18:00:00Z
The balances in the response are the sum of all the Ledger Entries that are currently recorded in the system with effective_at less than or equal to 2022-09-30T18:00:00Z.
{
"id": "09fa6c2e-ab3e-42c8-86dd-6afbe7ef05ae",
"object": "ledger_account",
"name": "Alice's account",
"ledger_id": "a9d970da-207e-43da-b4d6-6e9ae01ba2cc",
"description": "Alice's account",
"lock_version": 5,
"normal_balance": "credit",
"balances": {
"pending_balance": {
"credits": 50000,
"debits": 10000,
"amount": 40000,
"currency": "USD",
"currency_exponent": 2
},
"posted_balance": {
"credits": 20000,
"debits": 1000,
"amount": 19000,
"currency": "USD",
"currency_exponent": 2
},
"available_balance": {
"credits": 20000,
"debits": 10000,
"amount": 10000,
"currency": "USD",
"currency_exponent": 2
}
},
"metadata": {},
"live_mode": true,
"created_at": "2022-08-04T16:54:32Z",
"updated_at": "2022-08-04T16:54:32Z"
}
Updated 6 months ago