- Published on
Integrating with the Selling Partner API using Laravel
If you need help building custom e-commerce solutions, get in touch. We spend every day working on tools to speed up and improve e-commerce business processes.
We have built a lot of Laravel applications with our Selling Partner API library for PHP. After the umpteenth time re-integrating it, we did what any self-respecting developers would do and turned that integration into a library – and highsidelabs/laravel-spapi is that library.
Our library allows you to type-hint Selling Partner API classes into Laravel methods, which saves you from needing to build SP API configuration infrastructure. It supports both single-account setups (if you're a solo seller who needs to access the SP API) and more complex multi-account systems (if you own multiple seller accounts, or build tools that are authorized by multiple sellers).
Let's get started.
Installation
This is the easiest part: assuming you already have a Laravel project set up, install the package:
$ composer require highsidelabs/laravel-spapi
Then publish the library's Laravel configuration file:
$ php artisan vendor:publish --provider="HighsideLabs\LaravelSpApi\SellingPartnerApiServiceProvider" --tag="config"
That command places the library's config file in your config/
folder, so that you can edit it if you want. Later on we'll discuss some of the changes you might want to make.
Single-seller installations
Setup
Add some variables to your .env
:
SPAPI_AWS_ACCESS_KEY_ID=
SPAPI_AWS_SECRET_ACCESS_KEY=
SPAPI_LWA_CLIENT_ID=
SPAPI_LWA_CLIENT_SECRET=
SPAPI_LWA_REFRESH_TOKEN=
# Optional
# SPAPI_AWS_ROLE_ARN=
# SPAPI_ENDPOINT_REGION=
Fill in the AWS- and LWA-related variables with the relevant credentials. You only need to use the SPAPI_AWS_ROLE_ARN
environment variable if the IAM ARN you used to create your Selling Partner API application is a role ARN (rather than a user ARN). If you're not sure if this is you, it probably isn't – role ARNs look like arn:aws:iam::012345678901:role/<role name>
. For a detailed explanation of how to get the SP API credentials you need, check out our post on getting access to the Selling Partner API.
If the Seller account you're working with is in Amazon's North America region, you can leave the SPAPI_ENDPOINT_REGION
blank. If you're in one of the other regions, you'll want to populate it – valid values are NA
, EU
, and FE
. That will ensure you're making calls to the correct regional SP API endpoint.
Usage
When you're only using the Selling Partner API with a single set of seller credentials, usage is super simple. All you need to do is type-hint Selling Partner API classes into your methods, and you'll be able to make calls to the API! The example below assumes you have access to the Selling Partner Insights
role (more info on that here) in your SP API app configuration so that you can call the SellersV1Api::getMarketplaceParticipations()
endpoint, but the same principle applies to type-hinting any other Selling Partner API class.
Put this in app/Http/Controllers/SingleSellerController.php
:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
use SellingPartnerApi\Api\SellersV1Api as SellersApi;
use SellingPartnerApi\ApiException;
class SingleSellerController extends Controller
{
public function participations(SellersApi $api): JsonResponse
{
try {
$result = $api->getMarketplaceParticipations();
return response()->json($result);
} catch (ApiException $e) {
$jsonBody = json_decode($e->getResponseBody());
return response()->json($jsonBody, $e->getCode());
}
}
}
Then add this to routes/api.php
:
use App\Http\Controllers\SingleSellerController;
// ...
Route::get('/seller/participations', [SingleSellerController::class, 'participations'])
->name('seller.participations');
If you start your Laravel application with php artisan serve
and then go to http://localhost:8000/api/seller/participations
, you should see a JSON response that contains the Selling Partner API response data. If you get a 403 Unauthorized
error, you might not have access to the Selling Partner Insights
role mentioned earlier.
For single-seller setups, that's basically all there is to know! If you want to use this library to interface with the Selling Partner API using multiple sets of Seller credentials, keep on reading.
Multi-seller installations
If you work with more than one seller (people who build tools for Sellers fall into this category, for instance), or if you only have one Seller account but you sell in multiple regions (and therefore have multiple sets of credentials for the same Seller), this package supports that use case too.
Setup
To get started, change the installation_type
key in config/spapi.php
from single
to multi
. If the different sets of seller credentials you plan to use will have different AWS credentials, change aws.dynamic
to true
. If you operate multiple seller accounts, each of which has its own SP API application configured in Seller Central, and the different SP API applications were configured with separate AWS accounts, this applies to you...but if you're building an application that sellers authorize via OAuth, it probably doesn't. Most OAuth-based SP API applications will have the same AWS credentials associated with all authorized seller accounts.1
There are some database migrations associated with multi-seller installations, because we're going to store the different sets of credentials in the database. Publish those migrations:
$ php artisan vendor:publish --provider="HighsideLabs\LaravelSpApi\SellingPartnerApiServiceProvider" --tag="multi"
If you want to change anything about those tables, now is the time to do so. You can edit the two migration files that were just added to your database/migrations/
folder. The create_spapi_sellers_table
migration is intended to be extended with any fields you need to save business-specific data about a particular seller.
Run the migrations:
$ php artisan migrate
You will now have two new tables: spapi_sellers
and spapi_credentials
. spapi_sellers
is very simple, and mostly exists to link multiple sets of credentials for the same seller (which is a common need, since one seller will have a different set of credentials for each Amazon region they are active in). spapi_credentials
stores the actual tokens needed to make calls to the SP API, and links back to the spapi_sellers
table. There are corresponding Seller
and Credentials
models linked to those tables, which you can import from the HighsideLabs\LaravelSpApi\Models
namespace.2
If you changed the aws.dynamic
flag to true
in config/spapi.php
, you can leave your .env
alone. If you didn't change that configuration value, you will need to update your .env
to include your AWS credentials:
SPAPI_AWS_ACCESS_KEY_ID=
SPAPI_AWS_SECRET_ACCESS_KEY=
# SPAPI_AWS_ROLE_ARN=
As mentioned in the single-seller setup instructions, you only need to use the SPAPI_AWS_ROLE_ARN
environment variable if the IAM ARN you used to create your Selling Partner API application is a role ARN (rather than a user ARN).
Usage
Since we're working with multiple sets of Selling Partner API credentials, we need a way to specify which SP API credentials to use with a particular SP API class instance before we start actually making calls to the API with that instance. There are two ways to do that.
Auto-injected API classes with placeholder credentials
As with the single-seller setup, we can auto-inject SP API classes into methods in classes that are in the Laravel service container. The injected instance will have non-functional SP API credentials associated with it, so we need to retrieve some legitimate credentials and pass them to the API class instance:
<?php
namespace App\Http\Controllers;
use HighsideLabs\LaravelSpApi\Models\Credentials;
use Illuminate\Http\JsonResponse;
use SellingPartnerApi\Api\SellersV1Api as SellersApi;
use SellingPartnerApi\ApiException;
class MultiSellerController extends Controller
{
public function injected(SellersApi $api): JsonResponse
{
// Retrieve a set of credentials
$creds = Credentials::first();
// Inject the credentials into the API class instance
$creds->useOn($api);
try {
// Now we can make SP API calls!
$result = $api->getMarketplaceParticipations();
return response()->json($result);
} catch (ApiException $e) {
$jsonBody = json_decode($e->getResponseBody());
return response()->json($jsonBody, $e->getCode());
}
}
}
If we try to make a request with the SP API class instance without first injecting real credentials, we will get an error:
<?php
// ...
class MultiSellerController extends Controller
{
// ...
public function goingToFail(SellersApi $api): void
{
$api->getMarketplaceParticipations();
// Exception: You must call Credentials::useOn($apiInstance) before calling any API methods.
}
}
Create SP API classes yourself and inject credentials into them
We can also make an SP API class instance manually (without having Laravel auto-inject it) with the SellingPartnerApi::makeApi()
method:
<?php
// ...
use HighsideLabs\LaravelSpApi\SellingPartnerApi;
class MultiSellerController extends Controller
{
// ...
public function manual(): JsonResponse
{
// Retrieve the credentials we want to use to make the API call
$creds = Credentials::first();
// Generate an instance of a particular API class, already populated with the creds we retrieved above
$api = SellingPartnerApi::makeApi(SellersApi::class, $creds);
try {
// Then make an SP API call!
$result = $api->getMarketplaceParticipations();
return response()->json($result);
} catch (ApiException $e) {
$jsonBody = json_decode($e->getResponseBody());
return response()->json($jsonBody, $e->getCode());
}
}
}
Let's put this all together into one controller. Put this in your Laravel project, in app/Http/Controllers/MultiSellerController.php
:
<?php
namespace App\Http\Controllers;
use HighsideLabs\LaravelSpApi\Models\Credentials;
use HighsideLabs\LaravelSpApi\SellingPartnerApi;
use Illuminate\Http\JsonResponse;
use SellingPartnerApi\Api\SellersV1Api as SellersApi;
use SellingPartnerApi\ApiException;
class MultiSellerController extends Controller
{
public function injected(SellersApi $api): JsonResponse
{
// Retrieve a set of credentials
$creds = Credentials::first();
// Inject the credentials into the API class instance
$creds->useOn($api);
try {
// Now we can make SP API calls!
$result = $api->getMarketplaceParticipations();
return response()->json($result);
} catch (ApiException $e) {
$jsonBody = json_decode($e->getResponseBody());
return response()->json($jsonBody, $e->getCode());
}
}
public function manual(): JsonResponse
{
// Retrieve the credentials we want to use to make the API call
$creds = Credentials::first();
// Generate an instance of a particular API class, already populated with the creds we retrieved above
$api = SellingPartnerApi::makeApi(SellersApi::class, $creds);
try {
// Then make an SP API call!
$result = $api->getMarketplaceParticipations();
return response()->json($result);
} catch (ApiException $e) {
$jsonBody = json_decode($e->getResponseBody());
return response()->json($jsonBody, $e->getCode());
}
}
}
And then make those methods accessible by adding this to your routes/api.php
:
use App\Http\Controllers\MultiSellerController;
// ...
Route::controller(MultiSellerController::class)->group(function () {
Route::get('/multi/injected', 'injected')
->name('multiSeller.injected');
Route::get('/multi/manual', 'manual')
->name('multiSeller.manual');
});
To test this, we're going to need some actual SP API credentials in the database. Find a set of functional SP API credentials and save them to the database:
$ php artisan tinker
> use HighsideLabs\LaravelSpApi\Models;
> $seller = Models\Seller::create(['name' => 'My Seller']);
> $credentials = Models\Credentials::create([
'selling_partner_id' => 'ABCDEFGHIJK1234',
'region' => 'NA', # One of NA, EU, FE
'client_id' => 'amzn1.application-oa2-client......',
'client_secret' => 'e2c7......',
'refresh_token' => 'Aztr|IWeBI......',
'seller_id' => $seller->id,
# The following attributes are only relevant if you set `aws.dynamic` to true in config/spapi.php.
# If you have that value set to `false`, you can omit these attributes entirely
'access_key_id' => 'AKIA......',
'secret_access_key' => 'frhn12/......',
# As mentioned throughout this article, this is only needed if you configured your SP API app with an IAM role ARN
'role_arn' => 'arn::aws::iam::123456789012:role/myrolename',
]);
> ^D
Now we have a Seller and some Credentials, so the code in our controller will actually work! Try making GET
requests to localhost:8000/api/multi/injected
and localhost:8000/api/multi/manual
endpoints. If you set everything up right, and the credentials you added to the database are valid, you should get back a JSON response containing Selling Partner API seller participations data!
Wrapup
If you find any bugs in the library, please open a GitHub issue. If you have any questions or comments on this post, please feel free to email us! We'd love to hear from you.
We specialize in developing custom e-commerce API solutions, so if you need help with something related to this article, or with any other e-commerce integration, get in touch and we'll figure out how we can help.
Footnotes
If you ran the multi-seller migrations before realizing you needed dynamic AWS credentials, there's a secret migration you can use to fix that. First, make sure that the
aws.dynamic
config key is set totrue
. Here's how to use it:↩$ composer require doctrine/dbal # This is likely already installed, but just in case $ php artisan vendor:publish --provider="HighsideLabs\LaravelSpApi\SellingPartnerApiServiceProvider" --tag="add-aws" $ php artisan migrate
To modify the models used by this library, extend them in your Laravel project. For instance, if in the migrations you changed the name of the table that stores Selling Partner API credentials from
spapi_credentials
tocredentials
, you can make a model that reflects that like so:<?php namespace App\Models; use HighsideLabs\LaravelSpApi\Models\Credentials as SpApiCredentials; class Credentials extends SpApiCredentials { protected $table = 'credentials'; }
Then, everywhere that the
Credentials
model is referenced in thehighsidelabs/laravel-spapi
documentation, use yourCredentials
model fromApp\Models\Credentials
instead of the library's model (HighsideLabs\LaravelSpApi\Models\Credentials
). ↩