emporiqa / sylius-plugin
Integrates Sylius with Emporiqa, an AI shop assistant for sales and support in your shop's chat and customer emails.
Package info
Type:sylius-plugin
pkg:composer/emporiqa/sylius-plugin
Requires
- php: >=8.1
- doctrine/doctrine-bundle: ^2.9 || ^3.0
- sylius/sylius: ^1.12 || ^2.0
- symfony/http-client: ^6.4 || ^7.0 || ^8.0
- symfony/security-bundle: ^6.4 || ^7.0 || ^8.0
Requires (Dev)
- phpunit/phpunit: ^10.0 || ^11.0
- symfony/test-pack: ^1.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-26 07:57:21 UTC
README
Integrates Sylius with Emporiqa, an AI shop assistant for sales and support, in the chat on your shop and in your shop's customer emails, working with your team: a person can take over any chat. The plugin provides webhook-based synchronization of products and pages, in-chat cart operations with checkout, an embeddable chat widget, order status lookups, and order completion webhooks.
The chat reads your synced catalog and pages: a shopper describes what they need (or uploads a photo), and it returns matching products, answers questions from your own content, and drives cart and checkout through the plugin's APIs. It answers in 65 languages, whichever the shopper writes in.
Emporiqa also drafts replies to your shop's customer emails: connect your shop's mailbox (Gmail, Google Workspace, Microsoft 365, Outlook.com, IONOS, Strato, OVHcloud or any IMAP mailbox) in your Emporiqa dashboard and it drafts each reply from your catalog and pages, in the customer's language. Order details in drafts, and automatic replies, work on Gmail, Google Workspace and Microsoft (Outlook.com and Microsoft 365). Automatic replies are off until you switch them on. They cover only topics your team has already answered many times without changing the draft, and each waits 10 minutes so anyone can stop it. Every other reply is a draft your team checks and sends from your own address. Emporiqa never refunds, cancels or changes an order. Nothing to set up in Sylius.
Try it yourself on the live demo store, or watch the 30-second demo (a shopper's question, the recommendation, the cart).
The chat runs on your storefront, reads your catalog and answers in the shopper's own words:
Documentation
Everything beyond this page lives in the full developer documentation at emporiqa.com/docs/sylius/. It covers the configuration reference, webhook events and payloads, the cart and checkout API, order status, console commands, customization, and troubleshooting.
Features
- Product Sync: Real-time synchronization of Sylius products and variants via webhooks
- Page Sync: Synchronization of any translatable page entity (policies, FAQ, blog posts, etc.)
- Multi-Channel: Consolidated events with per-channel pricing, availability, and content across all languages
- Cart & Checkout: REST API for in-chat cart operations (add, update, remove, clear, view, checkout URL) with event hooks
- Order Status rule: Emporiqa's ready-made Order status rule looks orders up through a signed, rate-limited endpoint; a signed-in shopper gives only the number of an order they placed signed in
- Signed-in customers: a signed-in shopper sees the price your shop calculates for them, is greeted by first name, and is not asked for a name or email when the chat passes them to your team
- Other ready-made rules: under Settings > Rules in Emporiqa, returns, cancellations, order changes, quotes and invoice requests go to your team by email
- Customer info: the plugin tells Emporiqa a signed-in shopper's name, email and newest orders (
actions/customer-info). Emporiqa uses it to answer "where is my order?" with their newest order when they give no number, and to fill in their email in your rules - Order Completion: Webhook notification when checkout completes (supports both Sylius 1.x and 2.x)
- Chat Widget: Cache-safe embeddable chat widget with currency/channel awareness; a signed-in shopper's token comes from an uncached endpoint, never from the page
- Visual Search: Shoppers upload a photo in the widget; the chat matches it against your synced Sylius catalog (no extra config required)
- Voice Conversations (optional, off by default): the shopper taps the microphone, speaks, and hears the answer read aloud while the product cards stay on screen. $0.15 more per voice conversation
- Widget Appearance: up to four starter questions per language under the welcome message, your store's picture in the chat header and next to the chat's answers, and your team's own names and photos on their replies
- Multi-language: Syncs content in all configured Sylius locales with currency switcher support. The chat itself answers in 65 languages, independent of which locales you sync. A locale left out of
enabled_languagesis not synced, and its pages show no chat - Console Commands: Memory-efficient sync commands with batching, dry-run, and session management
- Webhook Retry: Automatic retry with backoff for transient failures; changes Emporiqa did not accept (down, a wrong secret) are kept and sent again with the next change
- Only what the shop shows: a disabled product, variant or page is removed from Emporiqa, so the chat never links a page your shop answers with 404
- Fully Extensible: Decorate any service interface, listen to events (
PostFormatEvent,CartOperationEvent,PreSyncEvent, etc.)
Emporiqa also works with Drupal Commerce, WooCommerce, Magento, PrestaShop, Shopware, and any store via webhook API. One Emporiqa account and dashboard runs across all of them.
Requirements
- PHP 8.1+ (Sylius 2.3 itself needs PHP 8.3+, and Symfony 8 needs PHP 8.4+)
- Sylius 1.12 or later 1.x, or Sylius 2.0 to 2.3
- Symfony 6.4, 7.x or 8.x (6.0 to 6.3 are not supported)
- An Emporiqa account (sign up)
Checked on Sylius 2.3 with Symfony 8.1 and PHP 8.4, Sylius 2.2 with Symfony 7.4 and PHP 8.3, and Sylius 1.12 with Symfony 6.4 and PHP 8.1. Sylius 1.12 and 1.13 no longer get security fixes, and a current Composer refuses to install them unless their advisories are ignored: upgrade Sylius first.
Installation
There is no Sylius admin screen yet: setup is done by your developer in configuration. The plugin adds no database tables, so there are no migrations to run. The steps, each detailed below:
composer require emporiqa/sylius-plugin- Register the bundle in
config/bundles.php, if Symfony Flex has not added it - Import the plugin's routes in
config/routes/emporiqa.yaml - Create
config/packages/emporiqa.yaml, reading the store id, webhook URL and webhook secret from environment variables - Set
EMPORIQA_STORE_ID,EMPORIQA_WEBHOOK_URLandEMPORIQA_WEBHOOK_SECRET(from your Emporiqa dashboard) andSITE_URLin.env - Add the chat widget to your shop layout, then run
bin/console assets:installandbin/console cache:clear - Run
bin/console emporiqa:test-connection, thenbin/console emporiqa:sync:all - Test the chat in your Emporiqa dashboard and press Go live
composer require emporiqa/sylius-plugin
Register the Plugin
Add to config/bundles.php:
return [ // ... other bundles Emporiqa\SyliusPlugin\EmporiqaPlugin::class => ['all' => true], ];
Import Routes
Create config/routes/emporiqa.yaml:
emporiqa: resource: '@EmporiqaPlugin/config/routes.yaml'
This registers the Order status endpoints, the cart API endpoints, and the customer token endpoint. If you don't need some features, you can disable them individually in configuration.
Create Configuration
Create config/packages/emporiqa.yaml:
emporiqa: store_id: '%env(EMPORIQA_STORE_ID)%' webhook_url: '%env(EMPORIQA_WEBHOOK_URL)%' webhook_secret: '%env(EMPORIQA_WEBHOOK_SECRET)%'
These three are required. All other settings have sensible defaults. See the Configuration Reference for the full list.
Environment Variables
Add to your .env file:
EMPORIQA_STORE_ID=your_store_id EMPORIQA_WEBHOOK_URL=https://emporiqa.com/webhooks/sync/ EMPORIQA_WEBHOOK_SECRET=your_secret_key
Add the Chat Widget
In your shop layout template (e.g. templates/bundles/SyliusShopBundle/Layout/base.html.twig), add before </body>:
{# With cart support (recommended) #} {{ emporiqa_cart_widget() }} {# Or simple inline embed without cart #} {{ emporiqa_widget() }}
Install Bundle Assets
bin/console assets:install
This copies the plugin's JavaScript files (emporiqa-cart.js, emporiqa-customer-token.js) to public/bundles/emporiqaplugin/js/.
Clear Cache
bin/console cache:clear
Set the Router Default URI
Console commands run without an HTTP request, so the router needs a base URI to generate absolute product links. In config/packages/framework.yaml:
framework: router: default_uri: '%env(SITE_URL)%'
And in .env:
SITE_URL=https://your-store.com
Verify the connection with bin/console emporiqa:test-connection, then run a first full sync with bin/console emporiqa:sync:all. When the sync is done, test the chat in your Emporiqa dashboard and press Go live. New stores start with the chat off, so shoppers see nothing until you do. You can also set it up from Claude or ChatGPT: connect your assistant and it creates your store, sets up the chat and walks you through the install (emporiqa.com/docs/ai-assistants/); you install the plugin and press Go live yourself. The developer documentation has the widget variants and the rest of the reference.
Order status
Emporiqa's ready-made Order status rule is how the chat answers "where is my order?" from your Sylius orders.
- Set
framework.router.default_urito your shop's https address (the address must be https). - Run
bin/console emporiqa:test-connection. Under Ready-made rules it prints your Order status address (https://your-store.com/emporiqa/api/) and whether the rule is On. - In Emporiqa, add the Order status rule (Settings > Rules). It asks for this address: paste it there, then click the link Emporiqa emails you to confirm it.
- Try it with one of your recent order numbers and its email, then click Go live.
Shoppers who are not signed in prove an order with its number and email. A signed-in shopper is matched by their Sylius customer id, for the orders they placed signed in; an order placed as a guest (even with the same email) still needs its email. When an email is given, the email is the proof and the customer id is not checked, so a signed-in shopper can also look up a guest order they placed with another email.
Once the order is proved, the chat can answer its status and tracking, and its details when the shopper asks: what was ordered, the totals, payment, shipping method and delivery time, and the shipping and billing addresses.
The other ready-made rules under Settings > Rules in Emporiqa pass returns, cancellations, order changes, quotes and invoice requests to your team by email, with no plugin endpoint involved.
To change that answer or add your own details, listen to
OrderStatusEvent (emporiqa.order_status). It runs after the answer is
filled. Put your own fields under extra (at most 3 levels deep, 30 keys,
strings up to 500 characters):
use Emporiqa\SyliusPlugin\Event\OrderStatusEvent; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; #[AsEventListener(event: OrderStatusEvent::NAME)] final class GiftWrapOrderStatusListener { public function __invoke(OrderStatusEvent $event): void { $data = $event->getData(); $data['extra']['gift_wrap'] = true; $event->setData($data); } }
The same address also answers actions/customer-prices, which gives
Emporiqa the prices a signed-in customer pays. In Sylius core that is the
channel price with its catalog promotions, the same as the synced price.
Customer info
The same address answers actions/customer-info: for a signed-in shopper
(matched by their Sylius customer id from a token Emporiqa verified), the
account's name, first and last name and email, and up to 10 of the
orders they placed signed in, newest first: number, date, status, total
and currency. Carts, guest checkouts (also those with the account's email,
which Sylius keeps on the same customer record), and orders in channels
the plugin does not sync are left out. Nothing else is sent: no
addresses, phone or internal ids. There is nothing to set up.
To remove fields or add your own, listen to CustomerInfoEvent
(emporiqa.customer_info). It runs after the answer is filled; extra
takes the same bounds as for Order status:
use Emporiqa\SyliusPlugin\Event\CustomerInfoEvent; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; #[AsEventListener(event: CustomerInfoEvent::NAME)] final class LoyaltyCustomerInfoListener { public function __invoke(CustomerInfoEvent $event): void { $data = $event->getData(); unset($data['customer']['email']); $data['extra']['loyalty_tier'] = 'gold'; $event->setData($data); } }
Customer info is limited to 30 calls per customer and 600 per store per 10 minutes.
The rate limits of these endpoints are counted in cache.app. If your shop
runs on more than one web server, that pool must be shared (Redis or
Memcached), not APCu.
The chat tells shoppers it is an AI
The default greeting says the shopper is talking to the store's AI assistant, in every language the chat speaks. A merchant who rewrites that greeting has to keep the disclosure: one that drops it is refused when saved. Emporiqa's Terms of Service section 8.6 treats removing it, including through custom CSS or custom code, as a breach.
Keeping your catalog in sync
Product, variant and page changes reach Emporiqa automatically through Sylius resource events and Doctrine listeners, including a variant added or deleted in the admin and a page edited in one language only. Delivery is synchronous: events queue per request and flush on kernel.terminate, so no messenger:consume worker, supervisord setup, or background cron is required. If Emporiqa does not accept a batch (it is down, or the secret is wrong after a change), the changed products and pages are noted in cache.app and sent again later, built again from your shop at that moment, so a retry never sends an older version than one Emporiqa already has. A retry rides on a later change that Emporiqa accepted: that change goes first, then at most 25 waiting items, oldest first, each tried at most once every 10 minutes. Up to 500 items wait, for at most 7 days and 20 tries each (spaced by those 10 minutes, so hours of outage); bin/console emporiqa:test-connection says how many are waiting, and a completed emporiqa:sync:all makes them unnecessary. With symfony/lock installed, the list is updated under a lock. A retried deletion of an item that is gone dispatches PreSyncEvent with operation delete and an Emporiqa\SyliusPlugin\Model\DeletedItem as the entity, so a listener that cancels deletions is honoured. Re-run bin/console emporiqa:sync:all after changes that do not re-save products (a new channel, locale or currency, a moved taxon, a changed tax rate or promotion, a renamed brand attribute, a bulk import that bypasses Doctrine events, or an extended outage on the Emporiqa side), and once a week as a safety net. The commands and their flags are documented in Console Commands.
Pricing
The plugin is free. Emporiqa is Pay-as-you-go: $0.25 per conversation and $0.15 per AI-drafted email reply you send, +$0.15 per voice conversation (optional, off by default). New stores get $25 of signup credit (about 100 conversations, once), no card required at signup. No seat fees, and AI model costs are included. You set a monthly limit on the billing page (new stores start at $199): a ceiling, not a charge, which you can raise, lower or clear. At the limit the chat is hidden from your shop and charging stops. Prices exclude VAT. Enterprise option for catalogs over 100,000 products. Full pricing at emporiqa.com/pricing/.
Support
- Integration overview: https://emporiqa.com/integrations/sylius/
- Documentation: https://emporiqa.com/docs/sylius/
- Issues: https://github.com/emporiqa/sylius/issues
- Email: support@emporiqa.com
License
MIT License - see LICENSE file for details.
Who makes Emporiqa
Emporiqa is built by Rosel Group LTD, an EU company based in Sofia, Bulgaria, founded by Rosen Hristov, who has built e-commerce software for 15 years. He works with every store himself, before and after the sale. It is GDPR-compliant and never uses shopper data to train AI models. This plugin is listed on Sylius Addons, which reviews every submission before it goes on the shelf, and it installs from Packagist with Composer.
