Contents

Rewards are a common customer retention strategy for e-commerce and embedded finance products. In simple terms, you ‘reward’ customers for continuing to buy with you.

For you, the developer, it’s important for you to know if a customer has rewards, exactly how much has been rewarded, and how to help them redeem it.

In this guide, you'll learn how to implement a rewards system using the Blnk Ledger: from managing customer wallets to assigning and redeeming rewards at purchase. We'll use SunnySide Mart, a mid-sized supermarket franchise, as our example.

Step 1: Setting up your ledger design

Since we’re using Blnk, make sure you have a deployed Blnk instance. If you don’t have one, we wrote a guide here on how to get started.

First, let’s review our rewards feature. We want customers to:

  • Earn rewards when they make a purchase.
  • Redeem the rewards as discount on a subsequent purchase

To do this, we’ll need to create and track a balance per customer for their rewards earned. To implement this with Blnk:

  1. Create a ledger: Rewards Ledger to group all customer-owned balances. Read docs.
  2. Create an identity for each customer: Add each customer as an individual identity. We’ll use this to create a balance for the customer in the next step. Read docs.
  3. Create a rewards balance: Using the customer’s identity, create a balance for the customer under the Rewards ledger. Read docs.

Once you've done these, you'll have your customer balance ID. Save it, you'll need them for the next step.

Step 2: Earn rewards on purchase

For this guide: when a customer makes a purchase, we’ll issue a reward based on the amount spent. For simplicity, we'll award a 1% reward on purchases of $1,000 or more.

```

--CODE language-bash--

if (purchase_amount >= 1000) {
reward_amount = 0.01 * purchase_amount
return reward_amount
}

```

So if a customer spent $3,000, they’d get $30 as rewards. To record this in Blnk, we’ll need two transactions that happen together:

  1. We’ll record the customer $3,000 purchase as an external payment (e.g. card) to our revenue balance.
  2. We’ll top-up the customer’s reward wallet with $30, using the balance ID from Step 1.
Money movement map for rewards payout after customer purchase.

Here's how to implement it with Blnk's bulk transactions feature:

```

--CODE language-bash--

curl -X POST "http://localhost:5001/transactions/bulk" \
 -H "Content-Type: application/json" \
 -H "X-blnk-key: YOUR_API_KEY" \
 -d '{
   "atomic": true,
   "inflight": false,
   "skip_queue": true,
   "transactions": [
     {
       "amount": 3000,
       "precision": 100,
       "currency": "USD",
       "reference": "ref_purchase_order_10001",
       "source": "@CustomerPurchase",
       "destination": "@Revenue",
       "allow_overdraft": true,
       "description": "SunnySide order purchase",
       "meta_data": {
         "transaction_type": "purchase",
         "order_id": "10001",
         "customer_email": "peter.johnson@example.com"
       }
     },
     {
       "amount": 30,
       "precision": 100,
       "currency": "USD",
       "reference": "ref_reward_order_10001",
       "source": "@RewardsPool",
       "destination": "CUSTOMER_REWARD_BALANCE_ID",
       "allow_overdraft": true,
       "description": "Reward issued for order",
       "meta_data": {
         "transaction_type": "reward_earned",
         "order_id": "10001",
         "reward_rate": "1%"
       }
     }
   ]
 }'

```

You'll get the following response:

```

--CODE language-json--

{
   "batch_id": "bulk_e1fb5f7a-74bc-47ad-83b9-44f428d4da97",
   "status": "applied",
   "transaction_count": 2
}

```

Here's what happened:

  • With atomic: true, Blnk ensures that both transactions are successful together or not. If one isn’t successful, the other fails or is reversed.
  • The reference fields act as idempotency keys.
  • allow_overdraft: true allows system balances like @CustomerPurchase and @RewardsPool to go negative. This completes the double-entry requirement: every destination (revenue and customer rewards wallet) must have a source.
The transactions table shows the purchase to @Revenue and the reward issuance from @RewardsPool, both applied successfully.

