Below are two different integration strategies for creating a digital wallet using Ledgers. Event Handlers allow you to stream information to be ledgered based on previously-created handler templates. The Transactions API gives you full control over when and how you ledger activity.

TAB-Event Handlers

# Overview

You have a wallet product. You want to support top ups and track how much each user has topped up as well as their wallet balance. Therefore, every user has two ledger accounts: their wallet balance (credit normal) and their topped up balance (debit normal).

To associate users and to identify which ledger account corresponds to what type (wallet or top up), you would use `metadata` tags such as:



## Ledger Event Handler

`POST /api/ledger_event_handlers`

Assuming you have the accounts set up, you first setup the **Ledger Event Handler** handling the top-up portion of the functionality:

### Example Request



### Example Response



The Event Handler describes how to transform a ledgerable event (single entry) into the ledger transaction (double entry) through the `ledger_transaction_template` field. In this case, we require two ledger accounts: the `“wallet”` and `“top_up”` accounts for that particular user. These can be accessed by writing a query within the `variables` field. Each variable is a map of `name -> (object_type, query)`. The `object_type` is `ledger_account`, and the query specifies a metadata search.

## Ledgerable Event

`POST /api/ledgerable_events`

To leverage the event handler, we now need a **Ledgerable Event** representing the top-up:

### Example Request



### Example Response



A Top Up of `$15 USD` occurs. The name matches to the `conditions` field of the Event Handler. The Event Handler is able to extract the necessary fields it needs from the Ledgerable Event to query the DB for the relevant tables, and then create the LT:

### Ledger Transaction



Engineers creating Ledgerable Events do not need to know how the Event Handler translates single entry to a ledger transaction.

As an example, you now enforce a flat $1 fee for top-ups and want to track overall how many fees have been paid per user, as well as across your product. The ledgerable event does not change, but you leverage your new accounts with a new event handler:

### Example Request



A new `conditions` query needs to be used to avoid ledgerable events matching to two event handlers (which is not allowed). Clients may control rollout of using the new event handler by controlling the name of the event.

TAB-Transactions API

# Overview

Technology companies with products that move money often need to hold balances for users or external counterparties. For example, your app might allow users to deposit funds into a wallet from which they can invest, or it might let your vendors accumulate points in a rewards wallet. This is a common use case across fintech, marketplaces, vertical SaaS, and e-commerce. Any time balances are being held, a unified data store is required to keep track of transactions and balances.

Ledgers is such a data store - an immutable financial database that allows companies to hold balances at scale.

This tutorial will explain how to use the [Ledgers API](🔗) for a digital wallet. In this example, we will assume you are building a service called SendCash that allows users to deposit money and send it to their friends. We will demonstrate a simple flow here with 3 payments:

  • A user deposits money in their wallet

  • The user sends money to a friend's wallet

  • The friend withdraws money

Additionally, there are some questions SendCash might ask, such as:

  • How much money does this user have in their SendCash account?

  • How much cash is in my bank account that holds all my user funds?

In order to facilitate these payment flows and be able to answer these questions, we will set up a ledger that has 3 ledger accounts.

  • Cash in SendCash's bank account

  • Funds held for a given user, Jane Doe

  • Funds held for another given user, John Doe

## Who is this guide for

We assume you are a company interested in spinning up digital wallets as part of your product offering. This guide explains how to use Ledgers as the underlying infrastructure to power such digital wallets, and it is divided in three parts.

  • First, we will create a sample **chart of accounts**. Accounts are the balances your platform will track (more detail in our [guide to ledger objects](🔗)).

  • Next, we will work through a sample set of **transactions**. As business events happen in your digital wallet platform, you can use the guidance here to define how to write these transactions in the ledger. Transactions are logged in the ledger with the `create ledger transaction` endpoint. For sample API calls, review our [quickstart guide for digital wallets](🔗).

  • Finally, we’ll discuss the use of metadata, transaction timing, account categories, and other features that can be helpful to any company launching a digital wallet.

# Step 1. Designing Your Chart of Accounts

