Overview

Building a robust customer loyalty points system can significantly increase user engagement and retention in your eCommerce or fintech app. In this example, you’ll learn how to implement a loyalty point management system, process transactions, and ensure smooth and secure workflows, all with the Blnk Ledger.

We’ll learn about:

  • Defining and creating your ledger structure
  • Balance (loyalty points) creation
  • Awarding points
  • Redeeming points
  • Best Practices (with Inflight)

1. Ledger Structure

The entry point of the Blnk ledger system is ledger folders. These folders serve as a way to group and manage assets, accounts, and balances that fit your product or organization’s structure.

In this guide, we’ll use a simple structure:

  • Loyalty Points Ledger: Contains all loyalty point accounts for customers

The ledger structure is flexible and can be customized based on your specific needs. For instance, you could group by users instead of currencies, or use a combination of both.

See also:

Creating a Loyalty Points Ledger

NodeJS
const request = require('request');

const options = {
  method: 'POST',
  url: 'http://localhost:5001/ledgers',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'YOUR_AUTH_TOKEN_HERE'
  },
  body: JSON.stringify({
    "name": "Customer Loyalty Points Ledger",
    "meta_data": {
      "project_name": "RetailStore App"
    }
  })
};

request(options, (error, response) => {
  if (error) throw new Error(error);
  console.log(response.body);
});
Response
{
    "ledger_id": "ldg_12345678-90ab-cdef-1234-567890abcdef",
    "name": "Customer Loyalty Points Ledger",
    "created_at": "2024-07-05T08:06:26.84333909Z",
    "meta_data": {
        "project_name": "RetailStore App"
    }
}

Always store the ledger_id in your database. You’ll need it for future operations related to this ledger.

2. Balance (Wallet) Creation

Blnk uses the concept of ledger balances to manage accounts/balances in a ledger. In this example, we’ll create loyalty point accounts for customers. Each loyalty point account will be represented as a balance in the ledger.

See also:

Creating a loyalty points account for a customer

NodeJS
const request = require('request');

const options = {
  method: 'POST',
  url: 'http://localhost:5001/balances',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    "ledger_id": "ldg_12345678-90ab-cdef-1234-567890abcdef",
    "currency": "POINTS",
    "meta_data": {
      "customer_name": "Alice",
      "customer_internal_id": "5678"
    }
  })
};

request(options, (error, response) => {
  if (error) throw new Error(error);
  console.log(response.body);
});
Response
{
    "balance": 0,
    "version": 0,
    "inflight_balance": 0,
    "credit_balance": 0,
    "inflight_credit_balance": 0,
    "debit_balance": 0,
    "inflight_debit_balance": 0,
    "precision": 0,
    "ledger_id": "ldg_12345678-90ab-cdef-1234-567890abcdef",
    "identity_id": "",
    "balance_id": "bln_9f8d7e6c-5b4a-4c9d-8a7e-6f5b4a8c9d7e",
    "indicator": "",
    "currency": "POINTS",
    "created_at": "2024-07-05T08:13:18.882616461Z",
    "meta_data": {
        "customer_internal_id": "5678",
        "customer_name": "Alice"
    }
}

The balance_id is crucial. Always store this in your database and associate it with the customer. You’ll use this ID for all future transactions involving this loyalty point account.

3. Awarding Points

Whenever a customer makes a purchase, you can award them loyalty points. We’ll use the Inflight feature to manage loyalty point transactions.

See also:

Awarding points for a purchase

NodeJS
const request = require('request');

const options = {
  method: 'POST',
  url: 'http://localhost:5001/transactions',
  headers: {
    'X-Blnk-Key': 'blnk-api',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    "amount": 100,  // Representing 100 points
    "precision": 1,
    "reference": "purchase-001",
    "description": "Points for purchase",
    "currency": "POINTS",
    "source": "@Store",
    "destination": "bln_9f8d7e6c-5b4a-4c9d-8a7e-6f5b4a8c9d7e",  // Alice's loyalty point balance_id
    "inflight": true,
    "meta_data": {
      "customer_name": "Alice",
      "purchase_id": "purchase-001"
    }
  })
};

