<?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>Mon, 16 Mar 2026 08:55:46 +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.
- *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>Mon, 16 Mar 2026 08:55:32 +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>Verify Vertex Connection</title>
            <description>This document describes how to verify Vertex integration.

## Prerequisites

- [Install Vertex](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html).
- Create an account with [Vertex](https://www.vertexinc.com/). If you need support getting a Vertex account, contact [support](https://support.spryker.com/) or your Customer Success Manager.
- Optional: For Vertex Validator integration, create an account with [Vertex Validator](https://www.vertexinc.com/).

## Verify Vertex connection

{% info_block warningBox &quot;Test the configuration&quot; %}

To ensure accuracy and compliance with tax laws, we highly recommend thoroughly testing the Vertex integration.

{% endinfo_block %}

Once you&apos;ve configured Vertex, the taxes are calculated in real time in the checkout. A message about this is displayed on the checkout page.

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

On the Storefront, the tax amount is displayed on the checkout summary page.

In the Back Office, the taxes are displayed on the order details page.

If you configured invoices to be saved in Vertex, you can view the taxes processed by Vertex as follows:

1. In the Vertex dashboard, go to **Reporting** &gt; **Standard Reports**.
2. Click **Report Output**.
3. Next to the report you want to view the taxes for, click **Action**&gt;**View report**.
![vertex-report-output](https://spryker.s3.eu-central-1.amazonaws.com/docs/pbc/all/tax-management/vertex/configure-vertex/vertex-report-output.png)
4. On the invoice page, you can verify the invoice number that corresponds to the Spryker order number and the applicable country tax calculated by Vertex.
![invoice-in-vertex](https://spryker.s3.eu-central-1.amazonaws.com/docs/pbc/all/tax-management/vertex/configure-vertex/invoice-in-vertex.png)


## Verify Vertex Validator tax ID validation

Validate a tax ID by sending a request to `/tax-id-validate` using Glue API.

### Request

```json
{
    &quot;data&quot;: {
        &quot;type&quot;: &quot;tax-id-validate&quot;,
        &quot;attributes&quot;: {
            &quot;countryCode&quot;: &quot;**&quot;,
            &quot;taxId&quot;: &quot;*****&quot;
        }
    }
}
```

One of the following should be returned:

Successful response: HTTP code: 200.

```json
{
  &quot;data&quot;: [],
  &quot;links&quot;: []
}
```

Unsuccessful response: HTTP code: 400, 422.

```json
{
  &quot;errors&quot;: [
    {
      &quot;status&quot;: 400,
      &quot;detail&quot;: &quot;Wrong format of the tax number.&quot;
    }
  ]
}
```</description>
            <pubDate>Mon, 16 Mar 2026 08:55:32 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/verify-vertex-connection.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/verify-vertex-connection.html</guid>
            
            
        </item>
        
        <item>
            <title>Release notes 202507.0</title>
            <description>Spryker Cloud Commerce OS is an end-to-end solution for digital commerce. This document contains a business-level description of new features and improvements.

For information about installing Spryker, see [Getting started guide](/docs/dg/dev/development-getting-started-guide.html).



## Self-Service Portal {% include badge.html type=&quot;new-product&quot; %}

Self-Service Portal is a comprehensive digital solution that empowers customers to manage their own experience. It unifies traditional commerce and after-sales interactions within a single, intuitive self-service platform.

![Self-Service Portal](https://spryker.s3.eu-central-1.amazonaws.com/docs/About/all/releases/release-notes-202507.0.md/SSP.png)


### Key capabilities

- Self-service dashboard: A centralized hub for managing all asset-related data and interactions, offering permission-based access, enhanced visibility, and great operational efficiency
- Asset management: Enables customers to organize, track, and access assets, such as physical or digital products
- Services: Consolidates offline and online services into a unified ordering and management process
- General inquiries: Streamlines how customers submit general questions or requests related to products and services
- Claims: Simplifies the submission and resolution of warranty claims, refund requests, and order-related issues, improving service quality and reducing operational costs
- Asset inquiries: Supports detailed inquiries about specific assets, such as technical specs or irregular behavior
- File management: Offers secure, centralized file storage and sharing to enhance collaboration and ensure vital documents for the assets are always accessible

### Business benefits

- Customer empowerment and convenience: Reduce support overhead by enabling customers to independently manage inquiries, assets, and services through an intuitive self-service interface
- Operational efficiency: Centralize permission-based access to assets and files to streamline data management, improve accuracy, and reduce manual processes
- Enhance customer satisfaction and loyalty: Increase satisfaction and retention by delivering faster resolutions and full transparency across all after-sales and service interactions



### Docs

- [Self-Service Portal](/docs/pbc/all/self-service-portal/latest/self-service-portal)
- [Install Self-Service Portal](/docs/pbc/all/self-service-portal/latest/install/install-self-service-portal)



## Order Amendment {% include badge.html type=&quot;feature&quot; %}

The Order Amendment feature enhances the shopping experience by enabling customers to add, update, and remove items from existing orders after placement. This brings flexibility and control to the post-purchase process:
- Flexible price recalculation: Choose between retaining original prices, applying current catalog prices, or defining a custom strategy to suit your business logic.
- Flexible stock recalculation: Allow order edits even if items are deactivated or out of stock by preserving original order stock. Quantity can be adjusted down or increased, up to the combined amount of reserved order stock and current catalog availability.
- Seamless multi-cart experience: Customers can switch between editing an order and shopping in their active cart without losing progress. This functionality requires [multi-cart](/docs/pbc/all/cart-and-checkout/latest/base-shop/feature-overviews/multiple-carts-feature-overview).
- Preserve original order reference: Maintain consistent tracking and reporting by keeping the original order reference.


&lt;figure class=&quot;video_container&quot;&gt;
    &lt;video width=&quot;100%&quot; height=&quot;auto&quot; controls&gt;
    &lt;source src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/pbc/all/order-management-system/base-shop/order-amendment-feature-overview.md/Order_Amendment_Explained.mp4&quot; type=&quot;video/mp4&quot;&gt;
  &lt;/video&gt;
&lt;/figure&gt;


### Business benefits

- Reduce cancellations by allowing post-checkout edits
- Minimize manual customer service interventions



### Docs

- [Order Amendment feature overview](/docs/pbc/all/order-management-system/latest/base-shop/order-amendment-feature-overview)
- [Install the Order Amendment feature](/docs/pbc/all/order-management-system/latest/base-shop/install-and-upgrade/install-features/install-the-order-amendment-feature)







## Bulk product import in Merchant Portal {% include badge.html type=&quot;early-access&quot; %} {% include badge.html type=&quot;feature&quot; %}

The Product Import feature in the Merchant Portal enables you to bulk upload products using a universal CSV format, streamlining workflows, reducing manual effort, and accelerating time-to-market.

![merchant-portal-import](https://spryker.s3.eu-central-1.amazonaws.com/docs/About/all/releases/release-notes-202507.0.md/merchant-portal-import.png)



### Key capabilities

- Import products, pricing, and stock in one go: Upload a single file to populate essential product data, minimizing repetitive tasks and improving data accuracy.
- Simplified CSV structure: Use a clean, single-line format that supports fast onboarding and easy updates to large product catalogs.
- Built-in import logs: Get immediate feedback with success and error logs to troubleshoot issues and ensure smooth uploads.

### Business benefits


- Empower merchants with self-service tools
- Launch and update product catalogs faster
- Reduce data entry errors and manual rework

### Docs

- [Install the Marketplace Merchant Portal Data Import feature](/docs/pbc/all/product-information-management/latest/marketplace/install-and-upgrade/install-features/install-the-merchant-portal-data-import-feature.html)
- [Install the Marketplace Merchant Portal Product Data Import feature](/docs/pbc/all/product-information-management/latest/marketplace/install-and-upgrade/install-features/install-the-merchant-product-data-import-feature.html)



## Marketplace Discounts {% include badge.html type=&quot;improvement&quot; %}

The Marketplace Discounts enhancements introduce advanced targeting capabilities for Marketplace Operators, enabling promotions specific to individual merchants or product offers:

- Merchant-specific discounts: Apply discounts exclusively to products from a specific merchant using merchant references in discount conditions.
- Product offer-specific discounts: Target discounts at the product offer level for more granular promotions.

![marketplace-discounts](https://spryker.s3.eu-central-1.amazonaws.com/docs/About/all/releases/release-notes-202507.0.md/marketplace-discounts.png)



### Business benefits

- Strategic promotions: Gain full control to drive growth in specific segments, support underperforming merchants, or push high-priority inventory.
- Merchant performance and retention: Equip your merchants with tools to run tailored promotions under your governance, helping them increase sales and stay competitive.


### Docs

- [Install the Marketplace Merchant + Promotions &amp; Discounts feature](/docs/pbc/all/merchant-management/latest/marketplace/install-and-upgrade/install-features/install-the-marketplace-merchant-promotions-and-discounts-feature)
- [Install the Marketplace Product Offer + Promotions &amp; Discounts feature](/docs/pbc/all/offer-management/latest/marketplace/install-and-upgrade/install-features/install-the-marketplace-product-offer-promotions-and-discounts-feature)




## Discount conditions for customer-related criteria {% include badge.html type=&quot;improvement&quot; %}

The latest discount condition enhancements introduce more precise control over customer-related promotion scenarios, enabling restrictions and targeting directly based on customer identity or behavior:

- Maximum uses per customer: Limit how many times a logged-in customer can redeem a specific discount or voucher. Ideal for one-time offers, such as welcome codes, newsletter subscription rewards, or limited campaigns where repeated usage should be prevented.
- Customer reference: Target a discount at a specific customer by assigning their unique customer reference. Useful for compensation vouchers, exclusive rewards, or customer-specific promotional scenarios.


![customer-discount](https://spryker.s3.eu-central-1.amazonaws.com/docs/About/all/releases/release-notes-202507.0.md/customer-discount.png)


### Business benefits

- Precision in customer targeting and control: Define exactly who can use a promotion and how often, enabling tailored experiences for first-time buyers, high-value customers, or compensation scenarios.
- Increased promotion efficiency and ROI: Align discount usage with customer behavior and strategic goals, ensuring that promotions reach the right audience with the right frequency.



### Docs

[Install the Customer Account Management + Promotions &amp; Discounts feature](/docs/pbc/all/customer-relationship-management/latest/base-shop/install-and-upgrade/install-features/install-the-customer-account-management-promotions-and-discounts-feature)


## Back Office UX improvements {% include badge.html type=&quot;improvement&quot; %}

These updates make it easier to work with large data sets in the Back Office, especially across key areas like orders, products, and marketplace operations:

- Advanced table filters with multi-select: Quickly narrow down results in views, such as Orders, Products, Product Offers, Merchants, and Discounts, using flexible, multi-select filters.
- Search by product variant SKU: Find specific products faster by searching for concrete product SKUs in the Abstract Products list.
- Measurement unit management: Back Office users can now manage measurement units, including the ability to add and maintain translations for each unit.


![BO-filter-orders](https://spryker.s3.eu-central-1.amazonaws.com/docs/About/all/releases/release-notes-202507.0.md/BO-filter-orders.png)


### Business benefits

- Operational speed and efficiency: Save time on routine tasks with faster filtering and improved search capabilities—allowing teams to process orders, manage catalogs and discounts, and support merchants more effectively.
- Scalability in daily workflows: Handle high volumes of data with ease. The improved navigation and filtering ensure the Backoffice stays responsive and usable as your orders, product, and merchant base grows.





## Spryker Monitoring Integration {% include badge.html type=&quot;feature&quot; %}

Spryker Monitoring Integration integrates Spryker&apos;s monitoring data into your APM platform based on the Spryker&apos;s implementation of the OpenTelemetry framework. It enables you to unite Spryker&apos;s insights with your monitoring ecosystem, ensuring full visibility across eCommerce workflows, faster issue detection, and alignment with your monitoring best practices.


### Business benefits

- Personalized application monitoring: Integrate Spryker into your monitoring platform for a tailored, customized monitoring experience.
- Comprehensive tracing and health check metrics: Forward traces and health check metrics from both your application and Spryker services to enable precise performance analysis and faster anomaly detection
- Consolidated monitoring: Consolidate all performance data in a singe monitoring platform, ensuring full visibility across your entire eCommerce workflow


### Docs

[Spryker Monitoring Integration](/docs/ca/dev/monitoring/spryker-monitoring-integration/spryker-monitoring-integration.html)




## Configurable data exporter {% include badge.html type=&quot;feature&quot; %}

Configurable Data Exporter provides structured access to your operational data, built for flexibility, performance, and security. Export curated datasets on a scheduled basis to your own cloud storage without affecting production systems. Secure RDS-to-S3 transfers enable integration into your analytics stack, data lake, or ETL pipeline — whether for BI, ML, or advanced audits — all without added operational risk.


### Business benefits

- Plug into any destination: Easily connect to your BI tools or data pipelines, from Snowflake to Looker or custom analytics platforms.
- Scheduled and scalable: Automate your exports based on business cadence, ensuring consistency and performance as your data needs grow.
- Governed and composable: Fine-grained control over data scope and structure means exports align with internal policies and evolving business questions.
- Controlled access: Avoid direct querying of your production systems, protecting uptime while granting safe access to curated, business-critical datasets.


### Docs

[Set up data export to S3](/docs/ca/dev/set-up-data-export-to-s3.html)


## Algolia as a global search {% include badge.html type=&quot;improvement&quot; %}

The Algolia ACP app is expanded to support search through content within CMS pages and PDF documents, on top of existing product catalog search. This upgrade significantly enriches the search experience, delivering more relevant and complete results.

### Business benefits

- Improved user experience: Provides richer, more complete search results.
- Increased content discoverability: Makes all types of information searchable.

### Docs

[Algolia](/docs/pbc/all/search/latest/base-shop/third-party-integrations/algolia/algolia)
[Integrate Algolia](/docs/pbc/all/search/latest/base-shop/third-party-integrations/algolia/integrate-algolia.html)


### Technical prerequisites

[Install prerequisites and enable ACP](/docs/dg/dev/acp/install-prerequisites-and-enable-acp)



## Vertex Tax ID validator {% include badge.html type=&quot;feature&quot; %}

Simplify B2B invoicing and tax compliance checks with the updated Vertex ACP App. This release features direct, out-of-the-box integration of the Vertex Validator API into checkout. With Vertex Validator and Vertex ACP App, you can validate business tax IDs for syntax, validity, and location, reducing operational costs from incorrect invoices and ensuring accurate application of VAT.

### Business benefits

- Automated tax ID validation during checkout or any part of the process thanks to the headless integration
- Improved tax compliance through ID verification and accurate VAT application via company location data
- Decreased operational costs thanks to minimized invoicing errors
- Global validation in over 65 countries

### Docs

[Integrate Vertex Validator](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex-validator)

### Technical prerequisites

- [Install prerequisites and enable ACP](/docs/dg/dev/acp/install-prerequisites-and-enable-acp)
- [Install Vertex](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html)



## Multi-Factor Authentication {% include badge.html type=&quot;improvement&quot; %}

Multi-Factor Authentication (MFA) adds an additional layer of protection by requiring users to verify their identity through multiple methods, such as a password and a one-time code sent to their email.

![MFA-email-code](https://spryker.s3.eu-central-1.amazonaws.com/docs/About/all/releases/release-notes-202507.0.md/MFA-email-code.png)

### Key capabilities

- An additional authentication layer for Storefront, Back Office, Merchant Portal, and API endpoints
- Supports for custom authenticity validators, such as TOTP or Short Message
- Ensures that an email address is validated before a user signs up or updates their email address



### Business benefits


Improves the overall security of your project, as well as the security of each customer.


### Docs

[Multi-Factor Authentication](/docs/pbc/all/multi-factor-authentication/latest/multi-factor-authentication)








## SEO Sitemap {% include badge.html type=&quot;improvement&quot; %}

The Sitemap feature generates XML sitemaps that improve SEO by helping search engines efficiently index your Storefront content. Generated sitemaps include products, categories, product sets, CMS pages, and merchant pages by default. You can configure other entities to be included on the project level.

### Business benefits

Improved SEO

### Docs

- [Sitemap feature overview](/docs/pbc/all/miscellaneous/latest/sitemap-feature-overview)
- [Install the Sitemap feature](/docs/pbc/all/miscellaneous/latest/install-and-upgrade/install-features/install-the-sitemap-feature)








## Add to cart from images (AI-powered) {% include badge.html type=&quot;early-access&quot; %} {% include badge.html type=&quot;feature&quot; %}

This feature enables customers to add products to cart by uploading images on the Quick Order page.

Upload a PDF, image, photo of handwritten notes, or any other text mentioning products to add to cart. Based on the uploaded image, OpenAI detects matching products in your catalog and adds them to cart.

A single image can contain multiple products, and they both will be added to cart.

Customers need own OpenAI accounts to use this feature.

&lt;figure class=&quot;video_container&quot;&gt;
    &lt;video width=&quot;100%&quot; height=&quot;auto&quot; controls&gt;
    &lt;source src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/About/all/releases/release-notes-202507.0.md/AI_Visual_Add_To_Cart.mp4&quot; type=&quot;video/mp4&quot;&gt;
  &lt;/video&gt;
&lt;/figure&gt;

### Business benefits

- Enable more buying routes
- Reduce friction in transactions for power users








## Accessibility improvements {% include badge.html type=&quot;improvement&quot; %}


Accessibility ensures inclusive experiences for all users in Back Office and B2B Storefront, enhancing usability and helping customers in compliance with the 2025 EU Accessibility Act:

- Keyboard usage: Users with mobility impairments can navigate seamlessly without a mouse.
- Distinguishable colors: Users can easily read and interact with content, even if they have visual impairments or color blindness.

B2B Strorefront has a 100% Lighthouse score in Google Chrome:


![accessibility-improvement](https://spryker.s3.eu-central-1.amazonaws.com/docs/About/all/releases/release-notes-202507.0.md/B2B-SF-Accessibility.png)


### Business benefits

- Meeting regulatory requirements: reduced legal risks related to 2025 EU Accessibility Act
- Inclusive user experience: Improves usability for all users, including those with disabilities
- Broader market reach: Enables access for a wider audience, enhancing engagement and trust


### Docs

- [Install Back Office accessibility improvements](/docs/pbc/all/back-office/latest/base-shop/install-and-upgrade/install-back-office-accessibility-improvements)
- [Integrate accessibility improvements](/docs/dg/dev/integrate-and-configure/integrate-accessibility-improvements)





## Performance optimizations in cart and checkout {% include badge.html type=&quot;improvement&quot; %}

This release delivers major performance improvements to checkout, order placement, and large cart processing—ensuring a smooth and responsive experience during peak traffic and high order volumes:

### Key capabilities

- Smarter order reference generation: Introduces a new random string algorithm for Sales Order References, enabling high-speed, database lock-free order placement. This approach supports faster checkouts and seamless scaling during peak demand.
- Optimized support for large orders (50–100 items): key features, such as Cart, Checkout, Inventory, OMS, Discounts, Shipments, Product, and Merchant, have been fine-tuned to efficiently handle large orders. Internal benchmarks show up to 40% faster performance across Storefront, Glue API, and background OMS operations.
- Improved cart page performance: The dynamic cart page now renders up to twice as fast, delivering a more responsive and seamless customer experience.

### Business benefits

Smooth, efficient processing of large carts and orders, enhancing the checkout experience for both B2C and B2B customers.

### Docs

- [Unique random order reference generator](/docs/pbc/all/order-management-system/latest/base-shop/unique-random-order-reference-generator)
- To benefit from these improvements, make sure to update the recommended modules listed in [Performance Guidelines](/docs/dg/dev/guidelines/performance-guidelines/general-performance-guidelines.html#use-the-newest-modules)
- Cart page performance is now improved. The new configuration is described in the [Cart installation guide](/docs/pbc/all/cart-and-checkout/latest/base-shop/install-and-upgrade/install-features/install-the-cart-feature#set-up-configuration)



## Valkey key-value store {% include badge.html type=&quot;improvement&quot; %}

Spryker is migrating its cache solution from Redis to Valkey, a high-performance, open-source in-memory data store, supported by AWS ElasticCache. This integration significantly enhances data processing capabilities, offering improved speed, scalability, and security.

### Business benefits

- Accelerate performance: Leverage Valkey&apos;s advanced multi-threading for substantially higher throughput (up to 5x observed in tests for write operations) and more stable latencies, resulting in faster application response times, especially during peak traffic.
- Enhance scalability and reliability: Benefit from Valkey&apos;s superior scaling capabilities and improved cluster failover mechanisms, ensuring your platform can robustly handle business growth and larger, more complex workloads.
- Improve system efficiency: Utilize Valkey&apos;s optimized memory management for better resource utilization and overall system performance.
- Future-proof your infrastructure: Redis reached its end-of-life version, so migrating to Valkey ensures ongoing security updates, a clear BSD 3-clause licensing model, and strong, long-term support backed by the Linux Foundation and major industry players.


### Docs

[Use and configure Redis or Valkey as a key-value store](/docs/dg/dev/backend-development/client/use-and-configure-redis-or-valkey-as-a-key-value-store)



## Cache performance improvement: Data Compression {% include badge.html type=&quot;feature&quot; %}

Spryker is introducing seamless and efficient data compression in Valkey key-value store to enhance overall system performance and reduce latency. By minimizing the size of stored and transferred data without compromising speed, this feature optimizes data-intensive operations, leading to faster access times and more efficient use of network and storage resources. With intelligent compression levels tailored for performance, Spryker enables businesses to scale more effectively while maintaining rapid user experiences.

### Business benefits

- Enhanced performance: Transparent compression in Valkey boosts application responsiveness by reducing storage overhead
- Faster data transfer: Up to 50% reduction in data size leads to quicker transfers between database and Spryker applications
- Reduced latency: Improved data retrieval speeds from Valkey ensure smoother, low-latency experiences for end users
- Efficient compression: Uses fast compression algorithms that minimize text data without introducing performance overhead


### Docs

[Advanced configuration for Redis compression](/docs/dg/dev/set-up-spryker-locally/key-value-store-configuration#advanced-configuration-for-redis-compression)

### Technical prerequisites

[Use and configure Redis or Valkey as a key-value store](/docs/dg/dev/backend-development/client/use-and-configure-redis-or-valkey-as-a-key-value-store)






## Cloud self-service: Storage and access management {% include badge.html type=&quot;feature&quot; %}

Cloud Self Service is a new automated system for handling common customer support requests. This feature leverages internal tooling to process requests for IAM user creation, VPN and SSH access, and S3 bucket creation automatically, streamlining the support process and empowering customers with faster resolutions.

### Business benefits

- Reduce lead times: Speed up development and operational tasks by having common requests fulfilled faster
- Enhance request quality and consistency: Automated processing minimizes human error, ensuring that requests are handled accurately and consistently every time








## Cloud security improvements {% include badge.html type=&quot;improvement&quot; %}

This release introduces both internal and customer-facing enhancements, including Multi-Factor Authentication (MFA) and improved password policy, now enabled by default for all new and existing cloud users. All IAM users are now required to activate MFA and use more complex passwords by default. These measures significantly reduce the risk of credential exposure and prevent unauthorized access to your cloud environments.

### Business benefits

- Enhanced account security: Multi-Factor authentication and stronger password policies safeguard your cloud environments against unauthorized access and credential misuse
- Security best practices by default: Pre-configured security settings ensure a strong baseline without additional setup, making it easier to maintain a secure and resilient cloud setup


### Docs

[Multi-factor authentication and passwords](/docs/ca/dev/security/multi-factor-authentication-and-passwords)






## Stable Workers {% include badge.html type=&quot;early-access&quot; %}


Introducing a significant enhancement to Publish and Synchronize (P&amp;S) focused on increasing its job processing stability. While Jenkins continues to manage non-P&amp;S tasks, P&amp;S now uses a new Stable Worker Architecture.

This redesign addresses stability challenges from its previous Jenkins-based execution, ensuring more reliable data synchronization (products, prices, assets), especially for large catalogs and frequent updates.

The new architecture provides isolated worker contexts, automatic retries, and better error handling for a more robust P&amp;S operation.


### Docs

[Stable Workers](/docs/dg/dev/backend-development/cronjobs/stable-workers)



### Business benefits

- Improved P&amp;S performance and stability: Faster, more stable catalog data refreshes and timely frontend updates
- Better handling of complex scenarios: Efficiently manage large, frequently updated catalogs
- Reduced operational disruptions: Minimized downtime and manual P&amp;S interventions due to enhanced resilience
- Enhanced logging: Better visibility for logs (CloudWatch) for quicker resolution of P&amp;S issues





## Support for GitHub Enterprise {% include badge.html type=&quot;feature&quot; %}

Spryker now offers native integration for GitHub Enterprise Server (GHES). This enhancement lets you directly connect your self-hosted GHES repositories with the Spryker platform, eliminating the previous requirement to mirror repositories.

### Business benefits

- Simple, direct integration: Directly connect your GitHub Enterprise Server, removing the complexity and overhead of mirroring repositories
- Streamlined workflows: Improved development and deployment workflows through a direct, native connection to your GHES infrastructure
- Reduced operational overhead: Eliminate the need for maintaining and managing repository mirroring processes





## Improved autoscaling {% include badge.html type=&quot;improvement&quot; %}

Spryker Cloud Autoscaling has been enhanced with a faster reaction to traffic spikes. The measured improvement is up to five times faster to scale out from the time an event is observed. Aggressive scale out and scale-in better address temporary traffic surges–for example, during sales events–and improve the reliability of your shop.

The improvements are already implemented with no action required from you.

### Business benefits

- Improved reliability: Services scale five times faster
- Improved end-user experience: No increase in request latency for users




































































</description>
            <pubDate>Mon, 16 Mar 2026 08:55:32 +0000</pubDate>
            <link>https://docs.spryker.com/docs/about/all/releases/release-notes-202507.0.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/about/all/releases/release-notes-202507.0.html</guid>
            
            
        </item>
        
        <item>
            <title>Release notes 202311.0</title>
            <description>The Spryker Commerce OS is an end-to-end solution for digital commerce. This document contains a business-level description of new features and enhancements.

For information about installing the Spryker Commerce OS, see [Getting started guide](/docs/dg/dev/development-getting-started-guide.html).

## &lt;span class=&quot;inline-img&quot;&gt;![core-commerce](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/icon_Spryker+Commerce+OS_128.png)&lt;/span&gt; Fulfillment App {% include badge.html type=&quot;feature&quot; %}

As part of Spryker&apos;s Unified Commerce capability, the Fulfillment App provides an all-new user interface designed to streamline your order fulfillment process. Supporting new business models and with enhanced functionalities, the Fulfillment App simplifies tasks for warehouse and store staff, offering an efficient and effective fulfillment process.

The fulfillment App includes the following features:

- New picking list concept: Compatible with many picking strategies to increase order fulfillment efficiency.
- Warehouse allocation strategy: Optimize warehouse space utilization for your specific warehouse setup.
- Offline mode: Ensure uninterrupted picking, even without an internet connection.
- Backend API architecture: Better performance and improved scalability.
- Powered by Spryker&apos;s Oryx Framework: Make rapid frontend customizations by utilizing a rich library of components.

**Business benefits**:
- Fulfill orders faster, easier, and smarter.
- Rapidly customize and scale with a flexibly built app.

### Documentation

[Fulfillment App overview](/docs/pbc/all/warehouse-management-system/latest/unified-commerce/fulfillment-app-overview.html)


## &lt;span class=&quot;inline-img&quot;&gt;![core-commerce](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/icon_Spryker+Commerce+OS_128.png)&lt;/span&gt; Click&amp;Collect {% include badge.html type=&quot;feature&quot; %}

With Enhanced Click&amp;Collect, your customers now have the flexibility to choose between delivery and pickup during checkout, enhancing their shopping experience. Store operators also benefit from advanced configuration capabilities for their in-store stock.

Click&amp;Collect includes the following features:

- Service points: Service points broaden the scope of services you can offer at your physical locations beyond order collection. Its adaptable framework simplifies implementing features such as return services and appointment scheduling, allowing businesses to tailor solutions to their specific needs.
- Integrated shipment types at checkout: Provide your customers with the flexibility to choose between delivery and pickup during checkout. With the flexible architecture of the Enhanced Click&amp;Collect, you can create custom shipment types, like &quot;Ship-from-Store&quot;, on the project level.
- Works seamlessly with multi-address checkout: Lets your customers divide their orders for different delivery methods. For example, they can have some items delivered to their doorstep while they pick up other items at a location they select.
- Merchant Portal integration: As a store operator, you can now do the following:
  - Specify product availability based on different service points: physical retail outlets, warehouses, or any other pickup location.
  - Adjust stock availability for each service point.
  - Offer varied pricing for items based on their pickup or delivery location.


![click-and-collect-demo](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/release-notes-202311.0/click-and-collect.gif)

**Business benefits**:&lt;br&gt;
Enhanced Click&amp;Collect facilitates immediate product availability, offering both B2B and B2C clients the convenience of bypassing wait times associated with shipping. This feature not only significantly reduces or eliminates shipping costs but also provides an opportunity for immediate product inspection, ensuring quality and specifications meet the client&apos;s standards. Moreover, it seamlessly blends the digital shopping experience with the tangible benefits of a physical store, fostering direct customer-business interactions and potentially driving additional in-store purchases.

While pickup has its roots in B2C operations, its utility in B2B contexts is growing:
- Automotive industry: Manufacturers and dealers can offer customers the convenience of ordering parts online with the option for on-site installation.
- Manufacturing sector: Streamline operations by letting clients directly retrieve bulk orders from warehouses, enhancing the efficiency of the procurement process.

### Documentation

[Service point management](/docs/pbc/all/service-point-management/latest/service-point-management.html)

## &lt;span class=&quot;inline-img&quot;&gt;![data](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/data.png)&lt;/span&gt; Data Exchange API {% include badge.html type=&quot;feature&quot; %}

Traditionally, developing APIs required technical expertise and time-consuming coding processes. However, with the new Spryker dynamic Data Exchange API infrastructure, we have removed the complexities, making it seamless for you to create APIs effortlessly. With this tool, you can quickly build, customize, and manage APIs tailored to your specific business requirements, all through an intuitive user interface.

The key features of the Data Exchange API include the following:

- No coding required: No complex coding and development efforts are needed. The user-friendly interface enables you to create APIs effortlessly.

- Rapid API generation: The streamlined process lets you generate APIs in a matter of minutes. This helps you speed up your integration projects and get your applications up and running faster than before.

- Flexibility and customization: You can tailor your API endpoints to your exact needs. You can define parameters, which allows for seamless compatibility with your systems.

- Real-time updates: You can modify your API endpoints on the go. Our infrastructure allows you to make changes dynamically so you can adapt to evolving business needs without any downtime.


**Business benefits**:
- Reduce time-to-market, speeding up faster integration
- Cost savings, especially on maintenance

### Documentation

- [Data Exchange API](/docs/pbc/all/data-exchange/{{site.version}}/data-exchange.html)

### Technical prerequisites

- [Install the Data Exchange API](/docs/pbc/all/data-exchange/latest/install-and-upgrade/install-the-data-exchange-api.html)
[Install the Data Exchange API + Inventory Management feature](/docs/pbc/all/data-exchange/latest/install-and-upgrade/install-the-data-exchange-api-inventory-management-feature.html)

## &lt;span class=&quot;inline-img&quot;&gt;![data](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/data.png)&lt;/span&gt; Next Generation Middleware: Spryker Middleware powered by Alumio {% include badge.html type=&quot;feature&quot; %}

The Spryker Middleware powered by Alumio solves the main challenges of data integrations in a flexible and customizable way and, therefore, greatly reduces the efforts for Spryker&apos;s data exchange use cases. It is the foundation on which we build our Integration Apps. The Spryker Middleware powered by Alumio uses Alumio data integration technology.

The Spryker Middleware powered by Alumio helps you to reach the following outcomes:

- Lower the total cost of ownership, centralizing the management of data flows.
- Lower return rate with more comprehensive &amp; accurate product information.
- Gain higher customer satisfaction by keeping consistent and up-to-date data across all touchpoints.
- Gain higher conversion rate by reacting to customer demands and competitive challenges more quickly.

**Business benefit**:&lt;br&gt;
Faster time-to-value shortening setup times for integrations


### Technical prerequisites

To connect Spryker Middleware powered by Alumio with Spryker Cloud Commerce OS, you need to install or deploy the [Data Exchange API feature](/docs/pbc/all/data-exchange/latest/install-and-upgrade/install-the-data-exchange-api.html) in your environment.


## &lt;span class=&quot;inline-img&quot;&gt;![data](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/data.png)&lt;/span&gt; Akeneo PIM Integration App {% include badge.html type=&quot;feature&quot; %}

Our Akeneo PIM Integration App simplifies the management of your product information by providing an out-of-the-box and highly flexible integration with the popular Akeneo PIM system. This saves you time and effort, allowing you to seamlessly manage your product information across all channels, resulting in a more efficient and effective sales process.

The Spryker Akeneo PIM Integration App allows you to do the following:
- Reduce time to market and set up a product data synchronization feed between Spryker and Akeneo PIM without any coding.
- Easily adapt to any changes in your data model with intuitive, visual data mapping capabilities.
- Increase the reliability of your data flow between Spryker and Akeneo PIM with buffering, retries, and extensive troubleshooting capabilities.


**Business benefit**:&lt;br&gt;
Reduce time-to-market with a flexible integration to Akeneo PIM, keeping new product information synchronized at the rhythm your business demands.


### Technical prerequisites

- To use your Akeneo PIM Integration App, you need to have the Spryker Middleware powered by Alumio.
- The Akeneo PIM Integration App works with B2C or B2B business models of Spryker Cloud Commerce. Currently, it doesn&apos;t cover the Marketplace business models.

## &lt;span class=&quot;inline-img&quot;&gt;![cloud](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/icon_Spryker+Cloud_128.png)&lt;/span&gt; Log forwarding and metric streaming to Dynatrace {% include badge.html type=&quot;feature&quot; %}


{% info_block warningBox &quot;Improved version of Dynatrace&quot; %}

We&apos;re going to release a refactored version of the Dynatrace integration. This version will be more robust and future-proof. For most projects, we recommend waiting for the new version.

{% endinfo_block %}

We are delighted to announce our newest integration - Dynatrace with Log Forwarding and Metrics Streaming from Spryker PaaS+! This integration is a key step in our journey to support more monitoring platforms compatible with Open Telemetry.

This integration significantly enhances our current monitoring capabilities by extending the coverage of metrics and logs across crucial services such as Amazon ECS, RDS, OpenSearch Service, ElastiCache (Redis), PHP Exceptions, and RabbitMQ. Previously, the scope of these services was more limited, but with this enhancement, a broader and more precise range of metrics for tracking, debugging, and optimization is achieved. These monitoring improvements will also be available in New Relic and CloudWatch at no additional cost.

This feature is ideal for customer DevOps/SREs seeking enhanced, flexible monitoring solutions.

**Business benefits**:&lt;br&gt;
Until now, New Relic was the sole option for aggregating logs and metrics. This integration offers customers the flexibility to connect and integrate their Dynatrace account to Spryker PaaS+, thus enhancing observability and cloud extensibility.

Key features of this integration include the following:

- Log forwarding: Facilitates forwarding of logs from Spryker Cloud services to Dynatrace, covering services like Amazon RDS, ECS, Redis, RabbitMQ, and OpenSearch.
- Metric streaming: Streams performance metrics like CPU usage, memory, network latency, and error rates to Dynatrace, offering real-time insights.
- Unified Observability Platform: Offers a centralized platform for all monitoring needs, compatible with various third-party platforms.
- Efficient data processing: Ensures immediate forwarding of logs and metrics, with frequent data transmission for up-to-date monitoring.
- Spryker support 24/7: Designed to work seamlessly with existing monitoring solutions, Spryker will keep watching over for you 24/7, regardless of the monitoring platform you use.
- Scalability and adaptability: Can handle varying data volumes and peaks, with 24 hours of retention in case of unavailability.

### Technical prerequisites

- Only available for Spryker Cloud customers.
- You need a self-managed Dynatrace account, and you have to provide the necessary Endpoints to Spryker.

## &lt;span class=&quot;inline-img&quot;&gt;![acp](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/icon_App+Orchestration+Platform_128.png)&lt;/span&gt; Improved performance, stability, and scalability {% include badge.html type=&quot;improvement&quot; %}

Adding third-party integrations via apps to your existing SCCOS solution has become easier with the App Composition Platform (ACP). Get in touch with us to get ACP enabled faster and take advantage of ACP&apos;s steadily growing number of no and low-code apps.

**Business benefit**:&lt;br&gt;
Simplified and faster enablement of ACP for SCCOS, as well as improved scalability, performance, and data security of the entire platform.

### Documentation

[ACP overview](/docs/acp/user/intro-to-acp/acp-overview.html)

### Technical prerequisites

[Install the ACP catalog](/docs/dg/dev/acp/app-composition-platform-installation.html)

## &lt;span class=&quot;inline-img&quot;&gt;![acp](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/icon_App+Orchestration+Platform_128.png)&lt;/span&gt; Vertex app {% include badge.html type=&quot;feature&quot; %}

Staying up-to-date with ever-changing tax rules and rates can require a lot of resources. Spryker, through the Vertex integration, offers a means for businesses to automate tax calculation and centralize sales taxes on their transactions.

**Business benefits**:
- Comply with tax frameworks anywhere you do business. Let Vertex take care of tax management with a seamless and easy-to-use solution that meets the needs across Tax, IT, and Finance teams.
- Free up valuable resources for other operations as it stays compliant and up to date with the tax regulations of your markets.
- Automate tax processes and improve business agility by easily validating business tax at check-out and issuing tax-compliant invoices at the point of sale.

### Documentation

[Vertex](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/vertex.html)

### Technical prerequisites

- [Install ACP](/docs/acp/user/app-composition-platform-installation.html)
- [Install Vertex](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html)

## &lt;span class=&quot;inline-img&quot;&gt;![acp](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/icon_App+Orchestration+Platform_128.png)&lt;/span&gt; Algolia app {% include badge.html type=&quot;improvement&quot; %}

Build an efficient path to purchase for your buyers with Algolia search, an innovative search and navigation solution that empowers your customers to quickly find the products they want. With our powerful and flexible implementation, headless or with search components on your storefront, you can easily integrate search capabilities into your storefront, streamlining the customer journey and increasing conversions.

**Business benefits**:
- Easily bring search into your storefront with our implementation, headless or with frontend search components, and enable customers to get to what matters faster.
- With the latest feature addition, you can now use the search components to display Algolia search results and support your users with search suggestions.

### Documentation

[Algolia](/docs/pbc/all/search/latest/base-shop/third-party-integrations/algolia/algolia.html)

### Technical prerequisites

[Integrate Algolia](/docs/pbc/all/search/latest/base-shop/third-party-integrations/algolia/integrate-algolia.html)

## &lt;span class=&quot;inline-img&quot;&gt;![code-upgrader](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/code-upgrader.png)&lt;/span&gt; Autointegration of code releases {% include badge.html type=&quot;improvement&quot; %}

In addition to updating Spryker packages in your repository, with this release, Spryker Code Upgrader starts integrating plugins, settinh configurations keys, and adding new translations and similar elements to your project code. Now engineers don&apos;t have to figure out and manually apply code changes to activate new features.

**Business benefit**:&lt;br&gt;
Reduce the engineering time needed to integrate a Spryker module release into your project.

### Documentation

[Integrating code releases](/docs/ca/devscu/integrating-code-releases/integrating-code-releases.html)

### Technical prerequisites

Connect to [Spryker Code Upgrader](/docs/ca/devscu/spryker-code-upgrader.html) service to receive security updates semi-automatically.

## &lt;span class=&quot;inline-img&quot;&gt;![code-upgrader](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/code-upgrader.png)&lt;/span&gt; Security upgrades {% include badge.html type=&quot;improvement&quot; %}

Receive security releases before any other releases offered by Spryker Code Upgrader. The Upgrader prioritizes security releases, ensuring a timely application of critical security fixes.


**Business benefit**:&lt;br&gt;
Reduce the security risks from running outdated software by taking security updates before other updates.

### Documentation

[Integrating security releases](/docs/ca/devscu/integrating-code-releases/integrating-security-releases.html)

### Technical prerequisites

Connect to [Spryker Code Upgrader](/docs/ca/devscu/spryker-code-upgrader.html) service to receive security updates semi-automatically.

## &lt;span class=&quot;inline-img&quot;&gt;![code-upgrader](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/code-upgrader.png)&lt;/span&gt; Upgradability Evaluator improvements {% include badge.html type=&quot;improvement&quot; %}

This update offers notifications about critical security issues and vulnerabilities in Spryker and third-party components based on known vulnerability databases from NPM and Composer ecosystems. These improvements enhance the security monitoring and upgrade process. This update is complementary to the [Security Upgrades] improvement for Spryker Code Upgrader, but addresses all Spryker users.

**Business benefit**:&lt;br&gt;
Better awareness of security issues and vulnerabilities.

### Documentation

- [Handling upgrade warnings](/docs/ca/devscu/integrating-code-releases/handling-upgrade-warnings.html)
- [Spryker security checker](/docs/dg/dev/guidelines/keeping-a-project-upgradable/upgradability-guidelines/spryker-security-checker.html)
- [NPM checker](/docs/dg/dev/guidelines/keeping-a-project-upgradable/upgradability-guidelines/npm-checker.html)
- [Open-source vulnerabilities checker](/docs/dg/dev/guidelines/keeping-a-project-upgradable/upgradability-guidelines/open-source-vulnerabilities.html)

### Technical prerequisites

Install and run [Upgrader compliance Evaluator](/docs/dg/dev/guidelines/keeping-a-project-upgradable/run-the-evaluator-tool.html) to detect security issues.

## &lt;span class=&quot;inline-img&quot;&gt;![composable-frontend](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/icon_Composable+Storefront_128.png)&lt;/span&gt; Oryx Framework {% include badge.html type=&quot;improvement&quot; %}

Oryx Framework empowers developers to efficiently build composable frontends. Oryx provides a rich library of Oryx components, including a design system, allowing developers to rapidly create modern and visually appealing user interfaces. These components integrate with Spryker APIs by default, providing a seamless, decoupled experience for developers and end consumers.

**Business benefit**:&lt;br&gt;
Save time and effort with Oryx Framework. Spryker&apos;s purpose-built framework lets developers utilize fast, lightweight, and reactive components for storefronts and other frontends that quickly and dynamically display various devices.

### Learn more

[Oryx in 90 seconds videos](https://www.youtube.com/playlist?list=PLJooqCSo73Sj9r_632NRtr-O0zuY7eHPb)

### Documentation

[Oryx](/docs/dg/dev/frontend-development/latest/oryx/oryx.html)

### Technical prerequisites

Oryx can be installed on your local machine and requires a Node.js or a compatible Javascript runtime and an npm runtime. For installation instructions, see [Set up Oryx](/docs/dg/dev/frontend-development/latest/oryx/getting-started/set-up-oryx.html).

## &lt;span class=&quot;inline-img&quot;&gt;![composable-frontend](https://spryker.s3.eu-central-1.amazonaws.com/docs/scos/user/intro-to-spryker/releases/release-notes/icon_Composable+Storefront_128.png)&lt;/span&gt; Composable Storefront: Additional foundation features - EA (early access) {% include badge.html type=&quot;improvement&quot; %}

Additional features are being released for Spryker&apos;s new upgradeable, decoupled frontend solution — Composable Storefront. This set of features provides essential components for commonplace purchase journeys. Spryker Composable Storefront is built using Spryker&apos;s Oryx framework, a reactive, fast, and lightweight framework.

For more information about this Early Access product, contact your Spryker representative.

**Business benefit**:&lt;br&gt;
Provides commonplace features out-of-the-box for future-proof, agile, scalable, and upgradeable solutions for digital commerce business models.

### Learn more

Composable Storefront is part of the Oryx framework. Oryx provides the features, and the presets for the various applications that you can create with Oryx, such as a Composable Storefront or Fulfillment App.

### Documentation

[Oryx](/docs/dg/dev/frontend-development/latest/oryx/oryx.html)

### Technical prerequisites

Oryx can be installed on your local machine and requires a Node.js or a compatible Javascript runtime and an npm runtime. See Set up Oryx for more information on the installation.
</description>
            <pubDate>Mon, 16 Mar 2026 08:55:32 +0000</pubDate>
            <link>https://docs.spryker.com/docs/about/all/releases/release-notes-202311.0.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/about/all/releases/release-notes-202311.0.html</guid>
            
            
        </item>
        
        <item>
            <title>Project configuration for Vertex</title>
            <description>This document describes the project configuration to consider when using Vertex for tax calculation.

## Adding country-specific fields to the address form

Make sure that, on the Storefront, the address form has the required fields for each country. For example, the US store should have the **State** field, and the CA store should have the **Province** field.

## Sending additional data to Vertex

By default, the following data is sent to Vertex for tax calculation:

- Customer Shipping address
- Product SKU
- Shipping(delivery) method key
- Warehouse address that also includes the Merchant warehouse address for a Marketplace model
- Product SKUs
- Product prices
- Discounts
- Shipping costs

You can send additional data to Vertex, like a Customer Exemption Certificate, using plugins and the `taxMetadata` fields. You can add more data to request any specific information that&apos;s not available in Spryker by default. For example, this could be data from ERP, other systems, and customized Spryker instances. For the implementation details, see [Configure Vertex-specific metadata](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/configure-vertex-specific-metadata.html#2-implement-vertex-specific-metadata-extender-plugins).

## Additional configuration options for Vertex

- You can configure the Vertex app for invoices to be saved in Vertex. However, we recommend to send invoice requests only for paid orders, as specified in [Integrate Vertex](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html#8-optional-sending-tax-invoices-to-vertex-and-handling-refunds). The current implementation works asynchronously, so no response is saved in Spryker.

- The default Spryker functionality uses tax rates to manage taxes. When using Vertex for tax determination, Vertex doesn&apos;t provide any tax rates to Spryker. To avoid confusion, we recommend removing the default Spryker tax rates. In the Back Office, you can delete them in **Administration** &gt; **Tax Rates**.

## Logging and tracking Vertex issues

If the Vertex app is down or taxes can&apos;t be calculated for other reasons, taxes are displayed as 0, letting customers place orders. For some orders, taxes might actually be 0, so there is no way to identify if there is an issue with tax calculation. In future, there will be a flag to identify and track these issues.


## Next steps

[Verify Vertex connection](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/verify-vertex-connection.html)








































</description>
            <pubDate>Mon, 16 Mar 2026 08:55:32 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/project-configuration-for-vertex.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/project-configuration-for-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

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 |
|----------|-------------|
| `IS_ACTIVE` | Enables or disables Vertex tax calculation. |
| `CLIENT_ID` | OAuth client ID for the Vertex API. |
| `CLIENT_SECRET` | OAuth client secret for the Vertex API. |
| `SECURITY_URI` | Vertex OAuth security endpoint. |
| `TRANSACTION_CALLS_URI` | Vertex transaction calls endpoint. |

### Optional configuration constants

| Constant | Description                                                                                                                                |
|----------|--------------------------------------------------------------------------------------------------------------------------------------------|
| `TAXAMO_API_URL` | Vertex Validator API URL for tax ID validation. [Details](https://developer.vertexinc.com/vertex-e-commerce/docs/stand-alone-deployments). |
| `TAXAMO_TOKEN` | Vertex Validator API authentication token.                                                                                                 |
| `VENDOR_CODE` | Vendor code for Vertex tax calculations.                                                                                                   |
| `DEFAULT_TAXPAYER_COMPANY_CODE` | Default taxpayer company code.                                                                                                             |

## 3. Override feature flags

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(): bool
    {
        return true;
    }

    public function isInvoicingEnabled(): 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. 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(),
    ];
}
```

## 7. 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 %}
```

## 8. 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 step

[Configure Vertex-specific metadata](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/configure-vertex-specific-metadata.html)</description>
            <pubDate>Mon, 16 Mar 2026 08:55:32 +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. 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>Mon, 16 Mar 2026 08:55:32 +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-specific metadata</title>
            <description>&lt;p&gt;After you have &lt;a href=&quot;/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html&quot;&gt;integrated Vertex module&lt;/a&gt; for tax calculation, you can Configure Vertex-specific metadata.&lt;/p&gt;
&lt;p&gt;Spryker doesn’t have the same data model as Vertex, which is necessary for accurate tax calculations. Therefore, the integration requires project developers to add some missing information to the Quote object before sending a calculation request.&lt;/p&gt;
&lt;p&gt;The following diagram shows the data flow of the tax calculation request from the Spryker Cart to the Vertex API.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/pbc/all/tax-management/vertex/install-vertex/vertex-tax-calculation-requests.png&quot; alt=&quot;tax-calculation-request&quot; /&gt;&lt;/p&gt;
&lt;p&gt;To integrate Vertex, follow these steps.&lt;/p&gt;
&lt;h2 id=&quot;configure-vertex-specific-metadata-transfers&quot;&gt;1. Configure Vertex-specific metadata transfers&lt;/h2&gt;
&lt;p&gt;Define specific Vertex Tax metadata transfers and extend other transfers with them:&lt;/p&gt;
&lt;div class=&quot;language-xml 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;?xml version=&quot;1.0&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;transfers&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;spryker:transfer-01&quot;&lt;/span&gt;
           &lt;span class=&quot;na&quot;&gt;xmlns:xsi=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;
           &lt;span class=&quot;na&quot;&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;spryker:transfer-01
    http://static.spryker.com/transfer-01.xsd&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Calculable Object is extended with SaleTaxMetadata --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;transfer&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;CalculableObject&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;property&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;taxMetadata&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;SaleTaxMetadata&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;strict=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/transfer&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Order is extended with SaleTaxMetadata --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;transfer&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Order&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;property&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;taxMetadata&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;SaleTaxMetadata&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;strict=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/transfer&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Expense is extended with ItemTaxMetadata --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;transfer&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Expense&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;property&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;taxMetadata&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ItemTaxMetadata&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;strict=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/transfer&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Item is extended with ItemTaxMetadata --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;transfer&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Item&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;property&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;taxMetadata&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ItemTaxMetadata&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;strict=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/transfer&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Product Option is extended with ItemTaxMetadata --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;transfer&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ProductOption&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;property&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;taxMetadata&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ItemTaxMetadata&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;strict=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/transfer&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Sales Tax Metadata. It contains Vertex tax metadata which is related to Order or Quote in general. --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;transfer&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;SaleTaxMetadata&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;strict=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;property&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;seller&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;array&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;associative=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;singular=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;property&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;customer&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;array&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;associative=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;singular=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/transfer&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Items Tax Metadata. It contains Vertex tax metadata which is related to Item.--&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;transfer&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ItemTaxMetadata&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;strict=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;property&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;product&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;array&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;associative=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;singular=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;property&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;flexibleFields&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;array&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;associative=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;singular=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/transfer&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;/transfers&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;SaleTaxMetadata&lt;/code&gt; and &lt;code&gt;ItemTaxMetadata&lt;/code&gt; are designed to be equal to the Vertex Tax Calculation API request body. You can extend them as you need, following the Vertex API structure.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SaleTaxMetadata&lt;/code&gt; equals the Invoicing/Quotation request payload, excluding LineItems.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ItemTaxMetadata&lt;/code&gt; equals the Line Item API payload.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;implement-vertex-specific-metadata-extender-plugins&quot;&gt;2. Implement Vertex-specific metadata extender plugins&lt;/h2&gt;
&lt;p&gt;You need to introduce several types of expander plugins. As a starting point, you use the examples provided the module. The plugins in this module are for development purposes. The data in the &lt;code&gt;TaxMetaData&lt;/code&gt; fields needs to be collected from the project database or other sources, like an external ERP.&lt;/p&gt;
&lt;h3 id=&quot;configure-the-customer-class-code-expander-plugins&quot;&gt;Configure the Customer Class Code Expander plugins&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Introduce &lt;code&gt;Pyz/Zed/{YourDesiredModule}/Communication/Plugin/Order/OrderCustomerWithVertexCodeExpanderPlugin.php&lt;/code&gt; using the following example:&lt;/li&gt;
&lt;/ol&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&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;YourDesiredModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Communication\Plugin\Order&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;Generated\Shared\Transfer\OrderTransfer&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\Kernel\Communication\AbstractPlugin&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\Dependency\Plugin\OrderVertexExpanderPluginInterface&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;OrderCustomerWithVertexCodeExpanderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderVertexExpanderPluginInterface&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * @param \Generated\Shared\Transfer\OrderTransfer $orderTransfer
     *
     * @return \Generated\Shared\Transfer\OrderTransfer
     */&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;expand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;OrderTransfer&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$orderTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;OrderTransfer&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$orderTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getTaxMetadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;customerCode&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;classCode&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;vertex-customer-code&apos;&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;nv&quot;&gt;$orderTransfer&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;ol start=&quot;2&quot;&gt;
&lt;li&gt;Introduce &lt;code&gt;Pyz/Zed/{YourDesiredModule}/Communication/Plugin/Quote/CalculableObjectCustomerWithVertexCodeExpanderPlugin.php&lt;/code&gt; using the following example:&lt;/li&gt;
&lt;/ol&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;Spryker\Zed&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;YourDesiredModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Communication\Plugin\Quote&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;Generated\Shared\Transfer\CalculableObjectTransfer&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\Kernel\Communication\AbstractPlugin&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\Dependency\Plugin\CalculableObjectVertexExpanderPluginInterface&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;CalculableObjectCustomerWithVertexCodeExpanderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CalculableObjectVertexExpanderPluginInterface&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * @param \Generated\Shared\Transfer\CalculableObjectTransfer $calculableObjectTransfer
     *
     * @return \Generated\Shared\Transfer\CalculableObjectTransfer
     */&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;expand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;CalculableObjectTransfer&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$calculableObjectTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CalculableObjectTransfer&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$calculableObjectTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getTaxMetadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;customerCode&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;classCode&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;vertex-customer-code&apos;&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;nv&quot;&gt;$calculableObjectTransfer&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;h3 id=&quot;configure-the-customer-exemption-certificate-expander-plugins&quot;&gt;Configure the Customer Exemption Certificate Expander plugins&lt;/h3&gt;
&lt;p&gt;Configure the following plugins using the provided example.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PLUGIN&lt;/th&gt;
&lt;th&gt;NAMESPACE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Customer Exemption Certificate Expander plugin for order&lt;/td&gt;
&lt;td&gt;Pyz/Zed/{YourDesiredModule}/Communication/Plugin/Order/OrderCustomerWithVertexExemptionCertificateExpanderPlugin.php&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customer Exemption Certificate Expander plugin for quote&lt;/td&gt;
&lt;td&gt;Pyz/Zed/{YourDesiredModule}/Communication/Plugin/Quote/CalculableObjectCustomerWithVertexExemptionCertificateExpanderPlugin.php&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderCustomerWithVertexExemptionCertificateExpanderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CalculableObjectVertexExpanderPluginInterface&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * @param \Generated\Shared\Transfer\CalculableObjectTransfer $calculableObjectTransfer
     *
     * @return \Generated\Shared\Transfer\CalculableObjectTransfer
     */&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;expand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;CalculableObjectTransfer&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$calculableObjectTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CalculableObjectTransfer&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$calculableObjectTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getTaxMetadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;exemptionCertificate&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;exemptionCertificateNumber&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;vertex-exemption-certificate-number&apos;&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;nv&quot;&gt;$calculableObjectTransfer&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;h3 id=&quot;configure-the-product-class-code-expander-plugins&quot;&gt;Configure the Product Class Code Expander plugins&lt;/h3&gt;
&lt;p&gt;Configure the following plugins using the provided example.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PLUGIN&lt;/th&gt;
&lt;th&gt;NAMESPACE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Product Class Code Expander plugin for order items&lt;/td&gt;
&lt;td&gt;Pyz/Zed/{YourDesiredModule}/Communication/Plugin/Order/OrderItemVertexProductClassCodeExpanderPlugin.php`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Product Class Code Expander plugin for quote items&lt;/td&gt;
&lt;td&gt;Pyz/Zed/{YourDesiredModule}/Communication/Plugin/Quote/CalculableObjectItemWithVertexProductClassCodeExpanderPlugin.php&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ItemWithVertexClassCodeExpanderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CalculableObjectVertexExpanderPluginInterface&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * @param \Generated\Shared\Transfer\CalculableObjectTransfer $calculableObjectTransfer
     *
     * @return \Generated\Shared\Transfer\CalculableObjectTransfer
     */&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;expand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;CalculableObjectTransfer&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$calculableObjectTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CalculableObjectTransfer&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$calculableObjectTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getItems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$itemTransfer&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;nv&quot;&gt;$itemTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getTaxMetadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setProduct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;productClass&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;vertex-product-class-code&apos;&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$calculableObjectTransfer&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;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;Use the same Product Class Code&lt;/div&gt;
&lt;p&gt;You must use the same Product Class Code extension for all product options and other order expenses. Vertex considers each of them as a separate item for tax calculation. For guidance on where to place them, see the definition of transfers in &lt;a href=&quot;#configure-vertex-specific-metadata-transfers&quot;&gt;Configure Vertex-specific Metadata Transfers&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;h3 id=&quot;configure-the-flexible-fields-extension&quot;&gt;Configure the flexible fields extension&lt;/h3&gt;
&lt;p&gt;Configure the flexible files extension using the following example:&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;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ItemWithFlexibleFieldsExpanderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CalculableObjectVertexExpanderPluginInterface&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * @param \CalculableObjectTransfer $calculableObjectTransfer
     *
     * @return \CalculableObjectTransfer
     */&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;expand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;CalculableObjectTransfer&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$calculableObjectTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CalculableObjectTransfer&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$calculableObjectTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getItems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$itemTransfer&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;nv&quot;&gt;$itemTransfer&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getTaxMetadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setFlexibleFields&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;s1&quot;&gt;&apos;flexibleCodeFields&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;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;s1&quot;&gt;&apos;fieldId&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                &lt;span class=&quot;s1&quot;&gt;&apos;value&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;vertex-flexible-code-value&apos;&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;span class=&quot;p&quot;&gt;);&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;nv&quot;&gt;$calculableObjectTransfer&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;configure-the-vertex-dependency-provider&quot;&gt;3. Configure the Vertex dependency provider&lt;/h2&gt;
&lt;p&gt;After the Vertex dependency provider configuration, the plugin stack should look similar to the following:&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;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Zed\Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// The following plugins are for Marketplace only.&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spryker\Zed\MerchantProfile\Communication\Plugin\TaxApp\MerchantProfileAddressCalculableObjectTaxAppExpanderPlugin&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\MerchantProfile\Communication\Plugin\TaxApp\MerchantProfileAddressOrderTaxAppExpanderPlugin&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\ProductOfferAvailability\Communication\Plugin\TaxApp\ProductOfferAvailabilityCalculableObjectTaxAppExpanderPlugin&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\ProductOfferAvailability\Communication\Plugin\TaxApp\ProductOfferAvailabilityOrderTaxAppExpanderPlugin&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;VertexDependencyProvider&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerTaxAppDependencyProvider&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * @return array&amp;lt;\SprykerEco\Zed\Vertex\Dependency\Plugin\CalculableObjectVertexExpanderPluginInterface|\Spryker\Zed\TaxAppExtension\Dependency\Plugin\CalculableObjectTaxAppExpanderPluginInterface&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;getCalculableObjectVertexExpanderPlugins&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;# This plugin stack is responsible for expansion of CalculableObjectTransfer based on present fields. Add your custom implemented expander plugins here following the example in `spryker-eco/vertex` module.&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;// The following plugins are for Marketplace only.&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# This plugin is expanding CalculableObjectTransfer object with merchant address information.&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MerchantProfileAddressCalculableObjectTaxAppExpanderPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# This plugin is expanding CalculableObjectTransfer object with product offer availability information.&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProductOfferAvailabilityCalculableObjectTaxAppExpanderPlugin&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;cd&quot;&gt;/**
     * @return array&amp;lt;\SprykerEco\Zed\Vertex\Dependency\Plugin\OrderVertexExpanderPluginInterface|\Spryker\Zed\TaxAppExtension\Dependency\Plugin\OrderTaxAppExpanderPluginInterface&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;getOrderVertexExpanderPlugins&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;# This plugin stack is responsible for expansion of OrderTransfer based on present fields. Add your custom implemented expander plugins here following the example in `spryker-eco/vertex` module.&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;// The following plugins are for Marketplace only.&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# This plugin is expanding OrderTransfer object with merchant address information.&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MerchantProfileAddressOrderTaxAppExpanderPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# This plugin is expanding OrderTransfer object with product offer availability information.&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProductOfferAvailabilityOrderTaxAppExpanderPlugin&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;marketplace-only-configure-product-offer-stock-dependency-provider&quot;&gt;4. Marketplace only: Configure Product Offer Stock dependency provider&lt;/h2&gt;
&lt;p&gt;After you have configured the Product Offer Stock dependency provider for Marketplace, the plugin stack should look similar to the following:&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;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Zed\ProductOfferStock&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\ProductOfferStock\ProductOfferStockDependencyProvider&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerProductOfferStockDependencyProvider&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\StockAddress\Communication\Plugin\Stock\StockAddressStockTransferProductOfferStockExpanderPlugin&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;ProductOfferStockDependencyProvider&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerProductOfferStockDependencyProvider&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\ProductOfferStockExtension\Dependency\Plugin\StockTransferProductOfferStockExpanderPluginInterface&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;getStockTransferExpanderPluginCollection&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;# This plugin is providing warehouse address to StockTransfer objects which is used during tax calculation.&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StockAddressStockTransferProductOfferStockExpanderPlugin&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;optional-configure-custom-seller-and-buyer-countries&quot;&gt;5. Optional: Configure custom seller and buyer countries&lt;/h2&gt;
&lt;p&gt;If a user doesn’t choose a country during the checkout Address step, the system automatically uses the first country listed in the selected Spryker store. The same rule applies to sellers, except that the country is taken from the first warehouse address of a product stock.&lt;/p&gt;
&lt;p&gt;To change this default behavior, you can configure the country for both sellers and buyers. These configured countries will be the default values for tax calculations. You can use the following configuration methods to do this:&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;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Zed\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\Zed\Vertex\VertexConfig&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerVertexConfig&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;SprykerVertexConfig&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;getSellerCountryCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&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;s1&quot;&gt;&apos;FR&apos;&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;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;getCustomerCountryCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&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;s1&quot;&gt;&apos;DE&apos;&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;add-translations&quot;&gt;6. Add translations&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Append the glossary according to your configuration:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;src/data/import/glossary.csv&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-yaml 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;s&quot;&gt;cart.total.tax_total.calculated_at_checkout,an der Kasse berechnet,de_DE&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;cart.total.tax_total.calculated_at_checkout,calculated at checkout,en_US&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Import the updated glossary:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;language-yaml 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;s&quot;&gt;console data:import glossary&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;reference-mapping-of-quote-and-order-objects-to-vertex-api&quot;&gt;Reference: Mapping of Quote and Order objects to Vertex API&lt;/h2&gt;
&lt;p&gt;The following table reflects the mapping of the Spryker Quote and Order transfer object to the Vertex API request format. This information is useful for developing custom plugins for a deeper integration with your project.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;QuoteTransfer/OrderTransfer object properties&lt;/th&gt;
&lt;th&gt;Vertex API field&lt;/th&gt;
&lt;th&gt;Comment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Current date (Y-m-d)&lt;/td&gt;
&lt;td&gt;documentDate&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;QuoteTransfer.uuid / OrderTransfer.orderReference / new Uuid4 (if quote.uuid is not present)&lt;/td&gt;
&lt;td&gt;documentNumber&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;QuoteTransfer.uuid / OrderTransfer.orderReference / new Uuid4 (if quote.uuid is not present)&lt;/td&gt;
&lt;td&gt;transactionId&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;transactionType&lt;/td&gt;
&lt;td&gt;Always &lt;code&gt;SALE&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;saleMessageType&lt;/td&gt;
&lt;td&gt;Depending on the type of operation, &lt;code&gt;INVOICE&lt;/code&gt; or &lt;code&gt;QUOTATION&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;taxMetadata&lt;/td&gt;
&lt;td&gt;Mapped over the final request 1:1.&lt;/td&gt;
&lt;td&gt;Metadata needs to follow the structure of the Vertex API request.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;taxMetadata.seller.company&lt;/td&gt;
&lt;td&gt;seller.company&lt;/td&gt;
&lt;td&gt;Required by Vertex from the legal standpoint.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;items[].sku&lt;/td&gt;
&lt;td&gt;lineItems[].lineItemId; lineItems[].product.value; lineItems[].vendorSku&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lineItems[].lineItemId&lt;/code&gt; can be changed if there are multiple items with the same SKU in the request.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;items[].shipment.shippingAddress&lt;/td&gt;
&lt;td&gt;lineItems[].customer.destination&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;billingAddress&lt;/td&gt;
&lt;td&gt;lineItems[].customer.administrativeDestination&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;items[].merchantStockAddresses&lt;/td&gt;
&lt;td&gt;lineItems[].seller.physicalOrigin&lt;/td&gt;
&lt;td&gt;Multiple addresses are mapped to multiple items in the Vertex PBC and Vertex API &lt;code&gt;lineItems[]&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;items[].merchantProfileAddress&lt;/td&gt;
&lt;td&gt;lineItems[].seller.administrativeOrigin&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;items[].unitDiscountAmountFullAggregation&lt;/td&gt;
&lt;td&gt;lineItems[].discount.discountValue&lt;/td&gt;
&lt;td&gt;Prices are converted from the Spryker’s cent-based format to the Vertex decimal format.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;lineItems[].discount.discountType&lt;/td&gt;
&lt;td&gt;Always &lt;code&gt;DiscountAmount&lt;/code&gt;. Spryker stores discounts based on amount, so there is no need for percentage-based discounts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;items[].unitPrice (either GROSS or NET depending on the selected mode)&lt;/td&gt;
&lt;td&gt;lineItems[].unitPrice&lt;/td&gt;
&lt;td&gt;Prices are converted from Spryker’s cent-based format to Vertex decimal format.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;items[].merchantStockAddresses.quantityToShip&lt;/td&gt;
&lt;td&gt;lineItems[].quantity.value&lt;/td&gt;
&lt;td&gt;If &lt;code&gt;quantityToShip&lt;/code&gt; is less than the quantity requested in cart, the item is mapped to multiple items in the Vertex API.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;lineItems[].quantity.unitOfMeasure&lt;/td&gt;
&lt;td&gt;Always &lt;code&gt;EA&lt;/code&gt; (“each”). Other units of measure are not supported.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;items[].taxMetadata&lt;/td&gt;
&lt;td&gt;Mapped over specific &lt;code&gt;lineItem&lt;/code&gt; one to one.&lt;/td&gt;
&lt;td&gt;Metadata needs to follow the structure of the Vertex API request. For &lt;code&gt;lineItems&lt;/code&gt;, it’s mapped over each corresponding item based on &lt;code&gt;lineItemId&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;items[].taxMetadata.seller.company&lt;/td&gt;
&lt;td&gt;lineItems[].seller.company&lt;/td&gt;
&lt;td&gt;Required by Vertex from the legal standpoint.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;expenses (only for expenses with the &lt;code&gt;SHIPMENT_EXPENSE_TYPE&lt;/code&gt; type)&lt;/td&gt;
&lt;td&gt;lineItems&lt;/td&gt;
&lt;td&gt;Shipments are treated like products in Vertex - like a line item.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;expenses.hash&lt;/td&gt;
&lt;td&gt;lineItems[].lineItemId&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;expenses.shipment.shipmentAddress&lt;/td&gt;
&lt;td&gt;lineItems[].customer.destination&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;expenses.shipment.method.shipmentMethodKey&lt;/td&gt;
&lt;td&gt;lineItems[].product.value&lt;/td&gt;
&lt;td&gt;Depends on the selected shipment method.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;billingAddress&lt;/td&gt;
&lt;td&gt;lineItems[].customer.administrativeDestination&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;expenses.sumPrice (either GROSS or NET depending on the selected mode)&lt;/td&gt;
&lt;td&gt;lineItems[].extendedPrice&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;expenses.sumDiscountAmountAggregation&lt;/td&gt;
&lt;td&gt;lineItems[].discount.discountValue&lt;/td&gt;
&lt;td&gt;Prices are converted from the Spryker’s cent-based format to the Vertex decimal format.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lineItems[].discount.discountType&lt;/td&gt;
&lt;td&gt;Always &lt;code&gt;DiscountAmount&lt;/code&gt;. Spryker stores discounts based on amount, so there is no need to use percentage-based discounts.&lt;/td&gt;
&lt;td&gt;priceMode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lineItems[].taxIncludedIndicator&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;NET mode: false; GROSS mode: true.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;location-mapping&quot;&gt;Location mapping&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Spryker&lt;/th&gt;
&lt;th&gt;Vertex&lt;/th&gt;
&lt;th&gt;Comment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;address1&lt;/td&gt;
&lt;td&gt;streetAddress1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;address2&lt;/td&gt;
&lt;td&gt;streetAddress2&lt;/td&gt;
&lt;td&gt;Should be either not empty or &lt;code&gt;null&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;city&lt;/td&gt;
&lt;td&gt;city&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;state&lt;/td&gt;
&lt;td&gt;mainDivision&lt;/td&gt;
&lt;td&gt;Should be either not empty or &lt;code&gt;null&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zipCode&lt;/td&gt;
&lt;td&gt;postalCode&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;country.iso2Code&lt;/td&gt;
&lt;td&gt;country&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;next-step&quot;&gt;Next step&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>Mon, 16 Mar 2026 08:55:32 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/configure-vertex-specific-metadata.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-specific-metadata.html</guid>
            
            
        </item>
        
        <item>
            <title>Install Amazon QuickSight</title>
            <description>This document describes how to install Amazon QuickSight.

## Install feature core

Follow the steps below to install the Amazon QuickSight core.

### Prerequisites

Install the required features:

| NAME                     | VERSION          | INSTALLATION GUIDE                                                                                                                                                              |
|--------------------------|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Analytics                | {{page.release_tag}} | [Install the Analytics feature](/docs/pbc/all/business-intelligence/latest/install-the-analytics-feature.html)                           |
| Spryker Core Back Office | {{page.release_tag}} | [Install the Spryker Core Back Office feature](/docs/pbc/all/identity-access-management/latest/install-and-upgrade/install-the-spryker-core-back-office-feature.html) |

### 1) Install the required modules

Install the required modules using Composer:

```bash
composer require spryker-eco/amazon-quicksight:&quot;^2.0.0&quot; --update-with-dependencies
```

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

Make sure the following modules have been installed:

| MODULE           | EXPECTED DIRECTORY                   |
|------------------|--------------------------------------|
| AmazonQuicksight | vendor/spryker-eco/amazon-quicksight |

{% endinfo_block %}

### 2) Set up the configuration

1. Add one of the following QuickSight asset bundles to the project level, for example–to `src/Pyz/Zed/AmazonQuicksight/data/asset-bundle.zip`.
Preconfigured asset bundles per demo shop:
- [B2B Marketplace](https://spryker.s3.eu-central-1.amazonaws.com/docs/pbc/all/business-intelligence/amazon-quicksight-third-party-integration/install-amazon-quicksight.md/b2b-mp-asset-bundle.zip)
- [B2B](https://spryker.s3.eu-central-1.amazonaws.com/docs/pbc/all/business-intelligence/amazon-quicksight-third-party-integration/install-amazon-quicksight.md/b2b-asset-bundle.zip)
- [B2C Marketplace](https://spryker.s3.eu-central-1.amazonaws.com/docs/pbc/all/business-intelligence/amazon-quicksight-third-party-integration/install-amazon-quicksight.md/b2c-mp-asset-bundle.zip)
- [B2C](https://spryker.s3.eu-central-1.amazonaws.com/docs/pbc/all/business-intelligence/amazon-quicksight-third-party-integration/install-amazon-quicksight.md/b2c-asset-bundle.zip)

{% info_block infoBox &quot;SELECT statements in custom SQL queries&quot; %}

In custom SQL queries, avoid using `*` in `SELECT` statements. Instead, explicitly specify the required columns. This reduces the risk of exposing sensitive data when modifying asset bundles or creating custom datasets.

{% endinfo_block %}

2. Define the path to the asset bundle:

**src/Pyz/Zed/AmazonQuicksight/AmazonQuicksightConfig.php**

```php
&lt;?php

namespace Pyz\Zed\AmazonQuicksight;

use SprykerEco\Zed\AmazonQuicksight\AmazonQuicksightConfig as SprykerEcoAmazonQuicksightConfig;

class AmazonQuicksightConfig extends SprykerEcoAmazonQuicksightConfig
{
    /**
     * @var string
     */
    protected const ASSET_BUNDLE_IMPORT_FILE_PATH = &apos;%s/src/Pyz/Zed/AmazonQuicksight/data/asset-bundle.zip&apos;;

    /**
     * @return string
     */
    public function getAssetBundleImportFilePath(): string
    {
        return sprintf(static::ASSET_BUNDLE_IMPORT_FILE_PATH, APPLICATION_ROOT_DIR);
    }
}
```

3. To enable the asset bundle import, configure the data sets and data source IDs from one of the asset bundles:

**src/Pyz/Zed/AmazonQuicksight/AmazonQuicksightConfig.php**

&lt;details&gt;
&lt;summary&gt;B2B Marketplace&lt;/summary&gt;

```php
&lt;?php

namespace Pyz\Zed\AmazonQuicksight;

use SprykerEco\Zed\AmazonQuicksight\AmazonQuicksightConfig as SprykerEcoAmazonQuicksightConfig;

class AmazonQuicksightConfig extends SprykerEcoAmazonQuicksightConfig
{
    /**
     * @var list&lt;string&gt;
     */
    protected const ASSET_BUNDLE_IMPORT_DELETE_DATA_SET_IDS = [
        &apos;SprykerB2BMPDefaultDatasetCategoryLocalizedProductAbstract&apos;,
        &apos;SprykerB2BMPDefaultDatasetCompany&apos;,
        &apos;SprykerB2BMPDefaultDatasetCustomer&apos;,
        &apos;SprykerB2BMPDefaultDatasetCustomerAddress&apos;,
        &apos;SprykerB2BMPDefaultDatasetMerchantCommission&apos;,
        &apos;SprykerB2BMPDefaultDatasetMerchantOrder&apos;,
        &apos;SprykerB2BMPDefaultDatasetMerchantOrderCategory&apos;,
        &apos;SprykerB2BMPDefaultDatasetMerchantOrderItems&apos;,
        &apos;SprykerB2BMPDefaultDatasetMerchantProductOffer&apos;,
        &apos;SprykerB2BMPDefaultDatasetMerchantProductProductAbstract&apos;,
        &apos;SprykerB2BMPDefaultDatasetMerchantStore&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderDiscounts&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderItemCategoryProductBrand&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderItemLocalizedProductConcrete&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderItemProductCategory&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderItemsReturnDate&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderItemState&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderItemStateCustomers&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderItemStateHistory&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderPaymentMethods&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderReturns&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderReturnsProductConcrete&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderShipmentMethods&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderTotalsCustomerCompany&apos;,
        &apos;SprykerB2BMPDefaultDatasetOrderTotalsCustomSQL&apos;,
        &apos;SprykerB2BMPDefaultDatasetProductConcreteAvailability&apos;,
        &apos;SprykerB2BMPDefaultDatasetProductConcreteStore&apos;,
        &apos;SprykerB2BMPDefaultDatasetQuoteProducts&apos;,
        &apos;SprykerB2BMPDefaultDatasetShoppingListProducts&apos;,
    ];

    /**
     * @var string
     */
    protected const DEFAULT_DATA_SOURCE_ID = &apos;SprykerB2BMPDefaultDataSource&apos;;
}
```

&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;B2B&lt;/summary&gt;

```php
&lt;?php

namespace Pyz\Zed\AmazonQuicksight;

use SprykerEco\Zed\AmazonQuicksight\AmazonQuicksightConfig as SprykerEcoAmazonQuicksightConfig;

class AmazonQuicksightConfig extends SprykerEcoAmazonQuicksightConfig
{
    /**
     * @var list&lt;string&gt;
     */
    protected const ASSET_BUNDLE_IMPORT_DELETE_DATA_SET_IDS = [
        &apos;SprykerB2BDefaultDatasetOrderShipmentMethods&apos;,
        &apos;SprykerB2BDefaultDatasetOrderReturnsProductConcrete&apos;,
        &apos;SprykerB2BDefaultDatasetOrderReturns&apos;,
        &apos;SprykerB2BDefaultDatasetOrderItemCategoryProductBrand&apos;,
        &apos;SprykerB2BDefaultDatasetOrderItemLocalizedProductConcrete&apos;,
        &apos;SprykerB2BDefaultDatasetOrderItemProductCategory&apos;,
        &apos;SprykerB2BDefaultDatasetOrderItemsReturnDate&apos;,
        &apos;SprykerB2BDefaultDatasetOrderItemState&apos;,
        &apos;SprykerB2BDefaultDatasetOrderItemStateHistory&apos;,
        &apos;SprykerB2BDefaultDatasetOrderDiscounts&apos;,
        &apos;SprykerB2BDefaultDatasetOrderPaymentMethods&apos;,
        &apos;SprykerB2BDefaultDatasetOrderItemStateCustomers&apos;,
        &apos;SprykerB2BDefaultDatasetOrderTotalsCustomerCompany&apos;,
        &apos;SprykerB2BDefaultDatasetOrderTotalsCustomSQL&apos;,
        &apos;SprykerB2BDefaultDatasetCategoryLocalizedProductAbstract&apos;,
        &apos;SprykerB2BDefaultDatasetProductConcreteStore&apos;,
        &apos;SprykerB2BDefaultDatasetMerchantStore&apos;,
        &apos;SprykerB2BDefaultDatasetQuoteProducts&apos;,
        &apos;SprykerB2BDefaultDatasetProductConcreteAvailability&apos;,
        &apos;SprykerB2BDefaultDatasetCompany&apos;,
        &apos;SprykerB2BDefaultDatasetCustomer&apos;,
        &apos;SprykerB2BDefaultDatasetCustomerAddress&apos;,
    ];

    /**
     * @var string
     */
    protected const DEFAULT_DATA_SOURCE_ID = &apos;SprykerB2BDefaultDataSource&apos;;
}
```

&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;B2C Marketplace&lt;/summary&gt;

```php
&lt;?php

namespace Pyz\Zed\AmazonQuicksight;

use SprykerEco\Zed\AmazonQuicksight\AmazonQuicksightConfig as SprykerEcoAmazonQuicksightConfig;

class AmazonQuicksightConfig extends SprykerEcoAmazonQuicksightConfig
{
    /**
     * @var list&lt;string&gt;
     */
    protected const ASSET_BUNDLE_IMPORT_DELETE_DATA_SET_IDS = [
        &apos;SprykerB2CMPDefaultDatasetCategoryLocalizedProductAbstract&apos;,
        &apos;SprykerB2CMPDefaultDatasetCustomer&apos;,
        &apos;SprykerB2CMPDefaultDatasetCustomerAddress&apos;,
        &apos;SprykerB2CMPDefaultDatasetMerchantCommission&apos;,
        &apos;SprykerB2CMPDefaultDatasetMerchantOrder&apos;,
        &apos;SprykerB2CMPDefaultDatasetMerchantOrderCategory&apos;,
        &apos;SprykerB2CMPDefaultDatasetMerchantOrderItems&apos;,
        &apos;SprykerB2CMPDefaultDatasetMerchantProductOffer&apos;,
        &apos;SprykerB2CMPDefaultDatasetMerchantProductProductAbstract&apos;,
        &apos;SprykerB2CMPDefaultDatasetMerchantStore&apos;,
        &apos;SprykerB2CMPDefaultDatasetOrderDiscounts&apos;,
        &apos;SprykerB2CMPDefaultDatasetOrderItemCategoryProductBrand&apos;,
        &apos;SprykerB2CMPDefaultDatasetOrderItemLocalizedProductConcrete&apos;,
        &apos;SprykerB2CMPDefaultDatasetOrderItemProductCategory&apos;,
        &apos;SprykerB2CMPDefaultDatasetOrderItemsReturnDate&apos;,
        &apos;SprykerB2CMPDefaultDatasetOrderItemState&apos;,
        &apos;SprykerB2CMPDefaultDatasetOrderItemStateHistory&apos;,
        &apos;SprykerB2CMPDefaultDatasetOrderPaymentMethods&apos;,
        &apos;SprykerB2CMPDefaultDatasetOrderReturns&apos;,
        &apos;SprykerB2CMPDefaultDatasetOrderReturnsProductConcrete&apos;,
        &apos;SprykerB2CMPDefaultDatasetOrderShipmentMethods&apos;,
        &apos;SprykerB2CMPDefaultDatasetOrderTotalsCustomSQL&apos;,
        &apos;SprykerB2CMPDefaultDatasetProductConcreteAvailability&apos;,
        &apos;SprykerB2CMPDefaultDatasetProductConcreteStore&apos;,
        &apos;SprykerB2CMPDefaultDatasetQuoteProducts&apos;,
    ];

    /**
     * @var string
     */
    protected const DEFAULT_DATA_SOURCE_ID = &apos;SprykerB2CMPDefaultDataSource&apos;;
}
```

&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;B2C&lt;/summary&gt;

```php
&lt;?php

namespace Pyz\Zed\AmazonQuicksight;

use SprykerEco\Zed\AmazonQuicksight\AmazonQuicksightConfig as SprykerEcoAmazonQuicksightConfig;

class AmazonQuicksightConfig extends SprykerEcoAmazonQuicksightConfig
{
    /**
     * @var list&lt;string&gt;
     */
    protected const ASSET_BUNDLE_IMPORT_DELETE_DATA_SET_IDS = [
        &apos;SprykerB2CDefaultDatasetCategoryLocalizedProductAbstract&apos;,
        &apos;SprykerB2CDefaultDatasetCustomer&apos;,
        &apos;SprykerB2CDefaultDatasetCustomerAddress&apos;,
        &apos;SprykerB2CDefaultDatasetOrderDiscounts&apos;,
        &apos;SprykerB2CDefaultDatasetOrderItemCategoryProductBrand&apos;,
        &apos;SprykerB2CDefaultDatasetOrderItemLocalizedProductConcrete&apos;,
        &apos;SprykerB2CDefaultDatasetOrderItemProductCategory&apos;,
        &apos;SprykerB2CDefaultDatasetOrderItemsReturnDate&apos;,
        &apos;SprykerB2CDefaultDatasetOrderItemState&apos;,
        &apos;SprykerB2CDefaultDatasetOrderItemStateHistory&apos;,
        &apos;SprykerB2CDefaultDatasetOrderPaymentMethods&apos;,
        &apos;SprykerB2CDefaultDatasetOrderReturns&apos;,
        &apos;SprykerB2CDefaultDatasetOrderReturnsProductConcrete&apos;,
        &apos;SprykerB2CDefaultDatasetOrderShipmentMethods&apos;,
        &apos;SprykerB2CDefaultDatasetOrderTotalsCustomSQL&apos;,
        &apos;SprykerB2CDefaultDatasetProductConcreteAvailability&apos;,
        &apos;SprykerB2CDefaultDatasetProductConcreteStore&apos;,
        &apos;SprykerB2CDefaultDatasetQuoteProducts&apos;,
    ];

    /**
     * @var string
     */
    protected const DEFAULT_DATA_SOURCE_ID = &apos;SprykerB2CDefaultDataSource&apos;;
}
```

&lt;/details&gt;

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

These changes are verified in a later step.

{% endinfo_block %}

4. Add the following environment configuration:

| CONFIGURATION                                                     | SPECIFICATION                                                                                   | NAMESPACE                          |
|-------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|------------------------------------|
| AmazonQuicksightConstants::AWS_ACCOUNT_ID                         | ID of the AWS account holding your Amazon QuickSight account.                        | SprykerEco\Shared\AmazonQuicksight |
| AmazonQuicksightConstants::AWS_REGION                             | AWS region of your Amazon QuickSight account.                                  | SprykerEco\Shared\AmazonQuicksight |
| AmazonQuicksightConstants::AWS_QUICKSIGHT_NAMESPACE               | Name of the QuickSight namespace.                                                           | SprykerEco\Shared\AmazonQuicksight |
| AmazonQuicksightConstants::DEFAULT_DATA_SOURCE_USERNAME           | Username of the default data source.                                                               | SprykerEco\Shared\AmazonQuicksight |
| AmazonQuicksightConstants::DEFAULT_DATA_SOURCE_PASSWORD           | Default data source password.                                                               | SprykerEco\Shared\AmazonQuicksight |
| AmazonQuicksightConstants::DEFAULT_DATA_SOURCE_DATABASE_NAME      | Default data source database name.                                                          | SprykerEco\Shared\AmazonQuicksight |
| AmazonQuicksightConstants::DEFAULT_DATA_SOURCE_DATABASE_HOST      | Default data source database host.                                                          | SprykerEco\Shared\AmazonQuicksight |
| AmazonQuicksightConstants::DEFAULT_DATA_SOURCE_DATABASE_PORT      | Default data source database port.                                                          | SprykerEco\Shared\AmazonQuicksight |
| AmazonQuicksightConstants::DEFAULT_DATA_SOURCE_VPC_CONNECTION_ARN | Default data source VPC connection ARN.                                                     | SprykerEco\Shared\AmazonQuicksight |
| AmazonQuicksightConstants::GENERATE_EMBED_URL_ALLOWED_DOMAINS     | List of domains allowed for generating embed URLs.                                          | SprykerEco\Shared\AmazonQuicksight |
| AmazonQuicksightConstants::QUICKSIGHT_ASSUMED_ROLE_ARN            | The role ARN used by `Aws\Sts\StsClient` to assume a role used for all API calls to Quicksight. | SprykerEco\Shared\AmazonQuicksight |

**config/Shared/config_default.php**

```php
&lt;?php

use SprykerEco\Shared\AmazonQuicksight\AmazonQuicksightConstants;

// -------------------------------- AWS QUICKSIGHT -------------------------------
$config[AmazonQuicksightConstants::AWS_ACCOUNT_ID] = getenv(&apos;AWS_ACCOUNT_ID&apos;);
$config[AmazonQuicksightConstants::AWS_REGION] = getenv(&apos;AWS_REGION&apos;);
$config[AmazonQuicksightConstants::AWS_QUICKSIGHT_NAMESPACE] = getenv(&apos;QUICKSIGHT_NAMESPACE&apos;);
$config[AmazonQuicksightConstants::DEFAULT_DATA_SOURCE_USERNAME] = getenv(&apos;SPRYKER_BI_DB_USER&apos;);
$config[AmazonQuicksightConstants::DEFAULT_DATA_SOURCE_PASSWORD] = getenv(&apos;SPRYKER_BI_DB_PASSWORD&apos;);
$config[AmazonQuicksightConstants::DEFAULT_DATA_SOURCE_DATABASE_NAME] = getenv(&apos;SPRYKER_DB_DATABASE&apos;);
$config[AmazonQuicksightConstants::DEFAULT_DATA_SOURCE_DATABASE_HOST] = getenv(&apos;SPRYKER_DB_RO_REPLICA_HOST&apos;);
$config[AmazonQuicksightConstants::DEFAULT_DATA_SOURCE_DATABASE_PORT] = getenv(&apos;SPRYKER_DB_PORT&apos;);
$config[AmazonQuicksightConstants::DEFAULT_DATA_SOURCE_VPC_CONNECTION_ARN] = getenv(&apos;QUICKSIGHT_VPC_CONNECTION_ARN&apos;);
$config[AmazonQuicksightConstants::GENERATE_EMBED_URL_ALLOWED_DOMAINS] = [
    sprintf(&apos;https://%s&apos;, getenv(&apos;SPRYKER_BE_HOST&apos;)),
];
$config[AmazonQuicksightConstants::QUICKSIGHT_ASSUMED_ROLE_ARN] = getenv(&apos;QUICKSIGHT_ASSUMED_ROLE_ARN&apos;);
```

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

We recommended not defining the AWS credentials and let the SDK attempt to load them from the environment. If you need to specify the credentials,for example–for local development, you can do it as follows:

| CONFIGURATION                                     | SPECIFICATION          | NAMESPACE                          |
|---------------------------------------------------|------------------------|------------------------------------|
| AmazonQuicksightConstants::AWS_CREDENTIALS_KEY    | AWS access key ID.     | SprykerEco\Shared\AmazonQuicksight |
| AmazonQuicksightConstants::AWS_CREDENTIALS_SECRET | AWS access key secret. | SprykerEco\Shared\AmazonQuicksight |
| AmazonQuicksightConstants::AWS_CREDENTIALS_TOKEN  | AWS security token.    | SprykerEco\Shared\AmazonQuicksight |

```php
&lt;?php

use SprykerEco\Shared\AmazonQuicksight\AmazonQuicksightConstants;

// -------------------------------- AWS QUICKSIGHT -------------------------------
$config[AmazonQuicksightConstants::AWS_CREDENTIALS_KEY] = getenv(&apos;AWS_ACCESS_KEY_ID&apos;);
$config[AmazonQuicksightConstants::AWS_CREDENTIALS_SECRET] = getenv(&apos;AWS_SECRET_ACCESS_KEY&apos;);
$config[AmazonQuicksightConstants::AWS_CREDENTIALS_TOKEN] = getenv(&apos;AWS_SESSION_TOKEN&apos;);
```

{% endinfo_block %}

### 3) Set up database schema and transfer objects

Apply database changes and generate entity and transfer changes:

```bash
console propel:install
console transfer:generate
```

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

Make sure the following changes have been applied in the database:

| DATABASE ENTITY                        | TYPE  | EVENT   |
|----------------------------------------|-------|---------|
| spy_quicksight_user                    | table | created |
| spy_quicksight_asset_bundle_import_job | table | created |

Make sure the following changes have been triggered in transfer objects:

| TRANSFER                                                      | TYPE   | EVENT   | PATH                                                                                       |
|---------------------------------------------------------------|--------|---------|--------------------------------------------------------------------------------------------|
| QuicksightUser                                                | class  | created | src/Generated/Shared/Transfer/QuicksightUserTransfer                                       |
| QuicksightUserCriteria                                        | class  | created | src/Generated/Shared/Transfer/QuicksightUserCriteriaTransfer                               |
| QuicksightUserConditions                                      | class  | created | src/Generated/Shared/Transfer/QuicksightUserConditionsTransfer                             |
| QuicksightUserCollection                                      | class  | created | src/Generated/Shared/Transfer/QuicksightUserCollectionTransfer                             |
| QuicksightUserCollectionResponse                              | class  | created | src/Generated/Shared/Transfer/QuicksightUserCollectionResponseTransfer                     |
| QuicksightDeleteUserResponse                                  | class  | created | src/Generated/Shared/Transfer/QuicksightDeleteUserResponseTransfer                         |
| QuicksightDeleteUserRequest                                   | class  | created | src/Generated/Shared/Transfer/QuicksightDeleteUserRequestTransfer                          |
| QuicksightListUsersRequest                                    | class  | created | src/Generated/Shared/Transfer/QuicksightListUsersRequestTransfer                           |
| QuicksightListUsersResponse                                   | class  | created | src/Generated/Shared/Transfer/QuicksightListUsersResponseTransfer                          |
| QuicksightGenerateEmbedUrlRequest                             | class  | created | src/Generated/Shared/Transfer/QuicksightGenerateEmbedUrlRequestTransfer                    |
| QuicksightExperienceConfiguration                             | class  | created | src/Generated/Shared/Transfer/QuicksightExperienceConfigurationTransfer                    |
| QuicksightConsole                                             | class  | created | src/Generated/Shared/Transfer/QuicksightConsoleTransfer                                    |
| QuicksightGenerateEmbedUrlResponse                            | class  | created | src/Generated/Shared/Transfer/QuicksightGenerateEmbedUrlResponseTransfer                   |
| QuicksightEmbedUrl                                            | class  | created | src/Generated/Shared/Transfer/QuicksightEmbedUrlTransfer                                   |
| QuicksightAssetBundleImportJob                                | class  | created | src/Generated/Shared/Transfer/QuicksightAssetBundleImportJobTransfer                       |
| QuicksightAssetBundleImportJobCollection                      | class  | created | src/Generated/Shared/Transfer/QuicksightAssetBundleImportJobCollectionTransfer             |
| QuicksightAssetBundleImportJobCriteria                        | class  | created | src/Generated/Shared/Transfer/QuicksightAssetBundleImportJobCriteriaTransfer               |
| QuicksightAssetBundleImportJobConditions                      | class  | created | src/Generated/Shared/Transfer/QuicksightAssetBundleImportJobConditionsTransfer             |
| QuicksightStartAssetBundleImportJobRequest                    | class  | created | src/Generated/Shared/Transfer/QuicksightStartAssetBundleImportJobRequestTransfer           |
| QuicksightAssetBundleImportSource                             | class  | created | src/Generated/Shared/Transfer/QuicksightAssetBundleImportSourceTransfer                    |
| QuicksightOverrideParameters                                  | class  | created | src/Generated/Shared/Transfer/QuicksightOverrideParametersTransfer                         |
| QuicksightOverrideParametersDataSource                        | class  | created | src/Generated/Shared/Transfer/QuicksightOverrideParametersDataSourceTransfer               |
| QuicksightOverrideParametersDataSourceCredentials             | class  | created | src/Generated/Shared/Transfer/QuicksightOverrideParametersDataSourceCredentialsTransfer    |
| QuicksightOverrideParametersDataSourceCredentialPair          | class  | created | src/Generated/Shared/Transfer/QuicksightOverrideParametersDataSourceCredentialPairTransfer |
| QuicksightOverrideParametersDataSourceParameters              | class  | created | src/Generated/Shared/Transfer/QuicksightOverrideParametersDataSourceCredentialPairTransfer |
| QuicksightOverrideParametersDataSourceMariaDbParameters       | class  | created | src/Generated/Shared/Transfer/QuicksightOverrideParametersDataSourceCredentialPairTransfer |
| QuicksightOverrideParametersDataSourceVpcConnectionProperties | class  | created | src/Generated/Shared/Transfer/QuicksightOverrideParametersDataSourceCredentialPairTransfer |
| QuicksightOverridePermissions                                 | class  | created | src/Generated/Shared/Transfer/QuicksightOverridePermissionsTransfer                        |
| QuicksightOverridePermissionsAnalysis                         | class  | created | src/Generated/Shared/Transfer/QuicksightOverridePermissionsAnalysisTransfer                |
| QuicksightOverridePermissionsDashboard                        | class  | created | src/Generated/Shared/Transfer/QuicksightOverridePermissionsDashboardTransfer               |
| QuicksightOverridePermissionsDataSet                          | class  | created | src/Generated/Shared/Transfer/QuicksightOverridePermissionsDataSetTransfer                 |
| QuicksightOverridePermissionsDataSource                       | class  | created | src/Generated/Shared/Transfer/QuicksightOverridePermissionsDataSourceTransfer              |
| QuicksightPermissions                                         | class  | created | src/Generated/Shared/Transfer/QuicksightPermissionsTransfer                                |
| QuicksightStartAssetBundleImportJobResponse                   | class  | created | src/Generated/Shared/Transfer/QuicksightStartAssetBundleImportJobResponseTransfer          |
| QuicksightDescribeAssetBundleImportJobRequest                 | class  | created | src/Generated/Shared/Transfer/QuicksightDescribeAssetBundleImportJobRequestTransfer        |
| QuicksightDescribeAssetBundleImportJobResponse                | class  | created | src/Generated/Shared/Transfer/QuicksightDescribeAssetBundleImportJobResponseTransfer       |
| EnableQuicksightAnalyticsRequest                              | class  | created | src/Generated/Shared/Transfer/EnableQuicksightAnalyticsRequestTransfer                     |
| EnableQuicksightAnalyticsResponse                             | class  | created | src/Generated/Shared/Transfer/EnableQuicksightAnalyticsResponseTransfer                    |
| ResetQuicksightAnalyticsRequest                               | class  | created | src/Generated/Shared/Transfer/ResetQuicksightAnalyticsRequestTransfer                      |
| ResetQuicksightAnalyticsResponse                              | class  | created | src/Generated/Shared/Transfer/ResetQuicksightAnalyticsResponseTransfer                     |

{% endinfo_block %}

### 4) Add translations

Generate a new translation cache for Zed:

```bash
console translator:generate-cache
```

### 5) Set up behavior

1. Enable the following behaviors by registering the plugins:

| PLUGIN                                      | SPECIFICATION                                                                                                        | PREREQUISITES | NAMESPACE                                                         |
|---------------------------------------------|----------------------------------------------------------------------------------------------------------------------|---------------|-------------------------------------------------------------------|
| QuicksightAnalyticsCollectionExpanderPlugin | Expands the provided `AnalyticsCollectionTransfer` with QuickSight analytics.                                    |               | SprykerEco\Zed\AmazonQuicksight\Communication\Plugin\AnalyticsGui |
| QuicksightUserExpanderPlugin                | Populates `UserTransfer.quicksightUser` in the collection with existing QuickSight users.                                |               | SprykerEco\Zed\AmazonQuicksight\Communication\Plugin\User         |
| DeleteQuicksightUserPostUpdatePlugin        | Deletes a QuickSight user when the QuickSight role is deselected for the user or when the user is deactivated or deleted. |               | SprykerEco\Zed\AmazonQuicksight\Communication\Plugin\User         |

**src/Pyz/Zed/AnalyticsGui/AnalyticsGuiDependencyProvider.php**

```php
&lt;?php

namespace Pyz\Zed\AnalyticsGui;

use Spryker\Zed\AnalyticsGui\AnalyticsGuiDependencyProvider as SprykerAnalyticsGuiDependencyProvider;
use SprykerEco\Zed\AmazonQuicksight\Communication\Plugin\AnalyticsGui\QuicksightAnalyticsCollectionExpanderPlugin;

class AnalyticsGuiDependencyProvider extends SprykerAnalyticsGuiDependencyProvider
{
    /**
     * @return list&lt;\Spryker\Zed\AnalyticsGuiExtension\Dependency\Plugin\AnalyticsCollectionExpanderPluginInterface&gt;
     */
    protected function getAnalyticsCollectionExpanderPlugins(): array
    {
        return [
            new QuicksightAnalyticsCollectionExpanderPlugin(),
        ];
    }
}
```

**src/Pyz/Zed/User/UserDependencyProvider.php**

```php
&lt;?php

namespace Pyz\Zed\User;

use Spryker\Zed\User\UserDependencyProvider as SprykerUserDependencyProvider;
use SprykerEco\Zed\AmazonQuicksight\Communication\Plugin\User\DeleteQuicksightUserPostUpdatePlugin;
use SprykerEco\Zed\AmazonQuicksight\Communication\Plugin\User\QuicksightUserExpanderPlugin;

class UserDependencyProvider extends SprykerUserDependencyProvider
{
    /**
     * @return list&lt;\Spryker\Zed\UserExtension\Dependency\Plugin\UserExpanderPluginInterface&gt;
     */
    protected function getUserExpanderPlugins(): array
    {
        return [
            new QuicksightUserExpanderPlugin(),
        ];
    }

    /**
     * @return list&lt;\Spryker\Zed\UserExtension\Dependency\Plugin\UserPostUpdatePluginInterface&gt;
     */
    protected function getUserPostUpdatePlugins(): array
    {
        return [
            new DeleteQuicksightUserPostUpdatePlugin(),
        ];
    }
}
```

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

| PLUGIN | VERIFICATION |
| - | - |
| Verify `QuicksightAnalyticsCollectionExpanderPlugin`|  Go to `https://mysprykershop.com/analytics-gui/analytics` and make sure QuickSight analytics is displayed. By default, you should see the `No Analytics permission has been granted to the current user` message. |
| Verify `QuicksightUserExpanderPlugin`|  Create a new QuickSight user in the `spy_quicksight_user` DB table and call `UserFacade::getUserCollection()` for a user used for the newly created QuickSight user. Make sure the `UserCollection.user.quicksightUser` is expanded. |
| Verify `DeleteQuicksightUserPostUpdatePlugin`|  In the Back Office, go to **Users**&gt;**Users**. For a newly created QuickSight user,  deactivate deactive the respective Back Office user. Make sure the corresponding row is deleted in the `spy_quicksight_user` DB table. |

{% endinfo_block %}

2. Enable behaviors by registering the console commands:

| PLUGIN                          | SPECIFICATION                                                                                            | PREREQUISITES | NAMESPACE                                             |
|---------------------------------|----------------------------------------------------------------------------------------------------------|---------------|-------------------------------------------------------|
| QuicksightUserSyncCreateConsole | In the `spy_quicksight_user` DB table, persists the users registered in QuickSight by persisted user emails.      |               | SprykerEco\Zed\AmazonQuicksight\Communication\Console |

**src/Pyz/Zed/Console/ConsoleDependencyProvider.php**

```php
&lt;?php

namespace Pyz\Zed\Console;

use Spryker\Zed\Console\ConsoleDependencyProvider as SprykerConsoleDependencyProvider;
use Spryker\Zed\Kernel\Container;
use SprykerEco\Zed\AmazonQuicksight\Communication\Console\QuicksightUserSyncCreateConsole;

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

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

1. Create a QuickSight user in QuickSight.
2. Sync QuickSight to Back Office users:

```bash
console quicksight-user:sync:create
```

In the `spy_quicksight_user` table, make sure that the corresponding QuickSight user has been added.

{% endinfo_block %}

3. Optional: To sync users automatically during deployment, configure the installation stage of a pipeline, for example–destructive pipeline. Add the following command to the end of the `demodata` section:

**config/install/destructive.yml**

```yaml
sections:
    demodata:
#       ...other commands
        create-quicksight-users:
            command: &apos;vendor/bin/console quicksight-user:sync:create&apos;
```


4. Clear router cache:

```bash
console router:cache:warm-up:backoffice
```

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

In the Back Office, make sure you can access the Analytics page: `https://backoffice.mysprykershop.com/amazon-quicksight/analytics/enable`.

{% endinfo_block %}

## Install feature frontend

Follow the steps below to install the Amazon QuickSight frontend.

### Prerequisites

Install the required features:

| NAME         | VERSION          | INSTALLATION GUIDE                                                                                                                                          |
|--------------|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Spryker Core | {{page.release_tag}} | [Install the Spryker Core feature](/docs/pbc/all/miscellaneous/latest/install-and-upgrade/install-features/install-the-spryker-core-feature.html) |

### 1) Install npm dependencies and enable Javascript and CSS changes

1. In `package.json`, add the `amazon-quicksight-embedding-sdk` npm package to `dependencies` and add the vendor workspace:

**package.json**

```json
{
    &quot;dependencies&quot;: {
        &quot;amazon-quicksight-embedding-sdk&quot;: &quot;2.10.0&quot;
    },
    &quot;workspaces&quot;: [
        &quot;vendor/spryker-eco/*/assets/Zed&quot;
    ]
}
```

2. Install dependencies and build the Back Office frontend:

```bash
npm install
console frontend:zed:build
```

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

Make sure the Back Office frontend build completes without errors. The output must not contain `Module not found` messages. Verify that the following assets are generated:

- `public/Zed/assets/css/spryker-zed-gui-commons.css`
- `public/Zed/assets/css/spryker-zed-productmanagement-main.css`

If assets are missing after deployment, verify that `amazon-quicksight-embedding-sdk` is present in `package.json` and rerun the build.

{% endinfo_block %}
</description>
            <pubDate>Fri, 13 Mar 2026 16:03:41 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/business-intelligence/latest/amazon-quicksight-third-party-integration/install-amazon-quicksight.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/business-intelligence/latest/amazon-quicksight-third-party-integration/install-amazon-quicksight.html</guid>
            
            
        </item>
        
        <item>
            <title>Adding Custom Scopes to Configuration Management</title>
            <description>&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;/h2&gt;
&lt;p&gt;The Configuration feature ships with two built-in scopes: &lt;code&gt;global&lt;/code&gt; and &lt;code&gt;store&lt;/code&gt;. The scope system is extensible – you can add custom scopes like &lt;code&gt;locale&lt;/code&gt;, &lt;code&gt;merchant&lt;/code&gt;, or &lt;code&gt;customer_group&lt;/code&gt; at the project level.&lt;/p&gt;
&lt;p&gt;Custom scopes integrate into the existing hierarchy. Values resolve from the most specific scope upward until a value is found, falling back to &lt;code&gt;default_value&lt;/code&gt; from the YAML schema.&lt;/p&gt;
&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;customer_group (most specific)
  -&amp;gt; store
    -&amp;gt; global (least specific)
      -&amp;gt; default_value (from schema)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;what-you-need&quot;&gt;What You Need&lt;/h2&gt;
&lt;p&gt;Adding a custom scope requires changes in three areas:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;What&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Shared Config&lt;/td&gt;
&lt;td&gt;Register scope in hierarchy&lt;/td&gt;
&lt;td&gt;Value resolution knows the parent chain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zed Plugin&lt;/td&gt;
&lt;td&gt;Provide scope identifiers&lt;/td&gt;
&lt;td&gt;Backoffice scope switcher lists available identifiers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optional: Zed + Client Plugin&lt;/td&gt;
&lt;td&gt;Expand read requests with scope context&lt;/td&gt;
&lt;td&gt;&lt;code&gt;getModuleConfig()&lt;/code&gt; calls automatically include scope&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;step-by-step-guide&quot;&gt;Step-by-Step Guide&lt;/h2&gt;
&lt;p&gt;This guide uses &lt;code&gt;locale&lt;/code&gt; as an example custom scope that inherits from &lt;code&gt;store&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-1-override-shared-configuration&quot;&gt;Step 1: Override Shared Configuration&lt;/h3&gt;
&lt;p&gt;Create a project-level Shared Config that extends the core one:&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;c1&quot;&gt;// src/Pyz/Shared/Configuration/ConfigurationConfig.php&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Shared\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\Shared\Configuration\ConfigurationConfig&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerConfigurationConfig&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\Shared\Store\StoreConstants&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;ConfigurationConfig&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerConfigurationConfig&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;const&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SCOPE_LOCALE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;locale&apos;&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;getAvailableScopes&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;nb&quot;&gt;array_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAvailableScopes&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;k&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SCOPE_LOCALE&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;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;getScopeHierarchy&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;nb&quot;&gt;array_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getScopeHierarchy&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;k&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SCOPE_LOCALE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StoreConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SCOPE_STORE&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;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; The hierarchy map is &lt;code&gt;[scopeKey =&amp;gt; parentScopeKey]&lt;/code&gt;. A scope with parent &lt;code&gt;null&lt;/code&gt; is the root.&lt;/p&gt;
&lt;p&gt;Built-in hierarchy:&lt;/p&gt;
&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;global (parent: null)       -- root, no identifier needed
store  (parent: global)     -- requires identifier, e.g. &quot;DE&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After adding &lt;code&gt;locale&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;global (parent: null)
store  (parent: global)
locale (parent: store)      -- requires identifier, e.g. &quot;de_DE&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;step-2-create-a-scope-identifier-provider-plugin&quot;&gt;Step 2: Create a Scope Identifier Provider Plugin&lt;/h3&gt;
&lt;p&gt;The Back Office uses this plugin to list available identifiers in the scope switcher dropdown.&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;c1&quot;&gt;// src/Pyz/Zed/Locale/Communication/Plugin/Configuration/LocaleConfigurationScopeIdentifierProviderPlugin.php&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Zed\Locale\Communication\Plugin\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\ConfigurationExtension\Dependency\Plugin\ConfigurationScopeIdentifierProviderPluginInterface&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\Kernel\Communication\AbstractPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cd&quot;&gt;/**
 * @method \Spryker\Zed\Locale\Business\LocaleFacadeInterface getFacade()
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleConfigurationScopeIdentifierProviderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationScopeIdentifierProviderPluginInterface&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;getScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&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;s1&quot;&gt;&apos;locale&apos;&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;cd&quot;&gt;/**
     * @return array&amp;lt;string&amp;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;getIdentifiers&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;nv&quot;&gt;$localeTransfers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getFacade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getLocaleCollection&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;nb&quot;&gt;array_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$localeTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$localeTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getLocaleNameOrFail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$localeTransfers&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;h3 id=&quot;step-3-register-the-identifier-provider-plugin&quot;&gt;Step 3: Register the Identifier Provider Plugin&lt;/h3&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;c1&quot;&gt;// src/Pyz/Zed/Configuration/ConfigurationDependencyProvider.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;Pyz\Zed\Locale\Communication\Plugin\Configuration\LocaleConfigurationScopeIdentifierProviderPlugin&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;Spryker\Zed\Store\Communication\Plugin\Configuration\StoreConfigurationScopeIdentifierProviderPlugin&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\ConfigurationScopeIdentifierProviderPluginInterface&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;getScopeIdentifierProviderPlugins&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StoreConfigurationScopeIdentifierProviderPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleConfigurationScopeIdentifierProviderPlugin&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;h3 id=&quot;step-4-use-the-new-scope-in-yaml-schemas&quot;&gt;Step 4: Use the New Scope in YAML Schemas&lt;/h3&gt;
&lt;p&gt;Add the scope to your setting and group declarations:&lt;/p&gt;
&lt;div class=&quot;language-yaml 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;na&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;catalog&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Catalog&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;tabs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;display&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Display&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;labels&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Labels&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;scopes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Group visible at all three scopes&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;currency_symbol&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Currency Symbol&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;string&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;default_value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;scopes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Setting configurable at all three scopes&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;storefront&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Run &lt;code&gt;docker/sdk cli console configuration:sync&lt;/code&gt; after changes.&lt;/p&gt;
&lt;h3 id=&quot;optional-step-5-create-request-expander-plugins&quot;&gt;Optional Step 5: Create Request Expander Plugins&lt;/h3&gt;
&lt;p&gt;Without an expander, callers must explicitly pass scope context as &lt;code&gt;ConfigurationScopeTransfer&lt;/code&gt; objects:&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;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Generated\Shared\Transfer\ConfigurationScopeTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getModuleConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;catalog:display:labels:currency_symbol&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;$&apos;&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationScopeTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;locale&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setIdentifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;de_DE&apos;&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;With an expander, the current locale is injected automatically into every &lt;code&gt;getModuleConfig()&lt;/code&gt; call:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Zed expander:&lt;/strong&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;c1&quot;&gt;// src/Pyz/Zed/Locale/Communication/Plugin/Configuration/LocaleConfigurationValueRequestExpanderPlugin.php&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Zed\Locale\Communication\Plugin\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;Generated\Shared\Transfer\ConfigurationScopeTransfer&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;Generated\Shared\Transfer\ConfigurationValueRequestTransfer&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\ConfigurationExtension\Dependency\Plugin\ConfigurationValueRequestExpanderPluginInterface&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\Kernel\Communication\AbstractPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cd&quot;&gt;/**
 * @method \Spryker\Zed\Locale\Business\LocaleFacadeInterface getFacade()
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleConfigurationValueRequestExpanderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationValueRequestExpanderPluginInterface&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;expand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;ConfigurationValueRequestTransfer&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&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;kt&quot;&gt;ConfigurationValueRequestTransfer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getScopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$scope&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;locale&apos;&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&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;nv&quot;&gt;$configurationValueRequestTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addScope&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationScopeTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;locale&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setIdentifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getFacade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getCurrentLocale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getLocaleNameOrFail&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&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;&lt;strong&gt;Client expander&lt;/strong&gt; (same logic, different layer namespace and plugin interface):&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;c1&quot;&gt;// src/Pyz/Client/Locale/Plugin/Configuration/LocaleConfigurationValueRequestExpanderPlugin.php&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Client\Locale\Plugin\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;Generated\Shared\Transfer\ConfigurationScopeTransfer&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;Generated\Shared\Transfer\ConfigurationValueRequestTransfer&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\Client\ConfigurationExtension\Dependency\Plugin\ConfigurationValueRequestExpanderPluginInterface&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\Client\Kernel\AbstractPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cd&quot;&gt;/**
 * @method \Spryker\Client\Locale\LocaleClientInterface getClient()
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleConfigurationValueRequestExpanderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationValueRequestExpanderPluginInterface&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;expand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;ConfigurationValueRequestTransfer&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&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;kt&quot;&gt;ConfigurationValueRequestTransfer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getScopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$scope&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;locale&apos;&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&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;nv&quot;&gt;$configurationValueRequestTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addScope&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationScopeTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;locale&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setIdentifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getCurrentLocale&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&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;h3 id=&quot;optional-step-51-register-request-expander-plugins&quot;&gt;Optional Step 5.1: Register Request Expander Plugins&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Zed:&lt;/strong&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;c1&quot;&gt;// src/Pyz/Zed/Configuration/ConfigurationDependencyProvider.php&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;getConfigurationValueRequestExpanderPlugins&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StoreConfigurationValueRequestExpanderPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleConfigurationValueRequestExpanderPlugin&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;&lt;strong&gt;Client:&lt;/strong&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;c1&quot;&gt;// src/Pyz/Client/Configuration/ConfigurationDependencyProvider.php&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Client\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;Pyz\Client\Locale\Plugin\Configuration\LocaleConfigurationValueRequestExpanderPlugin&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\Client\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;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;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;getConfigurationValueRequestExpanderPlugins&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StoreConfigurationValueRequestExpanderPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleConfigurationValueRequestExpanderPlugin&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;how-value-resolution-works&quot;&gt;How Value Resolution Works&lt;/h2&gt;
&lt;p&gt;When &lt;code&gt;getModuleConfig(&apos;catalog:display:labels:currency_symbol&apos;, &apos;$&apos;)&lt;/code&gt; is called with expander plugins providing &lt;code&gt;locale=de_DE&lt;/code&gt; and &lt;code&gt;store=DE&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check &lt;code&gt;locale:de_DE&lt;/code&gt; – value saved specifically for German locale?&lt;/li&gt;
&lt;li&gt;Not found -&amp;gt; check parent &lt;code&gt;store:DE&lt;/code&gt; – value saved for DE store?&lt;/li&gt;
&lt;li&gt;Not found -&amp;gt; check parent &lt;code&gt;global&lt;/code&gt; – value saved globally?&lt;/li&gt;
&lt;li&gt;Not found -&amp;gt; return &lt;code&gt;default_value&lt;/code&gt; from YAML schema (&lt;code&gt;&amp;quot;$&amp;quot;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Schema has no such key -&amp;gt; return &lt;code&gt;$default&lt;/code&gt; argument (&lt;code&gt;&apos;$&apos;&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first non-null value wins.&lt;/p&gt;
&lt;h2 id=&quot;advanced-use-cases&quot;&gt;Advanced Use Cases&lt;/h2&gt;
&lt;p&gt;Custom scopes enable dynamic configuration scenarios beyond static identifiers like &lt;code&gt;store&lt;/code&gt; or &lt;code&gt;locale&lt;/code&gt;. This section covers two common advanced patterns: calculated scopes and A/B testing.&lt;/p&gt;
&lt;h3 id=&quot;calculated-scopes&quot;&gt;Calculated Scopes&lt;/h3&gt;
&lt;p&gt;Calculated scopes determine their identifier at runtime based on request context. Unlike static scopes where identifiers are predefined (such as store codes), calculated scopes derive their value from dynamic data like user attributes, request headers, or external services.&lt;/p&gt;
&lt;h4 id=&quot;example-region-based-configuration-by-ip-address&quot;&gt;Example: Region-Based Configuration by IP Address&lt;/h4&gt;
&lt;p&gt;You can create a &lt;code&gt;region&lt;/code&gt; scope that determines the user’s geographic region from their IP address. This enables region-specific configurations without requiring users to explicitly select their region.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Define the region scope in Shared Configuration:&lt;/strong&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;c1&quot;&gt;// src/Pyz/Shared/Configuration/ConfigurationConfig.php&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Shared\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\Shared\Configuration\ConfigurationConfig&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerConfigurationConfig&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;ConfigurationConfig&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerConfigurationConfig&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;const&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SCOPE_REGION&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;region&apos;&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;getAvailableScopes&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;nb&quot;&gt;array_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAvailableScopes&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;k&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SCOPE_REGION&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;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;getScopeHierarchy&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;nb&quot;&gt;array_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getScopeHierarchy&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;k&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SCOPE_REGION&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SCOPE_STORE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Region inherits from global&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;&lt;strong&gt;Step 2: Create an identifier provider with region definitions:&lt;/strong&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;c1&quot;&gt;// src/Pyz/Zed/Region/Communication/Plugin/Configuration/RegionConfigurationScopeIdentifierProviderPlugin.php&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Zed\Region\Communication\Plugin\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\ConfigurationExtension\Dependency\Plugin\ConfigurationScopeIdentifierProviderPluginInterface&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\Kernel\Communication\AbstractPlugin&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;RegionConfigurationScopeIdentifierProviderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationScopeIdentifierProviderPluginInterface&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;getScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&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;s1&quot;&gt;&apos;region&apos;&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;cd&quot;&gt;/**
     * @return array&amp;lt;string&amp;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;getIdentifiers&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;c1&quot;&gt;// Define available regions for the backoffice scope switcher&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;s1&quot;&gt;&apos;eu-west&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;eu-east&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;us-west&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;us-east&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;apac&apos;&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;p&gt;&lt;strong&gt;Step 3: Create a request expander that calculates the region from IP:&lt;/strong&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;c1&quot;&gt;// src/Pyz/Client/Region/Plugin/Configuration/RegionConfigurationValueRequestExpanderPlugin.php&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Client\Region\Plugin\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;Generated\Shared\Transfer\ConfigurationScopeTransfer&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;Generated\Shared\Transfer\ConfigurationValueRequestTransfer&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\Client\ConfigurationExtension\Dependency\Plugin\ConfigurationValueRequestExpanderPluginInterface&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\Client\Kernel\AbstractPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cd&quot;&gt;/**
 * @method \Pyz\Client\Region\RegionClientInterface getClient()
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RegionConfigurationValueRequestExpanderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationValueRequestExpanderPluginInterface&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;expand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;ConfigurationValueRequestTransfer&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&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;kt&quot;&gt;ConfigurationValueRequestTransfer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getScopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$scope&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;region&apos;&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&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;c1&quot;&gt;// Calculate region from the current request&apos;s IP address&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$regionIdentifier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getRegionByCurrentIp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addScope&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationScopeTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;region&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setIdentifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$regionIdentifier&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&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;&lt;strong&gt;Step 4: Implement the region detection logic in the client:&lt;/strong&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;c1&quot;&gt;// src/Pyz/Client/Region/RegionClient.php&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Client\Region&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\Client\Kernel\AbstractClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cd&quot;&gt;/**
 * @method \Pyz\Client\Region\RegionFactory getFactory()
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RegionClient&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractClient&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RegionClientInterface&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;getRegionByCurrentIp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&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;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createRegionResolver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;resolveRegionByIp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getRequestStack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getCurrentRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getClientIp&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;With this setup, configuration values automatically resolve based on the user’s geographic region. For example, you can configure different shipping options, payment methods, or promotional content for users in different regions.&lt;/p&gt;
&lt;h3 id=&quot;ab-testing-with-custom-scopes&quot;&gt;A/B Testing with Custom Scopes&lt;/h3&gt;
&lt;p&gt;Custom scopes provide a mechanism for A/B testing by assigning users to experiment variants. This approach enables you to test different configuration values and measure their impact on user behavior.&lt;/p&gt;
&lt;h4 id=&quot;example-experiment-scope-for-ab-testing&quot;&gt;Example: Experiment Scope for A/B Testing&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Define the experiment scope:&lt;/strong&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;c1&quot;&gt;// src/Pyz/Shared/Configuration/ConfigurationConfig.php&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Shared\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\Shared\Configuration\ConfigurationConfig&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerConfigurationConfig&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;ConfigurationConfig&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerConfigurationConfig&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;const&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SCOPE_EXPERIMENT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;experiment&apos;&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;getAvailableScopes&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;nb&quot;&gt;array_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAvailableScopes&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;k&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SCOPE_EXPERIMENT&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;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;getScopeHierarchy&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;nb&quot;&gt;array_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getScopeHierarchy&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;c1&quot;&gt;// Experiment is the most specific scope, inheriting from store&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SCOPE_EXPERIMENT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SCOPE_STORE&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;p&gt;&lt;strong&gt;Step 2: Create an identifier provider for experiment variants:&lt;/strong&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;c1&quot;&gt;// src/Pyz/Zed/Experiment/Communication/Plugin/Configuration/ExperimentConfigurationScopeIdentifierProviderPlugin.php&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Zed\Experiment\Communication\Plugin\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\ConfigurationExtension\Dependency\Plugin\ConfigurationScopeIdentifierProviderPluginInterface&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\Kernel\Communication\AbstractPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cd&quot;&gt;/**
 * @method \Pyz\Zed\Experiment\Business\ExperimentFacadeInterface getFacade()
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ExperimentConfigurationScopeIdentifierProviderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationScopeIdentifierProviderPluginInterface&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;getScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&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;s1&quot;&gt;&apos;experiment&apos;&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;cd&quot;&gt;/**
     * @return array&amp;lt;string&amp;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;getIdentifiers&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;c1&quot;&gt;// Return all active experiment variants from the database&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// This allows configuring values for each variant in the backoffice&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getFacade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getActiveExperimentVariantIdentifiers&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;&lt;strong&gt;Step 3: Create a request expander that assigns users to variants:&lt;/strong&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;c1&quot;&gt;// src/Pyz/Client/Experiment/Plugin/Configuration/ExperimentConfigurationValueRequestExpanderPlugin.php&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Client\Experiment\Plugin\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;Generated\Shared\Transfer\ConfigurationScopeTransfer&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;Generated\Shared\Transfer\ConfigurationValueRequestTransfer&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\Client\ConfigurationExtension\Dependency\Plugin\ConfigurationValueRequestExpanderPluginInterface&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\Client\Kernel\AbstractPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cd&quot;&gt;/**
 * @method \Pyz\Client\Experiment\ExperimentClientInterface getClient()
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ExperimentConfigurationValueRequestExpanderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationValueRequestExpanderPluginInterface&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;expand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;ConfigurationValueRequestTransfer&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&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;kt&quot;&gt;ConfigurationValueRequestTransfer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getScopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$scope&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;experiment&apos;&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&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;c1&quot;&gt;// Get the experiment variant for the current user&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// This can be based on session, customer ID, or random assignment&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$experimentVariant&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getCurrentUserExperimentVariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getKey&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$experimentVariant&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&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;c1&quot;&gt;// User is not part of any experiment, skip adding the scope&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// Value resolution falls back to the parent scope (store)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&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;nv&quot;&gt;$configurationValueRequestTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addScope&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationScopeTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;experiment&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setIdentifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$experimentVariant&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$configurationValueRequestTransfer&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;&lt;strong&gt;Step 4: Implement the experiment assignment logic:&lt;/strong&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;c1&quot;&gt;// src/Pyz/Client/Experiment/ExperimentClient.php&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Client\Experiment&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\Client\Kernel\AbstractClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cd&quot;&gt;/**
 * @method \Pyz\Client\Experiment\ExperimentFactory getFactory()
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ExperimentClient&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractClient&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ExperimentClientInterface&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * Returns the experiment variant identifier for the current user.
     * Returns null if the user is not enrolled in any experiment.
     */&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;getCurrentUserExperimentVariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$settingKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;?string&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;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createExperimentAssigner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getVariantForUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getSessionClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;$settingKey&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;h4 id=&quot;using-ab-testing-in-yaml-schemas&quot;&gt;Using A/B Testing in YAML Schemas&lt;/h4&gt;
&lt;p&gt;Define settings that support experiment variants:&lt;/p&gt;
&lt;div class=&quot;language-yaml 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;na&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;checkout&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Checkout&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;tabs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;layout&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Layout&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;buttons&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Buttons&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;scopes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;experiment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;checkout_button_color&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Checkout Button Color&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;string&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;default_value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;blue&quot;&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;scopes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;experiment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;storefront&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
              &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;checkout_button_text&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Checkout Button Text&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;string&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;default_value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Complete&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Purchase&quot;&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;scopes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;experiment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;storefront&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In the Back Office, you can then configure different values for each experiment variant:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;experiment:control&lt;/code&gt; — &lt;code&gt;checkout_button_color: blue&lt;/code&gt;, &lt;code&gt;checkout_button_text: Complete Purchase&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;experiment:variant_a&lt;/code&gt; — &lt;code&gt;checkout_button_color: green&lt;/code&gt;, &lt;code&gt;checkout_button_text: Buy Now&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;experiment:variant_b&lt;/code&gt; — &lt;code&gt;checkout_button_color: orange&lt;/code&gt;, &lt;code&gt;checkout_button_text: Place Order&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;best-practices-for-ab-testing-scopes&quot;&gt;Best Practices for A/B Testing Scopes&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Practice&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;Consistent assignment&lt;/td&gt;
&lt;td&gt;Ensure users see the same variant throughout their session by persisting the assignment in session or database.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graceful fallback&lt;/td&gt;
&lt;td&gt;When a user is not part of an experiment, the value resolution automatically falls back to the parent scope.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setting-level experiments&lt;/td&gt;
&lt;td&gt;Pass the setting key to the assigner to run different experiments on different settings.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Analytics integration&lt;/td&gt;
&lt;td&gt;Track which variant each user sees to measure the impact of configuration changes.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;combining-multiple-custom-scopes&quot;&gt;Combining Multiple Custom Scopes&lt;/h3&gt;
&lt;p&gt;You can combine calculated scopes with static scopes to create sophisticated targeting. For example:&lt;/p&gt;
&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;experiment (most specific)
  -&amp;gt; region
    -&amp;gt; store
      -&amp;gt; global (least specific)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This hierarchy enables scenarios like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Default value for all users (global)&lt;/li&gt;
&lt;li&gt;Store-specific override (store)&lt;/li&gt;
&lt;li&gt;Region-specific customization based on IP (region)&lt;/li&gt;
&lt;li&gt;A/B test variant for users in the experiment (experiment)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When a user in the &lt;code&gt;us-west&lt;/code&gt; region is assigned to &lt;code&gt;variant_a&lt;/code&gt; of an experiment in the &lt;code&gt;US&lt;/code&gt; store, the resolution order is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;experiment:variant_a&lt;/code&gt; — check experiment-specific value&lt;/li&gt;
&lt;li&gt;&lt;code&gt;region:us-west&lt;/code&gt; — check region-specific value&lt;/li&gt;
&lt;li&gt;&lt;code&gt;store:US&lt;/code&gt; — check store-specific value&lt;/li&gt;
&lt;li&gt;&lt;code&gt;global&lt;/code&gt; — check global value&lt;/li&gt;
&lt;li&gt;&lt;code&gt;default_value&lt;/code&gt; — use schema default&lt;/li&gt;
&lt;/ol&gt;
</description>
            <pubDate>Fri, 13 Mar 2026 15:59:05 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/backend-development/configuration-management/custom-scopes.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/backend-development/configuration-management/custom-scopes.html</guid>
            
            
        </item>
        
    </channel>
</rss>
