> ## 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 Savings Application

> Learn how to implement scheduled savings deposit with Blnk.

## Overview

In this tutorial, you'll learn how to implement, monitor, and manage scheduled savings deposits with the Blnk ledger. Here's what we'll do:

1. Create a customer savings wallet balance.
2. Initiate a scheduled deposit transaction. For one-time funding: [Wallet Funding Tutorial →](/tutorials/quick-start/wallet-management#funding-the-main-wallet).
3. Update the savings frequency.

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 scheduled savings deposit workflow, here's our map:

<img src="https://mintcdn.com/blnk/jKiGmb7nTD9y-R5a/images/tutorials/savings-application-map.png?fit=max&auto=format&n=jKiGmb7nTD9y-R5a&q=85&s=80facbf32339972f6fd593cfe578de89" alt="Savings application map" width="890" height="433" data-path="images/tutorials/savings-application-map.png" />

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

Read more: [Scheduling transactions →](/transactions/scheduling)

***

## Set up your implementation

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

1. Initiate a scheduled transaction to `Savings Wallet`
2. Monitor the date of the next scheduled deposit to ensure timely execution.
3. Set up a new scheduled transaction after the current one has been successfully processed.

***

## 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.
4. A customer savings ledger to organise the customers' savings balances. Learn how: [How to Create a Ledger →](/tutorials/quick-start/wallet-management#create-customer-ledger)

***

## Create customer savings balance

Create a balance with the `ledger_id` of your `Customer Savings Ledger` to represent your customer savings wallet:

<CodeGroup>
  ```javascript TypeScript theme={"system"}
  async function createSavingsWallet(savingsLedgerId, identityId, currency) {
    const blnk = await getBlnkInstance();
    const { LedgerBalances } = blnk;
    
    const savingsWallet = await LedgerBalances.create({
      ledger_id: savingsLedgerId,
      identity_id: identityId,
      currency: currency,
      meta_data: {
        wallet_type: "savings",
        schedule_savings: true,
        savings_frequency: "monthly",
        savings_amount: 10000,
        next_scheduled_savings: ""
      }
    });
    
    console.log("Savings Wallet created:", savingsWallet.data.balance_id);
    return savingsWallet.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-savings-ledger-id>",
      "identity_id": "<customer-identity-id>",
      "currency": "USD",
      "meta_data": {
          "wallet_type": "savings",
          "schedule_savings": true,
          "savings_frequency": "monthly",
          "savings_amount": 10000,
          "next_scheduled_savings": ""
      }
    }'
  ```
</CodeGroup>

This creates a savings balance with a set of default metadata:

1. This customer balance is subscribed to scheduled deposits.
2. Schedule frequency is monthly.
3. The next scheduled savings date can be monitored on the customer balance

***

## Initiate scheduled transaction

Schedule a transaction on the ledger with the `scheduled_for` parameter:

<CodeGroup>
  ```javascript TypeScript theme={"system"}
  async function createScheduledSavingsTransaction(savingsBalanceId, savingsAmount, uniqueReference, description, scheduledDate) {
    const blnk = await getBlnkInstance();
    const { Transactions } = blnk;
    
    const scheduledSavings = await Transactions.create({
      amount: savingsAmount,
      precision: 100,
      reference: uniqueReference,
      description: description || "Scheduled savings deposit",
      currency: "USD",
      source: "@WorldUSD",      // Represents external funding source
      destination: savingsBalanceId, 
      scheduled_for: scheduledDate,
      meta_data: {
        transaction_type: "savings"
      }
    });
    
    console.log("Savings successfully scheduled:", scheduledSavings.data.transaction_id);
    return scheduledSavings.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": "SAV_0001",
      "description": "Scheduled savings deposit",
      "currency": "USD",
      "source": "@WorldUSD",
      "destination": "<savings-balance-id>",
      "scheduled_for": "2025-12-25T02:42:19Z",
      "meta_data": {
        "transaction_type": "savings"
      }
    }'
  ```
</CodeGroup>

A `SCHEDULED` transaction is created waiting to be applied on the specified scheduled date.

***

## Set up new scheduled transaction

To schedule the next savings deposit, verify that `scheduled_savings` is still active on the customer's balance and retrieve its frequency.

<Tip>
  Blnk sends a webhook when a scheduled transaction gets applied.
</Tip>

```javascript [expandable] theme={"system"}
import express from 'express';
const app = express();
app.use(express.json());
app.post('/webhooks/transactions', async (req, res) => {
  const { event, data } = req.body;
  
  if (event === 'transaction.applied') {
    const transaction = data;
    
    if (
      transaction.meta_data?.transaction_type === 'savings'
    ) {
      console.log('Scheduled savings completed:', transaction.transaction_id);
      
      const blnk = await getBlnkInstance();
      const { LedgerBalances, Transactions } = blnk;
      
      const savingsBalanceId = transaction.destination;
      const savingsBalance = await LedgerBalances.retrieve(savingsBalanceId);
      
      if (
        savingsBalance.meta_data?.schedule_savings === true
      ) {
        const frequency = savingsBalance.meta_data.savings_frequency || "monthly";
        const amount = savingsBalance.meta_data.savings_amount;
        
        const nextScheduledDate = calculateNextScheduledDate(frequency);
        
        // 1. Update metadata with the next scheduled date
        await LedgerBalances.updateMetadata(savingsBalanceId, {
          "meta_data": {
            "next_scheduled_savings": nextScheduledDate.toISOString()
          }
        });
        
        // 2. Create a new scheduled transaction
        const uniqueReference = `sch-savings-${Date.now()}`;
        const scheduledSavings = await Transactions.create({
          amount: amount,
          precision: 100,
          reference: uniqueReference,
          description: "Scheduled savings deposit",
          currency: "USD",
          source: "@WorldUSD",
          destination: savingsBalanceId,
          scheduled_for: nextScheduledDate.toISOString(),
          meta_data: {
            transaction_type: "savings"
          }
        });
        
        console.log(`Next scheduled deposit created for ${nextScheduledDate.toISOString()}:`, scheduledSavings.data.transaction_id);
      } else {
        console.log(`Scheduled savings is no longer active for balance ${savingsBalanceId}`);
      }
    }
  }
  
  res.status(200).send('Webhook received');
});

function calculateNextScheduledDate(frequency) {
  const now = new Date();
  const nextDate = new Date(now);
  
  switch (frequency) {
    case 'daily':
      nextDate.setDate(now.getDate() + 1);
      break;
    case 'weekly':
      nextDate.setDate(now.getDate() + 7);
      break;
    case 'biweekly':
      nextDate.setDate(now.getDate() + 14);
      break;
    case 'monthly':
      nextDate.setMonth(now.getMonth() + 1);
      break;
    default:
      nextDate.setMonth(now.getMonth() + 1);
  }
  
  return nextDate;
}

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Webhook server listening on port ${PORT}`);
});
```

***

## Change savings frequency

To change the savings frequency of a balance, use the [Update Metadata](/metadata/update-metadata) endpoint:

<CodeGroup>
  ```javascript TypeScript theme={"system"}
  async function updateSavingsFrequency(balanceId, newFrequency) {
    const blnk = await getBlnkInstance();
    const { LedgerBalances } = blnk;
    
    try {
      const response = await LedgerBalances.updateMetadata(balanceId, {
        "meta_data": {
          "savings_frequency": newFrequency
        }
      });
      
      console.log(`Successfully updated savings frequency to ${newFrequency} for balance ${balanceId}`);
      return response.data;
    } catch (error) {
      console.error(`Failed to update savings frequency for balance ${balanceId}:`, error);
      throw error;
    }
  }
  ```

  ```json theme={"system"}
  curl --request POST \
    --url http://localhost:5001/balances/<balance-id>/metadata \
    --header 'X-blnk-key: <api-key>' \
    --header 'Content-Type: application/json' \
    --data '{
    "meta_data": {
      "savings_frequency": "daily"
    }
  }'
  ```
</CodeGroup>

***

## Conclusion

In this tutorial, we’ve built a scheduled savings workflow for a wallet app using Blnk. Here’s what we covered:

* Setting up savings ledgers and customer savings accounts
* Adding scheduled deposits
* Automatically rescheduling deposits after they’re completed
* Handling deposit frequencies and customer preferences
* Using webhooks to detect completed transactions and schedule new deposits.

With these features, your app offers customers an easy, automated way to save regularly without extra effort. The webhook-based architecture ensures that your system remains resilient and responsive to transaction events.

***

## 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!
