Handling Concurrency
Overview
Every time you check a ledger account balance in your app, you get a snapshot of that balance at a moment in time. As money moves, you need to be confident that that snapshot is accurate even as balances are constantly shifting in real time.
To prevent a double-spend situation, your ledger needs to be able to record transactions that are conditional on the state of an account balance or account version. The Ledgers API provides both of these mechanisms.
Locking on account balance
When creating or updating a ledger transaction, you can send balance filters as part of a ledger entry to validate the balance of the corresponding ledger account if the current ledger transaction were created or updated. If this ledger transaction would cause the ledger account's current balance to go outside of the specified range, the request will fail with a 422.
The available types of balance filters are pending_balance_amount
, posted_balance_amount
, and available_balance_amount
and the balance may be filtered with gt
(>), gte
(>=), eq
(=), lte
(<=), and lt
(<).
Note balance filters consider every ledger entry on the corresponding ledger account, regardless of their effective_at
values.
For example, suppose you are recording a payment moving $1 out of a credit-normal user account. You can specify that the account's available_balance
must remain greater than or equal to $0 upon completion of the transaction:
curl --request POST \
--url https://app.moderntreasury.com/api/ledger_transactions \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"effective_at": "2022-01-01T00:00:00.000",
"status": "pending",
"ledger_entries": [{
"amount": 100,
"direction": "debit",
"available_balance_amount": { "gte": 0 },
"ledger_account_id": "89c8bd30-e06a-4a79-b396-e6c7e13e7a12"
}, {
"amount": 100,
"direction": "credit",
"ledger_account_id": "a30e5616-9408-4e5e-957a-bb0bcea5f0ce"
}]
}'
Using the lock_version field
You can specify a lock_version
when writing an entry to the ledger account. If the lock_version
specified is not the same as the current lock_version
of the ledger account balance, the transaction will fail to be created.
For example, suppose you are recording a payment paying out $10.32 from a credit-normal user account. You can specify that the transaction be written if and only if the ledger account has not been updated since you last checked its lock_version
:
curl --request POST \
--url https://app.moderntreasury.com/api/ledger_transactions \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"description": "Payout",
"effective_at": "2022-01-01T00:00:00.000",
"status": "pending",
"external_id": "97dbb8b1-e6f2-485e-a0ec-6267e3c60718",
"ledger_entries": [
{
"amount": 1032,
"direction": "debit",
"lock_version": 5
}
]
}'
If the lock_version
of your ledger account balance is not 5, meaning there has been another entry written to the account since lock_version
5, the transaction will fail.
Updated 5 months ago