Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Akeneo Client Laravel Package

justbetter/laravel-akeneo-client

A Laravel-friendly wrapper around Akeneo’s PHP API client, offering configuration, service container bindings, and convenient access to PIM products, categories, families, and other resources from your application.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the client and publish its config:

composer require justbetter/laravel-akeneo-client
php artisan vendor:publish --tag=akeneo-config

Add credentials to .env (names may differ slightly per version — check the published config/akeneo.php):

AKENEO_BASE_URI=https://your-pim.example.com
AKENEO_CLIENT_ID=1_abc123
AKENEO_CLIENT_SECRET=secret
AKENEO_USERNAME=api_user
AKENEO_PASSWORD=api_pass

The service provider registers the Akeneo PIM client in the container and exposes a facade. Your first use case is almost always a read: pull a page of products to confirm connectivity.

use Akeneo\Pim\ApiClient\AkeneoPimClientInterface;

$client = app(AkeneoPimClientInterface::class);

$page = $client->getProductApi()->listPerPage(10);
foreach ($page->getItems() as $product) {
    dump($product['identifier']);
}

Where to look first:

  1. config/akeneo.php — connection/base URI, credentials, and any HTTP options.
  2. The package's service provider — confirms exactly which interfaces are bound (the concrete AkeneoPimClientInterface, and possibly the individual API classes).
  3. The upstream akeneo/api-php-client docs — this package is a thin Laravel binding, so most behaviour you'll debug lives there.

Implementation Patterns

Inject the interface, never instantiate the client. Constructor injection into jobs, actions, and console commands keeps tests swappable and lets Laravel resolve the configured client:

class SyncProduct
{
    public function __construct(private AkeneoPimClientInterface $akeneo) {}

    public function handle(string $sku): void
    {
        $product = $this->akeneo->getProductApi()->get($sku);
        // map + persist locally
    }
}

Use the facade for terse, one-off calls in controllers or tinker-style scripts:

use JustBetter\Akeneo\Facades\Akeneo;

Akeneo::getProductApi()->get('SKU-123');

Paginate with cursors, not offsets. Akeneo's search API is paginated by search_after. The client's cursor() helper handles the loop for you:

$api = $client->getProductApi();

$cursor = $api->all(100, [
    'search' => ['updated' => [['operator' => '>', 'value' => $since]]],
    'pagination_type' => 'search_after',
]);

foreach ($cursor as $product) {
    // stream into your importer — do not collect() a whole catalog
}

Push work through the queue. API calls are I/O-bound and Akeneo has per-connection throttling. Wrap per-page or per-SKU work in jobs with ->onQueue('akeneo') and a RateLimited middleware so bursts don't get you 429s:

public function middleware(): array
{
    return [new RateLimited('akeneo')];
}

Model delta syncs around updated. Store a high-water mark (last successful run timestamp) instead of pulling the full catalog. Use the search filter above and commit the timestamp only after the batch succeeds, so a failure replays cleanly.

Upsert with upsertList for bulk writes, chunked to ~100 items to stay under request-size limits. Check the per-item response for 422s rather than assuming the batch succeeded.

Test with a fake binding. In TestCase or per-test, bind a mock of the interface so nothing leaves your process:

$this->mock(AkeneoPimClientInterface::class, function ($mock) {
    $mock->shouldReceive('getProductApi->get')->andReturn(['identifier' => 'SKU-1']);
});

If you need to swap the underlying client in local/dev environments, rebind AkeneoPimClientInterface in a service provider after the package's provider (order matters) and return a stub.

Gotchas and Tips

  • Base URI / request URL quirks. Version 1.6.1 is a fix for request URL construction. If you're upgrading from 1.6.0, verify your base_uri setting has no trailing slash mismatch — a malformed base URL silently produces wrong endpoint paths and confusing 404s. After upgrading, hit a single getProductApi()->get() in tinker to confirm the resolved URL before running any sync.
  • Config caching. Credentials read from .env inside the package config will be baked into the cached config. Run php artisan config:clear after changing any Akeneo env value, or your rotated secret will appear to have no effect.
  • Token caching. The Akeneo client authenticates per instance and caches a token in memory. A long-running queue worker can hold a stale token until it expires; if you see sporadic 401s in Horizon, restart workers after long idle periods or keep jobs short-lived.
  • Don't resolve the client in a singleton you register yourself unless you want one shared token across the whole process — usually fine, but it makes parallel testing and per-tenant credentials awkward.
  • The client is not multi-connection. There is no built-in notion of two PIMs. If you need more than one, instantiate the upstream AkeneoPimClientBuilder yourself with a second config block and bind it under a distinct key.
  • Errors surface as Guzzle exceptions. Wrap calls in try/catch on Akeneo\Pim\ApiClient\Exception\HttpException and inspect getResponse()->getBody() — Akeneo's validation messages are detailed and worth logging verbatim.
  • Pagination limits are hard-capped at 100. Asking for more throws. Also, search_after requires a deterministic sort order; without a proper sort on updated/identifier, you can silently skip or duplicate records.
  • Extension points. The provider resolves the client through the container, so the cleanest customisation is to rebind the interface in a later-registered provider (e.g. AppServiceProvider) and decorate it — add logging via a middleware handler on the Guzzle stack, or wrap API objects with your own retry/telemetry logic rather than forking the package.
  • Log correlation. Pass a X-Request-Id-style header through the Guzzle client options if you debug sync failures often; Akeneo support will ask for it.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle