<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Spryker Documentation</title>
        <description>Spryker documentation center.</description>
        <link>https://docs.spryker.com/</link>
        <atom:link href="https://docs.spryker.com/feed.xml" rel="self" type="application/rss+xml"/>
        <lastBuildDate>Fri, 24 Jul 2026 09:07:28 +0000</lastBuildDate>
        <generator>Jekyll v4.2.2</generator>
        
        
        <item>
            <title>Vertex</title>
            <description>![vertex-hero](https://spryker.s3.eu-central-1.amazonaws.com/docs/pbc/all/tax-management/vertex/vertex.md/vertex-hero.png)

The Spryker Vertex module, based on the *Vertex O Series*, performs automatic, near-real-time tax calculations at the point of purchase while accounting for the following:

- Tax rates in each state, county, and city.
- Laws, rules, and jurisdiction boundaries.
- Special circumstances like tax holidays and product exemptions.

For more information about how Vertex calculates taxes, see the [Vertex O Series website](https://www.vertexinc.com/solutions/products/vertex-indirect-tax-o-series).

The Spryker Vertex module offers the following features that are worth considering when comparing it to the default Spryker [Tax Management capability](/docs/pbc/all/tax-management/latest/tax-management.html):

- *Configure Vertex in Spryker*: Add your Vertex configurations, including your company code, in `config/Shared/config_default.php` to connect your Spryker project to Vertex. Alternatively, you can manage every Vertex setting from the Back Office, per global or store scope, and choose the tax provider with the **Taxes** &gt; **Tax Provider** switch. For details, see [Configure Vertex in the Back Office](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/configure-vertex-in-the-back-office.html).
- *Tax determination and calculation*: View tax estimates during checkout and calculated taxes before generating an invoice. This feature works across all regions, including countries where taxes are included in the price.
- *Discounts Support*: The Vertex module uses both the discount and the amount paid by the customer, sending this information to Vertex for tax calculation and estimation.
- *Manage tax exemptions*: Configure your project to exclude tax-exempt customers using the Vertex module.
- *View invoice reports in Vertex dashboard*: The Vertex module allows customers to send invoice reports for paid orders from Spryker to Vertex. Customers can opt out of sending invoices to Spryker if they choose.
- *Support for refunds*: When order items are returned, refunded, or a paid order is canceled, the Vertex module updates the tax report in Vertex for accurate reporting and compliance.
- *Failover Solution*: Store owners and marketplace operators can manage refunds and ensure accurate tax reporting even during downtime.
- *Supported Product Types*: The integration currently supports tax calculation only for items/products created using Spryker Product capabilities.
- *Application of custom tax rules to products*: You can implement custom tax rules to accommodate unique product categorizations or specific tax regulations that apply to your business. The Vertex Integration provides a means for taxes to be calculated using these rules.

## Supported Use Cases and Business Models

1. Tax Calculation in Regions where taxes are excluded from prices. For example, in the US and Canada.
2. Tax Calculation in Regions where taxes are included in the price. For example, in the EU.
3. Marketplace: Every line item sent from Spryker to Vertex includes the customer&apos;s shipping address and the merchant&apos;s warehouse address, which Vertex uses for tax calculation.
4. Support for Delivery Terms: Vertex allows customers to set delivery terms within their dashboard, which are used in tax calculation. This is especially important for cross-border transactions when the seller wants to use the customer&apos;s location to determine the applicable tax rate.
5. Inclusion of Shipping Tax in the Total Tax Calculated: Spryker sends the selected shipping method to Vertex. The `delivery-method-key` set in Spryker is used for this purpose. Projects must ensure this is mapped correctly inside the Vertex dashboard by following the steps below:
   - In Vertex you create a Taxability Driver with the same value from Spryker
   - In Vertex you create a Taxability Mapping for the driver to one of Vertex&apos;s defined Delivery Charges

The following diagram demonstrates the flow of the Vertex integration:

![vertex-flow](https://spryker.s3.eu-central-1.amazonaws.com/docs/pbc/all/tax-management/vertex/vertex.md/vertex-flow.png)

## How Vertex calculates taxes for different countries

The Vertex module calculates taxes based on the tax rules and rates of the country where the product is shipped. The Vertex app uses the shipping address to determine the tax rate.

In some cases, the Vertex module can&apos;t calculate taxes and returns a 0 tax rate. For example, when a seller is located in EU, and the buyer is located in the US.

So, make sure your project has a logic for such cases. For example, when a buyer selects a shipping address different from the project&apos;s default tax region or country, a warehouse address in the respective region needs to be used.


## Product Class Code

The Product Class Code is used to represent groups or categories of products or services with identical taxability. By default, Spryker Product SKU is sent as `LineItems[].product.value` and `LineItems.lineItemId`. The Vertex module does not create any Vertex Tax Categories.

### Item Flexible Fields

Item Flexible Fields are optional fields provided by a project. They are needed for the customization of tax calculation. Flexible Fields are supported by the Vertex module, and whether or not to use them is a business decision.

## Freight tax for shipment

Spryker doesn&apos;t support freight shipment in terms of big packaging support; but calculation of taxes for shipping prices is supported.

## Sending invoices to Vertex through OMS

The Spryker OMS transition command is used as an execution point to send a full order with all existing and custom fields provided by the project. The results will be visible in the Invoice Tax Details report.



## Next steps

[Integrate Vertex](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html)
</description>
            <pubDate>Thu, 23 Jul 2026 10:10:41 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/vertex.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/vertex.html</guid>
            
            
        </item>
        
        <item>
            <title>Integrate Vertex</title>
            <description>This document describes how to integrate [Vertex](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/vertex.html) into a Spryker shop.

## Prerequisites

Before integrating Vertex, ensure the following prerequisites are met:

- Make sure that your deployment pipeline executes database migrations.

## 1. Install the module

Install the Vertex module using Composer:

```bash
composer require spryker-eco/vertex
```

## 2. Configure the module

{% info_block infoBox &quot;Manage settings in the Back Office&quot; %}

Instead of environment variables, you can manage every Vertex setting from the Back Office **Configuration**, per global or store scope, and choose the tax provider with a **Taxes** &gt; **Tax Provider** switch. This is opt-in and backward compatible. For details, see [Configure Vertex in the Back Office](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/configure-vertex-in-the-back-office.html).
If you decide so, skip this section.

{% endinfo_block %}

Add the following configuration to `config/Shared/config_default.php`:

```php
use SprykerEco\Shared\Vertex\VertexConstants;

$config[VertexConstants::IS_ACTIVE] = getenv(&apos;VERTEX_IS_ACTIVE&apos;);
$config[VertexConstants::CLIENT_ID] = getenv(&apos;VERTEX_CLIENT_ID&apos;);
$config[VertexConstants::CLIENT_SECRET] = getenv(&apos;VERTEX_CLIENT_SECRET&apos;);
$config[VertexConstants::SECURITY_URI] = getenv(&apos;VERTEX_SECURITY_URI&apos;);
$config[VertexConstants::TRANSACTION_CALLS_URI] = getenv(&apos;VERTEX_TRANSACTION_CALLS_URI&apos;);
// Optional: Tax ID Validator (requires Vertex Validator, previously known as Taxamo, see https://developer.vertexinc.com/vertex-e-commerce/docs/stand-alone-deployments)
$config[VertexConstants::TAXAMO_API_URL] = getenv(&apos;TAXAMO_API_URL&apos;);
$config[VertexConstants::TAXAMO_TOKEN] = getenv(&apos;TAXAMO_TOKEN&apos;);

// Optional: Vendor Code
$config[VertexConstants::VENDOR_CODE] = &apos;&apos;;
```

### Required configuration constants

| Constant | Description | Where to get the value |
|----------|-------------|------------------------|
| `IS_ACTIVE` | Enables or disables Vertex tax calculation. | Set to `true` to enable. |
| `CLIENT_ID` | OAuth client ID for the Vertex API. | Obtain from your Vertex account. For details, see [Vertex documentation](https://tax-calc-api.vertexcloud.com/resources/index.html). |
| `CLIENT_SECRET` | OAuth client secret for the Vertex API. | Obtain from your Vertex account. For details, see [Vertex documentation](https://tax-calc-api.vertexcloud.com/resources/index.html). |
| `SECURITY_URI` | Vertex OAuth security endpoint. | Obtain from your Vertex platform. For details, see [Vertex documentation](https://tax-calc-api.vertexcloud.com/resources/index.html). |
| `TRANSACTION_CALLS_URI` | Vertex transaction calls endpoint. | Obtain from your Vertex platform. For details, see [Vertex documentation](https://tax-calc-api.vertexcloud.com/resources/index.html). |

### Optional configuration constants

| Constant | Description | Where to get the value |
|----------|-------------|------------------------|
| `TAXAMO_API_URL` | Vertex Validator API URL for tax ID validation. | Obtain from your Vertex Validator environment. For details, see [Standalone Vertex Validator](https://developer.vertexinc.com/vertex-e-commerce/docs/stand-alone-deployments). |
| `TAXAMO_TOKEN` | Vertex Validator API authentication token. | Obtain from your Vertex Validator account. For details, see [Accessing the APIs](https://developer.vertexinc.com/vertex-marketplaces/docs/getting-started-1). |
| `VENDOR_CODE` | Vendor code for Vertex tax calculations. | Set in your Vertex account. |
| `DEFAULT_TAXPAYER_COMPANY_CODE` | Default taxpayer company code. | The company code you set in your Vertex account. |

## 3. Override feature flags

{% info_block warningBox %}
If you decided to use the Back Office Configuration, skip this section.
{% endinfo_block %}

The `isTaxIdValidatorEnabled`, `isTaxAssistEnabled`, and `isInvoicingEnabled` methods default to `false` and are not driven by constants. To enable them, override `src/Pyz/Zed/Vertex/VertexConfig.php`:

```php
namespace Pyz\Zed\Vertex;

use SprykerEco\Zed\Vertex\VertexConfig as SprykerEcoVertexConfig;

class VertexConfig extends SprykerEcoVertexConfig
{
    public function isTaxIdValidatorEnabled(): bool
    {
        return true;
    }

    public function isTaxAssistEnabled(array $configurationScopeTransfers = []): bool
    {
        return true;
    }

    public function isInvoicingEnabled(array $configurationScopeTransfers = []): bool
    {
        return true;
    }
}
```

### Config methods

The following methods must be overridden in `src/Pyz/Zed/Vertex/VertexConfig.php` to enable the respective features:

| Method | Default | Description                                                                                                                                                                       |
|--------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `isTaxIdValidatorEnabled()` | `false` | Enables tax ID validation via [Vertex Validator](https://developer.vertexinc.com/vertex-e-commerce/docs/stand-alone-deployments). Requires `TAXAMO_API_URL` and `TAXAMO_TOKEN` to be set.                                                                                     |
| `isTaxAssistEnabled()` | `false` | Enables the tax assist feature. Return Assisted Parameters in the response that will provide more details about the calculation. The logs can be checked in the Vertex Dashboard. |
| `isInvoicingEnabled()` | `false` | Enables invoicing functionality. Requires OMS plugins to be registered. See [Register OMS plugins](#register-oms-plugins).                                                        |
| `getSellerCountryCode()` | `&apos;&apos;` | Overrides the default seller country code (2-letter ISO code, for example, `US`). Defaults to the first country of the store.                                                     |
| `getCustomerCountryCode()` | `&apos;&apos;` | Overrides the default customer country code (applied only when no customer billing address is provided).  Defaults to the first country of the store.                             |

## 4. Set up the database schema

Install the database schema:

```bash
vendor/bin/console propel:install
```

## 5. Generate transfer objects

Generate transfer objects for the module:

```bash
vendor/bin/console transfer:generate
```

## 6. Import glossary data

The module provides translation data for tax validation messages.

**Option 1: Import using the module&apos;s configuration file**

```bash
vendor/bin/console data:import --config=vendor/spryker-eco/vertex/data/import/vertex.yml
```

**Option 2: Copy file content and import individually**

Copy content from `vendor/spryker-eco/vertex/data/import/*.csv` to the corresponding files in `data/import/common/common/`. Then run:

```bash
vendor/bin/console data:import glossary
```

**Option 3: Add to the project&apos;s main import configuration**

Add the import actions to your project&apos;s main data import configuration file and include them in your regular import pipeline.

## 7. Register plugins

### Register the tax calculation plugin

Add the Vertex calculation plugin to `src/Pyz/Zed/Calculation/CalculationDependencyProvider.php`:

```php
use SprykerEco\Zed\Vertex\Communication\Plugin\Calculation\VertexCalculationPlugin;

protected function getQuoteCalculatorPluginStack(Container $container): array
{
    return [
        //...

        # Suggested plugins order is shown.

        new ItemDiscountAmountFullAggregatorPlugin(),

        # This plugin is replacing other tax calculation plugins in the stack and will use them as a fallback.
        # No other tax calculation plugins except for VertexCalculationPlugin should be present in the stack.
        new VertexCalculationPlugin(),

        new PriceToPayAggregatorPlugin(),

        //...
    ];
}

protected function getOrderCalculatorPluginStack(Container $container): array
{
    return [
        //...

        # Suggested plugins order is shown.

        new ItemDiscountAmountFullAggregatorPlugin(),

        # This plugin is replacing other tax calculation plugins in the stack and will use them as a fallback.
        # No other tax calculation plugins except for VertexCalculationPlugin should be present in the stack.
        new VertexCalculationPlugin(),

        new PriceToPayAggregatorPlugin(),

        //...
    ];
}
```

#### Register Fallback Calculation Plugins

Add order and quote Fallback Calculation Plugins to `src/Pyz/Zed/Vertex/VertexDependencyProvider.php`:

```php
use Spryker\Zed\Calculation\Communication\Plugin\Calculator\ItemTaxAmountFullAggregatorPlugin;
use Spryker\Zed\Calculation\Communication\Plugin\Calculator\PriceToPayAggregatorPlugin;
use Spryker\Zed\Tax\Communication\Plugin\Calculator\TaxAmountAfterCancellationCalculatorPlugin;
use Spryker\Zed\Tax\Communication\Plugin\Calculator\TaxAmountCalculatorPlugin;
use Spryker\Zed\Tax\Communication\Plugin\Calculator\TaxRateAverageAggregatorPlugin;

/**
 * {@inheritDoc}
 *
 * @return array&lt;\Spryker\Zed\CalculationExtension\Dependency\Plugin\CalculationPluginInterface&gt;
 */
protected function getFallbackQuoteCalculationPlugins(): array
{
    return [
        # These plugins will be called if Vertex configuration is missing or Vertex is disabled.
        # Please note that this list includes PriceToPayAggregatorPlugin - this plugin isn&apos;t a part of tax calculation logic but it&apos;s required by TaxRateAverageAggregatorPlugin.
        new TaxAmountCalculatorPlugin(),
        new ItemTaxAmountFullAggregatorPlugin(),
        new PriceToPayAggregatorPlugin(),
        new TaxRateAverageAggregatorPlugin(),
    ];
}

/**
 * {@inheritDoc}
 *
 * @return array&lt;\Spryker\Zed\CalculationExtension\Dependency\Plugin\CalculationPluginInterface&gt;
 */
protected function getFallbackOrderCalculationPlugins(): array
{
    return [
        # These plugins will be called if Vertex configuration is missing or Vertex is disabled.
        # Please note that this list includes PriceToPayAggregatorPlugin - this plugin isn&apos;t a part of tax calculation logic but it&apos;s required by TaxAmountAfterCancellationCalculatorPlugin.
        new TaxAmountCalculatorPlugin(),
        new ItemTaxAmountFullAggregatorPlugin(),
        new PriceToPayAggregatorPlugin(),
        new TaxAmountAfterCancellationCalculatorPlugin(),
    ];
}
```

In general, `getFallbackQuoteCalculationPlugins()` and `getFallbackOrderCalculationPlugins()` methods should contain the tax calculation plugins, which are replaced by `VertexCalculationPlugin` in `\Pyz\Zed\Calculation\CalculationDependencyProvider`.
The code snippet above is an example of such configuration based on the Spryker default tax calculation plugins.
Tax calculation plugins moved:
- from `getQuoteCalculatorPluginStack` method: `TaxAmountCalculatorPlugin`, `ItemTaxAmountFullAggregatorPlugin`, `PriceToPayAggregatorPlugin`, `TaxRateAverageAggregatorPlugin`
- from `getOrderCalculatorPluginStack` method: `TaxAmountCalculatorPlugin`, `ItemTaxAmountFullAggregatorPlugin`, `PriceToPayAggregatorPlugin`, `TaxAmountAfterCancellationCalculatorPlugin`

{% info_block infoBox &quot;Fallback behavior&quot; %}

There are three different failure scenarios where `VertexCalculationPlugin` might need to use a fallback logic:

1. Vertex isn&apos;t connected: fallback plugins defined in `getFallbackQuoteCalculationPlugins()` and `getFallbackOrderCalculationPlugins()` will be used to calculate taxes.
2. Vertex is disabled: fallback plugins defined in `getFallbackQuoteCalculationPlugins()` and `getFallbackOrderCalculationPlugins()` will be used to calculate taxes.
3. Vertex is not responding or is responding with an error: tax value will be set to zero, and the customer will be able to proceed with the checkout.

{% endinfo_block %}

### Register CalculableObject and order expander plugins

Add order and CalculableObject expander plugins to `src/Pyz/Zed/Vertex/VertexDependencyProvider.php`. The proposed plugins are examples, you can select which ones to register based on your requirements or create custom ones if needed.

```php
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderCustomerWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderExpensesWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderItemProductOptionWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderItemWithVertexSpecificFieldsExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectCustomerWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectExpensesWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectItemProductOptionWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectItemWithVertexSpecificFieldsExpanderPlugin;

protected function getCalculableObjectVertexExpanderPlugins(): array
{
    return [
        // ... other plugins
        new CalculableObjectCustomerWithVertexCodeExpanderPlugin(),
        new CalculableObjectExpensesWithVertexCodeExpanderPlugin(),
        new CalculableObjectItemProductOptionWithVertexCodeExpanderPlugin(),
        new CalculableObjectItemWithVertexSpecificFieldsExpanderPlugin(),
    ];
}

protected function getOrderVertexExpanderPlugins(): array
{
    return [
        // ... other plugins
        new OrderCustomerWithVertexCodeExpanderPlugin(),
        new OrderExpensesWithVertexCodeExpanderPlugin(),
        new OrderItemProductOptionWithVertexCodeExpanderPlugin(),
        new OrderItemWithVertexSpecificFieldsExpanderPlugin(),
    ];
}
```

## 8. Configure the Shop Application dependency provider

Add the following code to `src/Pyz/Yves/ShopApplication/ShopApplicationDependencyProvider.php`:

```php

namespace Pyz\Yves\ShopApplication;

use SprykerShop\Yves\ShopApplication\ShopApplicationDependencyProvider as SprykerShopApplicationDependencyProvider;
use SprykerShop\Yves\CartPage\Widget\CartSummaryHideTaxAmountWidget;

class ShopApplicationDependencyProvider extends SprykerShopApplicationDependencyProvider
{
    /**
     * @phpstan-return array&lt;class-string&lt;\Spryker\Yves\Kernel\Widget\AbstractWidget&gt;&gt;
     *
     * @return array&lt;string&gt;
     */
    protected function getGlobalWidgets(): array
    {
        return [
            //...

            # This widget is replacing Spryker default tax display in cart summary page with text stating that tax amount will be calculated during checkout process.
            CartSummaryHideTaxAmountWidget::class,
        ];
    }
}

```

If you have custom Yves templates or make your own Frontend, add `CartSummaryHideTaxAmountWidget` to your template. The core template is located at `SprykerShop/Yves/CartPage/Theme/default/components/molecules/cart-summary/cart-summary.twig`.

Here is an example with `CartSummaryHideTaxAmountWidget`:

```html
{% raw %}
&lt;li class=&quot;list__item spacing-y&quot;&gt;
    {{ &apos;cart.total.tax_total&apos; | trans }}
    {% widget &apos;CartSummaryHideTaxAmountWidget&apos; args [data.cart] only %}
    {% nowidget %}
        &lt;span class=&quot;float-right&quot;&gt;{{ data.cart.totals.taxTotal.amount | money(true, data.cart.currency.code) }}&lt;/span&gt;
    {% endwidget %}
&lt;/li&gt;
{% endraw %}
```

## 9. Optional: Sending tax invoices to Vertex and handling refunds

Configure payment `config/Zed/oms/{your_payment_oms}.xml`as in the following example:

```xml
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;statemachine
    xmlns=&quot;spryker:oms-01&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;spryker:oms-01 http://static.spryker.com/oms-01.xsd&quot;
&gt;

    &lt;process name=&quot;SomePaymentProcess&quot; main=&quot;true&quot;&gt;

        &lt;!-- other configurations --&gt;

        &lt;states&gt;

            &lt;!-- other states --&gt;

            &lt;state name=&quot;tax invoice submitted&quot; reserved=&quot;true&quot; display=&quot;oms.state.paid&quot;/&gt;

            &lt;!-- other states --&gt;

        &lt;/states&gt;

        &lt;transitions&gt;

            &lt;!-- other transitions --&gt;

            &lt;transition happy=&quot;true&quot;&gt;
                &lt;source&gt;paid&lt;/source&gt; &lt;!-- Suggested that paid transition should be the source, but it&apos;s up to you --&gt;
                &lt;target&gt;tax invoice submitted&lt;/target&gt;
                &lt;event&gt;submit tax invoice&lt;/event&gt;
            &lt;/transition&gt;

            &lt;!-- other transitions --&gt;

            &lt;transition happy=&quot;true&quot;&gt;
                &lt;source&gt;tax invoice submitted&lt;/source&gt;

                &lt;!-- Here are the contents of the target transition --&gt;

            &lt;/transition&gt;

            &lt;!-- other transitions --&gt;

        &lt;/transitions&gt;

        &lt;events&gt;

            &lt;!-- other events --&gt;

            &lt;event name=&quot;submit tax invoice&quot; onEnter=&quot;true&quot; command=&quot;Vertex/SubmitPaymentTaxInvoice&quot;/&gt;

            &lt;!-- other events --&gt;

        &lt;/events&gt;

    &lt;/process&gt;

&lt;/statemachine&gt;
```

### Register OMS plugins

{% info_block infoBox &quot;Optional&quot; %}

This step is required only if you want to use invoicing functionality. Make sure `isInvoicingEnabled()` is set to `true` in `VertexConfig.php`.

{% endinfo_block %}

Add OMS plugins to `src/Pyz/Zed/Oms/OmsDependencyProvider.php`:

```php
use SprykerEco\Zed\Vertex\Communication\Plugin\Oms\Command\VertexSubmitPaymentTaxInvoicePlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Oms\VertexOrderRefundedEventListenerPlugin;

# This configuration is necessary for Invoice functionality
protected function extendCommandPlugins(Container $container): Container
{
    $container-&gt;extend(self::COMMAND_PLUGINS, function (CommandCollectionInterface $commandCollection) {
        // ... other command plugins
        $commandCollection-&gt;add(new VertexSubmitPaymentTaxInvoicePlugin(), &apos;Vertex/SubmitPaymentTaxInvoice&apos;);

        return $commandCollection;
    });

    return $container;
}

# This configuration is necessary for Refund functionality
protected function getOmsEventTriggeredListenerPlugins(Container $container): array
{
    return [
        // ... other plugins
        new VertexOrderRefundedEventListenerPlugin(),
    ];
}
```

This configuration of `getOmsEventTriggeredListenerPlugins` method is required to ensure that the correct tax amount will be used during the refund process.

{% info_block infoBox &quot;OMS configuration requirement&quot; %}

The refund functionality will only work if the OMS event is called `refund`.

{% endinfo_block %}

## Next steps

- [Configure Vertex-specific metadata](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/configure-vertex-specific-metadata.html)
- [Migrate from the ACP Vertex app](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/migrate-from-acp-to-vertex.html)
</description>
            <pubDate>Thu, 23 Jul 2026 10:10:41 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html</guid>
            
            
        </item>
        
        <item>
            <title>Integrate Vertex Validator</title>
            <description>To integrate Vertex Validator, take the following steps.

Registers the `POST /tax-id-validate` Glue REST API endpoint that validates a customer&apos;s Tax Identification Number (VAT ID) against a given country code via the Vertex Taxamo service. This is useful for B2B storefronts where customers must provide a valid VAT ID during checkout or address management to qualify for tax-exempt or reverse-charge transactions within the EU.

## 1. Install required modules

```bash
composer require spryker-eco/vertex
```

## 2. Add glossary keys

1. Add the following keys to your existing glossary file:

&lt;details&gt;
&lt;summary&gt;Click to view all glossary keys&lt;/summary&gt;

```csv
key,translation,locale
vertex.tax-number-country-blocked,Dieses Land ist in den Einstellungen blockiert.,de_DE
vertex.tax-number-validation-not-available,Die Steuernummer konnte nicht durch den Dienst überprüft werden.,de_DE
vertex.tax-number-ignored,&quot;Die Steuernummer wurde ignoriert, da Nummern für diese Region, dieses Land oder diesen Verkäufer blockiert wurden.&quot;,de_DE
vertex.tax-number-syntax-valid,Das Format der Steuernummer ist korrekt. Es wurden jedoch keine weiteren Prüfungen durchgeführt.,de_DE
vertex.tax-number-syntax-invalid,Das Format der Steuernummer ist ungültig.,de_DE
vertex.tax-number-considered-valid-in-domestic-country,Die Steuernummer ist im Heimatland des Verkäufers gültig.,de_DE
vertex.tax-number-valid-according-to-external-service,Die Steuernummer wurde erfolgreich bei der Steuerbehörde validiert.,de_DE
vertex.tax-number-invalid-according-to-external-service,Die Steuernummer wurde bei der Steuerbehörde überprüft und ist ungültig.,de_DE
vertex.tax-number-validation-requested-additional-interactions,&quot;Die Steuerbehörde verlangt zusätzliche Informationen (z. B. CAPTCHA), um die Nummer zu validieren.&quot;,de_DE
vertex.tax-number-service-temporarily-unavailable,Der Validierungsdienst ist vorübergehend nicht erreichbar.,de_DE
vertex.tax-number-syntax-considered-valid-but-not-verified,&quot;Das Format der Steuernummer ist korrekt, aber der Status konnte nicht bestätigt werden, da der externe Dienst nicht reagierte.&quot;,de_DE
vertex.tax-number-country-blocked,This county is blocked in the settings.,en_US
vertex.tax-number-validation-not-available,The service was not able to validate this number.,en_US
vertex.tax-number-ignored,&quot;The number is ignored because the settings have been changed to block numbers for this region, country or seller.&quot;,en_US
vertex.tax-number-syntax-valid,&quot;The syntax of the ID is valid. However, no further validations were done. In cases where a checksum is required, like for India, the ID is considered valid if the syntax is valid and the checksum is not configured.&quot;,en_US
vertex.tax-number-syntax-invalid,The syntax of the ID is invalid.,en_US
vertex.tax-number-considered-valid-in-domestic-country,The Tax ID is valid in the domestic country of the supplier.,en_US
vertex.tax-number-valid-according-to-external-service,The Tax ID has been validated against the Tax Authority&apos;s database of Tax IDs and is valid.,en_US
vertex.tax-number-invalid-according-to-external-service,The Tax ID has been validated against the Tax Authority&apos;s database of Tax IDs and is invalid.,en_US
vertex.tax-number-validation-requested-additional-interactions,&quot;The Tax Authority has requested additional parameters. For example, a country might require CAPTCHA validation and needs more information before they can validate the ID.&quot;,en_US
vertex.tax-number-service-temporarily-unavailable,Could not connect to validation service due to temporary unavailability of the service.,en_US
vertex.tax-number-syntax-considered-valid-but-not-verified,The Tax ID syntax is valid but the ID&apos;s status could not be verified by the external service. This occurs when the on-error settings is set to syntax-check and external service does not respond.,en_US
vertex.invalid-request-data,Invalid request data.,en_US
vertex.invalid-request-data,Ungültige Anfragedaten.,de_DE
vertex.tax-app-disabled,Tax service is disabled.,en_US
vertex.tax-app-disabled,Die Steueranwendung ist deaktiviert.,de_DE
vertex.tax-validator-unavailable,Tax Validator API is unavailable.,en_US
vertex.tax-validator-unavailable,Die Steuerprüfungs-API ist nicht verfügbar.,de_DE
vertex.validator-api-inactive,Unable to connect to Vertex Validator API: vertex app or tax id validation is inactive.,en_US
vertex.validator-api-inactive,Verbindung zur Vertex Validator API fehlgeschlagen: Die Vertex-Anwendung oder der Steuernummern-Prüfdienst ist nicht aktiv.,de_DE
vertex.request-failed,Request to Vertex API failed.,en_US
vertex.request-failed,Anfrage an die Vertex-API fehlgeschlagen.,de_DE
vertex.invalid-credentials,Invalid credentials.,en_US
vertex.invalid-credentials,Ungültige Anmeldeinformationen.,de_DE
```

&lt;/details&gt;

2. Import the updated glossary:

```bash
console data:import:glossary
```

### 3. Register the Glue API plugin

{% info_block infoBox &quot;Optional&quot; %}

This step is required only if you want to expose tax validation via the REST API.

{% endinfo_block %}

Add the Glue plugin to `src/Pyz/Glue/GlueApplication/GlueApplicationDependencyProvider.php`:

```php
&lt;?php

namespace Pyz\Glue\GlueApplication;

use Spryker\Glue\GlueApplication\GlueApplicationDependencyProvider as SprykerGlueApplicationDependencyProvider;
use SprykerEco\Glue\Vertex\Plugin\VertexTaxValidateIdResourceRoutePlugin;

class GlueApplicationDependencyProvider extends SprykerGlueApplicationDependencyProvider
{
    protected function getResourceRoutePlugins(): array
    {
        return [
            // ... other plugins
            new VertexTaxValidateIdResourceRoutePlugin(),
        ];
    }

}
```

## 4. Make sure that the tax ID validator is enabled

```php
namespace Pyz\Zed\Vertex;

use SprykerEco\Zed\Vertex\VertexConfig as SprykerEcoVertexConfig;

class VertexConfig extends SprykerEcoVertexConfig
{
    public function isTaxIdValidatorEnabled(): bool
    {
        return true;
    }
}
```

## 5. Use translations

To use translations, send requests with the `Accept-Language` header. For example, to use German translations, include the `Accept-Language: de` header.

## Next step

[Verify Vertex connection](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/verify-vertex-connection.html)
</description>
            <pubDate>Thu, 23 Jul 2026 10:02:19 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex-validator.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex-validator.html</guid>
            
            
        </item>
        
        <item>
            <title>Configure Vertex in the Back Office</title>
            <description>&lt;p&gt;This document describes how to manage Vertex settings from &lt;strong&gt;Back Office&lt;/strong&gt; &amp;gt; &lt;strong&gt;Configuration&lt;/strong&gt; and how to select the tax provider per scope &lt;code&gt;store&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With this feature enabled, operators manage every Vertex setting from the Back Office, per &lt;strong&gt;global&lt;/strong&gt; or &lt;strong&gt;store&lt;/strong&gt; scope, instead of environment variables. A new &lt;strong&gt;Configuration&lt;/strong&gt; &amp;gt; &lt;strong&gt;Taxes&lt;/strong&gt; &amp;gt; &lt;strong&gt;Tax Provider&lt;/strong&gt; switch chooses between the built-in Spryker tax calculation and Vertex. Save-time validation prevents leaving the integration in a broken state.&lt;/p&gt;
&lt;section class=&apos;info-block &apos;&gt;&lt;i class=&apos;info-block__icon icon-info&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Backward compatible&lt;/div&gt;
&lt;p&gt;This feature is opt-in and backward compatible. Until you &lt;a href=&quot;#1-enable-the-configuration-source&quot;&gt;enable it&lt;/a&gt;, Vertex keeps reading its configuration from environment variables, and nothing changes for existing integrations.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;spryker-eco/vertex&lt;/code&gt; version &lt;code&gt;1.5.0&lt;/code&gt; or later.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html&quot;&gt;Integrate Vertex&lt;/a&gt; into your Spryker shop.&lt;/li&gt;
&lt;li&gt;Install the Configuration Management feature. The Vertex module depends on &lt;code&gt;spryker/configuration-extension&lt;/code&gt;, but it does not require the &lt;code&gt;spryker/configuration&lt;/code&gt; module that provides the Back Office UI and stores the values. If the Configuration Management feature is not installed yet, install it first. For details, see &lt;a href=&quot;/docs/dg/dev/integrate-and-configure/integrate-confguration-feature.html&quot;&gt;Install the Configuration Management feature&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;enable-the-configuration-source&quot;&gt;1. Enable the configuration source&lt;/h2&gt;
&lt;p&gt;The configuration source is gated behind the &lt;code&gt;isConfigurationModuleUsed()&lt;/code&gt; flag, which defaults to &lt;code&gt;false&lt;/code&gt; (environment-based behavior). To read values from the Back Office instead, override the flag in &lt;code&gt;src/Pyz/Shared/Vertex/VertexConfig.php&lt;/code&gt; to return &lt;code&gt;true&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Shared\Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerEco\Shared\Vertex\VertexConfig&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerEcoVertexConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VertexConfig&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerEcoVertexConfig&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isConfigurationModuleUsed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When the flag is &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;SprykerEco\Zed\Vertex\VertexConfig&lt;/code&gt; reads values using &lt;a href=&quot;/docs/dg/dev/backend-development/configuration-management.html#reading-configuration-values&quot;&gt;getModuleConfig&lt;/a&gt; instead of from the &lt;code&gt;config/Shared/config_default.php&lt;/code&gt; constants.&lt;/p&gt;
&lt;h2 id=&quot;register-the-pre-save-validation-plugin&quot;&gt;2. Register the pre-save validation plugin&lt;/h2&gt;
&lt;p&gt;Register &lt;code&gt;VertexTaxProviderPreSavePlugin&lt;/code&gt; in &lt;code&gt;src/Pyz/Zed/Configuration/ConfigurationDependencyProvider.php&lt;/code&gt; to enable save-time validation:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Zed\Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spryker\Zed\Configuration\ConfigurationDependencyProvider&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerConfigurationDependencyProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerEco\Zed\Vertex\Communication\Plugin\Configuration\VertexTaxProviderPreSavePlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationDependencyProvider&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerConfigurationDependencyProvider&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * @return array&amp;lt;\Spryker\Zed\ConfigurationExtension\Dependency\Plugin\ConfigurationValuePreSavePluginInterface&amp;gt;
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getConfigurationValuePreSavePlugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// ... other plugins&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VertexTaxProviderPreSavePlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;sync-the-configuration-schema&quot;&gt;3. Sync the configuration schema&lt;/h2&gt;
&lt;p&gt;Sync the configuration schema so the Vertex settings appear in the Back Office:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;console configuration:sync
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;manage-vertex-settings-in-the-back-office&quot;&gt;4. Manage Vertex settings in the Back Office&lt;/h2&gt;
&lt;p&gt;After the sync, the settings are available under &lt;strong&gt;Configuration&lt;/strong&gt; in Integrations &amp;gt; Vertex. All settings are scoped to &lt;strong&gt;global&lt;/strong&gt; and &lt;strong&gt;store&lt;/strong&gt; by default.&lt;/p&gt;
&lt;h3 id=&quot;integrations-gt-vertex&quot;&gt;Integrations &amp;gt; Vertex&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Group&lt;/th&gt;
&lt;th&gt;Label&lt;/th&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Configuration&lt;/td&gt;
&lt;td&gt;Security URI&lt;/td&gt;
&lt;td&gt;Required, URL-validated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration&lt;/td&gt;
&lt;td&gt;Transaction calls URI&lt;/td&gt;
&lt;td&gt;Required, URL-validated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration&lt;/td&gt;
&lt;td&gt;Client ID&lt;/td&gt;
&lt;td&gt;Required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration&lt;/td&gt;
&lt;td&gt;Client secret&lt;/td&gt;
&lt;td&gt;Required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration&lt;/td&gt;
&lt;td&gt;Default taxpayer company code&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration&lt;/td&gt;
&lt;td&gt;Vendor code&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration&lt;/td&gt;
&lt;td&gt;Seller country code&lt;/td&gt;
&lt;td&gt;Optional, 2-letter ISO code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration&lt;/td&gt;
&lt;td&gt;Customer country code&lt;/td&gt;
&lt;td&gt;Optional, 2-letter ISO code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tax ID validation (Taxamo)&lt;/td&gt;
&lt;td&gt;Taxamo API URL&lt;/td&gt;
&lt;td&gt;URL-validated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tax ID validation (Taxamo)&lt;/td&gt;
&lt;td&gt;Taxamo token&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invoicing&lt;/td&gt;
&lt;td&gt;Submit Tax invoices to Vertex&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tax Assist&lt;/td&gt;
&lt;td&gt;Enable Tax Assist in Vertex&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;section class=&apos;info-block &apos;&gt;&lt;i class=&apos;info-block__icon icon-info&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Tax ID validation&lt;/div&gt;
&lt;p&gt;The Taxamo API URL and token are stored but consumed only when the tax ID validator is enabled. For details, see &lt;a href=&quot;/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex-validator.html&quot;&gt;Integrate Vertex Validator&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;h3 id=&quot;taxes-gt-tax-provider&quot;&gt;Taxes &amp;gt; Tax Provider&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Label&lt;/th&gt;
&lt;th&gt;Values&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tax provider&lt;/td&gt;
&lt;td&gt;&lt;code&gt;spryker&lt;/code&gt; (default) or &lt;code&gt;vertex&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Selecting &lt;strong&gt;vertex&lt;/strong&gt; requires a complete Vertex configuration for that scope. This requirement is enforced at save time.&lt;/p&gt;
&lt;h2 id=&quot;configuration-source-and-precedence&quot;&gt;Configuration source and precedence&lt;/h2&gt;
&lt;p&gt;The active configuration source depends on the flag &lt;code&gt;Spryker\Shared\Vertex\VertexConfig::isConfigurationModuleUsed()&lt;/code&gt; or its project-level value:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Flag off (default):&lt;/strong&gt; getters read the legacy &lt;code&gt;VERTEX:*&lt;/code&gt; environment values from &lt;code&gt;config/Shared/config_default.php&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flag on:&lt;/strong&gt; getters resolve values per scope &lt;code&gt;store&lt;/code&gt; from the &lt;code&gt;spryker/configuration&lt;/code&gt;. Environment values from &lt;code&gt;config/Shared/config_default.php&lt;/code&gt; is ignored.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;save-time-validation&quot;&gt;Save-time validation&lt;/h2&gt;
&lt;p&gt;When you save a configuration, the following changes are blocked to prevent leaving the integration in a broken state:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Selecting Vertex while incomplete:&lt;/strong&gt; you cannot switch the tax provider to Vertex if Vertex is not fully configured for that scope. The error lists the missing fields.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Breaking an active configuration:&lt;/strong&gt; you cannot clear or remove a credential that would leave Vertex incomplete while Vertex is the selected provider for that scope. This applies to both edits and deletions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-scope breakage:&lt;/strong&gt; a change to the &lt;strong&gt;global&lt;/strong&gt; scope that would break any &lt;strong&gt;store&lt;/strong&gt; that has Vertex selected and inherits the global values is blocked. The error names the affected store.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Invalid URLs:&lt;/strong&gt; the Security URI, Transaction calls URI, and Taxamo API URL must be valid URLs, even when Vertex is not the selected provider.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/verify-vertex-connection.html&quot;&gt;Verify Vertex connection&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Thu, 23 Jul 2026 10:02:19 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/configure-vertex-in-the-back-office.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/configure-vertex-in-the-back-office.html</guid>
            
            
        </item>
        
        <item>
            <title>Upgrade the Algolia module</title>
            <description>{% include pbc/all/upgrade-modules/upgrade-the-algolia-module.md %} &lt;!-- To edit, see /_includes/pbc/all/upgrade-modules/upgrade-the-algolia-module.md --&gt;
</description>
            <pubDate>Thu, 23 Jul 2026 09:19:42 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/search/latest/base-shop/third-party-integrations/algolia/upgrade-the-algolia-module.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/search/latest/base-shop/third-party-integrations/algolia/upgrade-the-algolia-module.html</guid>
            
            
        </item>
        
        <item>
            <title>Integrate Algolia</title>
            <description>This document explains how to integrate [Algolia](/docs/pbc/all/search/latest/base-shop/third-party-integrations/algolia/algolia.html) with your Spryker shop.

## Prerequisites

Install the required module:

```bash
composer require -W spryker-eco/algolia:&quot;^2.0.0&quot;
```

## Configure Algolia credentials

You can configure Algolia credentials using environment variables or the Back Office.

### Option A: Environment variable-based credentials

In `config/Shared/config_default.php` or, for local development, in `config_local.php`, add the following:

```php
use SprykerEco\Shared\Algolia\AlgoliaConstants;

$config[AlgoliaConstants::APPLICATION_ID] = getenv(&apos;ALGOLIA_APPLICATION_ID&apos;);
$config[AlgoliaConstants::ADMIN_API_KEY] = getenv(&apos;ALGOLIA_WRITE_API_KEY&apos;);
$config[AlgoliaConstants::SEARCH_ONLY_API_KEY] = getenv(&apos;ALGOLIA_SEARCH_API_KEY&apos;);
// Optional: use when sharing one Algolia account across multiple environments. Default is &quot;production&quot;.
// $config[AlgoliaConstants::TENANT_IDENTIFIER] = &apos;john&apos;;
```

### Option B: Back Office configuration

This option requires the [Spryker Configuration feature](/docs/dg/dev/integrate-and-configure/integrate-confguration-feature.html) to be installed.

1. Enable the Configuration module for this module by creating `src/Pyz/Shared/Algolia/AlgoliaConfig.php`:

```php
&lt;?php

namespace Pyz\Shared\Algolia;

use SprykerEco\Shared\Algolia\AlgoliaConfig as SprykerEcoAlgoliaConfig;

class AlgoliaConfig extends SprykerEcoAlgoliaConfig
{
    public function isConfigurationModuleUsed(): bool
    {
        return true;
    }
}
```

2. Sync configuration settings to the database to register the Algolia configuration keys:

```bash
vendor/bin/console configuration:sync
```

3. In the Back Office, go to **Configuration &gt; Integrations &gt; Algolia** and enter the Application ID, Admin API Key, and Search-Only API Key.

4. Optional: To validate credentials against the Algolia API before saving, register `AlgoliaCredentialsPreSavePlugin` in `src/Pyz/Zed/Configuration/ConfigurationDependencyProvider.php`:

```php
&lt;?php

namespace Pyz\Zed\Configuration;

use SprykerEco\Zed\Algolia\Communication\Plugin\Configuration\AlgoliaCredentialsPreSavePlugin;

class ConfigurationDependencyProvider extends SprykerConfigurationDependencyProvider
{
    protected function getConfigurationValuePreSavePlugins(): array
    {
        return [
            new AlgoliaCredentialsPreSavePlugin(),
        ];
    }
}
```

## Integrate Algolia

### 1. Enable the console command

In `src/Pyz/Zed/Console/ConsoleDependencyProvider.php`, register the export console command:

```php
&lt;?php

namespace Pyz\Zed\Console;

use Spryker\Zed\Console\ConsoleDependencyProvider as SprykerConsoleDependencyProvider;
use SprykerEco\Zed\Algolia\Communication\Console\AlgoliaEntityExportConsole;

class ConsoleDependencyProvider extends SprykerConsoleDependencyProvider
{
    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return array&lt;\Symfony\Component\Console\Command\Command&gt;
     */
    protected function getConsoleCommands(Container $container): array
    {
        $commands = [
            // ... existing commands
            new AlgoliaEntityExportConsole(),
        ];

        return $commands;
    }
}
```

### 2. Configure entity exporter plugins

In `src/Pyz/Zed/Algolia/AlgoliaDependencyProvider.php`, register the entity exporter plugins:

```php
&lt;?php

namespace Pyz\Zed\Algolia;

use SprykerEco\Zed\Algolia\AlgoliaDependencyProvider as SprykerEcoAlgoliaDependencyProvider;
use SprykerEco\Zed\Algolia\Communication\Plugin\Algolia\CmsPageAlgoliaEntityExporterPlugin;
use SprykerEco\Zed\Algolia\Communication\Plugin\Algolia\ProductAlgoliaEntityExporterPlugin;

class AlgoliaDependencyProvider extends SprykerEcoAlgoliaDependencyProvider
{
    /**
     * @return array&lt;\SprykerEco\Zed\Algolia\Dependency\Plugin\AlgoliaEntityExporterPluginInterface&gt;
     */
    protected function getAlgoliaEntityExporterPlugins(): array
    {
        return [
            new ProductAlgoliaEntityExporterPlugin(),
            new CmsPageAlgoliaEntityExporterPlugin(),
        ];
    }
}
```

### 3. Configure the search adapter plugin

In `src/Pyz/Client/Search/SearchDependencyProvider.php`, register the Algolia search adapter:

```php
&lt;?php

namespace Pyz\Client\Search;

use Spryker\Client\Search\SearchDependencyProvider as SprykerSearchDependencyProvider;
use SprykerEco\Client\Algolia\Plugin\Search\AlgoliaSearchAdapterPlugin;

class SearchDependencyProvider extends SprykerSearchDependencyProvider
{
    /**
     * @return array&lt;\Spryker\Client\SearchExtension\Dependency\Plugin\SearchAdapterPluginInterface&gt;
     */
    protected function getClientAdapterPlugins(): array
    {
        return [
            new AlgoliaSearchAdapterPlugin(),
        ];
    }
}
```

### 4. Configure catalog search query plugins

{% info_block infoBox &quot;&quot; %}

This step requires the catalog search provider to be set to Algolia. You can do this in one of the following ways:
- Override `isSearchInFrontendEnabledForProducts()` to return `true` in `src/Pyz/Client/Algolia/AlgoliaConfig.php`.
- If you are using [Back Office configuration](#option-b-back-office-configuration), go to **Configuration &gt; Catalog &gt; Search** in the Back Office and set the search provider to Algolia.

The integration also depends on SearchHttp module plugins. Make sure they are enabled in `src/Pyz/Client/Catalog/CatalogDependencyProvider.php`.

{% endinfo_block %}

In `src/Pyz/Client/Catalog/CatalogDependencyProvider.php`, register the Algolia search query plugins:

```php
&lt;?php

namespace Pyz\Client\Catalog;

use Spryker\Client\Catalog\CatalogDependencyProvider as SprykerCatalogDependencyProvider;
use SprykerEco\Client\Algolia\Plugin\Search\AlgoliaProductConcreteSearchQueryPlugin;
use SprykerEco\Client\Algolia\Plugin\Search\AlgoliaSearchQueryPlugin;
use SprykerEco\Client\Algolia\Plugin\Search\AlgoliaSuggestionSearchQueryPlugin;

class CatalogDependencyProvider extends SprykerCatalogDependencyProvider
{
    /**
     * @return array&lt;\Spryker\Client\SearchExtension\Dependency\Plugin\QueryInterface&gt;
     */
    protected function createCatalogSearchQueryPluginVariants(): array
    {
        return [
            new AlgoliaSearchQueryPlugin(),
        ];
    }

    /**
     * @return array&lt;\Spryker\Client\SearchExtension\Dependency\Plugin\QueryInterface&gt;
     */
    protected function createSuggestionQueryPluginVariants(): array
    {
        return [
            new AlgoliaSuggestionSearchQueryPlugin(),
        ];
    }

    /**
     * @return array&lt;\Spryker\Client\SearchExtension\Dependency\Plugin\QueryInterface&gt;
     */
    protected function createProductConcreteCatalogSearchQueryPluginVariants(): array
    {
        return [
            new AlgoliaProductConcreteSearchQueryPlugin(),
        ];
    }
}
```

### 5. Configure the CMS page search query plugin

{% info_block infoBox &quot;&quot; %}

This step is optional. It requires the CMS search provider to be set to Algolia. You can do this in one of the following ways:
- Override `isSearchInFrontendEnabledForCmsPages()` to return `true` in `src/Pyz/Client/Algolia/AlgoliaConfig.php`.
- If you are using [Back Office configuration](#option-b-back-office-configuration), go to **Configuration &gt; CMS &gt; Search** in the Back Office and set the search provider to Algolia.

The integration also depends on SearchHttp module plugins. Make sure they are enabled in `src/Pyz/Client/SearchHttp/SearchHttpDependencyProvider.php` and `src/Pyz/Client/CmsPageSearch/CmsPageSearchDependencyProvider.php`.

{% endinfo_block %}

In `src/Pyz/Client/CmsPageSearch/CmsPageSearchDependencyProvider.php`, register the Algolia search query plugin for CMS pages:

```php
&lt;?php

namespace Pyz\Client\CmsPageSearch;

use Generated\Shared\Transfer\SearchContextTransfer;
use Spryker\Client\CmsPageSearch\CmsPageSearchConfig;
use Spryker\Client\CmsPageSearch\CmsPageSearchDependencyProvider as SprykerCmsPageSearchDependencyProvider;
use SprykerEco\Client\Algolia\Plugin\Search\AlgoliaSearchQueryPlugin;

class CmsPageSearchDependencyProvider extends SprykerCmsPageSearchDependencyProvider
{
    /**
     * @return array&lt;\Spryker\Client\SearchExtension\Dependency\Plugin\QueryInterface&gt;
     */
    protected function getCmsPageSearchQueryPlugins(): array
    {
        return [
            new AlgoliaSearchQueryPlugin(
                (new SearchContextTransfer())
                    -&gt;setSourceIdentifier(CmsPageSearchConfig::SOURCE_IDENTIFIER_CMS_PAGE),
            ),
        ];
    }
}
```

### 6. Generate transfers

```bash
vendor/bin/console transfer:generate
```

### 7. Verify the installation

```bash
vendor/bin/console | grep algolia
vendor/bin/console algolia:entity-export
```

### 8. Export data to Algolia

```bash
vendor/bin/console algolia:entity-export --all

# Or export specific entity types:
vendor/bin/console algolia:entity-export product
vendor/bin/console algolia:entity-export cms-page
```

For scheduling and additional options, see [Full indexing](#full-indexing).

### 9. Verify data in the Algolia Dashboard

1. Log in to Algolia.
2. In the **Search** section, check the created indexes and the data inside.
3. Run searches from the Algolia Dashboard.
4. Configure index settings like [facets](https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/) and [searchable attributes](https://www.algolia.com/doc/guides/managing-results/must-do/searchable-attributes/) as needed.

### 10. Configure real-time synchronization

In `src/Pyz/Zed/Publisher/PublisherDependencyProvider.php`, register the Algolia publisher plugins:

```php
&lt;?php

namespace Pyz\Zed\Publisher;

use Spryker\Zed\Publisher\PublisherDependencyProvider as SprykerPublisherDependencyProvider;
use SprykerEco\Zed\Algolia\Communication\Plugin\Publisher\CmsPage\AlgoliaCmsPageDeletePublisherPlugin;
use SprykerEco\Zed\Algolia\Communication\Plugin\Publisher\CmsPage\AlgoliaCmsPagePublisherPlugin;
use SprykerEco\Zed\Algolia\Communication\Plugin\Publisher\CmsPage\AlgoliaCmsPageVersionPublisherPlugin;
use SprykerEco\Zed\Algolia\Communication\Plugin\Publisher\Product\AlgoliaProductAbstractPublisherPlugin;
use SprykerEco\Zed\Algolia\Communication\Plugin\Publisher\Product\AlgoliaProductConcreteDeletePublisherPlugin;
use SprykerEco\Zed\Algolia\Communication\Plugin\Publisher\Product\AlgoliaProductConcretePublisherPlugin;

class PublisherDependencyProvider extends SprykerPublisherDependencyProvider
{
    protected function getPublisherPlugins(): array
    {
        return [
            new AlgoliaProductConcretePublisherPlugin(),
            new AlgoliaProductAbstractPublisherPlugin(),
            new AlgoliaProductConcreteDeletePublisherPlugin(),
            new AlgoliaCmsPagePublisherPlugin(),
            new AlgoliaCmsPageVersionPublisherPlugin(),
            new AlgoliaCmsPageDeletePublisherPlugin(),
        ];
    }
}
```

For details on each plugin and its subscribed events, see [Real-time synchronization](#real-time-synchronization).

### 11. Enable search in the frontend and API

{% info_block warningBox &quot;&quot; %}

Make sure you have data in the Algolia indices before enabling search in the frontend. Otherwise, search returns no results.

{% endinfo_block %}

Enable product and CMS page search in one of the following ways:

**Option A: Configuration class**

In `src/Pyz/Client/Algolia/AlgoliaConfig.php`, override the search provider methods:

```php
&lt;?php

namespace Pyz\Client\Algolia;

use SprykerEco\Client\Algolia\AlgoliaConfig as SprykerEcoAlgoliaConfig;

class AlgoliaConfig extends SprykerEcoAlgoliaConfig
{
    public function isSearchInFrontendEnabledForProducts(): bool
    {
        return true;
    }

    public function isSearchInFrontendEnabledForCmsPages(): bool
    {
        return true;
    }
}
```

**Option B: Back Office configuration**

If you are using [Back Office configuration](#option-b-back-office-configuration), configure the search providers in the Back Office:
- Go to **Configuration &gt; Catalog &gt; Search** and set the search provider to Algolia to enable product search.
- Go to **Configuration &gt; CMS &gt; Search** and set the search provider to Algolia to enable CMS page search.

### 12. Configure sorting replicas

Sorting in Algolia uses replica indices. Each sortable attribute gets ascending and descending replicas created automatically during data export. By default, no sorting replicas are configured. To enable sorting, create or update `src/Pyz/Zed/Algolia/AlgoliaConfig.php`:

```php
&lt;?php

namespace Pyz\Zed\Algolia;

use SprykerEco\Zed\Algolia\AlgoliaConfig as SprykerEcoAlgoliaConfig;

class AlgoliaConfig extends SprykerEcoAlgoliaConfig
{
    /**
     * @return array&lt;string&gt;
     */
    public function getProductSortingAttributes(): array
    {
        return [
            &apos;rating&apos;,
            &apos;abstract_name&apos;,
            &apos;prices.eur.gross&apos;,
            &apos;prices.eur.net&apos;,
        ];
    }

    /**
     * @return array&lt;string&gt;
     */
    public function getCmsPageSortingAttributes(): array
    {
        return [&apos;name&apos;];
    }

    /**
     * @return array&lt;array&lt;string&gt;&gt;
     */
    public function getSuggestionGenerateAttributes(): array
    {
        return [
            [&apos;category&apos;],
            [&apos;attributes.brand&apos;],
        ];
    }
}
```

If a sort parameter name used by the storefront differs from the Algolia attribute name used in the replica index, configure the mapping in `src/Pyz/Client/Algolia/AlgoliaConfig.php`:

```php
&lt;?php

namespace Pyz\Client\Algolia;

use SprykerEco\Client\Algolia\AlgoliaConfig as SprykerEcoAlgoliaConfig;

class AlgoliaConfig extends SprykerEcoAlgoliaConfig
{
    /**
     * @return array&lt;string, string&gt;
     */
    public function getProductSortingParamToAttributeMapping(): array
    {
        return [
            &apos;name&apos; =&gt; &apos;abstract_name&apos;,
        ];
    }
}
```

In this example, when a customer sorts by `name` on the storefront, the system resolves it to the `abstract_name` replica index in Algolia.

## Real-time synchronization

### Product publisher plugins

Product publisher plugins are located in `SprykerEco\Zed\Algolia\Communication\Plugin\Publisher\Product\`.

#### AlgoliaProductConcretePublisherPlugin

Publishes product concrete (variant) data to Algolia when products are created or updated.

**Subscribed events:**
- Product creation and update events
- Product localized attribute changes
- Product image changes
- Product bundle changes (if `ProductBundleStorage` is installed)
- Product price changes (if `PriceProduct` is installed)
- Product search data changes (if `ProductSearch` is installed)

#### AlgoliaProductAbstractPublisherPlugin

Publishes all concrete products of a product abstract when abstract-level data changes.

**Subscribed events:**
- Product abstract updates
- Category assignments
- Product labels
- Reviews
- Images
- Price changes (if `PriceProduct` is installed and enabled in the configuration)

#### AlgoliaProductConcreteDeletePublisherPlugin

Removes deleted products from Algolia indices.

**Subscribed events:**
- `PRODUCT_CONCRETE_UNPUBLISH`
- `ENTITY_SPY_PRODUCT_DELETE`

### CMS page publisher plugins

CMS page publisher plugins are located in `SprykerEco\Zed\Algolia\Communication\Plugin\Publisher\CmsPage\`.

#### AlgoliaCmsPagePublisherPlugin

Publishes CMS page data to Algolia when pages are created or updated.

**Subscribed events:**
- `ENTITY_SPY_CMS_PAGE_UPDATE`

**Behavior:**
- Fetches full CMS page data including the latest version.
- Checks if the page is active and searchable before publishing.
- Extracts locale-specific CMS content.
- Removes pages from all relevant indices if the page is inactive or not searchable.

#### AlgoliaCmsPageVersionPublisherPlugin

Publishes CMS pages when new versions are created or published.

**Subscribed events:**
- `CMS_VERSION_PUBLISH`
- `ENTITY_SPY_CMS_VERSION_CREATE`

## Full indexing

To export entities to Algolia, run the following commands:

```bash
# Export all products
vendor/bin/console algolia:entity:export product

# Export all CMS pages for a specific store
vendor/bin/console algolia:entity:export cms-page --store=DE

# Export for a specific locale
vendor/bin/console algolia:entity:export product --locale=en_US

# Export with a custom chunk size
vendor/bin/console algolia:entity:export product --chunk-size=200
```

### Schedule automatic exports

For periodic full re-indexing, add cron jobs to `config/Zed/cronjobs/jenkins.php`:

```php
/* Algolia - Weekly full export */
$jobs[] = [
    &apos;name&apos; =&gt; &apos;algolia-export-products&apos;,
    &apos;command&apos; =&gt; $logger . &apos;$PHP_BIN vendor/bin/console algolia:entity:export product&apos;,
    &apos;schedule&apos; =&gt; &apos;0 2 * * 0&apos;,
    &apos;enable&apos; =&gt; true,
];

$jobs[] = [
    &apos;name&apos; =&gt; &apos;algolia-export-cms-pages&apos;,
    &apos;command&apos; =&gt; $logger . &apos;$PHP_BIN vendor/bin/console algolia:entity:export cms-page&apos;,
    &apos;schedule&apos; =&gt; &apos;30 2 * * 0&apos;,
    &apos;enable&apos; =&gt; true,
];
```

- `0 2 * * 0`: runs at 2:00 AM every Sunday.
- `30 2 * * 0`: runs at 2:30 AM every Sunday.

{% info_block infoBox &quot;&quot; %}

Cron jobs complement the real-time publisher plugins. The publisher plugins handle incremental updates, while the cron jobs ensure full data consistency by performing periodic complete exports.

{% endinfo_block %}

## Configuration

### Available configuration methods

**Product events:**
- `getProductConcreteSubscribedEvents()`: product variant events.
- `getProductAbstractSubscribedEvents()`: product abstract events.
- `getProductConcreteUnpublishSubscribedEvents()`: delete events.

**CMS page events:**
- `getCmsPageUpdateSubscribedEvents()`: page update events.
- `getCmsPageVersionPublishSubscribedEvents()`: version publish events.

**Search:**
- `isSearchInFrontendEnabledForProducts()`: enables product search in the frontend.
- `isSearchInFrontendEnabledForCmsPages()`: enables CMS page search in the frontend.

**Sorting (Zed layer — `src/Pyz/Zed/Algolia/AlgoliaConfig.php`):**
- `getProductSortingAttributes()`: list of Algolia attribute names for product sorting replicas.
- `getCmsPageSortingAttributes()`: list of attribute names for CMS page sorting replicas.
- `getSuggestionGenerateAttributes()`: facet attribute groups for Query Suggestions generation.

**Sort parameter mapping (Client layer — `src/Pyz/Client/Algolia/AlgoliaConfig.php`):**
- `getProductSortingParamToAttributeMapping()`: maps storefront sort parameter names to Algolia replica attribute names for products.
- `getCmsPageSortingParamToAttributeMapping()`: maps storefront sort parameter names to Algolia replica attribute names for CMS pages.

**Insights, analytics, and personalization:**
- `getIsPersonalizationEnabled()`: enables or disables Algolia Personalization. This feature requires a premium Algolia plan.
- `getProjectMappingFacets()`: maps facet names for Algolia Insights event tracking.

### Default event subscriptions

All publisher plugins get their subscribed events from `AlgoliaConfig`. The configuration automatically includes events from optional modules if they are installed:

**Products:**
- All product abstract and product concrete events.
- `ProductBundle`: bundle events (if the module is installed).
- `PriceProduct`: price events (if the module is installed).
- `ProductLabel`: label events (if the module is installed).
- `ProductReview`: review events (if the module is installed).

**CMS pages:**
- CMS: all CMS page and version events.

### Customize event subscriptions

To customize events, extend `AlgoliaConfig` in your project:

```php
&lt;?php

namespace Pyz\Zed\Algolia;

use SprykerEco\Zed\Algolia\AlgoliaConfig as SprykerEcoAlgoliaConfig;

class AlgoliaConfig extends SprykerEcoAlgoliaConfig
{
    public function getProductConcreteSubscribedEvents(): array
    {
        // Override all events
        return [
            &apos;Product.product_concrete.publish&apos;,
            &apos;Entity.spy_product.update&apos;,
        ];
    }

    public function getCmsPageUpdateSubscribedEvents(): array
    {
        // Extend parent events
        $events = parent::getCmsPageUpdateSubscribedEvents();
        $events[] = &apos;YourCustom.custom_event&apos;;

        return $events;
    }

    public function getDefaultExportChunkSize(): int
    {
        return 500;
    }
}
```

## Custom entity index mapping

The Algolia module supports searching custom entities that are already indexed in Algolia but are not natively supported by the module—like products or CMS pages. This lets you integrate any custom entity search without creating new plugins or modules.

Use entity-to-index mapping when you want to search custom entities—like documents, manufacturers, or locations—that are already indexed in Algolia, without creating custom publisher plugins for read-only search.

See details in the [&quot;Using Algolia search with custom indexes&quot;](/docs/pbc/all/search/latest/base-shop/third-party-integrations/algolia/algolia-search-by-custom-entity-index.html) guide.


## Integrate frontend

To enable CMS page search on the frontend, update `spryker-shop/cms-search-page` to version 1.5 or higher.

If your project is based on an older version than `{{page.release_tag}}`, adjust your Search CMS page templates to the latest changes from Spryker&apos;s demo shops:

- [B2C changes](https://github.com/spryker-shop/b2c-demo-shop/pull/793/files)
- [B2C Marketplace changes](https://github.com/spryker-shop/b2c-demo-marketplace/pull/668/files)
- [B2B changes](https://github.com/spryker-shop/b2b-demo-shop/pull/832/files)
- [B2B Marketplace changes](https://github.com/spryker-shop/b2b-demo-marketplace/pull/732/files)

## Verify the integration

{% info_block warningBox &quot;&quot; %}

Verify the following:
- Product and CMS page data are synchronized from your Spryker site to Algolia.
- The frontend displays results from Algolia:
  - On Yves: `/search/suggestion?q=ca` (search box suggestions widget), `/search?q=` (catalog page), `/search/cms?q=` (CMS pages list)
  - Via Glue API: `/catalog-search?q=`, `/catalog-search-suggestions?q=sams`, `/cms-pages?q=`
- In Algolia Dashboard, select the index for product or CMS page for the relevant store and locale. Check the number and order of records for the same search term on your Spryker site.
- In Algolia API logs for the selected index, make sure there is a user-agent header similar to `&quot;Algolia for PHP (3.4.1); PHP (8.3.13); Guzzle (7); Spryker Eco Algolia module&quot;`.

{% endinfo_block %}

## Migrate from the ACP Algolia app

If you are migrating from the MessageBroker-based [Algolia ACP App](/docs/pbc/all/search/latest/base-shop/third-party-integrations/algolia/algolia.html):

{% info_block infoBox &quot;&quot; %}

The data synchronization logic remains the same. To avoid re-synchronizing all data to Algolia, set `TENANT_IDENTIFIER` to match the ACP tenant ID:

```php
$config[AlgoliaConstants::TENANT_IDENTIFIER] = getenv(&apos;SPRYKER_TENANT_IDENTIFIER&apos;); // tenant-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx
```

{% endinfo_block %}

### 1. Remove old ACP plugins and configuration

**1a. Update `src/Pyz/Zed/Publisher/PublisherDependencyProvider.php`**

Remove the following imports and their usages:

```php
use Spryker\Zed\Cms\Communication\Plugin\Publisher\CmsPageUpdateMessageBrokerPublisherPlugin;
use Spryker\Zed\Cms\Communication\Plugin\Publisher\CmsPageVersionPublishedMessageBrokerPublisherPlugin;
use Spryker\Zed\Product\Communication\Plugin\Publisher\ProductAbstractUpdatedMessageBrokerPublisherPlugin;
use Spryker\Zed\Product\Communication\Plugin\Publisher\ProductConcreteCreatedMessageBrokerPublisherPlugin;
use Spryker\Zed\Product\Communication\Plugin\Publisher\ProductConcreteDeletedMessageBrokerPublisherPlugin;
use Spryker\Zed\Product\Communication\Plugin\Publisher\ProductConcreteExportedMessageBrokerPublisherPlugin;
use Spryker\Zed\Product\Communication\Plugin\Publisher\ProductConcreteUpdatedMessageBrokerPublisherPlugin;
```

Also remove the methods that register them—such as `getProductMessageBrokerPlugins()` and `getCmsPageMessageBrokerPlugins()`—and their calls from `getPublisherPlugins()`.

{% info_block infoBox &quot;&quot; %}

Keep `ProductCategoryProductUpdatedEventTriggerPlugin` and `ProductLabelProductUpdatedEventTriggerPlugin`. These are not ACP-specific and must remain. Re-register them under the new Algolia plugins method in step 2.

{% endinfo_block %}

**1b. Update `src/Pyz/Zed/MessageBroker/MessageBrokerDependencyProvider.php`**

Remove the following imports and plugin instantiations:

```php
use Spryker\Zed\Cms\Communication\Plugin\MessageBroker\CmsPageMessageHandlerPlugin;
use Spryker\Zed\Product\Communication\Plugin\MessageBroker\ProductExportMessageHandlerPlugin;
use Spryker\Zed\SearchHttp\Communication\Plugin\MessageBroker\SearchEndpointMessageHandlerPlugin;
```

**1c. Update `config/Shared/config_default.php`**

Disable product publishing via MessageBroker:

```php
// Before:
$config[ProductConstants::PUBLISHING_TO_MESSAGE_BROKER_ENABLED] = $config[MessageBrokerConstants::IS_ENABLED];

// After:
$config[ProductConstants::PUBLISHING_TO_MESSAGE_BROKER_ENABLED] = false;
```

At the end of the file, add the Algolia configuration:

```php
use SprykerEco\Shared\Algolia\AlgoliaConstants;

$config[AlgoliaConstants::APPLICATION_ID] = getenv(&apos;ALGOLIA_APPLICATION_ID&apos;);
$config[AlgoliaConstants::ADMIN_API_KEY] = getenv(&apos;ALGOLIA_WRITE_API_KEY&apos;);
$config[AlgoliaConstants::SEARCH_ONLY_API_KEY] = getenv(&apos;ALGOLIA_SEARCH_API_KEY&apos;);
$config[AlgoliaConstants::IS_ACTIVE] = $config[AlgoliaConstants::APPLICATION_ID] &amp;&amp; $config[AlgoliaConstants::ADMIN_API_KEY] &amp;&amp; $config[AlgoliaConstants::SEARCH_ONLY_API_KEY];
$config[AlgoliaConstants::TENANT_IDENTIFIER] = getenv(&apos;SPRYKER_TENANT_IDENTIFIER&apos;);
```

**1e. Update `src/Pyz/Client/Search/SearchDependencyProvider.php`**

Replace `SearchHttpSearchAdapterPlugin` with `AlgoliaSearchAdapterPlugin` and remove `SearchHttpSearchContextExpanderPlugin`:

```php
// Remove:
use Spryker\Client\SearchHttp\Plugin\Search\SearchHttpSearchAdapterPlugin;
use Spryker\Client\SearchHttp\Plugin\Search\SearchHttpSearchContextExpanderPlugin;

// Add:
use SprykerEco\Client\Algolia\Plugin\Search\AlgoliaSearchAdapterPlugin;
```

In `getClientAdapterPlugins()`, replace `new SearchHttpSearchAdapterPlugin()` with `new AlgoliaSearchAdapterPlugin()`.

In `getSearchContextExpanderPlugins()`, remove `new SearchHttpSearchContextExpanderPlugin()`.

**1f. Update `src/Pyz/Client/Catalog/CatalogDependencyProvider.php`**

Replace SearchHttp query plugins with Algolia equivalents:

```php
// Remove:
use Spryker\Client\SearchHttp\Plugin\Catalog\Query\ProductConcreteSearchHttpQueryPlugin;
use Spryker\Client\SearchHttp\Plugin\Catalog\Query\SearchHttpQueryPlugin;
use Spryker\Client\SearchHttp\Plugin\Catalog\Query\SuggestionSearchHttpQueryPlugin;

// Add:
use SprykerEco\Client\Algolia\Plugin\Search\AlgoliaProductConcreteSearchQueryPlugin;
use SprykerEco\Client\Algolia\Plugin\Search\AlgoliaSearchQueryPlugin;
use SprykerEco\Client\Algolia\Plugin\Search\AlgoliaSuggestionSearchQueryPlugin;
```

Replace plugin instantiations:
- In `createCatalogSearchQueryPluginVariants()`: replace `SearchHttpQueryPlugin` with `AlgoliaSearchQueryPlugin`.
- In `createSuggestionQueryPluginVariants()`: replace `SuggestionSearchHttpQueryPlugin` with `AlgoliaSuggestionSearchQueryPlugin`.
- In `createProductConcreteCatalogSearchQueryPluginVariants()`: replace `ProductConcreteSearchHttpQueryPlugin` with `AlgoliaProductConcreteSearchQueryPlugin`.

**1g. Update `src/Pyz/Client/CmsPageSearch/CmsPageSearchDependencyProvider.php`**

```php
// Remove:
use Spryker\Client\SearchHttp\Plugin\Catalog\Query\SearchHttpQueryPlugin;

// Add:
use SprykerEco\Client\Algolia\Plugin\Search\AlgoliaSearchQueryPlugin;
```

In `getCmsPageSearchQueryPlugins()`, replace `new SearchHttpQueryPlugin(...)` with `new AlgoliaSearchQueryPlugin(...)`.

### 2. Add new Algolia integration

**2a. Register the console export command**

In `src/Pyz/Zed/Console/ConsoleDependencyProvider.php`:

```php
use SprykerEco\Zed\Algolia\Communication\Console\AlgoliaEntityExportConsole;

// In getConsoleCommands():
new AlgoliaEntityExportConsole(),
```

**2b. Create `src/Pyz/Zed/Algolia/AlgoliaDependencyProvider.php`**

```php
&lt;?php

namespace Pyz\Zed\Algolia;

use SprykerEco\Zed\Algolia\AlgoliaDependencyProvider as SprykerEcoAlgoliaDependencyProvider;
use SprykerEco\Zed\Algolia\Communication\Plugin\Algolia\CmsPageAlgoliaEntityExporterPlugin;
use SprykerEco\Zed\Algolia\Communication\Plugin\Algolia\ProductAlgoliaEntityExporterPlugin;

class AlgoliaDependencyProvider extends SprykerEcoAlgoliaDependencyProvider
{
    /**
     * @return array&lt;\SprykerEco\Zed\Algolia\Dependency\Plugin\AlgoliaEntityExporterPluginInterface&gt;
     */
    protected function getAlgoliaEntityExporterPlugins(): array
    {
        return [
            new ProductAlgoliaEntityExporterPlugin(),
            new CmsPageAlgoliaEntityExporterPlugin(),
        ];
    }
}
```

**2c. Register real-time publisher plugins**

In `src/Pyz/Zed/Publisher/PublisherDependencyProvider.php`, add a new `getAlgoliaPlugins()` method and call it from `getPublisherPlugins()`:

```php
use SprykerEco\Zed\Algolia\Communication\Plugin\Publisher\CmsPage\AlgoliaCmsPagePublisherPlugin;
use SprykerEco\Zed\Algolia\Communication\Plugin\Publisher\CmsPage\AlgoliaCmsPageVersionPublisherPlugin;
use SprykerEco\Zed\Algolia\Communication\Plugin\Publisher\Product\AlgoliaProductAbstractPublisherPlugin;
use SprykerEco\Zed\Algolia\Communication\Plugin\Publisher\Product\AlgoliaProductConcreteDeletePublisherPlugin;
use SprykerEco\Zed\Algolia\Communication\Plugin\Publisher\Product\AlgoliaProductConcretePublisherPlugin;

// ...

protected function getAlgoliaPlugins(): array
{
    return [
        new AlgoliaCmsPagePublisherPlugin(),
        new AlgoliaCmsPageVersionPublisherPlugin(),
        new AlgoliaProductAbstractPublisherPlugin(),
        new AlgoliaProductConcretePublisherPlugin(),
        new AlgoliaProductConcreteDeletePublisherPlugin(),
        new ProductCategoryProductUpdatedEventTriggerPlugin(),
        new ProductLabelProductUpdatedEventTriggerPlugin(),
    ];
}
```

**2e. Enable frontend search**

Create `src/Pyz/Client/Algolia/AlgoliaConfig.php`:

```php
&lt;?php

namespace Pyz\Client\Algolia;

use SprykerEco\Client\Algolia\AlgoliaConfig as SprykerEcoAlgoliaConfig;

class AlgoliaConfig extends SprykerEcoAlgoliaConfig
{
    public function isSearchInFrontendEnabledForProducts(): bool
    {
        return true;
    }

    public function isSearchInFrontendEnabledForCmsPages(): bool
    {
        return true;
    }
}
```

**2f. Generate transfers**

```bash
vendor/bin/console transfer:generate
```

### 3. Export data and verify

- No data schema migration is needed—the data structure is the same as the ACP app.
- To reuse existing Algolia indices and avoid re-indexing, set `TENANT_IDENTIFIER` to match the ACP tenant ID.

Use the following command for the full export to re-populate Algolia indices (if needed):

```bash
vendor/bin/console algolia:entity-export --all
```
  
- Test a product update in the Back Office and verify the change appears in Algolia.
- Test a CMS page publish in the Back Office and verify the change appears in Algolia.

## Troubleshooting

### No entity types are available in console algolia:entity-export

**Problem:** `No entity exporters are registered`

**Solution:**
1. Make sure plugins are registered in `AlgoliaDependencyProvider::getAlgoliaEntityExporterPlugins()`.
2. Check that the dependency provider is in the `Pyz` namespace if extended.

### Transfer not found

**Problem:** `Class &apos;Generated\Shared\Transfer\AlgoliaExportCriteriaTransfer&apos; not found`

**Solution:**

```bash
vendor/bin/console transfer:generate
```

### Events are not triggering

**Problem:** Changes are not appearing in Algolia.

**Solution:**
1. Check that `AlgoliaConfig::getIsActive()` returns `true`.
2. Verify publisher plugins are registered in `PublisherDependencyProvider`.
3. Check that queue workers are running:

   ```bash
   vendor/bin/console queue:task:start publish
   ```

### Search requests are failing

**Problem:** Search queries return errors or no results.

**Solution:**
1. Verify that Algolia credentials in the configuration are correct.
2. Make sure indices exist in the Algolia Dashboard.
3. If you are not using an Algolia premium plan, disable personalization by setting `getIsPersonalizationEnabled()` to return `false`.
</description>
            <pubDate>Thu, 23 Jul 2026 09:19:42 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/search/latest/base-shop/third-party-integrations/algolia/integrate-algolia.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/search/latest/base-shop/third-party-integrations/algolia/integrate-algolia.html</guid>
            
            
        </item>
        
        <item>
            <title>AI Dev SDK Skills and Agents</title>
            <description>&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Experimental module&lt;/div&gt;
&lt;p&gt;The AiDev module is experimental and not stable. There is no backward compatibility promise for this module. We welcome your feedback and contributions as we continue to develop and improve this module.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;/h2&gt;
&lt;p&gt;The AI Dev SDK ships a set of skills and agents that codify common Spryker workflows. They reach your project in two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Via the &lt;code&gt;ai-dev:setup&lt;/code&gt; console command&lt;/strong&gt; — copies the skills and agents into your project’s AI-tool directories (&lt;code&gt;.claude/skills/&lt;/code&gt; + &lt;code&gt;.claude/agents/&lt;/code&gt;, &lt;code&gt;.windsurf/skills/&lt;/code&gt; + &lt;code&gt;.windsurf/agents/&lt;/code&gt;, and so on). Works for every AI tool listed on the &lt;a href=&quot;/docs/dg/dev/ai/ai-dev/ai-dev-overview.html#setup-command&quot;&gt;AI Dev SDK Overview&lt;/a&gt; that supports an agents directory. Codex CLI is the one exception — it has no agents directory, so agents are skipped for that tool.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Via the Claude Code plugin&lt;/strong&gt; — for Claude Code users, the &lt;a href=&quot;/docs/dg/dev/ai/ai-dev/ai-dev-claude-code-plugin.html&quot;&gt;Claude Code Plugin&lt;/a&gt; installs the same skills and agents through the official marketplace, no console command required.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both delivery paths read from the same source files — the plugin just packages them for marketplace installation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What’s the difference between a skill and an agent?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Skills&lt;/strong&gt; load into the active chat on demand. Use them when you want the assistant to follow a specific workflow (write a product requirement document, refresh caches, run QA).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agents&lt;/strong&gt; are isolated sub-conversations the assistant delegates to. Use them when you want focused, single-purpose work done in its own context window (verify a behavior, diagnose a failure).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You do not need to remember the names — the assistant picks the right skill or agent from your prompt. The tables below explain what each one does so you know what to expect.&lt;/p&gt;
&lt;h2 id=&quot;how-to-invoke&quot;&gt;How to invoke&lt;/h2&gt;
&lt;p&gt;In most cases you do not need to call a skill or agent by name. Describe what you want — &lt;em&gt;“build this feature”&lt;/em&gt;, &lt;em&gt;“verify the new fee shows on the cart”&lt;/em&gt;, &lt;em&gt;“write a product requirement document for…”&lt;/em&gt; — and the assistant matches your wording to the right skill or agent from the set installed in your project.&lt;/p&gt;
&lt;p&gt;If you want to invoke one explicitly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Claude Code plugin&lt;/strong&gt; — every skill is also available as a slash command. Type &lt;code&gt;/&amp;lt;skill-name&amp;gt;&lt;/code&gt; (for example &lt;code&gt;/spryker-customization&lt;/code&gt;) and the skill loads into the current chat. The full list of commands is on the &lt;a href=&quot;/docs/dg/dev/ai/ai-dev/ai-dev-claude-code-plugin.html#skills&quot;&gt;Claude Code Plugin&lt;/a&gt; page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Other AI tools&lt;/strong&gt; — invocation follows the tool’s own convention for skills and agents. In Cursor, Windsurf, Copilot, OpenCode, and Codex CLI, the skills and agents land in the tool-specific directories (&lt;code&gt;.cursor/&lt;/code&gt;, &lt;code&gt;.windsurf/&lt;/code&gt;, etc.) and are picked up automatically by your assistant. The &lt;a href=&quot;/docs/dg/dev/ai/ai-dev/ai-dev-overview.html#setup-command&quot;&gt;AI Dev SDK Overview&lt;/a&gt; lists the output paths per tool.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agents (subagents)&lt;/strong&gt; are not invoked by the user directly — they are spawned by the assistant or by a parent skill when the work calls for an isolated context. You can suggest one by name in your prompt (&lt;em&gt;“use the spryker-verifier to…”&lt;/em&gt;), but the assistant decides when to spawn.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;skills&quot;&gt;Skills&lt;/h2&gt;
&lt;p&gt;Skills are delivered through &lt;code&gt;ai-dev:setup&lt;/code&gt; (all supported AI tools) or the Claude Code plugin.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Skill&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Benefits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ai-dev-setup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate rules, an agents/context file, and skills for the project and the chosen AI tool&lt;/td&gt;
&lt;td&gt;One command sets up consistent AI tooling for the whole team&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;code-review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Review staged or PR changes against Spryker coding standards&lt;/td&gt;
&lt;td&gt;Catches Spryker-specific issues before they reach a pull request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;propel-schema&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create and modify Propel ORM schema files&lt;/td&gt;
&lt;td&gt;Follows Spryker schema conventions automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;data-import&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create and modify data import CSV files and importers&lt;/td&gt;
&lt;td&gt;Generates importers that fit Spryker’s data-import path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;codecept-functional&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate Codeception functional tests&lt;/td&gt;
&lt;td&gt;Tests follow Spryker test patterns out of the box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;static-validation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run and interpret static analysis tools (PHPStan, PHP CS Fixer)&lt;/td&gt;
&lt;td&gt;Quick diagnosis of style and type issues without context-switching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;payment-template&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scaffold payment method integration&lt;/td&gt;
&lt;td&gt;Follows Spryker payment module patterns end-to-end&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;yves-atomic-frontend&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create atomic design components for the Yves storefront&lt;/td&gt;
&lt;td&gt;Components match the project’s atomic conventions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;product-requirement-document&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Turn a feature idea into a research-grounded product requirement document before any code is written&lt;/td&gt;
&lt;td&gt;Spec-before-code; assigns a real Spryker actor to every story; cuts ambiguity before implementation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/docs/dg/dev/ai/ai-dev/ai-dev-customization-workflow.html&quot;&gt;&lt;code&gt;spryker-customization&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Walk a product requirement document or set of acceptance criteria through to a committed branch&lt;/td&gt;
&lt;td&gt;One workflow drives the full build; quality bar (PoC or MVP) chosen up-front; delegates focused work to the agents below; never auto-commits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-bugfix&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Drive a bug from an optional tracker ticket or a plain description through to a committed, validated, QA-accepted fix&lt;/td&gt;
&lt;td&gt;Orchestrates reproduce, root-cause, minimal fix, functional test, static validation, review, QA, and final verification; a shared attempt budget loops back on any failed gate; Autonomous mode adds a pushed Draft PR with a remote-CI watch loop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-refresher&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run the right post-change console and composer commands after edits&lt;/td&gt;
&lt;td&gt;Owns the file-to-command mapping (codegen, caches, frontend builds, class-resolver); no missed cache rebuilds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-qa-coverage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Turn acceptance criteria into a four-bucket test plan executed against the live app&lt;/td&gt;
&lt;td&gt;Coverage goes beyond literal ACs — happy / negative / authorization / corner cases; reports pass/fail with real evidence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-docs-research&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Look up the right answer in official Spryker documentation&lt;/td&gt;
&lt;td&gt;Grounds AI work in documented behavior rather than the model’s memory; falls back gracefully when MCP tools are unavailable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-runtime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Drive the running Spryker application — Yves, Back Office, Merchant Portal, console, HTTP&lt;/td&gt;
&lt;td&gt;Real authenticated sessions; read-only DB / Redis / queue inspection; reusable building block for higher-level skills and agents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ai-runtime-debugging&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inspect Spryker runtime state safely from an AI session&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[AI-DEBUG]&lt;/code&gt; tagged-log pattern plus optional XDebug step-debug; built-in cleanup of debug instrumentation before commit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;agents&quot;&gt;Agents&lt;/h2&gt;
&lt;p&gt;Agents are delivered through &lt;code&gt;ai-dev:setup&lt;/code&gt; (every supported AI tool with an agents directory) or the Claude Code plugin.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Benefits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-code-reviewer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Review code against Spryker’s coding standards and architectural rules&lt;/td&gt;
&lt;td&gt;Deeper, Spryker-aware review than a generic linter; catches layer-architecture and module-convention issues&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-feature-expert&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Answer “how does feature X work in this project / in Spryker”&lt;/td&gt;
&lt;td&gt;Pushes back when the user’s framing reinvents an existing primitive; surfaces canonical patterns first; never edits code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-verifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verify that a specific behavior holds in the running Spryker environment&lt;/td&gt;
&lt;td&gt;Returns PASS / FAIL / BLOCKED per acceptance criterion with raw evidence; never lies green; never tries to fix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-issue-diagnoser&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Investigate why something failed and return a root cause&lt;/td&gt;
&lt;td&gt;Reads logs, DB state, queue, search, browser console — returns a suggested direction; never attempts the fix itself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-data-seeder&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create small additive test data through Spryker’s existing import path&lt;/td&gt;
&lt;td&gt;Safe and incremental — CSV + &lt;code&gt;data:import&lt;/code&gt; only; never edits code, never writes directly to the database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-screenshot-collector&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Capture screenshots and GIFs of pages and flows for demos and documentation&lt;/td&gt;
&lt;td&gt;Pure capture — never asserts whether something works, never investigates failures, never edits&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;related&quot;&gt;Related&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/docs/dg/dev/ai/ai-dev/ai-dev-overview.html&quot;&gt;AI Dev SDK Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/docs/dg/dev/ai/ai-dev/ai-dev-mcp-server.html&quot;&gt;AI Dev MCP Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/docs/dg/dev/ai/ai-dev/ai-dev-claude-code-plugin.html&quot;&gt;Claude Code Plugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
            <pubDate>Wed, 22 Jul 2026 11:41:26 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/ai/ai-dev/ai-dev-skills-and-agents.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/ai/ai-dev/ai-dev-skills-and-agents.html</guid>
            
            
        </item>
        
        <item>
            <title>Claude Code Plugin</title>
            <description>&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Experimental module&lt;/div&gt;
&lt;p&gt;The AiDev module is experimental and not stable. There is no backward compatibility promise for this module. We welcome your feedback and contributions as we continue to develop and improve this module.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Project must be running&lt;/div&gt;
&lt;p&gt;The MCP server runs inside your Spryker Docker container. Start your project with &lt;code&gt;docker/sdk run&lt;/code&gt; before using any skills that rely on MCP tools.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;/h2&gt;
&lt;p&gt;Working with Spryker in an AI coding assistant without project-specific context leads to a predictable pattern: the AI generates plausible-looking code that does not follow Spryker’s layer architecture, uses the wrong patterns, or misses module conventions entirely. You end up spending more time correcting mistakes than you saved.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;spryker-ai-dev-sdk&lt;/code&gt; Claude Code plugin closes this gap. It gives Claude Code deep knowledge of how Spryker projects are structured — layers, namespaces, plugin stacks, transfer objects, OMS flows — so the code it generates fits your project from the start instead of requiring repeated corrections.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does for you:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No more explaining Spryker basics.&lt;/strong&gt; Rules covering 20 Spryker architectural patterns are automatically loaded into every session. Claude Code knows about factories, dependency providers, expanders, mappers, and more without you having to explain them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Correct code on the first attempt.&lt;/strong&gt; Skills for common Spryker tasks — Propel schema changes, data importers, functional tests, payment integrations, atomic frontend components — follow the exact conventions your project expects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Live project context.&lt;/strong&gt; The MCP server runs inside your Docker container and gives Claude Code real-time access to your transfer objects, module interfaces, and OMS configuration. The AI works with your actual project data, not guesses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistent code reviews.&lt;/strong&gt; The &lt;code&gt;spryker-code-reviewer&lt;/code&gt; subagent checks your changes against Spryker’s coding standards and architectural rules, catching issues before they reach a PR.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Team-wide consistency.&lt;/strong&gt; Generated rules and context files are committed to your repository, so every developer on the team works with the same AI configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The plugin is distributed through the &lt;code&gt;spryker-plugins-official&lt;/code&gt; marketplace and installed directly inside Claude Code.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://claude.ai/code&quot;&gt;Claude Code&lt;/a&gt; installed&lt;/li&gt;
&lt;li&gt;Your Spryker project is running: &lt;code&gt;docker/sdk run&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;install-the-plugin-from-the-marketplace&quot;&gt;Install the plugin from the marketplace&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open Claude Code in your terminal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the Spryker plugin marketplace:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/dg/dev/ai-dev/claude-plugin-step-1.png&quot; alt=&quot;step 1&quot; /&gt;
&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/dg/dev/ai-dev/claude-plugin-step-2.png&quot; alt=&quot;step 2&quot; /&gt;
&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/dg/dev/ai-dev/claude-plugin-step-3.png&quot; alt=&quot;step 3&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the plugin:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/dg/dev/ai-dev/claude-plugin-step-4.png&quot; alt=&quot;step 4&quot; /&gt;
&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/dg/dev/ai-dev/claude-plugin-step-5.png&quot; alt=&quot;step 5&quot; /&gt;
&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/dg/dev/ai-dev/claude-plugin-step-6.png&quot; alt=&quot;step 6&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After installation, reload plugins in Claude Code.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/dg/dev/ai-dev/claude-plugin-step-7.png&quot; alt=&quot;Choose output mode step 7&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;set-up-ai-tooling-for-your-project&quot;&gt;Set up AI tooling for your project&lt;/h2&gt;
&lt;p&gt;After installing the plugin, run the &lt;code&gt;ai-dev-setup&lt;/code&gt; skill to configure your project. The skill generates rules, context files, and reusable AI skills tailored to your project and AI tool.&lt;/p&gt;
&lt;p&gt;In Claude Code, run the setup skill:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/dg/dev/ai-dev/claude-skill-setup.png&quot; alt=&quot;ai-dev-setup&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The skill:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Installs the &lt;code&gt;spryker-sdk/ai-dev&lt;/code&gt; package in your Spryker project.&lt;/li&gt;
&lt;li&gt;Wires up console commands for &lt;code&gt;McpServerConsole&lt;/code&gt; and &lt;code&gt;AiToolSetupConsole&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Registers the AI Dev MCP server with Claude Code.&lt;/li&gt;
&lt;li&gt;Adds &lt;code&gt;.claude/rules/&lt;/code&gt; with Spryker coding conventions and architectural guidelines.&lt;/li&gt;
&lt;li&gt;Adds &lt;code&gt;CLAUDE.md&lt;/code&gt; with project-specific context loaded into every Claude Code session.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Check with running &lt;code&gt;/context&lt;/code&gt; in Claude Code to see:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/dg/dev/ai-dev/claude-install-1.png&quot; alt=&quot;claude-setup-1&quot; /&gt;
&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/dg/dev/ai-dev/claude-install-2.png&quot; alt=&quot;claude-setup-2&quot; /&gt;
&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/dg/dev/ai-dev/claude-install-3.png&quot; alt=&quot;claude-setup-3&quot; /&gt;
&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/dg/dev/ai-dev/claude-install-4.png&quot; alt=&quot;claude-setup-4&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;capabilities&quot;&gt;Capabilities&lt;/h2&gt;
&lt;p&gt;For a one-page reference of every skill and agent — what each does, when to use it, and the value it adds — see &lt;a href=&quot;/docs/dg/dev/ai/ai-dev/ai-dev-skills-and-agents.html&quot;&gt;AI Dev SDK Skills and Agents&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;skills&quot;&gt;Skills&lt;/h3&gt;
&lt;p&gt;The plugin bundles the following Spryker-aware skills. Invoke them in Claude Code with the &lt;code&gt;/&lt;/code&gt; prefix.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Skill&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AI Dev Setup&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:ai-dev-setup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generates rules, a context file, and skills for your project and AI tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code Review&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:code-review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reviews staged or PR changes against Spryker coding standards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Propel Schema&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:propel-schema&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Helps create and modify Propel ORM schema files following Spryker conventions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Import&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:data-import&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Assists with creating and modifying data import CSV files and importers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codecept Functional&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:codecept-functional&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generates Codeception functional tests following Spryker test patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static Validation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:static-validation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runs and interprets static analysis tools (PHPStan, PHP CS Fixer)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payment Template&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:payment-template&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scaffolds payment method integration following Spryker payment module patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yves Atomic Frontend&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:yves-atomic-frontend&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Helps create atomic design components for the Yves frontend&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Product Requirement Document&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:product-requirement-document&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Drafts a research-grounded product requirement document for a Spryker feature before implementation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spryker Customization&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:spryker-customization&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Orchestrates the end-to-end build of a customization from product requirement document to committed branch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spryker Bugfix&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:spryker-bugfix&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Orchestrates the end-to-end bug fix from a ticket or description to a committed, validated, QA-accepted branch (Autonomous mode adds a pushed Draft PR with a CI watch loop)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spryker Refresher&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:spryker-refresher&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runs the right post-change console and composer commands after edits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spryker QA Coverage&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:spryker-qa-coverage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Turns acceptance criteria into a four-bucket test plan and executes it against the running app&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spryker Docs Research&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:spryker-docs-research&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Looks up grounded answers in the official Spryker documentation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spryker Runtime&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:spryker-runtime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Drives the running Spryker application — storefront, back office, console, HTTP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI Runtime Debugging&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/spryker-ai-dev-sdk:ai-runtime-debugging&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Adds tagged debug logs (and optional XDebug) for inspecting Spryker runtime state&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;subagents&quot;&gt;Subagents&lt;/h3&gt;
&lt;p&gt;The plugin includes the following subagents. They are isolated sub-conversations that the assistant delegates to for focused, single-purpose work:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Subagent&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-code-reviewer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Performs deep code reviews of your changes against Spryker architectural patterns, coding standards, and best practices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-feature-expert&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Answers questions about how a Spryker feature, module, or capability works, grounded in docs and the project’s actual code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-verifier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verifies a specific behavior in the running Spryker environment and returns PASS, FAIL, or BLOCKED per acceptance criterion with raw evidence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-issue-diagnoser&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Investigates a failure across logs, database, queue, search, and browser state and returns a root cause&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-data-seeder&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creates small additive test data through Spryker’s existing data import path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spryker-screenshot-collector&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Captures screenshots and short GIFs of pages and flows for demos and documentation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;rules&quot;&gt;Rules&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ai-dev-setup&lt;/code&gt; skill writes a set of &lt;a href=&quot;https://github.com/spryker-sdk/ai-dev/tree/master/data/rules&quot;&gt;Spryker-specific coding rules&lt;/a&gt; into your project. These rules guide the AI to follow Spryker conventions automatically, without requiring you to explain them in every prompt.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule file&lt;/th&gt;
&lt;th&gt;What it enforces&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;business-models.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Business model structure and responsibilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;client-zed-communication.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Client–Zed gateway communication patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;controller.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Controller conventions and responsibilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dependency-provider.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dependency provider wiring and plugin stacks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enforce-constants-for-control-flow.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use of constants instead of magic strings in control flow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;expander-pattern.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expander pattern for extending transfer objects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;factory-pattern.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Factory class structure and dependency injection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;form-data-loading-performance.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Performant data loading in Zed forms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;layer-communication.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cross-layer call rules (Presentation → Communication → Business → Persistence)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mapper-pattern.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mapper pattern for transfer-to-transfer and entity-to-transfer mappings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;module-config.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Module configuration class conventions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;naming-conventions.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Class, method, and variable naming standards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;owasp.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OWASP security guidelines applied to Spryker code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;performance.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Performance best practices (query optimization, caching)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;persistence.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Persistence layer conventions (repositories, entity managers)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php-code-style.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PHP code style rules (PSR compliance, formatting)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;plugins.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Plugin and plugin interface implementation patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;table.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Back Office table and query container conventions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;transfer-object.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Transfer object usage and immutability rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upgradability.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Backward compatibility and upgradability guidelines&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;context-file&quot;&gt;Context file&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ai-dev-setup&lt;/code&gt; skill generates a &lt;code&gt;CLAUDE.md&lt;/code&gt; context file based on the &lt;a href=&quot;https://github.com/spryker-sdk/ai-dev/blob/master/data/agents/AGENTS.example.md&quot;&gt;AGENTS.example.md&lt;/a&gt; template. This file is automatically loaded into every Claude Code session and provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Common Docker CLI commands for your Spryker project&lt;/li&gt;
&lt;li&gt;Spryker application layer overview (Zed, Yves, Glue, Client, Service, Shared)&lt;/li&gt;
&lt;li&gt;Namespace and directory structure&lt;/li&gt;
&lt;li&gt;Component rules for controllers, plugins, factories, repositories, and more&lt;/li&gt;
&lt;li&gt;Abstract class references for all layers&lt;/li&gt;
&lt;/ul&gt;
&lt;section class=&apos;info-block &apos;&gt;&lt;i class=&apos;info-block__icon icon-info&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Starting point, not a complete setup&lt;/div&gt;
&lt;p&gt;The files generated by &lt;code&gt;ai-dev-setup&lt;/code&gt; are a baseline derived from Spryker defaults. They cover general Spryker conventions but do not include anything specific to your project — custom modules, third-party integrations, team conventions, or environment details. Treat the generated &lt;code&gt;CLAUDE.md&lt;/code&gt; and rules as a starting point and extend them with your project-specific requirements.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
</description>
            <pubDate>Wed, 22 Jul 2026 11:41:26 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/ai/ai-dev/ai-dev-claude-code-plugin.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/ai/ai-dev/ai-dev-claude-code-plugin.html</guid>
            
            
        </item>
        
        <item>
            <title>AWS permissions</title>
            <description>&lt;p&gt;The following permissions apply to all users regardless of whether they access the environment via IAM user or SSO.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service area&lt;/th&gt;
&lt;th&gt;What you can do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD&lt;/td&gt;
&lt;td&gt;Start, stop, retry, and monitor pipelines and builds; view repositories and deployment history.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring and logs&lt;/td&gt;
&lt;td&gt;View CloudWatch metrics; create, view, and delete dashboards; read log groups and run log queries.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Databases&lt;/td&gt;
&lt;td&gt;View, restore, reboot, and manage RDS database instances; create and delete snapshots; modify parameter groups; view Performance Insights metrics.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Containers&lt;/td&gt;
&lt;td&gt;View ECS clusters, services, and tasks; list and describe container images. Read-only.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;Read and write to project asset buckets and CSV upload bucket; list all buckets.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parameter Store&lt;/td&gt;
&lt;td&gt;Read and write configuration and secret parameters within &lt;a href=&quot;/docs/ca/dev/add-variables-in-the-parameter-store.html&quot;&gt;Environment Variable Management&lt;/a&gt; guardrails; manage application deployment version parameters.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CloudFront&lt;/td&gt;
&lt;td&gt;View CloudFront distributions; create cache invalidations; view WAF rules and ACM certificates.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;td&gt;Full access to Simple Email Service.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS&lt;/td&gt;
&lt;td&gt;Read-only access to hosted zones and domain names.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Backup&lt;/td&gt;
&lt;td&gt;Configure, manage, and execute backups across supported AWS services.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IAM (own account only)&lt;/td&gt;
&lt;td&gt;Manage your own password, MFA devices, SSH public keys, Git credentials, and access keys.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</description>
            <pubDate>Wed, 22 Jul 2026 11:23:41 +0000</pubDate>
            <link>https://docs.spryker.com/docs/ca/dev/access/aws-permissions.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/ca/dev/access/aws-permissions.html</guid>
            
            
        </item>
        
        <item>
            <title>SSO Access</title>
            <description>{% info_block infoBox %}

This feature is part of a gradual rollout and will be available to everyone eventually. We will notify your team once your project is onboarded.

{% endinfo_block %}

## What is SSO

**Single Sign-On (SSO)** is an authentication mechanism that allows users to sign in once and access multiple applications without re-authenticating for each service (RMQ, Jenkins).

SSO can be integrated with an external organizational identity provider (IdP), such as a corporate directory service, enabling centralized user management and access control.

This approach improves security by reducing password reuse and enhances the user experience by minimizing repeated logins.

## How SSO improves the user experience

SSO makes accessing services easier, faster, and more secure by providing:

- **Centralized authentication** through your company&apos;s identity provider, or via users managed in our identity system
- **Fewer passwords to remember**, reducing friction and support overhead
- **A faster and smoother login experience** across all connected services
- **Simplified user lifecycle management** (onboarding, updates, and offboarding)
- **Stronger security and compliance** through consistent authentication policies
- **Easy integration for enterprise organizations** that use their own identity provider

## How to access applications with an SSO user

You will need an SSO user, [User Management SSO](/docs/ca/dev/cloud-hub/sso-user-management.html) describes how to get one.

### AWS access

#### AWS Management Console

1. Click on **AWS Console** service in CloudHub which will lead to the SSO login page.
2. Log in using your SSO user credentials.
3. After successful authentication, you will be redirected to the AWS Management Console with access to your environment services.

#### AWS CLI

To access AWS services via the AWS CLI with your SSO credentials, see [Connecting to AWS CLI with an SSO user](/docs/ca/dev/access/connecting-to-aws-cli-with-an-sso-user.html).

### VPN access

VPN access uses short-lived sessions for improved security. To start a VPN session, you must go through the SSO login process and provide an MFA code.

1. Open your VPN client and initiate a connection to the target environment.
2. When prompted, log in using your SSO user credentials.
3. Provide your MFA code to complete authentication.
4. Once authenticated, the VPN session is established. The session is short-lived and will expire after a period of inactivity or at a set time limit.

To reconnect after a session expires, repeat the SSO login and MFA steps.

### RabbitMQ access

For RabbitMQ, the user must have VPN enabled for the specific environment they want to access. Once the VPN is enabled:

1. Click on **RabbitMQ** service in CloudHub which will lead to the RabbitMQ login page.
2. Click the **Log in** button.
3. You will be redirected to the SSO login form.
4. Provide your SSO user credentials and log in.

If you previously logged in to VPN or any other application in the same browser, for example Jenkins, log in happens automatically, because you are using the same SSO user.

### Jenkins access

For Jenkins, the user must have VPN enabled for the specific environment they want to access. Once the VPN is enabled:

1. Click on **Jenkins** service in CloudHub which will lead to the SSO login page.
2. Provide your SSO user credentials and log in.
3. You will be redirected to the Jenkins dashboard.

If you previously logged in to VPN or any other application in the same browser, for example RabbitMQ, log in happens automatically, because you are using the same SSO user.

### Keycloak access

Keycloak is where you can view and edit your SSO user profile (editing options are limited).

1. Click on **Keycloak** service in CloudHub which will lead to the SSO login page.
2. Provide your SSO user credentials and log in.
3. You will be redirected to Keycloak where you can change your username and password.

If you previously logged in to VPN or any other application in the same browser, for example RabbitMQ, log in happens automatically, because you are using the same SSO user.

## External IdP connection

As an alternative or additional authentication method, we support connection to external Identity Providers (IdPs) that use SAML or OpenID Connect (OIDC).

Benefits of using an external IdP:

- You can apply and enforce your own authentication policies.
- You can manage user assignments and permissions to all supported services directly through your IdP without creating any Self‑Service requests.
- Centralized lifecycle management of users (onboarding/offboarding handled entirely in your IdP).
- Stronger security posture through enterprise-grade features such as MFA, conditional access, and device or network policies.
- Seamless user experience with a single set of corporate credentials.
- Reduced administrative overhead by eliminating duplicate user management.
- Better compliance and auditing through centralized identity logs and policies.
- Faster and automated access provisioning as your organization scales.
- Improved security posture by not storing or processing passwords within our platform.

{% info_block infoBox &quot;Acquiring external IdP users limitation&quot; %}

Such users **cannot** be created or managed via CloudHub User Management (SSO) page. For configuration details, contact our support team.

{% endinfo_block %}

## Next steps

- [User Management SSO](/docs/ca/dev/cloud-hub/sso-user-management.html)
- [SSO Security Options](/docs/ca/dev/access/sso-security-options.html)
- [Connecting to AWS CLI with an SSO user](/docs/ca/dev/access/connecting-to-aws-cli-with-an-sso-user.html)
- [AWS permissions](/docs/ca/dev/access/aws-permissions.html)
</description>
            <pubDate>Wed, 22 Jul 2026 10:26:34 +0000</pubDate>
            <link>https://docs.spryker.com/docs/ca/dev/access/sso-access.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/ca/dev/access/sso-access.html</guid>
            
            
        </item>
        
    </channel>
</rss>
