revolution/laravel-amazon-product-api
Laravel package for integrating the Amazon Product Advertising API. Search products, look up details by ASIN, and retrieve pricing, images, and metadata through a simple, configurable client with Laravel-friendly setup.
Install and configure in three steps.
composer require revolution/laravel-amazon-product-api:^4.2
php artisan vendor:publish --tag=amazon-product-config # or --provider="Revolution\Amazon\Product\AmazonProductServiceProvider"
Version note: 4.2.0 dropped PHP 7.1 and Laravel 5.8 support, so
^4.2requires PHP ≥ 7.2 and Laravel ≥ 6. The same release declares end of active support — treat 4.2.x as the final line and pin the constraint explicitly rather than floating*. If you are stuck on PHP 7.1 / Laravel 5.8, pin^4.1and plan a migration.
Add credentials to .env (names match the published config):
AMAZON_ACCESS_KEY=AKIA...
AMAZON_SECRET_KEY=...
AMAZON_ASSOCIATE_TAG=yourtag-20
AMAZON_REGION=com # com | co.uk | de | co.jp | fr | it | es | ca | in ...
AMAZON_DEBUG=false
Then make your first call — typically an ASIN lookup for a product page:
use Revolution\Amazon\Product\Facades\AmazonProduct;
$response = AmazonProduct::item('B01N5IB20Q')->run();
$data = $response->json();
$title = data_get($data, 'ItemsResult.Items.0.ItemInfo.Title.DisplayValue');
Where to look first:
config/amazon-product.php — the region, host, and default resources keys are what everything else depends on.Revolution\Amazon\Product\Facades\AmazonProduct — it proxies the underlying client; each method (item, search, browseNodeLookup, getItems) returns a request builder that only fires when you call ->run().Revolution\Amazon\Product\Client — the class that signs requests and talks to the API; this is the seam to stub in tests or override for multi-region.The first real use case is almost always: ASIN → product detail block on a product page, backed by a cache. Do that before you attempt search or category browsing, because it exercises the whole auth/signature chain with the fewest moving parts.
Wrap the facade in a domain service, never call it from controllers or Blade. The package returns raw PA-API JSON; that shape is not something you want leaking into views.
class AmazonCatalog
{
public function __construct(private Cache $cache) {}
public function product(string $asin): ?ProductDto
{
return $this->cache->remember("amazon:item:{$asin}", now()->addHours(24), function () use ($asin) {
$json = AmazonProduct::item($asin)
->resources([
'ItemInfo.Title',
'ItemInfo.ByLineInfo',
'Images.Primary.Large',
'Offers.Listings.Price',
'BrowseNodeInfo.BrowseNodes',
])
->run()
->json();
if ($error = data_get($json, 'Errors.0')) {
Log::warning('PA-API error', $error);
return null;
}
return ProductDto::fromAmazon(data_get($json, 'ItemsResult.Items.0'));
});
}
}
Batch ASINs. getItems() accepts up to 10 ASINs per call — this is the single biggest cost saver. For a "related products" grid, do one call with 10 ASINs rather than ten item() calls.
Search + browse-node lookups for category pages. search() requires a SearchIndex (e.g. All, Electronics) alongside your keyword; browseNodeLookup() is how you discover the BrowseNodeId values to feed into it. Cache node trees — they change on a scale of weeks, not hours.
Throttle outbound work in a queue. PA-API gives you roughly 1 request/second and a fixed daily quota. Use Redis::throttle('amazon-paapi')->allow(1)->every(1)->then(...) inside a job, or a dedicated queue worker with --sleep. Never fan out an unbounded foreach of ASINs into synchronous calls.
Testing. Mock the facade in feature tests so no network call escapes CI:
AmazonProduct::shouldReceive('item->run->json')->andReturn($fixture);
Keep real captured JSON fixtures (a hit, an empty result, a TooManyRequests error) and test your DTO mapping against all three.
Integration tips.
null — never let a PA-API failure break a product page render.End of active support as of 4.2.0. The 4.2.0 release notes are essentially a maintenance tombstone: drop PHP 7.1 / Laravel 5.8 and stop active support. No new features are coming, and nothing will be patched if Amazon changes the PA-API wire format or if an illuminate/* constraint breaks against a future Laravel. Budget for one of: (a) pinning ^4.2 and freezing your Laravel major until you migrate, (b) a Composer replace/fork to widen constraints, or (c) dropping to the underlying revolution/amazon-product-api client and writing your own thin service provider. The wrapper is small; the client is the part doing real work.
Pin the constraint, and record which PHP/Laravel you need. ^4.2 is not interchangeable with ^4.1 — it silently raises your platform floor to PHP 7.2 / Laravel 6. In a monorepo or a shared CI image, a floating ^4.0 will resolve differently across machines. Pin the version, commit composer.lock, and add a platform.php entry if your deploy target lags your dev image.
PA-API 5.0 access is revocable. You must generate qualifying affiliate sales (currently three in 180 days) or Amazon revokes your keys. A silently failing integration is often a revoked account, not a code bug. Check the Errors[0].Code — AssociateNotEligible / AccessDenied mean the account, not the request.
Errors arrive with HTTP 200. The API returns an Errors array inside an otherwise-normal body. If you only check $response->successful() you will happily render empty product cards forever. Always inspect data_get($json, 'Errors.0') before touching Items.
Empty results are not errors. ItemsResult may be entirely absent when nothing matches, and data_get(..., 'ItemsResult.Items.0') will be null. Distinguish "no match" from "API failure" in your DTO so you can cache the negative result briefly and avoid hammering the API for a dead ASIN.
Resources must be exact. A typo like ItemInfo.Titles produces InvalidParameterValue for the whole request. Copy resource strings verbatim from the PA-API docs, and keep them in a config constant rather than scattered string literals.
Config caching bites. After changing .env credentials, run php artisan config:cache (or config:clear locally). A stale cached config with old keys yields confusing InvalidSignature errors that look like clock-skew problems.
Region and host are coupled. Setting region=co.jp without the matching host=webservices.amazon.co.jp yields 403s. Signature v4 signs against us-east-1 for most storefronts — do not override the signing region unless you know the specific exception.
Extension points worth knowing.
$this->app->bind(Client::class, ...)) to inject a custom Guzzle handler for logging or retry middleware.resources array globally; per-request ->resources() still wins.RetryMiddleware for 429/503 rather than hand-rolling backoff around ->run().Debugging checklist, in order: confirm the installed version (composer show revolution/laravel-amazon-product-api) matches what your code expects → credentials resolve from config → region/host/associate tag match the storefront → the Errors array is empty → ItemsResult.Items is non-empty → your DTO fields match the current API shape. Log the raw json() behind a debug flag; never log the secret key.
How can I help you explore Laravel packages today?