Skip the setup. Our team will have you taking orders in 24 hours. Get started →
Extensions

Loyalty Points

Installation Getting started Configuration Customer Loyalty Dashboard (view points & history) Checkout Integration Understanding loyalty history Usage E...

If you haven't already bought the TastyIgniter Loyalty Points extension, you can purchase it from the TastyIgniter Marketplace.

After purchasing the extension, add composer.tastyigniter.com as a repository in your composer.json file to allow Composer to find the package. This is done automatically when you install the extension via the TastyIgniter Admin.

"repositories": {
    "tastyigniter": {
        "type": "composer",
        "url": "https://composer.tastyigniter.com"
    }
},

Next, create a auth.json file under the same directory as your composer.json file to provide your TastyIgniter Marketplace credentials. This file should contain your email address and carte key in the following format:

{
    "http-basic": {
        "composer.tastyigniter.com": {
            "username": "your-tastyigniter-account-email-address",
            "password": "your-tastyigniter-site-carte-key"
        }
    }
}
  • username: Your TastyIgniter account email address.
  • password: Your TastyIgniter site carte key, which you can find in your TastyIgniter account under Sites.

After setting up the auth.json file, you'll be able to install the extension via composer using the following command:

composer require igniterlabs/ti-ext-loyaltypoints -W

Run the database migrations to create the required tables:

php artisan igniter:up

This section walks you through setting up loyalty points for your restaurant so customers can earn and redeem points with every order.

From your TastyIgniter Admin, navigate to Manage > Settings > Loyalty Points Settings in the admin panel to configure:

  1. Go to Settings > Loyalty Points
  2. Switch on Enable Loyalty Points
  3. Click Save to activate the feature

The point value determines how much discount each point is worth when redeemed. For example, if you set the value to $0.10, then 10 points equal $1.00 off.

  1. Go to Settings > Loyalty Points > Spending tab
  2. Set Point Value to your desired amount (e.g., $0.01, $0.10, etc.)
    • Example: If set to $0.05, then 20 points = $1.00 discount
  3. Click Save

You can choose how customers earn points based on their spending. There are two methods:

Customers earn a consistent number of points per dollar spent.

  1. Go to Settings > Loyalty Points > Earning tab
  2. Select Earning Method > "Fixed Rate (X points per 100 spent)"
  3. Set Points per 100 spent (e.g., 50 means customers earn 50 points per $100 spent)
    • Example: Setting to 50 = 0.5 points per dollar
  4. Click Save

Reward higher spenders with more points. Create multiple brackets based on order value (called "Earning Bands" in the settings).

  1. Go to Settings > Loyalty Points > Earning tab
  2. Select Earning Method > "Spending Tiers"
  3. Under Earning Bands, click Add Row for each tier:
    • Minimum Order Value: The order subtotal threshold (e.g., $15)
    • Points Earned: Fixed points for this tier (e.g., 25 points)
    • Example: Orders $15-$30 get 25 points, orders $31+ get 50 points
  4. Click Save

When calculating earned points, fractional amounts may occur. You can control how these are handled:

  1. Go to Settings > Loyalty Points > Earning tab
  2. Set Points Rounding:
    • Round Down: More conservative, e.g., 4.7 points becomes 4 points
    • Round Up: More generous to customers, e.g., 4.1 points becomes 5 points
  3. Click Save

By default, taxes are excluded when calculating points earned. You can change this:

  1. Go to Settings > Loyalty Points > Earning tab
  2. Toggle Include Tax in Earning:
    • Off (default): Points are calculated on the order subtotal minus tax
    • On: Points are calculated on the full order total including tax
  3. Click Save

Control when earned points become usable and when they expire:

  1. Go to Settings > Loyalty Points > Earning tab
  2. Configure the validity settings:
    • Points Valid After (hours): How many hours after earning before points can be used. Set to 0 for immediate availability. Example: Set to 24 to require a 1-day waiting period.
    • Points Expire After (days): How many days after earning until points expire. Example: Set to 365 for 1-year expiry, or 0 for no expiry.
  3. Click Save

You can restrict when customers are allowed to redeem their points (e.g., only on certain days or times):

  1. Go to Settings > Loyalty Points > Spending tab
  2. Set Spending Validity:
    • Always: Points can be redeemed at any time
    • Fixed Date: Points can only be redeemed on a specific date within a time window
    • Date Range: Points can only be redeemed between two specific dates
    • Recurring: Points can only be redeemed on specific days/times each week (e.g., weekends only, or 5-9pm daily)
  3. Configure dates and times based on your selection
  4. Click Save

Control how customers can redeem points with these options:

  1. Go to Settings > Loyalty Points > Spending tab
  2. Configure the following:

