Forloy API

v1

Rewards & Cashback

After recording transactions, customers may earn rewards (punch cards) or accumulate cashback balance. This guide covers how to claim earned rewards and redeem cashback.

End-to-End Flow

Loading diagram...

Punch Card Rewards

How Rewards Are Earned

  • Each transaction adds punches (default 1, configurable per card template).
  • When current_punches reaches punch_requirement, a reward is automatically created.
  • The record transaction response will show reward_earned: true.
  • Rewards accumulate — a customer can have multiple pending rewards.

Checking Pending Rewards

Use POST /api/v1/cards/lookup to see the pending_rewards count for a punch card.

Lookup Response (Punch Card)
{
  "card_instance_id": "ci_abc123",
  "card_type": "punch",
  "card_name": "Coffee Loyalty Card",
  "current_punches": 3,
  "punch_requirement": 10,
  "pending_rewards": 2,
  "lifetime_punches": 23,
  "status": "active"
}

Claiming a Reward

Call POST /api/v1/rewards/claim to claim the oldest pending reward (FIFO order).

POST /api/v1/rewards/claim
{
  "card_instance_id": "ci_abc123",
  "location_id": "loc_456",
  "staff_user_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Response

200 OK
{
  "transaction_id": "txn_reward_789",
  "reward_id": "rw_001",
  "reward_name": "Free Coffee",
  "reward_amount": 1,
  "earned_at": "2026-03-08T14:30:00Z",
  "pending_rewards_remaining": 1
}

Tip: Each call claims one reward. To claim multiple rewards, call the endpoint multiple times. The oldest reward is always claimed first.

Cashback Redemption

How Cashback Is Earned

  • Each purchase earns a percentage back based on the customer's current tier/rate.
  • Cashback balance grows with each transaction.
  • Tiers may change based on lifetime cashback earned.

Checking Cashback Balance

Use POST /api/v1/cards/lookup to see the current cashback_balance, cashback_rate, current_tier_name.

Lookup Response (Cashback Card)
{
  "card_instance_id": "ci_xyz789",
  "card_type": "cashback",
  "card_name": "Premium Cashback Card",
  "cashback_balance": 15.50,
  "cashback_rate": 0.05,
  "current_tier_name": "Gold",
  "lifetime_cashback": 142.30,
  "status": "active"
}

Redeeming Cashback

Call POST /api/v1/cashback/redeem to apply cashback balance against a purchase. Cashback is consumed in FIFO order — the oldest earned cashback is used first.

Example: A customer has a $15.50 balance and wants to redeem $10.00 on a $25.00 purchase.

POST /api/v1/cashback/redeem
{
  "card_instance_id": "ci_xyz789",
  "redemption_amount": 10.00,
  "purchase_amount": 25.00,
  "location_id": "loc_456",
  "staff_user_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "transaction_notes": "Redeemed at checkout"
}

Response

200 OK
{
  "transaction_id": "txn_cb_456",
  "redeemed_amount": 10.00,
  "new_balance": 5.50,
  "final_purchase_amount": 15.00,
  "redeemed_entries": [
    {
      "earning_transaction_id": "txn_earn_101",
      "amount_used": 7.25,
      "earned_at": "2026-02-15T10:00:00Z"
    },
    {
      "earning_transaction_id": "txn_earn_102",
      "amount_used": 2.75,
      "earned_at": "2026-02-20T16:45:00Z"
    }
  ]
}

The redeemed_entries array shows which earning transactions the cashback came from. This provides a full audit trail of how the redemption was fulfilled.

Tip: If the redemption_amount exceeds the available balance, the API returns an INSUFFICIENT_BALANCE error. Always check the balance before attempting a redemption.

Complete Integration Example

Here is a step-by-step walkthrough of a punch card reward being earned and claimed:

  1. LoginCall POST /api/v1/auth/login to get an access token.
  2. Customer scans cardCall POST /api/v1/cards/lookup to retrieve card details. You see it's a punch card with 9 out of 10 punches.
  3. Record purchaseCall POST /api/v1/transactions/record to add the 10th punch. The response returns reward_earned: true — a reward has been unlocked!
  4. Claim the rewardCall POST /api/v1/rewards/claim to redeem the reward. The customer gets their free coffee.

Error Handling

Key errors to handle when working with rewards and cashback:

  • NO_PENDING_REWARDS No rewards available to claim (punch cards). The customer has not yet reached the punch threshold.
  • INSUFFICIENT_BALANCE The requested redemption amount exceeds the available cashback balance.
  • CARD_NOT_FOUND The provided card_instance_id does not exist or does not belong to the merchant.
  • CARD_INACTIVE The card has been deactivated and cannot process rewards or redemptions.
  • COOLDOWN_ACTIVE Too soon after the last transaction. Punch cards have a 1-minute cooldown between transactions to prevent duplicate scans.

Back to Overview

← Return to Integration Guide