exeu/apai-io
ApaiIO is a flexible PHP library for the Amazon Product Advertising API (REST or SOAP), with built-in operations like ItemSearch and ItemLookup. Interface-driven and extensible. Note: the project is discontinued—fork it to add features.
Bottom line: exeu/apai-io is a legacy adapter for the discontinued Amazon Product Advertising API v1. Use it only to maintain or isolate existing integrations, not for new Amazon product-data work. PA-API 5.0 is the current API, and this package was archived in 2018 with no upstream fixes, security patches, or 5.0 support.
Minimal setup in Laravel:
composer require exeu/apai-io
There is no Laravel service provider. Put credentials in config/services.php and .env:
// config/services.php
'amazon' => [
'country' => env('AMAZON_COUNTRY', 'com'),
'access_key' => env('AMAZON_ACCESS_KEY'),
'secret_key' => env('AMAZON_SECRET_KEY'),
'associate_tag' => env('AMAZON_ASSOCIATE_TAG'),
],
First place to look is the package’s src/ApaiIO directory:
Configuration/GenericConfiguration.php — credentials, marketplace, request/response wiringApaiIO.php — runOperation() entry pointOperations/Search.php and Lookup.php — the two operations you will use mostRequest/GuzzleRequest.php — HTTP transport and signing pathResponseTransformer/XmlToArray.php — the usual response decoderFirst use case: an ItemSearch for a category and keyword set, or an ItemLookup by ASIN. In Laravel, resolve it through a small service rather than in a controller:
use ApaiIO\ApaiIO;
use ApaiIO\Configuration\GenericConfiguration;
use ApaiIO\Operations\Search;
use ApaiIO\Request\GuzzleRequest;
use ApaiIO\ResponseTransformer\XmlToArray;
$config = new GenericConfiguration();
$config->setCountry(config('services.amazon.country'));
$config->setAccessKey(config('services.amazon.access_key'));
$config->setSecretKey(config('services.amazon.secret_key'));
$config->setAssociateTag(config('services.amazon.associate_tag'));
$config->setRequest(new GuzzleRequest());
$config->setResponse(new XmlToArray());
$apaiIO = new ApaiIO($config);
$search = new Search();
$search->setCategory('Books');
$search->setKeywords('laravel');
$search->setResponseGroup(['Large']);
$result = $apaiIO->runOperation($search);
Before writing feature code, run one live or fixture-backed search and dump the result shape. That tells you immediately whether the legacy endpoint still responds in your environment, and it exposes the array structure you will have to normalize.
Wrap the package behind your own interface. Do not let ApaiIO, GenericConfiguration, or operation classes leak into controllers, jobs, and Blade templates. Define something like ProductCatalog::search() and ProductCatalog::lookup(), bind it in a service provider, and implement it with apai-io. This makes a future PA-API 5.0 migration a single adapter swap.
Use a dedicated service/factory for configuration. The configuration object is mutable and holds credentials, marketplace, request, and response strategy. Build it once per marketplace, not per request, but do not share a mutable instance across long-running workers where different locales or associate tags are used.
Cache aggressively. PA-API rate limits are tight and the package does not provide a robust retry/throttle layer. Use Cache::remember() with a key composed of operation, marketplace, keywords/ASIN, response groups, and associate tag. Product data changes slowly enough that a short TTL is usually acceptable.
Queue batch work. For category crawls, wishlist enrichment, or bulk ASIN lookups, dispatch jobs and throttle them. Handle failures per item so one throttled request does not fail an entire batch. Add exponential backoff around the service call.
Normalize the XML-to-array output. Amazon’s XML converts to arrays where a single item is an associative array and multiple items are a list. Write one normalizer that always returns a list of products with stable fields such as asin, title, price, url, and image. Use data_get() defensively.
Use the extension points deliberately. The package is interface-oriented: custom operations, custom request classes, and custom response transformers are the intended extension points. If you must keep using it, implement a request wrapper that adds logging, timeouts, retries, and redaction around Guzzle rather than scattering that logic through callers. For a fork, preserve the interfaces and replace the v1 signing/endpoint internals with PA-API 5.0 behavior.
Test without hitting Amazon. Fake your ProductCatalog interface in feature tests. For adapter tests, store recorded XML responses as fixtures and run them through the same response transformer/normalizer. Do not make live API calls in CI.
The biggest gotcha is viability. This library targets PA-API v1 only and is explicitly discontinued. Live calls against Amazon may fail because of endpoint, authentication, or API-version changes. Treat any successful live call as provisional and verify against Amazon’s current PA-API 5.0 requirements before building product features on it.
Composer conflicts are likely. The last release was February 2018 and it predates modern Laravel/Guzzle/PSR constraints. Check composer why-not exeu/apai-io and test on your actual PHP version. If you must retain it in a modern Laravel app, isolate it in a separate package/service or fork it with updated dependency constraints.
Credentials and marketplace mapping are easy to misconfigure. The associate tag is required for most operations, and the country/marketplace value must match what the library expects for the endpoint. A wrong secret, clock skew, or a proxy that rewrites the query string can break request signing. Log the final request URL with credentials redacted, and compare it to the signature requirements.
Empty results are not always errors. Check the response’s request/error section before assuming “no products.” Distinguish authentication/signature failures, throttling, malformed parameters, and genuinely empty result sets. Handle each differently.
Do not rely on the package for rate limiting. Add caching, queue throttling, retries with backoff, and timeouts at your service boundary. In Laravel, that usually means a job middleware or a small wrapper around the ApaiIO call.
Avoid mutable singletons under Octane and queue workers. If you bind ApaiIO as a singleton and then change marketplace or associate tag on the shared configuration, requests can leak state between jobs. Use a scoped binding or a factory that returns a configured instance per marketplace.
Plan the exit. Because the package is archived and has no dependents in the current ecosystem, assume you own any fixes. Keep the adapter small, keep fixtures, and document the exact operations and response fields you depend on so migration to a maintained PA-API 5.0 SDK is mechanical rather than archaeological.
How can I help you explore Laravel packages today?