| Setting | Purpose | Example | |------------------------------|------------------------------------------------------------------|-------------------------------------------| | Minimum Points to Redeem | Customers must redeem at least this many points per redemption | Set to 10 for minimum redemption | | Maximum Order Percentage | Points cannot cover more than this percentage of the order total | Set to 50 means points max out at 50% off | | Minimum Basket Value | Order must be at least this amount to use points | Set to $20 minimum order for points use | | Order Type Restriction | Allow points only for delivery, only for collection, or both | Delivery only / Collection only / Both |

By default, points can be redeemed against the entire order. You can limit points to specific menu items or categories:

  1. Go to Settings > Loyalty Points > Spending tab
  2. Switch on Apply to Specific Menu Items Only
  3. Select Applicable Categories and/or Applicable Menu Items that points can be used on
  4. Click Save

Now points can only discount the selected items/categories.

Reward customers for non-purchase actions to grow engagement:

  1. Go to Settings > Loyalty Points > Earning tab
  2. Scroll to Bonus Points section:
    • Registration Points: Points awarded when a customer creates an account (set to 0 to disable)
    • Review Points: Points awarded when a customer posts a review (set to 0 to disable)
  3. Enter the point amounts (e.g., 50 points for registration, 25 for reviews)
  4. Click Save

If you operate multiple locations, you can require customers to earn and spend points at the same location:

  1. Go to Settings > Loyalty Points > General tab
  2. Switch on Location Specific Points
    • When enabled, points earned at Location A can only be redeemed at Location A
    • When disabled, points work across all locations
  3. Click Save

You can also override settings per location:

  1. Go to Manage > Locations
  2. Find the location you want to customize and click the settings icon (gear/cog)
  3. Navigate to the Loyalty Points tab
  4. Switch on Override Default Settings
  5. Customize earning/spending rules for just this location
  6. Click Save

To let customers see their points balance and transaction history, add the loyalty dashboard component to your theme using the Livewire component igniterlabs-loyaltypoints::loyalty-dashboard:

<livewire:igniterlabs-loyaltypoints::loyalty-dashboard
    :itemsPerPage="10"
    sortOrder="date_used desc"
    :showTotalEarned="true"
/>

Component Properties:

  • itemsPerPage - (number, default: 10) - Items per page
  • sortOrder - (string, default: 'date_used desc') - Sort order options: 'date_used desc', 'date_used asc'
  • showTotalEarned - (boolean, default: true) - Show total earned card

The extension integrates with the cart. Using the igniterlabs-loyaltypoints::loyalty-form Livewire component, customers can apply their loyalty points as a discount during checkout. Customers may enter the number of points they want to redeem and apply them to their cart.

<livewire:igniterlabs-loyaltypoints::loyalty-form />

This form can be added anywhere on the checkout page and only displayed if the customer is logged in and points are enabled.

All loyalty transactions are tracked in a history table for auditing. Each record includes:

  • Customer: Who earned/redeemed the points
  • Order: Which order the points are tied to (if applicable)
  • Type: How points were earned (order purchase, registration bonus, review bonus, or redemption)
  • Points Earned: Points added to the customer's account
  • Points Used: Points consumed in a redemption
  • Status: Whether the transaction is active (true) or cancelled (false)
  • Validity Period: When the points become available and when they expire
  • Location: Which location earned the points (if location-specific mode is enabled)

This section covers how to integrate the Loyalty Points extension into your own extension if you're building an extension.

Award points to a customer for an order:

use Igniter\Cart\Models\Order;
use IgniterLabs\LoyaltyPoints\Classes\LoyaltyManager;

$order = Order::find(123);
$loyaltyManager = resolve(LoyaltyManager::class);

// Earn points for the order
$pointsEarned = $loyaltyManager->earnPoints($order);

// If loyalty discount was applied, subtract it from earning calculation
$redemptionDiscount = 10.50;
$pointsEarned = $loyaltyManager->earnPoints($order, $redemptionDiscount);

Returns the number of points earned (float).

Redeem points for a customer on an order:

$order = Order::find(123);
$loyaltyManager = resolve(LoyaltyManager::class);

// Redeem points (the amount is taken from the cart condition)
$pointsRedeemed = $loyaltyManager->redeemPoints($order);

Returns the number of points redeemed (float). Points must be added to the cart via the redemption form or cart condition first.

Get the customer's current point balance:

use IgniterLabs\LoyaltyPoints\Classes\LoyaltyManager;

$customerId = 42;
$locationId = null; // Optional, required if location-specific mode is enabled

$loyaltyManager = resolve(LoyaltyManager::class);
$available = $loyaltyManager->getAvailablePoints($customerId, $locationId);
// Returns: 150.5 (float)

Convert points to their cash equivalent:

$pointsValue = $loyaltyManager->calculatePointsValue(100);
// If point value is $0.10, returns: 10.00 (float)

Determine how many points are needed for a specific discount amount:

