> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blnkfinance.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Building a Wallet Management System

> Learn how to implement a complete wallet management system with Blnk.

## Overview

This tutorial will guide you through implementing a simple wallet management system using the Blnk Ledger. By the end, you'll have built a system that can:

1. Create customer wallets.
2. Link wallets to customer identities.
3. Support deposits and withdrawals from wallets.
4. Create purpose-specific wallets (e.g. card balances).
5. Enable transfers between wallets.

For this tutorial, we’ll use the [Blnk TypeScript SDK](/sdks/typescript/introduction) for the implementation. If you prefer, you can also refer to the [API reference](/reference/create-ledger) for details on the available endpoints.

***

## Designing your map

Before writing code, it's crucial to design a [money movement map](/ledgers/money-movement-map) that outlines how money moves in your system. This serves as the blueprint for your implementation.

For our wallet management system, here's how funds will flow:

<img src="https://mintcdn.com/blnk/jKiGmb7nTD9y-R5a/images/tutorials/wallet-management-map.png?fit=max&auto=format&n=jKiGmb7nTD9y-R5a&q=85&s=c0a3140509743435637d443a0c4675eb" alt="Wallet management map" width="1121" height="420" data-path="images/tutorials/wallet-management-map.png" />

[Explore the map yourself here](https://map.blnkfinance.xyz/1R830Knmgh)

This map shows three key components:

* `@World`: Represents external funding sources and withdrawal destinations.
* `Main Wallet`: The customer's primary wallet for deposits and withdrawals.
* `Card Wallet`: A second wallet for card-related transactions.

From our map, we can verify that:

* Customers can deposit money from external sources to their main wallet.
* Customers can withdraw money from their main wallet to external destinations.
* Customers can transfer money from their main wallet to their card wallet.

***

## Set up your implementation

Based on our map, we'll implement the following steps:

1. Create a customer ledger to organise all customer wallets.
2. Create customer identity for storing user information.
3. Create a main wallet and link it to the identity.
4. Implement deposit functionality.
5. Implement withdrawal functionality.
6. Create a card wallet and link it to the same identity.
7. Fund the card wallet from the main wallet.

***

## Prerequisites

Before starting, ensure you have:

1. A running Blnk Core instance (e.g. at `http://localhost:5001`).
2. An API key for Blnk (replace `YOUR_API_KEY` in the code examples). Required for authenticated requests.
3. Optionally, you can connect your Blnk Core to your [Blnk Cloud](https://cloud.blnkfinance.com) workspace to view your ledger data.

***

## Create customer ledger

First, we need to initialise Blnk and [create a ledger](/ledgers/introduction) to organise all customer wallets — main and card wallets.

<Tip>
  You can also create separate ledgers for different wallet types, e.g., `Customer Main Ledger` and `Customer Card Ledger`, to keep your balances more organized.
</Tip>

```javascript Initialising Blnk theme={"system"}
const { BlnkInit } = require('@blnkfinance/blnk-typescript');

let blnkInstance = null;

async function getBlnkInstance() {
  if (!blnkInstance) {
    blnkInstance = await BlnkInit('', { baseUrl: 'http://localhost:5001' });
  }
  return blnkInstance;
}
```

<CodeGroup>
  ```javascript TypeScript theme={"system"}
  async function createCustomerLedger() {
    const blnk = await getBlnkInstance();
    const { Ledgers } = blnk;
    
    const customerLedger = await Ledgers.create({
      name: "Customer Wallets Ledger",
      meta_data: {
        description: "Ledger for managing customer wallets",
        application: "Wallet Management System"
      }
    });
    
    console.log("Customer Ledger created:", customerLedger.data.ledger_id);
    return customerLedger.data.ledger_id;
  }
  ```

  ```bash cURL theme={"system"}
  curl --request POST \
    --url http://localhost:5001/ledgers \
    --header 'X-blnk-key: <api-key>' \
    --header 'Content-Type: application/json' \
    --data '{
      "name": "Customer Wallets Ledger",
      "meta_data": {
          "description": "Ledger for managing customer wallets",
          "application": "Wallet Management System"
      }
    }'
  ```
</CodeGroup>

<Warning>
  Always save the `ledger_id` in your database. You'll use this ID to create balances for the customer wallets.
</Warning>

***

## Create customer identity

Create your customer profiles with [identities](/identities/introduction):

<CodeGroup>
  ```javascript TypeScript theme={"system"}
  async function createCustomerIdentity(customerData) {
    const blnk = await getBlnkInstance();
    const { Identities } = blnk;
    
    const identity = await Identities.create({
      identity_type: "individual",
      first_name: customerData.firstName,
      last_name: customerData.lastName,
      email_address: customerData.email,
      phone_number: customerData.phone,
      meta_data: {
        customer_id: customerData.customerId,
        registration_date: new Date().toISOString()
      }
    });
    
    console.log("Customer Identity created:", identity.data.identity_id);
    return identity.data.identity_id;
  }
  ```

  ```bash cURL theme={"system"}
  curl --request POST \
    --url http://localhost:5001/identities \
    --header 'X-blnk-key: <api-key>' \
    --header 'Content-Type: application/json' \
    --data '{
      "identity_type": "individual",
      "first_name": "Alice",
      "last_name": "Johnson",
      "email_address": "alice@example.com",
      "phone_number": "+1234567890",
      "meta_data": {
          "customer_id": "CUST-001",
          "registration_date": "2024-02-25T10:30:00Z"
      }
    }'
  ```
</CodeGroup>

<Warning>
  Always save the `identity_id` in your database. You'll use this ID to link balances to this identity or query all balances owned by this identity.
</Warning>

***

## Create main wallet

[Create a balance](/balances/introduction) to represent the customer main wallet and link to the customer identity:

<CodeGroup>
  ```javascript TypeScript theme={"system"}
  async function createMainWallet(ledgerId, identityId, currency) {
    const blnk = await getBlnkInstance();
    const { LedgerBalances } = blnk;
    
    const mainWallet = await LedgerBalances.create({
      ledger_id: ledgerId,
      identity_id: identityId,
      currency: currency,
      meta_data: {
        wallet_type: "main",
        purpose: "general",
        status: "active"
      }
    });
    
    console.log("Main Wallet created:", mainWallet.data.balance_id);
    return mainWallet.data.balance_id;
  }
  ```

  ```bash cURL theme={"system"}
  curl --request POST \
    --url http://localhost:5001/balances \
    --header 'X-blnk-key: <api-key>' \
    --header 'Content-Type: application/json' \
    --data '{
      "ledger_id": "<customer-wallets-ledger-id>",
      "identity_id": "<customer-identity-id>",
      "currency": "USD",
      "meta_data": {
          "wallet_type": "main",
          "purpose": "general",
          "status": "active"
      }
    }'
  ```
</CodeGroup>

<Warning>
  Always store the `balance_id` in your database and associate it with the customer. You'll use this ID for all future transactions involving this wallet.
</Warning>

***

## Funding the main wallet

Use an [internal balance](/balances/internal-balances) to represent external deposit sources—such as bank accounts, cards, and other funding methods—responsible for funding a customer's wallet:

<CodeGroup>
  ```javascript TypeScript theme={"system"}
  async function depositToWallet(customerBalanceID, amount, uniqueReference, description) {
    const blnk = await getBlnkInstance();
    const { Transactions } = blnk;
    
    const deposit = await Transactions.create({
      amount: amount,
      precision: 100,
      reference: uniqueReference,
      description: description || "Deposit to wallet",
      currency: "USD",
      source: "@WorldUSD",
      destination: customerBalanceID,
      allow_overdraft: true, // Enable for the external source
      meta_data: {
        transaction_type: "deposit",
        channel: "bank_transfer"
      }
    });
    
    console.log("Deposit transaction created:", deposit.data.transaction_id);
    return deposit.data.transaction_id;
  }
  ```

  ```bash cURL theme={"system"}
  curl --request POST \
    --url http://localhost:5001/transactions \
    --header 'X-blnk-key: <api-key>' \
    --header 'Content-Type: application/json' \
    --data '{
      "amount": 1000,
      "precision": 100,
      "reference": "DEP-20250225-103000",
      "description": "Initial deposit",
      "currency": "USD",
      "source": "@WorldUSD",
      "destination": "<customer-main-balance-id>",
      "allow_overdraft": true,
      "meta_data": {
          "transaction_type": "deposit",
          "channel": "bank_transfer"
      }
    }'
  ```
</CodeGroup>

<Note>
  Setting `allow_overdraft` to `true` enables the transaction to proceed even if the source balance lacks sufficient funds.
</Note>

***

## Withdrawals from the main wallet

You can use the same internal balance to represent external withdrawal destinations to ensure it is balances out your ledger, or you can allocate a separate internal balance specifically for withdrawals.

<CodeGroup>
  ```javascript TypeScript theme={"system"}
  async function withdrawFromWallet(customerBalanceID, amount, uniqueReference, description) {
    const blnk = await getBlnkInstance();
    const { Transactions, LedgerBalances } = blnk;
    
    const withdrawal = await Transactions.create({
      amount: amount,
      precision: 100,
      reference: uniqueReference,
      description: description || "Withdrawal from wallet",
      currency: "USD",
      source: customerBalanceID,
      destination: "@WorldUSD",
      meta_data: {
        transaction_type: "withdrawal",
        channel: "bank_transfer"
      }
    });
    
    console.log("Withdrawal transaction created:", withdrawal.data.transaction_id);
    return withdrawal.data.transaction_id;
  }
  ```

  ```bash cURL theme={"system"}
  curl --request POST \
    --url http://localhost:5001/transactions \
    --header 'X-blnk-key: <api-key>' \
    --header 'Content-Type: application/json' \
    --data '{
      "amount": 100,
      "precision": 100,
      "reference": "WDR-20250225-104500",
      "description": "Wallet withdrawal",
      "currency": "USD",
      "source": "<customer-main-balance-id>",
      "destination": "@WorldUSD",
      "meta_data": {
          "transaction_type": "withdrawal",
          "channel": "atm"
      }
    }'
  ```
</CodeGroup>

***

## Creating a card balance

To create a card balance and link it to the customer:

<CodeGroup>
  ```javascript TypeScript theme={"system"}
  async function createCardWallet(ledgerId, identityId, currency) {
    const blnk = await getBlnkInstance();
    const { LedgerBalances } = blnk;
    
    const cardWallet = await LedgerBalances.create({
      ledger_id: ledgerId,
      identity_id: identityId,
      currency: currency,
      meta_data: {
        wallet_type: "card",
        purpose: "card_payments",
        status: "active",
        card_details: {
          masked_number: "xxxx-xxxx-xxxx-1234",
          expiry: "12/25",
          type: "virtual"
        }
      }
    });
    
    console.log("Card Wallet created:", cardWallet.data.balance_id);
    return cardWallet.data.balance_id;
  }
  ```

  ```bash cURL theme={"system"}
  curl --request POST \
    --url http://localhost:5001/balances \
    --header 'X-blnk-key: <api-key>' \
    --header 'Content-Type: application/json' \
    --data '{
      "ledger_id": "<customer-wallets-ledger-id>",
      "identity_id": "<customer-identity-id>",
      "currency": "USD",
      "meta_data": {
          "wallet_type": "card",
          "purpose": "card_payments",
          "status": "active",
          "card_details": {
              "masked_number": "xxxx-xxxx-xxxx-1234",
              "expiry": "12/25",
              "type": "virtual"
          }
      }
    }'
  ```
</CodeGroup>

***

## Funding the card from main wallet

Record a transaction between both balances to fund your card balance:

<CodeGroup>
  ```javascript TypeScript theme={"system"}
  async function transferToCardWallet(mainBalanceID, cardBalanceID, amount, uniqueReference, description) {
    const blnk = await getBlnkInstance();
    const { Transactions, LedgerBalances } = blnk;
    
    const transfer = await Transactions.create({
      amount: amount,
      precision: 100,
      reference: uniqueReference,
      description: description || "Transfer to card wallet",
      currency: "USD",
      source: mainBalanceID,
      destination: cardBalanceID,
      meta_data: {
        transaction_type: "internal_transfer",
        purpose: "fund_card"
      }
    });
    
    console.log("Transfer transaction created:", transfer.data.transaction_id);
    return transfer.data.transaction_id;
  }
  ```

  ```bash cURL theme={"system"}
  curl --request POST \
    --url http://localhost:5001/transactions \
    --header 'X-blnk-key: <api-key>' \
    --header 'Content-Type: application/json' \
    --data '{
      "amount": 200,
      "precision": 100,
      "reference": "TRF-20250225-110000",
      "description": "Transfer to card wallet",
      "currency": "USD",
      "source": "<customer-main-balance-id>",
      "destination": "<customer-card-balance-id>",
      "meta_data": {
          "transaction_type": "internal_transfer",
          "purpose": "fund_card"
      }
    }'
  ```
</CodeGroup>

***

## Conclusion

You should now have a fully functional and scalable wallet management system.

As your application grows, you can expand its capabilities with features like [transaction history](/search/typesense/introduction), [scheduled transfers](/transactions/scheduling), [balance monitors](/balances/balance-monitoring), and [notifications](/hooks/overview) to enhance performance and user experience.

***

## Can't find your use case?

If you’re searching for a specific tutorial that isn’t included here, you’re welcome to [contribute to our documentation](https://github.com/blnkfinance/blnk-docs/tree/main/tutorials) by sharing your expertise or requesting a new tutorial in [our Discord community](https://discord.gg/7WNv94zPpx).

We’re always thrilled to expand our resources with the help of our developer community!
