Version | PHP Version | Lightspeed Version | Support |
---|---|---|---|
alpha | ^7.4 | ^8.0 | 2 | 3 | Unsupported since 2023-11-14 |
1.0 | ^7.4 | ^8.0 | 2 | 3 | Unsupported since 2024-10-21 |
2.0 | ^8.0 | 2 | 3 | New features |
This package should be up to date with the Lightspeed API changes from 2024-07-31.
Via Composer
composer require timothydc/laravel-lightspeed-retail-api
For general information on how to use the Lightspeed Retail API, refer to the official documentation.
Before creating an API connection, you will need to sign up for an API client with Lightspeed Retail. You can do this via the client portal.
The API client is developer friendly, you can set https://your-domain.test
as your redirect URI.
Remember the value of your redirect URI, we will need it later on.
After your API client is approved you will receive a key
and secret
. Add those values to your .env
file.
LIGHTSPEED_RETAIL_API_KEY=xxx
LIGHTSPEED_RETAIL_API_SECRET=xxx
You can publish all resources, or you may choose to publish them separately:
php artisan vendor:publish --tag="lightspeed-api"
php artisan vendor:publish --tag="lightspeed-api:config"
php artisan vendor:publish --tag="lightspeed-api:migrations"
The API tokens are stored in the database, by default. So run your migrations.
php artisan migrate
Before we can request an access token you need to connect your Retail POS to this app.
You can manage the access level to your POS data via a scope. Choose a $scope
from the options in TimothyDC\LightspeedRetailApi\Scope
.
More information on the scopes can be found in the documentation.
php artisan retail:auth
The command will ask you about the scope, and you will get an URL in return. Excellent deal!
use TimothyDC\LightspeedRetailApi\Scope;
use TimothyDC\LightspeedRetailApi\Facades\LightspeedRetailApi;
$scope = Scope::EMPLOYEE_ALL;
return redirect()->to(LightspeedRetailApi::redirectToAuthorizationPortal($scope));
After requesting your initial access token you will be redirected to the Redirect URI
you provided when configuring your client information via the Lightspeed Retail API Client.
Register the following route in your routes/web.php
.
Update your-redirect-uri
with the redirect URI you entered in the API client.
use \TimothyDC\LightspeedRetailApi\Http\Controllers\SaveAccessTokenController;
Route::get('your-redirect-uri', [SaveAccessTokenController::class, '__invoke']);
The SaveAccessTokenController
will store the initial access token and make follow-up request for the refresh token.
Afterwards you will be redirected to RouteServiceProvider::HOME
.
If you would like to alter the redirect you may extend this controller.
You can now access the API. All resources return a Laravel collection... which means lots of fun!
use TimothyDC\LightspeedRetailApi\Facades\LightspeedRetailApi;
// get all
$account = LightspeedRetailApi::api()->account()->get();
// filter with GET with a limit and custom sorting (full details: https://developers.lightspeedhq.com/retail/introduction/parameters/)
$categories = LightspeedRetailApi::api()->category()->get(null, ['limit' => 10, 'sort' => 'name']);
// get category with ID 20
$categories = LightspeedRetailApi::api()->category()->get(20);
// same as above, but better
$categories = LightspeedRetailApi::api()->category()->first(20);
Note that not all resources are added (yet). Feel free to add them yourself via a pull request!
If you would like to filter the GET
-results you can look at the query parameters API
// advanced filtering
// get categories with an ID > 10
$categories = LightspeedRetailApi::api()->category()->get(null, ['categoryID' => ['operator' => '>', 'value' => 10]]);
// get products with their "Category" and "Note" relation
$products = LightspeedRetailApi::api()->item()->get(null, ['load_relations' => ['Category', 'Note']]);
// get sales sorted by timestamp in descending order
$sales = LightspeedRetailApi::api()->sale()->get(null, ['sort' => '-timestamp']);
As of V3 of the Lightspeed Retail API the pagination works cursor based. The full details of on how pagination works, you can find in the Pagination API documentation
use \TimothyDC\LightspeedRetailApi\Services\Lightspeed\ResourceSale;
$response = LightspeedRetailApi::api()->sale()->getWithPagination();
$attributes = $response['@attributes'];
// collect([
// 'next' => (request url),
// 'previous' => (request url),
// 'after' => (token),
// 'before' => (token),
// ])
$sales = $response[ResourceSale::$resource];
// Sales data as a collection
To get the next page of the resource, add the 'after' token to your request.
$response = LightspeedRetailApi::api()->sale()->getWithPagination(null, ['after' => $attributes->after]);
The 'after' attribute will be empty on the last page and the 'before' attribute will be empty on the first page. This is the same as the 'next' and 'previous' attributes as described in the Pagination API documentation
If you would like to automatically synchronise your data to Lightspeed,
you can add the HasLightspeedRetailResources
trait and the AutomaticSynchronisationInterface
interface to your model
In getLightspeedRetailResourceMapping()
you want to map your model fields to the Lightspeed resource.
The order of the resources is the order of the synchronisation.
In the example below we put the manufacturer resource before the product resource
because we need the manufacturer id
for when we are syncing the product.
In getLightspeedRetailResourceName()
you need to define the Lightspeed resource that represents your model. For example:
public function getLightspeedRetailResourceName(): string
{
return \TimothyDC\LightspeedRetailApi\Services\Lightspeed\ResourceItem::$resource;
}
Don't forget to add the HasLightspeedRetailResources
trait to your manufacturer
resource too.
use TimothyDC\LightspeedRetailApi\Traits\HasLightspeedRetailResources;
use TimothyDC\LightspeedRetailApi\Services\Lightspeed\{ResourceItem, ResourceVendor};
class Product extends \Illuminate\Database\Eloquent\Model
{
use HasLightspeedRetailResources;
public static function getLightspeedRetailResourceMapping(): array
{
return [
ResourceVendor::$resource => [
ResourceVendor::$name => 'product_vendor'
],
ResourceItem::$resource => [
ResourceItem::$description => 'name',
ResourceItem::$manufacturerId => ['manufacturer_id', 'manufacturer.id'],
ResourceItem::$archived => ['active', 'archive'],
],
];
}
}
You will notice some resources in the mapping have an array value. The first item in the array references the value which will be checked for a change, The second item is the value that will be sent to Lightspeed. It also accepts mutators:
In case of a relationship, the first value is the local foreign key. The second, is the related primary key.
public function getArchivedAttribute(): bool
{
return $this->attributes['active'] === false;
}
By default, the synchronisation process listens to your model events created
, updated
and deleted
.
Update the array if you want to listen to other events.
use TimothyDC\LightspeedRetailApi\Traits\HasLightspeedRetailResources;
class Product extends \Illuminate\Database\Eloquent\Model
{
use HasLightspeedRetailResources;
public static function getLightspeedRetailApiTriggerEvents(): array
{
return ['created', 'updated', 'deleted'];
}
}
If you would like to send fields to Lightspeed, even when the value isn't changed. You can add them to the $lsForceSyncFields
array.
use TimothyDC\LightspeedRetailApi\Traits\HasLightspeedRetailResources;
class Product extends \Illuminate\Database\Eloquent\Model
{
use HasLightspeedRetailResources;
public array $lsForceSyncFields = ['ean'];
}
Please see the changelog for more information on what has changed recently.
Please see contributing.md for details and a todolist.
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
- Timothy De Cort
- James Ratcliffe (https://github.com/jamesratcliffe/ls-retail-guzzle)
- All Contributors
MIT. Please see the license file for more information.