Ledgers implements double-entry accounting concepts. This ensures scalable consistency. If you are not familiar with debits and credits, start with our [guide to debits and credits](🔗). We also recommend reviewing our [guide to Ledgers Objects,](🔗) as it explains ledger accounts, transactions, and categories in detail.

Balances are tracked on Ledgers by way of ledger accounts. Implementing a digital wallet requires the following set of accounts:

  • **User balance accounts**, which track balances exposed to users;

  • **Cash accounts**, which track cash positions associated with your digital wallet product;

  • **Expense accounts** such as fees, which track expenses incurred in your digital wallet product;

  • **Revenue accounts** which track different revenue streams captured by your digital wallet product;

## User Balance Accounts

User balance accounts are credit normal accounts that track user balances. These are credit normal accounts because they represent funds your platform owes - or sources of funds. (For more, read our [guide to debits and credits](🔗)).

Your platform needs one ledger account per user. New accounts can be created using the [create ledger account](🔗) endpoint. Accounts can be enriched with free-form metadata. Here is a sample user balance account:

Account NameNormalityRepresentsIncreased By (Credits)Decreased By (Debits)Sample Metadata
User #1241241 BalanceCredit NormalBalance for user Robert Dylan.User deposits or credits.User withdrawals, fees.\`accountType: "User Balance", userFirstName: "Bob", userLastName: "Dylan", userState: "NY", userActive: yes\`

## Cash Accounts

Cash accounts track different cash positions associated with the digital wallet app. They are debit normal given they represent funds your platform owns.

There are many different cash positions you might want to track in your digital wallet app:

  • Reserve funds that represent cash that needs to be available to users for withdrawals;

  • Operating cash accounts that represent pools of funds you direct income to and deduct expenses from;

  • Any other cash pools tied to operational or regulatory requirements.

Here is a sample cash account:

Account NameNormalityRepresentsIncreased By (Debits)Decreased By (Credits)Sample Metadata
SendCash Operating Cash AccountDebit NormalOverall cash position of SendCash appCash inflows of any kindCash outflows of any kind`accountType: "Cash Omnibus", active: yes`

## Expense Accounts

Expense accounts track expenses incurred in the regular operation of the digital wallet app. These can be debit normal when they represent expenses **_paid_** (as they reflect money outflows in a regular course of business) and credit normal when they represent expenses **_due_** (as they reflect payables).

A few types of expense accounts include:

  • Card fees incurred in the event of an account deposit or withdrawal;

  • Any taxes or fees to third parties paid on balances or transfers in the platform;

  • Banking fees associated with specific transactions.

Here is a sample expense account:

Account NameNormalityRepresentsIncreased By (Debits)Decreased By (Credits)Sample Metadata
Credit card fees paidDebit NormalTotal paid in credit card feesNew credit card fees paidTypically not decreased unless in the event of an adjusting entry`accountType: expense`
Payable tor vendor XCredit NormalBalance due to vendor XNew amounts are recorded as due to vendor XPayouts`accountType: expense`, `vendor: X`

We recommend holding payable balances only if necessary and using debit normal expense accounts to tally up expenses incurred whenever possible.

## Revenue Accounts

Revenue accounts are counter to expense accounts and represent money inflows categorized as revenue by your digital wallet app. They are always credit normal accounts.

Different revenue accounts can be created to differentiate between revenue streams. Here are a few examples:

Account NameNormalityRepresentsIncreased By (Credits)Decreased By (Debits)Sample Metadata
Revenue from deposit feesCredit NormalRevenue incurred when users deposit funds in the appDepositsTypically ledger adjustments`accountType: revenue`, `revenueStream: deposit_fees`
Revenue from transfer feesCredit NormalRevenue incurred when users transfer funds from each other in the platformUser to user transfersTypically ledger adjustments`accountType: revenue`, `revenueStream: transfer_fees`

# Step 2. Defining Transaction Logic

With a set of accounts mapped out, the next step is define transaction logic for your digital wallet app. The table below shows the most common transactions happening in a digital wallet app and how they get recorded on Ledgers.

We will walk through the following flows:

  • Deposit: a user adds money to their digital wallet account;

  • In-app transfer: two users send money to each other;

  • Withdrawal: user takes money out of their balance. In this example we will assume your app charges a 2% fee on withdrawals, which is recognized as revenue;