request(options, (error, response) => {
  if (error) throw new Error(error);
  console.log(response.body);
});
Response
{
    "transaction_id": "txn_abcdef01-2345-6789-abcd-ef0123456789",
    "amount": 100,
    "precision": 1,
    "precise_amount": 100,
    "reference": "purchase-001",
    "description": "Points for purchase",
    "currency": "POINTS",
    "status": "INFLIGHT",
    "source": "@Store",
    "destination": "bln_9f8d7e6c-5b4a-4c9d-8a7e-6f5b4a8c9d7e",
    "created_at": "2024-07-05T08:21:04.001458635Z",
    "meta_data": {
        "customer_name": "Alice",
        "purchase_id": "purchase-001"
    }
}

When you use inflight on your transaction, you need to commit or void the transaction to complete the transaction workflow. To learn more, see Applying inflight.

4. Redeeming Points

Customers can redeem their loyalty points for rewards or discounts. We’ll use the Inflight feature to manage point redemptions.

Redeeming points

NodeJS
const request = require('request');

const options = {
  method: 'POST',
  url: 'http://localhost:5001/transactions',
  headers: {
    'X-Blnk-Key': 'blnk-api',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    "amount": 50,  // Representing 50 points
    "precision": 1,
    "reference": "redemption-001",
    "description": "Points redemption",
    "currency": "POINTS",
    "source": "bln_9f8d7e6c-5b4a-4c9d-8a7e-6f5b4a8c9d7e",  // Alice's loyalty point balance_id
    "destination": "@Store",
    "inflight": true,
    "meta_data": {
      "customer_name": "Alice",
      "redemption_id": "redemption-001"
    }
  })
};

request(options, (error, response) => {
  if (error) throw new Error(error);
  console.log(response.body);
});
Response
{
    "transaction_id": "txn_abcdef02-3456-7890-abcd-ef0234567890",
    "amount": 50,
    "precision": 1,
    "precise_amount": 50,
    "reference": "redemption-001",
    "description": "Points redemption",
    "currency": "POINTS",
    "status": "INFLIGHT",
    "source": "bln_9f8d7e6c-5b4a-4c9d-8a7e-6f5b4a8c9d7e",
    "destination": "@Store",
    "created_at": "2024-07-05T08:21:04.001458635Z",
    "meta_data": {
        "customer_name": "Alice",
        "redemption_id": "redemption-001"
    }
}

When you use inflight on your transaction, you need to commit or void the transaction to complete the transaction workflow. To learn more, see Applying inflight.

See also

Managing side effects with Inflight

A deep-dive guide into how to implement Inflight in your application.

Best Practices (with Inflight)

  1. Available Balance Calculation: In your application, calculate the available balance to prevent users from accessing funds that are held in Inflight transactions. This can be done as follows:
const availableBalance = balance - inflight_debit_balance;
  1. Error Handling: Implement robust error handling in your Inflight process. If a commit or void operation fails, you may need to retry or escalate to manual intervention.
  2. Customer Communication: Implement a system to notify customers about the status of their transactions, especially when they are held in Inflight. Clear communication can enhance customer trust and satisfaction.
  3. Reconciliation: Regularly reconcile your internal records with Blnk’s transaction logs to ensure accuracy. Pay special attention to Inflight transactions. Blnk v1 will support reconciliation features built into the ledger, which can aid in this process.
  4. Webhook Authentication: In a production environment, implement a mechanism to verify that webhooks are genuinely from your payment provider. This helps in maintaining the integrity and security of your transaction processing.
  5. Idempotency: Ensure your webhook handler is idempotent. Providers may send the same webhook multiple times, so your system should handle duplicate notifications gracefully. This prevents double-processing of transactions.
  6. Monitoring: Set up monitoring and alerting for your webhook endpoint and Inflight transactions. This can help you quickly identify and respond to any issues in the payment verification process.
  7. Data Security: Always ensure that sensitive card details are securely managed and stored. Mask or encrypt card numbers, CVVs, and other sensitive information when storing or displaying them.
  8. Transaction State Management: Use metadata to manage the state of virtual cards and transactions effectively. For example, track the transaction verification status (e.g., VERIFIED, DECLINED) in the metadata.
  9. Compliance: Ensure that your virtual card issuance and transaction processing comply with relevant regulations and standards, such as PCI-DSS for handling card data securely.
  10. Testing: Thoroughly test your virtual card issuance and transaction processing flows, including Inflight handling, to identify and resolve any issues before going live.

Need help?

Are you stuck? Do you have a question that isn’t answered in this doc? Have you run into a problem you can’t solve? Want to file a bug report?

Join our Discord server and share your questions/thoughts with other developers building financial applications like you.

Was this page helpful?