Ledger Account Settlements Overview

How to use ledger account settlements to offset balances

When a Ledger Transaction is created, its Ledger Entries are added to the corresponding Ledger Accounts. Each Ledger Account accumulates many Ledger Entries over time, which contributes to the Account’s balance increase. As a result, it makes sense to pay out those Accounts in order to safely empty their balances. For example, a marketplace will pay a supplier the entire amount owed according to the supplier’s payables account balance.

Settlements are difficult to manage because Ledger Entries can be backdated into periods that had been paid out previously already. For example, when paying out a Ledger Account’s February balance in March, Ledger Entries with a January effective time could have been added during February after January’s settlement was completed. These Ledger Entries should be paid out in March instead of being left behind. Additionally, itemizing Ledger Entries to their corresponding Settlement for accounting is complex.

Using the ledger_account_settlement solves these problems by giving you out-of-the-box snapshotting and itemization functionality. A ledger_account_settlement is an object that creates a ledger transaction to safely offset the posted balance of a ledger account.

How Modern Treasury handles Ledger Account Settlements

Let’s use the same monthly settlement example mentioned earlier. As a marketplace platform user, you pay out the supplier’s payables accounts on a monthly basis. Say today is February 2nd and you would like to pay out a supplier’s ledger account, you’d create a ledger_account_settlement object through Modern Treasury’s Create Ledger Account Settlement API.

Behind the scenes, Modern Treasury uses the criteria you provided through the API to gather the Ledger Entries for this settlement and calculate the settlement amount for you. It also creates a Ledger Transaction that reduces the Account’s balance as a result. Each Ledger Entry can be included in at most one Ledger Account Settlement. This prevents you from paying out the same amount twice. The settlement amount is computed asynchronously so that there is no limit on how many Ledger Entries can be processed per Settlement.

Creating a Ledger Account Settlement

When creating a ledger account settlement, the settled ledger account's ledger entries are used to calculate the settlement amount, and its balance is reduced as a result. The contra ledger account is used to send or receive funds, depending on the normality of the accounts. Each ledger entry of the settled ledger account can only be included in one ledger account settlement, which prevents paying one ledger entry multiple times.

An optional effective_at_upper_bound can be provided as an extra threshold to decide which ledger entries the settlement should include. For example, say today is 02/05/23 and you are paying out Alice's January ledger entries, you'd specify the effective_at_upper_bound as 2023-02-01T00:00:00.000Z, this way the February ledger entries are excluded in this settlement. It also excludes any ledger entries that have been paid out already.

The status is set to pending by default, because the common workflow is to first create a pending ledger account settlement, then move money based on the settlement amount, and lastly set the settlement to posted. But setting status directly to posted is also an option.

Modern Treasury processes Ledger Account Settlements asynchronously

Once a ledger account settlement is created, its status is set to processing immediately. When a ledger account settlement is still being processed, its amount and ledger_transaction_id are null. Once a ledger account settlement is processed successfully, the status is updated to pending or posted based on the status provided when creating the settlement and its amount and ledger_transaction_id are now available. Since the status is updated by Modern Treasury, an ledger_account_settlement.finish_processing webhook event is emitted for the ledger account settlement.

Updating a Ledger Account Settlements

When a ledger account settlement is in pending status, it can be updated through the Update Ledger Account Settlement API. This is where you can set the settlement to posted as mentioned above. You can also set the settlement to archived if it was created by mistake. Once the settlement is archived successfully, the ledger entries are detached from the settlement, and they can be included in future settlements again.

Retrieving Settlement related data

The settlements themselves can be retrieved through the Get Ledger Account Settlement API and the List Ledger Account Settlement API. To retrieve the itemized Ledger Entries of the settlement, use the ledger_account_settlement_id as a query parameter of the List Ledger Entries API. To retrieve the itemized Ledger Transactions of the settlement, use the ledger_account_settlement_id as a query parameter of the List Ledger Transactions API.

Migrating to the Ledger Account Settlement API

If you have been tracking ledger account settlements through metadata, or outside Modern Treasury's system, this article provides solutions for migrating to the Ledger Account settlement API.

Create migration settlements

  1. Get a list of Ledger Accounts that you would like to pay out to. It's advised to start off with a small batch of Ledger Accounts first.

  2. For each Ledger Account:

    2.a. Create a Settlement through the POST /ledger_account_settlements API with an effective_at_upper_bound cursor. Assuming that these Ledger Entries have been paid out by you in the past already, the status should be set to posted, and the skip_settlement_ledger_transaction should be set to true so that the settled ledger account's balance will not be reduced by the migration settlement. Please feel free to give the settlement a description like “Settlement for migration purpose only”. Once the Settlement is created, please take notes of the Settlement’s created_at timestamp from the API response. Since this is the first time you are using the Settlements API, it will scoop up all the historical Ledger Entries and include them in this Settlement. As a result, the Settlement amount is for backfilling purpose only, and you should NOT move money for the initial Settlement.

// Example request:
// Say today is 2023-02-01 and you are about to pay out Alice's January ledger entries
{
    "description": "Alice's migration settlement",
    "settled_ledger_account_id": "d44ad0d0-b3ea-4698-867d-09fe961e52a6",
    "contra_ledger_account_id": "3824af4d-4151-48f6-8e8b-bf859cbddbcd",
    "effective_at_upper_bound": "2023-02-01T00:00:00Z",
    "status": "posted",
    "skip_settlement_ledger_transaction": true
  }

2.b. Even though Ledger Account Settlements are processed on Modern Treasury side asynchronously, since you do not care about the settlement amount during migration, you would not need to wait for the settlement finish_processing webhook before moving on to your routine settlement workflow.

2.c. For your routine settlement workflow, if you have been using effective_at to query the Ledger Entries or Ledger Transactions, you would set it to the same value as the Ledger Account Settlement's effective_at_upper_bound. If you have been using posted_at to query, you would use the Ledger Account Settlement's created_at as an inclusive upper bound of posted_at.

After these migration settlements, the future settlements on these accounts should reflect the correct settlement amount.

Double writing phase

  • Please make sure the settlements created in the previous step are in posted status instead of processing before moving forward. This can be done through consuming Modern Treasury's ledger_account_settlement.finish_processing webhook event, or by listing the settlements with pagination and check their status.
  • When next Settlement cycle comes around, you should repeat the steps above, but this time please also compare the Settlement amount for each Account. If any discrepancies found, please reach out to Modern Treasury to resolve it. One heads-up is, the Ledger Account API does not take an effective_at lower bound. It is designed to prevent missing pay out back-dated Ledger Entries. If this is the root cause of the discrepancies, it is actually the desired behavior to catch any issues in the existing system.

Switch-over phase

  • Create Settlements through the POST /ledger_account_settlements API for future Settlements. It is now the new source of truth.