For a refresher on account normality and how debits and credits work review our [guide to debits and credits](🔗).

Sample TransactionDebited AccountsCredited AccountsNotes
DepositCash account (increase)User balance account (increase)As a user deposits in their balance, we capture the increase in cash and corresponding increase in the user balance.
In-App TransferSender user balance account (decrease)Receiver user balance account (increase)A transfer from user A to user B will deduct the sender balance and increase the receiver's. There is no actual money movement in this transaction, it's simply a ledger mutation.
WithdrawalUser balance account (decrease)Cash account (decrease); Revenue from fees (increase)This is the inverse flow to a deposit, with the exception that 2% of the withdrawal would be recognized as a revenue.

Your application code would handle transactions appropriately write them into the ledger according to the guidance presented above. Our team can help you structure your transaction rules in a way that meets your product requirements and optimizes database performance.

# Step 3. Defining metadata, categories, and transaction timing

With your chart of accounts and overall transaction schema mapped out, a few important questions remain.

**Metadata** Ledgers supports free-form metadata in the form of key-value pairs. Common metadata fields seen amongst digital wallet customers include:

ObjectMetadata
ledger`productID`
ledger account`walletID`; `userId`; `accountType`
ledger transaction`transactionType`
ledger account category`categoryType`

Ledgers supports querying based on metadata. Any time objects refer to an important concept, it’s helpful to tag them with relevant metadata. By using the [list ledger transactions](🔗) endpoint to query all accounts associated with user wallet #31512, for instance, the system will return all the transactions that modified this account.

**Categories** As mentioned before, categories are aggregations at the account level. Categories group multiple accounts. The balance in an account category is equal to the sum of the balances of the accounts within it.

A common category for digital wallets is a `user balances` grouping, which aggregate the overall balance held in user wallets according to a pre-defined criteria. Read more about categories [here](🔗).

**Transaction timing** Ledgers supports multi-state transactions. Transactions in the ledger can have one of the following status values: pending, posted, or archived.

Digital wallet companies might choose to leave transactions at a pending status until a certain condition is met. For instance: a user may execute a deposit in your digital wallet via ACH but you decide to only take the transaction into account once it clears. You can choose to represent these balances as **pending** until transactions are finalized, at which point they would become **posted**. Once posted, they are immutable.

Each account will have one of three balances: **posted** (sum of all posted entries), **pending** (sum of posted and pending entries), and **available** (sum of all posted entries minus outgoing pending entries).

Finally, Ledgers supports back and future dating in the form of an `effective_date` field on the `ledger transaction` object. This gives you the flexibility to differentiate between posted dates and effective dates for reporting purposes, as well as include future events in the ledger.

# Step 4. Setup your ledger

First, we will make a ledger.



This will return a ledger object with an ID to be used in the following step.



Next, we will create the 3 ledger accounts described above. Note that the bank account is `normal_balance=debit` (because it represents a balance that we hold), whereas the user wallet accounts are `normal_balance=credit` (because they represent balances that we owe).



This will return the 3 ledger accounts you've created.



# Step 5. Record transactions

Now that the setup is done, you can write to the ledger to record what happens in your business.

First, we can create a ledger transaction to record that Jane Doe has deposited $100 in her wallet. This will recognize that $100 has entered our bank account, and that $100 of funds are held on behalf of Jane.



Next, Jane uses our app to send $50 to John Doe's wallet. No cash transfer has to occur; we simply record that a portion of the cash that we are holding is owed to a different user. We can create the ledger transaction to record this transfer of funds across accounts.



Finally, John Doe withdraws $50 from his wallet. We can create a ledger transaction recording that $50 has left our bank account, and that $50 is no longer held on behalf of John.



# Step 6. Read balances

The ledger is a consistent source of truth for your user transactions and balances at scale. For example, you can query the ledger for a user's wallet balance in order to display it in your app.

When Jane wants to see her wallet balance, your app can query the Ledgers API:



This will return Jane's live wallet balance, which you can display in your app.