Step 3: Redeem rewards at checkout

Now, the customer wants to use their rewards at checkout. They have a $50 order; if the $30 reward is applied, they’ll only have to pay $20 out of pocket.

For this, we’ll record a split transaction. First, we clear the reward balance completely, i.e. deduct the whole amount. Then we charge the remaining amount to the customer.

Money movement map for when a customer redeems their earned rewards in a subsequent purchase

```

--CODE language-bash--

curl -X POST "http://localhost:5001/transactions/bulk" \
 -H "Content-Type: application/json" \
 -H "X-blnk-key: YOUR_API_KEY" \
 -d '{
   "atomic": true,
   "inflight": false,
   "skip_queue": true,
   "transactions": [
   {
       "amount": 30,
       "precision": 100,
       "currency": "USD",
       "reference": "ref_rewards_discount_order_10002",
       "source": "CUSTOMER_REWARD_BALANCE_ID",
       "destination": "@Revenue",
       "description": "Rewards applied as discount",
       "meta_data": {
         "transaction_type": "reward_spent",
         "order_id": "10002"
       }
     },
     {
       "amount": 20,
       "precision": 100,
       "currency": "USD",
       "reference": "ref_purchase_order_10002",
       "source": "@CustomerPurchase",
       "destination": "@Revenue",
       "allow_overdraft": true,
       "description": "SunnySide order purchase (discounted)",
       "meta_data": {
         "transaction_type": "purchase",
         "order_id": "10002",
         "customer_email": "peter.johnson@example.com",
         "discount_source": "rewards",
         "discount_amount": 10
       }
     }
   ]
 }'

```

You should get the following response:

```

--CODE language-json--

{
   "batch_id": "bulk_2eb77e28-ad3f-47b0-b04a-693c9a313a69",
   "status": "applied",
   "transaction_count": 2
}

```

Here's what happened:

  • Revenue reflects the total amount earned from the purchase.
  • The rewards spend is recorded explicitly so you can always see what was discounted and by how much.
  • Unlike internal balances, customer rewards balances usually should not allow overdrafts. If the customer does not have enough rewards, this movement should fail.
The transactions table shows the discounted purchase and reward spend applied successfully.

Fetching a customer's rewards balance

To show a customer, how much they have in their rewards, you can simply fetch it from the ledger:

```

--CODE language-bash--

curl -X GET http://localhost:5001/balances/CUSTOMER_REWARDS_BALANCE_ID \
 -H "Content-Type: application/json" \
 -H "X-blnk-key: YOUR_API_KEY"

```

You'll get your balance details in the response:

```

--CODE language-json--

{
 "balance_id": "bln_7d606316-27d4-4ba4-bae1-3581692de614",
 "currency": "USD",
 "balance": 500,
 "credit_balance": 3000,
 "debit_balance": 2500,
 "inflight_balance": 0
}

```

Note: Blnk stores amounts in the smallest unit. Divide balance by precision before displaying, e.g. 100 for cents in USD, as used throughout this guide.

Peter's (the customer) balance after redeeming their reward

Wrapping up

You now have a fully auditable, retry-safe rewards system where every reward is a ledger entry and every workflow is reversible. This approach ensures that your rewards programme remains transparent and accurate.

Every reward earned or spent is now recorded as a clear transaction with full traceability.

What makes this system reliable is its atomic transaction model; purchases and rewards are always linked together, so you never lose track of where value flows.

  • Discounts are routed through @Revenue, keeping your financial statements accurate whilst still giving customers the benefit they've earned.
  • Cash-outs and redemptions are logged with payout references in metadata, giving you a complete audit trail for reconciliation and support.

What else can you build?

With this foundation in place, you can extend your rewards system in other ways like:

  • Implementing reward expirations using scheduled reversals,
  • Creating tiered reward rates based on customer segments,
  • Generate customer reward statements
  • Exportable audit trails for compliance and customer service.

Building your ledger this way gives you the flexibility to evolve your rewards programme as your business grows.