Installation
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
Getting started
This section walks you through setting up loyalty points for your restaurant so customers can earn and redeem points with every order.
Configuration
From your TastyIgniter Admin, navigate to Manage > Settings > Loyalty Points Settings in the admin panel to configure:
Enable loyalty points
- Go to Settings > Loyalty Points
- Switch on Enable Loyalty Points
- Click Save to activate the feature
Configure point values (redemption rate)
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.
- Go to Settings > Loyalty Points > Spending tab
- 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
- Click Save
Set earning rules
You can choose how customers earn points based on their spending. There are two methods:
Method 1: Fixed rate (simple)
Customers earn a consistent number of points per dollar spent.
- Go to Settings > Loyalty Points > Earning tab
- Select Earning Method > "Fixed Rate (X points per 100 spent)"
- 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
- Click Save
Method 2: Spending tiers (advanced)
Reward higher spenders with more points. Create multiple brackets based on order value (called "Earning Bands" in the settings).
- Go to Settings > Loyalty Points > Earning tab
- Select Earning Method > "Spending Tiers"
- 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
- Click Save
Configure points rounding
When calculating earned points, fractional amounts may occur. You can control how these are handled:
- Go to Settings > Loyalty Points > Earning tab
- 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
- Click Save
Include or exclude tax from earnings
By default, taxes are excluded when calculating points earned. You can change this:
- Go to Settings > Loyalty Points > Earning tab
- 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
- Click Save
Set point expiry and activation delay
Control when earned points become usable and when they expire:
- Go to Settings > Loyalty Points > Earning tab
- 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.
- Click Save
Control when points can be redeemed
You can restrict when customers are allowed to redeem their points (e.g., only on certain days or times):
- Go to Settings > Loyalty Points > Spending tab
- 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)
- Configure dates and times based on your selection
- Click Save
Set redemption restrictions
Control how customers can redeem points with these options:
- Go to Settings > Loyalty Points > Spending tab
- 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 |
Restrict points to specific items
By default, points can be redeemed against the entire order. You can limit points to specific menu items or categories:
- Go to Settings > Loyalty Points > Spending tab
- Switch on Apply to Specific Menu Items Only
- Select Applicable Categories and/or Applicable Menu Items that points can be used on
- Click Save
Now points can only discount the selected items/categories.
Set up bonus points
Reward customers for non-purchase actions to grow engagement:
- Go to Settings > Loyalty Points > Earning tab
- 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)
- Enter the point amounts (e.g., 50 points for registration, 25 for reviews)
- Click Save
Use location-specific points (multi-location only)
If you operate multiple locations, you can require customers to earn and spend points at the same location:
- Go to Settings > Loyalty Points > General tab
- 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
- Click Save
You can also override settings per location:
- Go to Manage > Locations
- Find the location you want to customize and click the settings icon (gear/cog)
- Navigate to the Loyalty Points tab
- Switch on Override Default Settings
- Customize earning/spending rules for just this location
- Click Save
Customer Loyalty Dashboard (view points & history)
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 pagesortOrder- (string, default: 'date_used desc') - Sort order options: 'date_used desc', 'date_used asc'showTotalEarned- (boolean, default: true) - Show total earned card
Checkout Integration
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.
Understanding loyalty history
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)
Usage
This section covers how to integrate the Loyalty Points extension into your own extension if you're building an extension.
Earning points programmatically
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).
Redeeming points programmatically
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.
Check available points
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)
Calculate monetary value of points
Convert points to their cash equivalent:
$pointsValue = $loyaltyManager->calculatePointsValue(100);
// If point value is $0.10, returns: 10.00 (float)
Calculate points needed for a discount
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)
Update order status
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);
Get settings with location override
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);
Available events
The extension dispatches events that you can listen to:
Points earned event
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,
]);
});
Points redeemed event
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,
]);
});
Permissions
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.
API Endpoints
This extension provides REST API endpoints for accessing loyalty data programmatically. These endpoints require the tastyigniter/ti-ext-api extension.
Authentication
API tokens must have the loyalty:* ability to access these endpoints.
Available 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 |
Get loyalty balance
Retrieves the authenticated customer's loyalty points balance.
Required abilities: loyalty:*
GET /api/loyalty_balance
The loyalty balance object
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. |
Parameters
| Key | Type | Description |
|---------------|-----------|----------------------------------------------------------|
| location_id | integer | Optional. Get balance for a specific location. |
Response
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
}
}
}
List loyalty history
Retrieves a list of loyalty history records. Customers see only their own records.
Required abilities: loyalty:*
GET /api/loyalty
The loyalty history object
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). |
Parameters
| 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). |
Response
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"
}
}
Retrieve a loyalty history record
Retrieves a single loyalty history record.
Required abilities: loyalty:*
GET /api/loyalty/:id
Parameters
| Key | Type | Description |
|-----------|----------|-------------------------------------------------------------------------------------------------------------------------------------|
| include | string | What relations to include. Options: customer, order, location. Separate multiple with comma (e.g. ?include=customer,order). |
Response
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": []
}