trilix/akeneo-events-api-bundle
A Symfony bundle for integrating Akeneo PIM events into your application via API endpoints. It helps receive and process Akeneo event payloads so your app can react to catalog changes such as product and category updates.
This is an Akeneo PIM (Symfony) bundle, not a Laravel package — there is no ServiceProvider, no config/akeneo-events.php, and no artisan command. Your day-to-day flow is: install it inside the Akeneo instance, let it emit catalog-change events, then consume those events from your Laravel app.
Inside the Akeneo codebase (not your Laravel repo):
composer require trilix/akeneo-events-api-bundle
Register the bundle in config/bundles.php (Trilix\EventsApiBundle\TrilixEventsApiBundle::class => ['all' => true]) and clear the cache (bin/console cache:clear).
Check the bundle's DependencyInjection/Configuration.php for the real config tree before touching YAML — the README is thin, and the config keys you need (transport, endpoint, credentials, enabled event types) live there. Copy the reference config into config/packages/ and drive secrets from .env (EVENTS_API_*).
First use case: enable product.updated (and product.created/product.deleted), point the transport at a webhook endpoint on your Laravel app or at an AMQP exchange, then save a product in Akeneo and confirm the payload arrives. That single loop validates install, config, auth, and consumer wiring in one go.
Where to look first: README.md → DependencyInjection/Configuration.php → the EventSubscriber/ and Model/ (or Event/) directories. Those three tell you what events exist, their payload shape, and how to hook in.
Treat Akeneo as the producer, Laravel as the consumer. Don't try to run the bundle in Laravel; expose a route in Laravel and let Akeneo POST to it (or subscribe to its queue).
Webhook receiver in Laravel — the most common integration shape:
Route::post('/webhooks/akeneo', AkeneoWebhookController::class)
->middleware('akeneo.signature');
class AkeneoWebhookController
{
public function __invoke(Request $request)
{
$event = $request->validate([
'event' => ['required', 'string'],
'identifier' => ['required', 'string'],
'payload' => ['required', 'array'],
]);
SyncAkeneoProduct::dispatch($event)->onQueue('akeneo');
return response()->noContent();
}
}
Acknowledge fast (200) and do the real work in a queued job. Akeneo will retry on non-2xx, and slow handlers cause cascading retries.
Queue consumer pattern (if the bundle publishes to AMQP/RabbitMQ): use php-amqplib or a enqueue-style adapter wrapped in a Laravel command, and dispatch a job per message. Keep the ack in the consumer, not the job — otherwise a crashed worker silently drops events.
Idempotency is not optional. Deliveries are at-least-once. Key your upsert on (event_type, identifier) plus the event's own id or a payload version/timestamp:
DB::transaction(function () use ($event) {
ProcessedEvent::firstOrCreate(['event_id' => $event['id']]); // unique index
Product::updateOrCreate(
['sku' => $event['identifier']],
['payload' => $event['payload'], 'synced_at' => now()],
);
});
Map, don't mirror. Akeneo payloads are wide (localized labels, channel/locale-scoped values, associations, family/attribute metadata). Normalize in a dedicated mapper class before hitting Eloquent, and store the raw payload in a json column for replay/debugging.
Handle the full event family, not just products. Expect product.created/updated/deleted, plus model, category, family, and attribute events depending on config. Deletes usually carry only an identifier — delete by SKU, don't expect a payload.
Reconcile out-of-band. Events can be missed (broker down, consumer bug). Schedule a nightly diff against Akeneo's REST API for a rolling window, or expose a manual akeneo:resync {sku} command.
composer.json constraints against your Akeneo (5.x vs 6.x vs 7.x changes the event model materially). A composer install that "succeeds" in the wrong Akeneo version often fails at cache warmup.updated can land before created. Either serialize per-SKU (queue routing key by identifier) or make upserts resilient to missing parents.post_max_size and queue job payload limits; consider storing a reference and fetching full detail via the REST API.failed_jobs review step; silent drops are the top cause of "the catalog is out of sync again" tickets.bin/console --env=prod cache:clear after config changes is mandatory), inspect the bundle's event subscriber logs, and log the raw inbound payload in Laravel before validation so malformed events are visible.EventSubscriber classes and normalizers are the intended seams. If you need an event it doesn't emit, subclass/extend the subscriber rather than forking; overrides survive composer updates.composer.json, and be prepared to maintain a fork. Budget time for that before adopting.How can I help you explore Laravel packages today?