Quickstart for Digital Wallets

Overview

This guide 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

Setup

First, we will make a ledger.

curl --request POST \
  -u ORGANIZATION_ID:API_KEY \
  --url https://app.moderntreasury.com/api/ledgers \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "SendCash Ledger",
    "description": "Represents our USD funds and user balances",
    "currency": "USD"
  }'

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

{
    "id": "89c8bd30-e06a-4a79-b396-e6c7e13e7a12",
    "object": "ledger",
    "name": "SendCash Ledger",
    "description": "Represents our USD funds and user balances",
    "currency": "USD",
    "active": true,
    "metadata": {},
    "live_mode": true,
    "created_at": "2020-08-04T16:48:05Z",
    "updated_at": "2020-08-04T16:48:05Z"
}

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).

curl --request POST \
  -u ORGANIZATION_ID:API_KEY \
  --url https://app.moderntreasury.com/api/ledger_accounts \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Cash Account",
    "description": "Tracks our cash",
    "normal_balance": "debit",
    "ledger_id": "89c8bd30-e06a-4a79-b396-e6c7e13e7a12"
  }'
  
curl --request POST \
  -u ORGANIZATION_ID:API_KEY \
  --url https://app.moderntreasury.com/api/ledger_accounts \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Jane Doe Wallet",
    "description": "Tracks balance held on behalf of Jane Doe",
    "normal_balance": "credit",
    "ledger_id": "89c8bd30-e06a-4a79-b396-e6c7e13e7a12"
  }'

curl --request POST \
  -u ORGANIZATION_ID:API_KEY \
  --url https://app.moderntreasury.com/api/ledger_accounts \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "John Doe Wallet",
    "description": "Tracks balance held on behalf of John Doe",
    "normal_balance": "credit",
    "ledger_id": "89c8bd30-e06a-4a79-b396-e6c7e13e7a12"
  }'

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

{
    "id": "f1c7e474-e6d5-4741-9f76-04510c8b6d7a",
    "object": "ledger_account",
    "name": "Cash Account",
    "ledger_id": "89c8bd30-e06a-4a79-b396-e6c7e13e7a12",
    "description": "Tracks our cash",
    "normal_balance": "debit",
    "active": true,
    "metadata": {},
    "live_mode": true,
    "created_at": "2020-08-04T16:54:32Z",
    "updated_at": "2020-08-04T16:54:32Z"
}

{
    "id": "61574fb6-7e8e-403e-980c-ff23e9fbd61b",
    "object": "ledger_account",
    "name": "Jane Doe Wallet",
    "ledger_id": "89c8bd30-e06a-4a79-b396-e6c7e13e7a12",
    "description": "Tracks balance held on behalf of Jane Doe",
    "normal_balance": "credit",
    "active": true,
    "metadata": {},
    "live_mode": true,
    "created_at": "2020-08-04T16:54:32Z",
    "updated_at": "2020-08-04T16:54:32Z"
}

{
    "id": "463237a4-a93d-4396-9be8-5bacb8ceead1",
    "object": "ledger_account",
    "name": "John Doe Wallet",
    "ledger_id": "89c8bd30-e06a-4a79-b396-e6c7e13e7a12",
    "description": "Tracks balance held on behalf of John Doe",
    "normal_balance": "credit",
    "active": true,
    "metadata": {},
    "live_mode": true,
    "created_at": "2020-08-04T16:54:32Z",
    "updated_at": "2020-08-04T16:54:32Z"
}

Recording 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.

curl --request POST \
  -u ORGANIZATION_ID:API_KEY \
  --url https://app.moderntreasury.com/api/ledger_transactions \
  -H 'Content-Type: application/json' \
  -d '{
    "description": "Jane Doe cash deposit",
    "effective_date": "2020-08-27",
    "status": "posted",
    "external_id": "97dbb8b1-e6f2-485e-a0ec-6267e3c60718",
    "ledger_entries": [
      {
        "amount": 10000,
        "direction": "debit",
        "ledger_account_id": "f1c7e474-e6d5-4741-9f76-04510c8b6d7a"
      },
      {
        "amount": 10000,
        "direction": "credit",
        "ledger_account_id": "61574fb6-7e8e-403e-980c-ff23e9fbd61b"
      }
    ] 
  }'

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 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.

curl --request POST \
  -u ORGANIZATION_ID:API_KEY \
  --url https://app.moderntreasury.com/api/ledger_transactions \
  -H 'Content-Type: application/json' \
  -d '{
    "description": "Jane Doe wallet transfer to John Doe",
    "effective_date": "2020-08-29",
    "status": "posted",
    "external_id": "c006a6df-72ff-4cbf-aa4a-c18dde4b05c5",
    "ledger_entries": [
      {
        "amount": 5000,
        "direction": "credit",
        "ledger_account_id": "463237a4-a93d-4396-9be8-5bacb8ceead1"
      },
      {
        "amount": 5000,
        "direction": "debit",
        "ledger_account_id": "61574fb6-7e8e-403e-980c-ff23e9fbd61b"
      }
    ]
  }'

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.

curl --request POST \
  -u ORGANIZATION_ID:API_KEY \
  --url https://app.moderntreasury.com/api/ledger_transactions \
  -H 'Content-Type: application/json' \
  -d '{
    "description": "John Doe cash withdrawal",
    "effective_date": "2020-08-30",
    "status": "posted",
    "external_id": "a9a7fd22-8922-498a-b8b3-def4df72d5e4",
    "ledger_entries": [
      {
        "amount": 5000,
        "direction": "credit",
        "ledger_account_id": "f1c7e474-e6d5-4741-9f76-04510c8b6d7a"
      },
      {
        "amount": 5000,
        "direction": "debit",
        "ledger_account_id": "463237a4-a93d-4396-9be8-5bacb8ceead1"
      }
    ]
  }'

Reading 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:

curl --request GET \
  -u ORGANIZATION_ID:API_KEY \
   --url https://app.moderntreasury.com/api/ledger_accounts/61574fb6-7e8e-403e-980c-ff23e9fbd61b

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

{
  "id":"61574fb6-7e8e-403e-980c-ff23e9fbd61b",
  "object":"ledger_account",
  "live_mode":true,
  "name":"Jane Doe Wallet",
  "ledger_id": "89c8bd30-e06a-4a79-b396-e6c7e13e7a12",
  "description": "Tracks balance held on behalf of Jane Doe",
  "lock_version":2,
  "normal_balance":"credit",
  "balances":{
    "pending_balance":{
      "credits":10000
      "debits":5000
      "amount":5000
      "currency":"USD"
    },
    "posted_balance":{
      "credits":10000
      "debits":5000
      "amount":5000
      "currency":"USD"
    }
  },
  "metadata":{},
  "discarded_at":NULL,
  "created_at": "2020-08-04T16:54:32Z",
  "updated_at": "2020-08-04T17:23:12Z"
}

Did this page help you?