$pointsNeeded = $loyaltyManager->calculatePointsRequired(50.00);
// If point value is $0.10, returns: 500 (int)

When an order status changes (e.g., completed to cancelled), toggle the associated loyalty points:

use Igniter\Cart\Models\Order;
use IgniterLabs\LoyaltyPoints\Classes\LoyaltyManager;

$order = Order::find(123);
$loyaltyManager = resolve(LoyaltyManager::class);

// Activate points (make them usable)
$loyaltyManager->updateOrderStatus($order, true);

// Deactivate points (cancel them)
$loyaltyManager->updateOrderStatus($order, false);

Access loyalty settings with support for location-specific overrides:

use Igniter\Local\Models\Location;
use IgniterLabs\LoyaltyPoints\Classes\LoyaltyManager;

$location = Location::find(1);
$loyaltyManager = resolve(LoyaltyManager::class);

// Get a setting, checking location override first
$value = $loyaltyManager->getSetting('spending_minimum', 1, $location);

// Check if location has overrides enabled
$hasOverride = $loyaltyManager->hasLocationOverride($location);

The extension dispatches events that you can listen to:

Fired when a customer earns loyalty points from an order:

Event::listen('igniterlabs.loyaltypoints.pointsEarned', function($loyaltyHistory, $order) {
    // $loyaltyHistory: IgniterLabs\LoyaltyPoints\Models\LoyaltyHistory model
    // $order: `Igniter\Cart\Models\Order` model

    // Example: Send email notification
    Mail::send('points_earned', [
        'customer' => $order->customer,
        'points' => $loyaltyHistory->points_earned,
    ]);
});

Fired when a customer redeems loyalty points:

Event::listen('igniterlabs.loyaltypoints.pointsRedeemed', function($loyaltyHistory, $order) {
    // $loyaltyHistory: IgniterLabs\LoyaltyPoints\Models\LoyaltyHistory model
    // $order: `Igniter\Cart\Models\Order` model

    // Example: Log redemption
    logger('Redeemed', [
        'customer_id' => $order->customer_id,
        'points' => $loyaltyHistory->points_used,
    ]);
});

Two permissions control access to loyalty features in the admin panel:

| Permission | Purpose | |------------------------------------|--------------------------------------------| | IgniterLabs.LoyaltyPoints.Manage | Allow viewing and editing loyalty settings | | IgniterLabs.LoyaltyPoints.View | Allow viewing loyalty history (read-only) |

Assign these in Manage > Staff members > Roles.

This extension provides REST API endpoints for accessing loyalty data programmatically. These endpoints require the tastyigniter/ti-ext-api extension.

API tokens must have the loyalty:* ability to access these endpoints.

| Method | Endpoint | Permission | Description | |--------|------------------------|-------------|----------------------------------------------------------| | GET | /api/loyalty_balance | users | Get authenticated customer's points balance | | GET | /api/loyalty | users/admin | List loyalty history (customers see own, admins see all) | | GET | /api/loyalty/{id} | users/admin | Get specific history record |

Retrieves the authenticated customer's loyalty points balance.

Required abilities: loyalty:*

GET /api/loyalty_balance

Attributes

| Key | Type | Description | |---------------------|-----------|---------------------------------------------------------------------| | customer_id | integer | The unique identifier of the customer. | | location_id | integer | The location ID if location-specific points are enabled, else null. | | available_points | float | The customer's available loyalty points balance. | | points_value | float | The monetary value of the available points. | | spending_settings | object | Configuration for how points can be spent (see below). |

Spending settings object

| Key | Type | Description | |------------------------|-----------|--------------------------------------------------------| | points_per_currency | float | The monetary value of each point when redeemed. | | minimum_points | integer | Minimum points required to make a redemption. | | maximum_points | integer | Maximum percentage of order total payable with points. | | minimum_order_total | float | Minimum order value required to redeem points. | | is_location_specific | boolean | Whether points are restricted to specific locations. |

| Key | Type | Description | |---------------|-----------|----------------------------------------------------------| | location_id | integer | Optional. Get balance for a specific location. |

Status: 200 OK
{
    "data": {
        "customer_id": 4,
        "location_id": null,
        "available_points": 150,
        "points_value": 1.50,
        "spending_settings": {
            "points_per_currency": 0.01,
            "minimum_points": 20,
            "maximum_points": 80,
            "minimum_order_total": 0,
            "is_location_specific": false
        }
    }
}

Retrieves a list of loyalty history records. Customers see only their own records.

Required abilities: loyalty:*

GET /api/loyalty

Attributes

| Key | Type | Description | |---------------------------|------------|---------------------------------------------------------------------| | order_id | integer | The unique identifier of the associated order, if any. | | type | string | The type of transaction: order, review, or registration. | | customer_id | integer | The unique identifier of the customer. | | location_id | integer | The unique identifier of the location, if location-specific. | | order_total | float | The order total that earned these points. | | points_earned | float | The number of points earned in this transaction. | | points_used | float | The number of points redeemed in this transaction. | | date_used | dateTime | The datetime when the points were earned or used. | | valid_from | dateTime | The datetime when the points become available for use. | | valid_to | dateTime | The datetime when the points expire. | | status | boolean | Has the value true if the record is active, false if cancelled. | | created_at | dateTime | The datetime when the record was created. | | updated_at | dateTime | The datetime when the record was last updated. | | customer_name | string | The name of the customer (computed). | | available_points | float | The customer's current available points balance (computed). | | date_used_formatted | string | Human-readable date (computed). | | points_earned_formatted | string | Formatted points earned with monetary value (computed). | | points_used_formatted | string | Formatted points used or "-" if none (computed). | | order_total_formatted | string | Formatted order total with currency (computed). | | status_formatted | string | Human-readable status (computed). | | type_formatted | string | Human-readable type label (computed). | | points_value | float | The monetary value of points earned (computed). |

| Key | Type | Description | |-------------|-----------|-------------------------------------------------------------------------------------------------------------------------------------| | page | integer | The page number. | | pageLimit | integer | The number of items per page (default: 20). | | customer | integer | Filter by customer ID (admin only). | | location | integer | Filter by location ID. | | type | string | Filter by type. Options: order, review, registration. | | enabled | boolean | Filter by status. Default: true. | | valid | boolean | If true, only return non-expired points within their validity period. | | include | string | What relations to include. Options: customer, order, location. Separate multiple with comma (e.g. ?include=customer,order). |

Status: 200 OK
{
    "data": [
        {
            "type": "loyaltyhistory",
            "id": "1",
            "attributes": {
                "order_id": 104,
                "type": "order",
                "customer_id": 4,
                "location_id": null,
                "order_total": 199,
                "points_earned": 39,
                "points_used": 0,
                "date_used": "2026-01-08T08:16:50.000000Z",
                "valid_from": "2026-01-08T08:16:50.000000Z",
                "valid_to": "2027-01-08T08:16:50.000000Z",
                "status": true,
                "created_at": "2026-01-08T08:16:50.000000Z",
                "updated_at": "2026-01-08T08:16:50.000000Z",
                "customer_name": "John Doe",
                "available_points": 39,
                "date_used_formatted": "Jan 08, 2026",
                "points_earned_formatted": "39 ($0.39)",
                "points_used_formatted": "-",
                "order_total_formatted": "$199.00",
                "status_formatted": "Enabled",
                "type_formatted": "Order Earned",
                "points_value": 0.39
            },
            "relationships": {
                "customer": {
                    "data": []
                },
                "order": {
                    "data": []
                },
                "location": {
                    "data": []
                }
            }
        }
    ],
    "included": [],
    "meta": {
        "pagination": {
            "total": 1,
            "count": 1,
            "per_page": 20,
            "current_page": 1,
            "total_pages": 1
        }
    },
    "links": {
        "self": "https://your.url/api/loyalty?page=1",
        "first": "https://your.url/api/loyalty?page=1",
        "last": "https://your.url/api/loyalty?page=1"
    }
}

Retrieves a single loyalty history record.

Required abilities: loyalty:*

GET /api/loyalty/:id

| Key | Type | Description | |-----------|----------|-------------------------------------------------------------------------------------------------------------------------------------| | include | string | What relations to include. Options: customer, order, location. Separate multiple with comma (e.g. ?include=customer,order). |

Status: 200 OK
{
    "data": {
        "type": "loyaltyhistory",
        "id": "1",
        "attributes": {
            "order_id": 104,
            "type": "order",
            "customer_id": 4,
            "location_id": null,
            "order_total": 199,
            "points_earned": 39,
            "points_used": 0,
            "date_used": "2026-01-08T08:16:50.000000Z",
            "valid_from": "2026-01-08T08:16:50.000000Z",
            "valid_to": "2027-01-08T08:16:50.000000Z",
            "status": true,
            "created_at": "2026-01-08T08:16:50.000000Z",
            "updated_at": "2026-01-08T08:16:50.000000Z",
            "customer_name": "John Doe",
            "available_points": 39,
            "date_used_formatted": "Jan 08, 2026",
            "points_earned_formatted": "39 ($0.39)",
            "points_used_formatted": "-",
            "order_total_formatted": "$199.00",
            "status_formatted": "Enabled",
            "type_formatted": "Order Earned",
            "points_value": 0.39
        },
        "relationships": {
            "customer": {
                "data": []
            },
            "order": {
                "data": []
            },
            "location": {
                "data": []
            }
        }
    },
    "included": []
}

Did this answer your question?

Your feedback helps us improve our help articles.

Need more help?

Explore the help center, join the community, or get priority support from the TastyIgniter team.