# Welcome to Violet

We're glad you're here 💜

## What is Violet?

Violet is the easiest way to build cross platform integrations for multi-merchant checkout. You can use our 3 products in various ways. Each is meant to make it easier for you to integrate with Merchants, pass data back and forth, and simplify life for your Merchants.

{% hint style="info" %}
Our docs are AI enabled. Try asking a question using <kbd>Ctrl</kbd> + <kbd>K</kbd> (PC) or <kbd>Cmd</kbd> + <kbd>K</kbd> (Mac).
{% endhint %}

## Our products

Learn about our product offerings and see how they can help power your experience.

* [**Violet Connect**](/prism/violet-connect) – Let merchants connect their stores to you through our merchant onboarding tool.
* [**Prism**](/prism/checkout-guides) – Violet's flagship product; a Unified Commerce API that enables you to turn your experience into a fully functional marketplace.
* [**Relay**](/relay/relay) – Bidirectional access to real-time data from merchants across any integrated platform, using unified models.

## Dive Straight In

Get started quickly using our prebuilt collections.

* [**API Reference**](https://docs.violet.io/api-reference/) – Learn about our API in our interactive API reference.

## Popular Resources

Explore our most frequently used guides and tools.

* [**Getting Started**](/prism/overview) – Get started with the Violet Checkout API.
* [**FAQ**](/faqs) – Find answers to the most commonly asked questions about our API, features, and troubleshooting tips to help you resolve issues quickly.

Still unsure about whether Violet is for you?

[Book a demo](https://violet.io/meeting/bookdiscovery) to learn more about how we can work together, or read more on our [Blog](https://violet.io/blog).


# Change Log

Learn about Violet's latest integrations and features.

## 2026.08.04

#### 🆕 Features

**Shopify: Contextual Pricing for All Merchants**

Multi-currency contextual/presentment pricing is now the default configuration for all newly onboarding Shopify merchants. Previously, this was limited to specific apps.

**Beam: Automatic Contextual Pricing Registration**

Newly synced merchants are now automatically registered and opted into contextual pricing during product sync, removing a manual onboarding step.

**Feed Management: Regional Market Support**

Product feeds can now specify available markets, allowing sibling regional feeds to merge per-currency pricing and availability without overwriting each other.

#### 🔧 Fixes & Improvements

**Order Creation: Currency Override with Discounts**

Orders for merchants with an explicit order-currency override were failing when bag-level discounts were present. This has been resolved.

**Scheduled Transfers: Projection & Eligibility Fixes**

Improved the batched payout transfer projection calculation and improved the logic for determining which queued distributions are time-eligible for payout.

**Dashboard: Merchant Products Table Upgrade**

The Merchant Products page has been rebuilt with the modernized table experience, including:

* Row selection with bulk publish/unpublish actions
* Tri-state header checkbox and "select by" menu (Catalog / Page / Published / Unpublished)
* Searchable tag filter with dismissible pills
* Status filter with indicator dots matching row chip colors
* Keyboard-accessible publish/unpublish button and row activation

**Dashboard: Updated Typography & Dark Theme**

The Dashboard design system has been updated to refine dark theme surfaces with improved elevation contrast.

#### 📖 Documentation

**New: Net Receipts Payout Guide**

A new guide covers the Net Receipts payout model, including fee submission, how commission is calculated on a net-of-fee basis, merchant fee recovery, refund handling, and hold conditions. See the [Net Receipts](/prism/payments/payouts/net-receipts) documentation.

**New: Offer & SKU Deletion Behavior**

Documentation now describes what channels and merchants should expect when a source merchant deletes a SKU or Product. Deleting an individual variant permanently removes the SKU, while deleting an entire product moves the Offer to ARCHIVED status. See the updated [Offers](/prism/catalog/offers), [SKUs](/prism/catalog/skus), and [Catalog FAQ](/faqs/catalog) pages.

***

## 2026.07.28

#### 🆕 Features

**Dashboard: Payout Readiness & Transfer Batches**

Apps configured for scheduled transfers now have two new screens in the Dashboard. The Payout Readiness view shows per-merchant connection status, queued distribution totals, recent failure counts, and outstanding errors. The Transfer Batches view shows a history of completed batch runs with per-merchant breakdowns, including sent/failed status and error details. Both surfaces are available under the Payouts section when the app uses scheduled transfers.

**Shopify: Currency Override Order Submission**

Merchants configured with an order-currency override now have orders submitted to Shopify in their configured currency (e.g., EUR) while the Violet order remains in the base currency (e.g., USD). Exchange rates are captured at order creation, so refunds processed in the override currency convert accurately through the existing multi-currency path.

#### 🔧 Fixes & Improvements

**Order Search: Pagination Fix**

The order search endpoint now correctly returns results on all pages. Previously, pages near the end of the total results could return empty or throw an error.

**Rithum: Fallback Shipping Accuracy**

Fallback shipping rates now correctly evaluate order-amount thresholds when the order uses a converted currency.

**WooCommerce: Webhook Topic Filtering**

Webhook registration now respects excluded topics in sync policies, and scheduled reconciliation prunes webhooks that the policy excludes — matching the existing behavior for Shopify and BigCommerce.

**Webhooks: Correct Dispute Event Types**

Dispute webhook events now emit the correct event types, ensuring channels receive properly typed payloads for dispute-related notifications.

**Catalog API: Response Cleanup**

The catalog offers API no longer includes raw internal data in responses unless explicitly requested via the `include=offer_data` parameter. Previously, this data could be unintentionally included in some responses.

**Dashboard: Table Interaction & Accessibility Polish**

Keyboard navigation now works consistently across all dashboard table views, fixing a gap on the Transfers page. Additional refinements include the Export button anchored to the far right with a download icon, the per-page selector no longer disappearing on single-page data sets, and improved filter menu spacing.

**Performance & Reliability**

Broad infrastructure improvements across product sync, catalog, and webhook delivery reduce memory usage and improve throughput, particularly for merchants with large catalogs. These changes improve sync stability and API response times without changing any external behavior.

***

## 2026.07.21

#### 🆕 Features

**Payments: Net Receipts Commission Calculation**

Apps can now configure whether payment processing fees are deducted from the order total before commission is calculated. This "Net Receipts" setting is available as an app-level default and can be overridden per merchant. Refund reversals are fee-aware, correctly prorating the original commission when goods are partially refunded. Distributions include provenance fields showing which fee settings were applied.

**Feed Management: Made-to-Order Stock Level Support**

Spreadsheet product feeds now accept "MTO" (Made to Order) as a valid stock level. Previously, MTO entries were treated as out-of-stock. MTO products are now correctly imported as available.

#### 🔧 Fixes & Improvements

**Shopify: Contextual Pricing Country Fallback**

When contextual pricing is enabled but market discovery returns no countries, the system now falls back to all supported countries rather than failing silently. This prevents pricing syncs from breaking for merchants whose Shopify configuration doesn't expose market data.

**Beam: Order Submission Failure Notifications**

Merchants now receive order-submission-failed notifications when orders are blocked by unmapped variants during Beam order processing. Previously, these failures produced no notification.

**Dashboard: Shopware Platform Filter**

The merchant connections platform filter in the Dashboard now includes Shopware.

**Dashboard: Payouts & Distributions Table Upgrade**

The Payouts and Distributions tabs have been rebuilt with the same modernized table experience rolled out to other dashboard pages — including URL-driven filters, sortable columns, and improved pagination.

#### 📖 Documentation

**Shopify: Additional Required Access Scopes**

The Shopify integration documentation now includes read\_publications and write\_publications as required access scopes for channel app setup. These scopes enable product publishing visibility.

***

## 2026.07.14

#### 🔧 Fixes & Improvements

**Shopify: Inventory Accuracy for Tag-Force-Enabled Products**

SKUs on tag-force-enabled Shopify products with zero tracked inventory no longer incorrectly report as in stock. The availability override now respects inventory tracking. Only untracked SKUs or those with actual quantity are marked in stock.

**Catalog: Duplicate SKU Sync Resilience**

Product syncs no longer fail when a merchant's catalog contains duplicate SKU external IDs across different offers. The sync now gracefully resolves collisions by preferring the SKU attached to the offer being updated.

**Dashboard: Modernized Table Views**

The Merchants, Orders, Bags, Transactions, Transfers, and Transfer Reversals pages across both Channel and Merchant dashboards have been rebuilt with improved UX:

* URL-driven search and filters (searches and filters are now deep-linkable and survive page refresh)
* Date range pickers with presets (Today, Yesterday, Last 7 Days, Last 30 Days)
* Amount range filters on transfers and reversals
* Searchable, grouped filter menus with status indicator dots
* Sortable column headers with accessibility support
* Standardized pagination with configurable page sizes

#### 📖 Documentation

**Updated: Shopify API Scope Explanations**

The [Shopify platform guide](https://merchant-help.violet.io/platform-guides/shopify) now explains each required API scope in plain language, organized by function (Products & Inventory, Orders & Checkout, Customers, Shipping & Fulfillment, Discounts). A summary clarifies that all product, inventory, shipping, and discount scopes are read-only, and write access is limited to orders and customer records created through Violet.

***

## 2026.07.08

#### 🆕 Features

**Payments: Full Payout Account Visibility in Connection Health**

Channels can now see all of a merchant's payout accounts from the Payout Account tab in the [Connection Health](/prism/violet-connect/guides/connection-health) dashboard, rather than a single account. Accounts are grouped into a labeled section per platform connection for multi-platform merchants, and each account shows its KYC health status. Click into any account to view its details and outstanding requirements. The view is read-only and mirrors the layout merchants see in their own dashboard, keeping the experience consistent across channel and merchant.

***

## 2026.07.07

#### 🔌 Integrations

**Shopware 6: New Ecommerce Platform**

Shopware 6 is now available as a supported ecommerce platform. The integration covers product syncing, order management, direct order submission, customer sync, and real-time webhook updates. Merchants can connect their Shopware store through Violet Connect. See the [merchant onboarding guide](https://merchant-help.violet.io/platform-guides/shopware) for step-by-step setup instructions.

**Payments: Multiple Payout Account Visibility**

Channels can now view grouped payout accounts, including new multi payout account views in the Violet Dashboard, giving better visibility into merchants with more than one payout destination.

**Shopify: Metaobject Reference Flattening for All Merchants**

Shopify metaobject references in product metadata are now automatically simplified to their handle values for all merchants. Previously this behavior was limited to select merchants. Merchants whose stores don't expose metaobject data are unaffected.

#### 🆕 Features

**Payments: App-Provided Bag Transaction Fees**

Apps can now submit per-bag transaction fees through a new billing endpoint. Fees are validated against a configuration matrix that considers the merchant's payment setup, and accepted fees are persisted at the bag level. The endpoint supports idempotency and returns structured error codes for rejected submissions. See [Bag Transaction Fees](https://github.com/violetio/docs/tree/main/api-reference/orders-and-checkout/bag-transaction-fees/README.md) for details.

#### 🔧 Fixes & Improvements

**Beam: Contextual Pricing Sync for Large Catalogs**

Contextual pricing syncs no longer fail partway through for merchants with very large catalogs. Previously, these syncs could terminate before completing, leaving per-market prices stale.

**Shopify: Full Refund SKU Attribution**

Full refunds issued in Shopify without line-item detail (e.g., manual order-level refunds) are now correctly attributed to the order's SKUs. Previously these refunds arrived with no SKUs attached, which could prevent downstream settlement from processing correctly.

**Reporting: Distribution Report Exports**

Fixed an issue where distribution report exports could fail entirely. Exports now generate reliably.

**Violet Connect: Deep Links Preserved After Login**

Merchants who follow a direct link to the payments or commission rate page are now taken to that page after logging in, instead of being routed back through the onboarding flow.

**Dashboard: Expanded Platform Filter**

The merchant connections platform filter now includes Medusa, Shoplazza, and CartPanda.

#### 📖 Documentation

**New: Shopware 6 Merchant Onboarding Guide**

A full onboarding guide for Shopware 6 merchants is now available, including a granular permissions table covering exactly which API permissions the integration requires.

**Updated: Checkout FAQ**

New FAQ entries explain how refund and cancellation webhooks behave during checkout flows.

***

## 2026.06.30

#### 🔌 Integrations

**Cartpanda: New Ecommerce Platform**

Cartpanda is now available as a supported ecommerce platform. Merchants can connect their Cartpanda store through Violet Connect. See the [merchant onboarding guide](https://merchant-help.violet.io/platform-guides/cartpanda) for setup instructions.

**Shoplazza: New Ecommerce Platform**

Shoplazza is now available as a supported ecommerce platform. Merchants can connect their Shoplazza store through Violet Connect. See the [merchant onboarding guide](https://merchant-help.violet.io/platform-guides/shoplazza) for setup instructions.

**Medusa: New Ecommerce Platform**

Medusa is now available as a supported ecommerce platform. Merchants can connect their Medusa store through Violet Connect. See the [merchant onboarding guide](https://merchant-help.violet.io/platform-guides/medusa) for setup instructions.

#### 🆕 Features

**Shopify: Bundled Product Orders**

Orders containing Shopify bundle products are now fully supported, including bundle component lookup, draft order creation/completion, discount handling, and price preservation. Bundle products and variants remain purchasable during product sync even when Shopify marks them as requiring components.

**Shopify: Product Localization**

Product sync now supports fetching translated content (titles, descriptions, option names) via Shopify's Translations API. Configured per-merchant through a `syncLanguage` setting. When no language is configured, behavior is unchanged.

**Relay: Advanced Search Endpoints**

New POST search endpoints (`/relay/merchants/{id}/offers/search`, `/orders/search`, `/customers/search`) accept a JSON body for advanced filtering by query, status, date ranges, financial status, fulfillment status, and more. Existing list endpoints also now support search and filter query parameters.

**Relay: Store Info and Order Refunds**

New GET endpoints for retrieving normalized store information (`/relay/merchants/{id}/store`) and order refund data (`/relay/merchants/{id}/orders/{order_id}/refunds`) across Shopify, BigCommerce, and WooCommerce.

**Beam: Per-SKU Custom Commission Rates**

Destination Variant Mappings now support a commission rate field (0–100%) applied at the SKU level when Beam creates orders. Supports both standard and bundled mappings.

#### 🔧 Fixes & Improvements

**Address Validation: St. Barthélemy Support**

Orders shipping to St. Barthélemy now correctly resolve to ISO country code BL. Previously, various spellings of the country name (with/without accent, "St."/"Saint") caused address validation failures.

***

## 2026.06.25

#### 🆕 Features

**Payments: Automated Stripe Dispute (Chargeback) Handling**

Violet now automatically processes Stripe disputes for orders paid through Connect destination charges. When a dispute is opened, Violet evaluates whether the platform balance was actually debited and, if so, reverses the affected merchant transfer and records the corresponding ledger adjustments so balances stay accurate. When a dispute closes, the outcome is applied automatically: a win re-credits the merchant through the standard settlement pipeline, while a loss leaves the chargeback debit in place and marks the affected bags as disputed/refunded.

**Payments: Dispute Status on Payment Transactions and Bags**

Payment transactions (and their related bags) now carry a dispute status that tracks the chargeback lifecycle — `UNDISPUTED`, `IN_DISPUTE`, `DISPUTE_WON`, and `DISPUTE_LOST` — giving channels visibility into where a disputed payment stands.

**Webhooks: New Dispute Events**

Channels can now subscribe to dispute lifecycle webhooks: `PAYMENT_TRANSACTION_DISPUTE_OPENED`, `PAYMENT_TRANSACTION_DISPUTE_WON`, and `PAYMENT_TRANSACTION_DISPUTE_LOST`, plus an `ORDER_DISPUTED` event fired the first time any payment on an order is disputed. The event payload includes dispute details such as the disputed amount, Stripe reason code, dispute fee, and evidence submission deadline.

#### 📖 Documentation

**New: Handling Disputes Guide**

A new channel-facing guide explains how the dispute lifecycle maps to the order and payment‑transaction model — the dispute statuses, what each stage means for merchant funds, dispute fees, and what channels need to do. See [Handling Disputes](/prism/payments/disputes).

**New: Dispute Webhooks Reference**

A new webhook events reference covers the dispute lifecycle events — `PAYMENT_TRANSACTION_DISPUTE_OPENED`, `PAYMENT_TRANSACTION_DISPUTE_WON`, `PAYMENT_TRANSACTION_DISPUTE_LOST`, and `ORDER_DISPUTED` — including triggers, headers, and integration patterns. See [Dispute Webhooks](/prism/webhooks/events/dispute-webhooks).

***

## 2026.06.23

#### 🔌 Integrations

**Saleor: New Ecommerce Platform**

Saleor is now available as a supported e-commerce platform. Merchants can onboard via credential-based authentication using an App Token and optional Channel Slug. See the [merchant onboarding guide](https://merchant-help.violet.io/platform-guides/saleor) for setup instructions.

#### 🆕 Features

**Merchant Configuration Resource Endpoints**

Individual merchant configuration sections — shipping settings, shipping methods, inventory location filters, catalog rules, and catalog settings — are now available as first-class REST resources under `/merchants/{merchant_id}/*`. These endpoints support granular reads and updates without needing to fetch or overwrite the full configuration object.

#### 🔧 Fixes & Improvements

**Shopify: Clearer Error for Restricted Product Shipping**

When a Shopify merchant's Merchant of Record settings prevent shipping restricted products to a given address, the API now returns a clear message ("This merchant does not ship the selected item(s) to the provided shipping address.") instead of surfacing the raw Shopify error.

**Beam: False Shipping Reconciliation Adjustments**

Fixed an issue where pre-transfer shipping reconciliation could incorrectly adjust bags that had legitimate merchant-provided shipping rates. Only bags with placeholder shipping are now adjusted.

**Feeds: Vendor Fallback for Google Product Feeds**

When processing Google Product feeds, the offer vendor field now falls back to the merchant name when the feed item's brand is absent, consistent with CSV feed behavior.

#### 📖 Documentation

**New: Global-E x Shopify Guide**

A new guide explains how Global-E works on Shopify storefronts, why Violet orders bypass Global-E's checkout and Merchant of Record coverage, and recommended merchant configuration. Includes FAQs covering order creation, checkout routing, onboarding, reporting, and tax liability.

**New: Stripe Dashboard Transfers Guide**

A new channel-facing guide walks through creating transfers to connected Stripe accounts directly from the Stripe Dashboard, covering both the Balances page and Connected Account detail page methods.

**Clarification: Estimate Order Response Totals**

The Estimate Order docs now clarify that total, tax\_total, shipping\_total, and sub\_total are always populated on a successful response and can only be null when an error occurs.

**New: Discount Email Field in Order Estimate/Create Examples**

OpenAPI examples for POST /orders/estimate and POST /orders now show how to include an email field with discount objects.

***

## 2026.06.18

#### 🔌 Integrations

**SAP Commerce Cloud: New Ecommerce Platform**

SAP Commerce Cloud is now available as a supported ecommerce platform. Merchants on SAPCC can connect their stores through Violet Connect using a guided credential-based onboarding flow; entering their Client ID, Client Secret, and Base Site ID. Product sync, order handling, and webhook processing are fully supported. See the [merchant onboarding guide](https://merchant-help.violet.io/platform-guides/sap-commerce-cloud) for setup instructions.

**Dashboard: New Platform Support**

Oracle Commerce Cloud and SAP Commerce Cloud now appear in the dashboard's merchant connections platform filter with branded icons, making it easy to find and manage merchants on these platforms.

#### 🆕 Features

**Shopify: Combined Listings Support**

Shopify combined-listing products are now fully supported during product sync. Parent products are mapped to their underlying purchasable child variants while preserving merchandised pricing, options, and media. Child products are suppressed as standalone offers to prevent duplicate listings.

**Shopify: Metaobject Reference Metafields**

Product sync now resolves Shopify metaobject reference metafields across all sync paths. This requires new Shopify scopes, `read_metaobjects` and `read_metaobject_definitions`, which have been added to the required scopes documentation.

**Dashboard: Fulfillment Tracking for All Merchants**

Fulfillment tracking controls (add and edit) are now available in the dashboard for all merchant platforms. Previously, tracking management was limited to manual merchants only.

**Beam: Custom Shopify Line Items in Mixed Orders**

Beam orders that include custom Shopify line items (non-Beam products without variant IDs) are now accepted instead of being rejected as invalid mixed orders. This supports merchants who add custom charges or products alongside Beam-managed line items.

#### 🔧 Fixes & Improvements

**Payments: Improved Bank Statement Descriptors for Cross-Border Merchants**

Stripe payment intents now use the connected account's `card_payments` capability as the primary signal for `on_behalf_of` eligibility. This means more merchants, especially cross-border Express Connect accounts, will correctly show their own business name on customer bank and card statements instead of the channel's name. For accounts where capability data hasn't been synced yet, eligibility has been broadened to include Express accounts in any of the platform's supported transfer countries, not just same-country matches.

{% hint style="info" %}
The connected merchant account is not always eligible to be the settlement merchant. When a connected account lacks the `card_payments` capability — for example, accounts in countries where Stripe does not support card processing, or accounts that have not completed onboarding — `on_behalf_of` cannot be set. In these cases, the payment is settled through the platform account and the platform's statement descriptor will appear on the customer's bank or card statement instead of the merchant's. This is a Stripe Connect constraint; see Stripe's [Connect charges documentation](https://docs.stripe.com/connect/charges) for details on settlement behavior and capability requirements.
{% endhint %}

**Shopify: Managed Markets Cart Calculation**

Cart calculation for Shopify merchants using Managed Markets (Global-e) with restricted products no longer fails. When the Admin API encounters a merchant-of-record restriction, calculation automatically falls back to the Storefront API, which handles restricted products through the buyer-facing checkout flow.

**Wix: Product Option Name Fix**

Colons in Wix product option names (e.g., `Location:`) no longer corrupt variant data. Option names are now sanitized to prevent delimiter collisions during the product decomposition-to-checkout round-trip.

***

## 2026.06.11

#### 🔌 Integrations

**Oracle Commerce Cloud: New Ecommerce Platform**

Oracle Commerce Cloud is now available as a supported ecommerce platform. Merchants on Oracle CC can connect their stores through Violet Connect and begin selling through Violet-powered channels. See the [developer guide](/ecom-platforms/oracle-commerce-cloud) for integration details and the [merchant onboarding guide](https://merchant-help.violet.io/platform-guides/oracle-commerce-cloud) for setup instructions.

#### 🆕 Features

**Beta: Custom Commission Rates on Direct Order Submission**

You can now set custom commission rates at the bag level or individual SKU level when creating orders through [Direct Order Submission](/prism/checkout-guides/guides/custom-commission-rates). This gives channels granular control over commission on a per-order basis — useful for promotional orders, product-line-specific rates, or partner arrangements. This feature is currently in beta.

***

## 2026.06.09

#### 🔧 Fixes & Improvements

**EcomSync: Shoptet Custom Domain Merchant ID Collision**

Fixed a merchant `externalId` collision that occurred when Shoptet merchants used custom domains. Registration now enforces the canonical Shoptet project-URL pattern, and `externalId` derivation has been hardened to always resolve to the stable project identifier regardless of domain configuration.

**Null Serialization for Cart Totals and Order Monetary Fields**

Calculated cart totals that are `null` are now included in serialized responses, preventing client-side null-pointer errors when totals haven't been computed yet. Order monetary fields are always serialized even when `null`, ensuring downstream consumers receive a consistent response shape regardless of order state.

#### 📖 Documentation

**New: SAP Commerce Cloud Onboarding Guide**

A full onboarding guide for SAP Commerce Cloud (SAPCC) merchants is now available in the docs. Covers plugin setup, authentication, and common configuration steps.

**New: WooCommerce Shipping Extension Callout**

The WooCommerce onboarding guide now includes a callout explaining the shipping extension requirement and when it applies.

**Expanded: Supported Platforms List**

The supported ecommerce platforms list in the channel documentation has been expanded and updated to include all available integrations. Previously this could only be found in the merchant documentation.

**Updated: Shopify Permanent Domain Requirement**

The Shopify integration docs now explicitly call out that a permanent (`.myshopify.com`) domain is required at registration time, clarifying a common source of onboarding confusion when merchants added a vanity handle.

***

## 2026.06.02

#### 🆕 Features

**Beam: Reverse Shopify Fulfillment Sync**

Fulfillments created directly in a destination Shopify store are now automatically synced back to Violet. When a Beam user fulfills an order in Shopify, Beam detects the fulfillment via webhook and writes it back to the corresponding Violet order, closing the loop for multi-channel fulfillment workflows.

**Beam: Order Submission Failure Email Notifications**

Beam order submission failure notifications are now delivered via email in addition to the existing dashboard notification. App owners and org collaborators receive an email with a descriptive subject line, the Shopify order name, and a direct link to the affected order in the Shopify admin. Email delivery failures are logged but do not block the main notification flow.

#### 🔧 Fixes & Improvements

**WooCommerce: Cart Calculation Fallback**

WooCommerce cart calculations now degrade gracefully when the merchant's plugin endpoint is unavailable (401, 404, 500, or network failure). On checkout totals failure, the subtotal is computed locally. On shipping rate failure, configured fallback shipping methods are applied with currency conversion. This prevents cart estimation from failing entirely due to transient plugin issues.

**Beam: Contextual Pricing Sync Resilience**

Improved reliability of contextual pricing syncs for merchants with large catalogs. Syncs now support a `PARTIAL_SUCCESS` status when some price updates succeed while others are throttled, GraphQL throttle retries are more patient (6 attempts vs. 3), and long-running batches no longer time out prematurely. Additionally, variant refresh workflows no longer fail when contextual pricing context setup encounters an error — the refresh proceeds and pricing is applied on a best-effort basis.

**Dashboard: Shopify Order Name in Beam Notifications**

Beam order failure notifications in the dashboard now display the Shopify order name (e.g., #1001) instead of the internal Shopify order ID, making it easier for merchants to identify the affected order at a glance. The deep link to the Shopify admin still functions correctly.

**Dashboard: Beam Notification Layout & Dropdown Fixes**

Improved the layout of Beam error notifications by repositioning the Shopify link icon and removing unnecessary indentation. Fixed an issue where dropdown menus in the Beam mappings view could clip at viewport edges — menus now use viewport-aware positioning and flip above the trigger when needed.

***

## 2026.05.26

#### 🔧 Fixes & Improvements

**Shopify: Offer Availability Consistency**

Fixed a data inconsistency where the `available` flag on an offer could disagree with the offer's `status` when an enabled-tag rule forces availability. The `available` flag now correctly mirrors the status override, ensuring integrations that rely on either field get consistent results.

**Shopify: Honor Sale Price Sync Setting for Contextual Prices**

The merchant-level `shouldSyncSalePrice` setting is now correctly applied to per-market contextual prices. Previously, merchants who disabled sale-price syncing would still see sale prices on their contextual (multi-currency) pricing entries. Contextual sale prices are now set equal to the retail price when the setting is disabled, matching existing base-SKU behavior.

**Beam: Contextual Pricing Sync Fallback Resolution**

Contextual pricing syncs now use a three-tier fallback lookup to resolve source SKUs to destination Shopify variants. This ensures per-market prices sync correctly even when offer metadata contains only external IDs without complete Violet SKU mappings.

**Beam: "View in Shopify" Link on Order Failure Notifications**

Order failure notifications in the Violet Dashboard now include a "View in Shopify" link that opens the affected order directly in the Shopify admin, making it faster for merchants to investigate and resolve submission failures.

**Dashboard: Merchants Table Scroll Fix**

Fixed a layout issue where the merchants table in the Violet Dashboard could exhibit unexpected scroll behavior, improving the browsing experience when managing merchant connections.

**Dashboard: Overview Card Readability**

Adjusted font sizes and added text overflow handling on the analytics overview cards to prevent large values from overflowing and improve visual consistency.

**Dashboard: Beam Component Styling**

Fixed broken button and component styles in the Beam UI by migrating to the Petals design system tokens, ensuring visual consistency across the dashboard.

#### 📚 Documentation

**Oracle Commerce Cloud: Onboarding Guide**

Added a new [Oracle Commerce Cloud onboarding guide](https://merchant-help.violet.io/platform-guides/oracle-commerce-cloud) with step-by-step setup instructions covering server-side integration registration, store URL configuration, credential provisioning, and security considerations including token expiration and permission requirements.

***

## 2026.05.19

#### 🔌 Integrations

**Miva: New Ecommerce Platform**

Miva is now available as a supported ecommerce platform. Merchants can connect their Miva store through Violet Connect by providing their API Token, Signing Key, Store Code, and Store URL. The integration covers catalog syncing, order management, and customer data access through the Miva JSON API. See the [Miva onboarding guide](https://merchant-help.violet.io/platform-guides/miva) for step-by-step setup instructions.

#### ⚡ Performance

**Catalog: Lightweight Merchant Offers Endpoint (v1.1)**

A new `GET /offers/merchants/{merchant_id}/v1.1` endpoint is available that returns offer data without eagerly loading SKUs, variants, or albums. This significantly reduces payload size and response time for integrations that only need offer-level metadata — such as dashboard views or listing pages.

What's changed:

* The new endpoint supports the same filtering, pagination, and currency parameters as the existing endpoint.
* Maximum page size is 100.
* Use this endpoint when you only need offer-level fields (name, price, merchant, status) and do not need nested SKU, variant, or album data.

#### 🔧 Fixes & Improvements

**Shopify: Cart Resilience When Variant Access Is Denied**

Cart calculations for Shopify merchants now handle cases where variant data is unavailable due to revoked access scopes. Instead of failing silently, the system uses fallback SKU matching (exact, substring, positional) and surfaces a clear error indicating that the merchant has revoked a necessary scope.

**WooCommerce: Clean WPBakery Descriptions**

Product descriptions from WooCommerce merchants using the WPBakery page-builder theme are now cleaned of raw shortcode markup before being exposed in the catalog. Shortcodes like `[vc_row]` that previously rendered as visible text in product descriptions are now stripped automatically.

**Dashboard: Shoptet Platform Filter**

Shoptet now appears as a filterable platform option in the Violet Dashboard's merchant connections view, making it easier to locate and manage Shoptet merchant integrations.

**Dashboard: UX Theme Improvements**

The Violet merchant and channel dashboards have been updated with UX theme improvements for a more polished and consistent visual experience.

#### 📚 Documentation

**Shoptet: Standard Tier XML Feed Instructions**

Updated the Shoptet Standard Tier guide with detailed instructions for creating the required XML product feed, including an XML template example and security configuration steps.

***

## 2026.05.12

#### 🔌 Integrations

**Lightspeed: New Ecommerce Platform**

Lightspeed eCom is now available as a supported ecommerce platform. The integration covers catalog syncing, order estimation, direct order submission, and full order lifecycle events. Merchants can connect their Lightspeed store through Violet Connect — see the [Lightspeed onboarding guide](https://merchant-help.violet.io/platform-guides/lightspeed) for setup instructions.

**Shoptet: Standard Tier**

Shoptet merchants who do not have access to the Shoptet Private API can now connect to Violet using the new Standard tier. Standard tier merchants provide a Google Product Feed URL instead of a Private API token, and Violet syncs their catalog through the feed. During the Violet Connect onboarding flow, Shoptet merchants are presented with a tier selector to choose between Premium (API token) and Standard (product feed).

#### 🆕 Features

**Distributions: Duty Totals**

Distribution records now include duty tracking fields, extending the duty support [introduced on Orders and Bags on April 22nd](#2026.04.22). New `bag_duty_total`, `duty_amount`, and `duty_remitter` fields are available on Distribution responses, mirroring the existing tax tracking pattern. Duty is treated as a non-commissionable pass-through cost retained by the merchant by default.

Who this impacts:

* Channels that inspect distribution records for payout reconciliation. No action required — this is an additive change and existing integrations will continue to work without modification.

**Beam: Order Submission Failure Notifications**

A new Beam Order Submission Failed notification type is now available for Beam users. When a Shopify-to-Violet order submission fails, a notification is generated with a descriptive failure reason so operators can quickly identify and resolve the issue.

**Beam: Broken SKU Mapping Notifications**

A new Beam Broken SKU Mapping notification type is now available for Beam users. When a destination variant mapping is marked as broken, whether due to a SKU deletion by the source merchant or a product/variant deletion in the destination Shopify store, a notification is generated with a "View mapping" action that deep-links directly to the affected mapping in the Violet Dashboard.

#### 🔧 Fixes & Improvements

**API: Correct 404 Responses for Invalid Paths**

Requests to API paths that do not exist now correctly return a `404 Not Found` response instead of an unexpected `5xx` server error. This applies to all invalid or unrecognized URL paths across the API. No changes are needed for existing integrations — this only affects requests to endpoints that were never valid.

***

## 2026.05.06

#### 🔧 Fixes & Improvements

**Billing: Payout Webhook Processing Resilience**

Improved how Violet processes incoming Stripe payout webhooks for merchants connected through Stripe Connect, ensuring payouts are reliably attributed to the correct merchant account in the Violet Dashboard.

Previously, a small number of merchant payouts could be misattributed or silently dropped during processing, which in some cases caused payouts that had successfully landed at Stripe to not appear in a merchant's Violet payout history.

What's changed:

* Incoming payout events are now consistently matched to the originating merchant account, regardless of which webhook endpoint Stripe delivered to.
* Previously misattributed payout records will automatically self-correct the next time Stripe sends a follow-up event for that payout (for example, when the payout transitions to `paid`). No manual intervention or backfill is required.
* Internal Stripe API calls made while processing payout events now use the correct, connection-scoped credentials, improving reliability for channels that manage their own Stripe Connect credentials.

Merchants and channels do not need to take any action — payouts will continue to flow through normally, and any historical records affected by the prior behavior will reconcile themselves as new events arrive.

***

## 2026.05.05

#### ⚡ Performance

**Catalog: Offer Search Performance Improvements**

Several optimizations have been made to Offer Search to improve overall performance.

#### 🔧 Fixes & Improvements

**VioletConnect: OAuth State Preservation**

Fixed an issue where platform OAuth `state` parameters (Shopify, Square, etc.) could overwrite the channel's original callback state during the merchant connection flow. Channels that pass a custom `state` value when linking merchants to Violet Connect will now correctly receive that value back unchanged after the merchant completes authorization.

#### 📚 Documentation

**Orders: Estimate & Create Endpoint API Reference**

Improved the API Reference for the Estimate Order and Create Order endpoints with more accurate property definitions, clarifying which fields are required and which are optional in both requests and responses.

**Magento 2: Plugin v1.4.5**

Released [version 1.4.5](https://packagist.org/packages/violetio/magento2#1.4.5) of the Violet Magento 2 extension with improved order handling. The plugin now gracefully falls back to the shipping address when the billing address is missing from an order, preventing order write failures for merchants whose storefronts do not collect separate billing details.

***

## 2026.04.29

#### 🔧 Fixes & Improvements

**Dashboard: Merchant Summary Card Offer Counts**

Fixed an issue where the merchant summary cards in the Violet Dashboard displayed identical values for the total and published offer counts. The total count was previously fetched using an offer search that only returned published offers, so unpublished offers were never reflected.

Total and published counts will now correctly differ for merchants with unpublished offers.

**Catalog: Offer Search Visibility Filtering**

The `POST /catalog/offers/search` endpoint no longer applies a default visibility filter. Previously, the deprecated `exclude_hidden` query parameter defaulted to `true`, which silently filtered out all offers with `visible=false` — a common source of empty results for channels using test or private Shopify storefronts.

What's changed:

* By default, all offers are now returned regardless of their `visible` value.
* Use the `visible` field in the request body to filter explicitly: `true` for visible offers only, `false` for hidden offers only, or omit it entirely for no filter.
* The `exclude_hidden` query parameter is deprecated but still supported for backwards compatibility. If passed explicitly as `true`, it continues to filter out hidden offers.

Why offers may have `visible=false`:

* The merchant's store has no public online store URL configured (common for test stores)
* The product has not been published to the merchants storefront.

#### 📚 Documentation

**Catalog: Offer Search — Visibility Filtering Guide**

Added a new [Filtering by Visibility](/api-reference/catalog/offers/search-offers#filtering-by-visibility) section to the Offer Search endpoint docs explaining how `visible=false` offers are created during ingestion, when you might encounter them, and how to use the `visible` request body field to control filtering.

***

## 2026.04.28

#### 🆕 Features

**VioletConnect: Account Confirmation Flow**

The VioletConnect login and signup flow now includes account confirmation steps to prevent accidental account creation. When a user enters their email, the system checks whether an account already exists and routes them to the appropriate confirmation screen before proceeding:

* **New accounts** — Users who enter an unrecognized email are shown a confirmation prompt ("Create a new account?") before a verification code is sent. They can choose to continue or use a different email.
* **Existing accounts** — Users who enter an email tied to an existing account are prompted to sign in instead, reducing duplicate account creation.

This adds a lightweight safeguard without changing the overall authentication experience.

#### Improvements

**Catalog: Offer Search Maintenance Mode**

The Offer Search endpoints (`POST /offers/search` and `POST /offers/search/v1.1`) now return an HTTP `503 Service Unavailable` response when Elasticsearch is undergoing maintenance, instead of returning an unexpected error. The response body includes:

| Field     | Value                                          |
| --------- | ---------------------------------------------- |
| `error`   | `maintenance_mode`                             |
| `code`    | `9914`                                         |
| `message` | `Service is currently undergoing maintenance.` |

Channels can use the `9914` error code or `maintenance_mode` error type to detect this condition and display an appropriate message to end users while search is temporarily unavailable.

#### 📚 **Documentation**

**Magento 2: Composer 2 Requirement**

Updated the [Magento 2 installation guide](https://github.com/violetio/docs/blob/main/channel-docs/ecom-platforms/magento/README.md) to note that **Composer 2 is now required**. Composer 1 has been deprecated by Packagist and can no longer be used to install packages. The Packagist install command has also been pinned to version `1.4.3` of the Violet extension.

**PrestaShop: Version 1.7 Requirement**

Updated the [PrestaShop installation guide](https://merchant-help.violet.io/platform/prestashop) to note that **PrestaShop 1.7 or later is required**. Earlier versions of PrestaShop are not supported by the Violet plugin.

#### 🔌 Integrations

**Shoptet: New Ecommerce Platform**

Shoptet is now available as a supported ecommerce platform. Merchants can connect their Shoptet store to Violet by generating a Private API Token and providing it through Violet Connect. See the [Shoptet onboarding guide](https://merchant-help.violet.io/platform-guides/shoptet) for setup instructions.

#### 🔧 Fixes & Improvements

**VioletConnect: OAuth State Preservation**

Fixed an issue where platform OAuth `state` parameters (Shopify, Square, etc.) could overwrite the channel's original callback state during the merchant connection flow. Channels that pass a custom `state` value when linking merchants to Violet Connect will now correctly receive that value back unchanged after the merchant completes authorization.

**Analytics: Distribution Report Exports**

Resolved an issue with the analytics tooling that prevented the exporting of distribution reports. Exports now generate and download as expected.

***

## 2026.04.22

#### 🆕 Features

**Duty Total on Orders and Bags**

A new `duty_total` field is now returned on all Order and Bag responses, giving you explicit visibility into duty charges on your orders.

What's changed:

* A new `duty_total` field (in cents) is available on the **Order** and **Bag** objects.
* If you include `DUTY`-type rates on your Order SKUs, the system will automatically calculate and populate `duty_total` from those rates.
* You can also set `duty_total` directly on a Bag when submitting an order. If both a `duty_total` value and `DUTY`-type SKU rates are provided, the computed value from the rates takes precedence.
* The `total` field now includes duties in its calculation: `sub_total + shipping_total + tax_total + duty_total - discount_total`.

What this fixes:

* Previously, `DUTY`-type rates on Order SKUs were not reflected in any total field. Duty amounts were accepted on line items but silently excluded from `tax_total` and `total`, which could result in customers being under-charged. With this change, duties are tracked in their own dedicated field and correctly included in the order total.

Who this impacts:

* No action required. This is an additive change — existing integrations will continue to work without modification.
* Historical orders will return `null` for `duty_total` since this field was not tracked previously.
* New orders that do not include duties will have `duty_total` set to `0`.

***

## 2026.04.21

#### 🆕 Features

**Offer Webhooks: Consistent Payload Data**

Offer webhook payloads now consistently include `trade_compliance` data, Offer `data`, and SKU `metadata`. Previously, these fields could be missing or inconsistently populated.

Who this impacts:

* Channels consuming offer webhooks for international commerce. No integration changes needed, payloads are now reliably complete.

**Magento: Custom Violet Cart Endpoints**

When a Magento merchant has the latest version of the Violet extension installed, checkout now uses custom Violet cart endpoints for billing address, shipping estimation, and cart management, improving reliability.

Who this impacts:

* Channels with connected Magento merchants running the latest Violet extension. No integration changes needed, this applies automatically.

**Merchant Dashboard: Account Creation Confirmation**

The Merchant Dashboard now includes an account creation confirmation step when a user attempts to log in with an email that doesn't have an existing account. Previously, a new account would be created automatically, which could prevent users from correcting a mistyped email for their merchant account.

#### 🔧 Fixes & Improvements

**Shopify: Duplicate Order Prevention**

Fixed a rare race condition during retries that could create duplicate Shopify orders. A pre-order submission deduplication lookup now prevents resubmission.

**Payment Transfer Reliability**

* Fixed a bug where merchant transfers that encountered a temporary error would get permanently stuck and never retried during scheduled processing. Affected merchants will now automatically be retried on the next scheduled processing cycle.
* Resolved an issue where high transfer volume could cause transfers to exhaust retries and fail permanently due to contention on Stripe's side. Transfers under load now back off and recover correctly.

**Stripe Statement Descriptors**

Fixed statement descriptors on payouts for certain Stripe Connect account configurations where the descriptor was being truncated or composed incorrectly.

**Refunds**

Fixed two scenarios where refund records were not being correctly associated with the originating payment connection, which could cause inconsistencies in payout reporting.

**Stripe Account Onboarding**

Fixed an issue with Stripe platform account resolution during merchant onboarding that could cause the onboarding flow to fail.

**Merchant Dashboard: Payout Account Display**

Channels no longer see a broken state for merchant payout accounts that haven't completed the new onboarding flow yet.

***

## 2026.04.14

#### 🆕 Features

**Shopify: Contextual Pricing Expanded to 23 Countries**

Contextual pricing for Shopify merchants now supports 23 countries, up from the previous 5. When a SKU's local price isn't available in the requested currency, the system will automatically attempt EUR fallback resolution before defaulting to the base price.

What's changed:

* Contextual pricing now covers 23 countries (previously 5).
* EUR fallback resolution is applied when a direct currency match isn't available.

Who this impacts:

* Channels using [Contextual Pricing](/prism/catalog/contextual-pricing) with Shopify merchants. No integration changes needed — the expanded country support applies automatically.

**Swell: Discount Support & Order Cancellation**

The Swell integration now supports discount codes during checkout and order cancellation. Channels connected to Swell merchants can apply discount codes in Estimate Cart and Create Order flows, and cancel orders post-submission.

What's changed:

* Discount codes (fixed and percentage) are now supported in Swell checkout flows via the [Estimate Cart](https://docs.violet.io/api-reference/order-service/checkout-pricing/estimate-cart) and [Create Order](https://docs.violet.io/api-reference/order-service/orders/create-order) APIs.
* Order cancellation is now available for Swell orders.

Who this impacts:

* Channels with connected Swell merchants. If you are already using discount codes with other platforms, the same flow now applies to Swell.

**Magento: Shipping & Cart Reliability Improvements**

Several improvements to the Magento integration's checkout reliability:

* **Proactive shipping method estimation** — Orders now estimate shipping methods upfront, reducing failures caused by unsupported carrier configurations.
* **Shipping method fallback** — When Magento rejects the requested carrier (e.g. flatrate), the system falls back to the bag-level shipping method rather than failing the order.
* **Unavailable SKU detection** — SKUs that are out of stock or unavailable are now flagged during cart calculation instead of failing silently at order submission.
* **Guest cart cleanup** — Magento guest carts are now properly deleted after cart calculation and on order submission failure, preventing orphaned carts from accumulating.

Who this impacts:

* Channels with connected Magento merchants. No integration changes needed — these improvements apply automatically to all Magento checkout flows.

**Catalog Feeds: File Upload Blocked for URL-Synced Feeds**

Merchants with an active URL-synced catalog feed are now prevented from uploading feed files manually. This avoids conflicts between the two sync methods and ensures the URL-synced feed remains the source of truth.

What's changed:

* File upload via the [Catalog Feeds API](https://merchant-help.violet.io/feeds/upload-feed) is now blocked when a merchant has an active URL-synced feed.

Who this impacts:

* Channels or merchants using the Catalog Feeds API with URL-synced feeds. If you need to switch to file-based uploads, remove the URL-synced feed first.

#### 📚 **Documentation**

* Added a new [PrestaShop Required Scopes](https://merchant-help.violet.io/platform-guides/prestashop/prestashop-scope-reasons) documentation page explaining the specific API scopes required by the Violet PrestaShop integration and why each scope is needed.

***

## 2026.04.08

#### Bug Fixes

**Iterative Checkout (Non-DOS): Wallet Payment Intent Amounts with Price Overrides**

Resolved a cart-total caching issue in iterative checkout (non-DOS) that could cause missing or incorrect wallet payment intent amounts for users applying price overrides.

***

## 2026.04.01

#### Improvements

**Multi-Platform Payout Account Health**

The Merchant Connection Health system now evaluates payout account health across all payment platforms a merchant is connected to, not just their primary platform. This gives channels a more complete picture of a merchant's payout readiness.

* **Channel Dashboard** — The Connection Health tab on the Merchants page now displays payout account status per payment platform, so channel operators can see exactly which platform connections need attention.
* **API** — The Connection Health endpoints in the Operations Service now return per-platform payout health data.

{% hint style="info" %}
**Note**: This is only applicable iffor multi-platform payments enabled channels.
{% endhint %}

**Dashboard: Empty States for Financial Pages**

The Payouts, Distributions, Transfers, and Transfer Reversals pages in the Channel Dashboard now display informative empty states when no data is available, replacing blank pages with clear messaging.

#### Bug Fixes

* Improved reliability of queued distribution processing.

***

## 2026.03.31

#### New

**Violet Connect: Redesigned Platform Selection**

We've redesigned the platform selection screen to make it easier to find and connect your e-commerce platform.

* **Search** — Quickly find your platform by typing its name. Results are sorted by relevance so the best match always appears first.
* **Most Frequent** — The most popular platforms (Shopify, BigCommerce, WooCommerce, and Wix) are now featured at the top for one-click access.
* **All Platforms** — Browse every supported platform in an alphabetical list, each showing its name and logo side by side.
* **Keyboard and screen reader improvements** — The entire selection flow is now fully navigable by keyboard with improved screen reader support.

#### Integrations

* Location-filtered inventory checks for Shopify: Order submission and cart calculation now respect merchant-configured inventory locations, preventing overselling across warehouses.

**Shopify: Faster, More Reliable Product Sync with Bulk Operations**

Shopify product synchronization now uses [Shopify's Bulk Operations API](https://shopify.dev/docs/api/usage/bulk-operations), replacing the previous per-product paginated approach. This is a behind-the-scenes infrastructure change — no API or integration changes are required on your end.

For merchants with catalogs of 250+ products, product syncs are now submitted as a single bulk operation to Shopify, which processes the entire catalog server-side and returns results as a streaming download.

* **Significantly faster syncs** — Large catalogs that previously took hours now complete in minutes. A 5,000-product catalog now often syncs in under 20 minutes.
* **Improved reliability** — Syncs are orchestrated as durable workflows that automatically resume from where they left off if interrupted. Built-in retry logic handles transient network failures gracefully.
* **Reduced rate limit pressure** — A full catalog sync now requires a handful of API calls instead of hundreds, virtually eliminating rate limit bottlenecks.

All existing sync endpoints and webhooks behave identically. Merchants with smaller catalogs (under 250 products) continue to use the existing paginated sync.

***

## 2026.03.11

#### New

**Merchant Dashboard: Fallback Shipping Rate Configuration**

Merchants can now self-manage fallback shipping rates directly from the Merchant Dashboard. Fallback rates are returned by Violet during cart calculation when a merchant's e-commerce platform does not provide shipping methods. Previously, this configuration required manual intervention by the Violet team.

The new Shipping Configuration page supports:

* **Multiple fallback methods** — Define any number of shipping options with a label, description, price, currency, handle, and calculation type (`PER_ORDER` or `PER_ITEM`)
* **Conditional applicability** — Scope each method to specific countries (allowlist or blocklist), order amount ranges (min/max in cents), weight ranges (min/max with unit selector for LB, KG, or OZ), and offer IDs (allowlist or blocklist)
* **External shipping controls** — Toggle switches to exclude external free shipping methods or exclude all external shipping methods entirely (with a warning banner when the latter is enabled)

The underlying `shipping_config` object is stored within `MerchantConfiguration` and is surfaced on the merchant configuration API endpoints.

#### Improvements

**Merchants: Self-Service Email Change**

Merchant portal users can now request an email address change directly from their account settings. This workflow was previously only available to channel users.

#### Integrations

* The Square (`SQUARE`) integration is now available for all channels. Please reach out to your Violet account representative if you are interested in having this platform enabled for your app(s). *Square does provide realtime taxes but not realtime shipping rates. Square merchants can instead create their shipping rates using the above mentioned Shipping Configuration feature. The shipping rates they create will be surface when estimating orders for that merchant.*

***

## 2026.02.17

#### New

**Catalog: SKU Trade Compliance**

A new `trade_compliance` property has been added to SKUs, enabling merchants to store trade and customs compliance data directly on their inventory items. The `trade_compliance` object includes the following fields:

| Field                     | Type                       | Description                                                                                       |
| ------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------- |
| `harmonized_system_code`  | `string` (max 15 chars)    | The default Harmonized System (HS) code for the SKU, used for international tariff classification |
| `country_code_of_origin`  | `string` (2-char ISO code) | The ISO 3166-1 alpha-2 country code where the product originates                                  |
| `province_code_of_origin` | `string` (max 6 chars)     | The province or state subdivision code within the country of origin                               |

The `trade_compliance` property is returned as a nested object on all SKU responses across existing SKU endpoints. When updating a SKU via the offer sync flow, omitting `trade_compliance` (i.e., sending `null`) preserves the existing trade compliance data.

**Orders: Trade Compliance on Estimated Cart SKUs**

When estimating a cart or order, each SKU in the response may include a `trade_compliance` object containing international trade classification data sourced from the product catalog. This surfaces customs and origin information at the cart level, enabling downstream consumers to handle duties, tariffs, and cross-border requirements before order submission.

The `trade_compliance` object on estimated cart SKUs includes:

| Field                     | Type     | Description                                                                   |
| ------------------------- | -------- | ----------------------------------------------------------------------------- |
| `harmonized_system_code`  | `string` | The Harmonized System (HS) code used for international customs classification |
| `country_code_of_origin`  | `string` | ISO country code where the product was manufactured or produced               |
| `province_code_of_origin` | `string` | Province or state code within the country of origin                           |

The `trade_compliance` object is only present when the catalog SKU has trade compliance data configured. If the SKU has no trade compliance data, the field is omitted from the response.

## 2026.02.11

#### Bug Fixes

**Stripe Payout Eligibility Validation**

Fixed an issue where merchants could encounter errors during payout account setup when their banking country was incompatible with their app's payout configuration. Merchants now receive clearer feedback during the banking setup process.

***

## 2026.02.08

#### New

**Documentation: Catalog Feeds API**

Added comprehensive documentation for the [Catalog Feeds API](https://merchant-help.violet.io/feeds/feeds-overview) in the Merchant docs. Includes endpoints for uploading and retrieving feeds, XML format specification, inventory feed examples, and API credential management.

***

## 2026.01.30

#### Improvements

**Dashboard: Custom Properties on Order Line Items**

The Bag details view in the Channel and Merchant Dashboards now displays custom properties for order line items. This enhancement provides visibility into SKU-level customizations such as engraving text, gift messages, or other merchant-defined attributes that were previously only accessible via API.

**Bahrain (BH) Added to Postal Code Exempt Countries**

Bahrain (BH) has been added to the list of countries that do not require a postal code during checkout. See [Customers](/prism/checkout-guides/carts-and-bags/customers) for the complete list of exempt countries.

**Documentation: Shopify App Configuration Guidance**

Updated the [Shopify Pre-Registration guide](/ecom-platforms/shopify/pre-registration) to explicitly mention the requirement to uncheck the "Embed app in Shopify admin" checkbox when creating a Shopify app. This setting must be disabled for proper merchant onboarding.

#### Bug Fixes

**Pre-Registration Failure for Recently Onboarded Merchants**

Fixed a bug where Shopify pre-registration could fail if the merchant had recently onboarded to another channel. Pre-registration now correctly handles merchants with existing connections to other channels.

***

## 2026.01.27

#### ⚠️ Deprecation Notice

**API Deprecation Notice: Transfer Response Field Changes**

**Effective Date:** 02/03/2026 **Deprecation End Date:** 05/04/2026

**What is Changing?**

We are introducing new fields in our Transfer API responses with improved type consistency. The following fields are being deprecated and replaced:

| Deprecated Field        | New Field                  | Type Change                                         |
| ----------------------- | -------------------------- | --------------------------------------------------- |
| `related_orders`        | `related_order_ids`        | List of String → List of 64-bit Integer (i.e. Long) |
| `related_bags`          | `related_bag_ids`          | List of String → List of 64-bit Integer (i.e. Long) |
| `related_distributions` | `related_distribution_ids` | List of String → List of 64-bit Integer (i.e. Long) |
| `transfer_reversals`    | `transfer_reversal_ids`    | List of String → List of 64-bit Integer (i.e. Long) |

**Affected Endpoints:**

* `POST /v1/orders/{order_id}/transfer_funds`
* `POST /v1/orders/{order_id}/bags/{bag_id}/transfer_funds`
* `POST /v1/orders/transfer_funds`
* `POST /v1/orders/bags/transfer_funds`

**Why is This Changing?**

These fields have historically returned IDs as strings for future API version compatibility. We are standardizing all ID fields to return integers for consistency across our current API version, and will ensure that any type changes for ID fields only take place in the v2 Violet API.

**Is This Breaking?**

No, this change is not immediately breaking. During the deprecation period, both the old and new fields will be returned in API responses. Your existing integration will continue to work without modification.

{% hint style="warning" %}
**After 05/04/2026**, the deprecated fields will be removed. If your integration relies on the old field names, it will break after this date.
{% endhint %}

**Is Work Required on My Side?**

Yes, migration is required before 05/04/2026.

Update your integration to read from the new `*_ids` fields instead of the deprecated fields. If you are using a strongly-typed language, you may also need to update your type definitions to expect integers instead of strings.

**Timeline**

| Date           | Action                                                 |
| -------------- | ------------------------------------------------------ |
| **02/03/2026** | New fields available; both old and new fields returned |
| **05/04/2026** | Deprecated fields removed from responses               |

**Questions?**

Contact your account representative or reach out to <support@violet.io>.

#### 🆕 Features

**Squarespace Discount Support in Direct Order Submission (DOS)**

Violet now supports applying discounts to Squarespace orders submitted via Direct Order Submission (DOS). This enhancement brings Squarespace in line with other platforms that support promotional pricing during order creation.

**Custom Discounts (Channel-Defined)**

Channels can now apply custom discounts to Squarespace orders during DOS:

* Support for fixed amount discounts (e.g., $10 off)
* Support for percentage-based discounts (e.g., 15% off)
* Target discounts to order totals, shipping, or specific SKUs
* Discounts are validated and calculated using Violet's standard discount utilities
* Proper status tracking: `APPLIED`, `INVALID`, or `ERROR` based on validation results

**Synced Discounts (Merchant-Defined Promo Codes)**

Channels can now pass merchant-configured discount codes to Squarespace during DOS:

* Discount codes are validated by Squarespace during order creation
* Post-order validation confirms whether codes were successfully applied
* Discount amounts are extracted from Squarespace's order response
* Bag totals are automatically recalculated after code validation
* Status tracking: `PENDING` during submission, then `APPLIED` or `INVALID` based on Squarespace's response

Who this impacts:

* Channels using [Direct Order Submission](/prism/checkout-guides/guides/direct-order-submission) with Squarespace merchants.

{% hint style="info" %}
**Note**: Code-based discounts are not supported in Estimate Cart for Squarespace, as Squarespace does not provide a discount validation API. Custom discounts are supported in both Estimate Cart and DOS.
{% endhint %}

***

## 2026.01.21

#### Improvements

**Enhanced Payout Account Country Validation**

Violet Connect now performs more robust validation when merchants select their banking country during payout account setup. The system now accounts for [Destination Payments](/prism/payments/payment-settings/transfer-mechanisms#destination-payments) eligibility, ensuring merchants can only select countries where payouts are supported for their account configuration.

**Shopify Merchant Onboarding Improvements**

* **Refreshed UI**: Updated visual design for a cleaner, more intuitive onboarding experience
* **Pre-Registration Detection**: Merchants who visit Violet Connect directly (without a pre-registration link) can now enter their store URL, and the system will automatically detect any existing pre-registrations associated with that store. See [Merchant Onboarding](/ecom-platforms/shopify/merchant-onboarding#alternative-path-store-url-lookup) for details.

**Renamed Tabs in the Merchant Dashboard**

* "Bags" tab has been renamed to [Orders](/resources/merchant-dashboard#orders) in the Merchant Dashboard.
* "Offers" has been renamed to [Products](/resources/merchant-dashboard#products-publishing) in the Merchant Dashboard.

## 2026.01.06

#### 🆕 Features

**Shopify Merchant Pre-Registration (Required for New Shopify Merchants)**

In response to Shopify's January 2026 requirement that all new merchant connections use single-merchant custom apps, Violet has launched comprehensive pre-registration capabilities in both the Channel Dashboard and Violet Connect. This feature streamlines the previously complex Shopify onboarding process from 10+ minutes to under 2 minutes.

**Channel Dashboard Enhancements:**

* **New Pre-Registered Tab**: Navigate to Merchants → Pre-Registered to manage merchant onboarding before they connect
* **Pre-Registration Management**: Store OAuth credentials (Client ID, Client Secret) securely for each merchant before they begin installation
* **Merchant-Specific Links**: Generate unique Violet Connect links with pre-filled merchant details for one-click authorization
* **Real-Time Status Tracking**: Monitor merchant onboarding progress from pending to active, with automatic migration to Connected Merchants upon completion
* **Bulk Actions**: Edit, delete, or regenerate installation links for multiple pre-registered merchants

**Violet Connect Improvements:**

* **Pre-Filled Onboarding**: When merchants click their unique link, store details are automatically populated—no manual entry required
* **Simplified OAuth Flow**: Single "Connect to Shopify" button replaces complex credential entry, reducing errors and support tickets
* **Automatic Credential Validation**: OAuth handshake completed using pre-registered credentials without merchant involvement
* **Smart Redirect Handling**: Seamless return to Violet Connect after Shopify authorization for payout and commission setup

**Why This Matters:**

Shopify's deprecation of merchant-created custom apps means channels must now create and manage single-merchant apps for each merchant. Without pre-registration, this would require error-prone manual credential exchange. The new pre-registration workflow:

* Reduces onboarding time from 10+ minutes to under 2 minutes
* Eliminates credential copy/paste errors that caused 30% of onboarding failures
* Provides channels with centralized management of all pending merchant onboardings
* Ensures compliance with Shopify's new security requirements

**Documentation**: Complete setup guide available at [Shopify Merchant Onboarding](/ecom-platforms/shopify)

**Migration Note**: Existing Shopify merchants connected before January 2026 continue to work without changes. Only new merchant onboarding requires pre-registration.

***

**Weekend & Business Day Transfer Controls**

Scheduled transfers now support business day controls, giving you additional flexibility over when merchant payouts are executed.

* **`allowWeekendTransfers`**: When set to `false` (default), transfers scheduled to occur on weekends are automatically deferred to the following Monday. When `true`, transfers execute on any day of the week.

This setting works alongside existing scheduled transfer options (`time_interval_seconds` and `require_fulfillment`) to provide complete control over payout timing.

| Setting                                  | Behavior                           |
| ---------------------------------------- | ---------------------------------- |
| `allowWeekendTransfers: false` (default) | Saturday/Sunday transfers → Monday |
| `allowWeekendTransfers: true`            | Transfers execute any day          |

**Impact**: Channels can now align merchant payouts with banking hours, reducing reconciliation complexity and providing more predictable payout schedules.

***

## 2025.12.16

#### 🆕 Features

**Order Adjustments API**

New endpoints for managing post-order adjustments to bag totals. Adjustments are immutable audit records that track corrections to shipping, tax, or discount amounts after an order has been placed.

Use adjustments to:

* Correct shipping overcharges due to carrier rate updates
* Fix tax miscalculations for customer jurisdictions
* Apply post-order promotional discounts as customer goodwill

Each adjustment tracks how the cost change is distributed among the shopper, merchant, and channel—ensuring the amounts always sum to zero for proper accounting.

**New Endpoints:**

* `GET /v1/orders/{order_id}/adjustments` - Get all adjustments for an order
* `GET /v1/orders/{order_id}/bags/{bag_id}/adjustments` - Get adjustments for a specific bag
* `POST /v1/orders/{order_id}/bags/{bag_id}/adjustments` - Create a new bag adjustment
* `GET /v1/orders/{order_id}/bags/{bag_id}/adjustments/{adjustment_id}` - Get a specific adjustment

**Documentation**: See **Order Adjustments** in the API Reference under Orders & Checkout.

***

## 2025.12.10

#### 🆕 Features

**Scheduled Transfers & Fulfillment-Based Payouts**

Violet now supports scheduled merchant transfers with fulfillment requirements, giving channels complete control over when and how merchant payouts are executed. This feature addresses key challenges in marketplace payment operations by allowing channels to hold merchant payouts until orders are shipped and batch multiple transfers together on a predictable schedule.

**The Problem This Solves**

In traditional immediate-transfer setups, merchants receive payment the moment a customer's payment is captured—often before the order ships. This creates several challenges:

* **Fulfillment Risk**: Merchants are paid before confirming they can fulfill the order, increasing exposure if orders are cancelled or suppliers are out of stock
* **Chargeback Exposure**: When disputes arise, funds have already been transferred, making recovery difficult
* **High Transaction Volume**: Each order generates a separate transfer, creating thousands of micro-transactions for high-volume platforms
* **Unpredictable Cash Flow**: Merchants receive sporadic transfers throughout the day rather than predictable "paydays"

**New Configuration Options**

Two new settings are available in your app's payment configuration:

* **`require_fulfillment`**: When enabled, merchant transfers are only executed for bags in `SHIPPED` or `DELIVERED` status. This ensures merchants are paid only after orders are fulfilled, reducing risk from unfulfilled orders, cancellations, and potential fraud.
* **`time_interval_seconds`**: Set a minimum interval between transfers for each merchant to enable batched payouts:
  * `0` (default): Transfers execute immediately after payment capture
  * `86400`: Daily batched transfers—all eligible orders consolidated into one payout
  * `604800`: Weekly batched transfers—predictable "payday" scheduling for merchants
  * Some custom interval

**Real-World Use Cases**

| Business Model                  | Configuration                     | Benefit                                                                           |
| ------------------------------- | --------------------------------- | --------------------------------------------------------------------------------- |
| **Dropshipping Marketplace**    | `require_fulfillment: true`       | Pay merchants only after they confirm shipment from suppliers                     |
| **High-Volume Social Commerce** | `time_interval_seconds: 86400`    | Reduce thousands of daily micro-transfers to one consolidated payout per merchant |
| **Risk-Conscious Marketplace**  | Both enabled with weekly batching | 7-day buffer to identify issues before merchant payout                            |
| **B2B Platform**                | `time_interval_seconds: 604800`   | Predictable weekly "payday" for merchant cash flow planning                       |

**Documentation**: For detailed configuration options, use cases, and best practices, see [Scheduled Transfers](/prism/payments/payment-settings/scheduled-transfers).

**Impact**: This feature is ideal for channels operating dropshipping marketplaces, high-volume platforms with many small orders, or any business model where controlling payout timing reduces operational and financial risk.

{% hint style="info" %}
Transfer schedule settings can be configured at both the **app level** (applying to all merchants by default) and at the **merchant level** (overriding app defaults for specific merchants). To learn more or configure scheduled transfers, please [reach out to Violet](mailto:support@violet.io).
{% endhint %}

***

**Transfer Mechanism Options: Standard Transfers vs Destination Payments**

Violet now supports two distinct transfer mechanisms that control **how** funds are moved to merchants. This gives you flexibility to choose the payment flow that best fits your business model and compliance requirements.

**What is a Transfer Mechanism?**

While [Transfer Methods](/prism/payments/payment-settings/transfer-settings) (`AUTOMATIC`, `CUSTOM`, `EXTERNAL`, `DISABLED`) control **when** transfers occur, Transfer Mechanisms control **how** the actual fund movement is executed at the payment provider level.

**Standard Transfers** (Default)

Standard transfers use Stripe's separate charge-and-transfer model:

* Violet captures the payment from the shopper, then initiates a separate transfer operation to move funds to the merchant's connected account.
* The charge and transfer are distinct operations, giving you maximum flexibility over timing and control.
* Works with all transfer methods and supports both immediate and batched transfer schedules.

**Destination Payments**

Destination payments use [Stripe's destination charge model](https://docs.stripe.com/connect/destination-charges), where payment capture and merchant transfer occur atomically:

* Violet creates a Payment Intent with `transfer_data.destination`, which automatically transfers funds to the merchant's connected account upon payment capture.
* **Platform as Merchant of Record**: Your platform name appears on customer statements, providing a consistent brand experience across all merchants.
* **Automatic Application Fees**: Stripe creates Application Fee objects automatically, simplifying commission tracking and platform revenue reconciliation.
* **Simplified Fund Flow**: No separate transfer operation required—funds flow directly to the connected merchant account as part of the payment capture.

**When to Use Destination Payments**

Destination payments are ideal for:

* **Platform-Centric Marketplaces**: Similar to Airbnb or Lyft, where the platform is the primary business entity customers interact with and should appear on statements.
* **Simplified Accounting**: When you want Stripe to automatically track platform fees as Application Fee objects for easier reconciliation.
* **Atomic Transfers**: When you need the guarantee that payment capture and merchant fund distribution happen together in a single operation.

{% hint style="warning" %}
**Important**: Destination payments currently require [Scheduled Transfers](/prism/payments/payment-settings/scheduled-transfers) to be enabled. This ensures proper coordination between payment capture and fund distribution timing.
{% endhint %}

**Comparison**

| Consideration           | Standard Transfers                           | Destination Payments                  |
| ----------------------- | -------------------------------------------- | ------------------------------------- |
| **Merchant of Record**  | Can be platform or connected account         | Platform is always merchant of record |
| **Transfer Timing**     | Full control (immediate, batched, or custom) | Automatic upon capture                |
| **Stripe Fee Tracking** | Manual reconciliation                        | Automatic Application Fee objects     |
| **Scheduled Transfers** | Optional                                     | Required                              |

**Documentation**: For detailed information on transfer mechanisms and how to configure them, see [Transfer Mechanisms](/prism/payments/payment-settings/transfer-mechanisms).

{% hint style="info" %}
**Ready to configure transfer mechanisms?** Transfer mechanism settings are managed by the Violet team. To learn more or configure a transfer mechanism for your app, please [reach out to Violet](mailto:support@violet.io).
{% endhint %}

***

## 2025.12.09

#### 🆕 Features

**Transfer Details Enhancements**

Enhanced the Merchant Dashboard with a detailed view for transfers.

* **Transfer Detail Page**: Added a new view to inspect individual transfer details, including summary information and adjustment distribution types.
* **Comprehensive Tables**: Dedicated tables allow for easy inspection of all Distributions, Reversals, and Bags associated with a transfer.
* **Distributions Page**: Updated to use a paginated list for better performance and usability.

**Distribution Search Improvements**

* Added the ability to [search distributions](https://docs.violet.io/api-reference/payments/distributions/search-distributions) by payout transfer ID.

## 2025.12.02

#### 🆕 Features

**Merchant Dashboard Transfers & Reversals**

The merchant dashboard now includes comprehensive transfer and reversal management capabilities:

* **Transfers Table**: A new dedicated page displays all payout transfers for merchants, providing visibility into payment activity.
* **Transfer Reversals Tab**: The payouts page now includes a transfer reversals tab, making it easy to view and track reversed transactions.
* **Merchant Filtering**: Both transfers and reversals pages support filtering by merchant, enabling quick access to merchant-specific transaction data.

**Impact**: Merchants can now view and manage their transfers and reversals directly from the merchant dashboard, providing full transparency into payout activity.

**Enhanced Distribution Details**

Distribution details now include additional context for easier order lookup:

* Customer name is now displayed in distribution details on both channel and merchant dashboards.
* App Order ID is visible alongside distribution information on the channel dashboard, making it easier to cross-reference with your internal systems.

**Bag Fulfillment Management**

The Merchant Dashboard now includes comprehensive bag fulfillment tracking and management capabilities for manual merchants, making it easier to monitor and manage order fulfillment:

* **Organized Fulfillment View**: Fulfillments are now clearly separated into fulfilled and unfulfilled sections, making it easy to see what's been shipped and what's still pending at a glance.
* **Manual Tracking Entry**: Add and manage tracking information manually for bags, with support for multiple carrier options to accommodate different shipping providers.
* **Quick Tracking Updates**: Edit tracking details directly from the fulfillment view with an intuitive modal interface, allowing you to correct or update shipping information as needed.
* **Streamlined Workflow**: The tracking entry process has been simplified with automatic form resets and improved validation, ensuring accurate tracking information with minimum effort.
* **Enhanced Visibility**: Improved visual design and organization helps you quickly identify fulfillment status and take action on pending shipments.

**Impact**: Manual merchants can now manage bag fulfillments directly from the dashboard with complete visibility into tracking details, carrier information, and fulfillment status. This streamlines merchant support workflows, reduces time spent managing orders, and provides better order tracking capabilities for your customers.

#### 🔧 Fixes & Improvements

**Bag Fulfillment API Improvements**

* **API Authentication for Fulfillment Endpoints**: Improved authentication handling for merchant fulfillment API endpoints, ensuring proper authorization checks are consistently applied when merchants interact with bag fulfillments.
* **Fulfillment Accuracy**: Fixed an issue that could cause incorrect fulfillment quantity calculations, ensuring accurate tracking of fulfilled items.

## 2025.11.25

#### 🆕 Features

**ORDER\_FAILED Webhook Event**

A new webhook event type is now available to track failed order processing:

* `ORDER_FAILED` webhook events are triggered when order creation or processing fails.
* Provides detailed error information to help channels handle failed orders appropriately.
* Available in both OrderService and dashboard webhook configuration.

**Impact**: Channels can now build more robust error handling and customer support workflows by receiving real-time notifications when orders fail to process.

**Zero-Dollar Transaction Support**

Violet now fully supports $0 transactions throughout the platform:

* Process orders with $0 subtotals (e.g., fully discounted orders, promotional items).
* Support for $0 SKUs in Direct Order Submission (DOS).
* Enhanced payment capture and billing calculations to handle zero-dollar edge cases.
* Proper tax rate calculations when order subtotals are $0.

**Impact**: This enables channels to process promotional campaigns, loyalty rewards, and other scenarios where products or orders may have zero monetary value while still requiring order processing and fulfillment tracking.

#### 🔧 Fixes & Improvements

**Date Formatting Fix**

* Resolved an issue with Stripe Unix timestamp formatting in the dashboard, ensuring dates are displayed consistently and accurately across all payment-related views.

## 2025.11.18

#### 🆕 Features

**Adjustment Distributions**

Violet now supports adjustment distributions, enabling proper tracking and accounting for order modifications after initial transfer processing:

* Enhanced refund distribution records now include additional fields for more comprehensive financial reporting and reconciliation.
* Adjustment distributions appear alongside standard distributions in the dashboard, providing complete visibility into all financial movements related to an order.
* Support for tracking order adjustments, refunds, and other financial corrections in the payout system.

**Impact**: This feature ensures accurate financial records when orders require post-fulfillment adjustments, refunds, or corrections, giving you a complete audit trail for all payment activity throughout the order lifecycle.

**Orders and Bags Search by App Order ID**

The dashboard now supports searching for orders and bags using your channel's `app_order_id`, making it easier to locate specific orders when referencing your internal order tracking system.

* Quickly find orders using your own order identification system.
* Streamlines support workflows when customers reference order IDs from your platform.
* Available in both the orders and bags search interfaces.

#### 🔧 Fixes & Improvements

**Dashboard Enhancements**

* **Distribution Status Column**: The distributions view now displays status information directly in the grid, eliminating the need to open the detail view to check distribution status. This improvement speeds up workflow for users reviewing multiple distributions.
* **SKU Price Display Fix**: Corrected an issue where SKU sale prices were incorrectly displayed in cents instead of dollars in the SKU row component, ensuring price information is consistently formatted across the dashboard.
* **Commission Rate Display**: Improved commission rate display logic for clearer financial information throughout the dashboard.
* **Transfers Page Layout**: Enhanced the transfers page with better column width adjustments for improved readability across various screen sizes and monitor resolutions.
* **Payout Account ID Rendering**: Payout account IDs now display conditionally, showing relevant information only when applicable to reduce visual clutter and improve dashboard clarity.
* **Webhook Event Types**: Added missing webhook event types to the webhook configuration options in the dashboard settings, ensuring complete coverage of available webhook events.
* **UI Polish**: Fixed minor text spacing issue in the empty variant mappings view for improved visual consistency.

**Data & Performance**

* **Duplicate Transfer Records**: Resolved an issue where duplicate payout transfer records appeared in advanced search queries when multiple distributions pointed to the same transfer. Each transfer is now returned uniquely and accurately reflects the underlying payment activity.
* **Extended Tag Support**: Improved the tags column in the offers table to support longer tag strings and more flexible product categorization and metadata.

## 2025.11.04

#### 🔧 Fixes & Improvements

**Offer Updated Webhook Optimization**

* Implemented intelligent filtering for `OFFER_UPDATED` webhook events to eliminate unnecessary notifications when no material changes occur to offer data, even if an underlying ecommerce platform sends Violet a change notification.
* The system now performs deep comparison of offer fields including pricing, inventory, availability, descriptions, media, variants, and metadata before triggering webhooks.
* Webhooks are now only sent when meaningful changes occur to:
  * Product information (name, description, status, availability)
  * Pricing (min/max price, currency, commission rate)
  * Inventory (SKU quantities, in-stock status)
  * Media (images, source URLs, display order)
  * Variants and variant values
  * Product metadata and custom fields

**Impact**: This improvement significantly reduces webhook noise for channels consuming generic offer updates, particularly during merchant catalog reconciliation syncs or when platform webhooks are triggered for non-substantive changes.

## 2025.10.28

#### 🆕 Features

* Added a dedicated Distribution Detail View: Access detailed distribution breakdowns by selecting any distribution in the distributions view of your dashboard. [Learn more about distributions here](/prism/payments/payouts/distributions).

#### 🔧 Fixes & Improvements

* Fixed outdated, broken dashboard links.
* Unified search functionality across channel and merchant offers views:
  * Consistent offer ID filtering.
  * Consistent keyword search support.

## 2025.10.21

#### 📚 **Documentation Updates**

**Webhook Events Documentation Restructure**

* Completely reorganized webhook events documentation for improved clarity and navigation. The main webhooks overview page now provides a high-level introduction with links to dedicated pages for each entity type:
  * [Collection Webhooks](https://docs.violet.io/prism/webhooks/events/collection-webhooks) - Events for catalog collections
  * [Merchant Webhooks](https://docs.violet.io/prism/webhooks/events/merchant-webhooks) - Events for merchant connections and status changes
  * [Offer Webhooks](https://docs.violet.io/prism/webhooks/events/offer-webhooks) - Events for product offer updates
  * [Order Webhooks](https://docs.violet.io/prism/webhooks/events/order-webhooks) - Events for order lifecycle updates
  * [Payment Transaction Webhooks](https://docs.violet.io/prism/webhooks/events/payment-transaction-webhooks) - Events for payment processing
  * [Payout Account Webhooks](https://docs.violet.io/prism/webhooks/events/payout-account-webhooks) - Events for merchant payout accounts
  * [Sync Webhooks](https://docs.violet.io/prism/webhooks/events/sync-webhooks) - Events for catalog and order synchronization
  * [Transfer Webhooks](https://docs.violet.io/prism/webhooks/events/transfer-webhooks) - Events for fund transfers
* Each webhook event now includes detailed descriptions, example payloads, and implementation guidance
* Navigation has been simplified with a new events overview page that groups webhooks by entity type

**Payments Documentation Enhancement**

* Enhanced the [Payments landing page](https://docs.violet.io/prism/payments) with quick-access links to all payment features including payment methods, wallet management, refunds, and capture flows
* Added structured sections for better discoverability of payment-related documentation

{% hint style="info" %}
**Note**: These documentation changes do not affect API functionality. All existing integrations will continue to work without modification. The updates improve navigation and make it easier to find relevant webhook events and payment features.
{% endhint %}

## 2025.10.07

#### 🔧 **Fixes**

**Create Cart API: Promo Code Validation**

* Fixed an edge case where discount expiry dates were ignored when promo codes were applied directly in the Create Cart API instead of using the Add Discount To Cart API. The Create Cart API now properly validates promo code expiry dates regardless of which API endpoint is used to apply the discount.

**Transfer Funds API: Duplicate Request Handling**

* The [Transfer Funds for Order API](https://docs.violet.io/api-reference/orders-and-checkout/transfers/transfer-funds-single-order) and [Transfer Funds for Bag API](https://docs.violet.io/api-reference/orders-and-checkout/transfers/transfer-funds-single-bag) now return a `409 Conflict` error when attempting to process transfers for orders that have already had their distributions settled. Previously, duplicate requests would return a `2XX` response with an empty result. This change makes the API behavior more explicit and prevents unintended duplicate transfer attempts.

```json
 {
   "error": "transfer_already_processed",
   "error_code": "4461",
   "error_message": "All transfers for this entity have already been processed.",
 }
```

#### 🗑️ **Deprecations**

**OFFER\_CREATED Webhook Removal**

* The `OFFER_CREATED` webhook event has been fully removed as of October 7, 2025, following its deprecation notice on July 1, 2025. All integrations should now use the `OFFER_ADDED` event for comprehensive offer availability notifications. For more information about the difference between these events, see [Offer Webhooks](https://docs.violet.io/prism/webhooks/handling-webhooks#offer-webhooks).

## 2025.09.09

#### 🆕 Features

**Merchant Dashboard: API Credential Management Notice**

A new "API Credentials" section is now available in the dashboard settings. This is part of our ongoing effort to provide merchants with more control over API credentials for upcoming product feed management features. If product feed management is not relevant to your business, no action is required and you may disregard this section.

## 2025.09.03

#### 🆕 Features

**Direct Order Submission: Custom Discounts (Bag, SKU, and Shipping)**

Direct Order Submission now supports **custom discounts** defined by the channel—no merchant promo code required. You can apply fixed-amount or percentage discounts at the **bag (order)** level, to a specific **SKU**, or to **shipping**. Custom Discounts can be passed in **Estimate Cart** to evaluate the imapct of a Discount, and applied to the Order in **Create Order** as `BagDiscount` objects.

**Why this matters**

* Full control over pricing and promotions when merchant-managed codes aren’t a fit.
* You no longer need to apply pre-discounted prices during Create Order. Custom discounts will be reflected in the order totals and present in the merchant ecommerce store.

**Supported Platforms**

* **Shopify**
* **BigCommerce**
* **Ecwid**

**Platforms Coming Soon**

* **Magento**
* **WooCommerce**
* **Wix**

**Who this impacts** Channels using Direct Order Submission that want channel-controlled promotions independent of merchant promo code systems.

**Documentation** See the unified guide: **Discounts in Direct Order Submission (DOS)** — covering both **Synced Promotions** and **Custom Discounts**, request/response examples, and error payloads: [Discounts in Direct Order Submission (DOS)](/prism/checkout-guides/guides/direct-order-submission-with-discounts).

#### 🔧 **Fixes**

* Fixed duplicate entries in Violet API search responses for transfers and reversals. Each transfer and reversal record returned in search requests is now unique and accurately reflects the underlying payment activity.
* Restricted creation of Violet-managed payout accounts, which are now deprecated. Additionally, merchant payout accounts can no longer be created if the connected app is configured with a [`DISABLED`](/prism/payments/payment-settings/transfer-settings#disabled-transfer) transfer method. For more information, see [Transfer Settings](/prism/payments/payment-settings/transfer-settings).
* Fixed webhook event panel navigation: Order and offer entities now correctly link to their respective Channel Dashboard pages with accurate results.

## 2025.08.26

#### 🆕 Features

**Shopify Marketing Consent Support**

* Violet now supports capturing and passing email marketing consent requests for Shopify orders when using Direct Order Submission. When a shopper opts in to receive marketing communications during checkout, this consent is recorded and sent to Shopify via the Violet API. This ensures that merchants can accurately track customer marketing preferences in their Shopify store, supporting compliance and improved customer engagement.
* This feature is specific to Shopify and does not apply to other platforms at this time.
* For more details, see [Marketing Consent](/prism/checkout-guides/guides/marketing-consent).

**Transfers Dashboard**

* We've launched a dedicated "Transfers" tab in the Channel Dashboard's payouts section, providing comprehensive payment tracking capabilities:
  * Powerful Search Features:
    * Track specific transfers using Transfer ID
    * Find payments using your payment provider ID (i.e. the ID in Stripe)
    * Locate transfers associated with specific Order IDs
    * Search by Bag ID
    * Find transfers using Distribution ID
  * Flexible Filtering Options:
    * Date range filtering for transfer creation dates
    * Filter by transfer status
    * Currency-based filtering
    * Amount range filtering for precise financial tracking
  * Interactive Features:
    * Click through to view relevant reversals for transfers marked as "Reversed" or "Partially Reversed"
* More information about transfers can be found in the [Transfers](/prism/payments/payments-during-checkout/transfers) documentation.

**Transfer Reversals Dashboard**

* Introducing a new "Reversals" tab in the Channel Dashboard's payouts section for managing payment reversals:
  * Comprehensive Search Capabilities:
    * Look up specific reversals using Transfer Reversal ID
    * Find reversals associated with original Transfer IDs
    * Search using payment provider references (e.g., Stripe transaction ID)
  * Flexible Filtering Options:
    * Date range filtering for transfer creation dates
    * Filter by transfer status
    * Currency-based filtering
    * Amount range filtering for precise financial tracking
  * Quick Navigation:
    * Direct access to original transfer details through clickable transfer IDs
* More information about transfer reversals can be found in the [Transfer Reversals](/prism/payments/payments-during-checkout/transfer-reversals) documentation.

#### 🔧 **Fixes**

**Channel Dashboard Updates**

* Enhanced payment configuration logic: New merchant payout account setup is now restricted when an app is configured as transfer method `DISABLED`. See more information about transfer settings [here](/prism/payments/payment-settings/transfer-settings).

**Violet Connect Fixes**

* Users are now correctly redirected to the appropriate payments page after completing Stripe payout account onboarding in Violet Connect. More information about Violet Connect payment setup can be found [here](/prism/payments/payouts/prism-payout-accounts/setting-up-a-payout-account).

## 2025.08.19

#### 🆕 Features

**Enhanced Direct Order Submission (DOS) with Synced Promotions Support**

Direct Order Submission now supports accepting discount codes across major ecommerce platforms. When orders are submitted through Violet using DOS, discount codes and promotions that already exist in the merchant platforms can be included during order submission. These discounts will be applied to the cart totals that are submitted as a part of the request and appear in the merchant stores.

Support for discount codes has also been added to the Estimate Cart API, allowing you to estimate the total cost of an order with discounts applied before finalizing the Order for submission.

**Supported Platforms**

* **Shopify**
* **WooCommerce**
* **BigCommerce**
* **Magento**
* **Ecwid**

**Platforms Coming Soon**

* **Wix**

**What's New**

* Automatic discount code application during order creation on merchant platforms
* Real-time validation of discount codes against merchant platform rules
* Promotional pricing is accurately reflected in the merchant's order management system for orders placed through DOS
* Seamless integration with existing DOS workflows

**Who this Impacts**

Channels using Direct Order Submission with merchants on Shopify, WooCommerce, BigCommerce, Magento, Ecwid will be able to pass in discounts during DOS.

Review our [Direct Order Submission Guide](/prism/checkout-guides/guides/direct-order-submission), for complete implementation details.

Note: Discount codes were already supported in the iterative checkout flow, but this enhancement extends that support to the DOS flow.

#### 🔧 **Fixes**

* Fixes a scroll overflow issue in the Channel Dashboard, specifically on the bags and transactions pages. This fix ensures a better experience when interacting with the table views on these pages.

## 2025.08.12

#### 🛠️ Fixes

* Fixed an issue where merchants attempting to onboard a new payout account were incorrectly directed to the active payout account’s KYC onboarding flow in Stripe. Merchants adding or managing multiple payout accounts will now always be taken to KYC onboarding for the specific account they have selected. Learn more about how Merchants can manage multiple payout accounts [here](https://merchant-help.violet.io/interacting-with-violet/getting-paid/connecting-new-stripe-accounts).
* Fixed an issue with payout account status indicators in the merchant dashboard. The payout account status is now accurately reflected based on the actual state of the payout account being interacted with, ensuring merchants have clear visibility into their payout account health. Learn more about setting up a new Stripe account [here](https://merchant-help.violet.io/interacting-with-violet/getting-paid/connecting-new-stripe-accounts).
* New payout accounts are allowed to be activated from both the merchant dashboard and Violet Connect regardless of the target payout account's status, given that the merchant does not yet have an `ACTIVE` payout account. This fix ensures that merchants can successfully activate new payout accounts without being blocked by issues with previous accounts. Learn more about activating payout accounts [here](https://merchant-help.violet.io/interacting-with-violet/getting-paid/connecting-new-stripe-accounts#activating-your-payout-account).
* Adds KYC requirement details to the merchants page of the Channel Dashboard. Channel users can now see whether connected merchants have any pending KYC requirements directly from the merchant connection health panel view, improving visibility into merchant compliance status. Learn more about [KYC requirements for merchants](/prism/payments/payouts/guides/stripe-kyc-guide).

## 2025.08.04

#### 🧼 Cleanup

* `USD`, `GBP`, and `EUR` currencies are now prioritized in the currency options for payment transaction date filtering in the dashboard. This change ensures that popular currencies are more readily available for selection, improving usability of the currencies filter. Learn more about [Payment Transactions in the Channel Dashboard](/resources/channel-dashboard#transactions).

## 2025.07.29

#### 🆕 Features

**Introducing Order Transfer Groups**

Order Transfer Groups provide an order-centric view of transfer activity, complementing Violet's existing Transfer APIs. These new APIs organize transfer data by business context around Orders and Bags, making it easier to track payout completion status for multi-merchant orders and debug transfer issues.

**What's New**

* **Order Transfer Group API** - View complete transfer activity for a specific order, organized by bag and merchant
* **Bag Transfer Group API** - Focus on transfer attempts for individual bags within an order
* **Bulk Transfer Group APIs** - Retrieve transfer groups for multiple orders or bags with completion status filtering
* **Multi-attempt visibility** - Unlike individual Transfer APIs, Order Transfer Groups show all transfer attempts including failed ones for complete audit trails, from the lens of an Order.

**Key Features**

* **Order-level completion tracking** - `is_complete` field indicates whether all expected transfers for a given Order have been successfully sent to Merchants.
* **Complete audit trail** - Shows retry attempt history and debugging context for incomplete transfers for a specific Order.

**Available Endpoints**

* `GET /orders/{order_id}/transfer_group` - Get transfer group for specific order
* `GET /orders/{order_id}/bags/{bag_id}/transfer_group` - Get transfer group for specific bag
* `GET /orders/transfer_groups?is_complete={boolean}` - Get multiple order transfer groups with optional filtering
* `GET /orders/bags/transfer_groups?is_complete={boolean}` - Get multiple bag transfer groups with optional filtering

**Who this Impacts**

Anyone using `AUTOMATIC` or `CUSTOM` payments with Violet will be able to use the Order Transfer Group APIs to get insights into the state of transfers for any specific Order.

**When to Use Order Transfer Groups vs Transfer APIs**

* **Use Order Transfer Groups for:** Managing transfers from the lens of Orders and Bags. This lets you quickly go from Order/Bag → Related Transfer.
* **Use Transfer APIs for:** Managing individual transfer operations from the lens of a Transfer. This lets you quickly go from Transfer → Related Orders/Bags/Distributions.

Learn more in the [Order Transfer Groups](/prism/payments/payments-during-checkout/order-transfer-groups) documentation.

**Transactions in the Dashboard**

Payment transactions are now available in the Channel Dashboard, providing a comprehensive view of all payment-related activities. This feature allows you to monitor payment transactions directly from the dashboard, enhancing visibility and control over transactions across your orders.

Learn more about [Payment Transactions in the Channel Dashboard](/resources/channel-dashboard#transactions).

Learn more about payment transactions [here](/prism/payments/payments-during-checkout/payment-transactions).

#### 🛠️ Usability Improvements

**Violet Connect Shopify Flow: Storefront API Access Token Field Marked as Optional**

It is now clearly indicated in the Violet Connect onboarding flow for Shopify merchants that the Storefront API Access Token is optional.

## 2025.07.22

#### ⚙️ Integrations

**PRESTASHOP: Support added for Aliased Pricing**

When a Prestashop merchant enables tax-inclusive pricing the product price in the external product data will drift from the tax-inclusive price. Violet will now use Prestashop's price alias feature to obtain these prices outside of the product data.

**PRESTASHOP: Support added for Localized Product Data**

When a Prestashop merchant enables localization in their store the API-contract is effectively broken as most String objects are changed to `[Map<String,String>]` objects. Violet will now detect this change and gracefully extract the necessary values using the merchants default language.

**WOOCOMMERCE: Support added for the Yun Express Shipping Provider**

Violet is now able to obtain tracking details from WooCommerce orders fulfilled through Yun Express, also known as Yun Track. WooCommerce merchants can now select Yun Express as their shipping provider during onboarding and setup. Existing WooCommerce merchant's using Yun Express are **not** required to update the Violet plugin.

#### 🔧 **Fixes**

* Fixed an issue with user invites in the organization settings of the channel dashboard in which pending invites were not displayed correctly. All pending invites are now shown in the team page, allowing channel owners to manage and resend invites as needed.
* Fixed an issue with table padding on orders and bags pages in the dashboard. The padding has been adjusted to ensure consistent spacing and readability across all table views.

## 2025.07.15

#### 🆕 Features

**Dual Description Fields for Enhanced Content Flexibility (Shopify)**

Developers can now access both plain text and HTML product descriptions through separate, dedicated fields in Shopify offer objects. This enhancement provides complete format flexibility that wasn't possible with the previous conditional field behavior.

**Platform Scope:** This feature applies specifically to Shopify offers. Other e-commerce platforms will continue to use only the `description` field.

**What's Changed**

1. **New `html_description` Field**
   * The `html_description` field now consistently contains HTML-formatted product descriptions for Shopify offers
   * This field preserves original HTML formatting including tags, links, and styling
   * For non-Shopify platforms, this field will be `null`
2. **Enhanced `description` Field Behavior**
   * The `description` field now consistently contains plain text descriptions across all platforms
   * HTML tags are properly stripped to ensure clean plain text content
   * This field serves as the universal fallback for all e-commerce platforms
3. **Platform-Specific Behavior**
   * **Shopify offers:** Both `description` (plain text) and `html_description` (HTML) are populated
   * **Other platforms:** Only `description` is populated, `html_description` remains `null`
   * **Developer guidance:** Always check if `html_description` is `null` and fallback to `description` when needed

**Summary Table**

| Platform        | `description` Field    | `html_description` Field | Developer Action           |
| --------------- | ---------------------- | ------------------------ | -------------------------- |
| Shopify         | Plain text description | HTML description         | Use either field as needed |
| Other platforms | Plain text description | `null`                   | Use `description` field    |
| All platforms   | Always populated       | May be `null`            | Implement fallback logic   |

**What's Available Now**

* Both `description` and `html_description` fields are now available in all API responses for Shopify offers
* Complete format flexibility for developers to choose the appropriate field for their use case

**Action Required**

Update your integration based on the following recommendations:

* If you need HTML formatting, check `html_description` first (Shopify only)
* Always implement fallback logic to use `description` when `html_description` is `null`

**Note: Existing Offers May Have Stale HTML Descriptions**

Some Shopify offers may still have legacy or incomplete html\_description data if they haven't been updated since this change. This is because previously, descriptions may have been sanitized or left empty in the `html_description` field.

**How to Refresh HTML Descriptions**

To ensure your offer data uses the latest raw HTML format, you can manually re-sync specific offers from the Violet Channel dashboard:

1. Visit [Channel Dashboard Offers](https://channel.violet.io/offers)
2. Locate the affected offer(s)
3. Use the “Re-Sync” action to re-sync the offer from Shopify

After syncing, the `html_description` property will be fully up to date with the original HTML content from Shopify.

This enhancement provides the format flexibility developers need while maintaining backward compatibility during the transition period.

See [this page](/prism/catalog/offers#important-note-on-html_description-field-july-15-2025) for more information.

#### 🔧 **Fixes**

* Fixed an issue where commission rate change log entries in the dashboard were not displaying merchant ID and merchant name. Commission rate change logs now properly show merchant information for better tracking and identification. See [commission rate management documentation](/prism/payments/payouts/commission-rates) for more information about commissions and commission rate changes.

## 2025.07.08

#### 🆕 Features

**Summary of Changes to OFFER\_REMOVED and OFFER\_DELETED Webhooks**

**Background**

Previously, the `OFFER_REMOVED` webhook event was triggered when an Offer was marked for deletion or permanently deleted.

**What’s Changed**

1. **Introduction of `OFFER_DELETED` Event** There is now a distinct `OFFER_DELETED` webhook event specifically for when an Offer is marked for deletion or permanently deleted from the system. `OFFER_DELETED` is sent to all apps that were connected when an Offer is deleted (i.e., when the Offer is marked for deletion or removed from the database).
2. **New Behavior for `OFFER_REMOVED`** `OFFER_REMOVED` is now sent when an app loses access to an offer. This can happen when an offer is unpublished (status transitions from `PUBLISHED` to `NOT_PUBLISHED`), when a merchant disconnects from an app (all published offers for that merchant and app), or when an offer is marked for deletion. `OFFER_REMOVED` is no longer sent when an Offer is permanently deleted from the system, but it is sent when the offer is marked for deletion (prior to actual deletion).
3. **Bulk `OFFER_REMOVED` on App Disconnect** When a merchant disconnects from an app, the system now triggers `OFFER_REMOVED` webhooks for all currently published offers for that merchant and app. This allows apps to update their records and treat all the merchant’s offers as removed/unavailable upon disconnection.

**Summary Table**

| Action                                            | Previous Behavior (`OFFER_REMOVED`) | New Behavior (`OFFER_REMOVED`)   | New Behavior (`OFFER_DELETED`) |
| ------------------------------------------------- | ----------------------------------- | -------------------------------- | ------------------------------ |
| Offer unpublished (`PUBLISHED` → `NOT_PUBLISHED`) | Not sent                            | Sent                             | Not sent                       |
| Offer marked for deletion                         | Sent                                | Sent                             | Sent                           |
| Offer deleted (permanently removed)               | Sent                                | Not sent                         | Sent                           |
| Merchant disconnects app (all published offers)   | Not sent                            | Sent (`OFFER_REMOVED` per offer) | Not sent                       |

**Action Required**

Update your webhook handlers based on the following changes:

* **To track permanent offer deletions**, listen for the new `OFFER_DELETED` event.
* **The `OFFER_REMOVED` event** is no longer sent for permanent deletions. It is now sent when an offer is unpublished, marked for deletion, or when a merchant disconnects (triggering an event for each of their published offers).

**Export Connected Merchants**

Channels can now export comprehensive data about their connected merchants directly from the channel dashboard. This export provides a complete view of all connected merchants and their associated data for analysis and record-keeping.

Key Features:

* Fixed export format with all connected merchants included automatically
* Comprehensive merchant data including:
  * Merchant ID and name
  * E-commerce platform
  * Connection date
  * Current commission rate and rate change history
* CSV format for easy analysis and integration with other tools
* No customization needed - all relevant data is included by default

This feature complements the [merchants page in the Channel Dashboard](/resources/channel-dashboard#merchants) and provides an easy way to maintain records of your merchant network.

Learn more about [Connected Merchants Export](/prism/reporting/connected-merchants).

## 2025.07.01

#### 🆕 Features

**Enhanced Offer Publishing Notifications with `OFFER_ADDED` Webhooks**

Apps can now receive comprehensive real-time notifications when offers become available for purchase using the new `OFFER_ADDED` webhook event. This provides complete offer availability coverage that wasn't possible with the existing `OFFER_CREATED` event.

`OFFER_ADDED` Event Details:

* Triggers specifically when an offer becomes available for purchase

  * Fires automatically for:
    * Newly created offers that are immediately published
    * Existing offers whose status changes to "published" through individual updates
    * Offers updated to "published" status via bulk operations
    * Crucially: Pre-existing offers that become available when a merchant and Channel first connect

  Why `OFFER_ADDED` vs `OFFER_CREATED`:

  * `OFFER_CREATED`: Only fired when Violet first ingested an offer from a merchant's ecommerce platform
  * `OFFER_ADDED`: Fires whenever an offer becomes available for purchase, including pre-existing offers

  Key benefit: Channels connecting to merchants with existing offer catalogs will now receive `OFFER_ADDED` events for all available offers, eliminating the gap where pre-existing offers had no creation notification

  Deprecation Timeline:

  * `OFFER_CREATED` deprecated on September 30 2025
  * All integrations should migrate to `OFFER_ADDED` for comprehensive offer availability notifications

  Implementation:

  * Listen for `OFFER_ADDED` events using the [Create Webhook Endpoint](/api-reference/events/webhooks/create-webhook).
  * See the [Webhooks Overview](/prism/webhooks) and [Handling Webhooks](/prism/webhooks/handling-webhooks) guides for implementation details.

  **🐎 Faster Checkout with Asynchronous Transfers**

  Merchant fund transfers are now processed asynchronously to checkout. This update improves performance and ensures that issues during transfer processing for merchants no longer block cart submission if you are using `AUTOMATIC` transfers.

  What’s changed:

  * `AUTOMATIC` Transfers no longer delay or cancel cart submissions.
  * Checkout latency is reduced, especially for multi-merchant carts.
  * This is in both the [Submit Cart API](/api-reference/orders-and-checkout/cart-completion/submit-cart) and [Create Order API](/api-reference/orders-and-checkout/orders/create-order).
  * PaymentTransactions will now return a `transfer_status` of `PENDING` immediately following checkout. Previously this status would come back as `SENT`.
  * Once the transfer is completed asynchronously, the `transfer_status` is updated to `SENT`, and a `TRANSFER_SENT` webhook event will be emitted. You can subscribe to this webhook for updates or query the Order using the [Get Order API](/api-reference/orders-and-checkout/orders/get-order-by-id).
  * Failed transfers can be identified using the [Search Transfers API](/api-reference/payments/transfers/search-transfers).

  Who this impacts:

  * Channels using Prism Pay with `AUTOMATIC` transfer behavior.
  * If your system currently checks the `transfer_status` field on the Order or PaymentTransaction to confirm whether funds have been sent to merchants, we recommend shifting to webhook-based tracking for improved accuracy. Specifically, subscribing to the `TRANSFER_SENT` and `TRANSFER_FAILED` webhook events ensures you get real-time, reliable updates.

  Learn more about [Transfer settings](/prism/payments/payment-settings/transfer-settings) and [Transfer webhooks](https://github.com/violetio/docs/blob/main/channel-docs/product-info/broken-reference/README.md).

  This is the first step in a broader effort to make transfers more reliable and easier to monitor.

  **Export Commission Rate Change Logs**

  You can now export detailed reports of commission rate changes directly from the commission rates page in the dashboard.

  Key Features:

  * Flexible time ranges: Choose from Today, Yesterday, Current Month, Last 7 days, Last Month, or set a Custom date range.
  * Customizable columns: Include relevant data such as:
    * Commission rate change date
    * Previous and new rates
    * User details (type, name, email)
    * Context-specific information (Merchant ID/Name for channel users, App ID/Name for merchant users)
  * Export notifications: Optional alerts when your report is ready for download
  * Easy access: Download completed reports from the notifications area

  This feature provides better visibility into commission rate history and supports better compliance and auditing requirements.

  Learn more about [commission rate management](/prism/payments/payouts/commission-rates#commission-rate-management).

## 2025.06.24

#### 🆕 Features

**Improved Support for different Transfer Configurations in Iterative Checkout**

Iterative Checkout now fully supports `CUSTOM`, `EXTERNAL`, and `DISABLED` transfer configurations. Previously, the addSkuToCart step, if performed outside of Cart Creation, incorrectly required merchants to have a Violet payout account, even if your app was configured for `CUSTOM`, `EXTERNAL`, or `DISABLED` transfers.

What’s changed:

* addSkuToCart no longer enforces a payout account requirement for merchants if your app is configured with `CUSTOM`, `EXTERNAL`, or `DISABLED` transfers.

Who this impacts:

* Apps using Iterative Checkout with non-`AUTOMATIC` transfer behavior. No integration changes are needed — the fix is live and applies automatically.

Learn more about different transfer configurations [here](/prism/payments/payment-settings/transfer-settings) to see if this applies to you.

## 2025.06.17

#### 🆕 Features

**Prestashop Integration Simplified**

Apps onboarding Prestashop merchants no longer require the Violet Prestashop plugin installation if they don't use checkout or order-related API endpoints. This streamlines the onboarding process for merchants who only need basic integration functionality.

What's changed:

* Prestashop plugin installation is now optional for apps that don't utilize checkout or order features.
* These merchants can integrate more quickly without unnecessary plugin requirements.
* Existing integrations using checkout/order features remain unchanged.

Who this impacts:

* Apps that are configured for non-checkout/order related features. Please notify your Violet account representative if you have not previously communicated that your app does not require checkout/order features.

**Automatic Currency Conversion for Squarespace Orders**

Violet now automatically converts currencies when creating orders in Squarespace stores. If a store's base currency differs from the currency specified in the order request, and if the merchant's store is configured to reject alternative currencies, Violet will handle the conversion seamlessly instead of rejecting the order.

What's changed:

* Orders are no longer rejected due to currency mismatches in Squarespace stores.
* Currency conversion happens automatically during order creation.
* Improved success rate for cross-currency transactions.

Who this impacts:

* Apps onboarding Squarespace merchants who limit their store to an explicit currency.

**Filtering Offers by Tags in the Dashboard**

You can now filter offers in the Violet Dashboard using tags. This enhancement allows you to quickly find offers associated with specific tags. The tag filter supports logical operations, enabling you to filter down offers in a much more granular way. This makes it easier to manage and locate relevant offers based on your chosen criteria.

With the new tag filtering feature, you can create advanced queries using logical conditions. For example:

* To find offers that have both the "sale" and "clearance" tags, use:`tag EQUALS "sale" AND tag EQUALS "clearance"`
* To find offers where the tag is not empty or does not equal "archived", use:`tag IS NOT EMPTY OR tag DOES NOT EQUAL "archived"`

These combinations let you tailor your search to match exactly the offers you need based on their tags.

**View All Merchant Onboarding Records via API**

You can now retrieve a paginated list of all merchant onboarding records created under your app via the Violet API. This provides greater visibility into the onboarding process across your merchants and allows you to track status, payout configuration, and other onboarding metadata in real time.

What's changed:

* New endpoint: `GET /v1/merchants/onboard` returns a paginated list of all onboarding records. Learn more in the dedicated [API reference](/api-reference/onboarding/merchant-onboarding/list-merchant-onboarding-records)
* Supports standard `page` and `size` query parameters.
* Each record includes `merchant_onboarding_id`, `channel_merchant_id`, `payout_details`, and timestamps.
* If no onboarding records exist, an empty content array is returned.

Who this impacts:

* Apps that are currently using Violet's Onboarding APIs, available [here](/prism/violet-connect/guides/pre-provisioning-merchant-data). While there is no impact to your integration, if you already have Merchant Onboarding Records, you can now more easily interact with them.

**App Description on Violet Connect**

We've added app descriptions to the Violet Connect banner, making it easier for users to understand your app at a glance. Check out our guide on updating app settings [here](/prism/violet-connect).

## 2025.06.10

#### 🆕 Features

**More Flexibility with Active Payout Account Switching**

Merchants can now connect multiple Violet payout accounts and switch which one is active— without needing any migrations. This lets them easily change the account they have connected to Violet to receive funds.

What's changed:

* A new UI in the merchant dashboard and in Violet Connect allows merchants to manage and switch their active payout account. See [here](https://merchant-help.violet.io/interacting-with-violet/getting-paid/connecting-new-stripe-accounts) for how to switch the active payout account.
* Each app can have one active payout account at a time. New transactions will route to the current active account.
* The active payout account for the merchant is made more clear in the UI that displays the list of payout accounts in the dashboard and in Violet Connect
* Payment history and reporting remain tied to the payout account that was active at the time of each transaction.
* Previously used payout accounts remain viewable for audit and reference.

Who this impacts:

* Only channels using [Prism Pay](/prism/payments) are affected by this change.
* If your current flow is to onboard payout accounts outside of Violet (i.e. using DISABLED capture and transfer), this update does not impact you.

This new flow replaces the old “Payout Account Migration” process. You can send the following documentation to merchants who are trying to change their payout account: [Connecting a new Payout Account](https://merchant-help.violet.io/interacting-with-violet/getting-paid/connecting-new-stripe-accounts)

**Default Redirect Behavior for Violet Connect**

What's changed:

* When no custom Redirect URL is configured, merchants are now automatically redirected to the merchant dashboard (merchant.violet.io) after completing the Violet Connect flow.
* The Channel dashboard now displays the default redirect URL in the placeholder text when no custom URL is set
* Custom Redirect URLs cannot be set to any violet.io domain pages.

Configuration: Set your custom `Redirect URL` in the [Channel dashboard configuration page](/prism/violet-connect/setup#redirect-url)

**Merchant Connection Health**

What's changed:

* Connection health indicators for Merchant Payout Accounts and Commission Rates now return NOT\_APPLICABLE status for channels not using Violet Checkout.

Who this impacts:

* Only Channels operating without Violet Checkout are affected by this change.

## 2025.06.03

#### 🆕 Features

**Merchant Commission Rate Settings in the Channel Dashboard**

* Users without FINANCE `WRITE` permissions will now see an explicit view only tag when attempting to modify commission rates, improving clarity around access control and preventing confusion about why certain settings cannot be edited.

#### 🔧 **Fixes**

* Fixed an issue where the `Add SKU to Cart` flow failed to validate mismatched payment configurations across merchants. If a cart already contains merchants configured for `AUTOMATIC` capture and `AUTOMATIC` transfer, adding a SKU from a merchant with a different configuration—such as `AUTOMATIC` capture and `CUSTOM` transfer—will now correctly raise an unsupported\_merchant\_payments exception. All merchants in a cart must share identical capture and transfer settings. Learn more about different capture and transfer settings [here](/prism/payments/payment-settings).
* Fixes the ID column sizing in merchants and orders tables in the channel dashboard so that the ID is always visible regardless of window sizing.

## 2025.05.28

#### 🔧 **Fixes**

* The Stripe client ID is now optional when connecting a platform Stripe account. For details on when and how to use it, see [Connecting a Platform Stripe Account](/prism/payments/payment-integrations/supported-providers/stripe/connecting-a-platform-stripe-account).

## 2025.05.27

#### 🔧 **Fixes**

* Fixed misaligned error text in the payment configuration steps of Violet Connect.
* Prevented unnecessary Stripe API calls when the newly created payout account is of type `EXTERNAL` during Violet Connect onboarding. Learn more about `EXTERNAL` payout accounts [here](/prism/payments/payments-during-checkout/guides/using-external-transfers).

## 2025.05.19

#### 🆕 Features

**Offer Tags in the Channel Dashboard**

* Added a new "tags" column to the offers table in the channel dashboard. This column displays the tags associated with each offer, providing better visibility into the categorization of offers within the dashboard.
* Tags are now also visible in the offer detail view when an offer is selected. This allows users to quickly access and review the tags associated with a specific offer without needing to navigate away from the offer detail page.

**Transfer Reversals & Refund Flow Enhancements**

* Added support for `TransferReversal` objects to track and represent the reversal of funds from a merchant's payout account during a refund.
* Enhanced refund processing logic to automatically generate and persist reversal records, improving accuracy in reconciliation and visibility.
* Linked `Refunds`, `Distributions`, and `Transfers` for end-to-end traceability of all funds across the refund lifecycle.
* Learn more about how transfer reversals work [here](/prism/payments/payments-during-checkout/transfer-reversals).

**Refund and Transfer Webhook Events**

* The following webhook events are now emitted as part of this release:

  *Payment Transaction Events*

  * `PAYMENT_TRANSACTION_CAPTURE_STATUS_UPDATED`
  * `PAYMENT_TRANSACTION_CAPTURE_STATUS_REFUNDED`
  * `PAYMENT_TRANSACTION_CAPTURE_STATUS_PARTIALLY_REFUNDED`

  *Transfer Events*

  * `TRANSFER_UPDATED`
  * `TRANSFER_REVERSED`
  * `TRANSFER_PARTIALLY_REVERSED`
  * `TRANSFER_REVERSAL_FAILED`

  For payload examples and trigger details, visit the [Payments Webhooks Overview](https://github.com/violetio/docs/blob/main/channel-docs/product-info/broken-reference/README.md).

**Transfer and Transfer Reversal API Endpoints**

To support retrieval and inspection of both `Transfer` and `TransferReversal` objects, we’ve introduced the following endpoints:

* [Get Transfer by Transfer ID](/api-reference/payments/transfers/get-transfer-by-id)
* [Get Transfer by Payment Provider Transfer ID](/api-reference/payments/transfers/get-transfer-by-payment-provider-transfer-id)
* [Search Transfers](/api-reference/payments/transfers/search-transfers)
* [Get Transfer Reversal by ID](/api-reference/payments/transfer-reversals/get-transfer-reversal-by-id)
* [Get Transfer Reversals by Transfer ID](/api-reference/payments/transfer-reversals/get-transfer-reversals-by-transfer-id)
* [Get Transfer Reversals by Payment Provider Transfer ID](/api-reference/payments/transfer-reversals/get-transfer-reversals-by-payment-provider-transfer-id)
* [Search Transfer Reversals](/api-reference/payments/transfer-reversals/search-transfer-reversals)

## 2025.05.12

#### 🆕 Features

**API Changes**

* Added new payment webhook events: `MERCHANT_PAYOUT_ACCOUNT_ACTIVATED` and `MERCHANT_PAYOUT_ACCOUNT_DEACTIVATED`.
  * These events are emitted when a Prism Payout Account is activated or deactivated
  * Learn more [here](https://github.com/violetio/docs/blob/main/channel-docs/product-info/broken-reference/README.md).

## 2025.05.09

#### 🔧 **Fixes**

* Fixed an issue with generating payout exports in channel and merchant dashboards.
  * Addressed an issue where the payout export functionality in the channel and merchant dashboards would stall and fail to generate the report because of a bug in Violet's report run service. This has been resolved, and export should now generate successfully for all users.
  * For more information on how to generate payout exports, please refer to [this guide on exporting payouts](https://github.com/violetio/docs/blob/main/channel-docs/prism/payments/payouts/export.md).

## 2025.05.07

#### 🆕 Features

**API Changes**

* **Bulk Merchant App Uninstall API**
  * Added support for disconnecting multiple merchants with a single [API request](/api-reference/apps/merchant-app-installs/request-merchant-app-uninstall-bulk).
  * Learn more [here](/prism/merchants/merchant-app-connections).

## 2025.05.05

#### 🆕 Features

**API Changes**

* **Delete Prism Payout Account API**
  * Added support for deleting a Merchant Payout Account via API. This also removes the associated Stripe Express account when eligible.
  * Accounts are only deletable if they have never had any orders placed against them.
  * Upon successful deletion, the `MERCHANT_PAYOUT_ACCOUNT_DELETED` event will be emitted with the corresponding Prism Payout Account ID.
  * Learn more [here](/prism/payments/payouts/prism-payout-accounts/delete-payout-accounts).

## 2025.04.30

#### 🆕 Features

**Catalog Health Monitoring Improvements in the Channel Dashboard**

* Introduced a comprehensive new catalog health monitoring tab in the merchant connection panel that provides detailed insights into a merchant's overall catalog health.
* Added an offer status summary view that provides real-time insights on published and available offers.
* Added a detailed invalid products tracking table with:
  * Full search functionality
  * Comprehensive issue details for each problematic product

#### 🧼 Cleanup

* Expiration date for Violet Payout Accounts has been updated from **May 1, 2025** to **May 13, 2025**.
* Soon-to-be expiring Violet Payout Accounts are no longer shown in the Merchant Dashboard for irrelevant apps.

## 2025.04.28

#### 🆕 Features

**API Changes**

* **SKU Metadata**
  * SKU-level metadata syncing is now available for merchants on the `SHOPIFY` platform. Learn more [here](/prism/catalog/metadata-syncing/sku-metadata).
* **Contextual Pricing**
  * Contextual pricing is now available for all `COMMERCETOOLS` merchants.
  * Syncing is automatically enabled and requires no additional configuration.
  * Pricing is included directly in the base CommerceTools data.
  * Learn more [here](/prism/catalog/contextual-pricing).
* Added a new `email` field to the `PayoutAccount` object. This field captures the email address associated with underlying Stripe account and will be available as a part of the `payment_provider_account` data.

<details>

<summary>Sample Payout Account</summary>

```json
{
    "id": 12345,
    "account_type": "MERCHANT",
    "account_id": 12345,
    "app_id": 11111,
    "is_active": true,
    "country_code": "US",
    "payment_provider": "STRIPE",
    "payment_provider_account_id": "acct_ASDFGHJKLasdfghjkl",
    "payment_provider_account_type": "EXPRESS",
    "payment_provider_account": {
        "account_id": "acct_ASDFGHJKLasdfghjkl",
        "account_type": "EXPRESS",
        "email": "email@merchant.com",
        "banking_country": "US",
        "banking_currency": "usd",
        "charges_enabled": true,
        "payouts_enabled": true,
        "requirements": {
            "alternatives": [],
            "currently_due": [],
            "errors": [],
            "eventually_due": [],
            "past_due": [],
            "pending_verification": []
        }
    },
    "errors": [],
    "date_created": "2025-04-22T16:36:23+0000",
    "date_last_modified": "2025-04-22T16:36:23+0000"
}
```

</details>

* **Generate Custom Violet Connect Onboarding URLs**
  * Added a new endpoint to fetch links within the Violet Connect Flow. Learn more about this [here](/api-reference/merchants/onboarding/get-vc-urls).
  * Supports an optional step parameter to retrieve a direct link to a specific flow (`PAYOUTS`, `COMMISSION_RATE`, or `CREATE_STRIPE_EXPRESS_ACCOUNT`). If no step is provided, URLs for all available onboarding steps will be returned.

## 2025.04.15

#### 🆕 Features

**📦 New Payments APIs (Prism Pay)**

We’ve launched a set of Prism Pay APIs to give you deeper visibility and control over payment flows in Violet:

* [Get all Distributions](/api-reference/payments/distributions/get-distributions)
* [Search Distributions](/api-reference/payments/distributions/search-distributions)
* [Get active Prism Pay Account by Violet Merchant ID](/api-reference/payments/payout-accounts/get-payout-account)
* [Get Prism Pay Account by specific Prism Pay Account ID](/api-reference/payments/payout-accounts/get-payout-account-by-id)

These endpoints allow you to query payout accounts and view how Distributions are tracked across merchants.

**📡 New Payments Webhooks**

We're introducing **Payments-specific webhooks** to provide real-time insight into payout account events.\
These events help you monitor when a payout account is created or when KYC requirements change.

* `MERCHANT_PAYOUT_ACCOUNT_CREATED`
* `MERCHANT_PAYOUT_ACCOUNT_REQUIREMENTS_UPDATED`

Learn more about how to integrate with these webhooks [here](https://github.com/violetio/docs/blob/main/channel-docs/product-info/broken-reference/README.md).

## 2025.04.08

#### 🆕 Features

**API Changes**

* `DISABLED` has officially replaced `EXTERNAL` as a capture and transfer setting. Any channel previously configured with `EXTERNAL` for capture or transfer has been automatically migrated to use `DISABLED`. Meanwhile, `EXTERNAL` has been reintroduced with a new purpose—offering an additional, more flexible option for channels that need to manage payments and transfers outside of Violet's infrastructure. Learn more about this [here](/prism/payments/payment-settings).

**External Transfers Now Supported via Prism Pay**

* Channels can now use Prism Pay to generate Distributions for bookkeeping, process Transfers externally to merchants, and register those external transfers in Violet. This update gives you greater flexibility when managing payments outside of Violet’s infrastructure—especially useful for handling merchant transfers that fall outside your supported payments region. [Learn more about External Transfers](/prism/payments/payments-during-checkout/guides/using-external-transfers).

## 2025.03.31

#### 🆕 Features

**Enhanced Payment Integration Health Monitoring**

* Support for channels using their own integrated payment platforms, providing visibility into their payment integration health.
* Added a new comprehensive payment health overview in the Channel Dashboard settings (/settings/payments).
* Channel dashboard now displays:
  * Overall payment integration health status at a glance.
  * Detailed breakdown of payment components (credentials, webhooks, and scopes).
  * Stripe account configuration details and status.
* Quick access to payment details and payout accounts from the overview page.
* Learn more about this feature [here](/prism/payments/payment-integrations/supported-providers/stripe/payment-integration-health).

## 2025.03.17

#### 🆕 Features

**Multi-App Payout Account Management for Merchants**

* We've introduced a comprehensive new view in Payout Settings in the merchant dashboard that streamlines how merchants manage their payout accounts across different app connections. The redesigned interface now groups payout accounts by their associated apps, providing better organization and clarity. To ensure complete visibility of your payment configurations, you can now view both inactive payout accounts and any orphaned accounts from disconnected apps.

#### 🧼 Clean Up

* Distribution exports now reflect the updated field names and formats announced in the [March 10th, 2025 release](#id-2025.03.10). This aligns the dashboard export experience with the current distribution model.
* Orders and bags in the dashboard now display the actual submission time from your e-commerce platform, rather than when they were created in our system. This gives you a more accurate view of when your customers placed their orders.
  * `date_created` usage has switched over to `date_submitted` for orders and bags in the dashboard.

## 2025.03.10

#### 🆕 Features

**Enhanced support for non-US based Stripe Platform accounts**

* We’ve expanded capabilities for Stripe Platform accounts based outside the US to onboard merchant payout accounts in different countries within the same region. For example, a UK-based platform can now onboard merchant payout accounts across the European Economic Area (EEA) and automatically transfer funds to them. To see all supported countries in your region, visit your [Stripe dashboard](https://dashboard.stripe.com/settings/connect/onboarding-options/countries).

#### 📈 Update to Capture and Transfer Methods in Violet

{% hint style="warning" %}
Breaking Changes
{% endhint %}

**Summary**

Violet currently supports the following capture and transfer methods:

* `AUTOMATIC`
* `CUSTOM`
* `EXTERNAL`

We are introducing a new field on **March 24, 2025**:

* `DISABLED`

**Impacted Areas**

* **`PaymentTransaction`**
  * The `PaymentTransaction` model on the `Order` object will now include the `DISABLED` field.
  * This will replace the existing `EXTERNAL` capture and transfer method when this configuration is used in your payment infrastructure.

**Timeline**

* **March 24, 2025**
* `DISABLED` field released as a replacement to `EXTERNAL`.
* `EXTERNAL` takes a new meaning as a capture/transfer setting.

**What’s Changing?**

* **Capture Methods**
  * `EXTERNAL` will **no longer be supported** as a capture method.
  * `DISABLED` will replace `EXTERNAL` in this context, meaning Violet will **have no involvement** in capturing funds from the shopper—no payment infrastructure is used, and no records are created.
* **Transfer Methods**
  * `EXTERNAL` will now function as follows:
    * Violet will generate **Distributions** in a `PENDING` state at Checkout.
    * The channel can then transfer funds externally to the merchant (e.g., via direct bank transfer or other methods).
    * A new **"Register Transfer" API** will be available, allowing channels to register external transfers with Violet and mark corresponding Distributions as `SENT`.
  * `DISABLED` will mean that **Violet will have no involvement** in transferring funds to the merchant. This includes **not generating any Distribution records**.

**Next Steps**

* If your system currently relies on `EXTERNAL` being present in the `PaymentTransaction` on the Order object, please update to using `DISABLED`. Additional guides and documentation will also be published alongside these changes for you to learn about how they can be leveraged to support new capture and transfer flows. For any questions, reach out to our support team.

#### 📈 Upcoming Changes to Distribution Exports

{% hint style="warning" %}
Breaking Changes
{% endhint %}

**Summary**

We’re introducing new fields to `Distribution` entities and updating Distribution exports to include these fields. As part of this update, some existing columns will be replaced with improved versions.

**Impacted Areas**

* **`Distribution` Exports**: New columns will be added, and some existing ones will be deprecated.

**Timeline**

* **March 17, 2025**
* New fields become available.
* **April 7, 2025**
* Old fields will be removed from Distribution exports.

**What’s Changing?**

* **New Fields Being Added (Effective March 17, 2025)**

  | Field                                  | Description                                                                                       |
  | -------------------------------------- | ------------------------------------------------------------------------------------------------- |
  | **net\_distribution\_amount**          | The final amount to be distributed after all fees, commissions, and discounts.                    |
  | **distribution\_amount**               | The initial distribution amount before any deductions.                                            |
  | **tax\_amount**                        | The total tax amount included in the distribution.                                                |
  | **shipping\_amount**                   | The total shipping charges included in the distribution.                                          |
  | **payment\_provider**                  | The payment service provider handling the transaction (e.g., STRIPE). Replaces `payment_service`. |
  | **payment\_provider\_total\_fee**      | The total fee charged by the payment provider. Replaces `payment_service_total_fee`.              |
  | **payment\_provider\_fixed\_fee**      | The fixed fee component charged by the payment provider. Replaces `payment_service_fixed_fee`.    |
  | **payment\_provider\_volume\_fee**     | The percentage-based fee charged by the payment provider. Replaces `payment_service_volume_fee`.  |
  | **payment\_provider\_transaction\_id** | Unique identifier assigned by the payment provider. Replaces `external_transaction_id`.           |
  | **bag\_commissionable\_amount**        | The amount eligible for commission calculations (bag total minus shipping, tax, and discounts).   |
* **Fields Being Deprecated (Removal on April 7, 2025)**\
  These fields will be available until April 7, 2025, after which they will be fully removed in favor of the new fields above.

  | Deprecated Field                  | Replacement                       |
  | --------------------------------- | --------------------------------- |
  | **payment\_service**              | `payment_provider`                |
  | **payment\_service\_total\_fee**  | `payment_provider_total_fee`      |
  | **payment\_service\_fixed\_fee**  | `payment_provider_fixed_fee`      |
  | **payment\_service\_volume\_fee** | `payment_provider_volume_fee`     |
  | **external\_transaction\_id**     | `payment_provider_transaction_id` |
  | **amount**                        | `net_distribution_amount`         |

**Next Steps**

* If your system relies on the deprecated fields, update your integrations to use the new fields before **April 7, 2025**.

## 2025.03.03

#### 🆕 Features

**Channel Dashboard Updates**

* Commission Rate Change Log Enhancements
  * Added redirect functionality from commission rate change log entries to the merchant connections page.
  * When clicking a change log row, users are now directed to:
    * The specific merchant's connection details
    * The commissions tab for that merchant

**API Changes**

* Added further restrictions to prevent Offers in a `NOT_PUBLISHED` state from being submitted via [Direct Order Submission](/prism/checkout-guides/guides/direct-order-submission#retrieve-skus-from-the-violet-catalog).
* A `date_submitted` property has been added to the [Order](/api-reference/orders-and-checkout/orders/get-order-by-id) and Bag objects. This value, in the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format, will capture the following moments:
  * When the overall Order passed all validation checks and entered into a state of being submitted.
  * When each Bag within the Order was submitted to the external commerce platform.

**Violet Connect**

* BigCommerce
  * Violet Connect has been updated for [BigCommerce merchants](https://merchant-help.violet.io/platform-guides/big-commerce), allowing them to use store-level credentials to connect their stores to Violet instead of relying on the BigCommerce marketplace app via OAuth.

## 2025.02.24

#### 🆕 Features

**Filter Orders by Date in Dashboard UI**

* Added a new date filter option to the channel dashboard orders page. You can now filter orders by date with the following options:
  * Orders created after a specific date
  * Orders created before a specific date
  * Orders created between two dates
  * Orders created on a specific date

#### 🔧 **Fixes**

* Fixed an issue with Violet Connect's redirect handling after a successful Stripe standard account connection
  * Addressed an issue in which customers would onboard merchants in Violet Connect choosing to setup a Stripe Standard account. The Stripe Connect connection through OAuth would succeed, but when being redirected back to Violet Connect, the merchant would see an error page instead of the new payout account.

#### 🧼 Clean Up

* Clean up accuracy of search orders endpoint

## 2025.02.18

#### 🆕 Features

**Contextual Pricing**

* Commonly referred to as “Presentment Currencies”, is now available for use with merchants on the `BIGCOMMERCE` platform who are subscribed to the BigCommerce [Enterprise plan](https://www.bigcommerce.com/enterprise-pricing). Learn more [here](/prism/catalog/contextual-pricing).

#### ⚙️ Integrations

**SHOPIFY: ‘Sync Catalog’ by Collection using GraphQL**

* Shopify merchants who are using collection filtered catalog syncs will be migrated to the Shopify GraphQL API. Previously these merchants were required to remain using Shopify’s now-deprecated REST API as the GraphQL API did not support catalog collection filters. Violet will perform this migration for all merchants still using the Shopify REST API. No action is required from the channels connected to these merchants and no change in behavior or functionality will be experienced.

#### 🔧 Fixes

* Fixed issue where certain marketplace orders placed against a Shopify store could fail to have transactions persisted in Shopify. This could cause down-the-line issues when a Shopify order was refunded by a channel. Violet now has additional checks after order submission to retry the transaction request if Shopify does not persist the transaction on order creation.

## 2025.02.10

#### 🆕 Features

**Stripe Country Validations**

* Stripe only allows for Stripe Connect completion between two Stripe Standard accounts if they are located in the same country.
* Any merchant users trying to setup payments using a Stripe Standard account must validate their banking country before connecting their via OAuth.
  * This was originally implemented in Violet Connect and is now added to the Merchant Dashboard, as well.

Note: This does not affect merchant users setting up a Stripe Express account. The Stripe Express setup flow remains unchanged and is recommended for most users.

**WooCommerce Shipping Provider: Pirate Ship**

* Coverage of fulfillment tracking numbers for `WOOCOMMERCE` merchants using [Pirate Ship](https://www.pirateship.com/integrations/woocommerce) has been implemented. Pirate Ship can now be selected as the merchants shipment extension in the WooCommerce Violet Settings view. See [Configuring the Violet Plugin](https://merchant-help.violet.io/platform-guides/woo-commerce#step-2-configuring-the-violet-plugin).

#### 🔧 **Fixes**

* Fixed an issue where the [Get Available Shipping Methods](/api-reference/orders-and-checkout/cart-shipping/get-available-shipping-methods) request would fail for some Shopify merchants using a certain fulfillment provider. This fulfillment provider began injecting JWT's into the shipping method ID property which far exceeded the maximum length of an indexable value.
* Fixed an issue where shoppers attempting to inject bad data through the `first_name` and `last_name` properties would cause a failure to apply the customer to a cart. These inputs will now be truncated to the first 2 space-delimited values, with any character beyond 32 characters being omitted. This limit is now noted in the [API Reference](/api-reference/orders-and-checkout/cart-customer/apply-customer-to-cart).

## 2025.02.03

#### 🧼 Cleanup

* Violet Connect now requires a Standard Stripe account to be in the same banking country as the Stripe Platform account. If the countries do not match, merchants should create a Stripe Express account to enable cross-border payouts.

## 2025.01.30

#### 🆕 Features

* Added a new field to the `Bag` object called `external_reference_id`. This field will be populated when a successful order is placed on a platform that utilizes vanity numbers on the external orders. This is currently limited to the `SHOPIFY` platform which hides the true order ID and instead uses a vanity number in customer communication emails.

#### 🧼 Cleanup

* Added a line item availability check to the [Estimate Cart](/api-reference/orders-and-checkout/cart-pricing/estimate-cart) endpoint for the `COMMERCETOOLS` platform.

#### 🔧 **Fixes**

* Fixed an issue where presentment currencies were only reflected in the `presented_currency` field on an Offer but not in the `currency` field, leading to potential confusion. The provided `base_currency` value will now always be reflected in the `currency` field.

## 2025.01.27

#### 🆕 Features

* Contextual pricing, commonly referred to as "Presentment Currencies", is now available for use with merchants on the `SHOPIFY` platform. Learn more [here](/prism/catalog/contextual-pricing).
* Channels with Stripe Platform Accounts located outside the US can now connect their existing Stripe accounts for streamlined payment orchestration. Learn more [here](/prism/payments/payment-integrations/supported-providers/stripe/connecting-a-platform-stripe-account).

{% hint style="info" %}
Violet is restricted by Stripe's regional limitations. If you're a non-US Stripe platform trying to connect, learn about the cross-border limitations enforced by Stripe [here](https://docs.stripe.com/connect/cross-border-payouts).

Alternatively, you can create a new US-based platform account, if your business structure allows it. You can read more about the requirements to open a Stripe account in a another country [here](https://support.stripe.com/questions/requirements-to-open-a-stripe-account-in-another-country).
{% endhint %}

#### 🧼 Clean Up

* Additional validations have been implemented at the Violet API layer to ensure compliance with Stripe's cross-border payment restrictions.\
  When connecting a merchant payout account, if a Stripe Standard account is being connected, it must be in the same banking country as the Stripe Platform account. If the countries do not match, merchants should create Stripe Express accounts to enable cross-border payouts. Anytime this is not the case, Violet will now respond with the following error:

```json
{
  "error": "payout_account_connection_not_valid",
  "error_code": 4448,
  "error_message": "This payout account is not compatible with transactions because it is a Stripe Standard account registered in <MERCHANT_COUNTRY>, while the Platform Stripe account operates in <PLATFORM_COUNTRY>. Please set up a Stripe Express account to receive payouts."
}
```

#### 🔧 **Fixes**

* Customer address postal codes are no longer required for the following countries: `AO`, `AG`, `AW`, `BS`, `BZ`, `BJ`, `BM`, `BO`, `BQ`, `BW`, `BF`, `BI`, `CM`, `CF`, `TD`, `KM`, `CG`, `CD`, `CK`, `CI`, `CW`, `DJ`, `DM`, `GQ`, `ER`, `FJ`, `TF`, `GA`, `GM`, `GH`, `GD`, `GY`, `HM`, `HK`, `KI`, `KP`, `LY`, `MO`, `MW`, `ML`, `MR`, `NR`, `AN`, `NU`, `QA`, `RW`, `KN`, `ST`, `SC`, `SL`, `SX`, `SB`, `SO`, `SR`, `SY`, `TL`, `TG`, `TK`, `TO`, `TT`, `TV`, `UG`, `AE`, `VU`, `YE`, `ZW`.

## 2025.01.21

#### 🆕 Features

**Dashboard Orders Page Enhancements**:

* Introduced new orders page in the dashboard.
  * New tabs for "Orders" and "Bags" with "Orders" as the default tab. This allows users to easily switch between viewing and interacting with orders and bags.
  * The orders table now displays detailed information for each order, including:
    * **Order ID**: A unique identifier for each order.
    * **Date Created**: The date and time when the order was created.
    * **Full Name of the Customer**: The full name of the customer who placed the order.
    * **Order Total**: The total amount for the order.
    * **Order Status**: The current status of the order.
    * **Total Number of Bags in the Order**: The total count of bags included in the order.
    * **Total Number of Items in the Order**: The total count of individual items in the order.
  * Both orders and bags are now presented in a paginated table format
  * Enhanced search and filter capabilities for orders, enabling users to search and filter by:
    * **Order ID**: Search for orders using their unique identifier.
    * **Bag ID**: Search for orders by the ID of the bags included.
    * **Customer Name**: Filter orders by the customer's name.
    * **Customer Email**: Filter orders by the customer's email address.
    * **SKU Name**: Search for orders containing specific SKU names.
    * **Exact Total**: Filter orders by their exact total amount.
    * **Merchant ID**: Filter orders by the ID of the merchant.
    * **Order Status**: Filter orders by their current status.
  * The "Orders" tab in the merchant dashboard has been renamed to "Bags" to better reflect its content.

**Upcoming Improvements**:

* Order detail view: A detailed view for individual orders will be introduced, providing more in-depth information about each order.
* Export functionality: Users will be able to export order data for reporting.

## 2025.01.14

#### 🆕 Features

**API Updates**

*Upcoming Changes*

{% hint style="warning" %}
These changes were delayed to 03/17/2025 to ensure that there is enough time for all customers to understand and implement any necessary changes.
{% endhint %}

The following fields will be added to the Distributions model and will be included in distribution exports starting 01/27/2025:

| Field                                  | Description                                                                                                                                  |
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| **net\_distribution\_amount**          | The final amount to be distributed after all fees, commissions, and discounts are applied                                                    |
| **distribution\_amount**               | The initial distribution amount before any deductions                                                                                        |
| **tax\_amount**                        | The total tax amount included in the distribution.                                                                                           |
| **shipping\_amount**                   | The total shipping charges included in the distribution                                                                                      |
| **payment\_provider**                  | The payment service provider handling the transaction (e.g., STRIPE). This column will replace `payment_service`.                            |
| **payment\_provider\_total\_fee**      | The total fee charged by the payment provider for processing the transaction. This column will replace `payment_service_total_fee`.          |
| **payment\_provider\_fixed\_fee**      | The fixed fee component charged by the payment provider. This column will replace `payment_service_fixed_fee`.                               |
| **payment\_provider\_volume\_fee**     | The percentage-based fee charged by the payment provider based on transaction volume. This column will replace `payment_service_volume_fee`. |
| **payment\_provider\_transaction\_id** | Unique identifier assigned by the payment provider for the transaction. This column will replace `external_transaction_id`.                  |
| **bag\_commissionable\_amount**        | The amount that is eligible for commission calculations. This is the bag total minus shipping, tax, and discounts.                           |

As a result of including the fields mentioned above, the following fields will be deprecated. Starting on 02/10/2025, these fields will no longer be populated:

| Field                             | Reason                                                   |
| --------------------------------- | -------------------------------------------------------- |
| **payment\_service**              | Deprecated in favor of `payment_provider`                |
| **payment\_service\_total\_fee**  | Deprecated in favor of `payment_provider_total_fee`      |
| **payment\_service\_fixed\_fee**  | Deprecated in favor of `payment_provider_fixed_fee`      |
| **payment\_service\_volume\_fee** | Deprecated in favor of `payment_provider_volume_fee`     |
| **external\_transaction\_id**     | Deprecated in favor of `payment_provider_transaction_id` |
| **amount**                        | Deprecated in favor of `net_distribution_amount`         |

We will continue to include them in the data response until 02/17/2025, after which the fields will be removed.

#### 🔧 **Fixes**

* Resolved an issue where tax amounts during Direct Order Submission were incorrectly passed to merchant stores in the cart currency instead of the merchant store's currency when the channel was designated as the tax remitter. This was not impacting final prices, however, the merchant could see line item sums that did not add up to the total price of paid by the shopper because of this issue.

## 2024.12.17

#### 🆕 Features

**API Updates**

* Introduces the [Refund Bag](/api-reference/orders-and-checkout/order-refunds/refund-bag) endpoint. Using this API you can initiate refunds for any bags originated by your app.

**Integration Updates**

* We’ve updated the partial refund process in Violet to handle `refund_discrepancy` amounts returned by Shopify. If a merchant doesn’t properly allocate refund amounts to the corresponding line items, any resulting difference will now be taken from their distributions. This ensures that Channels do not have more commission reversed for an incorrect partial refund than they should.

## 2024.12.09

#### 🆕 Features

**API Updates**

* Bags with disputed payments will now reflect this in the new `dispute_status` field. When this field is `null` or `UNDISPUTED` there is no dispute on the payment. Disputes are bag level because a single charge can be disputed multiple times and each dispute typically reflects a single bag.

**Integration Updates**

* The Squarespace (`SQUARESPACE`) integration is now available for marketplace channels who calculate their own tax rates. Please reach out to your Violet account representative if you are interested in having this platform enabled for your app(s). *Squarespace does not provide a cart/checkout API at this time and therefore cannot be used by non-marketplace channels who rely on merchant tax rates.*

#### 🔧 **Fixes**

**API Updates**

* Fixed issue where `ORDER_SHIPPED` and `ORDER_UPDATED` event webhooks were not sent after an order had been partially fulfilled in the merchants system.
* Fixed issue where `ORDER_UPDATED` event webhooks were not sent after a fulfillment had been cancelled in the merchant system.

## 2024.12.03

#### 🆕 Features

**API Updates**

* Adds improved date last modified filtering when interacting with orders.
  * [Search Orders](/api-reference/orders-and-checkout/orders/search-orders)
    * The `before_date` param in the request body is now deprecated.
    * The `after_date` param in the request body is now deprecated.
    * The `date_last_modified:min` and `date_last_modified:max` request body params have been added. Each of these will accept an ISO 8601 datetime string.
    * The `date_created:min` and `date_created:max` request body params have been added. Each of these will accept an ISO 8601 datetime string.
  * [Search Bags](/api-reference/orders-and-checkout/orders/search-bags)
    * The `before_date` param in the request body is now deprecated.
    * The `after_date` param in the request body is now deprecated.
    * The `before_date_created` param in the request body is now deprecated.
    * The `after_date_created` param in the request body is now deprecated.
    * The `date_last_modified:min` and `date_last_modified:max` request body params have been added. Each of these will accept an ISO 8601 datetime string.
    * The `date_created:min` and `date_created:max` request body params have been added. Each of these will accept an ISO 8601 datetime string.
  * [Get All Orders](/api-reference/orders-and-checkout/orders/get-orders)
    * The `date_last_modified:min` and `date_last_modified:max` query params have been added. Each of these will accept an ISO 8601 datetime string.

**Dashboard Updates**

* The dashboard's ImageCropper now automatically enforces square image cropping when users upload rectangular images.
* Added a **Cancel Bag** button to the Channel dashboard's Bag details pane.
* The DevRev support widget has been relocated to the bottom of the main navigation bar in the Channel dashboard.

**Integration Updates**

* Support for WooCommerce merchants using non-native sales tools that inject the sale price into the `price_html` field has been added. These prices will now be extracted from the HTML and applied as the sale price on the Violet Sku.

## 2024.11.25

#### 🆕 Features

**API Updates**

* Adds improved date last modified filtering when retrieving a merchants offer count and when retrieving merchant offers.
  * The `since` query param on the [Get All Merchant Offers](/api-reference/catalog/offers/get-all-merchant-offers) endpoint is now deprecated.
  * The `date_last_modified:min` and `date_last_modified:max` query params have been added to the [Get All Merchant Offers](/api-reference/catalog/offers/get-all-merchant-offers) endpoint. Each of these will accept an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) datetime string.
  * The `date_last_modified:max` query param has been added to the [Get Count of Merchant Offers](/api-reference/catalog/offers/count-merchant-offers) endpoint. Similar to the existing `date_last_modified:min` query param on this endpoint it will accept an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) datetime string.

**Dashboard Updates**

* Adds the offer `type` property to the offer detail pane in the dashboard.

## 2024.11.18

#### 🆕 Features

**API Updates**

* The Cart endpoints in the Violet API Reference have been updated to include multiple request and response samples. These can be used to understand and account for potential non-happy-case scenarios.
* Violet will no longer create new Offers for external products that are initially in an archived state the first time they are synced. If an Offer was previously created in Violet before being externally archived the Offer will continue to be updated and will reflect a status of `ARCHIVED` before eventually moving to a `FOR_DELETION` state.

✨**Introducing enhanced support for `CUSTOM` Transfers**

You can now use the **Custom Transfers APIs** to manage pending distributions more flexibly during checkout. New capabilities include:

* Transferring pending distributions for a [**single order**](/api-reference/orders-and-checkout/transfers/transfer-funds-single-order)
* Transferring pending distributions for a [**single bag**](/api-reference/orders-and-checkout/transfers/transfer-funds-single-bag)
* Transferring pending distributions for [**multiple orders**](/api-reference/orders-and-checkout/transfers/transfer-funds-multiple-orders)
* Transferring pending distributions for [**multiple bags**](/api-reference/orders-and-checkout/transfers/transfer-funds-multiple-bags)

**Optimized Merchant Transfers for Bulk Distributions**:

When multiple distributions are associated with the same merchant, Violet now consolidates them into a single transfer, ensuring a streamlined and efficient bulk payment process.

Learn more about `CUSTOM` Transfers, [here](https://github.com/violetio/docs/blob/main/payments/payouts/guides/using-custom-transfers/README.md).

#### 🔧 **Fixes**

**Integration Updates**

* When the external commerce platform provides a carrier status that indicates an item has been successfully delivered, the Bag `fulfillment_status` will now have a value of `DELIVERED`. This will occur even when the external commerce platform does not have a native order fulfillment status that reflects delivery.

**API Updates**

* Resolved an issue where partial refunds for orders created via the [Create Order API](/api-reference/orders-and-checkout/orders/create-order) were miscalculating payment provider fees. Refund distributions now accurately reflect the correct amounts.
* Fixed a bug where the [Create Order API](/api-reference/orders-and-checkout/orders/create-order) did not correctly process line items with SKU quantities greater than one.

## 2024.11.13

#### 🆕 Features

**API Updates**

✨**Introducing Flexible Payment and Transfer Strategies**

Violet currently offers two payment processing models:

1. **Orchestrated Payments** — In this model, Violet orchestrates charges to the shopper and transfers payments to merchants.
2. **Bypassed Payments** — Here, Violet takes no action on payments or transfers. Instead, the Channel charges the shopper, and any transfers to merchants are managed by the channel.

We’re introducing greater flexibility in how you interact with Prism Pay, Violet’s orchestrated payments integration. You now have the ability to configure **capture** and **transfer** settings at both the app and merchant levels, giving you more control over the payment flow. You will see `capture_method`, `transfer_method` on the PaymentTransaction model that is returned as a part of the Cart. Each of these will have their own dedicated statuses, which you can learn more about in [PaymentTransactions](/prism/payments/payments-during-checkout/payment-transactions).

* **Capture Method** — This defines how the shopper’s payment method is charged. Available options are `AUTOMATIC`, `EXTERNAL` and `CUSTOM`.
  * **Automatic** — Violet generates a pending charge on the shopper’s payment method and automatically captures it once the order is successfully submitted.
  * **External** — The channel manages all aspects of fund capture from the shopper. Violet does not take any action with Stripe to charge the shopper in this scenario and assumes payment has been captured directly by you.
  * **Custom** — Violet creates a pending charge on the shopper’s payment method but will only capture funds when triggered separately by the channel. This setup is ideal if you want the shopper to be charged once specific conditions have been met. For example, capture funds only after the merchant fulfills the order. (Support for`CUSTOM` capture will be released in a future iteration of this feature. Timing TBD.)
* **Transfer Method** — This determines how Merchants receive funds for each order placed through Violet. Available options are `AUTOMATIC`, `EXTERNAL` and `CUSTOM`.
  * **Automatic** — Violet generates and processes the transfer of funds to Merchants automatically as part of each order submission, ensuring merchants are paid in an automated fashion.
  * **External** — The Channel fully manages Merchant transfers and payouts for orders placed through Violet. Violet does not generate any transfer, distribution or payout records for bags and orders associated with these Merchants.
  * **Custom** — Violet creates Distribution records for Merchants but only transfers funds when prompted by the channel. While merchants can view their pending Distributions in the Merchant Dashboard, they will not receive funds until the channel initiates the transfer of funds. (APIs for `CUSTOM` transfer initiation will be launched on Nov 18.)

App-level and merchant-level payment bypassing will now be known as `EXTERNAL` capture and `EXTERNAL` transfer. Reach out to our support team to learn more about how to configure these payment options.

## 2024.11.11

#### 🆕 Features

**Integration Updates**

* Safety stock rules can now be applied to a merchant's Violet configuration to enable custom out of stock levels. Upon request, safety stock rules can be applied based on collection, category, tag, or vendor. As an example, if a merchants custom out of stock level is 2, then relevant Sku’s will be marked as out of stock when their available quantity reaches 2 or less.

#### 🔧 **Fixes**

**Dashboard Updates**

* Fixes an issue with the dashboard not being able to migrate a Stripe standard account to a Stripe express account.
* Fixes an issue with refund distributions not being generated for transactions that occurred through a Stripe platform account.

## 2024.11.06

#### 🆕 Features

**Violet Connect Updates**

* Support for adding an optional Shopify Storefront API Access Token as part of the the Shopify API credential onboarding step.

## 2024.11.04

#### 🆕 Features

**Dashboard Updates**

* When a new Channel account is created on the [Violet Dashboard](https://channel.violet.io/sign-up), a pre-configured Payout Account for Demo mode is now automatically enabled, allowing for immediate order processing.

**API Updates**

* The [Create Order](/api-reference/orders-and-checkout/orders/create-order) API now supports orders in multiple currencies, enabling shoppers to be charged in the specified currency on the Cart when the Order is placed.
* **⚠️ Notice of Future Breaking Change**
  * On November 11th, 2024, the following changes will be made to the `Cart` object:
    * `bag.transactions` will be removed.
    * `intent_based_checkout` will be removed.
    * `payment_transaction.status` will be replaced by `payment_transaction.capture_status`.

{% hint style="info" %}
If your application uses fields that are being removed, we recommend migrating to the payment\_transactions field on the Cart object to view Order payment details. You can learn more about Payment Transactions [here](/prism/payments/payments-during-checkout/payment-transactions).
{% endhint %}

**Integration Updates**

* Shopify merchants can now limit the sourcing of their Sku inventory levels to an explicit list of one or more [locations](https://help.shopify.com/en/manual/fulfillment/setup/locations).
* Support of the Shopify [Storefront API](https://shopify.dev/docs/api/storefront) has been fully implemented. This API is rate-limit-free and will be used for all checkout steps prior to order submission for any merchants who provide the necessary scopes.

## 2024.10.28

#### 🆕 Features

**Integration Updates**

* Optimized RESTful endpoint has been added to the Magento 2 extension that enables for order creation using a single API call.
  * We recommend that Magento 2 (Adobe Commerce) merchants upgrade to version `1.3.0` when convenient to do so.
* We now request two additional scopes from Shopify merchants during [Shopify merchant onboarding](https://merchant-help.violet.io/platform-guides/shopify):
  * `write_merchant_managed_fulfillment_orders` - allows for a fulfillment hold to be applied to an order when fraud is suspected. This ensures that a merchant does not fulfill an order before an investigation has been completed.
  * `unauthenticated_write_checkouts` - allows for Shopify carts to be created using the [GraphQL Storefront API](https://shopify.dev/docs/api/storefront). This API allows for all cart creation steps before order submission to be performed without consuming rate limits.

## 2024.10.21

#### 🆕 Features

**API Updates**

* Stripe Payment Intents are now supported when performing [Direct Order Submission](/prism/checkout-guides/guides/direct-order-submission).
* Cart creation now surfaces improved error messaging when external failures occur. See [Handling Cart Creation Errors](/api-reference/orders-and-checkout/carts/create-cart#handling-cart-creation-errors).

## 2024.10.14

#### 🆕 Features

**API Updates**

* The ID of the parent Offer is now included in the Sku data for all new carts in the `offer_id` property.
* Added the `external_id` property to the [Offer Shipping Data](/prism/catalog/offers#offer-shipping-data).
* Added a default limit of `5` concurrent channel initiated catalog re-syncs. Please reach out to your Violet account manager of you require a higher limit.

**Integration Updates**

* Added a parser that extracts Magento 2 product descriptions from [Magezon Page Builder](https://commercemarketplace.adobe.com/magezon-module-pagebuilder.html) templating tags.

#### 🔧 **Fixes**

* Fixed issue where the `taxes_included` property on a Bag could default back to a value of `false` if the order was later processed by an order reconciliation event. This had no impact or totals or the amount the shopper was charged.

## 2024.10.07

#### 🆕 Features

**API Updates**

* Improved surfacing of errors cause by Sku unavailability during order submission. Additionally, when a platform rejects an order due to Sku unavailability Violet will imediately mark that Sku as no longer available in the Violet system. See [Handling Cart Submission Errors](/api-reference/orders-and-checkout/cart-completion/submit-cart#handling-cart-submission-errors) for more details.

#### 🔧 **Fixes**

* Fixed issue where the failure of a single bag during order submission could result in all bags being cancelled/voided. The root cause of this was a failure within Stripe when performing the developer account payout transfer after the capture amount had been reduced.

#### 🧼 Clean Up

* Began effort to significantly improve property descriptions and example responses in the Violet API Reference. The initial improvements will focus on Catalog and Cart/Order endpoints, and will expand from there.

## 2024.09.30

#### 🆕 Features

**API Updates**

* [Direct Order Submission](/api-reference/orders-and-checkout/orders/create-order) no longer requires approval and is open to all channels.

**Integration Updates**

* Adds support for extracting free shipping constraints for WooCommerce merchants using the [Flexible Shipping plugin](https://wordpress.org/plugins/flexible-shipping).
* Magento 2 extension version `1.2.0` has been released to the [Magento Marketplace](https://commercemarketplace.adobe.com/violet-violetconnect.html). This version adds several new custom endpoints to the Magento REST API that improves the speed and performance when performing Quick Checkout and Cart Estimations.

#### 🧼 Clean Up

* Improved exceptions thrown when Checkout is performed on a Merchant that does not have a payout account.

## 2024.09.23

#### 🆕 Features

**Dashboard Updates**

* The Bag ID column in the bags table is changed to use Order ID instead.
* The Order ID is included in the bag detail pane.

**API Updates**

* Shipping data on the Offer object can now be enabled on a per-merchant basis. It is currently limited to the `SHOPIFY` integration. You can learn more about how to enable and use Offer shipping data [here](/prism/catalog/offers#offer-shipping-data).

#### 🔧 **Fixes**

* Fixed issue where the Merchant synced offers count was showing a different offers synced count on the channel dashboard when compared to the merchant dashboard.

## 2024.09.16

#### 🆕 Features

**Dashboard Updates**

* Adds Offer status filtering on the Merchant and Channel dashboards.
* Adds Brand search on the Merchant and Channel offers pages.

**API Updates**

* Shipping data on the Offer object is now being beta-tested with several merchants. This feature will achieve stable release in an upcoming deployment.

**Integration Updates**

* Added an explicit inventory availability check during Shopify order submission. This is in response to recent observations of Shopify allowing for out of stock items to be purchased.

## 2024.09.09

#### 🆕 Features

**Dashboard Updates**

* Search by orderId functionality added to the merchant dashboard Bags page.

## 2024.09.06

#### 🆕 Features

**API Updates**

* When a cart is submitted the order `status` will now immediately change to `PROCESSING` and all additional calls to submit the cart will result in an exception until the initial request has completed. This is an expansion of our existing efforts to prevent double-submissions and the subsequent race condition errors that they can cause.

The following error message will be returned when subsequent order submission requests occur before the initial request has completed:

```json
{
"message": "Order submission is in progress. Please wait for the submission to complete before trying again.",
"error": "order_submission_in_progress",
"code": 4238
}
```

## 2024.09.04

#### 🆕 Features

**Dashboard Updates**

* Updates the offers page on the merchant dashboard for improved publishing controls.
* Updates the live and test mode toggle design on the channel dashboard.

**API Updates**

* Alternate text will now be present on media when the merchant has populated this value within their commerce platform.
* Added a fallback solution for the rare Shopify "Unable to reserve inventory" error during draft order submission. When Shopify returns this error Violet will now perform an additional query to Shopify to determine if this is a valid or invalid error. If the error is invalid Violet will bypass the error and re-submit the order.

#### 🔧 **Fixes**

* Fixed issue where the default switch value displayed on the notification settings in the Channel dashboard was incorrectly showing the setting as switched off when it should be on.
* Fixed issue where a Shopify refund may not immediately be processed when the webhook was received and was instead processed during the next reconciliation event.

## 2024.08.26

#### 🆕 Features

* Channel users will receive emails when a connected merchant store is disabled or re-enabled.
* Channel users will receive notifications on the notifications page when a connected merchant store is disabled or re-enabled.
* Channel users can control their email notification settings related to merchant status changes from the notification settings page.

#### 🔧 **Fixes**

* Fixed Stripe dashboard link issue in Violet Connect when clicking “Go to Stripe” after successful payout account setup.

## 2024.08.20

#### 🆕 Features

**Dashboard Updates**

* Channel users are now able to change the commission rate and commission locked values for each merchant in the merchants tab.

**API Updates**

* The syncing of "sale prices" can now be disabled on a per-merchant basis. When disabled, Violet will only sync the "retail price" which will be reflected on the Offer and will be used when creating carts and submitting orders.

#### 🔧 **Fixes**

* Fixed issue where missing properties in the Shopify product webhook data could lead to a failed webhook. As Shopify continues to remove properties from the webhook body we will continue to expand our usage of the Shopify GraphQL API to obtain extended data as real-time product events are processed.
* Added fallback handling for merchants who have removed the store name in their external commerce platform. While very rare and not possible in most platforms, this could lead to a failed onboarding.

## 2024.08.13

#### 🆕 Features

**API Updates**

* Support for ongoing order reconciliation has been added to the BigCommerce integration. This process will regularly check the status of external BigCommerce orders to ensure that no order fulfillment, refund, or cancellation webhooks were unsent or missed.

## 2024.08.05

#### 🆕 Features

**API Updates**

* Order cancellations is now in beta and available for use by all channels. See [Cancel Order](/api-reference/orders-and-checkout/order-cancellations/cancel-order).
* Commission rate change logs are now available on the API and available for use by all channels.

## 2024.07.29

#### 🆕 Features

**API Updates**

* Channels are now able to configure default commission rates and lock commission rates by default through the app configuration. New merchants connected to an app through Violet Connect will automatically have the app's default commission rate and locked values applied on connection.
* Channels can pre-configure custom commission rates and commission locked values with a `channel_merchant_id` which will be applied when a merchant is sent through Violet Connect with a matching `channel_merchant_id` query parameter. These custom values take priority over the app configuration's default commission rate values.

#### 🔧 **Fixes**

* Fixed issue where Violet was processing payout information for Stripe Standard accounts without accounting for payments not related to Violet. Payouts dashboards will no longer show data not related to Violet.

## 2024.07.22

#### 🆕 Features

**API Updates**

* An [Address Block List](https://github.com/violetio/docs/blob/main/channel-docs/prism/overview/carts-and-bags/customers.md#blocked-addresses) has been implemented that will prevent historically fraudulent addresses from being applied to a new Violet cart. These are addresses that have been used as the shipping address with proven stolen card numbers in past Violet orders. This block list can be enabled or disabled on a per-app basis.

#### 🔧 **Fixes**

* Fixed issue where automatic discounts from a `BIGCOMMERCE` merchants store were not being reflected on the Violet cart.
* Fixed issue where Variants and Variant Values for `WOOCOMMERCE` sourced Offers did not always have a populated `display_order` property.

## 2024.07.15

#### 🆕 Features

**API Updates**

* (Coming Soon) Order Cancellation via Violet APIs is now in alpha testing. Reach out to learn more about this feature.

**Integration Updates**

* Store pickup type shipping options will now be filtered out of the available shipping methods.

🔧 **Fixes**

* Fixed issue where incorrect Distributions would get updated on Stripe payout events

## 2024.07.08

#### 🆕 Features

**API Updates**

* ✨**Introducing Payment Transactions**
  * Carts that use Violet for payment orchestration will now expose Payment Transaction information, such as underlying payment provider and current payment state. Learn more about payment transactions [here](/prism/payments/payments-during-checkout/payment-transactions).
* ✨**Introducing Direct Order Submission**
  * Direct order submission enables channels who calculate their own tax and shipping rates to submit fully composed orders in a single request. Learn more about direct order submission [here](/prism/checkout-guides/guides/direct-order-submission).

**Integration Updates**

* Added a workaround for the new Shopify “Market has Changed” bug where Shopify would prevent international shipping addresses from being applied to any orders sourced by US merchants enrolled in the new [Managed Markets](https://www.shopify.com/international/managed) program. These orders will now succeed unless the items being purchased are [restricted](https://help.shopify.com/en/manual/international/managed-markets/prohibited-items) in the shoppers country.

**Dashboard Updates**

* Merchants can now view, export, and see a breakdown of their payouts in the Violet Dashboard.

#### 🔧 **Fixes**

* Fixed issue where new message threads on the Channel and Merchant dashboard would be stuck in an unread state.
* Fixed issue where automatic discounts in an external BigCommerce cart were not factored into the Violet cart totals when a promo code was also being applied.
* Fixed issue where modifying the quantity of an existing item in a Violet cart could fail with an exception stating that the merchants credentials were not found.
* Fixed issue where the inventory may have appeared as out of stock when a BigCommerce merchant used the parent product for tracking inventory instead of the individual variants.

## 2024.07.01

#### 🆕 Features

* Shopify free shipping discounts can now be applied to a cart before a shipping method is selected.
* Order reconciliation is now available for WooCommerce merchants. With order reconciliation, Violet will regularly check the status of the external order to ensure that no order lifecycle webhooks were unsent or not received. This feature is also currently available for Shopify and Wix merchants.

#### 🔧 **Fixes**

* Fixed issue where Offer-level currencies for non-USD Wix merchants would default to USD while the Sku-level currencies correctly reflected the store currency. Now both the Offer and Sku will reflect the store currency.
* Fixed issue where WooCommerce discount amounts were not spread evenly across all line items in a WooCommerce order.
* Fixed issue where WooCommerce Relay Shipping Zone lookup could fail if the merchant used a 3rd party plugin to inject custom prices that were rule-based strings instead of numeric prices. Violet will now parse the string to find the price and will fallback gracefully if the string is too complex or contains no numeric values.

## 2024.06.24

#### 🆕 Features

* Clicking into a specific payout in the payout dashboard will open up a new view that houses important information around payout summary and a list of relevant distributions. You can also export a single report.
* Adds support for price overrides in Magento 2. **Merchants must have installed the latest version of the** [**extension**](https://commercemarketplace.adobe.com/violet-violetconnect.html)**, `1.2.0` or higher, to unlock this feature.**
* Adds notification emails when a user has not read new messages in the Channel and Merchant dashboard.
* Users can update messaging notification preferences from the Channel and Merchant dashboard settings.
* Expands the detection of the Shopify "Totals Have Changed" Draft Orders API bug. Now anytime Draft Order submission fails with an error message that contains the partial string `totals have changed` or `try again` we delete the Draft Order and instead write the Order using the Shopify Orders API. This guarantees delivery of the Order.

#### 🔧 **Fixes**

* Fixed date formatting issues for payout\_date\_created and payout\_date\_settled in exported Payouts and Distributions reports.
* Fixed issue where non-US based Stripe Connect accounts migrating between Standard and Express accounts did not correctly assign service agreement type.

## 2024.06.17

#### 🆕 Features

* Added support for “New Customers Only” type Shopify discount codes. See [Customer Restricted Discounts](/prism/checkout-guides/discounts#customer-restricted-discounts).
* Added explicit opt-out for Shopify SMS marketing.
* SFCC collection syncs will now default to the OCAPI Shop API. Upon request this can be switched to the OCAPI Data API on a per-merchant basis.
* Create Thread modal will let the user know if they are an active participant in a thread.
* Selected thread on the dashboard will persist as the user navigates around the dashboard.
* Added Offer status to the Offer sidebar in the Offers page.

#### 🔧 **Fixes**

* Fixed issue where SFCC collection syncs could fail due to missing data in some RefArch products.

## 2024.06.10

#### 🆕 Features

**Integration Updates**

* Re-implements the usage of the Bag `SUBMITTED` status for non-cart platforms (WooCommerce, Ecwid) to prevent duplicated order submission when the Violet order submission endpoint is called multiple times in quick succession. See [Duplicate Submissions](/prism/checkout-guides/carts-and-bags/bags/lifecycle-of-a-bag#duplicate-submissions).

**Plugin Updates**

* Magento/Adobe Commerce extension [version 1.1.3 released](https://commercemarketplace.adobe.com/violet-violetconnect.html) to add remote webhook controls. This allows for Violet to remotely enable or disable the webhooks for a Magento merchant.

## 2024.05.28

#### 🆕 Features

**Dashboard Updates**

* Channels now have the option to include distributions in their payout reports.
  * When choosing what to include as part of the payout report, channels can opt to include ALL distributions columns, a CUSTOM set of distributions columns, or NONE.
  * If any distributions columns are chosen, the final report will be a downloadable ZIP containing two CSV files. One for payouts and one for distributions.
  * If NONE is selected, the final report will be a downloadable CSV that is just the payout report.

#### 🔧 **Fixes**

* Fixed issue where Distributions exports were missing the following columns
  * Payment provider fee reversals
  * Bag totals information (shipping total, tax total, discount total, etc.)
  * External Order information

## 2024.05.20

#### 🆕 Features

**Dashboard Updates**

* ✨**Introducing Messaging**
  * Channels and Merchants connected through Violet Connect are now able to message each other on the Dashboard

    * Support for Emojis and Rich text
    * Users typing indicator
    * Mark a thread as unread and come back to it later
    * \[Channels] Navigate to merchant connection health, bags, and offers from the messaging details pane
    * \[Merchants] Navigate to bags and distributions from the messaging details pane

    ⚠️ Restrictions

    * Channel org collaborators are unable to start conversations with merchants but can be added to conversations by Channel admins

    ![](https://res.cloudinary.com/ddhjp8mca/image/upload/v1716295010/mintlify/channel-dashboard/messaging_1_ckeowx.png)

    ![](https://res.cloudinary.com/ddhjp8mca/image/upload/v1716295005/mintlify/channel-dashboard/messaging_2_tfkn9k.png)

    ![](https://res.cloudinary.com/ddhjp8mca/image/upload/v1716294997/mintlify/channel-dashboard/messaging_3_jmonmp.png)

**Integration Updates**

* Can now filter Ecwid merchant catalogs by category ID upon merchant request.

#### 🔧 **Fixes**

* Fixed issue where a WooCommerce Sku that was deleted after a cart was created could still be purchased at checkout.
* Fixed issue where Credential errors when onboarding a Wix merchant were showing as generic “Something went wrong” errors.
* Fixed issue with broken payout docs link on the export payouts modal

#### 🧼 Clean Up

* Improved search behavior across pages

## 2024.05.13

#### 🆕 Features

**Dashboard Updates**

* Added export functionality to payouts dashboard.
  * Get a complete report of your payouts in CSV format in a given date range.
  * Functions the same way as distributions but with fixed columns for payouts (i.e. no column customization).

**API Updates**

* Added the `parent_id` property to the Collection model. This property will be populated when a child collection is synced from a SFCC merchant. For collections on any other platform, or for top level parent collections on SFCC, this property will be `null`.

**Integration Updates**

* Added support for preferring Short Description over Long Description for WooCommerce merchants who have added their data to that field. Please [contact support](/help/support-request) if you would like this enabled for one of your merchants.

#### 🔧 **Fixes**

* Fixed issue where removeSkuFromCart could fail in some cases.
* Fixed issue where SKU `type` could not be updated when it changed on a merchant’s platform.
* Fixed issue where Shopify and WooCommerce webhooks could sometimes get deactivated, especially by other parties in the merchant’s ecommerce platform, for example a different app or plugin. Webhooks are now re-subscribed on a schedule if they are detected to be inactive.
* Fixed issue where Shopify errors when trying to apply a shipping method were not being properly parsed and returned on the cart object.

## 2024.05.06

#### 🆕 Features

**Dashboard Updates**

* ✨**Introducing Payouts View**
  * Search and View payouts, funds transfers from the PSP to your bank account.
  * Available in its own tab in the left nav of the dashboard. Distributions are still accessible via a subtab within the payouts page.

**Integration Updates**

* Added support for using discount codes with ECWID. Discounts will automatically work for Ecwid merchants who onboarded after 04/30. Ecwid merchants who onboarded before 04/30 will need to perform the Ecwid OAuth process again to obtain the required scopes.
* Added support for Salesforce Commerce Cloud collection syncing.

#### 🔧 **Fixes**

* Fixed issue where distributions exports had an incorrect date format.
* Fixed versioning issue that prevented some PrestaShop merchants from onboarding.
* Fixed issue where collection-constrained Shopify discounts with a type of `across` were not being evenly spread across entitled products.

## 2024.04.29

#### 🆕 Features

**Integration Updates**

* ✨**Introducing Order Consolidation**
  * This feature will routinely examine bags in an `ACCEPTED` state and recheck their status in the external store to ensure that no order change events were missed.
  * This feature is initially supported for the `Wix` platform, due to their lack of webhook support.
  * Violet expects to add support for other platforms in the future.

#### 🔧 **Fixes**

* Fixed issue where collection-limited Shopify discounts could be applied in full to all entitled items instead of across all entitled items.
* Fixed issue where non-USD Wix merchants were not correctly setting the currency on the Violet Sku.
* Fixed issue where the Get Offer by ID endpoint didn't include a value for the `default_image_url`. This resolves the issue in the Offers View on the Dashboard where clicking on an offer would make the image thumbnail disappear.

## 2024.04.22

#### 🆕 Features

**API Updates**

* ✨**Introducing Webhook Events for** [**Collections**](/prism/catalog/collections)
  * See [docs](/prism/webhooks#collections) for more details.

**Integration Updates**

* Integrated with the developer preview of the new Wix Order Payments API endpoint. This remediates the long running Wix bug that has prevented merchants from performing granular refunds on orders placed through the Wix API. Wix merchants will no longer need to fully cancel an order to initiate a refund.
* We are now able to discover WooCommerce refunds that are nested in metadata even when the order itself is not marked as being refunded by the merchant.

**Distributions Updates**

* When you export distributions now from both the Channel and Merchant dashboards, all amounts shown are in the main currency unit, not fractional currency unit. For example, if your currency is USD, all amounts shown are now in dollars instead of cents.

#### 🔧 **Fixes**

* Fixed issue where a WooCommerce products with a single downloadable Sku was incorrectly being marked as `PHYSICAL` instead of `DIGITAL`.
* Fixed issue where new merchants had a status of `Application_In_Progress` instead of `Active`.

## 2024.04.09

#### 🆕 Features

**Dashboard Updates**

* Distributions exports now include payout settlement dates! When exporting Distributions, you can choose to include this column to easily go between the date a Payout hits your bank account and the associated Distributions in Violet.

**Integration Updates**

* Integrated with the Shopify GraphQL API for product syncs. This will allow Violet to add to support for new properties that Shopify is adding to their GraphQL models but not REST models. Violet will now begin switching Shopify merchants over to using the GraphQL sync in batches as we monitor how it scales.
* Added the ability for channels to request custom scopes during merchant onboarding. These can be in addition to the default scopes, a reduced version of the default scopes, or a completely custom set of scopes, depending on each channels requirements.

#### 🔧 **Fixes**

* Fixed issue where users with the finance readonly permission could begin a payout account migration.
* Fixed issue where App Name on Distributions on the Merchant dashboard were missing.

## 2024.04.01

#### 🆕 Features

**Dashboard Updates**

* Distributions in the Channel Dashboard can now be filtered by Date and Merchant.
* Distributions in the Merchant Dashboard can now be filtered by Date and Channel.

#### 🧼 Clean Up

* Improvements to payout migrations in dashboard.
  * Added external ids to all payout cards.
  * Updated styles on payout cards and loaders.
  * Dashboard links removed for past express accounts that never completed onboarding.
  * Added a learn more section for our payouts docs in the payouts page.
* Better handling of finance readonly permissions for payout migrations in dashboard.

## 2024.03.25

#### 🆕 Features

**Dashboard Updates**

* Merchants will now receive notifications when a channel changes their commission rate.

**Integration Updates**

* Added support for Wix discount codes.

#### 🔧 **Fixes**

* Fixed issue where Wix sample products were synced into Violet if the merchant did not remove them before connecting to Violet.
  * See [FAQ](/faqs/catalog#why-cant-i-see-my-test-offers-or-skus-or-variants-from-my-test-store-in-violet) for more info.
* Fixed issue where some Squarespace variants were not syncing correctly.
* Fixed issue where description HTML was being filtered out for Ecwid offers.

#### 🧼 Clean Up

* Added UI element to inform merchants that their commission rate has been locked by the channel is able to be edited.

## 2024.03.18

#### 🆕 Features

**Dashboard Updates**

* Users on the Merchant Dashboard can now exclude Channel distributions from exports.
* Users on the Channel Dashboard can now exclude Merchant distributions from exports.

**API Updates**

* Added the automatic detection and disablement of Bundled Shopify Products. This is in response to the growing adoption of the [Shopify Bundles app](https://apps.shopify.com/shopify-bundles) and Shopify’s decision to block the sale of bundled products through their Order API’s at this time. For any bundled product synced into Violet, the Offer and any nested Sku’s will have a `status` value of `UNAVAILABLE`.
* ⚠️ **Notice of Future Breaking Change** - On April 15th 2024 we will release an update that adds the `BUNDLED` enum to the `type` property on the Offer model. If your application uses enums for this property we recommend adding coverage of this enum before April 15th. Once added, the possible values will be `PHYSICAL, DIGITAL, VIRTUAL, BUNDLED`. Once implemented, any Offers sourced from a Bundled Shopify Product will have a `type` value of `BUNDLED`.

{% hint style="info" %}
If you are unable to implement coverage of the `BUNDLED` enum by April 15th please notify your primary contact at Violet.
{% endhint %}

## 2024.03.11

#### 🆕 Features

**Dashboard Updates**

* Added a toggle to the Dashboard distributions page to allow users to exclude Merchant or Channel distributions from the distributions table.

**API Updates**

* ✨**Introducing Merchant Configuration management by Channels via API**
  * Enable/disable the syncing of Offer Collections.
  * Enable/disable the syncing of Offer Metadata.
  * Managed on a per-merchant basis.
  * See [API Reference](/api-reference/merchants/configuration/get-merchant-configuration).

#### 🔧 **Fixes**

* Fixed issue where clicking out of the date picker in the distributions export modal did not close the date picker.
* Fixed issue where non-json webhook responses were not being displayed on the webhooks page.
* Fixed issue where a single product failing to sync would cause the entire catalog sync to fail.
  * Individual product sync failures will now only impact that particular product.
* Fixed issue where webhook `remote_endpoint` + `status` combinations could be duplicated for a channel.
* Fixed issue where cart creation and checkout endpoints periodically failed due to a database query failure.
  * Failed queries will be retried for up to 15 seconds.
  * We will be monitoring this for further tuning. Please [contact support](/help/support-request) if you see further `Internal Database Error` messages.
* Improved merchant health caching when a new merchant connects. Merchants who successfully completed all steps in the process show now show `COMPLETE` after they set their commission rate.
  * While this should cover most cases, there are still some moments when a Channel will need to click on the merchant and use the refresh button on the appropriate tab.
  * See [docs](/prism/violet-connect/guides/connection-health) for more details.

#### 🧼 Clean Up

* Added a tooltip to view long external order IDs in the Merchant Dashboard distributions.
* Added tooltips in the Dashboard distributions export modal to link to the Distributions docs.

## 2024.03.05

#### 🔜 Coming Soon

* In an upcoming release, Violet will begin auto-disabling webhooks that regularly fail.
  * Please take the time to use the [Channel Dashboard](https://channel.violet.io/webhooks) to help diagnose any issues you have with failing webhooks.
  * See [Documentation](/prism/webhooks/handling-webhooks).

#### 🆕 Features

**Dashboard Updates**

* ✨**Introducing Stripe Account Migration for existing Merchants and Channels**
  * Existing Merchants and Channels can migrate away from their existing Stripe Express Account to their own Stripe Standard Account which they already use to do business elsewhere.
  * See [Documentation](https://merchant-help.violet.io/interacting-with-violet/getting-paid/connecting-new-stripe-accounts).

**API Updates**

* ✨**Introducing Shipping Zones via Relay API**
  * Retrieve a Merchant's Shipping Zones.
  * Retrieve a Merchant's Shipping Regions.
  * Retrieve a Merchant's Shipping Methods.
  * See [Documentation](/relay/get-shipping-zones).
  * See [API Reference](/api-reference/relay/shipping/get-shipping-zones).
* ✨**Introducing Price Overrides in Checkout**
  * This much requested feature allows you to override line item and shipping method prices during checkout.
  * See [Documentation](/prism/checkout-guides/carts-and-bags/carts/override-prices).

#### 🔧 **Fixes**

* Fixed issue where Refund Distributions were not being tied to the correct Payout. These should now be linked to the Payout which Stripe debits the refund from.

## 2024.02.26

#### 🆕 Features

**Dashboard Updates**

* ✨**Introducing Real Time Merchant Notifications**
  * New Notifications page in Merchant Dashboard to view real time notifications.
  * Get notified when a Export is complete (see below).
  * More notifications to come in the future.
* ✨**Introducing Merchant Distributions with Exports**
  * New Distributions page in Merchant Dashboard to view detailed Merchant Payout information.
  * Export distributions data for a selected time frame.
* ✨**Introducing Stripe Account Linking for New Channels**
  * New Channels can connect an existing Stripe Account to Violet to be used for payouts through the Channel Dashboard.
  * See [Documentation](/prism/payments/payouts#stripe-standard-account).

**API Updates**

* ✨**Introducing Commission Rate management by Channels via API**
  * Set commission rate for your merchant.
  * Lock commission rate preventing changes by the merchant.
  * See [Documentation](/prism/payments/payouts/commission-rates).
  * See [API Reference](/api-reference/apps/commission-rates/set-merchant-app-commission-rate).

#### 🔧 Fixes

* Fixed issue where the “Store Disconnected” notification did not render the merchant name and merchant logo.
* Fixed issue where Sync Status was incorrectly showing as failed for some merchants.

## 2024.02.20

#### 🆕 Features

**Dashboard Updates**

* Merchant distributions are now included in the distributions export.

#### 🔧 Fixes

* Fixed issue where some merchant's product syncs would get locked and never update even when they were scheduled to update periodically.
* Fixed issue where distributions exports were not including the end date data in the report. Ex. Feb 16-19 will now correctly include data for the 19th.

#### 🧼 Clean Up

* Added missing icons for Merchants Tab.
* Updated language in the Scopes Tab of the Merchant Detail View in the Merchant Tab to clarify what is wrong and what needs fixing when a scope is missing.
* Updated Stripe brand assets across the dashboard.

## 2024.02.12

#### 🆕 Features

**Dashboard Updates**

* ✨**Introducing Real Time Notifications**
  * New Notifications page in Channel Dashboard to view real time notifications.
  * Get notified when a Merchant connects or disconnects from your channel.
  * Get notified when a Merchant updates their commission rate.
  * Get notified when a Export is complete (see below).
* ✨**Introducing Channel Distributions with Exports**
  * New Distributions page in Channel Dashboard to view detailed Channel Payout information.
  * Export distributions data for a selected time frame.
  * See [Documentation](/prism/payments/payouts/distributions)
* ✨**Introducing Stripe Account Linking for New Merchants**
  * Merchants can connect an existing Stripe Account to Violet to be used for payouts through both Violet Connect and the Merchant Dashboard.
  * See [Documentation](/prism/payments/payouts#stripe-standard-account).

**API Updates**

* ✨**Introducing Collections support**
  * Support for syncing merchant product collections.
  * See [Documentation](/prism/catalog/collections).
  * See [API Reference](/api-reference/catalog/collections).

**Integrations Updates**

* Added support for Wix images that surpass the max size, they will be automatically scaled down to the maximum allowed.

#### 🔧 **Fixes**

* Fixed issue where wallet based carts created without any SKUs would not have a `payment_intent_secret` value once a SKU was added and the cart was priced.
  * For all wallet based carts, as soon as a cart with a total that is greater than 0 is priced, the `payment_intent_secret` value will be returned on the response. A cart is priced either by passing `?price_cart=true`, calling the [Price Cart endpoint](/api-reference/orders-and-checkout/cart-pricing/price-cart) or via endpoints that auto price carts like [Set Shipping Methods](/api-reference/orders-and-checkout/cart-shipping/set-shipping-methods).
  * For a wallet based carts that never have a total greater than 0, i.e. promotions or gifts, a `payment_intent_secret` will never be generated.

#### 🧼 Clean Up

* Updated Navbar UI in Channel and Merchant Dashboard.

## 2024.02.05

#### 🆕 Features

**Order Updates**

* Include Carts in Order Search Responses.
  * Carts are not included by default, add `exclude_in_progress=false` to include them.
  * Filter for *only* Carts by adding `{"bag_status": "IN_PROGRESS"}` to the query.
  * See [API Reference](/api-reference/orders-and-checkout/orders/search-orders).
* The [Set Shipping Methods](/api-reference/orders-and-checkout/cart-shipping/set-shipping-methods) endpoint will now always return a fully priced cart in the response, regardless of the merchant's platform.

**Integrations Updates**

* Migrated from Shopify API version `2023-04` to the latest stable version `2024-01`. This will address warning emails sent out by Shopify indicating that Violet is using deprecated APIs.

#### 🔧 **Fixes**

* Fixed issue where Merchant Dashboard did not update commission rate when changed from 0%.

#### 🧼 Clean Up

* Cache redundant network requests in Channel Dashboard.

## 2024.01.29

#### 🆕 Features

**Integrations Updates**

* Introduced Merchant Configuration to better allow for the enablement of unique merchant requirements.
  * The syncing of product [metafields](https://help.shopify.com/en/manual/custom-data/metafields) can now be enabled for Shopify merchant’s who require it.
  * The use of custom shipping rates can now be disabled for Shopify merchants who are no longer impacted by Shopify’s $0 shipping bug and/or local pickup bug.
  * The products that Violet syncs can now optionally be limited to only those in a collection defined by a Shopify merchant.

#### 🔧 **Fixes**

* Fixed issue where Shopify promo codes that were applied before shipping methods were selected did not influence shipping methods that had price constraints. ex. A coupon that brings a total below $50 will now disqualify the order from the free shipping option for > $50 orders.
* Fixed issue where shipping methods were not being converted correctly back to a merchant’s currency in multi-currency bags.
* Fixed issue where non-USD currencies were not being converted correctly when displayed on the offer side panel in the channel dashboard and the matching view of the merchant dashboard.
* Fixed issue where the `remorsePeriodEnds` property on the bag did not reflect 30 days from the date the checkout was actually submitted.

## 2024.01.22

#### 🆕 Features

* Added webhook event cancel endpoint. See [API Reference](/api-reference/events/webhook-events/cancel-webhook-event-by-id).

#### 🔧 **Fixes**

* Fixed issue where the pagable property was null in certain endpoints.
* Fixed issue where wallet based orders were not being charged for apps with payment bypassing enabled.

## 2024.01.16

#### 🆕 Features

* Beta release of the new Estimate Cart endpoint. See [API Reference](/api-reference/orders-and-checkout/cart-pricing/estimate-cart).

#### 🔧 **Fixes**

* Fixed issue where bags were not being deleted off of a cart when the last sku was deleted for certain ecom platforms.
* Fixed issue where creating a cart with a foreign currency and an unavailable sku would result in an error.

## 2024.01.08

#### 🔧 **Fixes**

* Fixed issue where `page_number` property was 0 based instead of 1 based for paged endpoints.
* Fixed issue where Channel Dashboard would crash when adding a new app in the `/overview` or `/merchants` page.

#### 🧼 Clean Up

* Added missing demo tags to channel orders table.
* Updated examples for checkout APIs for easier use.

## 2023.12.18

#### 🆕 Features

**Dashboard Updates**

* Added sorting to orders pages in the dashboard.
* Added display merchant email button in channel connection page.
  * Email will be obfuscated a\*\*\*<r@gmail.com> for PII.
* Added support for custom ports in Violet Connect store url form.

**API Updates**

* Added documentation for endpoint allowing Channels to disconnect a Merchant from their App.
* Added support for Shopify discount codes with country entitlements.
* Added support for Webhook Event search by entity ids.
* Added endpoints for resending Webhook Events.

#### 🔧 **Fixes**

* Fixed issue where Wix image display orders were not being correctly calculated.
* Fixed issue where addresses were not being applied to all bags in multi-merchant checkouts under certain conditions.
* Fixed issue where double submitting an order would end up canceling it in certain conditions.
* Fixed issue where Wix refunds were not being processed due to bug introduced by Wix. This fix will be temporary until the bug is fixed in Wix’s code.
* Fixed issue where Shopify bundles were breaking checkout. Currently Shopify Bundles are not supported by the Shopify checkout API and so those products are disabled in Violet.
* Fixed issue where some non-USD transactions were not correctly persisting exchange rates, impacting payouts and analytics. Analytics will begin correctly tabulating from today onward.
* Fixed issue where Bag OrderSkus statuses were not correctly updated on partial refunds.
* Fixed issue where order totals were not visible from an overlap with the DevRev widget.

#### 🧼 Clean Up

* Updated sorting styling across pages with sortable data.
* Channel login page now includes a link to the signup page.
* Channel Dashboard users without a valid authentication token are now redirected to the sign-up page.
* Relocated the link to the Channel login page for enhanced visibility in the signup page.

## 2023.11.20

#### 🆕 Features

**Channel Dashboard Updates**

* ✨**Introducing Analytics Overview Page**
  * Users can check out GOV, commissions, and merchant data across various timelines.

#### 🔧 **Fixes**

* Fixed issue where `PARTIALLY_REFUNDED` bags were not updated to `REFUNDED` when subsequent refunds matched total amount.
* Fixed issue where some “Default Title” Shopify variants were not being properly ignored.
* Fixed issue where long order error messages were not being persisted.
* Fixed issue where BigCommerce webhooks were being incorrectly created.
* Fixed issue where Shopify email validation errors weren't translating to order errors in some situations.

#### 🧼 Clean Up

* Users can now open and close the bag detail view without losing their scroll position on the orders table.

## 2023.11.13

#### 🆕 Features

**Merchant Dashboard Updates**

* Added ability to filter by Channel and Date in the Orders View.
* Added ability to search by External Id in Orders View.
* Added ability to review selected products using Review mode in Products View.
  * Select the products you wish to review.
  * Click on "x Selected" and click "Review".

**✨Introducing Violet Support Widget**

* Contact support straight from your dashboard.
* View status of your tickets.

#### 🔧 **Fixes**

* Fixed issue where some Wix Orders were not able to be completed due to a serialization issue.
* Fixed issue where BigCommerce merchants were failing to register webhooks during onboarding.

#### 🧼 Clean Up

* Removed search by Violet Id from Merchant Dashboard.

## 2023.11.06

#### 🆕 Features

**Connection Health Updates**

* Added support for `Merchant_Complete` webhook. This webhook will fire when a previously unhealthy merchant becomes healthy.
  * Merchant health is evaluated at minimum once every 24 hours.
* Both `Merchant_Complete` and the existing `Merchant_Needs_Attention` will now correctly only fire once when a merchant’s overall health state changes.
* Both webhooks will now correctly take into account their overall health state as it relates specifically to each app they are connected to and will only fire for the appropriate apps.
* Added support to [Simulate Webhook](/prism/webhooks/simulating-webhook-events) for both `Merchant_Complete` and `Merchant_Needs_Attention`

**Integrations Updates**

* Adds post order failure reconciliation to the Shopify integration. When Shopify returns a failure response during order submission we will now query recent orders and attempt to discover if the order was successfully submitted before Shopify returned a failure response.

**Dashboard Updates**

* Removed the automated lock placed on merchants who onboard, delete their account quickly, then attempt to onboard again.
* ✨**Introducing Webhook Management on Channel dashboard**
  * View all your latest webhook events right on the Channel dashboard.
  * Use filters or search by event ID to narrow down your search for the right webhook event.
  * View all webhook endpoints subscribed by the Channel app along with their event count and error rates.
* Added the ability to filter orders by Merchant as well as Date in Channel Dashboard.
* Added the ability to filter products by Publishing Status as well as Availability in Merchant Dashboard.
* Added the ability to search, filter, and sort to the Merchants page in Channel Dashboard.
* Enabled beta offers search for offers page at `/offers` for Channel Dashboard and `/products` for Merchant Dashboard.
  * This will *greatly* enhance the responsiveness of these pages.
  * As a result, sort functionality on these pages has been disabled temporarily until sorting is better supported in the beta search.

**Order Updates**

* Added `external_id`, `before_date_created` & `after_date_created` filters to Bag Search [endpoint](/api-reference/orders-and-checkout/orders/search-bags).

#### 🔧 **Fixes**

* Fixed issue where Channel commission payout calculation was not taking discounts into consideration.
* Fixed issue where re-syncing a single Shopify product that has been deleted in Shopify would return a not found error. It now marks the offer as archived, as intended.
* Fixed issue where Channel specific commission rates were not displayed on the app cards on the merchant dashboard overview page.
* Fixed issue where Channel specific commission rates were not displayed on the merchant connection panel in the channel dashboard page.
* Fixed issue where the merchant filter menu in the channel orders table was missing some merchants.
* Fixed issue where the channel orders table was incorrectly sorted and missing some entries.
* Fixed issue where re-syncing a single product didn’t properly update for some ecom platforms.
* Fixed issue where creating a cart where the only sku for a merchant was out of stock lead to orphaned bags and made the cart unable to complete checkout.
* Fixed issue where the Channel orders page would fire off duplicate network requests.
* Fixed issue where changing the commission rate on a merchant dashboard app card would cause other app cards to display the default commission rate instead of their overridden values.

#### 🧼 Clean Up

* Updates to Merchant Dashboard Products table: reorganized columns, add Brand and Image columns, and removed Product ID column.
* Updates to Channel Dashboard Orders table: reorganized columns, add Merchant name and Date columns, and removed Order ID and Merchant ID columns.
* Added Date field to Bag Detail pane in Channel Dashboard Orders page.
* Re-enabled ability to filter offers by Inventory in Channel Dashboard.

## 2023.10.30

#### 🆕 Features

**Connection Health Updates**

* New Search Connection Health endpoint. See [API Reference](/api-reference/operations/connection/search-connection-health).
* Channels that do not use Violet Commissions (skipping the commissions screen in Violet Connect) will now always show their commission status as green in the Merchants tab on the Violet Channel Dashboard.
* Added scopes monitoring for ECWID merchants.

## 2023.10.23

#### 🆕 Features

**Channel Dashboard Updates**

* When loading the dashboard, the live/test toggle will automatically switch to the appropriate environment based on a Channel's live/not-live status.

#### 🔧 **Fixes**

* Fixed issue where Shopify free shipping discounts were improperly being deducted from the subtotal. They are now deducted from the shipping total as intended.

## 2023.10.17

#### 🆕 Features

**Webhook Updates**

* New Webhook Event Search [endpoint](/api-reference/events/webhook-events/search-all-webhook-events)!
* Added ability to retrieve the headers sent in a webhook event. See [API Reference](https://github.com/violetio/docs/blob/main/channel-docs/prism/webhooks/webhook-events.md#retrieving-a-single-event-headers-for-a-webhook)

**Shopify Integration**

* Expanded Shopify post-order reconciliation
  * A completed Shopify order is now more closely analyzed after submission to determine if any information is missing.
  * If it is determined that data is missing we will attempt to automatically update the order to reconcile the missing data.

#### 🔧 **Fixes**

* Fixed issue where Get Merchant by ID and Search Merchant endpoints were not loading `commission_rate` data correctly.
* Fixed issue where creating a `wallet_based` order with `UNAVAILABLE` SKUs did not surface correct error responses.
* Fixed issue where offers filter would crash when attempting to filter by merchant.

## 2023.10.09

#### 🆕 Features

**Channel Offer View Updates**

* Order search endpoint improved to allow search by `bag_id`, `merchant_id`, `bag_status`, `before_date` and `after_date`. See [API Reference](/api-reference/orders-and-checkout/orders/search-orders).
* Added option to filter by subscription status on offers page.
* Added subscription status to offers table.
* Added ability to select multiple offers for un/subscription on offers page.
* Added demo tags to demo offers and merchant connections in test mode.

#### 🔧 **Fixes**

* Fixed issue where digital-only bags would crash the order page bag view in channel dashboard.
* Fixed issue where Shopify discounts could not be applied when other discounts were in an `ERROR` / `EXPIRED` / `INVALID` state.

#### 🧼 Clean Up

* In the Merchant Dashboard, "Offers" and "Merchants" pages now redirect to the "Overview" page.
* Adjusted overflow on Order panel and Bag details dropdown.

## 2023.10.02

#### 🆕 Features

**New Integration: CommerceTools**

* Adds support for merchants on the CommerceTools platform.

**New Integration: Wix**

* Adds support for merchants on the Wix platform.

**Improved connection health monitoring**

* Added BigCommerce plan monitoring.
* Added WooCommerce scopes monitoring.
* Added Magento scopes monitoring.

#### 🔧 **Fixes**

* Fixed issue where shopify discounts were not correctly surfaced for Sandbox merchants.
* Fixed issue where empty offer descriptions would cause a crash in the channel dashboard offer panel.
* Fixed issue where a user who already had an org could still navigate to `/create-org` on the channel dashboard.
* Fixed issue for woocommerce stores whose IDs are larger than int.max.
* Fix issue where Product Tags from WooCommerce stores weren't flowing through to Violet Offers.
* Fixed issue where new channel account creation could fail in some cases.

## 2023.09.25

#### 🆕 Features

* Added support for Product Collection type Shopify Discounts.
* Added ability to filter offers by availability in tandem with filtering by merchant in channel dashboard.
* Added a total offer count in channel dashboard offers view.

#### 🔧 **Fixes**

* Fixed issue where the snack bar message incorrectly displayed "published" when unpublishing from offers in the Merchant Dashboard.
* Fixed issue where `channel.violet.io` did not redirect to the home page correctly.

#### 🧼 Clean Up

* The Channel Dashboard signup form now includes Company Function and Referral Channel fields, while the Country field has been removed.
* The Email Address and Organization Slug fields have been disabled in the Channel Dashboard Org Info form.
* Improved styling of Dashboard onboarding pages when the window width is reduced.

## 2023.09.18

#### 🔧 **Fixes**

* Fixed issue where new users were directed to create an org instead of accepting an invite to an existing org.
* Fixed issue where double clicking accept on an org invitation caused a duplicate user entry.
* Fixed routing behavior on account signup when using the browser back button.

#### 🧼 Clean Up

* Improved communication for merchant scopes status in Dashboard.
* Improved styling in the Dashboard Merchant connection panel when window width is reduced.
* Deleted Company Name field from the Org Info form in Dashboard.
* Add rate limiting to Dashboard Channel login attempts which can be reset by going through the forgot password flow.
* Fixed scrolling to view the entire form when window height is shortened in Dashboard onboarding pages.
* Cleaned up alignment issues on tables when content is scrollable.

## 2023.09.11

#### 🆕 Features

**Active Monitoring for Shopify Store App Scopes**

* Violet now actively monitors Shopify store app scope changes that could cause a checkout to fail.
* When store app scopes are missing a `MERCHANT_NEEDS_ATTENTION` webhook event is now triggered.

#### 🔧 **Fixes**

* Fixed issue that was leaving offers disabled during catalog resync.
* Fixed issue that allowed for expired or not started discounts to be used with Shopify carts.
* Fixed issue where previous offer image would be cropped by the loader when loading subsequent media.
* Fixed issue where Commission Rate was showing Needs Attention even though it had been correctly set.
* Fixed issue where adding different credentials for a store in Violet Connect didn’t immediately take effect, causing orders to fail for a number of minutes afterward.
* Fixed issue for mismatched values for order ID and merchant ID columns on channel orders page.

#### 🧼 Clean Up

* Granular calls to Connection Health will now update the parent cache for that merchantId.

## 2023.09.05

#### 🔧 **Fixes**

* Fixed issue where duplicate orders were placed when e-commerce platforms return certain 500 series response codes.
* Fixed issue where some Shopify merchants did not finish syncing their catalogs.
* Fixed issue where a Shopify’s merchant’s catalog was marked `disabled_available` shortly after initially going through Violet Connect.
* Fixed issue where the sub navigation menu remained open when clicking outside of it.

#### 🧼 Clean Up

* Updated External Payments information in settings/payments page and External Payments modal on Channel Dashboard.
* Fixed typos on country request list in Violet Connect.

## 2023.08.28

#### 🆕 Features

**Actively Monitoring for Shopify Store Plans**

* Violet now actively monitors Shopify plan changes that can affect the ability to complete a purchase.
* When a Shopify store moves to an inactive plan (eg. dormant or frozen), the corresponding merchant and its offers on Violet are automatically disabled. Similarly, when the store changes to an active plan (eg. basic), the corresponding merchant on Violet is automatically enabled and it's offers are resynced.
* This feature ensures accurate synchronization between Shopify and Violet, maintaining data integrity for the operation of your application.

**Merchant Filter**

* You can now filter your offers more intuitively with the new merchant filter on the channel dashboard offers page.

✨ **Shared Access to your Violet Dashboard \[BETA]**

* Add team members to your Organization in the Violet Channel dashboard.
  * Invite collaborators to your org to share management of apps and payments.
  * Different features are gated based on the permissions assigned to collaborators.
  * This was a large feature and may have a few things to iron out. Please let us know if you find something that could use a bit more polish.

#### 🔧 **Fixes**

* Fixed issue when wallet based cart was submitted with guest customer causing Shopify to fail.
* Improves parsing and handling of Shopify API error messages when a merchants store has been shut down or disabled by Shopify.
* Fixed issue where pricing a cart while applying an invalid discount code resulted in an API error.
* Fixed issue preventing carts with only digital items from checking out when no shipping address was provided.

#### 🧼 Clean Up

* Removed distracting UI from Login and Account Settings.
* Removed “Company Name” field from the Edit App Info Dialog.
* Improved UX for inputs and dropdowns across the dashboard.

## 2023.08.21

#### 🆕 Features

**Webhook Simulation Enhancements**

* `MERCHANT_ENABLED` and `MERCHANT_DISABLED` webhooks now supported.
* Further details can be found in our [**Webhook Documentation**](/prism/webhooks) **and** [**Simulating Webhooks Documentation**](https://github.com/violetio/docs/blob/main/channel-docs/prism/overview-1/webhooks/simulating-webhook-events.md)**.**

✨ **Relay \[Alpha] has been released with support for Shopify, BigCommerce, and WooCommerce.**

* If you're wanting to send and receive data in a more streamlined fashion, Relay might be perfect for you. Reach out to <support@violet.io> to get access.
* You can read more about how to try out the Relay API [here](/relay/relay).

**Sign up page update**

* The Channel dashboard signup page now has additional information for channels and merchants.

**Let's Chat button**

* “Let's Chat” button added to Channel dashboard nav bar for channels to get in contact with our marketing/sales team.

#### 🔧 **Fixes**

* Fixed issue when invalid discounts are added to cart causing a concurrency error.
* Fixed issue where merchant explore panel last items were cut off in dashboard.
* Update docs to call out that offer search with beta flag has incompatible search criteria.
  * `sort_by` and `sort_direction` are not supported.

#### 🧼 Clean Up

* Improved scrolling behavior across offers, orders, and merchants tables in dashboard.

## 2023.08.16

#### 🔧 **Fixes**

* Fixed issue where non live-enabled apps could not see connected sandbox merchants or explore merchant data.

## 2023.08.15

#### 🔧 **Fixes**

* Fixed bug in Merchant Explore view when an is app not live enabled.
* Fixed issue where the code verification flow was not consistent.

## 2023.08.14

#### 🆕 **Features**

**Merchant Search Endpoint Enhancements**

* New functionality added to the merchant search endpoint, allowing sorting by **`sort_by`** and **`sort_direction`** parameters in the request body.
* This feature provides greater flexibility and precision in locating the desired merchant information.
* For detailed information, please consult our [API Documentation](/api-reference/merchants/merchant/merchants-search).

**Webhook Monitoring for Shopify App Uninstallation**

* Violet now actively monitors Shopify app uninstallation events.
* When a Shopify app is uninstalled, the corresponding merchant on Violet is automatically disabled.
* This feature ensures accurate synchronization between Shopify and Violet, maintaining data integrity.

**New Webhook Events: `MERCHANT_ENABLED` & `MERCHANT_DISABLED`**

* Introducing two new webhook events: **`MERCHANT_ENABLED`** and **`MERCHANT_DISABLED`**.
* These events notify subscribed channels when a merchant is enabled or disabled on Violet; for example: because of a Shopify app unistallation.
* Stay updated on merchant status changes by utilizing these informative webhook events.
* Further details can be found in our [**Webhook Documentation**](/prism/webhooks).

**Improved Media Handling on Self-Hosted Commerce Platforms**

* All media content on self-hosted commerce platforms will now be seamlessly uploaded to a Violet-managed Content Delivery Network (CDN) during product synchronization.
* This enhancement aims to enhance media loading performance on self-hosted stores and allows for dynamic media transformations.
* More information on this update can be found in our [**Media Transformation Documentation**](/prism/catalog/media-transformations).

#### 🔧 **Fixes**

* Fixed `publishing_status` on Offer Search when using beta mode to be correctly filtered against.

#### 🧼 Clean Up

**Enhanced Security for User Verification Flows**

* Security enhancements have been implemented for the user verification processes within the dashboard.
* These improvements bolster the security of user accounts and interactions.

**Streamlined Merchant Login Code Verification**

* The previously used code verification iframe in the merchant login process has been replaced with a native code verification page.
* This change enhances the user experience and provides a smoother login process.

**Improved Error Handling for Channel Forgot Password**

* Error handling for the Channel forgot password functionality has been refined.
* Users will now receive clearer error notifications through a user-friendly snackbar interface.


# Merchant Help Center

{% hint style="info" %}

#### We've Upgraded the Merchant Experience

To provide a better, more focused experience for your merchants, we've moved all merchant documentation from docs.violet.io/merchants to our new dedicated portal at [merchant-help.violet.io](https://merchant-help.violet.io/).

* AI-powered search specifically trained on merchant content
* Faster loading times and better navigation
* Content tailored exclusively for merchant needs
* Enhanced search functionality with merchant-specific context

\
[Visit Merchant Help Center](https://merchant-help.violet.io/)
{% endhint %}

## Quick Links to Popular Pages

### 🛍️ Platform Integration Guides

{% columns %}
{% column %}
[**Shopify Integration**](https://merchant-help.violet.io/platform-guides/shopify)

Connect your Shopify Store

[**WooCommerce Integration**](https://merchant-help.violet.io/platform-guides/woo-commerce)

Install and configure your plugin

[**Squarespace Integration**](https://merchant-help.violet.io/platform-guides/squarespace)

Enable Violet on Squarespace
{% endcolumn %}

{% column %}
[**BigCommerce Integration**](https://merchant-help.violet.io/platform-guides/big-commerce)

Set up BigCommerce

[**Magento Integration**](https://merchant-help.violet.io/platform-guides/magento)

Connect your Magento 2 store

[**Wix Integration**](https://merchant-help.violet.io/platform-guides/wix)

Connect your Wix store
{% endcolumn %}
{% endcolumns %}

***

### Looking for something else?

Find all merchant resources, guides, and support at our new home.

[Explore Merchant Help Center](https://merchant-help.violet.io/)


# Apps

## Overview

A Violet Application is a unique entity with assigned credentials and tools to invoke our APIs and build your new system. You can create as many applications as you want in your Channel account. The important part is, the application is what Merchants will interact with.

## Creating an App

1. Sign up at [channel.violet.io/signup](https://channel.violet.io/signup) or login at [channel.violet.io/login](https://channel.violet.io/login)
2. Click 'Create App'
3. Name your application (don't worry, you can change this later as many times as you'd like).

<figure><img src="/files/8yHAMyk3qkKj8QdR2lo3" alt="Creating an App"><figcaption></figcaption></figure>

4. Save your App ID and App Secret, your will need them for API authentication.
5. That's it!

Your application has been created. You're now ready to work through the guides in our Channel Docs and our API Reference.

## Managing your App

Apps can be managed from the Channel Dashboard availble at [channel.violet.io](https://channel.violet.io).

### Renaming Your App

You are free to rename your app(s) as often as you like. From the App list in your Violet dashboard click on the app you would like to rename. From the app details screen click on the small toggle in the upper left corner of the app card to open your app controls. Clicking the 'Edit Name' button will render the name update field. Enter the desired name and click the arrow to persist the change.

{% hint style="warning" %}
Changes to your app name will propagate immediately. If the updated name is not recognizable to the merchants who have enabled your app it is possible that they may uninstall it. Be sure to notify any merchants of any upcoming name changes to prevent this.
{% endhint %}

### Rotating Your App Keys

In the event that your app keys have been compromised in any way it is recommended that you rotate your app keys. This action will generate a new App Secret and immedietly disable your previous App Secret.

**Key rotation can be initiated using the following endpoint:**

```
POST /apps/{app_id}/rotate_keys
```

Sample Request

```bash
curl -X POST https://sandbox-api.violet.io/v1/apps/{app_id}/rotate_keys \
-H "X-Violet-App-Id: your-app-id-here" \
-H "X-Violet-App-Secret: your-current-app-secret-here" \
-H "Content-type: application/json"
```

Sample Response

```json
{
  "id": 9999,
  "developer_id": 9999,
  "app_secret": "new-app-secret-here",
  "app_public": "new-app-public-here",
  "name": "Your App Name",
  "api_version": "v1",
  "status": "ACTIVE",
  "type": "APP",
  "date_created": "2020-07-16T21:25:26+0000",
  "date_last_modified": "2023-07-24T18:05:13+0000"
}
```

{% hint style="info" %}
You must perform this action for each environment where you want your keys rotated. Rotating them in Sandbox or Production will not automatically rotate them in the other environment.
{% endhint %}

### Deleting Your App

From the App list in your Violet dashboard click on the app you would like to delete. From the app details screen click on the small toggle in the upper left corner of the app card to open your app controls. Clicking the 'Delete' button will ask you to confirm that you wish to delete your app. Clicking 'Yes' will permanently delete your app. Clicking 'No' will close the controls and return you to the app details screen.

{% hint style="warning" %}
App deletions are permanent. Once your app is deleted your API keys will immediately stop working. You will loose access to all data related to the app including access to historical order data. Be sure you truly want to delete your app before deleting.
{% endhint %}


# Pagination

## Overview

The Violet APIs provide you with access to immense amounts of data. Through pagination, you can easily navigate through this data using the `page` and `size` query parameters.

**Requests**

Query Parameters:

| Field | Description                                                  | Default |
| ----- | ------------------------------------------------------------ | ------- |
| page  | The starting position for which this API should return data. | 1       |
| size  | Limit to the number of items returned by this request.       | 20      |

```bash
curl -X POST https://sandbox-api.violet.io/v1/<pagination_enabled_API>?page=1&size=20 \
-H "X-Violet-App-Id: your-app-id-here" \
-H "X-Violet-App-Secret: your-app-secret-here" \
-H "X-Violet-Token: your-token-here" \
```

**Response**

Responses for calls that support pagination include additional information designed to let you quickly navigate through our datasets. The following information is returned:

| Field                | Description                                                                                               |
| -------------------- | --------------------------------------------------------------------------------------------------------- |
| content              | Content you are requesting from the call.                                                                 |
| pageable             | Custom object that stores information about details for the current page, such as page number, sort, etc. |
| total\_elements      | Total number of elements matching query criteria.                                                         |
| last                 | Boolean denoting whether or not this is the last page.                                                    |
| total\_pages         | Total number of pages based on size input from query parameter.                                           |
| sort                 | Sorting details for ordering returned in content.                                                         |
| number\_of\_elements | Number of elements present in current page.                                                               |
| first                | Boolean denoting whether or not this is the first page.                                                   |
| size                 | Input size from query parameter.                                                                          |
| number               | The current page number.                                                                                  |
| empty                | Boolean denoting whether or not content is present.                                                       |

```json
{
    "content": [ ... ],
    "pageable": {
        "sort": {
            "unsorted": true,
            "sorted": false,
            "empty": true
        },
        "page_number": 0,
        "page_size": 1,
        "offset": 0,
        "paged": true,
        "unpaged": false
    },
    "total_elements": 133,
    "last": false,
    "total_pages": 133,
    "sort": {
        "unsorted": true,
        "sorted": false,
        "empty": true
    },
    "number_of_elements": 1,
    "first": true,
    "size": 1,
    "number": 0,
    "empty": false
}
```

As seen above, Violet uses `page` and `total_elements` in the response object to give you details on the total number of elements present in our datasets matching your criteria as well as the number of total pages you need to go through for all data. You can pass these page numbers through the request query parameters to fetch the next set of data.

Since Violet uses more than `next` and `previous` cursors to let you traverse through the dataset, you can even use page numbers and size to make parallel calls to our system to retrieve information as quickly as you need to for your application.


# Rate Limits

Handling rate limits with Violet

## Ecommerce Platform Rate Limits

Most E-Commerce Platforms have rate limits for their APIs. As you integrate with Violet you will need to be aware of these as they will affect your system.

When you make a request to Violet, often times Violet will make a background call to an E-Commerce platform to process your request, this is especially true during the checkout flow.

In the event that Violet receives a `429 Too Many Requests` HTTP Status code from an E-Commerce Platform, you will receive the same status code in Violet's response. We recommend that you handle this status code at a top level since it is a possibility for most endpoints.

It is also important to note that because each merchant has their own store in any one of our supported platforms, rate limits are separate on a per-merchant basis. This means that given randomized traffic to your site or app, you are unlikely to hit any one merchant's rate limit unless they are extremely popular or are having a sale.

However, automated calls to the Violet API, say for example a batch process that periodically deletes all abandoned carts, will *very easily* surpass a Merchant's rate limits. Hence Violet's recommendation to have a top level handler for 429's that allows for backoff retries or possibly re-queueing.

#### Shopify

Shopify tends to have the strictest rate limits against their REST API, you can read about their rate limits and algorithm [here](https://shopify.dev/docs/api/usage/rate-limits#compare-rate-limits-by-api). Note the REST API is the one applicable in our case.

### Direct Order Submission

Since rate limits are most likely going to be an issue during checkout, we have built capabilities to allow you to minimize the chance of hitting said limits when in high volume scenarios, such as a flash sale.

We recommend using **Direct Order Submission** in most case. See the guide on using [Direct Order Submission](/prism/checkout-guides/guides/direct-order-submission) for more information.


# Authentication

The Violet API uses a **JWT-based authentication system** with refresh tokens to provide secure, long-term access to your applications. This system ensures your credentials remain secure while providing seamless API access.

#### Key Concepts

* **App Credentials**: `X-Violet-App-Id` and `X-Violet-App-Secret` identify your application
* **Authentication Token**: Short-lived JWT token (24 hours) for API requests
* **Refresh Token**: Long-lived token for obtaining new authentication tokens
* **Environment Separation**: Different credentials for test and production environments

```mermaid
sequenceDiagram
    participant App as Your Application
    participant Violet as Violet API
    participant Dashboard as Channel Dashboard

    Note over App,Dashboard: Initial Setup
    App->>Dashboard: Create account & application
    Dashboard-->>App: App ID & App Secret

    Note over App,Violet: Initial Authentication
    App->>Violet: POST /login<br/>(credentials + headers)
    Violet-->>App: Authentication Token + Refresh Token

    Note over App,Violet: API Requests
    App->>Violet: API Request<br/>(with auth token)
    Violet-->>App: API Response

    Note over App,Violet: Token Refresh (before expiry)
    App->>Violet: GET /auth/token<br/>(with refresh token)
    Violet-->>App: New Authentication Token

    Note over App,Violet: Continued API Usage
    App->>Violet: API Request<br/>(with new auth token)
    Violet-->>App: API Response
```


# Initial Authentication

| Field    | Description                                                                                           |
| -------- | ----------------------------------------------------------------------------------------------------- |
| username | Username for your Violet account created on channel.violet.io (this is your email you signed up with) |
| password | Password for your Violet account you created on channel.violet.io                                     |

#### Making the Login Request

The first call to Violet that needs to be made is the /login call, to authenticate your Violet Account and credentials and retrieve an authentication token.

**Endpoint**: `POST /login`

**Required Headers**:

```http
X-Violet-App-Id: your-app-id-here
X-Violet-App-Secret: your-app-secret-here
Content-Type: application/json
```

**Request Body**

```json
{
  "username": "your-email@example.com",  
  "password": "your-password"
}
```

#### Sample Code

{% tabs %}
{% tab title="Bash" %}

```bash
curl -X POST https://sandbox-api.violet.io/v1/login \
  -H "X-Violet-App-Id: your-app-id-here" \
  -H "X-Violet-App-Secret: your-app-secret-here" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "your-email@example.com",
    "password": "your-password"
  }'
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
async function authenticateWithViolet() {
  try {
    const response = await fetch('https://sandbox-api.violet.io/v1/login', {
      method: 'POST',
      headers: {
        'X-Violet-App-Id': process.env.VIOLET_APP_ID,
        'X-Violet-App-Secret': process.env.VIOLET_APP_SECRET,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        username: process.env.VIOLET_USERNAME,
        password: process.env.VIOLET_PASSWORD
      })
    });

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(errorData.message || 'Authentication failed');
    }

    const data = await response.json();

    return {
      authToken: data.token,
      refreshToken: data.refresh_token,
      expiresAt: new Date(data.expires_at)
    };
  } catch (error) {
    console.error('Authentication failed:', error.message);
    throw error;
  }
}
```

{% endtab %}
{% endtabs %}

### Expected Response

```json
{
    "id": 10084,
    "first_name": "First",
    "last_name": "Name",
    "email": "user@violet.io",
    "type": "DEVELOPER",
    "verified": true,
    "date_created": "2022-04-11T21:03:04+0000",
    "date_last_modified": "2024-10-23T21:52:56+0000",
    "roles": [
        {
            "name": "ROLE_DEVELOPER",
            "permissions": [
                {
                    "name": "MANAGE_APPS"
                },
                {
                    "name": "MANAGE_USER"
                }
            ]
        }
    ],
    "tos_accepted": false,
    "token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ1c2VyQGV4YW1wbGUuY29tIiwic2NvcGVzIjpbIlJPTEVfREVWRUxPUEVSIl0sInVzZXJfaWQiOjEwMzk3LCJ1c2VyX3R5cGUiOiJERVZFTE9QRVIiLCJtZXJjaGFudF9pZHMiOltdLCJkZXZlbG9wZXJfaWQiOjEwMjkyLCJhcHBfaWQiOiIxMDM4MiIsImlzcyI6Imh0dHBzOi8vdmlvbGV0LmlvIiwiaWF0IjoxNjUyMzc3ODc0LCJleHAiOjE2NTI0NjQyNzR9.BW1HDpe1Gm2wA-esP8NWEtn9thEsfeKsIGEicAoMgDPEOyO6VdNP71ajqnPrMqITGadHApH-b6LewiBFAcobw",
    "refresh_token": "rt_1234567890abcdef"
}
```


# Making Authenticated Requests

Use this in the Header of every request you send to Violet.

#### Required Headers for API Requests

```http
X-Violet-App-Id: your-app-id-here
X-Violet-App-Secret: your-app-secret-here
X-Violet-Token: your-authentication-token-here
Content-Type: application/json
```

#### Example API Request

```javascript
async function makeVioletAPIRequest(authToken, endpoint, method = 'GET', data = null) {
  const url = `https://sandbox-api.violet.io/v1${endpoint}`;
  const options = {
    method,
    headers: {
      'X-Violet-App-Id': process.env.VIOLET_APP_ID,
      'X-Violet-App-Secret': process.env.VIOLET_APP_SECRET,
      'X-Violet-Token': authToken,
      'Content-Type': 'application/json'
    }
  };

  if (data && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
    options.body = JSON.stringify(data);
  }

  try {
    const response = await fetch(url, options);

    if (response.status === 401) {
      throw new Error('TOKEN_EXPIRED');
    }

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(errorData.message || 'API request failed');
    }

    return response.json();
  } catch (error) {
    throw error;
  }
}

// Example usage
const merchants = await makeVioletAPIRequest(authToken, '/merchants');
```


# Token Refresh Management

Auth tokens expire after a set time period. Use your refresh token to obtain new auth tokens without re-entering your login credentials. Always refresh your token before it expires to maintain uninterrupted API access.

#### Refreshing Tokens

**Endpoint**: `GET /auth/token`

**Required Headers**:

```http
X-Violet-App-Id: your-app-id-here
X-Violet-App-Secret: your-app-secret-here
X-Violet-Token: your-refresh-token-here
Content-Type: application/json
```

#### Example Automatic Token Refresh Implementation

```javascript
class VioletAuthManager {
  constructor(appId, appSecret, username, password) {
    this.appId = appId;
    this.appSecret = appSecret;
    this.username = username;
    this.password = password;
    this.authToken = null;
    this.refreshToken = null;
    this.expiresAt = null;
    this.baseURL = 'https://sandbox-api.violet.io/v1';
  }

  async initialize() {
    const tokens = await this.login();
    this.setTokens(tokens);
    return tokens;
  }

  async login() {
    const response = await fetch(`${this.baseURL}/login`, {
      method: 'POST',
      headers: {
        'X-Violet-App-Id': this.appId,
        'X-Violet-App-Secret': this.appSecret,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        username: this.username,
        password: this.password
      })
    });

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(errorData.message || 'Login failed');
    }

    const data = await response.json();

    return {
      authToken: data.token,
      refreshToken: data.refresh_token,
      expiresAt: new Date(data.expires_at)
    };
  }

  async refreshAuthToken() {
    if (!this.refreshToken) {
      throw new Error('No refresh token available. Please re-authenticate.');
    }

    try {
      const response = await fetch(`${this.baseURL}/auth/token`, {
        headers: {
          'X-Violet-App-Id': this.appId,
          'X-Violet-App-Secret': this.appSecret,
          'X-Violet-Token': this.refreshToken,
          'Content-Type': 'application/json'
        }
      });

      if (!response.ok) {
        throw new Error('Token refresh failed');
      }

      const data = await response.json();
      this.authToken = data.token;
      this.expiresAt = this.extractExpiryFromJWT(data.token);
      
      return this.authToken;
    } catch (error) {
      // If refresh fails, re-authenticate
      console.warn('Token refresh failed, re-authenticating...');
      const tokens = await this.login();
      this.setTokens(tokens);
      return this.authToken;
    }
  }

  async getValidToken() {
    // Check if token is expired or will expire within 5 minutes
    const now = new Date();
    const fiveMinutesFromNow = new Date(now.getTime() + 5 * 60 * 1000);

    if (!this.authToken || !this.expiresAt || this.expiresAt <= fiveMinutesFromNow) {
      await this.refreshAuthToken();
    }

    return this.authToken;
  }

  async makeRequest(endpoint, method = 'GET', data = null) {
    const token = await this.getValidToken();
    
    const url = `${this.baseURL}${endpoint}`;
    const options = {
      method,
      headers: {
        'X-Violet-App-Id': this.appId,
        'X-Violet-App-Secret': this.appSecret,
        'X-Violet-Token': token,
        'Content-Type': 'application/json'
      }
    };

    if (data && ['POST', 'PUT', 'PATCH'].includes(method)) {
      options.body = JSON.stringify(data);
    }

    try {
      let response = await fetch(url, options);

      if (response.status === 401) {
        // Token might be expired, try refreshing once
        await this.refreshAuthToken();
        options.headers['X-Violet-Token'] = this.authToken;
        response = await fetch(url, options);
      }

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.message || 'API request failed');
      }

      return response.json();
  }

  setTokens({ authToken, refreshToken, expiresAt }) {
    this.authToken = authToken;
    this.refreshToken = refreshToken;
    this.expiresAt = expiresAt;
  }

  extractExpiryFromJWT(token) {
    try {
      const payload = JSON.parse(atob(token.split('.')[1]));
      return new Date(payload.exp * 1000);
    } catch (error) {
      console.warn('Failed to extract expiry from JWT:', error);
      return new Date(Date.now() + 24 * 60 * 60 * 1000); // Default to 24 hours
    }
  }
}

// Usage example
const authManager = new VioletAuthManager(
  process.env.VIOLET_APP_ID,
  process.env.VIOLET_APP_SECRET,
  process.env.VIOLET_USERNAME,
  process.env.VIOLET_PASSWORD
);

await authManager.initialize();

// Make authenticated requests
const merchants = await authManager.makeRequest('/merchants');
const orders = await authManager.makeRequest('/orders');
```


# Environments

## Overview

The Violet API provides developers with access to two environments: **Test Mode** and **Live Mode**. From the experience of the developer, these environments are nearly identical with only two primary differences.

1. When an order is placed in Test Mode, no dollars are transacted and no orders are fulfilled. When an order is placed in Live Mode, dollars are transacted and orders will be received and fulfilled by real merchants.
2. The Test Mode product catalog is mostly static and much smaller than the Live Mode product catalog. The Live Mode product catalog is constantly growing as more merchants join Violet.

### Live Mode URLs

* **Violet API** - <https://api.violet.io>
* **Channel dashboard** - <https://channel.violet.io>
* **Merchant dashboard** - <https://merchant.violet.io>
* **Violet Connect** - <https://connect.violet.io/[VIOLET_CONNECT_URL]>

### Test Mode URLs

* **Violet API** - <https://sandbox-api.violet.io>
* **Channel dashboard** - <https://channel.violet.io>
* **Merchant dashboard** - <https://merchant.violet.dev>
* **Violet Connect** - <https://connect.violet.dev/[VIOLET_CONNECT_URL]>

## Test Mode

When first created, your app will be limited to Test Mode. This allows you to build and fully test out your application without the risk of transacting real dollars. The Test Mode product catalog provides you with a few thousand products across multiple taxonomies and complexities. These test products do live on private stores on real e-commerce platforms (ex. Shopify, Ecwid, etc) so you will be able to fully validate that your requests are working just as they would when using Live Mode.

{% hint style="info" %}
Depending on the product(s) ordered you may receive a confirmation email from the store that the Test Mode products are sourced from when your order is placed. These are automated by the e-commerce platform and are similar to the emails that your customers may receive when making live purchases through your application.
{% endhint %}

We typically recommend channels create a test e-commerce store and connect it to Test Mode so you can perform all actions related to the checkout/returns/refund process yourself as you are testing. It can also be helpful if a merchant partner has a test store they use for their own development needs to connect that test store so you can iron out any issues in your integration before connecting their live store to your app in Live Mode.\
You can access your Test Mode Violet Connect URL in the app settings page. Note that all Test Mode apps will have a unique GUID assigned for their URL. Also note that it points to `connect.violet.dev` the `.dev` domain indicates Test Mode.

{% hint style="warning" %}
We strongly advise you to NOT connect any live merchant stores to Test Mode as this could lead to real products being shipped due to test orders placed.
{% endhint %}

Test Mode can be managed just like Live Mode in your channel dashboard. Flip the live/test toggle to Test Mode and you will see all your test merchants, test orders, etc. You can find your appId and appSecret on the overview page. You will need these tokens as well as the app owner’s email and password to authenticate against the API in Test Mode. In this documentation and associated Postman collections, we point to our Test Mode domain which is `sandbox-api.violet.io`. The [Postman](/resources#postman) collection is useful when getting started, but as you begin building your real app and systems we recommend you maintain your own test environment that points to our Test Mode API so that you can validate changes made to your app before switching to Live Mode.

### Test Mode Order Payment

When applying a payment method to an order in Test Mode you will need to use a test credit card number.

**For successful results**

Please use one of the following:

| Card             | Number              |
| ---------------- | ------------------- |
| Visa             | 4242 4242 4242 4242 |
| Mastercard       | 5555 5555 5555 4444 |
| American Express | 3782 822463 10005   |

**To emulate payment failure**

Please use one of the following:

| Card               | Number              |
| ------------------ | ------------------- |
| Card Declined      | 4000 0000 0000 0002 |
| Insufficient Funds | 4000 0000 0000 9995 |
| Expired Card       | 4000 0000 0000 0069 |
| Invalid CVC        | 4000 0000 0000 0127 |
| Invalid Number     | 4242 4242 4242 4241 |
| Processing Failure | 4000 0000 0000 0119 |

{% hint style="info" %}
For additional test card numbers please visit [Stripe](https://stripe.com/docs/testing#cards)
{% endhint %}

{% hint style="info" %}
When you are ready to go live with your application please contact us at <support@violet.io>
{% endhint %}

## Live Mode

When your application has been approved you will gain access to Live Mode. Live Mode provides a developer with access to the live catalog of products. These are products associated with real stores where successful purchases result in true order fulfillment. The live product catalog is constantly growing. Each time a new merchant joins Violet, the catalog increases in size.

When making purchases in Live Mode true credit card numbers are required. The test credit card numbers available in Test Mode will not work when making requests against the API in Live Mode.

The hostname for Live Mode is `api.violet.io`. You will need a different appSecret for Live Mode, while your appId, email and password will be the same across both modes. While you appSecret will be accessible from the same place in the dashboard, you will need to complete the go live requirements you received as part of onboarding before you will be issued a Live Mode appSecret. The same goes for your Violet Connect URL. You will be able to customize this but only after meeting the same go live requirements. Again note that in Live Mode, the URL is `connect.violet.io`.

You can request Violet to review your application to make it live by sending us an email at <support@violet.io>. Access to Live Mode is granted upon the successful review of a developer's application. If the business model and application quality meet our requirements a developer's Live Mode API credentials will be enabled.


# Definitions

#### Merchant

An individual or company that holds inventory and sells products. This Merchant has a Primary Commerce Engine on one of the many e-commerce platforms or has built one of their own.

***

#### Channel

A channel is the entity that has created an application within Violet for the purpose of interacting directly with the data coming from a Merchant's Primary Commerce Engine.

***

#### E-Commerce Platform

Within Violet an e-commerce platform is the external platform that a merchant uses to facilitate their online sales. All products on Violet are sourced from these external platforms and orders are written back into these external platforms. A list of currently supported platforms can be found on the homepage of Violet.io.

***

#### Catalog

Catalog consists of products. The primary Product entity in Violet is called an Offer. You will want to use this 99% of the time. If you ever want to associate two products to a parent level entity, we have the concept of a Product Wrapper built into the API. Read more about [Catalog](/prism/catalog).

***

#### Offer

An offer represents a merchant's offering of a product. Multiple merchants within Violet can sell the same item, possibly at different prices or different commission rates. You as the developer can choose which offer you want to use when making a product available for purchase.

***

#### Product

A product in Violet is a top-level wrapper that acts as a parent for any offers from merchants who are selling this product. A top-level product is not purchasable; instead it provides a collection of offers from merchants selling this product in addition to metadata around the product.

***

#### SKU

A SKU is the combination of variants that represent an actual item that can be purchased. An example of this might be a hoodie that has a size of Large and a color of Purple.

***

#### Variant

A variant is a single option of a SKU. An example of a variant would be its size or its color. When one or more variants are combined they form a SKU.

***

#### Checkout

With Violet's Checkout APIs, you can provide your shoppers with an end-to-end checkout experience all without leaving your app. From creating a cart and adding products to shipping and tax; Violet lets you complete checkout from any Merchant via a standardized series of headless checkout endpoints.

Read more about Violet's Checkout APIs [here](/prism/overview).

***

#### Bag

A bag represents the products and cart/order data for a single merchant. All products of the same merchant will exist in the same bag within a cart/order. If you add a SKU to a cart that is not from the same merchant as the previous SKUs, a new bag will automatically be created and the item will be added to that bag. When the cart is submitted, the bag will be associated with the order placed on the merchant's e-commerce platform and contain the external order ID, status, and tracking information.

***

#### Commission Rate

The commission rate is the percentage of a sale that a merchant is willing to give to any channels who facilitate the sale of their products. This percentage is taken from the order's subtotal and does not include tax or shipping fees.

***

#### Payout Method

The payout method is the bank account a channel’s cut of a transaction is deposited into. Channels can sync their bank account to Violet from their dashboard at [channel.violet.io/settings/payments](https://channel.violet.io/settings/payments). The connection to this bank account only allows Violet to make deposits; we cannot read your account information or perform withdrawals.

***

For more e-commerce definitions, check out our [Glossary](https://violet.io/blog/ecommerce-glossary).


# Overview

Platform-specific guides for connecting merchants to Violet across supported ecommerce platforms

Violet supports 15+ ecommerce platforms. Each platform has its own authentication model, credential requirements, and integration behavior. This section provides an overview of each platform's integration from a channel developer's perspective.

For merchant-facing setup instructions, see the [Merchant Help Center](https://merchant-help.violet.io/).

## Platforms

### Popular Platforms

| Platform                                   | Setup Complexity   | Auth Method              |
| ------------------------------------------ | ------------------ | ------------------------ |
| [Shopify](/ecom-platforms/shopify)         | Medium (see guide) | Custom app OAuth         |
| [BigCommerce](/ecom-platforms/bigcommerce) | Low                | OAuth or Store Level API |
| [WooCommerce](/ecom-platforms/woocommerce) | Low                | Consumer Key / Secret    |

### Enterprise Platforms

| Platform                                                                                                 | Setup Complexity | Auth Method                        |
| -------------------------------------------------------------------------------------------------------- | ---------------- | ---------------------------------- |
| [Salesforce Commerce Cloud](/ecom-platforms/salesforce-commerce-cloud)                                   | High             | OCAPI client credentials           |
| [Magento](/ecom-platforms/magento)                                                                       | Medium           | API token + secret                 |
| [CommerceTools](https://github.com/violetio/docs/blob/main/channel-docs/ecom-platforms/CommerceTools.md) | Medium           | OAuth2 client credentials          |
| [SAP Commerce Cloud](/ecom-platforms/sap-commerce-cloud)                                                 | Medium           | OAuth2 client credentials (OCC v2) |
| [Oracle Commerce Cloud](/ecom-platforms/oracle-commerce-cloud)                                           | Medium           | Application key                    |
| [Centra](/ecom-platforms/centra)                                                                         | Medium           | Integration API bearer token       |

### Additional Platforms

| Platform                                      | Auth Method                                                   |
| --------------------------------------------- | ------------------------------------------------------------- |
| [PrestaShop](/ecom-platforms/prestashop)      | API key (+ Violet extension)                                  |
| [Ecwid](/ecom-platforms/ecwid)                | OAuth                                                         |
| [Wix](/ecom-platforms/wix)                    | API key                                                       |
| [Squarespace](/ecom-platforms/squarespace)    | Commerce API key                                              |
| [Swell](/ecom-platforms/swell)                | Secret key                                                    |
| [Spree Commerce](/ecom-platforms/spree)       | OAuth2 client credentials                                     |
| [Vendo](/ecom-platforms/vendo)                | OAuth2 client credentials                                     |
| [Miva Merchant](/ecom-platforms/miva)         | HMAC-SHA256 (API token + signing key)                         |
| [Shoprenter](/ecom-platforms/shoprenter)      | Username / password                                           |
| [Rithum](/ecom-platforms/rithum)              | Partner-managed (no self-service auth)                        |
| [Lightspeed eCom](/ecom-platforms/lightspeed) | API key / secret (HTTP Basic)                                 |
| [3dcart / Shift4Shop](/ecom-platforms/3dcart) | OAuth2                                                        |
| [Shoptet](/ecom-platforms/shoptet)            | Private API token or OAuth (Premium); product feed (Standard) |

***

> **Shopify note**: Shopify has the most developer-side requirements of any supported platform. See the [Shopify guide](/ecom-platforms/shopify) for full details on app setup, pre-registration, and the onboarding flow.


# Shopify

Complete guide for onboarding Shopify merchants using pre-registration in Channel Dashboard

{% hint style="warning" %}
**Effective January 1, 2026**: Shopify discontinued the ability for merchants to create their own custom apps. All new Shopify merchant connections must use single-merchant custom apps created by channels. This guide explains how to use Violet's pre-registration feature to streamline this required process.
{% endhint %}

## Overview

Shopify now requires channels to create "[single-merchant apps](https://shopify.dev/docs/apps/launch/distribution/select-distribution-method#install-a-custom-app-on-multiple-stores)" for each merchant instead of merchants creating their own custom apps. This guide shows you how to onboard Shopify merchants using Violet's pre-registration feature, which handles the OAuth complexity for you.

### Who This Guide Is For

* **Existing channels**: Migrating from the previous Shopify integration approach
* **New channels**: Setting up Shopify merchant onboarding for the first time

Both audiences follow the same process: create a custom app in Shopify Partner Dashboard, pre-register the merchant in Channel Dashboard, then send them a Violet Connect link. The merchant completes the entire onboarding—including Shopify app installation—in a single seamless flow.

## What You'll Learn

1. [Prerequisites](/ecom-platforms/shopify/prerequisites): What you need before getting started
2. [Shopify App Setup](/ecom-platforms/shopify/shopify-app-setup): Creating and configuring a custom app in Shopify Partner Dashboard
3. [Pre-Registration Process](/ecom-platforms/shopify/pre-registration): How to pre-register merchants in Channel Dashboard
4. [Merchant Onboarding](/ecom-platforms/shopify/merchant-onboarding): What happens when merchants use their installation link
5. [Troubleshooting & FAQs](/ecom-platforms/shopify/troubleshooting-faqs): Common issues and solutions

***

## Impact Assessment

### What Continues to Work

* **All existing merchant-created custom apps remain functional** — no forced migration
* Existing API credentials continue to work unchanged
* No disruption to current integrations
* Merchants can continue using their existing apps indefinitely

### What Stops Working (for new merchants)

* Merchants cannot create **new** custom apps after January 1, 2026
* The "Apps and sales channels > Develop apps" section no longer allows new app creation
* Merchants needing new integrations must request them from channels

***

## What Changed

### Before January 1, 2026

* Merchants created custom apps directly in their Shopify admin
* API credentials generated within the merchant's store
* Merchants managed their own app permissions and credentials
* No developer account required for basic integrations

### After January 1, 2026

* Merchants can no longer create custom apps in Shopify
* Only channels can create custom apps (now called "single-merchant apps")
* Each custom app must be created in a Shopify Partner account
* Channels generate unique installation URLs for each merchant
* Merchants no longer have to click through and add each of their custom scopes, or copy and paste any credentials
* Merchants receive a single Violet Connect link that handles both account setup and Shopify app installation
* Existing merchant-created custom apps continue to work (grandfathered)

***

## Key Differences and Considerations

### Access Token Format

| Token Type               | Prefix   | Notes                 |
| ------------------------ | -------- | --------------------- |
| Old custom apps          | `shpat_` | Merchant-created apps |
| New single-merchant apps | `shpua_` | Channel-created apps  |

Both work identically with Shopify APIs.

### Permission Management

| Aspect                  | Old Model                         | New Model                                       |
| ----------------------- | --------------------------------- | ----------------------------------------------- |
| Who manages permissions | Merchants could modify themselves | Channel updates app config, merchant reinstalls |
| Scope changes           | Self-service                      | Requires reinstallation                         |

**Important**: Request all necessary permissions upfront and consider future needs when selecting scopes.

### Credential Rotation

| Aspect         | Old Model                             | New Model                                                  |
| -------------- | ------------------------------------- | ---------------------------------------------------------- |
| Who can rotate | Merchants could regenerate themselves | Channel uninstalls/reinstalls or uses OAuth token exchange |

Plan for credential rotation procedures and document emergency access procedures.

***

## User Personas

### Channel Operator

* Managing Shopify merchant onboarding from Channel Dashboard
* **Goal**: Pre-register merchants quickly, track onboarding progress, minimize manual work
* **Pain Point**: Manual credential exchange is error-prone and creates support burden

### Merchant

* Received install link from channel partner
* **Goal**: Complete connection in under 2 minutes without technical knowledge
* **Pain Point**: Previous flow required understanding OAuth, API credentials, and multiple steps

***

**Ready to get started?** View [Prerequisites](/ecom-platforms/shopify/prerequisites) to see what you need and begin the setup process.


# Prerequisites

Before creating a pre-registration, ensure you have the following:

| Requirement                                                             | Details                                                       |
| ----------------------------------------------------------------------- | ------------------------------------------------------------- |
| [Shopify Partner account](#1-shopify-partner-account)                   | Required to create custom apps                                |
| [Violet Channel Dashboard access](#2-violet-channel-dashboard-access)   | Where you'll create pre-registrations                         |
| [Your Violet App Alias](#3-violet-app-alias)                            | Needed for App URL and Redirect URI configuration             |
| [Shopify app configured correctly](#4-shopify-app-configured-correctly) | One custom app per merchant with custom distribution selected |

***

## 1. Shopify Partner Account

You need a Shopify Partner account to create custom apps for your merchants.

**How to check if you have one:** Try logging in at [partners.shopify.com](https://partners.shopify.com). If you can access the Partner Dashboard, you're set.

**Don't have an account?** Shopify's Partner Program is free to join: → [Become a Shopify Partner](https://www.shopify.com/partners) (official Shopify guide)

{% hint style="info" %}
**Keep this open:** You'll need the [Shopify Partner Dashboard](https://partners.shopify.com) open while setting up your custom app.
{% endhint %}

***

## 2. Violet Channel Dashboard Access

The Channel Dashboard is where you'll create and manage merchant pre-registrations.

**What you'll use it for:**

* Creating pre-registrations for each merchant
* Copying your App Alias for Shopify configuration
* Tracking merchant onboarding status
* Managing connected merchants

**How to check your access:** Go to [channel.violet.io](https://channel.violet.io) and log in. If you can see your app and the Merchants section, you have the right access.

**Don't have access?** Contact your Violet representative or email <support@violet.io>.

{% hint style="info" %}
**Keep this open:** You'll need the [Channel Dashboard](https://channel.violet.io) open to copy your App Alias and create pre-registrations.
{% endhint %}

***

## 3. Violet App Alias

Your App Alias is a unique identifier for your Violet Connect integration. You'll need it when configuring your Shopify custom app.

**What is it?** A short string (like `your-channel-name`) that's part of your Violet Connect URL.

**Why you need it:** The App Alias goes into both the **App URL** and **Redirect URI** fields when creating your Shopify custom app. These URLs must use Violet's domain with your alias.

**How to find it:**

1. Go to [Channel Dashboard](https://channel.violet.io)
2. Navigate to **App Settings** → **Violet Connect**
3. Copy your App Alias

**When you'll use it:** During [Shopify App Setup](/ecom-platforms/shopify/shopify-app-setup) when configuring the App URL and Redirect URI fields.

***

## 4. Shopify App Configured Correctly

For each merchant you onboard, you need to create a custom app in Shopify Partner Dashboard with the correct configuration.

**What you'll configure:**

* App URL and Redirect URI (must use Violet's domain)
* All 26 required API scopes
* Custom distribution method (required to generate the Install Link)
* Install Link (copy from Distribution page after selecting custom distribution)
* Client ID and Client Secret (copy these immediately)

**How to do it:** Follow the [Shopify App Setup Guide](/ecom-platforms/shopify/shopify-app-setup) for step-by-step instructions.

{% hint style="warning" %}
**Most issues stem from this step.** Incorrectly configured App URL or Redirect URI causes errors during merchant onboarding. Forgetting to select custom distribution means you won't have the Install Link needed for pre-registration. Have questions or running into issues? See [Troubleshooting & FAQs](/ecom-platforms/shopify/troubleshooting-faqs) for common problems and solutions.
{% endhint %}

***


# Shopify App Setup

This guide walks through creating a custom app in Shopify Partner Dashboard for a merchant you want to onboard.

{% hint style="info" %}
**Don't have a Shopify Partner account?** You'll need one before proceeding. See [Prerequisites](/ecom-platforms/shopify/prerequisites#1-shopify-partner-account) or visit [shopify.com/partners](https://www.shopify.com/partners) to sign up (free).
{% endhint %}

***

## Step 1: Open Shopify Partner Dashboard

Go to [partners.shopify.com](https://partners.shopify.com) and log in.

![Shopify Partners Dashboard](/files/fjbfMjRbknI4Iz5ER2WI)

***

## Step 2: Navigate to Apps

Click **Apps** in the left sidebar, then click **Create app**.

![Shopify Dev Dashboard](/files/odKhMIOjzVwfnylk62Qn)

***

## Step 3: Select Custom App

When prompted, select **Custom app** (also called "single-merchant app").

***

## Step 4: Configure the App

{% hint style="danger" %}
**Critical: Must uncheck "Embed app in Shopify admin"**

For a smoother merchant onboarding experience, uncheck the "Embed app in Shopify admin" option (it's checked by default). If left checked, merchants will need to manually re-navigate to Violet Connect via the link you provide them after installing the app, instead of being redirected automatically.

See [Send the Violet Connect Link](/ecom-platforms/shopify/pre-registration#send-the-violet-connect-link) for more details on the merchant onboarding flow.
{% endhint %}

![Shopify App Creation](/files/BAl3knlgJBEdgqN8Np6P)

### App Name

This helps you identify which app belongs to which merchant when managing multiple apps. Use a descriptive name that identifies both your channel and the merchant:

* Example: `YourChannel - Merchant Store Name`

### App URL

{% hint style="danger" %}
**Critical: Must use Violet's domain**

The App URL must be set to Violet's domain with your App Alias:
{% endhint %}

| Mode          | App URL                                       |
| ------------- | --------------------------------------------- |
| **Live Mode** | `https://connect.violet.io/{YOUR_APP_ALIAS}`  |
| **Test Mode** | `https://connect.violet.dev/{YOUR_APP_ALIAS}` |

{% hint style="danger" %}
**Example:** If your App Alias is `acme-shopping`, your Live Mode App URL is: `https://connect.violet.io/acme-shopping`

**Why this matters:** Shopify requires the App URL and Redirect URI to share the same host. Using your own domain causes a **404 error** during OAuth.

**Find your App Alias:** [Channel Dashboard](https://channel.violet.io) → App Settings → Violet Connect
{% endhint %}

### Redirect URI

The Redirect URI must match the App URL host and include the Shopify connect path:

| Mode          | Redirect URI                                                            |
| ------------- | ----------------------------------------------------------------------- |
| **Live Mode** | `https://connect.violet.io/{YOUR_APP_ALIAS}/platforms/shopify/connect`  |
| **Test Mode** | `https://connect.violet.dev/{YOUR_APP_ALIAS}/platforms/shopify/connect` |

**Example:** If your App Alias is `acme-shopping`, your Live Mode Redirect URI is: `https://connect.violet.io/acme-shopping/platforms/shopify/connect`

### Required API Scopes

Select all 26 required API scopes listed below. Missing scopes will cause features to fail after the merchant connects.

{% hint style="warning" %}
**Select all scopes upfront.** Changing scopes later requires the merchant to reinstall the app.
{% endhint %}

```
read_customers,write_customers,read_locales,read_metaobject_definitions,read_metaobjects,read_price_rules,read_discounts,read_translations,write_draft_orders,read_draft_orders,read_fulfillments,read_inventory,read_legal_policies,read_locations,read_markets,write_merchant_managed_fulfillment_orders,read_orders,write_orders,read_products,read_publications,write_publications,read_returns,read_shipping,unauthenticated_write_checkouts,unauthenticated_read_product_inventory,unauthenticated_read_product_listings
```

<details>

<summary>Click to expand to learn more about the API scopes</summary>

### Products & Inventory

| Scope                         | Purpose                            |
| ----------------------------- | ---------------------------------- |
| `read_products`               | Read product catalog               |
| `read_inventory`              | Read inventory data                |
| `read_locations`              | Read inventory locations           |
| `read_metaobject_definitions` | Read metaobject definitions        |
| `read_metaobjects`            | Read metaobject data               |
| `read_publications`           | Read sales channel publications    |
| `write_publications`          | Publish products to sales channels |
| `read_locales`                | Read store locale data             |
| `read_translations`           | Read translation data              |

### Customers

| Scope             | Purpose                                  |
| ----------------- | ---------------------------------------- |
| `write_customers` | Create customers for non-guest checkouts |
| `read_customers`  | Read customer information                |

### Orders & Checkout

| Scope                                       | Purpose                         |
| ------------------------------------------- | ------------------------------- |
| `write_orders`                              | Create and update orders        |
| `read_orders`                               | Read orders submitted by Violet |
| `write_draft_orders`                        | Populate and submit orders      |
| `read_draft_orders`                         | Read draft order data           |
| `write_merchant_managed_fulfillment_orders` | Flag orders requiring review    |

### Fulfillment & Shipping

| Scope               | Purpose                   |
| ------------------- | ------------------------- |
| `read_fulfillments` | Read fulfillment statuses |
| `read_shipping`     | Read shipping policies    |
| `read_markets`      | Read shipping regions     |

### Pricing & Discounts

| Scope              | Purpose                |
| ------------------ | ---------------------- |
| `read_price_rules` | Read pricing rules     |
| `read_discounts`   | Read discount policies |

### Policies & Returns

| Scope                 | Purpose                     |
| --------------------- | --------------------------- |
| `read_legal_policies` | Read refund/return policies |
| `read_returns`        | Discover returned orders    |

### Cart Operations (Unauthenticated)

| Scope                                    | Purpose                               |
| ---------------------------------------- | ------------------------------------- |
| `unauthenticated_write_checkouts`        | Create carts without rate limits      |
| `unauthenticated_read_product_listings`  | Read product data without rate limits |
| `unauthenticated_read_product_inventory` | Read inventory without rate limits    |

</details>

***

## Step 5: Release your App

This will submit and create your new App.

## Step 6: Select Custom Distribution

After creating the app, you must select the distribution method to generate an Install Link.

![Select Distribution Method](/files/vjUnK5li5tB5dlqPJEKo)

Click **"Select custom distribution"** to confirm

{% hint style="warning" %}
**This step is required.** Without selecting "Custom distribution", you cannot generate the Install Link needed for merchant onboarding.
{% endhint %}

![Shopify Custom Distribution Choice](/files/plSRzTwqqnxMk9F6dClV)

***

## Step 6: Add your store domain to generate the Install Link

{% hint style="info" %}
**What is the Install Link?** This is the URL merchants will use to install your custom app in their Shopify admin. Merchants must install the app via this link BEFORE completing Violet Connect onboarding.
{% endhint %}

After selecting custom distribution, add your store domain and select the CTA to generate the link. Upon success, you should see the Distribution page with your **Install Link**.

![Copy Custom Install Link](/files/rwulG4QhTaMV2X7nMyNI)

1. Click the **Copy** button next to the Install Link
2. Save this link — you'll need it when creating the pre-registration in Violet

The Install Link format should resemble this:

```
https://admin.shopify.com/store/{store}/oauth/install_custom_app?client_id=...
```

***

## Step 7: Copy Credentials

After creating the app, go to "Settings" in the dev dashboard to reveal the **Client ID** and **Client Secret**. You will need this for the next step.

![Shopify App Credentials](/files/nBNjHO9OxOHHJdkvdvDq)

***

## Step 8: Create Pre-Registration in Violet

Now that you have your Install Link, Client ID, and Client Secret, go to [Channel Dashboard](https://channel.violet.io) to create a pre-registration for this merchant.

***

## Summary

Before moving on, confirm you have:

* [ ] App URL set to `connect.violet.io/{YOUR_APP_ALIAS}` (or `.violet.dev` for Test Mode)
* [ ] Redirect URI set to `connect.violet.io/{YOUR_APP_ALIAS}/platforms/shopify/connect`
* [ ] All 26 API scopes selected
* [ ] Custom distribution selected
* [ ] Install Link copied
* [ ] Client ID copied
* [ ] Client Secret copied

Once you have completed all of these items, proceed to [Pre-Registration Process](/ecom-platforms/shopify/pre-registration)

***

## Help

Have questions or running into issues? See [Troubleshooting & FAQs](/ecom-platforms/shopify/troubleshooting-faqs) for common problems and solutions.


# Pre-Registration Process

Pre-registration streamlines merchant onboarding by storing OAuth credentials upfront, eliminating manual credential exchange and reducing errors. Once you pre-register a merchant, they can complete onboarding in under 2 minutes.

## 1. Access the Pre-Registered Tab

The Pre-Registered tab displays a table of all merchants awaiting installation:

1. Navigate to **Channel Dashboard** → **Merchants**
2. Click the **"Pre-Registered"** tab (second tab, after "Connected Merchants")
3. Click the **"Add Pre-Registration"** button to begin

![Create Pre-registration](/files/12MwlvQ5NCWayu2Pk0NX)

The Pre-Registered tab displays a table of all merchants awaiting installation:

* **Merchant Name**: Display name for this merchant
* **Store URL**: The merchant's Shopify store URL (`*.myshopify.com`)
* **Merchant ID**: Unique identifier assigned by Violet (format: `mrc_abc123`)
* **Actions**: Menu for managing pre-registration

### Pre-Registered Merchants Table

![Pre-registrations Table and Action Menu](/files/zmokPvzZ1lHfHmsBx1RN)

The **Actions menu** (⋮) provides:

* **Copy Violet Connect Link** — Copy the Violet onboarding link to send to merchants
* **Edit** — Update merchant details or credentials
* **Delete** — Remove pre-registration (use if merchant is no longer onboarding)

{% hint style="info" %}
When a merchant completes onboarding, they automatically move from the "Pre-Registered" tab to the "Connected Merchants" tab.
{% endhint %}

***

## 2. Complete & submit Pre-Registration Form

Fill in the required fields and submit the form shown below:

![Create Pre-registration Modal](/files/YUojPaLFhin9wQl9YtIM)

| Field             | Description                                                              | Where to Get It                                                                                                                          |
| ----------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Merchant Name** | Display name for this merchant (optional)                                | Your choice (e.g., merchant's business name)                                                                                             |
| **Store URL**     | The merchant's **permanent** `*.myshopify.com` URL — not a vanity handle | Shopify Admin → **Settings** → **Domains**, listed as the store's original/permanent `myshopify.com` domain (e.g., `acme.myshopify.com`) |
| **Install Link**  | The Shopify custom app install URL                                       | Shopify Partner Dashboard → Apps → Your Custom App → Distribution page                                                                   |
| **Client ID**     | OAuth client identifier                                                  | Shopify Partner Dashboard → Apps → Your Custom App → API credentials tab                                                                 |
| **Client Secret** | OAuth secret key                                                         | Shopify Partner Dashboard → Apps → Your Custom App → API credentials tab (shown only once)                                               |

{% hint style="info" %}
**Install Link format:** The Install Link should look like: `https://admin.shopify.com/store/{store}/oauth/install_custom_app?client_id=...`

This link is found on the Distribution page of your custom app in Shopify Partner Dashboard after selecting "Custom distribution". See [Shopify App Setup - Step 6](/ecom-platforms/shopify/shopify-app-setup#step-6-copy-the-install-link) for details.
{% endhint %}

{% hint style="warning" %}
**Use the permanent `.myshopify.com` handle, not a vanity one.**

Shopify lets merchants rename their store handle after creation, but the original `.myshopify.com` URL assigned when the store was first created never changes — it's the only handle Shopify will recognize during the OAuth install flow.

If you pre-register a merchant with a renamed/vanity `.myshopify.com` handle, the merchant will hit a "Pre-Registration not found" error when they try to install the app.

**Where to find it:** In the merchant's Shopify Admin, go to **Settings → Domains**. The permanent handle is the `myshopify.com` URL listed there (it may not be the primary storefront domain the merchant uses publicly).
{% endhint %}

### After Submission

After creating the pre-registration, you'll see a success modal displaying:

* Confirmation message with merchant name
* Assigned Merchant ID (format: `mrc_abc123`)
* **Violet Connect link** for this merchant (format: `https://connect.violet.io/platforms/shopify/connect?preregistration={ENCODED_DATA}`)

{% hint style="success" %}
Copy this link and send it to your merchant. This is the recommended link — it provides the fastest onboarding experience with pre-filled merchant details.
{% endhint %}

***

## Getting the Violet Connect Link

### From the Pre-Registered Tab

Once you've successfuly pre-registered a merchant, you should see them in the Pre-Registrations table where you can retrieve the Violet Connect link at any time:

1. Find the merchant in the table
2. Click the **actions menu** (⋮) for that merchant
3. Click **Copy Violet Connect Link**

***

## What to Send Your Merchant

### Send the Violet Connect Link

Send your merchant the Violet Connect link. This link contains the encoded pre-registration data, so the merchant will be taken directly to the "Store Found" screen after logging in.

> **Subject: Connect Your Shopify Store to \[Your Channel Name]**
>
> Hi \[Merchant Name],
>
> To connect your Shopify store to \[Your Channel Name], please complete the following steps:
>
> **Click this link to get started:** \[Violet Connect Link]
>
> You'll be guided through:
>
> 1. Creating a Violet account (or logging in if you already have one)
> 2. Confirming your pre-registered store details
> 3. Installing the app on Shopify (you'll be redirected to Shopify to authorize)
> 4. Setting up your payout account
>
> The entire process takes just a few minutes.
>
> Questions? Reply to this email.

### Alternative Path: Store URL Lookup

If a merchant loses the Violet Connect link or prefers to start fresh, they can also go directly to `https://connect.violet.io/{your_app_alias}`:

1. Create an account or log in
2. Select **Shopify** as their platform
3. Enter their store URL (e.g., `yourstore.myshopify.com`)

If the pre-registration is set up correctly, they'll see a "Store Found" confirmation and can proceed with the installation.

{% hint style="warning" %}
If the pre-registration wasn't created correctly and associated with the merchant's store, the merchant will see a "Pre-Registration not found" error. Make sure you enter the merchant's **permanent** `.myshopify.com` handle (not a vanity/renamed one) when setting up their pre-registration, and ensure your merchant enters the same store URL if they take this path.

<img src="/files/tUjetsRRrB36WrkSauR0" alt="pre-registration-not-found" data-size="original">
{% endhint %}

***

**Next step:** Learn about the [merchant onboarding experience](/ecom-platforms/shopify/merchant-onboarding) so you understand what happens after you send the link.


# Merchant Onboarding

## Merchant Onboarding

After you've pre-registered a merchant in the Channel Dashboard, they complete onboarding through a single Violet Connect flow that handles both account creation and Shopify app installation. This page explains what the merchant experiences.

The merchant can onboard with the [Violet Connect Link](#using-violet-connect-link) or via the alternative path using [store URL lookup](#alternative-path-using-store-url-lookup).

## The Onboarding Flow

### Your Steps (Channel)

1. **Pre-register merchant** in Channel Dashboard with Store URL, Install Link, Client ID, and Client Secret
2. **Copy the Violet Connect link** from the Pre-Registered tab (Actions menu → Copy Violet Connect Link)
3. **Send Violet Connect link to merchant**

***

### Using Violet Connect Link

The merchant receives your Violet Connect link and completes the entire onboarding in one seamless flow:

**1. Open the Violet Connect Link**

* Merchant clicks the Violet Connect link you sent
* They're taken to the Violet Connect onboarding page

**2. Authenticate with Violet**

* Enter email address
* Receive and enter 6-digit verification code

![Violet Connect Login](/files/zdWNkKD2s6GwIZEvvICR)

![Violet Connect 6-digit Code Authentication](/files/zdTK4cHfaNPFYjzwkk6v)

**3. Review Pre-filled Details (Store Found)**

* Because the Violet Connect link contains the encoded pre-registration data, the merchant is taken directly to the "Store Found" screen
* They see their store name and URL already filled in
* Pre-registration detected automatically

![Violet Connect Store Found](/files/2tls0LYuEcfeih39o8R9)

**4. Install the Shopify App**

{% hint style="danger" %}
**Critical:** When installing the app, merchants should leave **"Embed app in Shopify admin"** unchecked (it's checked by default).
{% endhint %}

* Merchant clicks the **"Connect to Shopify"** button
* They're redirected to Shopify to authorize the app installation
* Merchant sees the "Install app" confirmation screen showing your app name and required permissions
* Merchant clicks **"Install"** button

![Install Custom App Screen](/files/cTFXP7ExllfaNPiPpcFL)

**5. Return to Violet Connect**

* After installation, merchant is automatically redirected back to Violet Connect
* Violet completes the OAuth handshake in the background

**6. Complete Setup**

* Set up payout account (if required)
* Configure commission settings (if applicable)

**7. Done!**

* Store is connected
* Merchant automatically moves to your Connected Merchants tab
* You receive webhook notification of successful connection

***

#### Why This Flow Works

| Benefit              | Description                                                 |
| -------------------- | ----------------------------------------------------------- |
| ✅ **Single link**    | Merchants only need one link to complete the entire process |
| ✅ **Seamless**       | App installation happens within the Violet Connect flow     |
| ✅ **Fast**           | Entire onboarding takes just a few minutes                  |
| ✅ **Error-free**     | No manual credential entry or typos                         |
| ✅ **Pre-configured** | All OAuth settings handled during pre-registration          |
| ✅ **Trackable**      | Real-time status updates in your Channel Dashboard          |
| ✅ **Secure**         | OAuth credentials never exposed to merchant                 |

***

#### Violet Connect Link Format

Your merchant-specific Violet Connect links should follow this format:

```
https://connect.violet.io/YOUR_APP_ALIAS/platforms/shopify/connect?preregistration=ENCODED_DATA
```

The encoded pre-registration data automatically connects everything to your pre-registration in the Channel Dashboard.

***

### Alternative Path: Using Store URL Lookup

The merchant loses the Violet Connect link or navigates directly to `https://connect.violet.io/{your_app_alias}`:

1. Merchant creates an account or logs in
2. Merchant selects **"Shopify"** as their platform
3. Merchant enters their store URL (e.g., `acme.myshopify.com`)
4. Violet detects the pre-registration and shows **"Store Found"** confirmation
5. Merchant clicks **"Connect to Shopify"** and is redirected to Shopify for app installation
6. After installation, merchant is redirected back to Violet Connect to complete setup

{% hint style="info" %}
**When to use this path**: If a merchant is not provided or loses their Violet Connect link, they can still complete onboarding by entering their store URL manually.
{% endhint %}

{% hint style="warning" %}
**The store URL must be the merchant's permanent `.myshopify.com` handle** — the original URL assigned by Shopify when the store was created, not a renamed/vanity handle. The merchant can find it in their Shopify Admin under **Settings → Domains**. A vanity handle will produce a "Pre-Registration not found" error even if pre-registration was set up correctly.
{% endhint %}

***

### Behind the Scenes

When a merchant completes onboarding, Violet automatically:

1. **Completes OAuth handshake** with Shopify using your pre-registered credentials
2. **Validates the connection** to ensure everything is working
3. **Updates merchant status** from "Pre-Registered" to "Connected"
4. **Sends webhook** to notify you of successful connection
5. **Begins catalog sync** to make products available in your channel

You don't need to handle any technical OAuth details — Violet manages the entire process using the Client ID and Client Secret you provided during pre-registration.

***

**Next steps:**

* [Troubleshooting & FAQs](/ecom-platforms/shopify/troubleshooting-faqs) — Common issues and solutions
* [Back to Pre-Registration](/ecom-platforms/shopify/pre-registration) — Set up more merchants


# Sales Channel Publishing

How a Violet channel appears as a native Shopify sales channel, letting merchants choose product-by-product which products they share.

When a Violet channel is set up as a Shopify sales channel, the channel appears in the merchant's Shopify admin alongside their other sales channels. The merchant decides, product by product, which products are available to that channel, and Violet syncs only those.

This replaces the previous behavior, where connecting a Shopify store shared the merchant's entire catalog with the channel.

{% hint style="info" %}
This is the shared concept page for the feature. The rest of this section builds on it:

* [Setting Up Your Sales Channel App](/ecom-platforms/shopify/sales-channel/setup): build the Shopify app that acts as your sales channel
* [Publication-Scoped Catalog Sync](/ecom-platforms/shopify/sales-channel/catalog-sync): what changes for your Violet API integration
* [Enablement & Rollout](/ecom-platforms/shopify/sales-channel/enablement): turn the feature on and roll it out to merchants
* [Troubleshooting & FAQ](/ecom-platforms/shopify/sales-channel/troubleshooting): common issues and answers
  {% endhint %}

## How Shopify models this

Two Shopify concepts do the work. You'll see both names throughout our documentation and in the Shopify API.

**Channel.** A destination where a merchant's products can be sold: their online store, point of sale, a marketplace, or an app like yours. When a merchant connects to a Violet channel configured for this feature, Violet creates a channel on their store during setup. The channel is named after the Violet app, so merchants see the partner's brand rather than "Violet."

**Publication.** Every channel has an associated publication: the set of products the merchant has made available to that channel. The publication is the actual list Violet reads from. A product that is not in the publication does not exist as far as the channel is concerned.

In the Shopify admin, merchants never see the word "publication." They see a checkbox for the channel on each product, and the act of ticking it is what adds the product to the publication.

## Who controls what

|                                          | Violet                        | Merchant   |
| ---------------------------------------- | ----------------------------- | ---------- |
| Creating the channel on the store        | ✅ automatically, during setup |            |
| Deciding which products the channel gets |                               | ✅ entirely |
| Syncing the published products           | ✅ continuously                |            |
| Removing a product from the channel      |                               | ✅          |

**Violet never publishes or unpublishes products on the merchant's behalf.** Product selection is the merchant's decision, made in their own admin, and it can change at any time without notice to the channel. This is the point of the feature: merchants get explicit, granular control over what they share, using the same interface they already use for every other sales channel.

## The three states of a product

**Not published.** The merchant has never made the product available to the channel. Violet does not sync it, and no record of it exists in the channel's catalog. New channels begin with every product in this state.

**Published.** The merchant has made the product available. Violet syncs it and it appears in the channel's catalog as an [Offer](/prism/catalog/offers), with each Shopify variant as a [SKU](/prism/catalog/skus).

**Unpublished after having been published.** The merchant has removed the product's availability. Violet marks the corresponding Offer `publishing_status: NOT_PUBLISHED`, and the product stops being sellable through the channel. Nothing is deleted: the Offer keeps its id, its data, and its SKUs, and its `status`, `available`, and `visible` are unchanged, because the product still exists and can keep selling in the merchant's own store. Re-publishing sets `publishing_status: PUBLISHED` again, on the same Offer.

## What this feature does *not* change

Sales channel publishing controls **catalog membership only**. Everything else about a Shopify connection behaves exactly as it did before:

* Order submission, order status, fulfillment, and refunds
* Inventory quantities and multi-location inventory
* Pricing, including contextual and multi-currency pricing
* Product data: titles, descriptions, media, variants, options, metafields
* Existing catalog rules such as collection filters and excluded tags or vendors, which continue to apply *on top of* publication filtering

Orders that were already placed are never affected by a merchant unpublishing a product.


# Setting Up Your App

Build the Shopify sales channel app that powers publication-scoped catalog sync: app creation, the channel\_config extension, scopes, deploy/release, and Violet setup.

This page is for channel partners building the Shopify app that will act as their sales channel. It assumes the concepts on [Sales Channel Publishing on Shopify](/ecom-platforms/shopify/sales-channel).

This guide walks you through creating a Shopify app that installs on a single store and registers as a native **sales channel**, so a merchant can publish products to your channel and only those products sync to Violet. You (the developer/partner) own the Shopify app; Violet integrates with it.

This document ends where [Enablement & Rollout](/ecom-platforms/shopify/sales-channel/enablement) begins: once your app is built, deployed, and released, that page covers configuring Violet and onboarding merchants.

## Overview

Publication-scoped catalog sync requires your Shopify app to be a genuine sales channel app, one that owns a channel on the merchant's store. That is what produces the checkbox merchants tick on each product. An ordinary app without a channel configuration cannot do this; Shopify rejects channel creation for it.

A sales channel is declared by deploying a `channel_config` extension. That's an app-level property, not something that requires a public App Store listing.

{% hint style="danger" %}
**Deploying the `channel_config` extension is irreversible.** It permanently declares the app a sales channel. Always build and test against a Shopify **development store** first, and confirm you are working against the intended app before you deploy.
{% endhint %}

Building it is a sequence of steps:

1. Install the Shopify CLI.
2. Create the app in the Dev Dashboard and link it to a local project.
3. Add a `channel_config` extension and define your channel specification.
4. Set access scopes.
5. Deploy **and** release the app version.
6. Select custom distribution and install on the merchant's store.
7. Configure the corresponding Violet app to match.

## Before you start

**Prerequisites**

* A Shopify Partner account and access to the **Dev Dashboard** ([dev.shopify.com/dashboard](https://dev.shopify.com/dashboard)). This is the same Partner account described in the general [Prerequisites](/ecom-platforms/shopify/prerequisites).
* **Node.js 22.12 or higher**, a Node package manager (npm, Yarn 1.x, or pnpm), and **Git 2.28 or higher**. These are prerequisites for the Shopify CLI.
* The **Shopify CLI** installed (see Step 1).
* The **`myshopify.com` domain** of the store this channel will run on.

{% hint style="info" %}
**Things to know going in**

* Declaring the app a sales channel (deploying the extension) is **irreversible**. Test on a development store first.
* Custom distribution **cannot use Shopify's Billing API**. That's fine for a channel you operate yourself.
  {% endhint %}

## Step 1: Install the Shopify CLI

First confirm your Node.js version meets the requirement:

```bash
node -v    # must be 22.12 or higher
```

If Node is missing or too old, install the latest LTS from [nodejs.org](https://nodejs.org/) (or via a version manager like nvm) before continuing.

Install the CLI globally using whichever package manager you use:

```bash
# npm
npm install -g @shopify/cli@latest

# or yarn
yarn global add @shopify/cli@latest

# or pnpm
pnpm install -g @shopify/cli@latest
```

On macOS you can instead use Homebrew, which also pulls in a compatible Node.js:

```bash
brew tap shopify/shopify
brew install shopify-cli
```

Verify the install:

```bash
shopify version
```

{% hint style="info" %}
Shopify CLI 4.0+ auto-upgrades itself after commands (skipped in CI and for local installs). To upgrade manually at any time, run `shopify upgrade`. If you're behind a corporate proxy, set `SHOPIFY_HTTP_PROXY` (and optionally `SHOPIFY_HTTPS_PROXY`) before running CLI commands.
{% endhint %}

## Step 2: Create the app in the Dev Dashboard

1. Go to [dev.shopify.com/dashboard](https://dev.shopify.com/dashboard) and create a new app.
2. Give it a name.
3. Open the app and copy its **Client ID**; you'll need it in the next step.

## Step 3: Link the app to your local project

From an empty project directory in your terminal:

```bash
shopify app config link --client-id <YOUR_CLIENT_ID>
```

This logs you in and writes a `shopify.app.toml` into the folder, connecting the directory to your Dev Dashboard app.

## Step 4: Add a package.json

The CLI needs a `package.json` at the project root to treat the folder as an app and hold extensions. Create one:

```json
{
  "name": "your-channel-sales-channel",
  "version": "1.0.0",
  "private": true,
  "license": "UNLICENSED",
  "scripts": {
    "dev": "shopify app dev",
    "deploy": "shopify app deploy",
    "generate": "shopify app generate"
  },
  "devDependencies": {
    "@shopify/cli": "latest"
  }
}
```

Then install:

```bash
npm install
```

## Step 5: Generate the channel config extension

```bash
shopify app generate extension --template channel_config --name channel-config
```

This creates:

```
extensions/channel-config/
├── shopify.extension.toml
└── specifications/
    ├── example-us.toml      ← sample, delete
    ├── example-de.toml      ← sample, delete
    ├── example-au.json      ← sample, delete
    └── icons/
        └── example-channel-icon.svg
```

## Step 6: Define your channel specification

Delete the three `example-*` spec files (leave the `icons/` folder). Then create one specification file describing your channel, named for your channel (e.g. `extensions/channel-config/specifications/your-channel.toml`). Use your own brand name for `handle` and `label`. The `label` is what merchants see in the Shopify admin, and the `handle` is the specification handle Violet uses when it creates the channel on the merchant's store.

```toml
handle = "your-channel"
label = "Your Channel"
icon = "icons/example-channel-icon.svg"   # replace with your own 20x20 SVG
productFeedManagement = "automatic"

# Capabilities default to false. Turn on only what the channel actually supports.
[capabilities]
bundles = true
digitalProducts = true
subscriptions = false
combinedListings = false
unlistedProducts = true
scheduledPublishing = false

[requirements]
# false = marketplace-style, channel can carry its own catalog/pricing.
# true  = referral-style (like Google/Meta) mirroring the online store;
#         this also requires the store to have a web-presence market covering the countries.
expectsOnlineStoreParity = false
# "channel"  = your external surface processes checkout/payment.
# "merchant" = the merchant's own Shopify checkout processes it.
merchantOfRecord = "merchant"

[[countries]]
code = "US"
languages = ["en"]
currency = "USD"

[[countries]]
code = "GB"
languages = ["en"]
currency = "GBP"
```

Field notes:

* **`handle`** is the specification handle. Note the exact spelling: Violet must send the same value when it creates the channel, and the two must match exactly.
* **`merchantOfRecord`**: set `"channel"` if you are the merchant of record, `"merchant"` if the Shopify store is.
* **`expectsOnlineStoreParity`**: keep `false` for marketplace-style channels. If you set `true`, channel creation will fail unless the store has a market with a valid web presence covering your countries.
* **`countries`**: one entry per country, with ISO country/language/currency codes. Each country generates its own product feed.

Also update the extension's own metadata in `extensions/channel-config/shopify.extension.toml`:

```toml
[[extensions]]
type = "channel_config"
name = "Your Sales Channel"
description = "Your sales channel configuration"
handle = "channel-config"
create_legacy_channel_on_app_install = false
```

### How the specification handle is matched

Violet sends a specification handle when it creates the channel on a merchant's store, and it must match the `handle` in your deployed spec exactly.

* If you set `specification_handle` on the Violet app configuration, that value is sent verbatim.
* If you leave it unset, Violet derives it from the Violet app's name by lowercasing it and replacing runs of whitespace with hyphens. An app named `Violet Marketplace` produces `violet-marketplace`.

Set `specification_handle` explicitly whenever your deployed handle doesn't follow that convention. A mismatch is the most common setup failure and surfaces as a `Channel specification not found` error during provisioning, which is non-fatal: affected merchants silently stay on full-catalog syncing.

## Step 7: Set access scopes

Open `shopify.app.toml` and make sure the `scopes` line includes these, at minimum:

```toml
[access_scopes]
scopes = "read_channels,write_channels,read_customers,write_customers,read_discounts,read_draft_orders,write_draft_orders,read_fulfillments,read_inventory,read_legal_policies,read_locales,read_locations,read_markets,write_merchant_managed_fulfillment_orders,read_metaobject_definitions,read_metaobjects,read_orders,write_orders,read_price_rules,read_products,read_product_listings,read_publications,write_publications,read_returns,read_shipping,read_translations,unauthenticated_read_product_inventory,unauthenticated_read_product_listings,unauthenticated_write_checkouts"
```

Beyond the product and order scopes a standard integration already uses (see the [26 scopes in the general App Setup guide](/ecom-platforms/shopify/shopify-app-setup#required-api-scopes)), a sales channel app needs the channel- and publication-specific scopes below.

| Scope                             | Why                                                                                                         | Required?                                                                                                        |
| --------------------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `read_channels`, `write_channels` | Create and manage the channel on the merchant's store                                                       | **Required** for a sales channel app                                                                             |
| `read_publications`               | Identifies the publication attached to your channel, the list of products the merchant has published to you | **Required.** Without it, provisioning cannot complete and every merchant silently stays on full-catalog syncing |
| `write_publications`              | Sets the channel's auto-publish behavior for products created after setup                                   | Only if auto-publish is being configured                                                                         |
| `read_product_listings`           | Reads the published product listings for the channel                                                        | **Required** for a sales channel app                                                                             |

{% hint style="danger" %}
**`read_publications` is not included in the generalized product scopes.** An app requesting only generalized scopes will not receive it. It must be declared explicitly, and it is the easiest prerequisite to miss.
{% endhint %}

{% hint style="warning" %}
Changing scopes means an existing app will be prompted to re-grant permissions the next time it's installed or opened. Select everything you need up front.
{% endhint %}

## Step 8: Deploy *and* release the app version

```bash
shopify app deploy
```

This bundles the config and the extension into a new **app version**. When prompted, **accept the release**.

{% hint style="danger" %}
The extension must be both **deployed** and **released**. A deployed-but-unreleased version behaves exactly like no extension at all: channel creation fails, and merchants continue on full-catalog syncing with no error surfaced to them. If you deploy without releasing (answering "no", or running non-interactively without `--force`), the store keeps running the previous version and your new specification won't exist as far as the API is concerned.
{% endhint %}

To release explicitly if needed:

```bash
shopify app release --version=<version-name>
```

Verify in the Dev Dashboard → your app → **Versions** that the **active/released** version's `channel-config` extension lists your real spec handle (e.g. `your-channel`), not the `example-*` handles.

## Step 9: Set custom distribution and install

1. In the Partner Dashboard → **App distribution**, select the app → **Choose distribution** → **Custom distribution**. This choice is permanent.
2. Enter the store's `myshopify.com` domain. To lock it to one store, uncheck "Allow multi-store installs for one Plus organization."
3. Click **Generate link**.
4. Pre-register the merchant in the Violet [Channel Dashboard](https://channel.violet.io) and complete installation.

This is the same custom-distribution and pre-registration flow used for every Shopify merchant. See [Shopify App Setup](/ecom-platforms/shopify/shopify-app-setup) and [Pre-Registration Process](/ecom-platforms/shopify/pre-registration) for the detailed walkthrough and the Install Link.

After installing, the app appears under the store's **Settings → Apps and sales channels** and in the **Sales channels** list.

## Step 10: The channel connection (handled by Violet)

Being listed as a sales channel is not enough for products to be publishable to it. A channel only appears in a product's **Manage publishing** dialog after a **channel connection** exists, which creates the publication and product feeds.

{% hint style="info" %}
**You don't create the channel connection yourself.** Violet performs it during merchant provisioning. When the merchant connects (or reconnects) through Violet, Violet calls Shopify's `channelCreate` mutation against the store using your specification handle, then identifies the resulting publication and turns on publication-scoped syncing. See [Enablement & Rollout](/ecom-platforms/shopify/sales-channel/enablement#what-happens-when-a-merchant-connects).
{% endhint %}

For reference, this is the Shopify mutation Violet issues against the store's GraphQL Admin API. The `specificationHandle` must exactly match the `handle` in your deployed, released spec:

```graphql
mutation ChannelCreate($input: ChannelCreateInput!) {
  channelCreate(input: $input) {
    channel { id handle specificationHandle }
    userErrors { field message code }
  }
}
```

On success, the channel has a publication, appears in the product Manage-publishing dialog, and product feeds begin syncing. From that point the merchant can immediately choose which products are published to your channel.

## Configure the Violet app

Set the following on your Violet app configuration so Violet provisions the channel for connecting merchants.

| Setting                                       | Purpose                                                                                                                                        |
| --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `sales_channel_behavior.enabled`              | Turns on channel provisioning for merchants connecting to this app                                                                             |
| `sales_channel_behavior.specification_handle` | The handle from your deployed extension. Optional; see [Step 6](#how-the-specification-handle-is-matched) for the derivation rule when omitted |
| `sales_channel_behavior.channel_name`         | Display name merchants see in their Shopify admin. Optional; defaults to the Violet app name                                                   |

## Verify the setup

On a Shopify development store:

1. Connect the store to your channel.
2. Confirm the channel appears in the store's admin under **Sales channels**, named as you expect.
3. Open any product and confirm your channel appears in the **Sales channels and apps** section.
4. Publish a product and confirm it reaches your Violet catalog.
5. Unpublish it and confirm it is withdrawn.

If step 2 fails, work through [The channel doesn't appear in the merchant's Shopify admin](/ecom-platforms/shopify/sales-channel/troubleshooting) in the troubleshooting guide.

## Converting an existing (legacy) app

For legacy merchants you can link their existing app and convert it to a sales channel app:

```bash
shopify app config link --client-id <YOUR_CLIENT_ID>
```

then follow the extension, scope, and deploy/release steps above. Converted merchants will need to be pre-registered again and re-install the app to accept the new scopes and inherit the new configuration. This is the same re-authorization requirement described in [Enablement & Rollout](/ecom-platforms/shopify/sales-channel/enablement#rollout-to-existing-merchants).

## Troubleshooting the build

**`shopify app generate extension` → "doesn't have a package.json".** `config link` didn't scaffold a project. Add the `package.json` from [Step 4](#step-4-add-a-packagejson), run `npm install`, and retry.

For merchant-facing and provisioning issues, see [Troubleshooting & FAQ](/ecom-platforms/shopify/sales-channel/troubleshooting).


# Catalog Sync

What publication-scoped syncing changes for your Violet API integration: which products you receive, the product lifecycle, and webhook behavior.

This page is for developers building against the Violet API for channels configured as a Shopify sales channel. It assumes the concepts on [Sales Channel Publishing on Shopify](/ecom-platforms/shopify/sales-channel).

## What changes for your integration

Your catalog for a Shopify merchant is now the set of products that merchant has published to your channel, not their whole store. Three consequences worth designing for:

1. **Catalog size is merchant-controlled and can change without warning.** A merchant can unpublish a hundred products in one bulk action. Your integration should handle the catalog shrinking as a normal event, not an error condition.
2. **A newly connected merchant may sync zero products.** Products are not published to a new channel automatically. Until the merchant publishes some, their catalog is legitimately empty. Do not treat an empty catalog after connection as a failed sync.
3. **Unpublishing is an update, not a deletion.** The Offer stays exactly where it is (same id, same data, same SKUs) with its `publishing_status` set to `NOT_PUBLISHED`. Read that field to know whether an Offer belongs in your catalog. See [Webhooks](#webhooks) below.

Everything else (order submission, inventory, pricing, refunds, the shape of the [Offer](/prism/catalog/offers) and [SKU](/prism/catalog/skus) models) is unchanged.

## Which products you receive

A product appears in your catalog only when **all** of the following are true:

* The merchant has published it to your channel in Shopify.
* Its Shopify status is Active.
* It is not excluded by the channel's existing catalog rules: collection filters, excluded collections, excluded tags, or excluded vendors. Publication filtering is applied *in addition to* these rules, not instead of them.

Publication filtering is applied consistently on every path that reads products: the product count, the paged catalog sync, the bulk catalog sync, the per-product webhook sync, and the direct product sync API. There is no route through which an unpublished product can enter your catalog.

## Product lifecycle

| Merchant action in Shopify                    | What Violet does                                         | Resulting Offer state                                                                                    | Webhook                                                                                                                   |
| --------------------------------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| Publishes a product to your channel           | Fetches the product and creates or republishes the Offer | `publishing_status: PUBLISHED`                                                                           | `OFFER_ADDED` for a newly created Offer; `OFFER_UPDATED` **and** `OFFER_ADDED` when republishing one that already existed |
| Edits a published product                     | Re-fetches and updates the Offer                         | Offer updated                                                                                            | `OFFER_UPDATED`, when there are material changes                                                                          |
| Unpublishes the product from your channel     | Withdraws the Offer from your catalog                    | `publishing_status: NOT_PUBLISHED`. **`status`, `available`, `visible`, and SKU statuses are unchanged** | `OFFER_UPDATED` **and** `OFFER_REMOVED`                                                                                   |
| Deletes the product in Shopify                | Archives the Offer                                       | `status: ARCHIVED`, `available: false`, `visible: false`, every SKU `status: ARCHIVED`                   | `OFFER_UPDATED`                                                                                                           |
| Re-publishes a previously unpublished product | Re-fetches and republishes the Offer                     | `publishing_status: PUBLISHED` again, same Offer id                                                      | `OFFER_UPDATED` and `OFFER_ADDED`                                                                                         |

Note the difference between the middle two rows. **Unpublishing from your channel is neither an archive nor a deletion.** It is an update to one field. The product is still active and selling in the merchant's own store; only its membership of your catalog changed, so its status and availability are left untouched. A product actually deleted in Shopify still archives, because it genuinely is gone.

Publish and unpublish are event-driven. In normal operation the catalog reflects a merchant's change within seconds, though delivery is not instantaneous and should not be relied on as synchronous.

## Webhooks

The event name is delivered in the `X-Violet-Topic` header. The request body is the Offer itself. For the full offer event reference, see [Offer Webhooks](/prism/webhooks/events/offer-webhooks).

### Unpublishing is an update, not a deletion

When a merchant unpublishes a product from your channel, Violet sets the Offer's `publishing_status` to `NOT_PUBLISHED` and sends **both** `OFFER_UPDATED` and `OFFER_REMOVED`.

Despite the event name, nothing is deleted. The Offer keeps its id, its data, and its SKUs; only the publishing status changed. That is what allows a re-publish to restore the same Offer rather than create a new one. (`OFFER_DELETED` is a separate event, for Offers that are genuinely removed.)

**`publishing_status` is the field that tells you whether an Offer belongs in your catalog.** `status` and `available` describe the product in the merchant's own store, and an unpublished product is often still `AVAILABLE` there because it is still selling on their other channels. Both values are accurate; they answer different questions.

```
X-Violet-Topic: OFFER_REMOVED
```

```json
{
  "id": 4821904,
  "merchant_id": 17240,
  "external_id": "7382910481234",
  "publishing_status": "NOT_PUBLISHED",
  "status": "AVAILABLE",
  "available": true,
  "visible": true,
  "skus": [
    { "id": 91827364, "external_id": "42918273645", "status": "AVAILABLE" },
    { "id": 91827365, "external_id": "42918273646", "status": "AVAILABLE" }
  ]
}
```

The two events are delivered independently and may arrive in either order, so don't depend on the sequence; `publishing_status` is correct in both.

### Other webhook behavior

* **Offers you never received stay silent.** If an Offer was never published to your app, no webhook is sent when it changes. This matches existing Violet behavior.
* **`OFFER_UPDATED` is suppressed when nothing material changed.** A re-sync that produces an identical Offer does not generate an event.
* **Relay channels receive additional events.** Channels on the [Relay](/relay/relay) plan also receive `RELAY_OFFER_UPDATED` when a product is published or edited, and `RELAY_OFFER_REMOVED` when it is unpublished, delivered directly from the sync layer.
* **Your channel's catalog rules still apply.** If a product is withheld by a collection, tag, or vendor rule (or if offers for that merchant are configured not to publish automatically), ticking the channel in Shopify does not override that. Channel membership and Violet publishing are separate gates, and a product must clear both.

## Reconciliation

Publication changes are delivered by webhook. If your integration needs to confirm the current state of a merchant's catalog (after downtime on your side, for example), re-read the catalog through the standard Violet catalog endpoints. The result is already scoped to the merchant's published set.

{% hint style="warning" %}
**Known limitation.** Violet's scheduled catalog validation checks whether products still exist and whether they are Draft or Archived in Shopify, but it does not currently re-verify publication membership. If a merchant unpublishes a product during an extended interruption in webhook delivery, that Offer can remain active in Violet until the product is next modified. If accurate withdrawal is critical to your integration, periodically reconcile against the catalog endpoints.
{% endhint %}

## Testing your integration

On a Shopify development store connected to your channel:

1. Publish a product to your channel and confirm you receive `OFFER_ADDED`.
2. Edit the product's title and confirm you receive `OFFER_UPDATED`.
3. Unpublish the product. Confirm you receive `OFFER_REMOVED` with `publishing_status: NOT_PUBLISHED`, and that your integration withdraws it. Note that `status` will still read `AVAILABLE`; the product is still selling in the merchant's store.
4. Re-publish it and confirm it returns with the same Offer id and `publishing_status: PUBLISHED`.
5. Confirm a product you have never published to the channel never reaches your catalog.


# Enablement & Rollout

Prerequisites for turning on Shopify sales channel publishing, what happens when a merchant connects, and how to roll the feature out to existing merchants.

This page is for channel partners preparing to turn on Shopify sales channel publishing, and the Violet solutions team supporting them. It assumes the concepts on [Sales Channel Publishing on Shopify](/ecom-platforms/shopify/sales-channel).

## Prerequisites

All four must be in place before any merchant can be provisioned. If any is missing, channel creation fails quietly and affected merchants continue on full-catalog sync; there is no error surfaced to the merchant, so verify these up front.

**1. A deployed and released Shopify channel configuration extension.** Your Shopify app needs a `channel_config` extension that is both deployed *and* released. Shopify rejects channel creation for apps without one. The extension declares a specification handle that Violet references when creating the channel. See [Setting Up Your Sales Channel App](/ecom-platforms/shopify/sales-channel/setup).

**2. Sales channel behavior enabled on the Violet app.** Set `sales_channel_behavior.enabled` on the app configuration. Two optional settings sit alongside it:

* `specification_handle`: the handle from your `channel_config` extension. If omitted, Violet derives it from the app name by lowercasing and replacing spaces with hyphens, so an app named `Violet Marketplace` produces `violet-marketplace`. Set it explicitly whenever your deployed handle doesn't match that convention.
* `channel_name`: the display name merchants see in their Shopify admin. Defaults to the app name.

**3. The `read_publications` Shopify scope.** This must be declared as a custom Shopify scope on the app. It is **not** included in the generalized product scopes. An app requesting only generalized scopes will not receive it, and provisioning will fail to resolve the publication. This is the easiest prerequisite to miss.

**4. Merchant authorization under the new scopes.** Merchants must authorize the connection after the scopes above are in place.

## What happens when a merchant connects

1. The merchant authorizes the connection as usual.
2. Violet creates a channel on their store, named after your app, and identifies the publication attached to it.
3. Violet turns on publication-scoped syncing for that merchant and registers publication webhooks.
4. From that point on, the channel's catalog is the merchant's published set.

Three properties of this sequence are worth knowing:

**It's all-or-nothing.** Publication-scoped syncing is enabled only after both the channel and its publication are confirmed. A partial failure leaves the merchant on full-catalog syncing. There is no half-enabled state where a merchant has publication webhooks but an unfiltered catalog.

**It's non-fatal.** If channel creation fails for any reason, the connection still succeeds and the merchant syncs normally. Nothing about onboarding breaks.

**It's idempotent and self-healing.** Reconnecting an already-provisioned merchant does not create a duplicate channel. If an earlier attempt created the channel but failed to record the publication, reconnecting repairs it.

## Rollout to existing merchants

**Merchants already connected are not migrated automatically.** They continue with full-catalog syncing until they re-authorize the connection.

This is deliberate. Existing merchants have neither a channel on their store nor the Shopify permissions needed to create one. Re-authorization is what grants the new permissions, and it is also what triggers channel creation, so the two cannot be separated, and there is no backfill that can enable a merchant without their involvement.

Practically, this means:

* Enabling the feature on your app changes nothing for your existing merchants until each one reconnects.
* Plan a merchant communication campaign around reconnection. A merchant who reconnects without warning will find their catalog scoped to an empty publication.
* **Sequence it carefully:** after reconnecting, a merchant's catalog is empty until they publish products to the new channel. Tell merchants to publish their products as part of the same session in which they reconnect. Walk them through the merchant-facing instructions in the [Merchant Help Center](https://merchant-help.violet.io/).

## Merchants connected to more than one Violet channel

A merchant can be connected to several Violet channels at once. Each connected app gets its own Shopify channel and its own publication, so:

* The merchant sees one checkbox per channel on each product.
* They can share different products with different channels.
* Publishing to one channel has no effect on any other.
* A merchant can be publication-scoped for one channel and full-catalog for another; for example, if one app has the feature enabled and another does not.

## Turning the feature off

Publication-scoped syncing can be disabled per merchant, which reverts them to full-catalog syncing. The Shopify channel remains on their store and is harmless; it simply stops being used as a filter. Talk to your Violet contact before doing this. Reverting a merchant to full-catalog syncing will expand their catalog back to the full store, which may not be what they agreed to.


# Troubleshooting & FAQ

Common issues with Shopify sales channel publishing (symptoms, causes, and resolutions) plus frequently asked questions for partners and the solutions team.

This page is for channel partners and the Violet solutions team. It assumes the concepts on [Sales Channel Publishing on Shopify](/ecom-platforms/shopify/sales-channel).

## Symptom → cause → resolution

<details>

<summary>The merchant connected, but their catalog is empty</summary>

**Most likely cause.** No products have been published to the channel yet. A new channel starts with none of the merchant's products, and this is the expected state immediately after connection.

**Resolution.** Walk the merchant through making their first products available, using the merchant-facing instructions in the [Merchant Help Center](https://merchant-help.violet.io/). This is the most common ticket on this feature. Front-load it in merchant onboarding rather than handling it reactively.

</details>

<details>

<summary>The channel doesn't appear in the merchant's Shopify admin</summary>

**Possible causes, in order of likelihood.**

1. The merchant connected before the feature was enabled for the channel and hasn't reconnected. They keep full-catalog syncing until they re-authorize.
2. The app's `channel_config` extension isn't deployed and released, so Shopify rejected channel creation.
3. The app's specification handle doesn't match the handle in the deployed extension.
4. The app is missing the `read_publications` scope, so the publication couldn't be identified.

**Resolution.** Confirm the prerequisites in [Enablement & Rollout](/ecom-platforms/shopify/sales-channel/enablement#prerequisites), then have the merchant reconnect. Reconnecting is safe and repairs partially provisioned connections without creating a duplicate channel.

</details>

<details>

<summary>The merchant published a product, but it never arrived</summary>

**Check in this order.**

1. **Shopify status.** Draft products sync but are never available for purchase; Archived products are archived in Violet. The product must be Active.
2. **Channel catalog rules.** Collection filters, excluded collections, excluded tags, and excluded vendors still apply on top of publication filtering. A published product matching an exclusion rule is correctly withheld.
3. **Which channel was ticked.** On a store connected to several Violet channels, it's easy to publish to the wrong one.
4. **Elapsed time.** Sync is event-driven and usually takes seconds, but is not instantaneous.

</details>

<details>

<summary>The merchant unpublished a product, but it's still being sold</summary>

**Most likely cause.** A missed publication event. Violet's scheduled catalog validation does not currently re-verify publication membership, so an unpublish that occurs during an extended webhook interruption may not be reflected until the product is next modified.

**Second cause.** The channel's integration is reading `status` or `available` rather than `publishing_status`. Unpublishing updates only `publishing_status`, so the other two keep describing the product as it is in the merchant's store, usually still `AVAILABLE`, since it is still selling there.

**Resolution.** Trigger a product re-sync for the affected product. If it recurs across products, check that the integration reads `publishing_status`. See [Unpublishing is an update, not a deletion](/ecom-platforms/shopify/sales-channel/catalog-sync#unpublishing-is-an-update-not-a-deletion).

</details>

<details>

<summary>The merchant is enabled for the feature but still syncing their whole catalog</summary>

**Cause.** The merchant-level setting is on, but no channel is provisioned for *this particular* app. This happens on stores connected to several Violet channels, where one connection is provisioned and another isn't.

**Resolution.** Have the merchant reconnect the affected channel. Provisioning is per connection, and reconnecting repairs the missing one without touching the others.

</details>

## FAQ

<details>

<summary>Does enabling this change anything for merchants already connected?</summary>

No. Existing merchants keep full-catalog syncing until they reconnect. Enabling the feature on an app does not retroactively scope anyone's catalog.

</details>

<details>

<summary>Can we migrate existing merchants in bulk?</summary>

No. Channel creation requires Shopify permissions that a merchant only grants by re-authorizing, so migration is necessarily merchant-initiated. Plan a reconnection campaign.

</details>

<details>

<summary>Can Violet publish the merchant's products to the channel for them?</summary>

Not today. Product selection is entirely merchant-driven, and there is no backfill that publishes an existing catalog to a new channel. Merchants must make the first selection themselves.

</details>

<details>

<summary>If a merchant unpublishes everything, is their connection broken?</summary>

No. It's a valid state: an empty publication means an empty catalog. The connection stays healthy and the catalog repopulates as soon as they publish something.

</details>

<details>

<summary>Does unpublishing a product affect orders already placed for it?</summary>

No. Existing orders, fulfillment, and refunds are unaffected.

</details>

<details>

<summary>Can a merchant share different products with different Violet channels?</summary>

Yes. Each connected app has its own channel and its own product selection.

</details>

<details>

<summary>What happens if we turn the feature off for a merchant?</summary>

They revert to full-catalog syncing and their catalog expands back to their whole store. Confirm this is what the merchant expects before doing it.

</details>


# Global-E x Shopify

## Overview

[Global-E](https://www.global-e.com/) is a cross-border e-commerce platform used by Shopify merchants to sell internationally. When a merchant enables Global-E (either through a direct integration or via Shopify's Managed Markets powered by Global-E), Global-E acts as the **Merchant of Record (MoR)** for international transactions. This means that international customers are legally purchasing from Global-E, not from the merchant, even though the transaction appears to happen on the merchant's storefront.

This document explains how Global-E's integration with Shopify works, why Violet cannot replicate this flow when creating orders via the Shopify API, and what this means for merchants who use both Violet and Global-E.

***

## How Global-E Works on a Shopify Storefront

### The Storefront Experience

When a Shopify merchant has Global-E enabled, international shoppers experience a modified version of the merchant's storefront. Global-E injects a client-side SDK (JavaScript) into the merchant's storefront that handles:

* **Country detection and switching:** Global-E identifies the shopper's location via IP geolocation and presents a welcome popup or country/currency switcher, allowing the shopper to browse in their local currency.
* **Price conversion:** Product prices displayed on the storefront (product listing pages, product detail pages, cart) are converted from the merchant's base currency to the shopper's local currency using Global-E's FX rates, country-specific pricing coefficients, and VAT adjustments.
* **Product restriction enforcement:** Products that cannot be shipped to the shopper's country (due to regulatory or commercial restrictions) are flagged or hidden.

Up to this point, the shopper is browsing the merchant's Shopify storefront normally. The Global-E SDK is modifying what they see (prices, currency, availability), but the underlying Shopify store is unchanged.

### The Checkout: Global-E's iFrame

The critical divergence happens at checkout. When an international shopper proceeds to check out, **they do not use Shopify's native checkout**. Instead:

1. The shopper's cart contents are transferred from the merchant's Shopify storefront to Global-E's servers via the `SendCartV2` API. This call includes all product details, prices, the destination country, and the selected currency.
2. Global-E's checkout is rendered inside an **iFrame** embedded in a container page on the merchant's site. The iFrame is hosted by Global-E and styled to match the merchant's branding, but it is entirely controlled by Global-E's infrastructure.
3. Inside this iFrame, Global-E calculates and displays:
   * **Localized product prices** in the shopper's currency
   * **Duties and taxes:** calculated by Global-E based on the product categories, HS codes, destination country regulations, and the merchant's configured duty/tax handling (DDP, DDU, inclusive pricing, etc.)
   * **International shipping options:** with costs and estimated delivery times from Global-E's carrier network
   * **The total landed cost:** the all-in price the shopper will pay, including product cost, shipping, duties, and taxes
4. **Payment is collected by Global-E**, not by the merchant. The shopper enters payment details into Global-E's checkout iFrame, and Global-E processes the transaction. The shopper is legally purchasing from Global-E.
5. Global-E performs a **fraud check** on the order. The merchant should not fulfill the order until this check is complete and the order status is updated to `PAID`.

### Order Creation: Global-E Writes to Shopify

After the shopper completes checkout in the iFrame, Global-E creates the order in Shopify on the merchant's behalf:

1. **Global-E calls the Shopify API** to create the order in the merchant's Shopify admin. The order is created using Shopify's multi-currency format with two currency representations:
   * **Presentment money:** the currency the international customer saw and paid in (e.g., EUR, GBP)
   * **Shop money:** the merchant's base store currency (e.g., USD), used for reporting and accounting
2. The Shopify order includes **Global-E-specific note attributes**, most importantly the `GEOrderId`, which links the Shopify order to Global-E's internal order record. This ID is required for all downstream Global-E operations (returns, refunds, financial reconciliation).
3. **Duties, taxes, and fees** appear as line items or note attributes on the Shopify order, depending on the merchant's configuration (e.g., whether duties are customer-paid, inclusive in price, or merchant-subsidized).
4. The order's initial payment status is `PENDING` while Global-E performs fraud review. Once cleared, Global-E updates the status to `PAID` via the Shopify API.
5. From an **accounting perspective**, the order should be treated as a domestic B2B transaction between the merchant and Global-E, not as a B2C transaction with the end customer. Global-E handles VAT/GST remittance, customs compliance, and financial settlement with the merchant.

### What Global-E Handles as Merchant of Record

When Global-E is the MoR for an international order, it is responsible for:

* **Collecting payment** from the international customer
* **VAT/GST registration, collection, and remittance** in each destination country
* **Duties and customs compliance:** including landed cost calculations and customs documentation
* **Currency risk:** settling with the merchant in their domestic currency regardless of what the customer paid
* **Fraud liability:** Global-E assumes fraud risk for orders processed through their checkout
* **Financial reconciliation:** providing the merchant with settlement reports

***

## Why Violet Cannot Recreate This Flow

Violet creates orders on behalf of merchants by calling the Shopify Admin API directly. This is fundamentally incompatible with Global-E's integration model for several reasons:

### 1. Global-E's Checkout Is Not an API

Global-E's duty/tax calculations, shipping options, and payment processing all happen inside their hosted checkout iFrame. There is no standalone API endpoint that accepts a list of products and a destination country and returns calculated duties and taxes. These calculations are tightly coupled to the checkout session and are not available outside of it.

### 2. Orders Must Originate from Global-E's Checkout for MoR Coverage

Global-E can only act as Merchant of Record for orders that flow through their checkout and payment infrastructure. An order created directly via the Shopify API, even if it's for an international customer in a Global-E-managed market, bypasses Global-E entirely. This means:

* **No duties or taxes are calculated** by Global-E for the order
* **No `GEOrderId`** is assigned, so the order is invisible to Global-E's systems
* **No MoR coverage:** the merchant, not Global-E, is the legal seller for that transaction
* **No VAT/GST remittance:** Global-E will not handle tax obligations for the order
* **No fraud coverage:** Global-E's fraud check does not apply
* **No financial reconciliation:** the order will not appear in Global-E's settlement reports

### 3. Global-E's API Does Not Support Standalone Duty Calculation

Global-E's API surface is designed to support their checkout-first model, not third-party order creation. While Global-E does offer APIs for shipping rates, price conversion, and product restriction checks, there is no endpoint to calculate duties and taxes independently. The duty/tax calculation engine is embedded in the checkout flow and is not exposed as a callable service.

### 4. Payment Cannot Be Retroactively Assigned to Global-E

Even if Violet could somehow calculate the correct duties and taxes, there is no mechanism to route payment through Global-E after the fact. Global-E's MoR status is established at the moment of payment. The customer must pay Global-E directly through their checkout. An order where the customer paid the merchant (or a channel) directly cannot be retroactively transferred to Global-E's MoR umbrella.

***

## Impact on Merchants Using Violet and Global-E

When a Shopify merchant uses both Violet and Global-E, the following applies:

### Domestic Orders (Non-Global-E Markets)

Orders created by Violet for **domestic customers** (e.g., a US customer buying from a US merchant) are **unaffected**. Global-E does not handle domestic transactions, and these orders flow through Shopify normally.

### International Orders in Global-E-Managed Markets

Orders created by Violet for **international customers in markets managed by Global-E** will bypass Global-E's checkout entirely. These orders:

* Will be created as standard Shopify orders with no Global-E involvement
* Will not include duty or tax calculations from Global-E
* Will not be covered under Global-E's MoR umbrella
* Will not appear in the merchant's Global-E financial reconciliation
* May create **tax compliance exposure** for the merchant, since VAT/GST obligations in the destination country are not being handled by Global-E

### Recommended Configuration

For merchants who require Global-E to be the Merchant of Record for all international orders, **international markets managed by Global-E should be disabled for orders originating through Violet**. This ensures that:

1. Violet only creates orders for markets where the merchant is prepared to handle tax and customs obligations directly (or where Global-E is not the MoR).
2. International customers in Global-E markets continue to purchase through the merchant's Shopify storefront, where Global-E's checkout iFrame handles the transaction correctly.
3. The merchant avoids unintentional tax compliance gaps from orders that bypass Global-E.

Merchants who are willing to process international orders without Global-E's MoR coverage, accepting responsibility for duties, taxes, and customs compliance themselves, may choose to keep international markets enabled for Violet. This decision should be made in consultation with the merchant's tax and legal advisors.

***

## Summary

| Scenario                                      | Violet Order Creation         | Global-E Involved?                | MoR Coverage                                         |
| --------------------------------------------- | ----------------------------- | --------------------------------- | ---------------------------------------------------- |
| Domestic order (e.g., US → US)                | Supported                     | No (not applicable)               | N/A                                                  |
| International order, non-Global-E market      | Supported                     | No                                | Merchant is responsible                              |
| International order, Global-E market          | Creates a Shopify order       | **No:** bypasses Global-E         | **None:** merchant assumes all tax/customs liability |
| International order via merchant's storefront | N/A (shopper uses storefront) | **Yes:** Global-E checkout iFrame | **Full:** Global-E is MoR                            |

Global-E's integration with Shopify is designed around a checkout-first model where international orders must originate from Global-E's hosted checkout to receive MoR coverage, duty/tax calculations, and financial reconciliation. Violet's order creation model, which calls the Shopify API directly, operates outside of this flow. Until Global-E provides API endpoints for standalone duty/tax calculation and third-party order ingestion with MoR coverage, these two systems cannot be combined for international orders in Global-E-managed markets.


# Troubleshooting & FAQs

## Troubleshooting Common Issues

<details>

<summary>404 Redirect Error During OAuth</summary>

**Problem**: Merchant clicks the installation link and sees a 404 error from Shopify during the OAuth redirect.

**Cause**: The **App URL** in Shopify Partner Dashboard uses a different host than the **Redirect URI**. Shopify requires both URLs to share the same host.

**What went wrong:**

* ❌ App URL: `https://yourcompany.com` + Redirect URI: `https://connect.violet.io/...` → **Hosts don't match**
* ✅ App URL: `https://connect.violet.io/your-alias` + Redirect URI: `https://connect.violet.io/your-alias/...` → **Hosts match**

**Solution:**

1. Go to [Shopify Partner Dashboard](https://partners.shopify.com) → **App Distribution**
2. Navigate to your Custom App → select **View on Dev Dashboard** (far right link)
3. Click **Configuration** (or **App setup**)
4. Update the **App URL** field to:
   * **Live Mode**: `https://connect.violet.io/{YOUR_APP_ALIAS}`
   * **Test Mode**: `https://connect.violet.dev/{YOUR_APP_ALIAS}`
5. Verify the **Redirect URI** uses the same host as the App URL
6. Save changes
7. Have the merchant retry the installation link

**Finding Your App Alias:** [Channel Dashboard](https://channel.violet.io) → App Settings → Violet Connect

**Prevention:** See [Shopify App Setup](/ecom-platforms/shopify/shopify-app-setup#app-url) for correct configuration.

</details>

<details>

<summary>Install Link Missing or Invalid</summary>

**Problem**: Cannot find the Install Link in Shopify Partner Dashboard, or the Install Link field shows an error in Violet pre-registration.

**Cause**: Custom distribution was not selected for the app.

**Solution:**

1. Go to [Shopify Partner Dashboard](https://partners.shopify.com) → **App Distribution** → Your Custom App
2. Look for the **Distribution** section on the app overview page
3. Click **"Select distribution method"**
4. Choose **"Custom distribution"** and confirm
5. After selection, you'll see the Distribution page with the Install Link
6. Copy the Install Link and use it in your Violet pre-registration

![Select Distribution Method](/files/vjUnK5li5tB5dlqPJEKo)

**Prevention:** Always select "Custom distribution" immediately after creating your custom app. See [Shopify App Setup - Step 5](/ecom-platforms/shopify/shopify-app-setup#step-5-select-custom-distribution).

</details>

<details>

<summary>Merchant Clicked Violet Connect Before Installing App</summary>

**Problem**: Merchant clicked the Violet Connect link but sees an error because the app isn't installed.

**Cause**: The merchant needs to install the custom app via the Shopify Install Link BEFORE using Violet Connect.

**Solution:**

1. Ask the merchant to close the Violet Connect page
2. Send them the **Shopify Install Link** (Channel Dashboard → Pre-Registered → Actions → Copy Shopify Install Link)
3. Have them click the Install Link and complete app installation in Shopify admin
4. After installation is confirmed, send them the Violet Connect link again
5. They should now be able to complete onboarding successfully

**Prevention:** Always send the Shopify Install Link first and confirm the merchant has installed the app before sending the Violet Connect link.

</details>

<details>

<summary>Wrong Store URL</summary>

**Problem**: Merchant reports the Violet Connect link shows the wrong store name/URL.

**Cause**: Store URL was entered incorrectly during pre-registration.

**Solution**:

1. Delete the incorrect pre-registration (Actions menu → Delete)
2. Create a new pre-registration with the correct store URL
3. Copy and send the new Violet Connect link to merchant

</details>

<details>

<summary>Permission Errors - Features Don't Work</summary>

**Problem**: Merchant completes installation but features don't work (products missing, shipping rates not calculating, etc.)

**Cause**: Missing API scopes in the custom app configuration.

**Solution**:

1. Go to [Shopify Partner Dashboard](https://partners.shopify.com) → **App Distribution**
2. Navigate to your Custom App → select **View on Dev Dashboard** (far right link)
3. Check Configuration tab → Admin API access scopes
4. Add missing scopes from [Prerequisites](/ecom-platforms/shopify/prerequisites) section
5. Update pre-registration: Actions menu → Edit
6. Have merchant use new link and reinstall

</details>

<details>

<summary>Missing Credentials from Shopify Partner Dashboard</summary>

**Problem**: Can't pre-register merchant because you don't have credentials.

**Cause**: Haven't completed prerequisites in Shopify Partner Dashboard.

**Solution**:

1. Review the [Prerequisites](/ecom-platforms/shopify/prerequisites) section
2. Log in to [Shopify Partner Dashboard](https://partners.shopify.com)
3. Create custom app for this merchant
4. Configure required API scopes
5. Generate and copy credentials
6. Return to Channel Dashboard to pre-register

</details>

<details>

<summary>Merchant Already Connected</summary>

**Problem**: Merchant tries to connect but sees "store already connected" error.

**Cause**: This store is already connected to your channel (check "Connected Merchants" tab).

**Solution**:

* If merchant needs a fresh connection, delete the existing connection first
* Create a new pre-registration
* Send new link to merchant

</details>

***

## Frequently Asked Questions

### Migration & Timeline

<details>

<summary>Do we need to migrate all existing custom apps immediately?</summary>

**No.** Existing merchant-created custom apps continue working indefinitely. Only migrate when you need to:

* Change permissions
* Rotate credentials
* Set up a new merchant

</details>

<details>

<summary>Can merchants still access their existing custom apps?</summary>

**Yes.** They can view them in Settings > Apps and sales channels, and they can uninstall them if needed. They just can't create new ones after January 1, 2026.

</details>

<details>

<summary>What happens to my old Shopify integrations?</summary>

**Old integrations**: Merchants connected before January 2026 will continue to work as-is. No changes needed for existing merchants.

**New onboarding**: All new merchants must follow the pre-registration process in this guide.

</details>

<details>

<summary>Why did Shopify require this change?</summary>

Shopify deprecated the previous channel-controlled custom app model to give merchants better security and control. With single-merchant custom apps:

* Each merchant owns their app and credentials
* Merchants can revoke access at any time
* Merchants have full visibility into API permissions
* Better audit trail for data access
* Merchants have full control over their integrations

</details>

### Permissions & Scopes

<details>

<summary>What if a merchant needs additional permissions?</summary>

You must create a new single-merchant app with the expanded permissions and send them a new installation link. The old app will continue working until they're ready to switch.

Permission changes require:

1. Update the custom app in Shopify Partner Dashboard to include additional scopes
2. Create a new pre-registration with the updated credentials
3. Have merchant reinstall using the new link

</details>

<details>

<summary>Do we need to update our API version?</summary>

Not necessarily. Single-merchant apps work with any stable API version. However, it's good practice to use recent versions (2025-10 or later).

</details>

### App Management

<details>

<summary>Can one single-merchant app be installed on multiple stores?</summary>

**No.** Each single-merchant app is designed for exactly one merchant. You need to create separate apps for each merchant, even if they're owned by the same company.

</details>

<details>

<summary>How do we handle merchants who create new stores after January 1, 2026?</summary>

You'll need to create a new single-merchant app and send them the installation link for each new store.

</details>

<details>

<summary>Can we automate app creation via API?</summary>

Shopify doesn't currently provide an API to create single-merchant apps programmatically. You must create them through the Partner dashboard. Violet will proactively notify you if this changes.

</details>

<details>

<summary>What if we have hundreds of merchants?</summary>

This is time-intensive but manageable:

* Create apps in batches
* Prioritize based on need
* Remember that existing apps don't require immediate migration
* Establish a process for creating new apps efficiently

</details>

### Credentials & Security

<details>

<summary>I lost my Client Secret or forgot to copy it before navigating away</summary>

The Client Secret appears only once in Shopify. If you didn't copy it, you'll need to regenerate it:

1. Go to [Shopify Partner Dashboard](https://partners.shopify.com) → **App Distribution**
2. Navigate to your Custom App → select **View on Dev Dashboard** (far right link)
3. Navigate to the **API credentials** section
4. Find the Client Secret field and click **Rotate**

![Shopify App Credentials](/files/nBNjHO9OxOHHJdkvdvDq)

4. Copy the new Client Secret immediately
5. Return to Violet Channel Dashboard
6. Edit the pre-registration for this merchant (Actions menu → Edit)
7. Update the **Client Secret** field with the new value
8. Save the pre-registration
9. If the merchant already started installation with the old credentials, send them the updated installation link

</details>

<details>

<summary>What happens to our existing API credentials?</summary>

They continue working unchanged. The access tokens from merchant-created custom apps remain valid.

</details>

### Pre-Registration

<details>

<summary>Can I edit a pre-registration after creating it?</summary>

Yes. Use the **Edit** action in the Pre-Registered tab to update:

* Merchant Name
* Store URL
* Client ID
* Client Secret

**Important**: If a merchant has already started installation, editing credentials will require them to reinstall with updated credentials.

</details>

<details>

<summary>How do I know when a merchant has completed installation?</summary>

The merchant automatically moves from the "Pre-Registered" tab to the "Connected Merchants" tab. You'll see them appear in your Connected Merchants list, and their status will change from "Pending" to "Active".

</details>

<details>

<summary>Can I pre-register the same merchant multiple times?</summary>

No. Each store URL can only have one active pre-registration. If you need to create a new pre-registration:

1. Delete the existing one (Actions menu → Delete)
2. Create a new pre-registration with the updated credentials
3. Send new installation link

</details>

<details>

<summary>What is the Install Link and where do I find it?</summary>

The **Install Link** is a Shopify-generated URL that allows merchants to install your custom app directly in their Shopify admin.

**Format:** `https://admin.shopify.com/store/{store}/oauth/install_custom_app?client_id=...`

**Where to find it:**

1. Go to [Shopify Partner Dashboard](https://partners.shopify.com)
2. Navigate to **App Distribution** → Select your custom app
3. Click on the **Distribution** section
4. If you haven't selected a distribution method, click "Select distribution method" and choose "Custom distribution"
5. The Install Link appears on the Distribution page with a Copy button

**When you need it:** The Install Link is required when creating a pre-registration in Violet Channel Dashboard. It's also what you send to merchants FIRST, before the Violet Connect link.

![Copy Custom Install Link](/files/rwulG4QhTaMV2X7nMyNI)

</details>

<details>

<summary>Why do merchants need to install the app before using Violet Connect?</summary>

The two-step process (Install Link, then Violet Connect) is required because:

1. **Shopify requirement**: Custom apps must be installed in the merchant's Shopify admin before OAuth can complete
2. **App authorization**: The Install Link triggers Shopify's app installation flow, which grants the necessary permissions
3. **OAuth handshake**: Violet Connect then completes the OAuth process using the pre-registered credentials

**The correct order is:**

1. Channel sends Shopify Install Link to merchant
2. Merchant installs app in Shopify admin
3. Channel sends Violet Connect link to merchant
4. Merchant completes Violet onboarding

Skipping step 2 will cause errors during Violet Connect onboarding.

</details>

### Global-E

<details>

<summary>Can Violet create orders for merchants who use Global-E?</summary>

**Yes, but with limitations.** Violet can create orders for domestic markets (e.g., US-to-US) without any issues. However, for international markets managed by Global-E, orders created through Violet bypass Global-E's checkout entirely. This means Global-E will not act as the Merchant of Record, and no duties, taxes, or landed costs will be calculated by Global-E for those orders. See the [Global-E x Shopify](/ecom-platforms/shopify/global-e) page for full details.

</details>

<details>

<summary>Why can't Violet route orders through Global-E's checkout?</summary>

Global-E's checkout is rendered inside an iFrame on the merchant's storefront and is not accessible via a standalone API. Duty/tax calculations, payment processing, and Merchant of Record coverage are all tightly coupled to that checkout session. There is no API endpoint to calculate duties independently or to retroactively assign MoR coverage to an order created outside of Global-E's flow.

</details>

<details>

<summary>What should a merchant do if they use Global-E and want to connect with Violet?</summary>

The merchant should notify their channel partner during onboarding that they use Global-E for international orders. The channel partner can then configure the integration so that Violet only creates orders in markets where Global-E is not the Merchant of Record, avoiding unintentional tax compliance gaps.

</details>

<details>

<summary>Will international orders created by Violet appear in Global-E's reporting?</summary>

**No.** Orders created by Violet go directly through the Shopify API and are invisible to Global-E. They will not receive a `GEOrderId`, will not appear in Global-E's settlement reports, and will not be covered by Global-E's financial reconciliation.

</details>

<details>

<summary>Is the merchant liable for taxes on international orders placed through Violet that bypass Global-E?</summary>

**Yes.** When an order bypasses Global-E, the merchant — not Global-E — is the legal seller. The merchant assumes responsibility for VAT/GST obligations, customs compliance, and duties in the destination country. Merchants should consult their tax and legal advisors before enabling international markets for Violet orders outside of Global-E's coverage.

</details>

## Costs & Billing

<details>

<summary>Are there any cost changes?</summary>

Single-merchant apps (custom apps) remain free. There's no cost difference between old and new custom apps.

</details>

***

### Installation Flow Diagram

```mermaid
graph TD
    A[Shopify Requires Change] --> B[Access Shopify Partner Dashboard]
    B --> C[Create Custom App for Each Merchant]
    C --> D[Configure Required API Scopes]
    D --> E[Select Custom Distribution]
    E --> F[Copy Install Link]
    F --> G[Copy Credentials<br/>Client ID & Secret]
    G --> H[Pre-register Merchant<br/>in Channel Dashboard]
    H --> I[Send Install Link<br/>to Merchant]
    I --> J[Merchant Installs App<br/>in Shopify Admin]
    J --> K[Send Violet Connect Link<br/>to Merchant]
    K --> L[Merchant Authenticates<br/>with Violet]
    L --> M[Pre-filled Store Details<br/>Displayed]
    M --> N[Merchant Clicks<br/>Connect to Shopify]
    N --> O[Violet Completes<br/>OAuth Handshake]
    O --> P[Merchant moves to<br/>Connected Merchants Tab]
    P --> Q[✓ Onboarding Complete]
```

***

### Additional Resources

#### Official Shopify Documentation

* [Partner Dashboard](https://partners.shopify.com/)
* [Custom Apps Guide](https://shopify.dev/docs/apps/build/authentication-authorization)
* [OAuth Documentation](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/authorization-code-grant)
* [API Scopes Reference](https://shopify.dev/docs/api/usage/access-scopes)

#### Violet Documentation

* [Violet Connect Overview](/prism/violet-connect)
* [Platform Integration Guides](/ecom-platforms/ecom-platforms)


# BigCommerce

Overview of Violet's BigCommerce integration for channel developers

BigCommerce is an enterprise-focused ecommerce platform with a comprehensive REST API and advanced webhook support. Merchants connect to Violet by providing API credentials either through an OAuth app flow or directly via Store Level API credentials.

## Connection

BigCommerce supports two connection paths:

**OAuth (Recommended)** — Merchants authorize through the BigCommerce App Marketplace. Violet receives a token exchange with `client_id`, `access_token`, and `store_hash` automatically.

**Store Level API** — Merchants generate credentials directly in their BigCommerce store admin and provide them manually. This requires the store URL (e.g. `https://store-{hash}.mybigcommerce.com`), Client ID, Client Secret, and Access Token.

### Required API Scopes

When connecting via Store Level API, Violet validates that all of the following scopes are present:

| Scope                            | Access Level                  |
| -------------------------------- | ----------------------------- |
| `store_v2_default`               | Default store access          |
| `store_v2_customers`             | Customers (modify)            |
| `store_cart`                     | Carts (modify)                |
| `store_v2_orders`                | Orders (modify)               |
| `store_v2_information_read_only` | Store information (read-only) |
| `store_checkout`                 | Checkout (modify)             |
| `store_v2_products_read_only`    | Products (read-only)          |

Violet will return an error listing any missing scopes during the connection attempt.

## Webhooks

Webhooks are registered automatically when a merchant connects. Violet listens for order and product lifecycle events. Webhook signatures are validated on all inbound requests.

## Notable Behavior

* **Coupon codes**: BigCommerce supports coupon codes natively. Use `Coupon Codes` (not `Promotions`) when creating discount codes for use with Violet-submitted orders.
* **Refunds**: Refunds submitted through Violet may appear as "offline" in BigCommerce — this is expected behavior.
* **Rate limits**: BigCommerce enforces rate limits of approximately 450 requests per 30 seconds. Violet handles retries with exponential backoff.
* **Product variants**: BigCommerce uses a named option/value system for variants. Violet maps these to its unified variant model automatically.


# WooCommerce

Overview of Violet's WooCommerce integration for channel developers

WooCommerce is a WordPress-based ecommerce plugin used by millions of online stores. Merchants connect to Violet using REST API keys generated from their WordPress admin.

## Connection

Merchants provide a **Consumer Key**, **Consumer Secret**, and their **Store URL**. These are generated in the WooCommerce admin under **WooCommerce → Settings → Advanced → REST API**.

### Permalink Requirement

WooCommerce's REST API requires the **Post name** permalink structure to function correctly. Merchants using the default WordPress permalink structure (`/?p=123`) will encounter 404 errors. Merchants should confirm this setting under **Settings → Permalinks** in WordPress.

## Webhooks

Webhooks are registered and managed automatically by Violet. The following topics are used:

| Topic             | Purpose                             |
| ----------------- | ----------------------------------- |
| `product.created` | New product published               |
| `product.updated` | Product changes synced              |
| `product.deleted` | Product removed from catalog        |
| `order.updated`   | Order status or fulfillment updated |
| `order.deleted`   | Order removed                       |

Webhooks are named using the pattern `violet_{topic}_{environment}` to distinguish Violet's webhooks from others and to avoid accidental deletion.

## Notable Behavior

* **Product types**: WooCommerce has `simple`, `variable`, `grouped`, `external`, `virtual`, and `downloadable` product types. Violet syncs `simple` and `variable` products. Variable products use WooCommerce's variation system, which Violet maps to its unified variant model.
* **Discount codes**: WooCommerce coupon codes are supported. Violet distributes discount amounts at the line-item level and creates a coupon line in the submitted order.
* **Tax**: WooCommerce's tax configuration can be complex. Tax calculation behavior depends on the merchant's store settings.


# Magento

Overview of Violet's Magento (Adobe Commerce) integration for channel developers

Magento (now Adobe Commerce) is an open-source ecommerce platform for mid-market and enterprise merchants. Violet supports Magento 2.x via its REST API, with enhanced functionality available through an optional Violet Magento extension.

## Connection

Merchants provide an **API Token**, **API Secret**, and their **Store URL**.

### Violet Extension (Recommended)

The Violet Magento extension unlocks additional capabilities and is recommended for most merchants. When the extension is installed, Violet can:

* Access store admin contact information
* Receive real-time webhook notifications for product and order changes
* Sync Violet's internal token directly to the merchant's store

Without the extension, Violet operates in **API-only mode**, which provides full order submission and product sync but relies on scheduled sync jobs rather than real-time events.

The extension is installed via **Composer 2+** and requires Magento 2.4.x.

### Bearer Tokens (Magento 2.4.4+)

Magento 2.4.4 and newer may require **standalone Bearer tokens** to be enabled. Merchants should verify this setting if they encounter authentication errors after providing valid credentials.

## Notable Behavior

* **Multi-store**: Magento supports complex multi-store and multi-website configurations. Violet connects to the default store view unless merchant configuration specifies otherwise.
* **No native scopes**: Unlike other platforms, Magento does not have granular API access scopes. Valid credentials provide full API access.


# Salesforce Commerce Cloud

Overview of Violet's Salesforce Commerce Cloud (SFCC) integration for channel developers

Salesforce Commerce Cloud (SFCC), formerly known as Demandware, is an enterprise ecommerce platform. SFCC uses the Open Commerce API (OCAPI) for backend integrations. This is one of the more involved platform setups due to SFCC's access control model.

## Connection

SFCC credentials are passed as a JSON blob containing the following fields:

| Field                   | Description                                         |
| ----------------------- | --------------------------------------------------- |
| `ocapi_client_id`       | OCAPI client ID configured in Business Manager      |
| `ocapi_client_password` | OCAPI client password                               |
| `access_key`            | Business Manager access key for the connecting user |
| `username`              | Business Manager username (email)                   |
| `site_id`               | The SFCC site ID to connect (e.g. `RefArch`)        |

The store URL is also required.

## Required OCAPI Permissions

Violet validates OCAPI permissions during authentication. Both **Shop API** and **Data API** resource access must be configured in Business Manager for the provided client ID. Violet checks for a defined set of required resources across both API types and returns a detailed error listing any missing scopes if they are not present.

To simplify setup, merchants can grant wildcard (`/**`) access to the client ID rather than configuring individual resource paths.

## Merchant Setup Requirements

* **Customer Group**: The SFCC site must have a customer group named `VIOLET_API`. Violet-submitted orders are placed under this customer group.
* **Payment Method**: A payment method must be configured on the site that Violet can reference when submitting orders.

## Webhooks

SFCC does not support traditional real-time webhooks for the OCAPI integration. Product and order data is synchronized via scheduled sync jobs rather than push notifications.

## Notable Behavior

* **Order management**: SFCC order management is handled separately from the core OCAPI integration. If merchants use a standalone Order Management System (OMS) alongside SFCC, additional configuration may be required.
* **Locales and sites**: SFCC supports complex multi-locale and multi-site configurations. Violet connects to the site specified in the `site_id` credential field.


# CommerceTools

Overview of Violet's commercetools integration for channel developers


# Centra

Overview of Violet's Centra integration for channel developers

Centra is a fashion and lifestyle-focused ecommerce platform built for mid-market to enterprise brands. It provides two separate APIs: a GraphQL Integration API for backend operations, and a REST Checkout API for cart and checkout flows.

## Connection

Merchants provide a **Store URL** and an **Integration API Token**. Optionally, a **Checkout API Shared Secret** can also be provided to enable real-time cart calculation.

| Credential                 | API                     | Description                                    |
| -------------------------- | ----------------------- | ---------------------------------------------- |
| Store URL                  | Both                    | Base URL of the Centra store                   |
| Integration API Token      | GraphQL Integration API | Bearer token for product/order operations      |
| Checkout API Shared Secret | Checkout API (optional) | Enables real-time shipping and tax calculation |

The Integration API token is a long-lived bearer token configured in the Centra admin.

## Webhooks

Centra does not expose a programmatic API for webhook registration. Webhooks must be configured manually in the Centra admin under the **Webhook plugin**, pointing each event type to the Violet webhook gateway.

Centra webhooks send arrays of entity IDs rather than full payloads. Violet fetches the full data for each ID via the Integration API upon receiving a notification.

Inbound webhook signatures use the format `X-Centra-Signature: t={timestamp},v1={hmac}`. If provided, the signature is verified using the optional webhook endpoint secret.

## Cart Calculation

When the Checkout API shared secret is provided, Violet uses Centra's Checkout API for real-time cart calculation. This enables accurate shipping rates and tax estimates before order submission. When the shared secret is not provided, Violet falls back to local calculation (taxes will be set to 0 and calculated at order time).

## Notable Behavior

* **Three-tier product structure**: Centra uses a Product → ProductVariant → ProductSize hierarchy. Violet maps ProductSizes as purchasable SKUs, with ProductVariant names (e.g. color) and ProductSize names (e.g. S/M/L) as variant dimensions.
* **Pricelist-based pricing**: Prices in Centra are linked to pricelists, which are associated with markets and currencies. Contextual pricing is supported.
* **Rate limiting**: Centra enforces limits on both request count and GraphQL query complexity. Violet handles 429 responses with retry logic.
* **Voucher codes**: Centra supports voucher codes on orders. Violet passes the discount code when submitting an order and validates whether it was applied based on the order response.
* **Wholesale and DTC**: Centra supports both direct-to-consumer and wholesale business models.


# PrestaShop

Overview of Violet's PrestaShop integration for channel developers

PrestaShop is an open-source ecommerce platform widely used in Europe. Violet integrates via PrestaShop's built-in web service API, with enhanced functionality available through the Violet PrestaShop extension.

## Connection

Merchants provide an **API Key** and their **Store URL**. The API key is generated in the PrestaShop admin under **Advanced Parameters → Webservice**.

### Violet Extension (Required for Full Functionality)

The Violet PrestaShop extension must be installed for the integration to function correctly. The extension enables real-time webhook notifications and provides additional endpoints for order management. Without it, Violet will return an error during authentication.

The extension is compatible with PrestaShop **1.7 and above**.

### API Key Permissions

The API key used for the integration requires access to the following PrestaShop resources:

* Orders (read/write)
* Products (read)
* Customers (read/write)
* Configurations (read)
* Currencies (read)
* Shops and Shop URLs (read)

Violet validates API access during authentication and will return an error if required permissions are missing.

## Notable Behavior

* **Store URL**: The store URL must include the full base URL with `https://` prefix.
* **Multi-store**: PrestaShop supports multi-store configurations. Violet connects to the primary shop by default.
* **Currency**: Currency is read from the store's configured default currency during connection.


# Ecwid

Overview of Violet's Ecwid (Lightspeed eCom) integration for channel developers

Ecwid (now part of Lightspeed) is a hosted ecommerce platform that can be embedded into existing websites. Violet integrates via Ecwid's REST API using OAuth-based authentication.

## Connection

Ecwid uses an OAuth app flow. The merchant authorizes Violet's app installation, and Violet receives an access token along with the merchant's Store ID. Merchants must be on the **Venture plan or higher** for API access.

### Required OAuth Scopes

The following scopes are required for the Violet integration to function:

| Scope                   | Purpose                     |
| ----------------------- | --------------------------- |
| `read_store_profile`    | Access store configuration  |
| `read_catalog`          | Sync product catalog        |
| `read_orders`           | Read order data             |
| `update_orders`         | Update order status         |
| `create_orders`         | Submit new orders           |
| `create_customers`      | Create customer records     |
| `read_customers`        | Read customer data          |
| `read_discount_coupons` | Access coupon/discount data |

Violet validates that all required scopes are granted during authentication.

## Webhooks

Webhooks are registered automatically via the Ecwid API when a merchant connects. Violet listens for product and order events to keep the catalog and order status in sync.

## Notable Behavior

* **Plan requirement**: The Ecwid Venture plan or higher is required for REST API access. Merchants on the Free or Venture plan may have limited API capabilities.
* **Discount codes**: Ecwid coupon/discount codes are supported for order submission.
* **Store URL**: The store's canonical URL is retrieved from the merchant's Ecwid profile during connection.


# Wix

Overview of Violet's Wix integration for channel developers

Wix is a website builder and ecommerce platform used by millions of businesses. Violet integrates via the Wix API using an API key generated in the Wix dashboard.

## Connection

Merchants provide a **Wix API Key** and their **Site ID**. API keys are generated in the Wix dashboard under **Settings → Advanced → API Keys**.

### Required Permissions

The API key must have the following permissions enabled:

| Permission      | Purpose                             |
| --------------- | ----------------------------------- |
| `manage_orders` | Read and update orders              |
| `read_store`    | Access store configuration and info |
| `read_products` | Read product catalog                |

Violet validates all three permissions during the connection attempt by making test API calls to each endpoint. Any permission that returns an authorization error will be reported as a missing scope.

## Webhooks

Webhooks for Wix merchants are registered via the Wix API after a successful connection. Violet receives events for product and order changes.

## Notable Behavior

* **Shipping methods**: Wix does not expose a dedicated API endpoint for retrieving configured shipping methods. Violet assumes shipping methods are configured and proceeds accordingly.
* **OAuth**: The Wix integration currently uses API key authentication rather than a full OAuth flow. Merchants generate keys directly in their dashboard and provide them during onboarding.
* **Site-based access**: Each Wix API key is scoped to a specific site. Merchants with multiple Wix sites will need separate connections for each.


# Squarespace

Overview of Violet's Squarespace integration for channel developers

Squarespace is a website builder and ecommerce platform known for its design-focused templates. Violet integrates via the Squarespace Commerce API.

## Connection

Merchants provide a **Commerce API Key** generated in their Squarespace account. This is created under **Settings → Advanced → Developer API Keys**.

## Webhooks

Squarespace webhooks are registered automatically after a merchant connects. Violet listens for product and order events.

## Notable Behavior

* **Currency objects**: The Squarespace Commerce API represents all monetary values as objects containing a `value` and `currency` code. Violet handles this currency object format natively — no additional configuration is required.
* **Discount codes**: Squarespace supports discount codes for Violet-submitted orders. Custom (fixed and percentage) discounts are also supported.
* **POS integration**: Squarespace has a point-of-sale (POS) product. Orders submitted through Violet are tagged as online orders and handled through the online order flow.
* **Tax**: Squarespace supports both tax-inclusive and tax-exclusive pricing. The interpretation is reflected in the order details returned after submission.
* **Inventory**: Squarespace tracks inventory at the variant level. Violet syncs stock quantities from the platform during catalog synchronization.


# Swell

Overview of Violet's Swell integration for channel developers

Swell is a headless ecommerce backend designed for modern storefronts. Violet integrates via Swell's API using a store secret key.

## Connection

Merchants provide a **Secret Key** and their **Store ID**. The secret key is generated in the Swell dashboard under **Developer → API Keys**. The store ID is the subdomain used to access the store (e.g. `my-store` from `my-store.swell.store`).

## Webhooks

Swell webhooks are registered automatically when a merchant connects. Violet listens for product and order lifecycle events.

## Notable Behavior

* **Headless-first**: Swell is designed as a headless backend, meaning the merchant may not have a traditional storefront URL. The store URL is derived from the store ID during connection.
* **Inventory**: Swell tracks inventory at the variant level. Stock quantities are synced during catalog synchronization.


# Spree Commerce

Overview of Violet's Spree Commerce integration for channel developers

Spree Commerce is an open-source Ruby on Rails ecommerce framework with a JSON:API-style REST API. Violet integrates using OAuth2 client credentials.

## Connection

Merchants provide a **Client ID** and **Client Secret** from an OAuth application configured in their Spree store. The OAuth application must be created with the `admin write` scope.

Merchants also provide their **Store URL** — the base URL of their Spree instance.

## Webhooks

Webhooks are registered automatically via the Spree API after a merchant connects. Violet listens for order and product lifecycle events. All Violet-originated orders are tagged with `channel = "Violet"` so that event processing can correctly identify Violet-placed orders.

## API Format

Spree responses follow JSON:API conventions, using `included` arrays for related resources. Violet handles this format transparently.

## Notable Behavior

* **Discounts**: Discount codes are not supported for Violet-submitted orders on Spree. Custom discount amounts are also not supported at this time.
* **Checkout flow**: Spree uses an explicit multi-step checkout flow. Violet manages this flow internally during order submission.
* **Product data**: Spree uses `taxons` for product categorization.

***

> **Looking for Vendo?** [Vendo](/ecom-platforms/vendo) is a hosted variant of Spree with a near-identical integration. See the Vendo page for any differences.


# Vendo

Overview of Violet's Vendo integration for channel developers

Vendo is a hosted, multi-vendor ecommerce platform built on top of Spree Commerce. Because Vendo is a managed Spree variant, the connection process and integration behavior are nearly identical to Spree with a few minor differences.

## Connection

Merchants provide a **Client ID** and **Client Secret** from an OAuth application, along with their **Store URL**. The OAuth application must be created with the `admin write` scope — the same requirement as Spree.

## Differences from Spree

| Feature                | Spree                              | Vendo                  |
| ---------------------- | ---------------------------------- | ---------------------- |
| Product categorization | `taxons`                           | `categories`           |
| Checkout flow          | Requires explicit step advancement | Advances automatically |

## Webhooks

Webhook behavior is the same as Spree — webhooks are registered automatically. Violet-originated orders are tagged with `channel = "Violet"`.

## Notable Behavior

All other behavior (discount support, API format, order submission flow) is the same as [Spree](/ecom-platforms/spree).


# Miva Merchant

Overview of Violet's Miva Merchant integration for channel developers

Miva Merchant is a mid-market to enterprise ecommerce platform with a single-endpoint JSON API. All API calls are authenticated using HMAC-SHA256 request signing.

## Connection

Merchants provide the following credentials:

| Field           | Description                                                 |
| --------------- | ----------------------------------------------------------- |
| **API Token**   | The API access token from the Miva admin                    |
| **Signing Key** | Base64-encoded HMAC-SHA256 signing key                      |
| **Store Code**  | The Miva store code (not the URL)                           |
| **Store URL**   | The API endpoint URL (e.g. `https://store.example.com/mm5`) |

All credentials are available in the Miva admin under **User Management** (for the API token and signing key).

## Webhooks / Notifications

Miva does not expose an API for programmatic webhook registration. Merchants must configure notifications manually in the Miva admin under **Utilities → Notifications**, pointing each topic to the Violet webhook gateway URL.

Violet receives the following notification types:

* `product.*` — triggers a product sync
* `order.*` — triggers an order sync

Inbound notifications are verified using HMAC-SHA256 with the merchant's signing key.

## Notable Behavior

* **Single endpoint**: All Miva API calls are POSTed to a single endpoint (`/json.mvc`), differentiated by a `Function` parameter. Violet handles this internally.
* **Product enrichment**: Miva requires separate API calls to fetch product images, attributes, and variants. Violet makes these calls in parallel to minimize latency during catalog sync.
* **Currency**: The Miva API returns a numeric currency ID rather than an ISO currency code. Currency must be configured on the merchant record separately — it cannot be auto-detected from the platform.
* **Order cancellation**: Miva does not provide an API for canceling orders. Cancellations must be handled through the Miva admin panel.
* **Price format**: Miva uses decimal dollar values (e.g. `19.99`), not integer cents.


# Shoprenter

Overview of Violet's Shoprenter integration for channel developers

Shoprenter is a hosted ecommerce platform popular in Central and Eastern Europe, particularly in Hungary. Violet integrates via Shoprenter's REST API using API credentials.

## Connection

Merchants provide a **Username**, **Password**, and their **Store URL**.

API credentials are generated in the Shoprenter admin dashboard.

## Notable Behavior

* **Regional focus**: Shoprenter is primarily used by merchants in Hungary and the surrounding region. Store URLs typically follow a `{storename}.shoprenter.hu` pattern, though custom domains are supported.
* **Product catalog**: Violet syncs products and variants from Shoprenter during catalog synchronization.


# SAP Commerce Cloud

Overview of Violet's SAP Commerce Cloud integration for channel developers

SAP Commerce Cloud (formerly Hybris) exposes its storefront API through the **OCC v2** (Omni-Commerce Connect) REST layer. Violet integrates using OAuth2 client credentials against this API.

## Connection

Merchants provide the following credentials:

| Field                             | Description                                                                        |
| --------------------------------- | ---------------------------------------------------------------------------------- |
| **Store URL**                     | OCC base URL (e.g. `https://api.merchant.com/occ/v2`)                              |
| **Client ID**                     | OAuth2 client ID                                                                   |
| **Client Secret**                 | OAuth2 client secret                                                               |
| **Base Site ID**                  | The OCC site ID (e.g. `electronics`, `apparel-uk`)                                 |
| **Service User UID** *(optional)* | A user UID scoped to order history access; falls back to `current` if not provided |

There is no OAuth user-consent flow. Onboarding is credential-based.

### Token Management

Violet mints OAuth tokens internally via the client credentials grant against `${baseUrl}/authorizationserver/oauth/token`. Tokens are cached and refreshed approximately 30 seconds before expiry. A 401 on any call invalidates the cached token and triggers a retry.

## Webhooks

SAP Commerce Cloud OCC v2 does not push native webhooks by default. Violet attempts to register webhooks via the optional **SAP Webhook Services** extension (`webhookconfigurations` endpoint). If the extension is not installed, Violet logs a degraded-mode message and operators must configure outbound webhooks manually via BackOffice, pointing them at the Violet webhook ingress endpoint.

Inbound webhook signatures use HMAC-SHA256 over the raw request body. The signature is passed in the `X-Sap-Cc-Webhook-Signature` header as a base64-encoded digest.

## Discounts

Both custom (fixed/percentage) and synced promo codes are supported:

* **Custom discounts**: applied before cart creation; the bag total is decremented directly.
* **Discount codes**: forwarded to the OCC `vouchers` endpoint during cart processing. After order placement, Violet validates whether the code was applied from the `appliedVouchers` response and marks the discount accordingly.

## Notable Behavior

* **Cart-based order submission**: Order submission follows the full OCC cart pipeline — create cart, add items, set addresses, set delivery mode, apply payment, apply vouchers, then place order.
* **Delivery mode selection**: Violet matches the requested shipping method to an available OCC delivery mode by code, then by name. If no match is found, the first available mode is used.
* **Payment**: OCC's payment model was designed for shopper-side card capture. Violet forwards the gateway transaction ID as a `subscriptionId`. Merchants whose storefronts require full PCI capture inside SAP Commerce Cloud must handle that separately before using Violet's Direct Order Submission.
* **Customer listing**: Standard OCC v2 does not expose a bulk customer listing endpoint. Customer sync is driven from order history rather than a direct customer list.
* **Service user UID**: The `fetchOrders` endpoint requires a user-scoped token. If using client-credentials only, provide a service user UID in the optional credential field. The literal `current` value only resolves under user-bearer grants, not client credentials.
* **Collections**: Category hierarchy and media are not synced — only name, handle, and status.


# Oracle Commerce Cloud

Overview of Violet's Oracle Commerce Cloud integration for channel developers

Oracle Commerce Cloud (OCC) is an enterprise ecommerce platform. Violet integrates using an application key registered in the OCC admin, which is exchanged for a short-lived access token via the OCC admin API.

## Connection

Merchants provide two credentials:

| Field               | Description                                                          |
| ------------------- | -------------------------------------------------------------------- |
| **Store URL**       | OCC instance hostname (e.g. `mystore.oracle.com`)                    |
| **Application Key** | JWT generated when the integration is registered in the OCC admin UI |

The application key is created in the OCC admin under the integrations or third-party applications section. Violet authenticates server-to-server via `/ccadmin/v1/login` using the application key as a bearer token with a `grant_type=client_credentials` body.

> **Note**: Username/password authentication (`/ccadmin/v1/mfalogin`) is reserved for internal admin users and is not used by Violet.

### Scope Validation

OCC permissions are determined by the application's assigned role at registration time, not per-call requested scopes. Violet validates credentials by performing a test authentication during connection — a successful token exchange confirms the key is valid and active.

## Webhooks

OCC ships a fixed catalog of webhook slots. Violet registers the following slots automatically after a merchant connects:

| Slot ID           | Event                |
| ----------------- | -------------------- |
| `order-submit`    | New order placed     |
| `order-update`    | Order status changed |
| `shipment-create` | Shipment created     |
| `shipment-update` | Shipment updated     |

Registration is performed via `PUT /ccadmin/v1/webhooks/{slotId}`. Failures on individual slots are logged but do not abort overall registration.

## Notable Behavior

* **Application key**: The application key is a JWT, not a username/password pair. It is generated once in the OCC admin when an integration is registered and does not expire on its own (expiry is determined by the application's configuration in OCC).
* **Token refresh**: Violet does not use OAuth refresh tokens for this platform. Each request exchanges the application key for a short-lived access token as needed.
* **Shipping methods**: Violet verifies that shipping methods are configured on the store during connection by querying the OCC shipping methods endpoint.


# Rithum

Overview of Violet's Rithum integration for channel developers

Rithum (formerly CommerceHub) is a B2B marketplace and drop-shipping platform that connects suppliers with retailers. Unlike direct-to-consumer storefronts, Rithum operates as a fulfillment network — merchants are suppliers who fulfill orders placed through retail channel partners.

> **Partner requirement**: Rithum is a partner-gated integration. To enable Rithum for your Violet application, you must first become a registered Rithum partner. Contact Violet support to initiate the partner enablement process once your Rithum partnership is established.

## Connection

Rithum does not use a standard Violet Connect onboarding flow. There is no OAuth redirect or credential form presented to the merchant. Instead, connection and authentication are managed through the Rithum partner relationship — credentials are provisioned externally and configured at the platform level.

Merchant profiles are fetched via the Rithum site profile API once the integration is active.

## Order Status

Rithum uses a three-tier status model that maps independently to Violet's order lifecycle:

| Rithum Status Type  | Description                                             |
| ------------------- | ------------------------------------------------------- |
| **Checkout status** | Whether the order has been acknowledged by the supplier |
| **Payment status**  | Payment state of the order                              |
| **Shipping status** | Fulfillment and shipment state                          |

Violet reconciles these three status dimensions into a unified order and bag state.

## Products

Rithum supports the following product types:

| Type               | Description                                                 |
| ------------------ | ----------------------------------------------------------- |
| `VARIATION_PARENT` | Parent product grouping variants (not directly purchasable) |
| `STANDARD`         | Standard physical product                                   |
| `DIGITAL`          | Downloadable or digital product                             |
| `BUNDLE`           | Bundle of multiple products                                 |

`VARIATION_PARENT` items are treated as offer containers and are not directly purchasable — child variants are exposed as SKUs.

## Discounts

Rithum does not have a native discount or coupon code system. Discounts are applied as negative line-item values using Rithum's `additionalCostOrDiscount` field. Custom discounts (fixed or percentage) are supported; synced promo codes are not.

## Shipping

When the requested shipping method cannot be matched to an available Rithum shipping option, Violet falls back to the first available shipping method configured on the supplier's account.

## Notable Behavior

* **No standard auth flow**: Onboarding is managed through the Rithum partner relationship rather than Violet Connect.
* **Drop-shipping model**: Rithum merchants are suppliers fulfilling orders on behalf of retail partners, not direct-to-consumer storefronts.
* **Order acknowledgment**: Orders must be acknowledged by the supplier (reflected in checkout status) before fulfillment proceeds.


# Lightspeed eCom

Overview of Violet's Lightspeed eCom integration for channel developers

Lightspeed eCom (formerly SEOshop) is a cloud-based ecommerce platform for retail merchants. Violet integrates using HTTP Basic authentication with an API key and secret provided by the merchant.

## Connection

Merchants provide three credentials:

| Field          | Description                                                         |
| -------------- | ------------------------------------------------------------------- |
| **Store URL**  | Lightspeed API base URL (e.g. `https://api.shoplightspeed.com/en/`) |
| **API Key**    | Generated in the Lightspeed merchant admin                          |
| **API Secret** | Generated alongside the API key                                     |

Credentials are validated during onboarding by hitting the Lightspeed Account endpoint. There is no OAuth consent flow. Lightspeed does not have a scope model; all permissions are determined by the API key at the time it is created.

## Webhooks

Violet registers webhooks automatically after a merchant connects. The following topics are subscribed:

| Topic             | Event                  |
| ----------------- | ---------------------- |
| `product.created` | Product created        |
| `product.updated` | Product updated        |
| `product.deleted` | Product deleted        |
| `order.created`   | Order placed           |
| `order.updated`   | Order updated          |
| `order.paid`      | Order payment received |
| `order.shipped`   | Order shipped          |
| `return.created`  | Return initiated       |
| `return.updated`  | Return updated         |
| `return.deleted`  | Return deleted         |

> **Note**: Lightspeed does not sign webhook deliveries — there is no HMAC signature to verify. Authenticity is established at registration time via the credentialed merchant URL.

## Direct Order Submission

Order submission follows a multi-step checkout pipeline:

1. `POST /checkouts.json` — create checkout with customer and addresses
2. `POST /checkouts/{id}/products.json` — add each line item
3. `PUT /checkouts/{id}.json` — set shipping method
4. `PUT /checkouts/{id}.json` — set payment method (always external "Violet")
5. `GET /checkouts/{id}/validate.json` — must return `{validated: true}`
6. `POST /checkouts/{id}/order.json` — finalize and retrieve order ID
7. `PUT /orders/{id}.json` — mark payment status as paid

## Discounts

Both custom discounts and synced promo codes are supported:

* **Custom discounts** (fixed or percentage): Amount is calculated and the bag total is decremented before checkout creation.
* **Discount codes**: Passed at checkout finalization. Lightspeed does not have a dedicated discount-code endpoint — the code is included when the checkout is submitted, and Violet reads the finalized order response to determine whether the code was applied.

## Products

Lightspeed's product model separates the product container from its purchasable variants:

* **Product**: Container only — holds name, description, and media. Not directly purchasable.
* **Variant**: Holds price, inventory, and dimensions. These map to Violet SKUs.

Variant titles use a `Type:Value, Type:Value` format (e.g. `Color:Red, Size:M`), which Violet parses into individual variant dimensions.

## Pagination

Lightspeed uses `?page=N&limit=N` pagination with a hard limit of 250 results per page. Order polling uses `?updated_at_min` (ISO-8601 with `+0000` offset) to fetch only recently modified records.

## Notable Behavior

* **No scope model**: Lightspeed does not use OAuth scopes. All permissions are implicit in the API key.
* **Webhook signatures**: Inbound webhooks are not signed. Violet does not perform signature verification for this platform.
* **Shipping validation**: Violet verifies that at least one shipping method is configured on the store during connection.
* **Fulfillment status mapping**: Only `shipped` and `partially_shipped` shipment statuses are mapped to Violet's fulfillment states. Orders in `not_shipped` or `cancelled` states leave the bag's fulfillment status unset.


# 3dcart / Shift4Shop

Overview of Violet's 3dcart (Shift4Shop) integration for channel developers

3dcart, now rebranded as Shift4Shop, is a hosted ecommerce platform. Violet integrates using OAuth 2.0 — merchants authorize access via a standard redirect flow using your app's registered client credentials.

> **Taxes and shipping**: 3dcart does not support dynamic tax calculation or real-time shipping rate retrieval. Channels are responsible for calculating and displaying taxes independently. Shipping rates must be configured statically — either by the merchant or by the channel — within Violet before checkout can complete.

## Connection

3dcart uses an OAuth redirect flow. Your Violet application must have a 3dcart client ID and client secret registered with Violet. When a merchant connects, Violet redirects them to:

```
https://apirest.3dcart.com/oauth/authorize
  ?client_id={clientId}
  &redirect_uri={callbackUrl}
  &response_type=code
  &store_url={merchantStoreUrl}
```

After the merchant approves, the authorization code is exchanged for an access token and stored as the merchant's credential.

> **App credentials required**: Your Violet application must have 3dcart OAuth credentials (client ID and client secret) registered before merchants can connect. Contact Violet support to configure these.

## Webhooks

Violet registers webhooks automatically after a merchant connects. The following events are subscribed:

| Event                   | Trigger                            |
| ----------------------- | ---------------------------------- |
| `Order Status Change`   | Order status updated               |
| `Product New`           | Product created                    |
| `Product Changed`       | Product details updated            |
| `Product Stock Changed` | Product inventory quantity changed |
| `Product Deleted`       | Product removed                    |

## Order Submission

Orders are submitted directly to the 3dcart store. The flow is:

1. Look up or create the customer by email
2. Compose and submit the order via the 3dcart Orders API
3. Set the order to `New` status at creation
4. Update to `Processing` status after payment is confirmed

## Products

3dcart uses a product + options model. SKU IDs in Violet are compound identifiers that encode the product catalog ID and any selected option values using `::` and `:` separators. Violet parses these internally when composing line items.

## Notable Behavior

* **No dynamic taxes**: 3dcart does not return tax estimates at cart or checkout time. Channels must calculate and display taxes independently.
* **No dynamic shipping rates**: 3dcart does not expose a live shipping rate endpoint. Shipping rates must be configured statically within Violet by the merchant or the channel.
* **No order polling**: Fetching individual orders or paginating order history is not implemented for this platform. Order state is driven entirely by inbound webhooks.
* **App credentials required**: Unlike some platforms where merchants supply their own API keys, 3dcart requires your Violet app to have registered OAuth credentials with 3dcart before any merchant can connect.


# Shoptet

Overview of Violet's Shoptet integration for channel developers

Shoptet is a Czech ecommerce platform popular in Central and Eastern Europe. Violet supports two tiers of Shoptet merchants — **Standard** and **Premium** — and the integration capabilities differ significantly between them.

> **Tier differences**: Standard tier merchants have no API access. Their catalog is synced via a product feed and order submission is not available. Premium tier merchants connect via API and support the full Violet feature set including real-time webhooks, direct order submission, and live cart calculation. Channels must be prepared to handle both merchant types if they intend to support Shoptet broadly.

## Standard Tier

Standard tier Shoptet merchants do not have access to the Shoptet REST API. Violet connects them using a store URL and a Google Product Feed URL.

**What is supported:**

* Catalog sync via Google Product Feed (ingested at connection time and on a scheduled basis)

**What is not supported:**

* Real-time webhook events (no API, no webhooks)
* Direct order submission
* Live cart calculation or shipping rate retrieval
* Credential validation (no API to test against)

**Connection inputs required:**

| Field         | Description                                   |
| ------------- | --------------------------------------------- |
| **Store URL** | The merchant's Shoptet storefront URL         |
| **Feed URL**  | URL to the merchant's Google Product Feed XML |

The feed is registered with Violet at onboarding and catalog ingestion begins immediately.

***

## Premium Tier

Premium tier merchants have Shoptet REST API access and support the full integration. Two auth flows are available depending on how your app is configured.

### Flow A — Marketplace OAuth Addon

Used when your Violet app is registered as a Shoptet marketplace addon. The merchant installs the addon from the Shoptet app store, which initiates an OAuth authorization flow. Violet exchanges the authorization code for a long-lived OAuth access token. Short-lived API Access Tokens (\~30 minutes) are minted on demand from this long-lived token and cached internally — no manual token refresh is required.

> **App credentials required**: Your Violet app must have Shoptet OAuth credentials registered with Violet before merchants can connect via this flow. Contact Violet support to configure these.

### Flow B — Private API Token

Used when merchants connect outside the Shoptet marketplace. The merchant generates a Private API Token in their Shoptet admin panel and provides it during Violet Connect onboarding. Credentials are validated against the Shoptet eshop endpoint at connection time.

| Field                 | Description                                     |
| --------------------- | ----------------------------------------------- |
| **Store URL**         | The merchant's Shoptet storefront URL           |
| **Private API Token** | Long-lived token generated in the Shoptet admin |

***

## Webhooks (Premium only)

Violet registers webhooks automatically for Premium tier merchants. The following events are subscribed:

| Event            | Trigger              |
| ---------------- | -------------------- |
| `product:create` | Product created      |
| `product:update` | Product updated      |
| `product:delete` | Product deleted      |
| `order:create`   | Order placed         |
| `order:update`   | Order status changed |

Shoptet webhook payloads are minimal (eshop ID, event type, timestamp). Violet fetches the full resource from the API on receipt.

## Direct Order Submission (Premium only)

Orders are submitted directly to the Shoptet API. VAT rates are fetched per product variant at order time to ensure line items carry the correct tax percentage. Order cancellation resolves the merchant's configured cancellation status by name (matching keywords like `storno` or `cancel`).

**Discount codes are not supported** for order submission — Shoptet's API does not validate codes pre-order and there is no reliable post-creation correlation. Code discounts are rejected up front before payment is captured.

## Cart Calculation (Premium only)

Shoptet has no cart estimation endpoint. Violet computes cart totals locally:

* **Subtotal**: Sum of SKU prices × quantities (prices are stored gross/VAT-inclusive).
* **Tax**: Estimated by fetching the VAT rate per product variant and extracting the embedded VAT from each gross line item. If a variant lookup fails, the tax total falls back to 0 while gross totals remain intact.
* **Shipping**: Sourced from the merchant's configured fallback shipping methods in Violet, filtered by the customer's country. The live Shoptet shipping endpoint is not used because it does not return reliable per-cart pricing.
* **Discounts**: Custom (fixed/percentage) discounts are supported. Discount codes are not supported at cart calculation time.

## Products (Premium only)

* Products are identified by **GUID** (not a numeric ID). Variants also have a GUID plus a `code` field used as the SKU identifier.
* Prices are stored per-variant with an `includingVat` flag indicating whether the stored price is gross or net. Violet normalizes all prices to gross before storing in the catalog.
* Promotional pricing (`actionPrice`) is supported — Violet uses the action price as the sale price when the current date falls within the validity window.
* Images, variant parameters, and per-warehouse stock are returned only when explicitly requested via Shoptet's `include` parameter.

## Notable Behavior

* **Standard vs Premium**: Channels must expect two distinct merchant types. Standard tier merchants will have catalog data but cannot receive orders through Violet's standard checkout flow.
* **No discount codes**: Shoptet does not support discount code validation at order creation time. Synced promo codes are marked as not supported for all Shoptet merchants.
* **VAT-inclusive pricing**: Shoptet is primarily used by European merchants. All prices are treated as VAT-inclusive and tax is extracted from gross line totals rather than added on top.
* **Rate limiting**: Shoptet enforces a leaky-bucket rate limit (50 connections per IP, 3 per token) with 5-second write locks.


# Quickstart

The best way to get started with the Violet Checkout API is to work your way through the subsequent pages. You will complete each of the following:

1. Logging into the Violet API
2. Viewing Merchants connected to your app
3. Finding Products (we call them offers) and SKUs
4. Adding SKUs to a cart
5. Completing a checkout

Navigate to 'Create a Violet Application' in the left nav to get started.


# Create a Violet Application

## About Violet Applications

Violet Applications provide you with the necessary credentials and tools to invoke our APIs and build your new system. Violet applications are the entry point to any system built on Violet and manage merchants you've connected to.

You can learn more about Violet Applications here [Apps](/concepts/apps), but for now, follow the steps below to continue with this recipe and create your first Violet Application.

## Create an App

1. Sign up at [channel.violet.io/signup](https://channel.violet.io/signup) or login at [channel.violet.io/login](https://channel.violet.io/login)
2. You will be asked to Create an Org, select a slug you feel comfortable with for use across your team
3. Invite other member of your team (you can do this later, too)
4. Name your application (don't worry, you can change this later as many times as you'd like).
5. Save your App ID and App Secret, you will need them for API authentication.


# Login

This section walks you through testing the Violet APIs. Make sure you have already signed up at channel.violet.io/signup and created an application in the previous step. If you haven't, please go through Create a Violet Application.

{% hint style="info" %}
You will need your App ID and App Secret in order to complete this step.
{% endhint %}

### Login

This API tests your connection to Violet by logging into your Application. Add `X-Violet-App-Id` and `X-Violet-App-Secret` added to your headers for login. These are available from the application you created on channel.violet.io. Every request after login will require these header params for authentication, along with the `X-Violet-Token` that you get from login and refreshing your token.

{% hint style="info" %}
While your username and password will be the same across environments (test and live) as will your `X-Violet-App-Id`, this is **not** true for your `X-Violet-App-Secret`.

The `X-Violet-App-Secret` you retrieve from the Channel dashboard is *different* depending on the live/test mode toggle. You must use the correct app secret that corresponds to the environment you are trying to login to: `test` for `sandbox-api.violet.io` and `live` for `api.violet.io`.
{% endhint %}

In addition to the headers mentioned above, include your `username` (your username is the email you signed up with) and `password`. If successful, an access token will be returned in the response body for use in additional requests against the API along with information about your API.

{% hint style="warning" %}
While the User Management feature of the Dashboard allows multiple users to login and view the dashboard,\
only an App's "Owner" username and password will allow you to generate a token.\
You can view who your App's owner is on the [team view](https://channel.violet.io/settings/team)
{% endhint %}

{% openapi src="/files/Z8lTzWUZ943hinGNXfLt" path="/login" method="post" expanded="true" %}
[user-service.yaml](https://2435497985-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZrOgj5n6PuU2r0Ya8Tzl%2Fuploads%2Fgit-blob-670a4e234cc11a295d9996f677a5ab50b430eb8f%2Fuser-service.yaml?alt=media)
{% endopenapi %}

**Refresh your Token**

Use the Refresh Token to get a new token. This is an operation you will have to do on a regular basis. You can use your App Id and App Secret with a refresh token to get a new token. This saves the step of having to send your username and password each time to get a new token.


# View Merchants

Before you get to creating orders we want you to understand the concepts of Merchants, Catalogs, and Products, as well as how they work within Violet. Merchants are storefronts that have integrated themselves with Violet, allowing for their catalog of products to be available through the Violet APIs. Additionally, Merchants have given Violet the access to write, read, place orders directly with their systems; allowing Violet (and you!) to seamlessly checkout. Merchants can be public or private when integrated with Violet. Public Merchants allow any Violet customer to view their catalog while private merchants require prior authorization for your Violet application to transact with them.

Continue with this recipe to retrieve a list of test merchants, see what they look like in Violet, and learn how to use this information. In this Recipe, we are only interacting with a few of the available Merchant APIs. To learn more about Merchants in Violet and for the complete list of available APIs, please refer to our [Merchants](/prism/merchants) page.

## [View Merchants you are connected to](/prism/overview/view-merchants/get-merchants)

{% hint style="info" %}
You can get a list of all the merchants that your app has access to by using the above endpoint.
{% endhint %}

## [Get Individual Merchant Info](/prism/overview/view-merchants/get-merchant-by-id)

{% hint style="info" %}
You can use this endpoint to view detailed information about any specific merchant using their merchant ID.
{% endhint %}


# Get Merchants

What Merchants am I connected to?

You can get a list of all the merchants that your app has access to by using the following endpoint.

{% openapi src="/files/4aTPn9xdHLUUFFF1Dmrf" path="/merchants" method="get" expanded="true" %}
[merchant-service.yaml](https://2435497985-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZrOgj5n6PuU2r0Ya8Tzl%2Fuploads%2Fgit-blob-247261bff470e8e872c7a1803ef78263c444666d%2Fmerchant-service.yaml?alt=media)
{% endopenapi %}


# Get Merchant by ID

Get Individual Merchant Info

{% openapi src="/files/4aTPn9xdHLUUFFF1Dmrf" path="/merchants/{merchant\_id}" method="get" expanded="true" %}
[merchant-service.yaml](https://2435497985-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZrOgj5n6PuU2r0Ya8Tzl%2Fuploads%2Fgit-blob-247261bff470e8e872c7a1803ef78263c444666d%2Fmerchant-service.yaml?alt=media)
{% endopenapi %}


# Interact with Catalogs

Catalogs are collections of purchasable Products available on Violet through integrated Merchants. Since multiple Merchants can sell the same product, each Merchant has a Product "Offer". These offers are often call Products in other e-commerce platforms. Each Offer is the parent entity for all of the nested SKUs associated with said Offer. It is the individual SKU, from an Offer, that be bought through your application when integrated with our checkout orchestration process.

In this section, you will take the Merchant Id you retrieved from [View Merchants](/prism/overview/view-merchants) and do the following:

1. Retrieve offers available from Merchants and understand what this information means
2. Take a SKU from the product offer and use it in the next section to [Place an Order](/prism/overview/place-an-order)


# List Connected Offers

Search and list Offers across all connected merchants

To retrieve Offers across all merchants you are connected to, use the Search Offers endpoint. This returns paginated results scoped to your channel — you will only see Offers from merchants that have an active connection with your application.

{% hint style="warning" %}
`POST /catalog/offers/search` returns eventually consistent data and is not real-time consistent. Use Offer Search for discovery, then use non-search Offer endpoints when you need real-time Offer data.
{% endhint %}

## Endpoint

```
POST /v1/catalog/offers/search
```

## Basic Request

To list all connected Offers with no filters, send a `POST` request with an empty body:

```bash
curl -X POST https://sandbox-api.violet.io/v1/catalog/offers/search?page=1&size=20 \
  -H "X-Violet-App-Id: your-app-id-here" \
  -H "X-Violet-App-Secret: your-app-secret-here" \
  -H "X-Violet-Token: your-token-here" \
  -H "Content-Type: application/json" \
  -d '{}'
```

The response is a standard [paginated response](https://github.com/violetio/docs/blob/main/concepts/pagination.md) containing an array of Offer objects.

## Filtering Results

The search body accepts optional filters to narrow results:

```json
{
  "query": "sneakers",
  "min_price": 2500,
  "max_price": 15000,
  "available": true
}
```

{% hint style="info" %}
Prices are in the smallest currency unit (e.g., cents). A `min_price` of `2500` means $25.00 USD.
{% endhint %}

For the full list of supported filter options, see the [Search Offers API Reference](https://github.com/violetio/docs/blob/main/api-reference/catalog-service/catalog-offers/search-offers.md).

## Currency Conversion

Pass the `base_currency` query parameter to receive prices in your preferred currency. The default is USD.

```
POST /v1/catalog/offers/search?base_currency=GBP
```

All prices in the response will reflect the specified currency.

## Enhanced Search (Beta)

An optional enhanced search mode provides faster response times and NLP-based querying. To enable it, pass `beta=true` as a query parameter:

```
POST /v1/catalog/offers/search?beta=true
```

See the [Search Offers API Reference](https://github.com/violetio/docs/blob/main/api-reference/catalog-service/catalog-offers/search-offers.md) for current capabilities and limitations of enhanced search.

## When to Use This vs. Get Merchant Offers

| Use Case                                            | Endpoint                                                                                                          |
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| Browse or search across **all** connected merchants | `POST /catalog/offers/search`                                                                                     |
| List offers from a **specific** merchant            | [`GET /catalog/offers/merchants/{merchant_id}`](/prism/overview/interact-with-catalogs/get-offers-for-a-merchant) |
| Fetch a **single** offer by ID                      | `GET /catalog/offers/{offer_id}`                                                                                  |

## Keeping Your Catalog Up to Date

{% hint style="info" %}
Violet **strongly** discourages scraping the search endpoint to keep your catalog current. Instead, use [Offer Webhooks](/prism/webhooks/events/offer-webhooks) to receive real-time notifications when Offers are added, updated, or removed.
{% endhint %}

**Recommended pattern:**

1. Perform an initial pull using this endpoint to populate your catalog
2. Subscribe to `OFFER_AVAILABLE`, `OFFER_UPDATED`, and `OFFER_REMOVED` webhooks
3. Use the [Get Offer by ID](https://github.com/violetio/docs/blob/main/api-reference/catalog-service/catalog-offers/get-offer-by-id.md) endpoint to fetch full details when a webhook fires

This approach keeps your catalog current without unnecessary API calls.

## Troubleshooting: Empty Results

If your search returns an empty `content` array regardless of what filters you use, the issue is usually with **your connections** — not your search parameters. The endpoint returns `200 OK` with empty content when there are no matching offers, which can be misleading.

### Check your parameter casing

The Violet API uses **snake\_case** for all request body parameters. Unrecognized parameters are silently ignored, so camelCase variants won't cause an error — they simply have no effect.

| Incorrect (camelCase) | Correct (snake\_case) |
| --------------------- | --------------------- |
| `merchantId`          | `merchant_id`         |
| `minPrice`            | `min_price`           |
| `maxPrice`            | `max_price`           |

{% hint style="warning" %}
If your filters seem to have no effect, check your casing first. This is the most common cause of unexpected results.
{% endhint %}

### Verify your merchant connections

Check whether your app is connected to any merchants in the environment you're testing against:

```bash
curl -X GET https://sandbox-api.violet.io/v1/merchants \
  -H "X-Violet-App-Id: your-app-id-here" \
  -H "X-Violet-App-Secret: your-app-secret-here" \
  -H "X-Violet-Token: your-token-here"
```

If this returns an empty list, you have no active merchant connections in this environment.

### Check your environment

Merchant connections are **environment-specific**. A merchant connected in live mode is not automatically connected in sandbox, and vice versa. Make sure you're querying the same environment where your merchants are connected (`sandbox-api.violet.io` vs `api.violet.io`).

{% hint style="info" %}
**New to sandbox?** All sandbox applications come pre-connected to Violet's demo merchants. If `GET /merchants` returns demo merchants but offer search is still empty, the demo catalog may still be syncing. Try filtering by one of the demo merchant IDs using `GET /catalog/offers/merchants/{merchant_id}` to confirm.
{% endhint %}


# Get Offers for a Merchant

Get Offers for a Merchant by Merchant Id

*Note: For more details on this endpoint and the other possible filter options it can take, please refer to the* [*API Reference*](/api-reference/catalog/offers/get-all-merchant-offers)

{% hint style="info" %}
When retrieving Offers, if you provide the `base_currency` query parameter the currency in the Offer object will match what was passed in and all prices will reflect that currency. The default currency when no parameter is provided is `USD`.
{% endhint %}

{% hint style="info" %}
Violet **strongly** discourages scraping this endpoint. Most offers do not change very often,\
so re-scraping all of a merchants offers on a regular basis is a very costly way to keep your catalog up to date.

Violet's recommendation is to make use of [offer webhooks](/prism/webhooks/handling-webhooks) to be notified when offers are added/updated in Violet's system.\
This works because when your merchants onboard, their products are pulled into Violet's system and so you will receive a webhook for each of the new merchant's offers.\
Additionally, Violet employs a number of methods to keep our merchant's catalogs up to date and all of those methods will generate webhooks sent to your system.
{% endhint %}

{% openapi src="/files/WvoCWRwklnzhcKrWChSh" path="/catalog/offers/merchants/{merchant\_id}" method="get" expanded="true" %}
[catalog-service.yaml](https://2435497985-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZrOgj5n6PuU2r0Ya8Tzl%2Fuploads%2Fgit-blob-c6e2fedb8258cc2d1a44f80a88a6690e23686c69%2Fcatalog-service.yaml?alt=media)
{% endopenapi %}


# Get Details About a SKU

Get details about a SKU given SKU ID

*Note: For more details on this endpoint and the other possible filter options it can take, please refer to the* [*API Reference*](/api-reference/catalog/skus/get-sku-by-id)

{% openapi src="/files/WvoCWRwklnzhcKrWChSh" path="/catalog/skus/{sku\_id}" method="get" expanded="true" %}
[catalog-service.yaml](https://2435497985-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZrOgj5n6PuU2r0Ya8Tzl%2Fuploads%2Fgit-blob-c6e2fedb8258cc2d1a44f80a88a6690e23686c69%2Fcatalog-service.yaml?alt=media)
{% endopenapi %}


# Try 'Iterative Checkout'

{% hint style="info" %}
If this is your first time trying Violet's Checkout API, we recommend following this guide step by step. Our docs allow you to try endpoints by entering your own values and submitting the request directly. You can also use cURL or any HTTP client of your choice — the request and response examples throughout serve as a reference for properly formatted requests when building your own integration with Violet.
{% endhint %}

So far you have been able to view all the Merchants available for your application, view their catalog of products and select one specific product. Here you will learn how to go through the entire flow of purchasing a product through Violet. To get started with the Checkout process, we will create a cart and add products to it. For this section, we have taken the SKU that we retrieved details for in [Interact with Catalogs](/prism/overview/interact-with-catalogs).

{% hint style="warning" %}
Currently Violet passes all failures in checkout relating to surpassing rate limits downstream. When integrating with Violet you must consider and prepare for such scenarios in all API calls to Violet. [Handling rate limits with Violet](/concepts/rate-limits)
{% endhint %}

{% hint style="warning" %}
A cart response can come back with status code `200` and still have errors in the `errors` field. This is because there might only be errors on some of the SKUs or Bags while the rest of the order is in a good state.

Make sure your system is coded to always check for the presence of the `errors` field on responses, no matter the status code.

Note that not all order errors are blocking. `INTERNAL_ADD_ITEM` for example just indicates that an item could not be added to the cart, this does not block checkout of other items.
{% endhint %}


# Create Cart

Create a new Cart with SKU 10064 in it.

*Note: For more details on this endpoint please refer to the the* [*API Reference*](/api-reference/orders-and-checkout/carts/create-cart)

Cart creation begins the checkout process. Products can be added to the cart at creation with a JSON Body listing 1 or more sku\_id & quantity pairs.

{% hint style="info" %}
It is not required that you add a SKU to create a cart, since it is possible for your customers cart to be empty, however, in this example, we will purchase a product with the SKU 10064 (which we noted down from the previous section)
{% endhint %}

{% openapi src="/files/SFt1gqvuZ3Y8AQjdppVs" path="/checkout/cart" method="post" expanded="true" %}
[order-service.yaml](https://2435497985-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZrOgj5n6PuU2r0Ya8Tzl%2Fuploads%2Fgit-blob-4abe5aea8922866d3520a6e30cc002332bcb9d5f%2Forder-service.yaml?alt=media)
{% endopenapi %}


# Apply Customer Info

Here we will apply customer info to the cart (including the address).

*Note: For more details on this endpoint please refer to the API Reference*

Once you have a cart with products in it you need to apply the customer information. For a brand new customer this would likely include Apply Guest Customer to Cart , Set Shipping Address , and Set Billing Address.

For the sake of ease in this example we will simplify address handling and use the same address for billing and shipping and pass this along with the customer the body of the request. For more details on what fields this API can take, refer to the documentation linked above. In this example, we have used the cart we created in the previous step. *Your Cart Id will be unique and need to be updated in the request below.*

Using `same_address: true` we can set the shipping and billing address simultaneously.

{% hint style="info" %}
See our [Quick Checkout Guide](/prism/checkout-guides/guides/utilizing-quick-checkout) for tips on how you can combine this step with the create cart call to reduce e-comm requests and use less rates
{% endhint %}

{% openapi src="/files/SFt1gqvuZ3Y8AQjdppVs" path="/checkout/cart/{cart\_id}/customer" method="post" expanded="true" %}
[order-service.yaml](https://2435497985-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZrOgj5n6PuU2r0Ya8Tzl%2Fuploads%2Fgit-blob-4abe5aea8922866d3520a6e30cc002332bcb9d5f%2Forder-service.yaml?alt=media)
{% endopenapi %}


# Get Shipping Method

This will get the available shipping methods, it will return an array of shipping methods for each bag in the cart.

*Note: For more information on this endpoint go to the* [*API Reference*](/api-reference/orders-and-checkout/cart-shipping/get-available-shipping-methods)

Once the Shipping and Billing Address are set, then you can get the shipping methods available for a cart (and bags within the cart).

{% openapi src="/files/SFt1gqvuZ3Y8AQjdppVs" path="/checkout/cart/{cart\_id}/shipping/available" method="get" expanded="true" %}
[order-service.yaml](https://2435497985-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZrOgj5n6PuU2r0Ya8Tzl%2Fuploads%2Fgit-blob-4abe5aea8922866d3520a6e30cc002332bcb9d5f%2Forder-service.yaml?alt=media)
{% endopenapi %}


# Apply Shipping Method

Set the shipping method for each bag within a cart. By passing in an array of Objects containing the bag id and associated shipping id.

*Note: For more information on this endpoint go to* [*Set Shipping Methods*](/api-reference/orders-and-checkout/cart-shipping/set-shipping-methods)

Once you have all the available shipping methods for the bags within the cart, you can select and apply them to the cart.

Note: Your `bag_id` and `cart_id` will be different from the example you have been following so far. Please update the calls with your information.

{% openapi src="/files/SFt1gqvuZ3Y8AQjdppVs" path="/checkout/cart/{cart\_id}/shipping" method="post" expanded="true" %}
[order-service.yaml](https://2435497985-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZrOgj5n6PuU2r0Ya8Tzl%2Fuploads%2Fgit-blob-4abe5aea8922866d3520a6e30cc002332bcb9d5f%2Forder-service.yaml?alt=media)
{% endopenapi %}


# Apply Payment Method

Apply a Payment Method for the Cart.

Set the payment method for your customer. Violet doesn't recommend using card numbers directly in API calls, even during testing. For this example, we have instead used a sample card token available through [Stripe](https://stripe.com/docs/testing).

When building out your live integration to Violet, learn about all the payment options available to you [here](/prism/payments).

{% openapi src="/files/SFt1gqvuZ3Y8AQjdppVs" path="/checkout/cart/{cart\_id}/payment" method="post" expanded="true" %}
[order-service.yaml](https://2435497985-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZrOgj5n6PuU2r0Ya8Tzl%2Fuploads%2Fgit-blob-4abe5aea8922866d3520a6e30cc002332bcb9d5f%2Forder-service.yaml?alt=media)
{% endopenapi %}


# Submit Cart

Submit a Cart, turning the Cart into an Order

For this example we didn't price our cart at any point. It will be done automatically before completing the checkout.

{% hint style="info" %}
When building your own integration with Violet, there are instances where carts are not priced automatically after applying shipping methods.

You will know this is needed when the response from the apply shipping methods call has a 0 value for `tax_total`. If that happens, make a call to [price cart](/api-reference/orders-and-checkout/cart-pricing/price-cart) before calling `submit`.
{% endhint %}

{% openapi src="/files/SFt1gqvuZ3Y8AQjdppVs" path="/checkout/cart/{cart\_id}/submit" method="post" expanded="true" %}
[order-service.yaml](https://2435497985-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZrOgj5n6PuU2r0Ya8Tzl%2Fuploads%2Fgit-blob-4abe5aea8922866d3520a6e30cc002332bcb9d5f%2Forder-service.yaml?alt=media)
{% endopenapi %}


# Violet Connect

{% hint style="warning" %}
**Important for Shopify Channels**: As of January 2026, Shopify requires all new merchant connections to use single-merchant custom apps. You MUST pre-register Shopify merchants in the Channel Dashboard before they can connect. See the [Shopify Custom App Migration Guide](https://github.com/violetio/docs/blob/main/channel-docs/prism/violet-connect/guides/shopify-custom-app-migration.md) for complete instructions.
{% endhint %}

Violet Connect is an onboarding tool that you can use to securely and safely onboard merchants onto your marketplace experience with ease. The tool acts as a bridge between a merchants store and Violet so that you can have them sync their catalog, connect payout accounts and set up commission rates; all without any additional work on your end.

### Key Features

#### For Shopify Merchants (Pre-Registration Required)

* **Pre-register merchants** in your Channel Dashboard with their app credentials
* **Send merchant-specific links** that streamline the onboarding to under 2 minutes
* **Track installation status** from pending to active in real-time
* See [complete Shopify documentation](/ecom-platforms/shopify)

#### For All Other Platforms

* Merchants enter their platform credentials directly in Violet Connect
* Standard onboarding flow with platform-specific requirements
* Full catalog sync and checkout capabilities once connected

### Customization

Violet provides you with the option to fully customize the onboarding experience for your merchants so that they are only interacting with your brand label. Your Violet Connect page will be customized with the following:

* A unique URL path of your choice
* The name of your application
* A description of your experience
* Your logo or icon

By default, Violet automatically shows every e-commerce platform we have integrations with on your Violet Connect dashboard, however, you can contact us to have a predefined list of supported platforms you want to show your merchants. Once completed, Violet redirects your merchants to a redirect URL that you have configured, along with any additional data you may need from our end about the merchant, such as the Violet specific merchant Id.

See the [Setup](/prism/violet-connect/setup) page for required configurations to enable Violet Connect for your channel.


# Setup

Follow these steps to get your Channel ready to connect merchants

{% hint style="warning" %}
**Shopify Pre-Registration Required**: As of January 2026, Shopify requires all new merchant connections to use single-merchant custom apps. You MUST pre-register Shopify merchants before they can connect. See [Pre-Registering Shopify Merchants](#pre-registering-shopify-merchants-required) below.
{% endhint %}

## Pre-Registering Shopify Merchants (Required)

Shopify now requires all merchants to use single-merchant custom apps. **You must pre-register merchants in the Channel Dashboard before they can connect through Violet Connect.**

{% hint style="info" %}
**Follow the full step-by-step guide:** [Pre-Registration Process](/ecom-platforms/shopify/pre-registration)
{% endhint %}

### Quick Steps for Shopify Pre-Registration:

1. **Create a single-merchant custom app** in your Shopify Partner Dashboard for each merchant
2. **Pre-register the merchant** in Channel Dashboard → Merchants → Pre-Registered tab
3. **Send the Violet Connect link** to your merchant for 2-minute authorization

Pre-registration provides:

* OAuth credentials configured upfront for each merchant
* Merchant-specific Violet Connect links (fastest onboarding path)
* Real-time tracking of installation status

**Background on this requirement**: [Shopify Custom App Migration Guide](/prism/violet-connect/guides/shopify-custom-app-migration)

##

## Set up Violet Connect

Violet Connect is customized to the user experience you want to provide so that your merchants are interacting with ***your*** brand. In order to get yourself set up with Violet Connect, you will need upload the following to your [Channel Dashboard](https://channel.violet.io/app-settings):

The channel will be responsible for providing the following values that will populate and configure the onboarding experience. These values can be configured by you in the Channel dashboard. There may be additional configuration options that will be discussed during your integration.

* App Name — This is displayed in the top left hand corner of your Violet Connect dashboard
* Square Logo or Icon — This is displayed in the top left hand corner of your Violet Connect dashboard
* Redirect URL — This is the page your merchant is taken to once the onboarding process is complete. Violet will append any information you need from our end, such as the merchant Id, to query parameters of this URL. See below.
* App Description
* More Info URL

Once all these have been set, you can contact Violet on <support@violet.io> or through Slack, depending on your support package and provide the final two values below and activate your Violet Connect experience.

* Custom Path (ex. connect.violet.io/myapp) - This is configured by Violet and once set, will enable merchant onboarding.
* Supported Commerce Platforms List (Optional) - You can filter which commerce platforms you show to your merchants instead of the complete list of Violet integrations

Once confirmed from our end, you can begin to onboard merchants in production, even if Checkout access is still disabled.

### Connecting Merchants

{% hint style="warning" %}
Do not connect real merchants through "Test Mode" Violet Connect (<https://connect.violet.dev>). If a real merchant, orders placed in "Test Mode" will not be distinguishable on their end from real orders, however, no money will have been transacted. This could result in your merchant incorrectly fulfilling orders.
{% endhint %}

{% hint style="info" %}
We encourage channels to create free test stores they can own and manage and then connect those test stores to their test mode channel. This will allow you to manage your own test products, initiate test refunds/returns for your orders and get some experience working with Violet Connect before you start onboarding real merchants. See a guide [here](/prism/violet-connect/testing/connecting-a-shopify-store)
{% endhint %}

Once setup you can go to your selected custom path `connect.violet.io/myapp` then go through the setup flow.

## Setting Details

### Redirect URL

The merchant will redirect to this URL after completion of the Violet Connect flow. You can pass in custom state information as documented below. Violet will append a query parameter, `merchant_id` to the redirect URL. This is the `merchant_id` stored in Violet and can be used by you for subsequent calls.

{% hint style="info" %}
When no custom Redirect URL is configured, merchants are automatically redirected to the merchant dashboard (merchant.violet.io) after completing the Violet Connect flow.
{% endhint %}

### Auth Callback URL

The auth callback URL receives an HTTP GET request after a merchant completes the credentials step in the Violet Connect flow. Violet appends a `merchant_id` query parameter to your callback URL, which contains the merchant ID stored in Violet's system. You can use this ID for subsequent API calls. Additionally, you can pass custom state information as documented below.

{% hint style="info" %}
This setting is currently optional and requires a support ticket to Violet for configuration.
{% endhint %}

### Custom State

Using the `state` query string parameter you can pass a value into Violet Connect by appending that to your Violet Connect URL, for example `connect.violet.io/myapp?state=sample`. The passed in state will be returned to you when the merchant completes the onboarding process.

**NOTE: `state` should be set when linking merchants to Violet Connect, do not add the query parameter in the Violet Channel Dashboard**

As a more detailed example, if your base Violet Connect URL was `connect.violet.io/myapp` and you send the merchant to `connect.violet.io/myapp?state=sample` with your base redirect URL set as `myapp.com` after completion of Violet Connect the merchant will redirect to `myapp.com?state=sample` containing the same state or value that was passed into Violet Connect to start.

![](/files/s8DU5jtqPoc0mnUHsA2Q)

### State in Webhooks

The above mentioned state will also come across in a `x-violet-connect-state` header on the`MERCHANT_CONNECTED` webhook that is fired when a merchant completes a connection.\
This will give you additional options as to what and how you use this state field.

{% hint style="warning" %}
When testing the merchant onboarding process in Sandbox, do not use an email address that you later plan on using for a developer type account. When signing up as a developer we must create accounts in both the Production and Sandbox environments. If you use the email address with a Sandbox merchant it will become reserved in Sandbox and we will not be able to complete the creation of your developer account if you try to use it for that purpose in the future.
{% endhint %}


# Payouts

The payouts onboarding step during Violet Connect lets your merchant connect a bank account to Violet (if you've integrated with [Violet Payments](/prism/payments#violet-payments)) or your [Platform Stripe Account](/prism/payments/payment-integrations/supported-providers/stripe/connecting-a-platform-stripe-account) for automated payouts.

Stripe Connect Express accounts are a core part of Stripe's product offering and used by companies such as Doordash, Lyft, and Shopify to power their payment stacks. You can read more about it here: <https://stripe.com/connect>.

Violet supports the usage of [Stripe Express](https://stripe.com/docs/connect/express-accounts) to ensure that Stripe handles the onboarding and provides you with the ability to control your own payout schedules and connected bank accounts. This information never leaves Stripe and this account is only used by Violet for payouts. Violet does not currently support linking existing Stripe accounts and the Stripe Express account is not a "full" business Stripe account. The benefit of this flow vs. a full Stripe onboarding flow is that the KYC process is much simpler than onboarding with a full business Stripe account. Merchants select the country their bank account is based in and then complete onboarding through Stripe Connect.

If your merchant already has their own Stripe standard account, Violet also supports connecting existing standard accounts through Stripe Connect OAuth.

You can learn more about payout account onboarding in our [Stripe KYC Guide](/prism/payments/payouts/guides/stripe-kyc-guide).

{% hint style="warning" %}
**Recommended Restriction: Stripe Express Accounts Only**

We strongly recommend limiting merchants to Stripe Express accounts only during merchant onboarding. Violet can enforce this restriction upon confirmation from your team.

**Why Express Accounts are Preferred:**
{% endhint %}

| Aspect                        | Express Account                         | Standard Account                       |
| ----------------------------- | --------------------------------------- | -------------------------------------- |
| **Payout Schedule Control**   | Platform controls payout timing         | Merchant controls their own payouts    |
| **Negative Balance Recovery** | Auto-debit from merchant's bank enabled | No auto-debit; platform absorbs losses |
| **Dashboard Access**          | Express Dashboard (limited)             | Full Stripe Dashboard                  |

{% hint style="warning" %}
**Key Risk with Standard Accounts**: According to [Stripe's documentation](https://docs.stripe.com/connect/account-balances), Standard account holders are responsible for their own negative balances, but Stripe cannot auto-debit their bank accounts. If a transfer reversal is needed (e.g., for refunds after payout) and the account has insufficient balance, the reversal fails and your channel becomes liable.

**Express Account Advantage**: For Express accounts, while platforms are technically liable for negative balances, Stripe enables auto-debiting from the connected account's external bank account to recover funds (with `debit_negative_balances` setting). This provides a recovery path not available with Standard accounts.
{% endhint %}


# Commissions

Part of Violet Onboarding includes your merchant setting a commission rate so that you and your merchant are both able to take advantage of Violet’s automated payout logic. The Commission Rate is the percentage portion a channel receives from a merchant each time a product is sold. This relationship is agreed upon between you and the merchant, however, when input during the onboarding process, ensures that your portion is transferred at point of sale.

It is important to note that you do not control the commission rate and are not able to change it on behalf of your merchant, however, are able to confirm the commission rate that is set on your [Channel Dashboard](https://channel.violet.io/merchants). This commission rate only applies to you. If this merchant works with other Violet Channels, they can have multiple commission rates that are set.

You can learn more about commission rates and how they are applied in Violet, [here](/prism/payments/payouts/commission-rates).


# Guides

Welcome to the Violet Connect Guides! This section provides comprehensive instructions and resources to help you seamlessly integrate and manage merchant data using Violet Connect.

Whether you're pre-provisioning merchant information, following a step-by-step integration process, or monitoring the health of your connections, these guides are designed to assist you at every stage.

### Available Guides

* [**Pre-provisioning Merchant Data**](/prism/violet-connect/guides/pre-provisioning-merchant-data): Learn how to provision merchant data in advance, streamlining the onboarding process.
* [**Violet Connect for Channels**](/prism/violet-connect/guides/violet-connect-for-channels): An overview of the Violet Connect flow, prerequisites, and customization options for channels.
* [**Violet Connect for Merchants**](/prism/violet-connect/guides/violet-connect-for-merchants): A step-by-step walkthrough for merchants connecting their store to Violet Connect.
* [**Connection Health**](/prism/violet-connect/guides/connection-health): Understand how to monitor and maintain the health of your merchant connections to ensure reliability.
* [**Detecting Merchant Connections**](/prism/violet-connect/guides/detecting-merchants-post-connection): Find out how to detect and verify when a merchant has successfully connected their store.
* [**Shopify Custom App Migration Guide**](/prism/violet-connect/guides/shopify-custom-app-migration): Shopify now requires merchants to use single-merchant custom apps. Pre-register merchants in the Channel Dashboard to streamline this required process.
* [**Connecting Your BigCommerce App**](/prism/violet-connect/guides/violet-connect-your-bigcommerce-app): A specific guide for integrating your BigCommerce application with Violet Connect.


# Pre-provisioning Merchant Data

Violet's Onboarding APIs let Channels pre-provision merchant data **before** a merchant completes the Violet Connect flow. These APIs allow you to pass metadata—such as your internal Merchant ID or external Payment Provider credentials—to programmatically associate merchant and payout details prior to onboarding a Merchant via Violet Connect.

### Shopify Merchants: Two Pre-Registration Methods

Since Shopify now requires merchants to use single-merchant custom apps, Violet provides two ways to pre-register merchants before they complete Violet Connect:

1. **Channel Dashboard UI** (Recommended for most channels): Use the Pre-Registered tab to add merchants manually with their custom app credentials. See [Shopify Custom App Migration Guide](/prism/violet-connect/guides/shopify-custom-app-migration)
2. **Onboarding APIs** (Recommended for programmatic integrations): Use the APIs documented below to pre-provision merchant data at scale using your backend systems.

Both methods result in the same outcome - merchants can connect with pre-filled credentials and streamlined flows. Choose the method that fits your integration architecture.

## What Are Onboarding APIs?

The Onboarding APIs are designed to:

* Pass data about merchants in your system *before* they formally exist in Violet (i.e. prior to going through Violet Connect).
* Associate internal merchant identifiers (`channel_merchant_id`) with Violet merchants
* Attach metadata such as payout account credentials (e.g. Stripe Account IDs) to be used by Violet during Violet Connect onboarding.
* Retrieve and update onboarding records during the pre-connect phase

Once a merchant completes Violet Connect, this onboarding data is automatically merged into the Violet Merchant record. From that point on, use [Merchant APIs](/api-reference/merchants/merchant/get-merchants) to interact with merchant data.

#### Onboarding Flow Diagram

This is a sample flow of how our Onboarding APIs interact with Violet Connect during Merchant Onboarding.

```mermaid
sequenceDiagram
    participant Channel
    participant Merchant
    participant Violet
    participant Stripe

    Channel->>Violet: POST /v1/merchants/onboard (channel_merchant_id + payout details)
    Violet->>Violet: Store Onboarding Record (merchant_onboarding_id generated)
    Violet->>Channel: Return Merchant Onboarding with merchant_onboarding_id
    Merchant->>Channel: Begins onboarding flow
    Channel->>Merchant: Redirect to Violet Connect URL (+ merchant_onboarding_id param)
    Merchant->>Violet: Completes onboarding via Connect
    Violet->>Violet: Fetch Merchant Onboarding Record to associate pre-existing data with new Violet Merchant
    Violet->>Stripe: (Optional) Create Payout Account if Payout Details present in Merchant Onboarding record
    Stripe->>Violet: Stripe Express Account for Merchant in Channel Stripe Platform Account
    Violet->>Violet: Merge Onboarding Record Violet Merchant + Payout Account
    Violet-->>Channel: Emit MERCHANT_CONNECTED webhook
    Violet->>Merchant: Complete Violet Connect Onboarding Flow
    Merchant->>Channel: Redirected back to Channel
```

### Types of Onboarding Data

#### **Merchant Identity**

Use `channel_merchant_id` to uniquely identify the merchant in your system. This ensures that the merchant onboarding in your system is correctly linked to their Violet Connect onboarding process.

**Example use case:**

* Matching a merchant who’s onboarded to your marketplace with their corresponding record in Violet

#### **Payout Data**

You can attach payout account credentials such as a Stripe Connect `account_id` before the merchant is created in Violet. If you sent the `channel_merchant_id` or `merchant_onboarding_id` to Violet Connect while onboarding this merchant, Violet will automatically create a Violet Payout Account associated with this Stripe Account during onboarding.

### Available Onboarding APIs

Violet provides the following endpoints to manage onboarding records:

| Endpoint                                        | Method | Purpose                                           |
| ----------------------------------------------- | ------ | ------------------------------------------------- |
| `/v1/merchants/onboard`                         | `POST` | Create a new onboarding record                    |
| `/v1/merchants/onboard/:merchant_onboarding_id` | `PUT`  | Update by onboarding record ID                    |
| `/v1/merchants/onboard/:merchant_onboarding_id` | `GET`  | Get a specific onboarding record                  |
| `/v1/merchants/onboard`                         | `GET`  | List all onboarding records currently in progress |

Once onboarding is complete, these records are removed and replaced by standard Merchant and Payout Account objects.

Each of these APIs returns a `MerchantOnboardingRecord`. The `merchant_onboarding_id` can be passed into Violet Connect to tell Violet to use the pre-provided data during onboarding.

```json
{
  "merchant_onboarding_id": 10000,
  "channel_merchant_id": "chnl_123456789",
  "app_id": 10193,
  "date_created": "2024-06-24T15:30:55+0000",
  "date_last_modified": "2024-06-24T15:30:57+0000"
}
```

| Field                    | Type    | Description                                                                                                                                            |
| ------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `merchant_onboarding_id` | Integer | Unique identifier for the onboarding record generated by Violet. Used to track and update merchant data that will be used by Violet during onboarding. |
| `channel_merchant_id`    | String  | Unique identifier for the merchant in your system. Used to link your merchant record with the one created in Violet.                                   |
| `app_id`                 | Integer | Identifier for your application within Violet. Determines which channel or integration this onboarding record is associated with.                      |
| `date_created`           | Date    | Timestamp indicating when the onboarding record was first created. Format: `YYYY-MM-DDTHH:MM:SS+ZZZZ`                                                  |
| `date_last_modified`     | Date    | Timestamp of the most recent update to the onboarding record. Format: `YYYY-MM-DDTHH:MM:SS+ZZZZ`                                                       |

#### Create Merchant Onboarding Record

Creates a new onboarding record with a unique identifier for the merchant in your system.

```json
POST /v1/merchants/onboard

{
  "channel_merchant_id": "chnl_123456789"
}
```

Request Body Parameters

| Field                 | Required | Description                                                  |
| --------------------- | -------- | ------------------------------------------------------------ |
| `channel_merchant_id` | Yes      | Unique identifier of this merchant in the channel’s systems. |

<details>

<summary>Sample Response</summary>

```json
{
  "merchant_onboarding_id": 10000,
  "channel_merchant_id": "chnl_123456789",
  "app_id": 10385,
  "date_created": "2024-06-24T15:30:55+0000",
  "date_last_modified": "2024-06-24T15:30:57+0000"
}
```

</details>

**Optional: Adding Payout Account Data**

You can include payout account information (e.g. a Stripe Connect ID) when creating a merchant onboarding record to associate a pre-existing Payment Provider account with a Violet Merchant during Violet Connect.

<details>

<summary>Sample Request</summary>

```json
POST /v1/merchants/onboard

{
  "channel_merchant_id": "chnl_123456789",
  "payout_details": {
    "payment_provider": "STRIPE",
    "payment_provider_metadata": {
      "stripe_account_id": "acct_123456789"
    }
  }
}
```

</details>

**Payout Detail Parameters**

| Field                       | Required | Description                                                                                                                                                               |
| --------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `payout_details`            | Yes      | Wrapper object that contains information needed for payout account onboarding.                                                                                            |
| `payment_provider`          | Yes      | Payment provider that this underlying payout account was created on. The metadata fields correspond to the payment provider.                                              |
| `payment_provider_metadata` | Yes      | Wrapper object that contains information specifically required to onboard payout accounts for the given payment provider. This field can also be passed in as `metadata`. |
| `stripe_account_id`         | Yes      | Account identifier of this merchant’s Stripe Connect account in Stripe’s systems.                                                                                         |

{% hint style="info" %}
If your Stripe Platform Account has not been set up with Violet, Violet will not subscribe to any webhook updates sent from Stripe for the provided Stripe Connect account.
{% endhint %}

<details>

<summary>Sample Response</summary>

```json
{
  "merchant_onboarding_id": 10000,
  "channel_merchant_id": "chnl_123456789",
  "app_id": 10385,
  "payout_details": {
    "payment_provider": "STRIPE",
    "payment_provider_metadata": {
      "stripe_account_id": "acct_123456789"
    }
  },
  "date_created": "2024-06-24T15:30:55+0000",
  "date_last_modified": "2024-06-24T15:30:57+0000"
}
```

</details>

#### Update Merchant Onboarding Record

Updates an onboarding record using the `merchant_onboarding_id`.

```jsx
PUT /v1/merchants/onboard/:merchant_onboarding_id
```

<details>

<summary>Sample Request</summary>

This call will update an existing Merchant Onboarding record with additional Payout Details:

```json
 PUT /v1/merchants/onboard/merchant_onboarding_id/10000

{
  "channel_merchant_id": "chnl_999999999",
  "payout_details": {
    "payment_provider": "STRIPE",
    "payment_provider_metadata": {
      "stripe_account_id": "acct_123456789"
    }
  }
}
```

</details>

<details>

<summary>Sample Response</summary>

```json
{
  "merchant_onboarding_id": 10000,
  "channel_merchant_id": "chnl_999999999",
  "app_id": 10385,
  "payout_details": {
    "payment_provider": "STRIPE",
    "payment_provider_metadata": {
      "stripe_account_id": "acct_123456789"
    }
  },
  "date_created": "2024-06-24T15:30:55+0000",
  "date_last_modified": "2024-06-24T15:30:57+0000"
}
```

</details>

**Potential Errors**

<table><thead><tr><th>Request</th><th width="90.16015625">Error Code</th><th width="347.59375">Error Title</th><th width="224.1796875">Error Message</th><th width="197.7421875">Reason</th><th width="222.80078125">How to Fix</th></tr></thead><tbody><tr><td><code>PUT</code></td><td>4429</td><td>merchant_onboarding_record_not_found</td><td>Merchant onboarding record with ID {} not found.</td><td>The provided <code>merchant_onboarding_id</code> doesn’t exist in our system.</td><td>Create a new <code>merchant_onboarding_record</code> using the <code>POST /merchant/onboarding</code> API.</td></tr><tr><td><code>POST</code></td><td>2514</td><td>merchant_already_onboarded</td><td>This merchant already exists in Violet (Merchant Id: {}). Once a merchant has been onboarded, you must directly interact with the <a href="/pages/4LBICFd5WAFobRST5Gq0">Merchant endpoints available here</a> to retrieve or update merchant details.</td><td>Call is made after the merchant has already been onboarded through Violet Connect and that merchant in Violet has the same <code>channel_merchant_id</code> as this merchant onboarding update request.</td><td>Directly interact with the Merchant endpoints available in Violet Docs to retrieve/update merchant details.</td></tr></tbody></table>

**Update Limitations**

<table><thead><tr><th width="252.26953125">Field</th><th>Can be updated?</th><th>Behavior if passed in</th><th>Notes</th></tr></thead><tbody><tr><td><code>merchant_onboarding_id</code></td><td>No</td><td>Used for record retrieval</td><td>If a <code>merchant_onboarding_id</code> is passed in and a record is not found, a <code>merchant_onboarding_record_not_found</code> exception will be thrown.</td></tr><tr><td><code>channel_merchant_id</code></td><td>Yes</td><td>Updated</td><td></td></tr><tr><td><code>date_created</code></td><td>No</td><td>Ignored</td><td></td></tr><tr><td><code>date_last_modified</code></td><td>No</td><td>Ignored</td><td></td></tr></tbody></table>

#### Retrieve a specific Merchant Onboarding Record

Returns the Merchant Onboarding Record for the given `merchant_onboarding_id`.

```jsx
GET /v1/merchants/onboard/:merchant_onboarding_id
```

Request Parameters

<table><thead><tr><th width="242.69140625">Field</th><th>Type</th><th width="103.9453125">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>merchant_onboarding_id</code></td><td>Path Parameter</td><td>Yes</td><td>The unique identifier for this merchant’s onboarding record. This value was returned as a part of the Create External Account call.</td></tr></tbody></table>

Violet will respond with the following if a merchant onboarding record matching the given id is found.

<details>

<summary>Sample Response</summary>

```json
{
  "merchant_onboarding_id": 10000,
  "app_id": 10385,
  "channel_merchant_id": "chnl_123456789",
  "payout_details": {
    "payment_provider": "STRIPE",
    "payment_provider_metadata": {
      "stripe_account_id": "acct_123456789"
    }
  },
  "date_created": "2024-06-24T15:30:55+0000",
  "date_last_modified": "2024-06-24T15:30:57+0000"
}
```

</details>

**Potential Errors**

<table><thead><tr><th width="89.48046875">Request</th><th width="96.640625">Error Code</th><th width="330.34765625">Error Title</th><th width="214.59765625">Error Message</th><th width="285.73828125">Reason</th><th width="221.140625">How to Fix</th></tr></thead><tbody><tr><td><code>PUT</code></td><td>4429</td><td>merchant_onboarding_record_not_found</td><td>Merchant onboarding record with ID {} not found.</td><td>The provided <code>merchant_onboarding_id</code> doesn’t exist in our system.</td><td>Create a new <code>merchant_onboarding_record</code> using the <code>POST /merchant/onboarding</code> API.</td></tr><tr><td><code>POST</code></td><td>2514</td><td>merchant_already_onboarded</td><td>This merchant already exists in Violet (Merchant Id: {}). Once a merchant has been onboarded, you must directly interact with the <a href="/spaces/8lXIp71Ct5qCUhXjko2q/pages/fGBfj43OVbWWB6k2vV6H">Merchant endpoints available here</a> to retrieve or update merchant details.</td><td>Call is made after the merchant has already been onboarded through Violet Connect and that merchant in Violet has the same <code>channel_merchant_id</code> as this merchant onboarding update request.</td><td>Directly interact with the Merchant endpoints available in Violet Docs to retrieve/update merchant details.</td></tr></tbody></table>

### View all Merchant Onboarding Records

Returns a paginated list of all onboarding records you’ve created.

```jsx
GET /v1/merchants/onboard
```

Request Parameters

| Field  | Type            | Required | Description                                                                                                                                                                                                             |
| ------ | --------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `size` | Query Parameter | No       | Maximum number of items to be returned in the response. By default, 20 elements will be returned. The `total_pages` and `total_elements` in the response will denote the total number of elements available.            |
| `page` | Query Parameter | No       | Maximum number of items to be returned in the response. By default, the first page of data will be returned. The `total_pages` and `total_elements` in the response will denote the total number of elements available. |

Violet will respond with a Page of Merchant Onboarding Records that exist. For this example, let’s assume there 3 accounts currently in the onboarding phase.

<details>

<summary>Sample Response</summary>

```json
{
    "content": [
      {
				"merchant_onboarding_id": 10000,
				"app_id": 10385,
				"channel_merchant_id": "chnl_123456789",
				"payout_details": {
                    "payment_provider": "STRIPE",
                    "payment_provider_metadata": {
                        "stripe_account_id": "acct_123456789"
                    }
                },
				"date_created": "2024-06-24T15:30:55+0000",
				"date_last_modified": "2024-06-24T15:30:57+0000"
			},
			{
				"merchant_onboarding_id": 10001,
				"app_id": 10385,
				"channel_merchant_id": "chnl_1111111111",
				"payout_details": {
                    "payment_provider": "STRIPE",
                    "payment_provider_metadata": {
                        "stripe_account_id": "acct_1111111111"
                    }
                },
				"date_created": "2024-06-24T15:30:55+0000",
				"date_last_modified": "2024-06-24T15:30:57+0000"
			},
			{
				"merchant_onboarding_id": 10003,
				"app_id": 10385,
				"channel_merchant_id": "chnl_222222222",
				"payout_details": {
                    "payment_provider": "STRIPE",
                    "payment_provider_metadata": {
                        "stripe_account_id": "acct_222222222"
                    }
				},
				"date_created": "2024-06-24T15:30:55+0000",
				"date_last_modified": "2024-06-24T15:30:57+0000"
			}
    ],
    "pageable": {
        "page_number": 0,
        "page_size": 3,
        "sort": {
            "unsorted": false,
            "sorted": true,
            "empty": false
        },
        "offset": 0,
        "paged": true,
        "unpaged": false
    },
    "total_pages": 1,
    "total_elements": 3,
    "last": false,
    "number_of_elements": 3,
    "first": true,
    "size": 3,
    "number": 0,
    "sort": {
        "unsorted": false,
        "sorted": true,
        "empty": false
    },
    "empty": false
}
```

</details>

If no merchants are in the onboarding state, a page with empty content will be returned.

### During Violet Connect

If you've sent Violet onboarding data ahead of time—such as merchant identifiers or payout credentials—you’ll need to ensure that data is correctly matched when the merchant begins the Violet Connect process.

#### Violet Connect

Each channel has a custom Violet Connect URL to onboard merchants. To associate an in-progress onboarding record with a merchant during Connect, include either the `channel_merchant_id` or the `merchant_onboarding_id` as a query parameter in the Connect link.

To onboard a merchant, each channel has a custom Violet Connect link. To learn about Violet Connect in more detail, refer to our [documentation](/prism/violet-connect).

For example, the Violet Connect URL could be:

`https://connect.violet.io/<channel_custom_url>/login?channel_merchant_id=chnl_123456789`

or it could be

`https://connect.violet.io/<channel_custom_url>/login?merchant_onboarding_id=10002`

When the merchant completes Violet Connect, Violet will automatically link the onboarding record to the new Merchant. After this point, the onboarding record is removed, and further updates must be made via the [Merchant APIs](/api-reference/merchants/merchant/get-merchants).

#### Merchant Webhooks

Upon successful onboarding, Violet emits the following webhook events:

* `MERCHANT_CONNECTED` – Sent when the merchant completes Violet Connect

Scenario Specific:

* `MERCHANT_PAYOUT_ACCOUNT_CREATED` – Sent if payout details were provided during onboarding and a payout account was successfully created

Learn more about these events and their payloads in our [Merchant Webhooks](/prism/webhooks#merchants) and [Payment Webhooks](https://github.com/violetio/docs/blob/main/channel-docs/prism/violet-connect/guides/broken-reference/README.md) documentation.


# Violet Connect for Channels

Violet Connect is the onboarding flow your merchants complete to connect their e-commerce store to your app. Merchants complete this process themselves — it is not a process channels complete on behalf of their merchants.

{% hint style="info" %}
We recommend trying Violet Connect out for yourself first using a [test store](/prism/violet-connect/testing/connecting-a-shopify-store).
{% endhint %}

## Prerequisites

Before directing merchants to Violet Connect, make sure:

* Your app settings are configured with a redirect URL — merchants will be sent here after completing onboarding
* Commission rates have been pre-agreed with your merchants
* **For Shopify merchants:** Review the [Shopify Merchant Onboarding guide](/ecom-platforms/shopify), which covers the pre-registration flow required for Shopify's custom app model

## Sharing Violet Connect with Merchants

Once your app is configured, send merchants their Violet Connect link. For a full walkthrough of what merchants will experience, share the [Violet Connect for Merchants](/prism/violet-connect/guides/violet-connect-for-merchants) guide with them directly.

## Customizing the Flow

The default Violet Connect flow includes: platform selection → store URL entry → credential entry → payout account setup → commission rate selection. Several steps can be configured:

### Payout Account

By default, merchants are prompted to set up a payout account via Stripe KYC. If you are bypassing Violet Payments, this step will not appear. Contact Violet to skip it for any other reason.

### Commission Rate

By default, merchants select their own commission rate during onboarding. If you are setting commission rates on behalf of merchants based on pre-negotiated agreements, this step can be bypassed. Contact Violet to configure this.

## Verifying Merchant Connections

Once a merchant completes Violet Connect, you can confirm their connection and verify the commission rate they selected on your [Channel Dashboard](https://channel.violet.io/merchant).

## Merchant Experience Preview

Watch a full demo of the merchant onboarding experience below.

<https://github.com/user-attachments/assets/8ba950de-ccd8-4c28-92d0-c16b70af7aed>


# Violet Connect for Merchants

This guide walks you through connecting your e-commerce store to Violet Connect. You will complete this process yourself — your channel cannot do it on your behalf.

## Before You Begin

Have the following ready before starting:

* A store on a supported e-commerce platform (Shopify, BigCommerce, etc.)
* Your store credentials (API keys, tokens, etc.) — see your [platform guide](https://merchant-help.violet.io/) for what you'll need
* A bank account for payout setup
* Your agreed commission rate with the channel

{% hint style="success" %}
Use a team or mailing list email address (e.g. `team@yourcompany.com`) to create your merchant account. This keeps access manageable if the person who originally set it up leaves the company.
{% endhint %}

## Steps

1. **Enter your email address** to create your Violet merchant account. Use this same email to access your dashboard at [merchant.violet.io](http://merchant.violet.io).

   ![Violet Connect Login](/files/zdWNkKD2s6GwIZEvvICR)
2. **Select your e-commerce platform.** Choose the platform your store is hosted on. Each platform has different credential requirements.

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p>Shopify merchants who have been pre-registered by their channel may skip this step automatically.</p></div>

   ![Violet Connect platform selection screen](/files/BpZQ766HgSPIkwrbN31B)
3. **Enter your store URL.**

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p>Pre-registered Shopify merchants: your store URL will be pre-filled.</p></div>

   ![Store URL entry screen](/files/Rfg9KUZgKyI9ZJtjXPyx)
4. **Enter your store credentials.** Your [platform guide](https://merchant-help.violet.io/) shows where to find these in your store admin.

   <div data-gb-custom-block data-tag="hint" data-style="warning" class="hint hint-warning"><p><strong>Shopify merchants:</strong> If you were pre-registered, you'll see a "Connect to Shopify" button instead. When installing the app, leave "Embed app in Shopify admin" unchecked.</p></div>

   ![Credential entry screen](/files/BzkpPpqjCgyWfbgvap2x)
5. **Set up your payout account.** Select the country your bank account is in. You'll be routed to Stripe to connect your account and complete identity verification.

   ![Payout account setup screen](/files/UwUEN0pImRnPa7xLS0v9)

   Learn more: [Stripe KYC Guide](/prism/payments/payouts/guides/stripe-kyc-guide)
6. **Select your commission rate.** This rate applies to orders placed through the channel's app and should match what you've agreed on with them.

   ![Commission rate selection screen](/files/ZxSSulYPnKpKGzrWZtAb) ![Commission rate set selection screen](/files/n7sn93k6b1H3FpWjcqb4)
7. **You're all set!** You'll be redirected to the channel's app to start selling.

   ![Completion screen](/files/TbkkPCRbVubPFzemdMij)

## Troubleshooting

**"Store URL Already Connected"** — If you need to update your credentials, sign in with the same email address you used when you first connected your store.


# Shopify Custom App Migration

Shopify now requires single-merchant custom apps for all new merchant connections

{% hint style="info" %}
**Documentation has moved:** The comprehensive guide for Shopify merchant onboarding using pre-registration has moved to a dedicated section. Please visit the link below for the complete, up-to-date documentation.
{% endhint %}

## 📍 New Documentation Location

The complete Shopify merchant onboarding documentation is now available at:

[**→ Shopify Merchant Onboarding Guide**](/ecom-platforms/shopify)

## What You'll Find There

The new documentation includes:

* [**Prerequisites**](/ecom-platforms/shopify/prerequisites): Setting up your Shopify Partner Dashboard, creating single-merchant custom apps, and complete API scope reference
* [**Pre-Registration Process**](/ecom-platforms/shopify/pre-registration): How to pre-register merchants in the Channel Dashboard
* [**Merchant Onboarding**](/ecom-platforms/shopify/merchant-onboarding): The streamlined merchant experience with screenshots
* [**Troubleshooting & FAQs**](/ecom-platforms/shopify/troubleshooting-faqs): Common issues, recovery steps, and comprehensive FAQ

## Why This Change?

As of January 2026, Shopify discontinued the ability for merchants to create their own custom apps. This change affects all new Shopify merchant connections:

| Aspect                | Old Way                          | New Way                       |
| --------------------- | -------------------------------- | ----------------------------- |
| Who creates apps      | Merchants in their Shopify admin | Channels in Partner Dashboard |
| Credential management | Merchant-controlled              | Channel-controlled            |
| Onboarding time       | 10+ minutes                      | Under 2 minutes               |

## Quick Start

1. **Create a Shopify Partner account** (if you don't have one)
2. **Create a single-merchant custom app** for each merchant
3. **Pre-register the merchant** in your Channel Dashboard
4. **Send the Violet Connect link** to your merchant

For detailed instructions, please visit the [new documentation](/ecom-platforms/shopify).

## Need Help?

If you have questions about the migration or pre-registration process:

* Review the [Troubleshooting & FAQs](/ecom-platforms/shopify/troubleshooting-faqs)
* Contact Violet support for assistance


# Connection Health

{% hint style="info" %}
This page, both the list and the results of any searches are **cached**.

Violet regularly updates this cache but there are some cases, especially when merchants are making changes to their account or occasionally right after a merchant connects to Violet for the first time where this information can be out of date.

In the event that you suspect that some information may be out of date, simply click on the merchant in question, select the appropriate tab and use the refresh button on that tab to make sure that the information is up to date and accurate.
{% endhint %}

As you onboard Merchants through Violet Connect, it is important to know what state they are in during the onboarding process as well as over time afterward to ensure that you are able to place orders to their store. Violet provides you with a “Connection Health” dashboard that you can access on [channel.violet.io/merchants](http://channel.violet.io/merchants) to check the state of a merchant, as seen below.

![](https://res.cloudinary.com/ddhjp8mca/image/upload/v1696039469/mintlify/connection_health_dashboard_y0t7zz.png)

Merchants can be in any of the “Complete”, “Incomplete”, or “Needs Attention” states denoting if any of their underlying connection states are failing. You can click into a merchant to check specific details.

* Complete — This state denotes that a merchant is fully connected to Violet and all orders will process as expected.
* Incomplete — This state denotes that there is some “non-blocking” action that needs to be taken by the merchant. Non-blocking means that orders can still *currently* be placed for this merchant, however, there are changes they need to make from their end, such as KYC updates, in order to keep their connection in good standing. An Incomplete Merchant can transition to a Needs Attention state if action items are not addressed.
* Needs Attention — This state denotes that the merchant is not ready to be able to have orders placed against them. Clicking into the merchant will provide you with information about what is missing. We recommend reviewing this list regularly and taking any action to prevent errors and failed orders.

{% hint style="success" %}
If App or Merchant level payment bypassing is being used, you can ignore the "Needs Attention" state if the Payout Account is the only Connection Health item that needs attention. Payout accounts are not requires for merchants for whom you are bypassing payments.
{% endhint %}

{% hint style="info" %}
`Incomplete` merchants are *never* in a blocked state, they can receive orders through Violet. `Incomplete`, at most, means that they need some maintenance now to prevent them from transitioning to `Needs Attention` (blocked) at some point in the future.

Payout accounts are a good example. `Incomplete` payout accounts have information that is `currently due` but that will *only* block payouts if the information is not delivered and they become `past due`. `Currently due` does not mean the merchant is blocked, hence the `Incomplete` state.
{% endhint %}

Clicking into a merchant, you can see the following:

![](https://res.cloudinary.com/ddhjp8mca/image/upload/v1696039474/mintlify/connection_health_merchant_g3vlq0.png)

* Connection — This field denotes whether or not the merchant has successfully connected to your app and Violet is able to communicate with their e-commerce store.
* Scopes — This field denotes whether or not the correct scopes have been configured in their e-commerce platform connection. Correct Scopes are necessary to ensure that Violet has the permissions we need to complete all steps of the checkout process.
* Sync Status — Denotes the status of the merchant's product sync into Violet.
* Invalid Products — This field denotes whether or not there are any products in the merchant catalog that were not able to be synced into Violet. The reason a product is invalid is provided in the view if this state is not green.
* Offers Published — This field denotes whether or not there are Offers from the merchant catalog that have been published for your application. You are only able to place orders against published offers.
* Payout Account — This field denotes whether or not a payout account is connected. When this is complete, payouts are fully enabled for this merchant and will be processed automatically. If Yellow (i.e. needs attention), there are additional fields the merchant needs to add to their Stripe KYC before they fall out of agreement. Once a payout account has fallen out of KYC agreement, or if KYC was not fully completed, this state moved into Red.
  * Not applicable to channels or merchants with payment bypass or without Violet checkout.
* Commission Rate — The field denotes whether or not a commission rate has been set. If a commission rate has been set, it is visible in the top left hand corner beneath the name of the merchant.
  * Not applicable to channels without Violet checkout.

### Troubleshooting Merchants

When a merchant is showing as Needs Attention or Incomplete, the dashboard will provide you with some guidance as to what is wrong and how it can be fixed.

For example if the payout account tab is Incomplete, selecting that tab will describe that while the merchant has a payout account there are some fields that Stripe needs, and they can be addressed by following the "Go to Stripe" link.


# Detecting Merchants Connections

Violet recommends storing the Violet `merchant_id` in your database once a merchant has successfully completed Violet Connect Onboarding. This is so that you are able to fetch details about this merchant adhoc to power your own dashboard.

There are two methods to accomplish this:

## Using Redirects

Violet appends `merchant_id` to the end of a [re-direct URL](/prism/violet-connect/setup#redirect-url) that you provide us as a query parameter. You can parse the `merchant_id` from this re-direct.

Here is a sample of how you could use the Violet Connect flow and where you can retrieve the `merchant_id`:

1. Merchant starts your onboarding flow
2. You send Merchant to Violet Connect
3. Merchant completes Violet Connect flow
4. Merchant is re-directed back to your dashboard through your re-direct URL
5. Merchant completes your onboarding flow

Step 4 is where Violet takes the re-direct URL you’ve set in the channel dashboard, appends the `merchant_id` as a query parameter show in the end of the URL and directs back to your onboarding dashboard. You can then take this `merchant_id` in Step 5, and store it on your end.

## Using Webhooks

You can subscribe to the [Merchant Connected](/prism/webhooks#merchants) webhook to receive the full `Merchant` object when a merchant connects to your channel. This object will contain useful details, including the `merchant_id`


# Connecting your BigCommerce App

{% hint style="warning" %}
**Only Required for Channels bringing their own BigCommerce App.**

The following guide is only for channels that wish to use their own BigCommerce app. This would be an app that you developed and have listed in the BigCommerce app marketplace. If you are using the Violet BigCommerce app the below requirements do not apply to you.
{% endhint %}

To connect BigCommerce merchants to your application through Violet, you must meet the following requirements.

* Have a BigCommerce Application
  * If you do not yet have a BigCommerce application, follow [this guide from BigCommerce](https://developer.bigcommerce.com/api-docs/apps/guide/intro).
  * Your app must include and embedded UX. This can be something as simple as a page rendering your company logo. There are no requirements from Violet as to the contents of this UX. This URL must be provided to Violet.
  * You will need to know your BigCommerce app ID.
* Your BigCommerce app must have the following scopes at a minimum.

![Minimum required BigCommerce App Scopes](/files/8f8Mv7rWN4OKLS5JRIfd)

* Additional App Scopes (if your Commerce Platform app requires scopes beyond the minimum required scopes). Any additional app scopes must be shared with Violet.
* Your BigCommerce app must use the Violet onboarding wizard as an Allowed redirection URL.

![You will find the Allowed redirect URL(s) field in the URLs section of your App setup view.](/files/7lW2tKc4ytxooPvrJynS)

* Provide Violet with Client ID and Client Secret for your BigCommerce application. These are required for Violet to communicate with with BigCommerce on your applications behalf. Any OAuth keys that are later created when merchant’s connect will be scoped to your applications Client ID and Client Secret. Please contact your Violet representative to provide these values when you are ready.

![You will find your credentials in the App list view of developer.bigcommerce.com.](/files/Sz4hmVWER9ueKl26DpMd)

{% hint style="warning" %}
Merchants must have 3rd party cookies enabled and any ad-blockers or browser shields in their browser disabled when using BigCommerce. It is recommended that these actions are taken before they begin the connection process.
{% endhint %}


# Testing

If you'd like to test the Merchant Onboarding experience end-to-end, the best way to do that is to set up a test Shopify store and go through your Violet Connect flow in Test Mode.

The URL for this is: **<https://connect.violet.dev/{your\\_path\\_here}>** .

{% hint style="info" %}
Violet Connect in Test Mode is activated once you become a paying customer.
{% endhint %}

Proceed to the next page for info on connecting your **TEST** Shopify Store in Test Mode.

{% hint style="warning" %}
WARNING: Only connect TEST stores to TEST MODE. Live stores connecting to Test Mode can result in termination of your service with Violet.
{% endhint %}


# Connecting a Shopify Store

We encourage channels to create free test stores they can own and manage and then connect those test stores to their test mode channel. This will allow you to manage your own test products, initiate test refunds/returns for your orders and get some experience working with Violet Connect before you start onboarding real merchants.

{% hint style="info" %}
**For Production**: For production merchant onboarding, Shopify now requires merchants to use single-merchant custom apps. See the [Shopify Custom App Migration Guide](/prism/violet-connect/guides/shopify-custom-app-migration) for pre-registration and credential setup in the Channel Dashboard.
{% endhint %}

## Connecting a Shopify Store

You can test the entire Violet Connect onboarding flow by creating a test Shopify merchant and then connecting it to your Violet application in test mode. You may select a different platform if you are more comfortable with it or you already have a test store, the basic steps should be the same.

{% hint style="warning" %}
Do not connect real merchants through “Test Mode” Violet Connect. If a real merchant, orders placed in “Test Mode” will not be distinguishable on their end from real orders, however, no money will have been transacted. This could result in your merchant incorrectly fulfilling orders.
{% endhint %}

## Creating a Shopify Store

If you don’t already have one, you can create a store on Shopify by following clicking [here](https://accounts.shopify.com/store-create?language=en\&locale=en&_y=c2b36ea1-031e-49de-8ff3-8dba0f4f032f\&signup_page=https://www.shopify.com/blog/start-online-store\&signup_page_referer=https://www.google.com/\&signup_types%5B%5D=paid_trial_experience\&signup_types%5B%5D=acq_discounted_shopify_payment&_s=e035330b-f5b1-4c29-9aa2-324390cfff78&_p=b9deba72-CA89-44FB-CBB4-BDA1B507CC37). Shopify will take you through creating an account, creating a store, and then uploading products. Once your store is ready, you should be able to navigate to the Products tab and see your list of products. Your Shopify merchants will have a similar view of products. These are what get synched into Violet during onboarding

![](https://res.cloudinary.com/ddhjp8mca/image/upload/v1696043430/mintlify/connect-shopify/shopify_store_iibgzy.png)

## Onboarding to Violet

{% hint style="warning" %}
When testing the merchant onboarding process in Sandbox, do not use an email address that you later plan on using for a developer type account. When signing up as a developer we must create accounts in both the Production and Sandbox environments. If you use the email address with a Sandbox merchant it will become reserved in Sandbox and we will not be able to complete the creation of your developer account if you try to use it for that purpose in the future.
{% endhint %}

1. Once your store is ready, you can navigate to your “Test Mode” Violet Connect URL available on [channel.violet.io](http://channel.violet.io), as seen below:

{% hint style="info" %}
In Test Mode, you cannot edit your Violet Connect URL
{% endhint %}

![](https://res.cloudinary.com/ddhjp8mca/image/upload/v1696043431/mintlify/connect-shopify/app_settings_yixcgg.png)

2. Navigate to your sandbox Violet Connect URL beginning with <https://connect.violet.dev/>
3. Create an account on Violet Connect by entering an email address to associate with this merchant. (See warning above)
4. Click “Shopify”. This will take you through a Shopify specific onboarding flow.
5. Follow [this](https://merchant-help.violet.io/platform-guides/shopify) guide to create your Shopify credentials.
6. Complete Violet onboarding as described in [Violet Connect for Merchants](/prism/violet-connect/guides/violet-connect-for-merchants) to successfully sync your merchant.
7. Your connection is now complete! You should be able to see this merchant in your Channel Dashboard under the “Merchants” tab.

![](https://res.cloudinary.com/ddhjp8mca/image/upload/v1696043433/mintlify/connect-shopify/merchant_connections_ttcv7e.png)

{% hint style="info" %}
Login at <https://merchant.violet.dev> with the same email address used on Violet Connect to view the dashboard from the merchant's perspective.
{% endhint %}


# FAQs

<details>

<summary>When will Violet be able to provide full integration with Squarespace?</summary>

Violet currently supports a full integration with Squarespace.

</details>

<details>

<summary>How do I connect a new merchant to my app?</summary>

You can view a step-by-step guide [here](/prism/violet-connect/guides/violet-connect-for-merchants) or watch a video example in the [Violet Connect for Channels](/prism/violet-connect/guides/violet-connect-for-channels) guide.

</details>

<details>

<summary>How do I pre-register Shopify merchants in the Channel Dashboard?</summary>

You can pre-register Shopify merchants in the Channel Dashboard by navigating to **Merchants → Pre-Registered tab → Add Pre-Registration**. This allows you to configure OAuth credentials upfront and provide merchants with direct installation links.

Shopify now requires merchants to use single-merchant custom apps instead of the previous channel-controlled approach. Pre-registration streamlines this required process for your merchants.

See the [Shopify Merchant Onboarding Guide](/ecom-platforms/shopify) for complete step-by-step instructions.

</details>

<details>

<summary>How do I disconnect a merchant from my app?</summary>

You can disconnect a merchant from your Channel by using the Request Merchant App Uninstall [endpoint](/api-reference/apps/merchant-app-installs/request-merchant-app-uninstall).

</details>

<details>

<summary>How do I let my merchant change the email they used for Violet Connect Onboarding?</summary>

To prevent issues of “dead emails” we *highly* recommend that merchants use a group based email address that multiple people have access to when initially setting up their accounts. `violet.merchant@companydomain.com` for example. We recommend adding this to you onboarding procedures as a recommendation to pass on.

Currently we have a manual process on Violet’s end that allows us to accomplish this task, however there are a few security related considerations.

1. The new email must be @companydomain.com. To avoid scams, we cannot transfer a merchant to [gmail.com](http://gmail.com) email address or any other public email provider.
2. The merchant cannot yet have setup their payout account; this is to prevent financial fraud. You can check this in the Merchants tab, if the `Payout Account` is marked “Needs Attention” they have not yet created their account.
   1. For cases where a payout account exists, we may require the merchant to complete additional verification steps before we can complete a transfer.

We have a project in our backlog to support merchants transferring ownership themselves, but for now it will be a manual process.

Assuming they fulfill the above conditions, to complete this process we will need from you:

1. The MerchantId and Name
2. The original email used (optional but useful)
3. The desired new email (must meet above conditions)
4. A screenshot of their payout account tab, to verify the above conditions. Make sure the merchant name and Id is visible in the shot.

Contact us with the above information and we will take a look.

</details>

<details>

<summary>Why is the ‘Write Customers’ permission required during onboarding?</summary>

Write Customers allows the order to be associated with a customer record in their system. This comes with things like their email, etc. Most Merchants want to make sure that data is carried through, and in order to do that, we have to be able to Write Customers as a part of the Order Creation process in their system.

We’ve historically requested this scope. Shopify did eventually give us the ability to write customers under the `write_orders` scope however we’ve continued requesting the `write_customers` scope for forwards compatibility. On July 1st Shopify will be rolling out a new suite of customer protection rules that will impact API functionality and having the `write_customers` scope ensures that there will be no disruptions to our integration with Shopify when this goes into effect. We will likely revisit our scopes once we’ve reached July 1st. If it’s safe to do so we can likely reduce this scope down to `read_customers`.

We prefer to over-optimize on scopes as asking all merchants to go back and change their scopes after onboarding has been a painful experience in the past. If the merchant is not comfortable with `write_customers`, they could complete the onboarding in Violet Connect, get past the scope validation part, then go back into their Shopify Custom Apps view and uncheck the `write_customers` scope. We don’t write any customers during that brief window that we have the `write_customers` scope so there will be no impact on their system. If we find that we require the scope once Shopify’s changes go into effect on July 1st we can then explain the need for it to the merchant and ask them to re-enable the scope for `write_customers`.

</details>

<details>

<summary>Where can my merchant see their payouts?</summary>

Merchants have access to the same [distributions](/prism/payments/payouts/distributions) exports as channels.

Merchants can also view their payout on Stripe's Stripe Express Dashboard.

* Have the merchant go to <https://merchant.violet.io/settings/payments>
  * They will need to login with the email they created their merchant with originally
* Press the “Go to Stripe” button
* They will be directed to the Stripe dashboard
  * They will need a text code from the phone number provided during setup
* Once on the dashboard, they can click on the transactions tab to see payments from violet as well Stripe Payouts to their bank account
* They can filter by date and export the data to CSV

</details>

<details>

<summary>What does the Channel Login Detected message mean?</summary>

If you see the Channel Login Detected dialog, that means that an account with the entered email already exists in Violet as a channel account. An account (email) cannot be both a merchant and a channel.

If you are a channel and you are trying to create a test store, you must use a different email address for the test merchant. Adding `+merchant` before the @ is often an easy way to accomplish this as the email will still go to the same inbox. E.g. <joe+merchant@company.com>

If a real merchant encounters this issue, that almost certainly means they accidentally created a channel account instead of following the Violet Connect flow to connect to your channel. In this case they will need to select a different email account to complete their Violet Connect flow.

If they are adamant that they want to use the already used email for Violet Connect, please contact Violet Support and explain that a merchant accidentally created a channel account and they want their email address made available to be used for their merchant account. Please provide the email address in question.

</details>

<details>

<summary>Should we restrict merchants to Stripe Express accounts during onboarding?</summary>

Yes, we strongly recommend limiting merchants to Stripe Express accounts only during the payout step of merchant onboarding. Violet can enforce this restriction upon confirmation from your team.

**Why Stripe Standard Accounts Create Risk:** Stripe Standard accounts present significant operational challenges because merchants retain full control over payout schedules. These accounts typically enable auto-payouts, preventing balance accumulation in their Stripe account. This creates a critical issue: Stripe prohibits auto-debiting from Standard accounts, so any transfer reversal attempts will fail when no balance exists. Your channel would then bear responsibility for these funds and must manually recover them from the merchant.

**Benefits of Stripe Express Accounts:** Stripe Express accounts eliminate these risks by enabling auto-debits, including allowing for negative balances, and giving your team control over payout schedules. This configuration ensures smoother operations and reduces your financial exposure.

</details>

<details>

<summary>Does Violet work with Global-e?</summary>

Yes, Violet works with Global-e via an indirect integration model. Violet does not interact directly with Global-e but interacts with the ecom platforms that interact with Global-e.

</details>


# Merchants

Merchants are stores whose products you may want to sell in your experience. These can be hosted in a variety of e-commerce platforms, however, Violet makes these available to you for Checkout through unified models.

Once a Merchant has onboarded and connected to your Violet Application through [Violet Connect](/prism/violet-connect), you will be able to access their products and facilitate checkout on their behalf.

{% hint style="info" %}
More information about merchant connections [here](/prism/merchants/merchant-app-connections)
{% endhint %}

### Test Mode

In test mode, including while working through our [Guides](/prism/violet-connect/guides/connection-health), you will see test merchants you didn't know or connect to yourself. That's okay. These sandbox merchants are connected to test stores on real ecommerce platforms. Though the merchants won't be familiar, the experience of viewing and getting merchant info will be the same as in production.

The Violet Merchant APIs allow you to view information about the various merchants that are integrated with Violet and that your application has access to. You can learn more about these APIs, [here](/api-reference/merchants/merchant).


# Merchant Parity

Merchants may occassionally change some parts of the configuration in their external store. Changes to some parts of this configuration may impact your ability to utilize an Offer or other data.

When a merchant changes critical data of their store, its data may get out of sync with Violet. In order to process this in a secure manner, when Violet systems notice such changes it immediately update the merchant information and acts accordingly with the property and changes detected.

The changes can trigger three sets of actions:

* Temporarily disable offers and resync
  * Disables all merchant offers and start resyncing the entire catalog. During this process some offers may be not available to sell. Once the process is complete, all offers are again up-to-date and ready to be sold.
  * Example scenarios:
    * Store currency changed.
* Merchant disable
  * Disables merchant and all offers. Offers become unavailable to sell. For scenarios like this an action from merchant is likely required to become enabled again.
  * Example scenarios:
    * Store platform plan moving from active to paused.
    * App uninstalled from platform.
    * Required platform app scopes removed.
* Merchant enable
  * Enables merchant and start resyncing the entire catalog. Once the process is complete, all offers are again up-to-date and ready to be sold.
  * Example scenarios:
    * Store platform plan moving from paused to active.
    * App installed to platform.
    * All required platform app scopes added.

{% hint style="info" %}
All actions defined in this page generate webhooks events, for topics and details please refer to [Webhooks](/prism/webhooks).
{% endhint %}

## Critical Merchant Properties

Currently Violet monitors lower-level merchant data changes critical to the operation of a Merchant's store and API connection. These include:

* Currency: Temporarily offer disable and resync
* Plan: Merchant disable / enable
* App Scopes: Merchant disable / enable

#### Platforms with Low-Level Merchant Data Monitoring

Current support:

* Shopify

#### Unmonitored Platforms

Platforms that are not yet monitored require Violet to manually update the merchant data and trigger the catalog resync.

If you noticed a merchant or offer with incorrect data compared to its platform, please reach out to us.


# Merchant App Connections

For an app to access a merchant’s catalog, the merchant must first connect to the app. Once connected, the channel can browse the merchant’s published products and sell any active offers.

When the connection is established, Violet sends a `MERCHANT_CONNECTED` webhook to the app and a `STORE_CONNECTED` notification to the channel dashboard.

If the merchant later disconnects the app, Violet emits a `MERCHANT_DISCONNECTED` webhook and a `STORE_DISCONNECTED` notification to the channel dashboard. Apps can initiate a disconnect through the [Merchant App Uninstall endpoint](/api-reference/apps/merchant-app-installs/request-merchant-app-uninstall).

{% hint style="warning" %}
After disconnection, the app loses all access to the merchant’s catalog and can no longer perform actions. To regain access, the merchant must complete the Violet Connect flow again.
{% endhint %}

Keep in mind that a merchant can be [disabled](/prism/merchants/merchant-enable-disable) while still remaining connected to an app.

#### Commission Rate

The commission rate is specific to each merchant–app connection. If that connection is terminated and later re-established, a new rate is applied based on the app’s default commission settings.


# Merchant Enabled / Disabled

Whenever a merchant enters a state where Violet cannot interact with their store or process an order, we disable the merchant. This involves marking the merchant as disabled, disabling all the offers associated with the merchant, and notifying any channels connected to the merchant that it has been disabled.

**There are currently two types of merchant disablement**:

* Sustained Merchant Disablement
* Temporary Merchant Disablement

***

## Sustained Merchant Disablement

Sustained merchant disablement occurs when a change in the merchant's connection or configuration requires Violet to disable their account. The merchant must take some action to resolve the issue from their side before Violet can re-enable their account.

### Common Causes of Sustained Merchant Disablement

The following are common causes for a merchant to enter a state of sustained disablement. For each cause, there is an associated action that the merchant can take to re-enable themselves.

**Merchant uninstalls the app that Violet uses to connect to their store.**

By uninstalling the connector app the merchant has invalidated the credentials we use to connect to their store. The merchant must reinstall the connector app before returning to Violet Connect to provide Violet with new credentials.

{% hint style="info" %}
This can be a relatively common occurrence because when merchants encounter an error, they attempt to uninstall and reinstall the violet app and they don't realize that this invalidates the credentials they previously provided us.

We recommend informing your merchants that they should never uninstall the Violet app unless they intend to completely sever their relationship with Violet and your channel or unless specifically instructed to.
{% endhint %}

**Merchant shuts down their store.**

When a merchant shuts down their store, they are ceasing all operations and are effectively deleting their account on whichever SaaS commerce platform they use. When a merchant takes this action they are automatically disconnected from Violet as any credentials Violet has for them are immediately invalidated. This is typically a permanent disconnection, unless the shutdown was unintentional. If the shutdown was unintentional and the merchant intends on resuming operations, the merchant must return to Violet Connect and perform the full connection process outlined for their platform.

**Merchant fails to pay subscription fee to the commerce platform that powers their store.**

If a merchant fails to pay their subscription fee to the commerce platform that powers their store, it generally results in a temporary disconnect that is reversed when the merchant resumes payment to the commerce platform. The merchant's store will typically return to the state it was in before the disconnection occurred, and thus, it likely does **not** need to return to Violet Connect as the existing credentials should still work.

**Merchant pauses their store or migrates to a subscription plan that doesn’t allow for the creation of new orders.**

If a merchant pauses their store or migrates to a subscription plan that does not allow for the creation of new orders, it generally results in a temporary disconnect that is reversed when the merchant returns to a subscription plan that allows for the creation of new orders. The merchant's store will return to the state it was in before order creation was paused, and it likely does not need to return to Violet Connect as the existing credentials should still work.

***

## Temporary Merchant Disablement

Temporary merchant disablement occurs when a merchant changes a configuration in their store that requires Violet to temporarily disable their catalog while it is being re-synced. If Violet did not disable the catalog during this time, it would be possible for items to be purchased with incorrect pricing.

### Common Causes of Temporary Merchant Disablement

The following are common causes for a merchant to enter a state of temporary disablement:

**Merchant changes their base currency.**

When the merchant changes the base currency of their store, Violet must immediately disable each of their Offers to ensure that none are available for purchase. Without taking this action, the items would reflect incorrect pricing and the shopper would end up paying too much or too little, depending on the changed currencies. Once each Offer is disabled, Violet initiates an immediate re-sync of the merchant's entire product catalog. As each external product is re-synced, the equivalent Offer is re-enabled with new currency and pricing applied.

***

## What Happens When a Merchant is Disabled?

When a merchant is disabled, multiple automated actions occur, each of which is outlined below:

### **Merchant Record is Disabled**

The Merchant record is updated with a status of `DISABLED`. We recommend that you subscribe to the `MERCHANT_DISABLED` webhook event so that you remain aware of the merchant being disabled. An additional header with the key `X-Violet-Reason` will be sent with the webhook to provide context for what caused the merchant to be disabled.

See our [webhooks section](/prism/webhooks/handling-webhooks) for more information

### **Merchant’s Offers are Disabled**

All Offers belonging to the merchant are disabled and updated with statuses that reflect their being disabled. The new disabled statuses will differ depending on the status they were in before they were disabled:

* If an Offer had a status of `AVAILABLE`, the new status will be `DISABLED_AVAILABLE`.
* If an Offer had a status of `UNAVAILABLE`, the new status will be `DISABLED_UNAVAILABLE`.
* Other Offer statuses like `ARCHIVED` and `FOR_DELETION` are not impacted by Offer disablement.

Violet will pause syncing offers with the merchant's store until the merchant has been re-enabled.

***

## What Happens When a Merchant is Enabled?

When a merchant is enabled, multiple automated actions occur, each of which is outlined below.

### **Merchant Record is Enabled**

The merchant record is updated with the status they had before they were disabled, which is typically `ACTIVE`. We recommend subscribing to the `MERCHANT_ENABLED` webhook event to remain aware of the merchant being enabled.

### **Merchant’s Offers are Enabled**

All offers belonging to the merchant are re-synced and updated with statuses that reflect their being re-enabled. The new enabled statuses will differ depending on the previous status:

* If an offer had a status of `DISABLED_AVAILABLE`, and the external product is still available after the re-sync, the new status will be `AVAILABLE`.
* If an offer had a status of `DISABLED_UNAVAILABLE`, and the external product is still unavailable, the new status will be `UNAVAILABLE`.
* Other offer statuses like `ARCHIVED` and `FOR_DELETION` are not impacted by offer enablement.

As each offer is re-synced, an event will be triggered for the `OFFER_UPDATED` webhook. If you persist offer data in your system, we recommend subscribing to this webhook event to remain aware of availability changes to an offer.

***

{% hint style="warning" %}
The statuses of `DISABLED_AVAILABLE` and `DISABLED_UNAVAILABLE` mentioned in this page are likely to change in the near future as they are consolidated into a single status. Violet will communicate these changes in advance.
{% endhint %}


# Merchant Configurations

This page describes the available configuration options for merchants, including feature flags, store settings, order behaviors, shipping configuration, and catalog sync policies. Feature flags are organized into two categories: **Global** flags that apply regardless of commerce platform, and **Platform-specific** flags that only apply when using certain commerce platforms.

## Managing Feature Flags via API

Merchant configuration can be retrieved and managed programmatically using the following API endpoints:

* [Get Merchant Config](https://github.com/violetio/docs/blob/main/api-reference/merchant-service/merchants-configuration/get-merchant-configuration/README.md) - Retrieve the current configuration for a merchant, including all feature flags
* [Toggle Global Feature Flag](https://github.com/violetio/docs/blob/main/api-reference/merchant-service/merchants-configuration/toggle-merchant-configuration-global-feature-flag/README.md) - Enable or disable a global feature flag for a merchant

{% hint style="warning" %}
Merchant Configuration is currently in beta. These properties may change at any time.
{% endhint %}

## Global Feature Flags

These flags apply to a merchant globally, regardless of their commerce platform. Set these in the `global_feature_flags` map. Global feature flags can be toggled using the [Toggle Global Feature Flag](https://github.com/violetio/docs/blob/main/api-reference/merchant-service/merchants-configuration/toggle-merchant-configuration-global-feature-flag/README.md) API endpoint.

| Flag Key                        | Default  | Description                                                                                                                                                                                              |
| ------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sync_metadata`                 | Disabled | When enabled, synchronizes product-level metadata (custom fields, tags, vendor info) from the commerce platform. Requires explicit `true`.                                                               |
| `sync_sku_metadata`             | Disabled | When enabled, synchronizes SKU-level metadata including variant-specific custom fields. Also triggers expanded SKU data collection for richer variant information. Requires explicit `true`.             |
| `sync_taxonomy`                 | Enabled  | When enabled, synchronizes product taxonomy and category hierarchies from the commerce platform. Set to `false` to disable.                                                                              |
| `sync_collections`              | Disabled | When enabled, synchronizes product collections/groupings (e.g., Shopify collections, Wix collections). Requires explicit `true`.                                                                         |
| `truify_offer_visibility`       | Disabled | When enabled, forces offer visibility to true during catalog sync, overriding the source platform's visibility settings. Requires explicit `true`.                                                       |
| `disable_hidden_offers`         | Disabled | When enabled, sets hidden/draft products to disabled status rather than syncing their original visibility. Requires explicit `true`.                                                                     |
| `auto_publish_offers`           | Enabled  | When enabled, automatically publishes offers after creation or update. Set to `false` to require manual publishing.                                                                                      |
| `sync_offer_sale_price`         | Enabled  | When enabled, synchronizes sale/promotional prices alongside regular prices. Set to `false` to ignore sale prices.                                                                                       |
| `sync_offer_shipping`           | Disabled | When enabled, synchronizes product-level shipping data including weight, dimensions, and shipping class. Requires explicit `true`.                                                                       |
| `use_contextual_prices`         | Disabled | When enabled, fetches and stores region or customer-segment specific pricing. Also triggers expanded SKU data collection. Requires explicit `true`.                                                      |
| `log_ecom_service_client`       | Disabled | When enabled, activates detailed trace logging for all commerce platform API calls including request/response bodies. Useful for debugging. Requires explicit `true`.                                    |
| `exclude_hidden_offers`         | Disabled | When enabled, completely excludes hidden/draft products from catalog sync rather than syncing them as disabled. Requires explicit `true`.                                                                |
| `bypass_inventory_policies`     | Disabled | When enabled, ignores commerce platform inventory policies and availability rules. Products are considered in-stock if purchasable, regardless of inventory tracking settings. Requires explicit `true`. |
| `proxy_original_customer_email` | Disabled | When enabled, forwards the original customer email address during order submission rather than using a proxy email. Requires explicit `true`.                                                            |
| `enable_addon_sku_injection`    | Disabled | When enabled, automatically injects addon SKUs into orders based on configured rules in `orders_config.conventions.addon_sku_config`. Requires explicit `true`.                                          |

## Platform Feature Flags

These flags apply to a merchant depending on their commerce platform. Set these in the `platform_feature_flags` map.

### Shopify

| Flag Key                        | Default  | Description                                                                                                                                                                            |
| ------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `use_custom_shipping_rates`     | Enabled  | When enabled, allows custom shipping rates via the DraftOrders API. Set to `false` to disable.                                                                                         |
| `filter_by_collections`         | Disabled | When enabled, filters product sync to only include products from collections specified in `shopify_config.enabled_collection_ids`. Requires explicit `true`.                           |
| `use_graph_products`            | N/A      | Legacy flag for GraphQL product sync. As of 2025.06.22, GraphQL is always used regardless of this setting.                                                                             |
| `populate_order_note_field`     | Enabled  | When enabled, populates the Shopify order note field with the platform Order ID for merchant reference. Set to `false` to disable.                                                     |
| `filter_inventory_by_locations` | Disabled | When enabled, filters inventory to only include stock from locations specified in `shopify_config.enabled_location_ids`. Requires explicit `true`.                                     |
| `disable_offline_offers`        | Disabled | When enabled, disables offers that are not published to the Shopify Online Store sales channel. Requires explicit `true`.                                                              |
| `use_native_order_name`         | Disabled | When enabled, uses Shopify's native order naming convention during order writeback instead of the platform's order ID. Requires explicit `true`.                                       |
| `use_storefront_api`            | Disabled | When enabled, uses the Shopify Storefront API for product sync and order writeback, allowing merchants to control product availability via Product Listings. Requires explicit `true`. |
| `use_cart_estimation`           | Disabled | When enabled, creates a draft order for shipping rate estimation instead of using draft order calculation. Requires explicit `true`.                                                   |
| `redistribute_taxes`            | Disabled | When enabled, requests tax distribution from Shopify during order creation and assigns taxes as line items. Requires explicit `true`.                                                  |

### WooCommerce

| Flag Key                   | Default  | Description                                                                                                                             |
| -------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `use_short_description`    | Disabled | When enabled, syncs the WooCommerce short description field instead of the full product description. Requires explicit `true`.          |
| `sync_duplicate_sku_media` | Disabled | When enabled, syncs media for products with duplicate SKUs. Requires explicit `true`.                                                   |
| `use_basic_auth`           | Disabled | When enabled, uses HTTP Basic Authentication instead of OAuth for WooCommerce API calls. Requires explicit `true`.                      |
| `filter_by_categories`     | Disabled | When enabled, filters product sync to only include products from categories specified in the platform config. Requires explicit `true`. |

### Salesforce Commerce Cloud (SFCC)

| Flag Key               | Default  | Description                                                                                                                                        |
| ---------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `filter_by_catalog`    | Disabled | When enabled, filters products and collections to only those in catalogs specified in `sfcc_config.enabled_catalog_ids`. Requires explicit `true`. |
| `filter_by_categories` | Disabled | When enabled, filters product sync to only include products from categories specified in the platform config. Requires explicit `true`.            |

### BigCommerce

| Flag Key                        | Default  | Description                                                                                                                                            |
| ------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `use_price_lists`               | Disabled | When enabled, uses BigCommerce price lists for pricing from `bigcommerce_config.enabled_price_list_ids`. Requires explicit `true`.                     |
| `filter_inventory_by_locations` | Disabled | When enabled, filters inventory to only include stock from locations specified in `bigcommerce_config.enabled_location_ids`. Requires explicit `true`. |
| `filter_by_categories`          | Disabled | When enabled, filters product sync to only include products from categories specified in the platform config. Requires explicit `true`.                |

### CommerceTools

| Flag Key                       | Default  | Description                                                                                                                                            |
| ------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `filter_inventory_by_channels` | Disabled | When enabled, filters inventory to only include stock from channels specified in `commercetools_config.enabled_channel_ids`. Requires explicit `true`. |

### Wix

| Flag Key                | Default  | Description                                                                                                                              |
| ----------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `filter_by_collections` | Disabled | When enabled, filters product sync to only include products from collections specified in the platform config. Requires explicit `true`. |

### Prestashop

| Flag Key                | Default  | Description                                                                                                                   |
| ----------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `use_short_description` | Disabled | When enabled, syncs the Prestashop short description field instead of the full product description. Requires explicit `true`. |

### Ecwid

| Flag Key               | Default  | Description                                                                                                                             |
| ---------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `filter_by_categories` | Disabled | When enabled, filters product sync to only include products from categories specified in the platform config. Requires explicit `true`. |

### Magento

| Flag Key               | Default  | Description                                                                                                                             |
| ---------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `filter_by_categories` | Disabled | When enabled, filters product sync to only include products from categories specified in the platform config. Requires explicit `true`. |

## Cross-Platform Flag Reference

Some flags apply to multiple platforms. The table below shows which platforms support each cross-platform flag.

| Flag Key                        | Platforms                                      |
| ------------------------------- | ---------------------------------------------- |
| `filter_by_collections`         | Shopify, Wix                                   |
| `filter_inventory_by_locations` | Shopify, BigCommerce                           |
| `use_short_description`         | WooCommerce, Prestashop                        |
| `filter_by_categories`          | WooCommerce, BigCommerce, SFCC, Ecwid, Magento |

***

## Additional Configuration Options

{% hint style="info" %}
Many of the configuration sections below are now available as individual REST resources that you can read and update directly. See [Merchant Configuration Resources](/prism/merchants/merchant-configuration-resources) for the full list of endpoints. For configuration options not yet covered by a dedicated endpoint, please reach out to the Violet team.
{% endhint %}

## Store Configuration

The `store_config` object contains default settings for a merchant's store.

| Field                 | Type   | Description                                                             |
| --------------------- | ------ | ----------------------------------------------------------------------- |
| `default_weight_unit` | String | Default weight unit used by the merchant (e.g., `KG`, `LB`, `OZ`, `G`). |
| `default_size_unit`   | String | Default size/dimension unit used by the merchant (e.g., `CM`, `IN`).    |
| `default_locale`      | String | Default locale used by the merchant (e.g., `en-US`).                    |
| `default_currency`    | String | Default currency code used by the merchant (e.g., `USD`, `EUR`).        |
| `base_url`            | String | Base URL of the merchant's store.                                       |
| `base_media_url`      | String | Base URL for media assets from the merchant's store.                    |

***

## Orders Configuration

The `orders_config` object controls order submission behaviors, sync policies, and order conventions.

### Basic Order Settings

| Field                          | Type         | Default | Description                                                                                       |
| ------------------------------ | ------------ | ------- | ------------------------------------------------------------------------------------------------- |
| `commerce_disabled`            | Boolean      | `false` | When `true`, disables order creation and cart submission for this merchant.                       |
| `order_prefix`                 | String       | `null`  | When supported by the commerce platform, this prefix will be used for orders.                     |
| `custom_tags`                  | Set\<String> | `null`  | Custom tags to be added to a merchant's orders upon submission.                                   |
| `prohibit_order_cancellations` | Boolean      | `false` | When `true`, prohibits order cancellations for this merchant.                                     |
| `prohibit_order_refunds`       | Boolean      | `false` | When `true`, prohibits order refunds for this merchant.                                           |
| `force_push_orders`            | Boolean      | `false` | When `true`, orders will be force-pushed to the commerce platform even if items are out of stock. |

### Order Sync Policy

The `sync_policy` object within `orders_config` controls how order status updates are synchronized.

| Field                             | Type    | Description                                                             |
| --------------------------------- | ------- | ----------------------------------------------------------------------- |
| `sync_type`                       | Enum    | The synchronization strategy: `POLLING`, `HYBRID`, or `NO_SYNC`.        |
| `sync_frequency_minutes`          | Integer | How often to poll for order updates (when using `POLLING` or `HYBRID`). |
| `consolidation_frequency_minutes` | Integer | How often to consolidate order data.                                    |

**Sync Types:**

| Type      | Description                                                           |
| --------- | --------------------------------------------------------------------- |
| `POLLING` | Periodically polls the commerce platform for order updates.           |
| `HYBRID`  | Combines webhook-based updates with periodic polling for reliability. |
| `NO_SYNC` | Disables automatic order synchronization.                             |

### Addon SKU Injection

When the `enable_addon_sku_injection` global feature flag is enabled, Violet can configure rules to automatically inject additional SKUs into orders based on product tags.

Addon SKU rules are configured in `orders_config.conventions.addon_sku_config.rules`:

| Field                 | Type         | Description                                                                                  |
| --------------------- | ------------ | -------------------------------------------------------------------------------------------- |
| `rule_name`           | String       | Human-readable name for this rule (for logging/debugging).                                   |
| `match_tags`          | Set\<String> | Offer tags that trigger this rule. If an Offer has ANY of these tags, the addon is injected. |
| `addon_sku_id`        | Long         | The SKU ID to inject when the rule matches.                                                  |
| `quantity_multiplier` | Integer      | Multiplier for addon quantity. Addon qty = original SKU qty × multiplier. Default: `1`.      |
| `reason`              | String       | Optional descriptor for why this addon is injected (e.g., `"return-packaging"`).             |
| `enabled`             | Boolean      | Whether this rule is active. Default: `true`.                                                |

**Example Use Case:** Automatically add return packaging materials when orders contain items tagged with `"returnable"`.

***

## Shipping Configuration

The `shipping_config` object controls shipping method behaviors, fallback options, and exclusion rules.

### Fallback Shipping Methods

When a merchant's commerce platform provides no shipping methods, Violet can configure fallback methods in `shipping_config.fallback_methods`.

Each fallback shipping method supports:

| Field              | Type    | Description                                                                            |
| ------------------ | ------- | -------------------------------------------------------------------------------------- |
| `label`            | String  | The display name of the shipping method.                                               |
| `description`      | String  | Description of the shipping method.                                                    |
| `price`            | Integer | The price of the shipping method in cents.                                             |
| `currency`         | String  | The currency code (e.g., `USD`).                                                       |
| `handle`           | String  | The handle or external ID to use when utilizing this method.                           |
| `calculation_type` | Enum    | `PER_ORDER` or `PER_ITEM` - whether the price applies to the entire order or per item. |
| `conditions`       | Object  | Conditions that determine when this shipping method is applicable.                     |

#### Shipping Method Conditions

| Field                    | Type         | Description                                                                  |
| ------------------------ | ------------ | ---------------------------------------------------------------------------- |
| `applicable_countries`   | Set\<String> | ISO Alpha-2 country codes where this method can be applied.                  |
| `inapplicable_countries` | Set\<String> | ISO Alpha-2 country codes where this method cannot be applied.               |
| `applicable_offer_ids`   | Set\<Long>   | Offer IDs that this shipping method is applicable to.                        |
| `inapplicable_offer_ids` | Set\<Long>   | Offer IDs that this shipping method is not applicable to.                    |
| `min_order_amount`       | Integer      | Minimum order amount (in cents) required for this method.                    |
| `max_order_amount`       | Integer      | Maximum order amount (in cents) for this method to be applicable.            |
| `min_weight`             | Object       | Minimum order weight for this method (`value` and `unit`: `KG`, `LB`, `OZ`). |
| `max_weight`             | Object       | Maximum order weight for this method.                                        |

### Simple Exclusion Flags

| Field                            | Type    | Default | Description                                                          |
| -------------------------------- | ------- | ------- | -------------------------------------------------------------------- |
| `exclude_external_free_shipping` | Boolean | `false` | When `true`, excludes free shipping methods from external platforms. |
| `exclude_external_methods`       | Boolean | `false` | When `true`, excludes all shipping methods from external platforms.  |

### Shipping Exclusions

For more granular control over which external shipping methods are excluded, Violet can configure `shipping_config.shipping_exclusions`. This supports both global exclusions (apply to all orders) and compound rules (conditional based on cart contents).

#### Global Shipping Exclusions

These exclusions apply unconditionally to all carts.

| Field                    | Type         | Description                                                                          |
| ------------------------ | ------------ | ------------------------------------------------------------------------------------ |
| `excluded_names`         | Set\<String> | Exact shipping method names/labels to exclude (case-insensitive).                    |
| `excluded_name_patterns` | Set\<String> | Substrings to match against shipping method names (case-insensitive contains match). |
| `excluded_ids`           | Set\<String> | Shipping method IDs or handles to exclude.                                           |
| `price_rules`            | Object       | Price-based exclusion rules (see below).                                             |

**Price Exclusion Rules** (`price_rules`):

| Field             | Type          | Description                                         |
| ----------------- | ------------- | --------------------------------------------------- |
| `exclude_above`   | Integer       | Exclude methods with price ≥ this value (in cents). |
| `exclude_below`   | Integer       | Exclude methods with price ≤ this value (in cents). |
| `excluded_prices` | Set\<Integer> | Specific price values to exclude (in cents).        |
| `exclude_free`    | Boolean       | Exclude free shipping methods (price = 0).          |

#### Compound Exclusion Rules

Compound rules in `shipping_exclusions.exclusion_rules` combine method matching criteria with offer-based conditions, allowing Violet to exclude certain shipping methods only when specific products are in the cart.

Each rule contains:

| Field              | Type    | Description                                        |
| ------------------ | ------- | -------------------------------------------------- |
| `rule_name`        | String  | Descriptive name for debugging/logging.            |
| `enabled`          | Boolean | Whether this rule is active. Default: `true`.      |
| `method_criteria`  | Object  | Criteria for matching shipping methods to exclude. |
| `offer_conditions` | Object  | Conditions based on cart contents.                 |

**Method Match Criteria**

Criteria for identifying which shipping methods to exclude. Multiple criteria use OR logic.

**Name-Based Filters:**

| Field           | Type         | Description                                      |
| --------------- | ------------ | ------------------------------------------------ |
| `names`         | Set\<String> | Exact method names (case-insensitive).           |
| `name_patterns` | Set\<String> | Substrings to match (case-insensitive contains). |
| `name_prefixes` | Set\<String> | Prefixes to match at start of names.             |
| `name_suffixes` | Set\<String> | Suffixes to match at end of names.               |

**ID-Based Filters:**

| Field         | Type         | Description                 |
| ------------- | ------------ | --------------------------- |
| `ids`         | Set\<String> | Exact method IDs/handles.   |
| `id_patterns` | Set\<String> | Substrings to match in IDs. |
| `id_prefixes` | Set\<String> | Prefixes to match in IDs.   |

**Price-Based Filters:**

| Field           | Type          | Description                                                    |
| --------------- | ------------- | -------------------------------------------------------------- |
| `price_above`   | Integer       | Match methods with price ≥ this value (cents).                 |
| `price_below`   | Integer       | Match methods with price ≤ this value (cents).                 |
| `price_between` | Object        | Match methods within a price range (`min` and `max` in cents). |
| `prices`        | Set\<Integer> | Match methods with these exact prices.                         |
| `is_free`       | Boolean       | Match free shipping methods (price = 0).                       |

**Carrier-Based Filters:**

| Field              | Type         | Description                                                          |
| ------------------ | ------------ | -------------------------------------------------------------------- |
| `carriers`         | Set\<String> | Carrier names to match (e.g., `"UPS"`, `"FedEx"`). Case-insensitive. |
| `carrier_patterns` | Set\<String> | Substrings to match in carrier names.                                |

**Service Level Filters:**

| Field               | Type         | Description                                                         |
| ------------------- | ------------ | ------------------------------------------------------------------- |
| `service_levels`    | Set\<String> | Service level codes (e.g., `"GROUND"`, `"EXPRESS"`, `"OVERNIGHT"`). |
| `exclude_expedited` | Boolean      | Match expedited/express methods.                                    |
| `exclude_overnight` | Boolean      | Match overnight/next-day methods.                                   |
| `exclude_ground`    | Boolean      | Match ground/standard methods.                                      |

**Delivery Time Filters:**

| Field               | Type    | Description                                             |
| ------------------- | ------- | ------------------------------------------------------- |
| `min_delivery_days` | Integer | Match methods with estimated delivery ≥ this many days. |
| `max_delivery_days` | Integer | Match methods with estimated delivery ≤ this many days. |

**Offer Conditions**

Conditions that determine when an exclusion rule applies based on cart contents.

**Product-Based Conditions:**

| Field                           | Type         | Description                                                                  |
| ------------------------------- | ------------ | ---------------------------------------------------------------------------- |
| `applicable_offer_ids`          | Set\<Long>   | Rule applies only when cart contains these offer IDs.                        |
| `inapplicable_offer_ids`        | Set\<Long>   | Rule does NOT apply when cart contains these offer IDs (override/exemption). |
| `applicable_sku_ids`            | Set\<Long>   | Rule applies only when cart contains these SKU IDs.                          |
| `inapplicable_sku_ids`          | Set\<Long>   | Rule does NOT apply when cart contains these SKU IDs.                        |
| `applicable_external_sku_ids`   | Set\<String> | Rule applies only when cart contains SKUs with these external IDs.           |
| `inapplicable_external_sku_ids` | Set\<String> | Rule does NOT apply when cart contains SKUs with these external IDs.         |

**Category/Tag/Collection Conditions:**

| Field                      | Type         | Description                                                           |
| -------------------------- | ------------ | --------------------------------------------------------------------- |
| `applicable_categories`    | Set\<String> | Rule applies only when cart contains offers in these categories.      |
| `inapplicable_categories`  | Set\<String> | Rule does NOT apply when cart contains offers in these categories.    |
| `applicable_tags`          | Set\<String> | Rule applies only when cart contains offers with these tags.          |
| `inapplicable_tags`        | Set\<String> | Rule does NOT apply when cart contains offers with these tags.        |
| `applicable_collections`   | Set\<String> | Rule applies only when cart contains offers from these collections.   |
| `inapplicable_collections` | Set\<String> | Rule does NOT apply when cart contains offers from these collections. |
| `applicable_vendors`       | Set\<String> | Rule applies only when cart contains offers from these vendors.       |
| `inapplicable_vendors`     | Set\<String> | Rule does NOT apply when cart contains offers from these vendors.     |

**Cart Value/Quantity Conditions:**

| Field             | Type    | Description                                                |
| ----------------- | ------- | ---------------------------------------------------------- |
| `min_cart_value`  | Integer | Rule applies only when cart subtotal ≥ this value (cents). |
| `max_cart_value`  | Integer | Rule applies only when cart subtotal ≤ this value (cents). |
| `min_item_count`  | Integer | Rule applies only when cart contains ≥ this many items.    |
| `max_item_count`  | Integer | Rule applies only when cart contains ≤ this many items.    |
| `min_cart_weight` | Object  | Rule applies only when cart weight ≥ this value.           |
| `max_cart_weight` | Object  | Rule applies only when cart weight ≤ this value.           |

**Geographic Conditions:**

| Field                             | Type         | Description                                                      |
| --------------------------------- | ------------ | ---------------------------------------------------------------- |
| `applicable_countries`            | Set\<String> | Rule applies only for shipping to these countries (ISO Alpha-2). |
| `inapplicable_countries`          | Set\<String> | Rule does NOT apply for shipping to these countries.             |
| `applicable_regions`              | Set\<String> | Rule applies only for shipping to these regions/states.          |
| `inapplicable_regions`            | Set\<String> | Rule does NOT apply for shipping to these regions/states.        |
| `applicable_postal_codes`         | Set\<String> | Rule applies only for shipping to these postal codes.            |
| `inapplicable_postal_codes`       | Set\<String> | Rule does NOT apply for shipping to these postal codes.          |
| `applicable_postal_code_prefixes` | Set\<String> | Rule applies only for postal codes starting with these prefixes. |

**Match Mode:**

| Field        | Type | Default | Description                                                                                 |
| ------------ | ---- | ------- | ------------------------------------------------------------------------------------------- |
| `match_mode` | Enum | `ANY`   | How to evaluate multiple IDs: `ANY` = at least one must match, `ALL` = all must be present. |

***

## Catalog Configuration

The `catalog_config` object controls inventory behaviors, availability rules, exclusion rules, and catalog sync policies.

### Inventory Settings

Violet can configure inventory-related behaviors in `catalog_config.inventory`.

| Field                          | Type    | Default | Description                                                                                            |
| ------------------------------ | ------- | ------- | ------------------------------------------------------------------------------------------------------ |
| `enforce_zero_as_out_of_stock` | Boolean | `false` | When `true`, a stock level of zero is treated as out of stock, regardless of external inventory rules. |

#### Safety Stock Rules

Violet can configure safety stock thresholds that override data from the external commerce platform in `catalog_config.inventory.safety_stock_rules`.

| Field                        | Type               | Description                                                            |
| ---------------------------- | ------------------ | ---------------------------------------------------------------------- |
| `default_out_of_stock_level` | Integer            | The default stock level at which products are considered out of stock. |
| `tags`                       | Map\<String, Rule> | Stock rules keyed by product tag.                                      |
| `categories`                 | Map\<String, Rule> | Stock rules keyed by category.                                         |
| `collections`                | Map\<String, Rule> | Stock rules keyed by collection.                                       |
| `vendors`                    | Map\<String, Rule> | Stock rules keyed by vendor.                                           |

Each stock rule contains:

| Field                | Type    | Description                                                             |
| -------------------- | ------- | ----------------------------------------------------------------------- |
| `out_of_stock_level` | Integer | The stock level at which matching products are considered out of stock. |

### Availability Settings

Violet can configure availability-related behaviors in `catalog_config.availability`.

| Field                        | Type    | Default | Description                                                                                                                           |
| ---------------------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `enforce_draft_as_available` | Boolean | `false` | When `true`, draft products are considered available.                                                                                 |
| `bypass_inventory_policy`    | Boolean | `false` | When `true`, inventory policies and availability are ignored. Products are considered in stock and available if they are purchasable. |

#### Availability Rules

Violet can override availability based on product attributes in `catalog_config.availability.availability_rules`.

| Field         | Type               | Description                              |
| ------------- | ------------------ | ---------------------------------------- |
| `tags`        | Map\<String, Rule> | Availability rules keyed by product tag. |
| `categories`  | Map\<String, Rule> | Availability rules keyed by category.    |
| `collections` | Map\<String, Rule> | Availability rules keyed by collection.  |
| `vendors`     | Map\<String, Rule> | Availability rules keyed by vendor.      |

Each availability rule contains:

| Field       | Type    | Description                                              |
| ----------- | ------- | -------------------------------------------------------- |
| `available` | Boolean | Whether matching products should be marked as available. |

### Catalog Exclusion Rules

Violet can configure which products to exclude from the catalog or mark as unpublished in `catalog_config.exclusions.exclusion_rules`.

| Field         | Type               | Description                           |
| ------------- | ------------------ | ------------------------------------- |
| `tags`        | Map\<String, Rule> | Exclusion rules keyed by product tag. |
| `categories`  | Map\<String, Rule> | Exclusion rules keyed by category.    |
| `collections` | Map\<String, Rule> | Exclusion rules keyed by collection.  |
| `vendors`     | Map\<String, Rule> | Exclusion rules keyed by vendor.      |

Each exclusion rule contains:

| Field         | Type    | Description                                                                                                                           |
| ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `excluded`    | Boolean | When `true`, matching products are completely excluded from sync. Setting this to `true` automatically sets `unpublished` to `false`. |
| `unpublished` | Boolean | When `true`, matching products are synced but marked as unpublished. Setting this to `true` automatically sets `excluded` to `false`. |

### Catalog Sync Policy

Violet can configure how the catalog is synchronized in `catalog_config.sync_policy`.

| Field                             | Type          | Description                                                               |
| --------------------------------- | ------------- | ------------------------------------------------------------------------- |
| `sync_type`                       | Enum          | The synchronization strategy (see below).                                 |
| `sync_frequency_minutes`          | Integer       | How often to poll for catalog updates (when using `POLLING` or `HYBRID`). |
| `consolidation_frequency_minutes` | Integer       | How often to consolidate catalog data.                                    |
| `excluded_webhook_topics`         | List\<String> | Webhook topics to ignore when using `EVENTS` or `HYBRID` sync.            |

**Sync Types:**

| Type      | Description                                                           |
| --------- | --------------------------------------------------------------------- |
| `POLLING` | Periodically polls the commerce platform for catalog updates.         |
| `EVENTS`  | Relies entirely on webhooks for real-time catalog updates.            |
| `HYBRID`  | Combines webhook-based updates with periodic polling for reliability. |
| `NO_SYNC` | Disables automatic catalog synchronization.                           |


# Merchant Configuration Resources

## Overview

Individual merchant configuration sections — shipping settings, shipping methods, inventory location filters, catalog rules, and catalog settings — are available as first-class REST resources under `/merchants/{merchant_id}/*`. These endpoints let you read and update specific configuration sections without fetching or overwriting the full [Merchant Configuration](https://github.com/violetio/docs/blob/main/api-reference/merchant-service/merchants-configuration/get-merchant-configuration/README.md) object.

Each resource follows standard REST semantics: `GET` to read, `PATCH` for partial updates, `PUT` for full replacement, `POST` for creation, and `DELETE` for removal.

{% hint style="info" %}
These resource endpoints manage the same underlying configuration as the monolithic [Get Merchant Configuration](https://github.com/violetio/docs/blob/main/api-reference/merchant-service/merchants-configuration/get-merchant-configuration/README.md) endpoint. Changes made through either interface are reflected in both.
{% endhint %}

## Shipping Settings

Shipping settings control fallback shipping behavior toggles for a merchant. These are separate from the fallback shipping methods themselves, which have their own resource (see below).

| Field                            | Type    | Description                                                                              |
| -------------------------------- | ------- | ---------------------------------------------------------------------------------------- |
| `exclude_external_methods`       | Boolean | When `true`, excludes all shipping methods returned by the merchant's commerce platform. |
| `exclude_external_free_shipping` | Boolean | When `true`, excludes free shipping methods from the commerce platform.                  |
| `use_fallback_methods_on_empty`  | Boolean | When `true`, returns fallback shipping methods when the commerce platform provides none. |

**Read settings:**

```
GET /merchants/{merchant_id}/shipping-settings
```

```json
{
  "exclude_external_methods": true,
  "exclude_external_free_shipping": false,
  "use_fallback_methods_on_empty": true
}
```

**Update settings:**

```
PATCH /merchants/{merchant_id}/shipping-settings
Content-Type: application/merge-patch+json
```

```json
{
  "exclude_external_methods": true
}
```

Only the fields present in the request body are modified; omitted fields are left untouched.

## Shipping Methods

Shipping methods are the fallback methods Violet returns when a merchant's commerce platform provides no shipping options (or when `exclude_external_methods` is enabled). Each method is identified by a unique `handle` per merchant.

| Field              | Type    | Required | Description                                                         |
| ------------------ | ------- | -------- | ------------------------------------------------------------------- |
| `label`            | String  | Yes      | Display name of the shipping method.                                |
| `description`      | String  | No       | Description shown to the customer.                                  |
| `price`            | Integer | Yes      | Price in cents.                                                     |
| `currency`         | String  | Yes      | ISO 4217 currency code (e.g., `USD`).                               |
| `handle`           | String  | No       | Unique identifier. Generated from the label if omitted on creation. |
| `calculation_type` | Enum    | No       | `PER_ORDER` (default) or `PER_ITEM`.                                |
| `conditions`       | Object  | No       | Rules that restrict when this method is available.                  |

### Conditions

Conditions let you scope a shipping method to specific countries, offers, order amounts, or weights.

| Field                    | Type      | Description                                                  |
| ------------------------ | --------- | ------------------------------------------------------------ |
| `applicable_countries`   | String\[] | ISO Alpha-2 country codes where this method can be used.     |
| `inapplicable_countries` | String\[] | ISO Alpha-2 country codes where this method cannot be used.  |
| `applicable_offer_ids`   | Long\[]   | Offer IDs this method applies to.                            |
| `inapplicable_offer_ids` | Long\[]   | Offer IDs this method does not apply to.                     |
| `min_order_amount`       | Integer   | Minimum order amount (in cents) required.                    |
| `max_order_amount`       | Integer   | Maximum order amount (in cents) allowed.                     |
| `min_weight`             | Object    | Minimum order weight (`value` and `unit`: `KG`, `LB`, `OZ`). |
| `max_weight`             | Object    | Maximum order weight.                                        |

### Endpoints

**List all methods:**

```
GET /merchants/{merchant_id}/shipping-methods
```

```json
[
  {
    "label": "Standard",
    "description": "5-7 business days",
    "price": 500,
    "currency": "USD",
    "handle": "standard",
    "calculation_type": "PER_ORDER",
    "conditions": {
      "applicable_countries": ["US", "CA"],
      "min_order_amount": 1000
    }
  }
]
```

**Create a method:**

```
POST /merchants/{merchant_id}/shipping-methods
```

```json
{
  "label": "Express",
  "price": 1500,
  "currency": "USD",
  "calculation_type": "PER_ORDER"
}
```

If `handle` is omitted, one is generated from the label (e.g., `"Express"` becomes `"express"`). If a handle is supplied and already exists for this merchant, the request returns `409 Conflict`.

**Get a single method:**

```
GET /merchants/{merchant_id}/shipping-methods/{handle}
```

**Create or replace a method by handle:**

```
PUT /merchants/{merchant_id}/shipping-methods/{handle}
```

**Delete a method:**

```
DELETE /merchants/{merchant_id}/shipping-methods/{handle}
```

{% hint style="info" %}
Renaming a method's handle requires deleting the old method and creating a new one. A `handle` in the request body, if present, must match the path handle.
{% endhint %}

## Catalog Settings

Catalog settings control offer visibility and publishing behavior during catalog sync.

| Field                     | Type    | Description                                                                                                  |
| ------------------------- | ------- | ------------------------------------------------------------------------------------------------------------ |
| `truify_offer_visibility` | Boolean | Forces offer visibility to `true` during catalog sync, overriding the source platform's visibility settings. |
| `auto_publish_offers`     | Boolean | Automatically publishes offers after creation or update. Set to `false` to require manual publishing.        |

**Read settings:**

```
GET /merchants/{merchant_id}/catalog-settings
```

```json
{
  "truify_offer_visibility": true,
  "auto_publish_offers": false
}
```

**Update settings:**

```
PATCH /merchants/{merchant_id}/catalog-settings
Content-Type: application/merge-patch+json
```

```json
{
  "auto_publish_offers": false
}
```

Only the fields present in the request body are modified; omitted fields are left untouched.

{% hint style="warning" %}
`truify_offer_visibility` is restricted to channel and admin tokens. Merchant tokens attempting to set this field receive a `403 Forbidden` response.
{% endhint %}

## Catalog Rules

Catalog rules control which products are included, excluded, or unpublished during catalog sync. Rules are organized into two types — **availability** and **exclusions** — and are keyed by **dimension** (`tags` or `vendors`) and a dimension value (the specific tag or vendor name).

**Read all rules:**

```
GET /merchants/{merchant_id}/catalog-rules
```

```json
{
  "availability": {
    "tags": {
      "sale": {
        "available": true,
        "published": true
      }
    },
    "vendors": {}
  },
  "exclusions": {
    "tags": {},
    "vendors": {
      "Pucci": {
        "excluded": true,
        "unpublished": false
      }
    }
  }
}
```

### Availability Rules

Availability rules override whether products matching a given tag or vendor are marked as available and/or published.

| Field       | Type    | Description                                        |
| ----------- | ------- | -------------------------------------------------- |
| `available` | Boolean | Whether matching products are marked as available. |
| `published` | Boolean | Whether matching products are marked as published. |

**Create or replace an availability rule:**

```
PUT /merchants/{merchant_id}/catalog-rules/availability/{dimension}/{key}
```

For example, to mark all products tagged `"clearance"` as available and published:

```
PUT /merchants/{merchant_id}/catalog-rules/availability/tags/clearance
```

```json
{
  "available": true,
  "published": true
}
```

**Delete an availability rule:**

```
DELETE /merchants/{merchant_id}/catalog-rules/availability/{dimension}/{key}
```

### Exclusion Rules

Exclusion rules control whether products matching a given tag or vendor are excluded from sync entirely, or synced but marked as unpublished.

| Field         | Type    | Description                                                          |
| ------------- | ------- | -------------------------------------------------------------------- |
| `excluded`    | Boolean | When `true`, matching products are completely excluded from sync.    |
| `unpublished` | Boolean | When `true`, matching products are synced but marked as unpublished. |

{% hint style="warning" %}
`excluded` and `unpublished` are mutually exclusive. Setting one to `true` automatically clears the other.
{% endhint %}

**Create or replace an exclusion rule:**

```
PUT /merchants/{merchant_id}/catalog-rules/exclusions/{dimension}/{key}
```

For example, to exclude all products from the vendor `"Pucci"`:

```
PUT /merchants/{merchant_id}/catalog-rules/exclusions/vendors/Pucci
```

```json
{
  "excluded": true,
  "unpublished": false
}
```

**Delete an exclusion rule:**

```
DELETE /merchants/{merchant_id}/catalog-rules/exclusions/{dimension}/{key}
```

{% hint style="info" %}
The `{key}` path parameter should be URL-encoded if the tag or vendor name contains special characters.
{% endhint %}

## Inventory Location Filters

Inventory location filters restrict which warehouse or fulfillment locations are used for inventory calculations. When filtering is enabled, only stock from the specified locations is considered when determining product availability.

| Field               | Type      | Description                                         |
| ------------------- | --------- | --------------------------------------------------- |
| `location_ids`      | String\[] | The set of enabled location IDs (numeric strings).  |
| `filtering_enabled` | Boolean   | Read-only. `true` when `location_ids` is non-empty. |

{% hint style="warning" %}
Inventory location filters are only supported for Shopify merchants. Requests for merchants on other platforms return `400 Bad Request`.
{% endhint %}

**Read filters:**

```
GET /merchants/{merchant_id}/inventory-location-filters
```

```json
{
  "location_ids": ["12345678", "87654321"],
  "filtering_enabled": true
}
```

**Replace filters:**

```
PUT /merchants/{merchant_id}/inventory-location-filters
```

```json
{
  "location_ids": ["12345678", "87654321"]
}
```

This replaces the full set of enabled location IDs. The `filter_inventory_by_locations` platform feature flag is derived automatically — it is enabled when the list is non-empty and disabled when the list is empty. The `filtering_enabled` field in the response is read-only and ignored on write.

To disable location filtering, pass an empty list:

```json
{
  "location_ids": []
}
```

## Relationship to Get Merchant Configuration

The [Get Merchant Configuration](https://github.com/violetio/docs/blob/main/api-reference/merchant-service/merchants-configuration/get-merchant-configuration/README.md) endpoint returns the complete configuration object for a merchant, including all of the sections covered above. The resource endpoints documented on this page provide targeted access to individual sections.

Use the full configuration endpoint when you need a complete snapshot. Use the individual resource endpoints when you need to read or update a specific section — they are lighter, avoid accidental overwrites of unrelated settings, and support partial updates via JSON Merge Patch where applicable.


# Catalog

The Violet Catalog is where you can access collections of purchasable Products available on Violet through connected Merchants. The Violet [Catalog APIs](/api-reference/catalog/offers) provide developers with access to information such as product categories, product details, and individual SKUs.

{% hint style="info" %}
The Violet Catalog is composed of what we call “Offers” which are product offerings from specific merchants. When you onboard a merchant through [Violet Connect](/prism/violet-connect), we sync the product data from their e-commerce platform catalog and create a unified model that you can interact with to power your experiences.
{% endhint %}

You can learn more about Offers, SKUs, and Categories in the following pages and interact with the Violet Catalog through our [suite of APIs](/api-reference/catalog/offers).


# Offers

An Offer in Violet refers to a specific product offered by a merchant. While some platforms use the term "Products," we have chosen to use the term "Offer" to refer to these products. Offers are used to provide detailed information about specific aspects of a product, including variations. Each combination of these variations is referred to as a SKU, which is also included in the Offer object.

Each Offer in Violet has a unique Offer ID, which allows for easy identification of individual offers. An offer also has an External ID, which is the ID assigned by the e-commerce platform.

Every Offer includes nested data for each individual SKU available from the merchant. Violet provides SKUs as part of the Offer response, allowing you to use them to populate your Product Detail Page (PDP) with all available variants. Additionally, the Offer includes the Merchant ID and structured media albums.

You can interact with our Offer model using our [Catalog APIs](/api-reference/catalog/offers), and a sample `Offer` can be seen below:

<details>

<summary>Sample Response</summary>

```json
{
    "id": 39041,
    "product_id": "206bc004966b4883a737d7ec1f25c557",
    "external_id": "8335219130669",
    "external_url": "https://the-violet-garden.myshopify.com/products/dancing-sneaker-green",
    "name": "Dancing Sneaker Green",
    "description": "Dancing sneakers in a beautiful green.",
    "html_description": "<p>Dancing sneakers in a beautiful green.</p>",
    "source": "SHOPIFY",
    "seller": "the violet garden",
    "vendor": "The Violet Garden",
    "merchant_id": 10189,
    "available": true,
    "visible": true,
    "min_price": 13500,
    "max_price": 13500,
    "currency": "USD",
    "source_category_name": "",
    "meta": [],
    "variants": [
        {
            "id": 858860,
            "external_id": "10558450303277",
            "name": "Style",
            "visual": true,
            "values": [
                {
                    "id": 6049067,
                    "external_id": "Design Two",
                    "name": "Design Two",
                    "sku_ids": [
                        196611,
                        196598,
                        196602,
                        196600,
                        196616,
                        196606
                    ],
                    "display_order": 2
                },
                {
                    "id": 6049070,
                    "external_id": "Design One",
                    "name": "Design One",
                    "sku_ids": [
                        196609,
                        196613,
                        196597,
                        196612,
                        196601,
                        196605
                    ],
                    "display_order": 1
                },
                {
                    "id": 6049069,
                    "external_id": "Design Four",
                    "name": "Design Four",
                    "sku_ids": [
                        196595,
                        196599,
                        196596,
                        196603,
                        196607,
                        196604
                    ],
                    "display_order": 4
                },
                {
                    "id": 6049068,
                    "external_id": "Design Three",
                    "name": "Design Three",
                    "sku_ids": [
                        196594,
                        196610,
                        196608,
                        196593,
                        196615,
                        196614
                    ],
                    "display_order": 3
                }
            ],
            "display_order": 2
        },
        {
            "id": 858861,
            "external_id": "10558450270509",
            "name": "Size",
            "visual": false,
            "values": [
                {
                    "id": 6049076,
                    "external_id": "43",
                    "name": "43",
                    "sku_ids": [
                        196614,
                        196597,
                        196600,
                        196604
                    ],
                    "display_order": 6
                },
                {
                    "id": 6049071,
                    "external_id": "38",
                    "name": "38",
                    "sku_ids": [
                        196594,
                        196602,
                        196601,
                        196607
                    ],
                    "display_order": 1
                },
                {
                    "id": 6049074,
                    "external_id": "41",
                    "name": "41",
                    "sku_ids": [
                        196609,
                        196608,
                        196598,
                        196599
                    ],
                    "display_order": 4
                },
                {
                    "id": 6049075,
                    "external_id": "42",
                    "name": "42",
                    "sku_ids": [
                        196610,
                        196613,
                        196596,
                        196616
                    ],
                    "display_order": 5
                },
                {
                    "id": 6049073,
                    "external_id": "40",
                    "name": "40",
                    "sku_ids": [
                        196615,
                        196603,
                        196606,
                        196605
                    ],
                    "display_order": 3
                },
                {
                    "id": 6049072,
                    "external_id": "39",
                    "name": "39",
                    "sku_ids": [
                        196611,
                        196595,
                        196593,
                        196612
                    ],
                    "display_order": 2
                }
            ],
            "display_order": 1
        }
    ],
    "skus": [
        {
            "id": 196603,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101326008621",
            "name": "Dancing Sneaker Green - 40 / Design Four",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91022,
                    "parent_id": 196603,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 40 / Design Four Media",
                    "media": [
                        {
                            "id": 185738,
                            "album_id": 91022,
                            "external_id": "41484160827693",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185738,
                        "album_id": 91022,
                        "external_id": "41484160827693",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Size",
                    "value": "40"
                },
                {
                    "variant": "Style",
                    "value": "Design Four"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196614,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101326401837",
            "name": "Dancing Sneaker Green - 43 / Design Three",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91033,
                    "parent_id": 196614,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 43 / Design Three Media",
                    "media": [
                        {
                            "id": 185749,
                            "album_id": 91033,
                            "external_id": "41484160958765",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185749,
                        "album_id": 91033,
                        "external_id": "41484160958765",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Three"
                },
                {
                    "variant": "Size",
                    "value": "43"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:24+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196599,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101326139693",
            "name": "Dancing Sneaker Green - 41 / Design Four",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91018,
                    "parent_id": 196599,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 41 / Design Four Media",
                    "media": [
                        {
                            "id": 185734,
                            "album_id": 91018,
                            "external_id": "41484160827693",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185734,
                        "album_id": 91018,
                        "external_id": "41484160827693",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Four"
                },
                {
                    "variant": "Size",
                    "value": "41"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196616,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101326205229",
            "name": "Dancing Sneaker Green - 42 / Design Two",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91035,
                    "parent_id": 196616,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 42 / Design Two Media",
                    "media": [
                        {
                            "id": 185751,
                            "album_id": 91035,
                            "external_id": "41484160860461",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185751,
                        "album_id": 91035,
                        "external_id": "41484160860461",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Two"
                },
                {
                    "variant": "Size",
                    "value": "42"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:24+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196597,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101326303533",
            "name": "Dancing Sneaker Green - 43 / Design One",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91016,
                    "parent_id": 196597,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 43 / Design One Media",
                    "media": [
                        {
                            "id": 185732,
                            "album_id": 91016,
                            "external_id": "41484161155373",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185732,
                        "album_id": 91016,
                        "external_id": "41484161155373",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design One"
                },
                {
                    "variant": "Size",
                    "value": "43"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196602,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101325648173",
            "name": "Dancing Sneaker Green - 38 / Design Two",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91021,
                    "parent_id": 196602,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 38 / Design Two Media",
                    "media": [
                        {
                            "id": 185737,
                            "album_id": 91021,
                            "external_id": "41484160860461",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185737,
                        "album_id": 91021,
                        "external_id": "41484160860461",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Size",
                    "value": "38"
                },
                {
                    "variant": "Style",
                    "value": "Design Two"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196604,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101326467373",
            "name": "Dancing Sneaker Green - 43 / Design Four",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91023,
                    "parent_id": 196604,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 43 / Design Four Media",
                    "media": [
                        {
                            "id": 185739,
                            "album_id": 91023,
                            "external_id": "41484160827693",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185739,
                        "album_id": 91023,
                        "external_id": "41484160827693",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Four"
                },
                {
                    "variant": "Size",
                    "value": "43"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196609,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101326041389",
            "name": "Dancing Sneaker Green - 41 / Design One",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91028,
                    "parent_id": 196609,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 41 / Design One Media",
                    "media": [
                        {
                            "id": 185744,
                            "album_id": 91028,
                            "external_id": "41484161155373",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185744,
                        "album_id": 91028,
                        "external_id": "41484161155373",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design One"
                },
                {
                    "variant": "Size",
                    "value": "41"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:24+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196598,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101326074157",
            "name": "Dancing Sneaker Green - 41 / Design Two",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91017,
                    "parent_id": 196598,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 41 / Design Two Media",
                    "media": [
                        {
                            "id": 185733,
                            "album_id": 91017,
                            "external_id": "41484160860461",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185733,
                        "album_id": 91017,
                        "external_id": "41484160860461",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Two"
                },
                {
                    "variant": "Size",
                    "value": "41"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196600,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101326336301",
            "name": "Dancing Sneaker Green - 43 / Design Two",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91019,
                    "parent_id": 196600,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 43 / Design Two Media",
                    "media": [
                        {
                            "id": 185735,
                            "album_id": 91019,
                            "external_id": "41484160860461",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185735,
                        "album_id": 91019,
                        "external_id": "41484160860461",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Two"
                },
                {
                    "variant": "Size",
                    "value": "43"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196595,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101325877549",
            "name": "Dancing Sneaker Green - 39 / Design Four",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 9,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91014,
                    "parent_id": 196595,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 39 / Design Four Media",
                    "media": [
                        {
                            "id": 185730,
                            "album_id": 91014,
                            "external_id": "41484160827693",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185730,
                        "album_id": 91014,
                        "external_id": "41484160827693",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Size",
                    "value": "39"
                },
                {
                    "variant": "Style",
                    "value": "Design Four"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196605,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101325910317",
            "name": "Dancing Sneaker Green - 40 / Design One",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91024,
                    "parent_id": 196605,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 40 / Design One Media",
                    "media": [
                        {
                            "id": 185740,
                            "album_id": 91024,
                            "external_id": "41484161155373",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185740,
                        "album_id": 91024,
                        "external_id": "41484161155373",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design One"
                },
                {
                    "variant": "Size",
                    "value": "40"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196601,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101325615405",
            "name": "Dancing Sneaker Green - 38 / Design One",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91020,
                    "parent_id": 196601,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 38 / Design One Media",
                    "media": [
                        {
                            "id": 185736,
                            "album_id": 91020,
                            "external_id": "41484161155373",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185736,
                        "album_id": 91020,
                        "external_id": "41484161155373",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design One"
                },
                {
                    "variant": "Size",
                    "value": "38"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196611,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101325812013",
            "name": "Dancing Sneaker Green - 39 / Design Two",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91030,
                    "parent_id": 196611,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 39 / Design Two Media",
                    "media": [
                        {
                            "id": 185746,
                            "album_id": 91030,
                            "external_id": "41484160860461",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185746,
                        "album_id": 91030,
                        "external_id": "41484160860461",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Size",
                    "value": "39"
                },
                {
                    "variant": "Style",
                    "value": "Design Two"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:24+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196612,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101325779245",
            "name": "Dancing Sneaker Green - 39 / Design One",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 4,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91031,
                    "parent_id": 196612,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 39 / Design One Media",
                    "media": [
                        {
                            "id": 185747,
                            "album_id": 91031,
                            "external_id": "41484161155373",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185747,
                        "album_id": 91031,
                        "external_id": "41484161155373",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Size",
                    "value": "39"
                },
                {
                    "variant": "Style",
                    "value": "Design One"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:24+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196606,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101325943085",
            "name": "Dancing Sneaker Green - 40 / Design Two",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 8,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91025,
                    "parent_id": 196606,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 40 / Design Two Media",
                    "media": [
                        {
                            "id": 185741,
                            "album_id": 91025,
                            "external_id": "41484160860461",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185741,
                        "album_id": 91025,
                        "external_id": "41484160860461",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Size",
                    "value": "40"
                },
                {
                    "variant": "Style",
                    "value": "Design Two"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196610,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101326237997",
            "name": "Dancing Sneaker Green - 42 / Design Three",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91029,
                    "parent_id": 196610,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 42 / Design Three Media",
                    "media": [
                        {
                            "id": 185745,
                            "album_id": 91029,
                            "external_id": "41484160958765",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185745,
                        "album_id": 91029,
                        "external_id": "41484160958765",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Three"
                },
                {
                    "variant": "Size",
                    "value": "42"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:24+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196607,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101325713709",
            "name": "Dancing Sneaker Green - 38 / Design Four",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91026,
                    "parent_id": 196607,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 38 / Design Four Media",
                    "media": [
                        {
                            "id": 185742,
                            "album_id": 91026,
                            "external_id": "41484160827693",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185742,
                        "album_id": 91026,
                        "external_id": "41484160827693",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Size",
                    "value": "38"
                },
                {
                    "variant": "Style",
                    "value": "Design Four"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196613,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101326172461",
            "name": "Dancing Sneaker Green - 42 / Design One",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91032,
                    "parent_id": 196613,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 42 / Design One Media",
                    "media": [
                        {
                            "id": 185748,
                            "album_id": 91032,
                            "external_id": "41484161155373",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185748,
                        "album_id": 91032,
                        "external_id": "41484161155373",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design One"
                },
                {
                    "variant": "Size",
                    "value": "42"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:24+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196608,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101326106925",
            "name": "Dancing Sneaker Green - 41 / Design Three",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91027,
                    "parent_id": 196608,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 41 / Design Three Media",
                    "media": [
                        {
                            "id": 185743,
                            "album_id": 91027,
                            "external_id": "41484160958765",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185743,
                        "album_id": 91027,
                        "external_id": "41484160958765",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Three"
                },
                {
                    "variant": "Size",
                    "value": "41"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196594,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101325680941",
            "name": "Dancing Sneaker Green - 38 / Design Three",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91013,
                    "parent_id": 196594,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 38 / Design Three Media",
                    "media": [
                        {
                            "id": 185729,
                            "album_id": 91013,
                            "external_id": "41484160958765",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185729,
                        "album_id": 91013,
                        "external_id": "41484160958765",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Three"
                },
                {
                    "variant": "Size",
                    "value": "38"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196596,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101326270765",
            "name": "Dancing Sneaker Green - 42 / Design Four",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91015,
                    "parent_id": 196596,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 42 / Design Four Media",
                    "media": [
                        {
                            "id": 185731,
                            "album_id": 91015,
                            "external_id": "41484160827693",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185731,
                        "album_id": 91015,
                        "external_id": "41484160827693",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Four"
                },
                {
                    "variant": "Size",
                    "value": "42"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196593,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101325844781",
            "name": "Dancing Sneaker Green - 39 / Design Three",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 10,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91012,
                    "parent_id": 196593,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 39 / Design Three Media",
                    "media": [
                        {
                            "id": 185728,
                            "album_id": 91012,
                            "external_id": "41484160958765",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185728,
                        "album_id": 91012,
                        "external_id": "41484160958765",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Three"
                },
                {
                    "variant": "Size",
                    "value": "39"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:23+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        },
        {
            "id": 196615,
            "offer_id": 39041,
            "merchant_id": 10189,
            "external_id": "45101325975853",
            "name": "Dancing Sneaker Green - 40 / Design Three",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 9,
            "inventory_tracked": true,
            "sale_price": 13500,
            "retail_price": 13500,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 91034,
                    "parent_id": 196615,
                    "type": "SKU",
                    "name": "Dancing Sneaker Green - 40 / Design Three Media",
                    "media": [
                        {
                            "id": 185750,
                            "album_id": 91034,
                            "external_id": "41484160958765",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185750,
                        "album_id": 91034,
                        "external_id": "41484160958765",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Three"
                },
                {
                    "variant": "Size",
                    "value": "40"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:24+0000",
            "date_last_modified": "2023-08-07T15:02:53+0000",
            "sku_dimensions": {
                "weight": 3.0,
                "type": "SKU"
            }
        }
    ],
    "albums": [
        {
            "id": 90986,
            "parent_id": 39041,
            "type": "OFFER",
            "name": "Primary Album",
            "media": [
                {
                    "id": 185752,
                    "album_id": 90986,
                    "external_id": "41484161155373",
                    "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                    "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                    "type": "IMAGE",
                    "display_order": 1,
                    "primary": true
                },
                {
                    "id": 185753,
                    "album_id": 90986,
                    "external_id": "41484160958765",
                    "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                    "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_85d6d1fe-b49c-4d4b-97b6-0bef6815cfbb.png",
                    "type": "IMAGE",
                    "display_order": 3,
                    "primary": false
                },
                {
                    "id": 185755,
                    "album_id": 90986,
                    "external_id": "41484160860461",
                    "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                    "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_79f40a05-4ede-4cd0-ad76-4f301bf0aa57.png",
                    "type": "IMAGE",
                    "display_order": 2,
                    "primary": false
                },
                {
                    "id": 185677,
                    "album_id": 90986,
                    "external_id": "41484160925997",
                    "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_d793242c-e9da-4b37-844d-2636695bf4f8.png",
                    "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_d793242c-e9da-4b37-844d-2636695bf4f8.png",
                    "type": "IMAGE",
                    "display_order": 6,
                    "primary": false
                },
                {
                    "id": 185754,
                    "album_id": 90986,
                    "external_id": "41484160991533",
                    "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_a0b733cd-321a-4e85-b925-722b9bb8eb67.png",
                    "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_a0b733cd-321a-4e85-b925-722b9bb8eb67.png",
                    "type": "IMAGE",
                    "display_order": 4,
                    "primary": false
                },
                {
                    "id": 185678,
                    "album_id": 90986,
                    "external_id": "41484160827693",
                    "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                    "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_158776f7-2cd6-4c39-9c89-ab1a95924100.png",
                    "type": "IMAGE",
                    "display_order": 5,
                    "primary": false
                }
            ],
            "primary_media": {
                "id": 185752,
                "album_id": 90986,
                "external_id": "41484161155373",
                "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_shoes_floating_with_a_green_pastel_colour_6d8d2c39-c9b3-4943-a41e-0214bf0df19c.png",
                "type": "IMAGE",
                "display_order": 1,
                "primary": true
            }
        }
    ],
    "three_denabled": false,
    "type": "PHYSICAL",
    "status": "AVAILABLE",
    "publishing_status": "PUBLISHED",
    "date_created": "2023-05-01T20:08:23+0000",
    "date_last_modified": "2023-08-07T15:02:53+0000",
    "commission_rate": 25.0,
    "currency_symbol": "$",
    "subscription_status": "NOT_SUBSCRIBED",
    "tags": [
        "madebymidjourney"
    ]
}
```

</details>

{% hint style="info" %}
Generating a map of available SKUs for an individual offer across multiple variant types (such as color, size, etc.) can be a complex algorithm to implement correctly while integrating with Violet.
{% endhint %}

## Offer Descriptions

Offers may include two description fields to provide flexibility in how product descriptions are displayed:

* **`description`** - Plain text description, available for all offers
* **`html_description`** - HTML-formatted description, available for Shopify offers only

### Description Field Behavior

**For Shopify Offers:**

* Both `description` and `html_description` fields are populated
* `description` contains clean plain text with HTML tags stripped
* `html_description` preserves the original HTML formatting from Shopify

**For Non-Shopify Offers:**

* Only `description` is populated
* `html_description` will be `null`

### Implementation Guidelines

**Best Practices:**

* Always implement fallback logic to use `description` when `html_description` is `null`
* Check the platform type or `html_description` availability before attempting to render HTML content

For offers from other platforms, the `html_description` field would be `null`.

***

### Important Note on `html_description` Field (July 15, 2025)

As of July 15, 2025, Violet updated the behavior of the `html_description` field for Shopify offers. Previously, this field was populated with sanitized HTML content, which may have excluded certain formatting or embedded elements from the original Shopify product description. After this change, the `html_description` property now contains the raw HTML exactly as provided by Shopify, preserving all original formatting and markup.

This update enables more accurate rendering of product descriptions and improves parity with Shopify's own storefronts. However, it also means that the HTML may contain elements that were previously sanitized out.

If you observe that an offer's `html_description` appears incomplete or missing expected formatting, it may be due to the offer not having been updated or sold since the July 15, 2025 change. Some offers may still have the legacy, sanitized `html_description` value until they are next modified or resynced by Violet. See below for steps to resolve this.

{% hint style="info" %}
To manually re-sync an offer's `html_description`, go to the [Violet Channel dashboard](https://channel.violet.io/offers), locate the offer, and use the "Re-Sync Offer" action. This will immediately fetch the latest product description (including raw HTML) from Shopify.
{% endhint %}

***

### What statuses can be associated with an Offer?

* **`UNAVAILABLE`** This status for an offer means that the product associated with the offer is currently out of stock or not available for purchase. This status indicates that while the offer exists in the Violet system, it cannot be sold or purchased at the moment.
* **`AVAILABLE`** This status for an offer means that the product associated with the offer is currently in stock and ready for purchase.
* **`DISABLED_UNAVAILABLE`** This status indicates that an offer is currently disabled and the associated product is unavailable. This status typically occurs when a merchant's offers are disabled as a whole, and the underlying product was already unavailable or out of stock before the disablement.
* **`DISABLED_AVAILABLE`** This status means that an offer is currently disabled but the associated product is still available. This status typically occurs when a merchant's offers are disabled as a whole, but the underlying product remains in stock or available on the merchant's platform.
* **`FOR_DELETION`** This status means that an offer has been marked for eventual removal from the Violet system. This status typically occurs after an offer has been in the **`ARCHIVED`** state for an extended period.
* **`ARCHIVED`** This status means that a product has been deleted or removed from the merchant's platform, but Violet hasn't immediately deleted it from its system.

<details>

<summary>As a Channel, how should I interpret or act upon each status?</summary>

* **`UNAVAILABLE`** The channel would confirm with the merchant that the offer is correctly set up in their store, and if it is, they can use the dashboard to re-sync the offer. If there is still an issue after a re-sync, contacting support would be the next step.
* **`AVAILABLE`** Unless the offer should *not* be available, there is nothing needed here. The channel can re-sync an offer via the dashboard, and contact support if that doesn’t resolve the issue.
* **`DISABLED_UNAVAILABLE` / `DISABLED_AVAILABLE`** Both of the “disabled” statuses are due to a merchant being disabled, so a channel would need to handle that situation, first. They are also automatically updated when a merchant is disabled or re-enabled, so the channel would generally not need to do anything. If the status hasn’t be automatically updated, and the merchant’s status is enabled, then a re-sync via the dashboard should resolve the issue. Otherwise, raising a ticket to support would be the next step.
* **`FOR_DELETION`** Offers in this state were already in an **`ARCHIVED`** status for an extended period of time, and so likely the channel wouldn’t need to do anything here. If this is an error, a re-sync via the dashboard should fix it, else raising a ticket to support would be the next step.
* **`ARCHIVED`** The channel would need to confirm with the merchant, but given this happens when the offer is deleted on the merchant’s side, there is not really anything that can be done by the channel. While the merchant could recreate the product, it would show up in Violet as a new offer. Eventually, an archived offer would go into **`FOR_DELETION`** status to eventually be deleted.

</details>

<details>

<summary>As a Merchant, how should I interpret or act upon each status?</summary>

* **`UNAVAILABLE`** This indicates an inventory issue or a misconfigured product. (For example, a digital item likely wouldn’t have a quantity or be tracked by inventory, so checking its configuration can resolve an incorrect status.)
* **`AVAILABLE`** Unless this is a mistake, nothing needs to be done here. Otherwise, checking the item configuration or inventory stock should resolve it.
* **`DISABLED_UNAVAILABLE` / `DISABLED_AVAILABLE`** The merchant would need to resolve its own status in order to resolve the offer statuses.
* **`FOR_DELETION` / `ARCHIVED`** These are going to be due to the merchant deleting a product from their store so that its associated offer becomes archived. At this point, while the merchant could (re)create the product, a new offer would be created, instead, leaving the old one a stub which will eventually be deleted from Violet's system.

</details>

### What happens to an Offer when a merchant deletes the Product?

When a merchant deletes a product from their e-commerce platform, Violet does not immediately remove the associated Offer. Instead, the Offer is moved to an **`ARCHIVED`** status and preserved as a **snapshot of the Offer's final state** at the moment of deletion.

The SKUs on the Offer inherit the Offer's `ARCHIVED`/`FOR_DELETION` status, and which SKUs are captured in that snapshot depends on the state of the external product when it was deleted:

* If the merchant deletes the product while its variants still exist, the snapshot's Offer will still reflect **all SKUs** that existed on the external product at deletion time (each carrying the Offer's archived status).
* If the merchant deletes the external variants (SKUs) **before** deleting the external product, those SKUs are permanently removed from Violet first (see [SKUs](/prism/catalog/skus)), and so they will **not** be included in the Offer's final snapshot.

{% hint style="info" %}
The archived Offer is a point-in-time snapshot. It is not updated after the product is deleted. To understand which SKUs a shopper could have purchased, inspect the SKUs present on the archived Offer rather than assuming the full set that once existed on the merchant's platform.
{% endhint %}

***

## Data Inclusion

Certain Offer data is not returned by default in order to keep responses lean and performant. You can request additional data by providing the `?include=` query parameter with a comma-separated list of values. This parameter is supported on the [Get Offer by ID](/api-reference/catalog/offers/get-offer-by-id) and [Get All Merchant Offers](/api-reference/catalog/offers/get-all-merchant-offers) endpoints.

**Example:** `GET /catalog/offers/{offer_id}?include=metadata,shipping`

The following values are supported:

| Value          | Description                                                                                                                                                                                                                                                            |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `metadata`     | Additional metadata associated with the Offer. Returns an array of key-value pairs sourced from the merchant's e-commerce platform.                                                                                                                                    |
| `collections`  | Collections the Offer belongs to. Returns an array of collection objects including `name`, `handle`, `description`, and `status`.                                                                                                                                      |
| `shipping`     | **\[BETA]** Shipping data for the Offer. Returns available shipping methods, pricing, regional availability, and any conditions that must be met. Currently limited to Shopify merchants only. See [Offer Shipping Data](#offer-shipping-data) below for more details. |
| `sku_metadata` | Additional metadata at the SKU level. Returns an array of key-value pairs for each SKU within the Offer.                                                                                                                                                               |

{% hint style="info" %}
You can combine multiple include values in a single request using commas: `?include=metadata,collections,shipping,sku_metadata`
{% endhint %}

### Metadata

When `?include=metadata` is provided, the `metadata` field on the Offer will be populated with an array of `MetaObject` entries. Each entry contains a `key`, `value`, and `type` (e.g., `STRING`, `JSON`, `INTEGER`, `BOOLEAN`). Metadata is sourced from the merchant's e-commerce platform and can contain product-level custom fields such as care instructions, material composition, or vendor-specific attributes.

### Collections

When `?include=collections` is provided, the `collections` field on the Offer will be populated with the collections the Offer belongs to. Each collection includes an `id`, `name`, `handle`, `description`, `status`, and `type` (either `CUSTOM` or `AUTOMATED`).

### SKU Metadata

When `?include=sku_metadata` is provided, the `metadata` field on each SKU within the Offer will be populated. This works the same as Offer-level metadata but at the individual SKU level, allowing you to access variant-specific custom fields.

***

## Digital vs Physical Offers

Many items for sale these days are digital in nature and can be delivered to a shopper without requiring shipping. Violet uses the `type` field to denote if an Offer is physical and requires shipping or is digital.

This field follows the rules of the merchant's e-commerce platform to determine if a product is digital or if it is physical. This can differ by platform, but in the event that a product has an unexpected value in the `type` field,\
the merchant will need to go edit that product in their e-commerce platform to make sure it is correctly configured as digital or physical.

***

## Offer Shipping Data

Shipping data can now be populated on Offers for qualified Shopify merchants. This shipping data shows which shipping methods are available for each individual Offer and, if applicable, what requirements must be met to unlock a shipping method. This data can be especially useful for showing shoppers when an Offer has free shipping available.

{% hint style="info" %}
Shipping data is currently limited to the Offers sourced from merchants on the `SHOPIFY` platform.
{% endhint %}

**Enabling Shipping Data for a Merchants Offers**\
To enable the syncing of shipping data for a merchant you can toggle on the `sync_product_shipping` global feature flag. This can be done using the [Toggle Global Feature Flag](/api-reference/merchants/configuration/toggle-merchant-configuration-global-feature-flag#available-feature-flags) endpoint.

**Including Shipping Data with Offers**\
By default the shipping data will not be included when retreiving an Offer. This is to ensure that consumers of the Offer endpoints can choose when to include or exclude this data and to account for how it may impact performance. To include the shipping data simply provide the `?include=shipping` query param in your request. You can learn more about the `include` query param in the API Reference for the [Get Offer by ID](/api-reference/catalog/offers/get-offer-by-id) and [Get All Merchant Offers](/api-reference/catalog/offers/get-all-merchant-offers) endpoints.

**Shipping Data Parity**\
Obtaining per-product shipping data from Shopify is very expensive in terms of API rate limits. For this reason we cannot sync shipping data on every Offer update. Instead we will sync shipping data soon after it is first toggled for a merchant and/or when a merchants catalog is first synced. From there the shipping data will be resynced on a scheduled basis that is determined by the size of a merchants catalog. The smaller a merchants catalog is the more frequently the shipping data can be updated. Infrequent updates will likely not cause issues as merchants typically make changes to their per-product shipping configurations infrequently.

{% hint style="info" %}
You may not immediately see shipping data when it is first toggled on for a merchant. Our system will evaluate the merchants catalog and schedule it for processing in an upcoming sync.
{% endhint %}

If you need to resync the shipping data of a single Offer this can be done using the [Sync Offer](/api-reference/ecom-syncs/offers/sync-offer-by-id) endpoint. This will perform an immediate resync of the Offer and its associated shipping data.


# SKUs

### What is a SKU?

A SKU (Stock Keeping Unit) represents a specific, purchasable configuration of a product, such as a black pair of shoes in size 7. Shoppers cannot purchase an Offer directly; they must select a SKU, which is a distinct combination of variant options that represent an actual item.

### **Offers and SKUs**

Offers serve as the top-level category or wrapper in Violet's system. One Offer can contain multiple SKUs, sometimes just one, but in other cases, as many as 100 or more. This variability directly impacts the sizing and processing demands on our respective systems.

For example, an Offer may represent a t-shirt with variant options for COLOR and SIZE. The combination of the RED color variant option and the MEDIUM size variant option creates an individual SKU. Each distinct combination constitutes its own unique SKU.

### SKU Data

Each SKU has its own unique ID. SKU data includes specific details about a product, such as

* Quantity available (inventory)
* Pricing information
* Other product-specific attributes

While a SKU may carry a specific inventory quantity, that quantity is simply a data value within the SKU entity and is not included in the SKU count calculation.

You can access individual SKU data within the Offer Object, or retrieve data for a specific SKU by using its ID.

### Product Types

Both Offers and SKUs have a `type` property that indicates the nature of the product. The possible values are:

| Type       | Description                                                            |
| ---------- | ---------------------------------------------------------------------- |
| `PHYSICAL` | Traditional physical goods that require shipping and fulfillment       |
| `DIGITAL`  | Digital or downloadable products (e.g., e-books, software, gift cards) |
| `VIRTUAL`  | Virtual services or experiences that don't require physical delivery   |
| `BUNDLED`  | Bundle products that combine multiple items                            |

### Digital Product Delivery

When a shopper purchases a digital product (`type: "DIGITAL"`), the fulfillment process differs from physical goods:

* **No shipping method required**: Digital products do not require a shipping method. When all SKUs in a bag are digital, you should skip the shipping method selection during checkout.
* **Email delivery**: Digital products such as downloadable files, e-books, software licenses, and gift cards are delivered to the shopper via email. The merchant's e-commerce platform handles this delivery automatically after the order is completed. The email is sent to the customer email address associated with the order.
* **Instant fulfillment**: Unlike physical products that require shipping time, digital products are typically fulfilled immediately upon successful order completion.

{% hint style="info" %}
The delivery email content and format are controlled by the merchant's e-commerce platform settings. Violet does not modify or control the digital product delivery emails sent by merchants.
{% endhint %}

### **Keeping SKUs Updated**

It is essential to keep every SKU up to date. When a SKU is updated in the merchant's platform, a webhook typically notifies Violet's system so we can update the SKU accordingly. Violet doesn't create a new SKU for every update; instead, Violet stores a new version to ensure that inventory, pricing, and related details remain accurate for shoppers.

### **Deleted SKUs**

How a SKU is affected depends on whether the merchant deleted just the **variant** or the **entire product**:

* **The merchant deletes an individual variant (SKU).** The SKU is **permanently deleted** from Violet and simply removed from its parent Offer. It does not receive an archived or "marked for deletion" status of its own; it disappears from the Offer's SKU list entirely.
* **The merchant deletes the entire product.** The parent Offer is moved to an `ARCHIVED` (and eventually `FOR_DELETION`) status, and its SKUs **inherit that same status** from the Offer. In this case a SKU *can* be seen in an `ARCHIVED` or `FOR_DELETION` state, but only because its parent Offer was set into that state.

{% hint style="warning" %}
If a channel no longer sees a SKU listed under an Offer that it previously appeared on, it means the merchant has **permanently deleted** that individual SKU from their store. The SKU will not return unless the merchant recreates it, in which case it would come back as a new SKU with a new ID.
{% endhint %}

Because individual SKU deletions are not surfaced through a dedicated webhook event, you'll typically detect a removed SKU either by comparing the SKUs on the Offer against a previously stored copy, or by handling the [`OFFER_UPDATED`](/prism/webhooks/events/offer-webhooks) event that fires when an Offer's SKUs change.

Here is an example of a SKU as part of the Offer object:

<details>

<summary>SKU as part of Offer</summary>

```json
{
    "id": 39045,
    "product_id": "8d8c749c469b45e795f458360e2fc4be",
    "external_id": "8335172993325",
    "external_url": "https://the-violet-garden.myshopify.com/products/rouge-fire-flower-t-shirt",
    "name": "Shirt",
    "description": "Pastel-red flower design, short-sleeved t-shirt. Designed to keep you cool when you need to be cool and hot when you need to be hot. This shirt looks great on a sunny day under a blue sky.",
    "source": "SHOPIFY",
    "seller": "the violet garden",
    "vendor": "The Violet Garden",
    "merchant_id": 10189,
    "available": true,
    "visible": true,
    "min_price": 3000,
    "max_price": 3000,
    "currency": "USD",
    "source_category_name": "",
    "meta": [],
    "variants": [ ... ],
    "skus": [
        {
            "id": 196701,
            "offer_id": 39045,
            "merchant_id": 10189,
            "external_id": "45101095092525",
            "name": "Shirt - Large / Design Three / Red",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 100,
            "inventory_tracked": true,
            "sale_price": 3000,
            "retail_price": 3000,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Three"
                },
                {
                    "variant": "Size",
                    "value": "Large"
                },
                {
                    "variant": "Color",
                    "value": "Red"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:25+0000",
            "date_last_modified": "2023-06-29T23:58:33+0000",
            "sku_dimensions": {
                "weight": 0.0,
                "type": "SKU"
            }
        },
        {
            "id": 196697,
            "offer_id": 39045,
            "merchant_id": 10189,
            "external_id": "45101095059757",
            "name": "Shirt - Large / Design Two / Red",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 100,
            "inventory_tracked": true,
            "sale_price": 3000,
            "retail_price": 3000,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [],
            "variant_values": [
                {
                    "variant": "Size",
                    "value": "Large"
                },
                {
                    "variant": "Color",
                    "value": "Red"
                },
                {
                    "variant": "Style",
                    "value": "Design Two"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:25+0000",
            "date_last_modified": "2023-06-29T23:58:33+0000",
            "sku_dimensions": {
                "weight": 0.0,
                "type": "SKU"
            }
        },
        {
            "id": 196705,
            "offer_id": 39045,
            "merchant_id": 10189,
            "external_id": "45101094797613",
            "name": "Shirt - Small / Design Two / Red",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 99,
            "inventory_tracked": true,
            "sale_price": 3000,
            "retail_price": 3000,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [
                {
                    "id": 90993,
                    "parent_id": 196705,
                    "type": "SKU",
                    "name": "Rouge Fire Flower T-Shirt - Small / Design Two Media",
                    "media": [
                        {
                            "id": 185704,
                            "album_id": 90993,
                            "external_id": "41483613471021",
                            "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_b6d58e24-200e-42b9-86c4-8feeaf4bc8e6.png",
                            "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_b6d58e24-200e-42b9-86c4-8feeaf4bc8e6.png",
                            "type": "IMAGE",
                            "display_order": 1,
                            "primary": true
                        }
                    ],
                    "primary_media": {
                        "id": 185704,
                        "album_id": 90993,
                        "external_id": "41483613471021",
                        "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_b6d58e24-200e-42b9-86c4-8feeaf4bc8e6.png",
                        "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_b6d58e24-200e-42b9-86c4-8feeaf4bc8e6.png",
                        "type": "IMAGE",
                        "display_order": 1,
                        "primary": true
                    }
                }
            ],
            "variant_values": [
                {
                    "variant": "Size",
                    "value": "Small"
                },
                {
                    "variant": "Color",
                    "value": "Red"
                },
                {
                    "variant": "Style",
                    "value": "Design Two"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:25+0000",
            "date_last_modified": "2023-06-29T23:58:33+0000",
            "sku_dimensions": {
                "weight": 0.0,
                "type": "SKU"
            }
        },
        ...
    ],
    "albums": [
        {
            "id": 90990,
            "parent_id": 39045,
            "type": "OFFER",
            "name": "Primary Album",
            "media": [
                {
                    "id": 185779,
                    "album_id": 90990,
                    "external_id": "41483613339949",
                    "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_e963dc9b-12e7-4b1e-96bb-97dc1b061cbc.png",
                    "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_e963dc9b-12e7-4b1e-96bb-97dc1b061cbc.png",
                    "type": "IMAGE",
                    "display_order": 1,
                    "primary": true
                },
                {
                    "id": 185780,
                    "album_id": 90990,
                    "external_id": "41483613405485",
                    "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_a80ec00e-eae1-41e4-8d6b-81c64bbc8f52.png",
                    "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_a80ec00e-eae1-41e4-8d6b-81c64bbc8f52.png",
                    "type": "IMAGE",
                    "display_order": 2,
                    "primary": false
                },
                {
                    "id": 185781,
                    "album_id": 90990,
                    "external_id": "41483613274413",
                    "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/grid_0.webp",
                    "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/grid_0.webp",
                    "type": "IMAGE",
                    "display_order": 3,
                    "primary": false
                },
                {
                    "id": 185782,
                    "album_id": 90990,
                    "external_id": "41483613372717",
                    "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_d2f90fab-7ac4-4161-b710-5363f1b4e244.png",
                    "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_d2f90fab-7ac4-4161-b710-5363f1b4e244.png",
                    "type": "IMAGE",
                    "display_order": 5,
                    "primary": false
                },
                {
                    "id": 185783,
                    "album_id": 90990,
                    "external_id": "41483613438253",
                    "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_d90ec5f7-a1a7-43c6-bdf9-38f7ff5764b9_1.png",
                    "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_d90ec5f7-a1a7-43c6-bdf9-38f7ff5764b9_1.png",
                    "type": "IMAGE",
                    "display_order": 6,
                    "primary": false
                },
                {
                    "id": 185778,
                    "album_id": 90990,
                    "external_id": "41483613471021",
                    "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_b6d58e24-200e-42b9-86c4-8feeaf4bc8e6.png",
                    "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_b6d58e24-200e-42b9-86c4-8feeaf4bc8e6.png",
                    "type": "IMAGE",
                    "display_order": 4,
                    "primary": false
                }
            ],
            "primary_media": {
                "id": 185779,
                "album_id": 90990,
                "external_id": "41483613339949",
                "url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_e963dc9b-12e7-4b1e-96bb-97dc1b061cbc.png",
                "source_url": "https://cdn.shopify.com/s/files/1/0758/9363/7421/files/wealthy_floral_design_tshirt_with_a_red_pastel_colour_backgroun_e963dc9b-12e7-4b1e-96bb-97dc1b061cbc.png",
                "type": "IMAGE",
                "display_order": 1,
                "primary": true
            }
        }
    ],
    "three_denabled": false,
    "type": "PHYSICAL",
    "status": "AVAILABLE",
    "publishing_status": "PUBLISHED",
    "date_created": "2023-05-01T20:08:25+0000",
    "date_last_modified": "2023-06-29T23:58:33+0000",
    "commission_rate": 25.0,
    "currency_symbol": "$",
    "subscription_status": "NOT_SUBSCRIBED",
    "tags": [
        "madebymidjourney"
    ]
}
```

</details>

Here is an example of a SKU object in isolation:

<details>

<summary>SKU JSON</summary>

```json
{
            "id": 196701,
            "offer_id": 39045,
            "merchant_id": 10189,
            "external_id": "45101095092525",
            "name": "Shirt - Large / Design Three / Red",
            "gtin": "",
            "upc": "",
            "in_stock": true,
            "qty_available": 100,
            "inventory_tracked": true,
            "sale_price": 3000,
            "retail_price": 3000,
            "currency": "USD",
            "taxable": true,
            "tax_type": "DEFAULT",
            "albums": [],
            "variant_values": [
                {
                    "variant": "Style",
                    "value": "Design Three"
                },
                {
                    "variant": "Size",
                    "value": "Large"
                },
                {
                    "variant": "Color",
                    "value": "Red"
                }
            ],
            "type": "PHYSICAL",
            "status": "AVAILABLE",
            "date_created": "2023-05-01T20:08:25+0000",
            "date_last_modified": "2023-06-29T23:58:33+0000",
            "sku_dimensions": {
                "weight": 0.0,
                "type": "SKU"
            }
        }
```

</details>

You can learn more about how to interact with SKUs in our [API Reference](/api-reference/catalog/skus/get-sku-by-id).


# Categories

We’ve all been on an ecommerce site and browsed products according to a category: Shirts, Jackets, Pants, etc. The primary structure for category data models on the internet today is the [Google Product Taxonomy](https://www.google.com/basepages/producttype/taxonomy.en-US.txt). Categories in Violet are based on the Google Product Taxonomy, with a few updates for areas that could use more specificity.

## Syncing Categories

Upon connecting a Store, Violet syncs with the Merchant’s catalog. When syncing, Violet pulls in category data that exists the ecommerce platform.

{% hint style="warning" %}
Category data can lack consistency. Please read the ‘Limitations’ section below to make sure this is accounted for you in your experience.
{% endhint %}

## Limitations

**Data Availability**

Data coming from Violet is a reflection of the data coming from a Merchant. If a Merchant hasn't entered categories for their products, there would be no data for Violet to consume and pass along for us in your application. Availability of category data is a common problem and something to watch out for as you construct your own category experience.

**Data Structure**

While the most common data model is the Google Product Taxonomy, there is still a lot of variability within the models used by Merchants. As a result, some category data may not map to anything in the Google Taxonomy at all, or may be subject to linguistic or cultural nuances in which the Merchant specializes. Cleanliness of category data is a common problem and something to watch out for as you construct your own category experience.

## Categories via API

You can use the [Get Categories](/api-reference/catalog/categories/get-categories) API to retrieve all categories that your products fall into. You can read more about our Category endpoints in the API Reference.

{% hint style="info" %}
You may also want to include the taxonomy tree in the Offer data you retrieve, instead of through dedicated APIs. To do this, you can include the following header in the request: `X-Violet-Api-Features: include-offer-taxonomy`.

If the merchant uses category names that map to Google’s taxonomy names we will include the full taxonomy tree in a new `categories:[]` property on the Offer object.

This currently works with the following endpoints:

`GET offers/{offer_id}`

`GET offers/merchants/{merchant_id}`
{% endhint %}


# Collections

{% hint style="warning" %}
The collections sync feature is not enabled by default. If you plan to use it with a Merchant, you can use [this endpoint](/api-reference/merchants/configuration/toggle-merchant-configuration-global-feature-flag) to enable collection syncs for that Merchant.
{% endhint %}

Offer collections refer to curated groups or sets of offers that share common characteristics, themes, or purposes. Merchants often create offer collections to enhance the shopping experience for customers and to organize their inventory more effectively. These collections can be based on various criteria, such as product type, seasonality, trends, or specific themes.

Each `Collection` in Violet has a unique Collection ID, which allows for easy identification of individual collections. A `Collection` also has an `ExternalID`, which is the ID assigned by the e-commerce platform.

You can interact with our `Collection` model using our [Catalog APIs](/api-reference/catalog/collections/get-collection-by-id).

### Types

There are 2 types of collections:

#### CUSTOM

Manually curated by merchants. The merchant needs to select each offer inside the collection.

#### AUTOMATED

Automatically curated by the platform given a set of rules. The platform is responsible for selecting the offers inside the collection. Eg.: Offers that contain blue in the title.

### Supported Platforms

* Shopify

### Syncing Collections

Once a store is connected and collection sync is enabled, Violet will sync with the Merchant’s collections on a daily basis. This frequency can be adjusted as needed, by request.


# Metadata

{% hint style="info" %}
**Enabling Metadata Syncing**

The syncing of Product metadata and Sku metadata can be enabled on a per-merchant basis using the [Toggle Global Feature Flag](/api-reference/merchants/configuration/toggle-merchant-configuration-global-feature-flag) endpoint in the Merchant Configuration API. Offer metadata and Sku metadata must be enabled separately.
{% endhint %}

Offer and Sku metadata allows for the custom data that merchants have applied to their products to be surfaced with the Violet Offer and Sku objects. It is currently only enabled on a per-merchant basis as most commerce platforms (including Shopify) require additional API calls to be made in order to access metadata. By enabling metadata on a per-merchant basis we can ensure that the sync performance is not degraded for merchants who don’t utilize metadata.

***

## Schema

When present, metadata will be available in the `metadata` property of an `Offer` or `Sku` object.

<details>

<summary>Example Metadata as part of Offer of Sku</summary>

```json
{
  ...
  "metadata": [{
    "version": 1.0,
    "type": "STRING",
    "external_type": "single_line_text_field",
    "key": "region",
    "value": "US",
    "source": "EXTERNAL"
  }]
  ...
}
```

</details>

`version` - the schema version for the metadata (all will be `1.0` at this time)

`type` - `STRING | JSON | INTEGER | LONG | DECIMAL | BOOLEAN`

`external_type` - raw value type from the external commerce platform

`key` - the key or name that represents the data

`value` - the value of the data

`source` - `INTERNAL | EXTERNAL` (all metadata is `EXTERNAL` at this time)

When the `type` property has a value of `JSON` the `value` property will consist of a serialized JSON string.

<details>

<summary>JSON Example</summary>

```json
{
  ...
  "metadata": [{
    "version": 1.0,
    "type": "JSON",
    "external_type": "json",
    "key": "json_example",
    "value": "{\"key\":\"value\"}",
    "source": "EXTERNAL"
  }]
  ...
}
```

</details>

***

## Including Offer Metadata

By default, Offer metadata is not included in the Offer data returned by the Violet API. To include metadata, you must add an `include` query parameter with a value that contains `metadata`.

Example - `?include=metadata`

This feature works with the following endpoints:

* [Get All Merchant Offers](/api-reference/catalog/offers/get-all-merchant-offers)
* [Get Offer By Id](/api-reference/catalog/offers/get-offer-by-id)

## Including Sku Metadata

By default, Sku metadata is not included in the Sku data returned by the Violet API. To include metadata, you must add an `include` query parameter with a value that contains `sku_metadata`.

Example - `?include=sku_metadata`

This feature works with the following endpoints:

* [Get All Merchant Offers](/api-reference/catalog/offers/get-all-merchant-offers)
* [Get Offer By Id](/api-reference/catalog/offers/get-offer-by-id)
* [Get Sku By Id](/api-reference/catalog/skus/get-sku-by-id)

***

## Supported Platforms

At this time metadata is limited to merchants on the `SHOPIFY` platform. Support for additional platforms is currently in development.

## Metadata Parity

Once a store is connected and metadata sync is enabled, Violet will sync with the Merchant’s metadata regularly.


# Syncing SKU Metadata

This guide provides a detailed walkthrough for enabling and utilizing SKU metadata through the Violet API. Metadata provides custom data applied by merchants to their products and is accessible through the Violet Offer and SKU objects. By following this guide, you will be able to enable SKU metadata syncing and include it in your API responses.

***

## **Step 1: Enable Metadata Syncing**

To enable the syncing of SKU metadata, you must use the **Toggle Global Feature Flag** endpoint in the Merchant Configuration API. Metadata syncing must be enabled for each merchant individually to avoid performance issues for merchants that do not use metadata.

* **Endpoint**: [Toggle Global Feature Flag](/api-reference/merchants/configuration/toggle-merchant-configuration-global-feature-flag)
* **Feature Flag to Enable**: `sync_sku_metadata`
* **Default Value**: `false`

### **Example Request**

```json
POST /v1/merchants/{merchant_id}/configuration/global_feature_flags/sync_sku_metadata
{
  "enabled": true
}
```

### **Key Notes**

* Enabling this flag allows SKU metadata to be included during catalog syncing.
* Be aware that enabling this feature may increase the time it takes to sync a merchant's catalog, as additional API calls are required to access metadata.

***

## **Step 2: Adding Metadata to API Responses**

### **Including SKU Metadata in Responses**

By default, SKU metadata is not included in the API responses. To include metadata, use the `include` query parameter with the value `sku_metadata`.

* **Query Parameter**: `include`
* **Value**: `sku_metadata`

### **Example Request**

```
GET /v1/catalog/skus/{sku_id}?include=sku_metadata

```

### **Supported Endpoints**

The following endpoints support the inclusion of SKU metadata:

* [Get All Merchant Offers](/api-reference/catalog/offers/get-all-merchant-offers)
* [Get Offer By Id](/api-reference/catalog/offers/get-offer-by-id)
* [Get SKU By Id](/api-reference/catalog/skus/get-sku-by-id)

***

## **Step 3: Understanding Metadata Schema**

When SKU metadata is included in the API response, it will be provided in the `metadata` property of the `Sku` object. The metadata will include the following fields:

### **Metadata Fields**

* **`version`**: The schema version for the metadata (currently `1.0`).
* **`type`**: The type of metadata value (e.g., `STRING`, `JSON`, `INTEGER`, `BOOLEAN`).
* **`external_type`**: The raw value type from the external commerce platform.
* **`key`**: The key or name representing the metadata.
* **`value`**: The value of the metadata.
* **`source`**: Source of the metadata (`EXTERNAL` for all current metadata).

### **Example Metadata Object**

```json
{
  "version": "1.0",
  "type": "STRING",
  "external_type": "text",
  "key": "custom_label",
  "value": "Limited Edition",
  "source": "EXTERNAL"
}
```

### **Handling JSON Metadata**

If the `type` property is `JSON`, the `value` property will contain a serialized JSON string.

### **Example JSON Metadata**

```json
{
  "type": "JSON",
  "key": "product_details",
  "value": "{\\"color\\":\\"red\\",\\"size\\":\\"M\\"}"
}
```

***

## **Step 4: Testing and Validation**

### **Testing Metadata Inclusion**

After enabling metadata syncing and adding the appropriate query parameter (`include=sku_metadata`), test the API responses to ensure that metadata is included.

### **Validation Checklist**

* Verify that the `metadata` property is present in the response.
* Confirm that the metadata fields match the expected schema (e.g., `version`, `type`, `key`, and `value`).
* For JSON metadata, ensure that the `value` property contains a valid serialized JSON string.

***

## **Best Practices**

1. **Enable Metadata Only If Necessary**: Since enabling metadata increases the time required for catalog syncing, it should only be enabled for merchants who specifically require it.
2. **Test Thoroughly**: Before deploying changes, test the integration with all relevant endpoints to confirm that metadata is included and correctly formatted.
3. **Monitor Performance**: Keep track of sync performance for merchants with metadata enabled to ensure that the additional API calls do not significantly impact overall performance.

***

By following these steps, you can successfully implement SKU metadata using the Violet API and provide merchants with access to their custom product data.


# Media Transformations

Media Transformations allow you to resize offer media dynamically in the cloud, saving bandwidth and page load time when rendering PDPs

## Self Hosted Commerce Platforms

In an effort to reduce the impact on the systems of merchants using self-hosted commerce platforms we upload all of their Offer and Sku media to a Cloudinary CDN bucket. Once an image has been uploaded to the CDN, the `url` property on the media element will change to a Cloudinary URL. The original URL of the media can still be found in the `source_url` property of the media element.

Self Hosted Commerce Platforms Include:

* WooCommerce
* Magento / Adobe Commerce
* Prestashop
* Spree Commerce

## SaaS Commerce Platforms

The SaaS commerce platforms Violet is currently integrated with provide a CDN by default. At this time Violet does not upload the media from these platforms to our Cloudinary instance. Instead both the `url` and `source_url` property will reflect the original path to the CDN hosted version of the media provided directly by the commerce platform.

SaaS Commerce Platforms Include:

* BigCommerce
* Shopify
* Ecwid
* Swell
* Vendo
* SFCC
* Wix

## Transformations

Currently transformations are possible on some commerce platforms.

## Self Hosted Platforms

For self-hosted platform sourced media you can utilize the basic transformations made available Cloudinary. These include resizing and cropping.

To resize an image from a self-hosted platform, add or modify the `w_*,h_*` part of the media `url` which exists in the file path following the `/upload/` part of the file path. The values should be integers and represent pixels. The following path shows an image that has been resized to a width of `100` and a height of `150`:

`https://res.cloudinary.com/violetlocal/image/upload/w_100,h_150/v1691555244/offer_media/10116_16181_6456.jpg`

## Shopify

For Shopify sourced media you can utilize the built in transformations provided by the Shopify CDN. These include resizing and cropping.

To resize a Shopify image, add `width` and/or `height` query params to the end of the media `url`. The values should be integers and represent pixels. The following path shows a Shopify image that has been resized to a width of `100` and a height of `150`:

`https://cdn.shopify.com/static/sample-images/garnished.jpeg?width=100&height=150`

## Wix

For Shopify sourced media you can utilize the built in transformations provided by the Wix CDN. These include resizing and quality level.

To resize a Wix image, modify the `w_*,h_*` part of the media `url` which exists in the file path between `/fit/` and `/file.jpg`. The values should be integers and represent pixels. The following Wix path shows an image that has been resized to a width of `100` and a height of `150`: `https://static.wixstatic.com/media/3c76e2_5062e9cc9b3f45dd84ec9bc9dcedde63~mv2.jpg/v1/fit/w_100,h_150/file.jpg`

## Swell

For Swell sourced media you can utilize the built in transformations provided by the Swell CDN. These are currently limited to resizing.

To resize a Swell image, add `width` and/or `height` query params to the end of the media `url`. The values should be integers and represent pixels. The following path shows a Swell image that has been resized to a width of `100` and a height of `150`:

`https://cdn.schema.io/violet/620052bf11d803013dc8c608/2aea5722002ec20d566265a012a5f4f4?width=100&height=150`

## Vendo

Vendo utilizes Cloudinary for their media so the same transformation strategy used by the self-hosted commerce platforms can be used with Vendo.

To resize an image from Vendo, add or modify the `w_*,h_*` part of the media `url` which exists in the file path following the `/upload/` part of the file path. The values should be integers and represent pixels. The following path shows a Vendo image that has been resized to a width of `100` and a height of `150`:

`https://res-4.cloudinary.com/vendo-production/image/upload/c_limit,f_auto,h_150,q_auto,w_100/v1/11cf5801-f7c8-4b7a-aedc-12a9d20162df/KAWSHOLIDAYSPACEBlack_1_1024x1024_2x-1-1024x1024-1_tgaurp`

## Unsupported Platforms

The following platforms do not support transformations at this time. We are actively looking at ways to enable transformations on these platforms.

* BigCommerce
* Ecwid
* SFCC

Future functionality will allow you to provide your desired dimensions when querying offers and have any media returned in the response with the dimensions already applied to the URL regardless of platform.


# Contextual Pricing

Contextual prices are any prices that are explicitly defined using criteria such as a currency code or region. Using contextual prices a merchant can set prices on their products that override traditional exchange rates. The most common form of this is **presentment currencies**, where prices are explicitly defined on a product for various currencies instead of using traditional exchange rates.

### Supported Platforms

At this time contextual pricing is limited to merchants on the `SHOPIFY`, `BIGCOMMERCE`, and `COMMERCETOOLS` platforms. Support for additional platforms is currently in development.

### Enabling Contextual Pricing

The syncing and usage of contextual pricing can be enabled on a per-merchant basis using the [Toggle Global Feature Flag](/api-reference/merchants/configuration/toggle-merchant-configuration-global-feature-flag) endpoint in the Merchant Configuration API.

***

## Using Contextual Prices

When contextual prices are enabled for a merchant Violet will begin consuming any contextual prices during product syncs. These will be persisted internally and will not imemdiately impact the standard prices returned on a Violet Offer or Sku.

When using a endpoint that supports a "Base Currency" parameter, these presentment currencies will be activated if the base currency value provided by your request does not match the merchants default currency and if there is a presentment currency that matches the base currency you provided.

{% hint style="warning" %}
If a merchant does not have a presentment currency value that matches the provided base currency value then tranditional exchange rates will be used to calculate the prices.
{% endhint %}

### Catalog

Contextual pricing can be used with the following catalog endpoints.

#### Get Merchant Offers

When [retrieving paginated merchant offers](/api-reference/catalog/offers/get-all-merchant-offers) include the `base_currency` query parameter with your desired currency code as the value. Example: `?base_currency=USD`.

```bash
curl -L POST https://sandbox-api.violet.io/v1/catalog/offers/merchants/{merchant_id}?base_currency=USD \
-H "X-Violet-App-Id: your-app-id-here" \
-H "X-Violet-App-Secret: your-app-secret-here" \
-H "X-Violet-Token: your-token-here" \
-H "Content-type: application/json"
```

#### Get Offer by ID

When [retrieving an indivudual offer](/api-reference/catalog/offers/get-offer-by-id) include the `base_currency` query parameter with your desired currency code as the value. Example: `?base_currency=USD`.

```bash
curl -L POST https://sandbox-api.violet.io/v1/catalog/offers/{offer_id}?base_currency=USD \
-H "X-Violet-App-Id: your-app-id-here" \
-H "X-Violet-App-Secret: your-app-secret-here" \
-H "X-Violet-Token: your-token-here" \
-H "Content-type: application/json"
```

***

### Orders

Contextual pricing can be used with the following order endpoints.

#### Estimate Order

When [estimating a cart or order](/api-reference/orders-and-checkout/cart-pricing/estimate-cart) include the `base_currency` requst body parameter with your desired currency code as the value.

```bash
curl -L POST https://sandbox-api.violet.io/v1/carts/estimate \
-H "X-Violet-App-Id: your-app-id-here" \
-H "X-Violet-App-Secret: your-app-secret-here" \
-H "X-Violet-Token: your-token-here" \
-H "Content-type: application/json" \
-d '{
    "base_currency": "USD", // define your base currency here
    "skus": [
        {
            "sku_id": 11111,
            "quantity": 1
        }
    ],
    "shipping_address": {
        "city": "Seattle",
        "state": "WA",
        "country": "US",
        "postal_code": "98121",
        "phone": "1234567890",
        "address_1": "2815 Elliott Ave, Unit 100",
        "first_name": "Super",
        "last_name": "Mario"
    }
}'
```

#### Create Order

When [creating an order (Direct Order Submission)](/api-reference/orders-and-checkout/orders/create-order) include the `order[currency]` requst body parameter with your desired currency code as the value.

{% hint style="info" %}
The order will be written into the merchants system using this currency if the merchant has enabled this presentment currency in their store. If the merchant has not enabled this presentment currency the prices will be converted using real-time exchange rates and then written into the merchants systems using the merchants default currency.
{% endhint %}

```bash
curl -L POST https://sandbox-api.violet.io/v1/orders \
-H "X-Violet-App-Id: your-app-id-here" \
-H "X-Violet-App-Secret: your-app-secret-here" \
-H "X-Violet-Token: your-token-here" \
-H "Content-type: application/json" \
-d '{
  "payment_method": {
    "type": "SINGLE_USE_CARD_TOKEN",
    "payment_provider": "STRIPE",
    "token": "tok_i1s2h8a9nyg1ukrju12h31kj212kh"
  },
  "order": {
    "currency": "USD", // define your base currency here
    "app_order_id": "mario-test-1",
    "customer": {
      "first_name": "Super",
      "last_name": "Mario",
      "email": "super@mar.io"
    },
    "bags": [
      {
        "skus": [
          {
            "sku_id": 11111,
            "price": 9999
          }
        ],
        "shipping_method": {
          "carrier": "OTHER",
          "label": "Teleportation",
          "price": 999
        },
        "tax_total": 899
      }
    ],
    "shipping_address": {
        "city": "Seattle",
        "state": "WA",
        "country": "US",
        "postal_code": "98121",
        "phone": "1234567890",
        "address_1": "2815 Elliott Ave, Unit 100",
        "first_name": "Super",
        "last_name": "Mario"
    },
    "billing_address": {
        "city": "Seattle",
        "state": "WA",
        "country": "US",
        "postal_code": "98121",
        "phone": "1234567890",
        "address_1": "2815 Elliott Ave, Unit 100",
        "first_name": "Super",
        "last_name": "Mario"
    }
  }
}'
```

{% hint style="info" %}
If you have any questions regarding contextual pricing please reach out to your Violet account representative or submit a support ticket.
{% endhint %}


# Checkout

From creating a cart and adding products to shipping and delivery; Violet lets you power multi-merchant checkout natively in your experience through a unified API.

## Unified API

Our unified Checkout API gives you a single interface to use to read and write data to multiple third-party E-Commerce Platforms.

## Common Models

Violet integrates with a variety of E-Commerce platforms so you don't have to. We also unify the data models that you need to power Checkout, including Offers, SKUs, Carts, etc. so that you only need to manage your integration with us.

### Available Dashboards

#### [📈 Channel Dashboard](/resources/channel-dashboard)

Manage your Violet-connected merchants and control your settings all in one place. Through the Channel Dashboard you can:

* Monitor connected merchants
* Review orders and payouts
* Configure application settings

#### [🔲 Merchant Dashboard](/resources/merchant-dashboard)

Let your Violet-connected merchants control their payouts and product offerings. The Merchant Dashboard enables merchants to:

* Manage payout settings
* Configure product offerings


# Checkout Guides

This section provides a collection of guides to help you implement and manage the checkout process using Violet's APIs. From understanding order states to integrating with payment providers, these guides offer step-by-step instructions for various checkout scenarios.

### Available Guides

* [**Order and Bag States**](/prism/checkout-guides/guides/order-and-bag-states): Learn about the different states an order and bag can be in throughout the checkout lifecycle.
* [**Direct Order Submission**](/prism/checkout-guides/guides/direct-order-submission): A guide on how to submit an order directly without going through the iterative cart-building process.
* [**Utilizing Quick Checkout**](/prism/checkout-guides/guides/utilizing-quick-checkout): Discover how to streamline the checkout experience with Violet's Quick Checkout feature.
* [**Checkout with Stripe.js v3**](/prism/checkout-guides/guides/violet-checkout-with-stripejs-v3): Detailed instructions for integrating Stripe.js v3 for payment processing.
* [**Checkout with Apple Pay or Google Pay**](/prism/checkout-guides/guides/violet-checkout-with-apple-pay): Learn how to implement wallet-based payment options like Apple Pay and Google Pay.
* [**Tax Remittance**](/prism/checkout-guides/guides/tax-remittance): Understand how tax remittance is handled within the Violet ecosystem.
* [**Cross-Border Duties**](/prism/checkout-guides/guides/cross-border-duties): Learn how import duties flow through Violet's checkout and how to submit them on orders.
* [**Calculating Duties with Avalara**](/prism/checkout-guides/guides/calculating-duties-with-avalara): Use Avalara AvaTax Cross-Border to calculate import duties, then submit them on Violet orders.


# Order and Bag States

## **Purpose**

This document articulates the states and state changes within the Direct Order Submission checkout flow for both Orders and Bags, providing a comprehensive understanding of how entities transition through the checkout process.

## **Table of Contents**

1. [Overview](#overview)
2. [Order States](#order-states)
3. [Bag States](#bag-states)
4. [State Transition Flow](#state-transition-flow)
5. [State Change Triggers](#state-change-triggers)
6. [Error States and Recovery](#error-states-and-recovery)
7. [State Synchronization](#state-synchronization)

***

## **Overview**

In Violet's Direct Order Submission flow, the checkout process involves two primary entities:

* **Order**: The top-level entity representing the entire purchase
* **Bag**: A merchant-specific subset of the order containing SKUs from a single merchant

Each entity progresses through specific states during the checkout process, with state transitions triggered by system events and external responses. Violet doesn't use a traditional "pending" concept - orders transition quickly through states.

***

## **Order States**

### **1. `IN_PROGRESS`**

* **Description**: Order has not yet been submitted to ecom platform
* **Entry Condition**: Order/Cart creation
* **Duration**: Until submission is initiated
* **Next States**: `PROCESSING`

### **2. `PROCESSING`**

* **Description**: Brief millisecond status while being submitted to the merchant's e-commerce platform
* **Entry Condition**: Submit endpoint called
* **Duration**: Milliseconds
* **Next States**: `REQUIRES_ACTION`, or error

### **3. `ACCEPTED`**

* **Description**: Merchant's system successfully accepted the order
* **Entry Condition**: All bags accepted by merchants
* **Duration**: Brief transitional state
* **Next States**: `COMPLETED`, `CANCELED`

### **4. `REJECTED`**

* **Description**: Merchant's system failed to process the order
* **Entry Condition**: Critical failure during submission
* **Duration**: Terminal state
* **Next States**: None (terminal)

### **5. `COMPLETED`**

* **Description**: Violet has submitted the order as a whole
* **Entry Condition**: Order successfully processed and payment captured
* **Duration**: Terminal state (with exceptions)
* **Next States**: `CANCELED`

### **6. `CANCELED`**

* **Description**: Merchant chose to cancel after initially accepting
* **Entry Condition**: Cancellation request from merchant or channel
* **Duration**: Terminal state
* **Next States**: None (terminal)

### **7. `REQUIRES_ACTION`**

* **Description**: Order-level status requiring intervention (e.g., 3D Secure authentication)
* **Entry Condition**: Payment requires additional authentication
* **Duration**: Until shopper completes action
* **Next States**: `PROCESSING`, `CANCELED`

***

## **Bag States**

Individual bags within an order can have different statuses:

### **1. `IN_PROGRESS`**

* **Description**: Initial state upon creation until submission
* **Entry Condition**: Bag entity created when items added to cart
* **Duration**: Until order submission
* **Next States**: `SUBMITTED`

### **2. `SUBMITTED`**

* **Description**: Brief transitional state when submitted to merchant (usually moves quickly to ACCEPTED)
* **Entry Condition**: Order submission initiated
* **Duration**: Milliseconds to seconds
* **Next States**: `ACCEPTED`, `REJECTED`, `IN_PROGRESS` (on retryable failure)
* **Note**: For platforms without external carts, bags remain in this state longer to prevent duplicate submissions

### **3. `ACCEPTED`**

* **Description**: Successfully received by the e-commerce platform and visible in merchant's dashboard
* **Entry Condition**: Positive merchant response with external order ID
* **Duration**: Until fulfillment or post-submission changes
* **Next States**: `COMPLETED`, `CANCELED`, `REFUNDED`, `PARTIALLY_REFUNDED`

### **4. `COMPLETED`**

* **Description**: All fulfillments have been shipped; bag is finished except for potential refunds/returns
* **Entry Condition**: All items fulfilled by merchant
* **Duration**: Terminal state (with exceptions)
* **Next States**: `REFUNDED`, `PARTIALLY_REFUNDED`

### **5. `REFUNDED`**

* **Description**: All items returned and fully refunded
* **Entry Condition**: Full refund processed by merchant
* **Duration**: Terminal state
* **Next States**: None (terminal)

### **6. `PARTIALLY_REFUNDED`**

* **Description**: Some items returned and partially refunded
* **Entry Condition**: Partial refund processed by merchant
* **Duration**: Can be terminal or transition to REFUNDED
* **Next States**: `REFUNDED` (if remaining items refunded)

### **7. `CANCELED`**

* **Description**: Order canceled by merchant (doesn't trigger automatic refund)
* **Entry Condition**: Merchant-initiated cancellation
* **Duration**: Terminal state
* **Next States**: None (terminal)

### **8. `REJECTED`**

* **Description**: E-commerce platform rejected the bag (Violet retries before accepting this state)
* **Entry Condition**: Multiple failed submission attempts
* **Duration**: Terminal state
* **Next States**: None (terminal)

***

## **State Transition Flow**

### **Direct Order Submission Flow Sequence**

```
1. Order Created → Order: IN_PROGRESS
                → Bags: IN_PROGRESS (auto-created)
   ↓
2. Submit Order → Order: PROCESSING (milliseconds)
                → Bags: SUBMITTED (brief transition)
   ↓
3. Merchant Response:
   - Success → Bags: ACCEPTED
             → Order: PROCESSING
   - Failure → Bags: REJECTED (after retries)
             → Order: REJECTED
   - Retry → Bags: IN_PROGRESS (retryable failures)
   ↓
4. Payment Processing:
   - Requires 3DS → Order: REQUIRES_ACTION
   - Direct capture → Continue
   ↓
5. All Bags Accepted + Payment Success → Order: COMPLETED
                                      → Bags remain ACCEPTED
   ↓
6. Post-Submission States:
   - Fulfillment → Bags: COMPLETED
   - Full Refund → Bags: REFUNDED
   - Partial Refund → Bags: PARTIALLY_REFUNDED
   - Cancellation → Order: CANCELED
				      → Bags: CANCELED
```

### **Key State Relationships**

1. **During Submission**:
   * Order moves through `PROCESSING` very quickly (milliseconds)
   * Bags transition through `SUBMITTED` briefly
   * Order cannot be `COMPLETED` unless at least one bag is `ACCEPTED`
2. **Post-Submission**:
   * Bag states are managed by merchant platforms
   * Violet syncs state changes via webhooks and reconciliation.
   * Bags can have different states within the same order

***

## **State Change Triggers**

### **Order State Triggers**

| Current State        | Trigger Event              | New State            | Condition                                         |
| -------------------- | -------------------------- | -------------------- | ------------------------------------------------- |
| `IN_PROGRESS`        | Submit API called          | `PROCESSING`         | Valid cart data                                   |
| `PROCESSING`         | At least 1 bag is accepted | NONE                 | Stays in PROCESSING until payment is successful   |
| `PROCESSING`         | Any bag rejected           | `REJECTED`           | Critical failure after retries                    |
| `PROCESSING`         | Payment needs auth         | `REQUIRES_ACTION`    | 3DS or other authentication                       |
| `REQUIRES_ACTION`    | Auth completed             | `PROCESSING`         | Re-submission initiated                           |
| `PROCESSING`         | Payment captured           | `COMPLETED`          | At least 1 bag was capture AND successful payment |
| `COMPLETED`          | Merchant cancels           | `CANCELED`           | Post-acceptance cancellation                      |
| `COMPLETED`          | Full refund processed      | `REFUNDED`           | All bags refunded                                 |
| `COMPLETED`          | Partial refund processed   | `PARTIALLY_REFUNDED` | Some bags/SKUs refunded                           |
| `PARTIALLY_REFUNDED` | Remaining items refunded   | `REFUNDED`           | All items now refunded                            |

### **Bag State Triggers**

| Current State          | Trigger Event      | New State            | Condition                    |
| ---------------------- | ------------------ | -------------------- | ---------------------------- |
| `IN_PROGRESS`          | Order submitted    | `SUBMITTED`          | Request sent to merchant     |
| `SUBMITTED`            | Merchant accepts   | `ACCEPTED`           | Positive API response        |
| `SUBMITTED`            | Merchant rejects   | `IN_PROGRESS`        | Retryable error              |
| `SUBMITTED`            | Multiple failures  | `REJECTED`           | Non-retryable or max retries |
| `ACCEPTED`             | Items backordered  | `BACKORDERED`        | Platform supports backorders |
| `ACCEPTED`             | All items shipped  | `COMPLETED`          | Fulfillment complete         |
| `ACCEPTED`/`COMPLETED` | Full refund        | `REFUNDED`           | All items refunded           |
| `ACCEPTED`/`COMPLETED` | Partial refund     | `PARTIALLY_REFUNDED` | Some items refunded          |
| `PARTIALLY_REFUNDED`   | Remaining refunded | `REFUNDED`           | All items now refunded       |
| Any state              | Merchant cancels   | `CANCELED`           | Cancellation request         |

***

## **Error States and Recovery**

### **Error Handling in Order States**

1. **PROCESSING Failures**:
   * Violet automatically retries retryable failures
   * Bags return to `IN_PROGRESS` for retry attempts
   * After max retries, bags move to `REJECTED`
2. **REQUIRES\_ACTION Recovery**:
   * Re-render payment sheet with same `payment_intent_client_secret`
   * Resubmit order after action completed

### **Nested Error Object Structure when at least one Bag succeeds and a least one Bag fails.**

```json
{
  "errors": [
    {
      "id": 10153,
      "order_id": 10634,
      "bag_id": 10645,
      "entity_type": "BAG",
      "entity_id": "10645",
      "type": "EXTERNAL_SUBMISSION_FAILED",
      "message": "Merchant API returned error: Invalid shipping method",
      "external_platform": "SHOPIFY",
      "date_created": "2025-06-16T14:21:24+0000"
    }
  ]
}
```

### **Important: Always Check Errors Array**

A cart response can come back with status code 200 and still have errors in the errors field. This happens when some bags succeed while others fail.

***

## **State Synchronization**

### **Post-Submission Synchronization**

Once bags are accepted by merchants, state management is handled by the merchant platform. Violet tracks these changes and updates the bag in our system.

### **Key Synchronization Mechanisms**

1. **Webhooks**: Primary method for real-time updates
   * Order lifecycle events (fulfillment, refund, cancellation)
   * Merchant-initiated changes
   * State transitions
2. **Order Reconciliation**: For platforms with limited webhook support
   * Periodic status checks for bags in `ACCEPTED`, `COMPLETED`, `PARTIALLY_REFUNDED` state
   * Ensures no missed events
3. **Platform-Specific Handling**:
   * **Cartless Platforms**: Bags remain in `SUBMITTED` state longer to prevent duplicate submissions
   * Poll Get Cart by ID endpoint until status changes

### **Date Tracking**

* `date_created`: When order/bag was created
* `date_submitted`: When validation passed and submission began
* `date_last_modified`: On an Order, this timestamp is updated only when a property of the Order itself is modified. Some, but not all, Bag status updates will also modify the parent Order. To ensure you have the latest status, check the `date_last_modified` of the associated Bag entities if the Order's timestamp has not changed.
* `date_last_consolidated`: Last sync with merchant platform

### **State Consistency Rules**

1. **Order-Bag Consistency**
   * Order reflects aggregate bag states
   * Mixed bag states possible (some `ACCEPTED`, some `REJECTED`)
2. **Refund vs Cancellation vs Returns**
   * `CANCELED` state doesn't always automatically trigger refunds - refunds may need to be initiated separately by merchant
   * `REFUNDED`/`PARTIALLY_REFUNDED` states indicate actual refund processing has occurred
   * Returns can happen with or without refunds:
     * **Return + Refund**: `fulfillment_status` of `RETURNED` with `financial_status` of `REFUNDED`/`PARTIALLY_REFUNDED`
     * **Return Only**: `fulfillment_status` of `RETURNED` with `financial_status` remaining `PAID`
   * Use `fulfillment_status` to track physical item movement, `financial_status` to track monetary transactions
3. **Retry Logic**
   * Violet handles automatic retries for transient failures
   * Bags remains in `SUBMITTED` during retry attempts
   * Final `REJECTED` state only after all retries exhausted

***

## **Best Practices**

### **State Management**

1. **Handle Brief Transitional States**:
   * `PROCESSING` and `SUBMITTED` are millisecond states
   * Don't rely on catching these states in polling
2. **Error Handling**:
   * Always check `errors` array regardless of HTTP status
   * For single bag order failures check the exception message.
   * Implement appropriate retry logic for your use case
3. **Cancellation vs Refund**:
   * Understand that `CANCELED` doesn't mean refunded
   * Track refund states separately (`REFUNDED`, `PARTIALLY_REFUNDED`)
4. **Return and Refund Tracking:**
   * Check both `fulfillment_status` and `financial_status` to understand complete bag state
   * Don't assume `RETURNED` fulfillment means money was refunded
   * For exchange scenarios, look for `RETURNED` + `PAID` combination

### **Monitoring Recommendations**

1. **Track State Durations**:
   * Alert on bags stuck in `SUBMITTED`
   * Monitor for orders in `REQUIRES_ACTION`
2. **Handle Mixed States**:
   * Orders can have bags in different states
   * Implement UI to show per-merchant status
3. **Webhook Best Practices**:
   * Subscribe to all relevant webhooks
   * Implement webhook retry logic
   * Use reconciliation as backup for missed webhooks


# Direct Order Submission

Direct order submission enables channels who calculate their own tax and shipping rates to submit fully composed orders in a single request. For most commerce platforms, the prices you provide in the order submission request will override the built-in pricing engine of the platform. This ensure’s that the merchants system of record and automated customer communication (ex. order confirmation emails) remain accurate.

This guide goes through the steps needed to compose an Order and directly submit it to the merchant through Violet.

## **Retrieve SKUs from the Violet Catalog**

Retrieve SKUs you are able to sell through the [Violet Catalog APIs](/api-reference/catalog/offers/get-all-merchant-offers)

### Offer Publishing Status

The parent Offer of each SKU in the Order must be published to your app at the time of Order creation. This can be determined by examining the `publishing_status` on an Offer and ensuring that it has a value of `PUBLISHED`.\
If the Offer is not published to your app at the time of Order creation the following exception will be returned:

```json
{
  "message": "Sku identified by %s is currently not available for purchase due to offer not published.",
  "error": "offer_not_published",
  "code": 2011
}
```

## Capture Shopper Information

Capture Shopper information through your UI elements. At a minimum, you will need the following:

1. First Name
2. Last Name
3. Email
4. Shipping Address

You will need to submit this information as a part of the Create Order endpoint. Optionally, if "Billing Address" is different to the "Shipping Address", those details can also be added to the request body.

## Estimate Cart Prices

Estimate Cart prices using the [Estimate Cart](/api-reference/orders-and-checkout/cart-pricing/estimate-cart) endpoint. You will need to input the information that was previously collected from the Shopper.

{% hint style="info" %}
You can also include **discounts** in your Estimate Cart request to see their impact on pricing before creating an order. See the [Discounts section](#discounts) below for details.
{% endhint %}

<details>

<summary>Sample Request</summary>

```jsx
POST /carts/estimate

{
  "base_currency": "USD",
  "skus": [
    {
      "quantity": 2,
      "sku_id": 123
    }
  ],
  "shipping_address": {
    "city": "Seattle",
    "state": "WA",
    "postal_code": "<string>",
    "country": "US",
    "address_1": "<string>",
    "address_2": "<string>"
  }
```

</details>

<details>

<summary>Sample Response</summary>

```jsx
{
  "estimated_carts": [
    {
      "merchant_id": 123,
      "platform": "SHOPIFY",
      "base_currency": "USD",
      "sub_total": 1,
      "shipping_total": 1,
      "discount_total": 1,
      "total": 1,
      "skus": [
        {
          "quantity": 1,
          "sku_id": 80455,
          "name": "Lunar Lemonade - 10 oz.",
          "price": 9999,
          "merchant_id": 10064,
          "external_id": "42519630413999",
          "available": true,
          "requires_shipping": true,
          "product_type": "PHYSICAL",
        }
      ],
      "available_shipping_methods": [
        {
          "carrier": "OTHER",
          "label": "Teleportation",
          "price": 10000
        }
      ],
      "has_shipping_methods": true,
      "external_error_messages": [
        "<string>"
      ]
    }
  ]
}
```

</details>

## Discounts

Direct Order Submission supports **two different discount mechanisms** to give you maximum flexibility in your Checkout strategy:

1. **Synced Discounts (Promo Codes)** — Honor merchant-managed promo codes validated against their ecommerce platform
2. **Custom Discounts** — Create your own channel-defined discounts with full control over amounts and targeting

### Key Features

* **Target different parts of the Order**: Apply discounts at order level, shipping level, or SKU level
* **Apply amount or percentage-based Discounts**: Pass in fixed amount discounts (in fractional currency unit, e.g. cents) or percentage-based discounts (e.g. 15% off)
* **Preview Discounts using Estimate Cart**: Use Estimate Cart to evaluate discount impact before creating orders

### Quick Example

Apply a custom 15% discount to an entire order:

```json
{
  "base_currency": "USD",
  "skus": [
    { "quantity": 1, "sku_id": 1, "price": 5000 }
  ],
  "discounts": [
    {
      "merchant_id": 11111,
      "type": "CUSTOM",
      "target_type": "ORDER", 
      "percentage": 15.0
    }
  ],
  "shipping_address": {
    "country": "US"
  }
}
```

### Complete Guide

For comprehensive documentation including request/response examples, field explanations, error handling, and best practices, see our dedicated guide:

[**Direct Order Submission with Discounts**](/prism/checkout-guides/guides/direct-order-submission-with-discounts)

This guide covers:

* Synced vs Custom discount types
* Estimate Cart and Create Order usage
* All targeting options (ORDER/SKU/SHIPPING)
* BagDiscount field reference
* Validation rules and error scenarios
* Supported platforms

## Custom Commission Rates

When creating orders through Direct Order Submission, you can optionally override the standard commission rate on a per-order basis. Set a `commission_rate` at the bag level to apply a uniform rate, or on individual SKUs for line-item granularity. If both are provided, the SKU-level rate takes precedence.

For full details on rate resolution, weighted averages, request examples, and lifecycle behavior, see the [Custom Commission Rates](/prism/checkout-guides/guides/custom-commission-rates) guide.

## Adding a Payment Method

{% hint style="info" %}
If you are bypassing payments (i.e. not using Violet to orchestrate payments and payouts), you do not need to include a payment method. When creating an Order in the next step, simply leave out the `payment_method` in the request.
{% endhint %}

Violet supports accepting two forms of payment method when creating Orders.

1. Single-use Card Tokens
2. Pre-authorized Stripe Payment Intents

### Creating a Single-use Card Token

Capture Shopper Credit Card information using Stripe JS Elements and create a Stripe Token:

* <https://docs.stripe.com/js/tokens/create\\_token?type=cardElement>

Alternatively, if you're using a different user input form to collect and store shopper credit card information, you can call the Stripe API directly to create a token

* <https://docs.stripe.com/api/tokens/create\\_card?lang=curl>

For the token to be accepted during Checkout, you'll need to ensure that its created using the Stripe Public Key that is associated with the same Stripe account being used for payment orchestration. If this is Violet's Account, please reach out to us for this key.

### Using a pre-authorized Payment Intent

{% hint style="info" %}
This payment method can only be used if you've connected your pre-existing Stripe Platform account to Violet. Learn more about this [here](/prism/payments).
{% endhint %}

{% stepper %}
{% step %}

#### Create a payment intent with Stripe

Start with creating a payment intent in Stripe using the [Payment Intents API](https://docs.stripe.com/api/payment_intents/create). This must be done on the same account you used to onboard with Violet Payments. Ensure that the amount and currency, match that of the Order you will be creating. Additionally, Violet requires that the payment intent is marked for manual capture. For example:

```
 curl https://api.stripe.com/v1/payment_intents \
     -u "sk_test_<REDACTED>:" \
     -d amount=120000 \
     -d currency=usd \
     -d capture_method=manual
```

Store the payment intent ID that Stripe returns in the response.
{% endstep %}

{% step %}

#### Add a payment method to the Payment Intent

A payment method must be added to the payment intent prior to it being used when creating an Order. To do this, you can use Stripe.js Elements, or the update [Payment Intents API](https://docs.stripe.com/api/payment_intents/update).

Alternatively, you can modify the call in the previous step to include a payment method on payment intent create. For example:

```bash
 curl https://api.stripe.com/v1/payment_intents \
     -u "sk_test_<REDACTED>:" \
     -d amount=120000 \
     -d currency=usd \
     -d payment_method=pm_card_visa \
     -d capture_method=manual
```

{% endstep %}

{% step %}

#### Authorize the payment intent

Authorize the payment intent by calling the [Confirm Payment Intent API](https://docs.stripe.com/api/payment_intents/confirm). This ensures that this is not a fraudulent payment method and that there are sufficient funds for this purchase. Alternatively, if Stripe.js Elements were used to capture the shopper payment method, Stripe may have automatically authorized the shopper payment method. Once a payment intent is authorized, its amount cannot change.
{% endstep %}

{% step %}

#### Include the payment intent when calling Create Order

When creating an Order using the API below, include the payment intent as a payment method. For example:

```json
"payment_method": {
    "type": "PAYMENT_INTENT",
    "payment_provider": "STRIPE",
    "token": "pi_123kj123k12j31k2j"
}
```

{% endstep %}
{% endstepper %}

### Line Item Tax and Duty Support

Line item taxes are required when Tax Remittance is enabled for your app. These can be passed using the `rates` object on each SKU in the Order. If only tax\_total is provided at the Bag level, Violet will automatically allocate it across the SKUs in the Bag based on their relative line prices. Our recommendation, however, is to always include it at the SKU level.

Each SKU within a Bag must include one or more `rates` objects containing:

| Field    | Type    | Required                  | Description                                                                           |
| -------- | ------- | ------------------------- | ------------------------------------------------------------------------------------- |
| `name`   | string  | Yes                       | Display name for the rate                                                             |
| `type`   | string  | Yes                       | `TAX` for sales tax, VAT, or GST. `DUTY` for import duties, tariffs, or customs fees. |
| `amount` | integer | Either `amount` or `rate` | Fixed amount in cents                                                                 |
| `rate`   | number  | Either `amount` or `rate` | Percentage rate                                                                       |

{% hint style="info" %}
If both `amount` and `rate` are provided, Violet uses `amount` for calculations but persists both values.
{% endhint %}

#### Tax Examples

The following examples show each option for submitting taxes:

<details>

<summary>Option 1: Rate</summary>

```json
"rates": [
  {
    "name": "WA Sales Tax",
    "type": "TAX",
    "rate": 10.0
  }
]
```

</details>

<details>

<summary>Option 2: Amount</summary>

```json
"rates": [
  {
    "name": "WA Sales Tax",
    "type": "TAX",
    "amount": 10000
  }
]
```

</details>

<details>

<summary>Option 3: Rate + Amount</summary>

```json
"rates": [
  {
    "name": "WA Sales Tax",
    "type": "TAX",
    "rate": 10.0,
    "amount": 10000
  }
]
```

{% hint style="info" %}
Violet prioritizes amount in calculations but persists both values.
{% endhint %}

</details>

A complete Create Order request, with line-item taxes, is shown below:

<details>

<summary>Sample Create Order request with line-item taxes</summary>

```json
{
  "payment_method": {
    "type": "SINGLE_USE_CARD_TOKEN",
    "payment_provider": "STRIPE",
    "token": "tok_amex"
  },
  "order": {
    "app_order_id": "ishan-dos-sandbox",
    "customer": {
      "first_name": "Ishan",
      "last_name": "Guru",
      "email": "ishan.guru+line_item_taxes@violet.io"
    },
    "bags": [
      {
        "skus": [
          {
            "sku_id": 80445,
            "price": 100000,
            "quantity": 2,
            "rates": [
              {
                "name": "Washington (WA) Sales Tax",
                "type": "TAX",
                "amount": 10000
              }
            ]
          }
        ],
        "shipping_method": {
          "label": "Teleportation2",
          "price": 10000
        }
      }
    ],
    "shipping_address": {
      "address_1": "2815 Elliott Ave",
      "address_2": "Unit 100",
      "city": "Seattle",
      "state": "WA",
      "country": "US",
      "postal_code": "98121"
    },
    "currency": "USD"
  }
}
```

</details>

<details>

<summary>Sample Response</summary>

```json
{
    "id": 99400,
    "token": "1a028df30d444a78992a52d117297c65",
    "errors": [],
    "app_id": 10193,
    "developer_id": 10122,
    "customer": {
        "first_name": "Ishan",
        "last_name": "Guru",
        "email": "ishan.guru+dos_testing@violet.io",
        "name": "Ishan Guru"
    },
    "bags": [
        {
            "id": 118380,
            "order_id": 99400,
            "merchant_id": 10064,
            "app_id": 10193,
            "external_id": "6277080055983",
            "status": "ACCEPTED",
            "fulfillment_status": "PROCESSING",
            "financial_status": "PAID",
            "dispute_status": "UNDISPUTED",
            "skus": [
                {
                    "id": 112067,
                    "merchant_id": 10064,
                    "app_id": 10193,
                    "product_id": "815b064726de41d9a21de4bfc029416f",
                    "sku_id": 80445,
                    "external_id": "42519630413999",
                    "name": "Lunar Lemonade - 10 oz.",
                    "brand": "Space Drinks",
                    "thumbnail": "https://cdn.shopify.com/s/files/1/0621/1849/4383/files/wealthy_lunar_lemonade_4a9c0731-8758-4847-91e1-d6d37d6ace22.png",
                    "quantity": 2,
                    "price": 100000,
                    "weight": 3.0,
                    "available": true,
                    "status": "PROCESSING",
                    "product_type": "PHYSICAL",
                    "rates": [
                        {
                            "order_sku_id": 112067,
                            "amount": 10000,
                            "rate": 10.0,
                            "type": "TAX",
                            "name": "Sales Tax",
                            "dollar_amount": 100.0,
                            "decimal_rate": 0.1
                        }
                    ],
                    "line_price": 200000
                }
            ],
            "shipping_method": {
                "type": "FLAT_RATE_PRICE",
                "label": "Teleportation2",
                "price": 10000,
                "custom": false,
                "id": 97302,
                "merchant_id": 10064
            },
            "taxes": [
                {
                    "order_id": 99400,
                    "merchant_id": 10064,
                    "state": "WA",
                    "rate": 5.0,
                    "amount": 10000
                }
            ],
            "sub_total": 200000,
            "shipping_total": 10000,
            "tax_total": 10000,
            "duty_total": 0,
            "total": 220000,
            "taxes_included": false,
            "external_checkout": false,
            "commission_rate": 25.0,
            "date_created": "2024-12-13T00:08:58+0000",
            "date_last_modified": "2024-12-13T00:08:58.000+00:00",
            "remorse_period_ends": "2025-01-12T00:08:58+0000",
            "currency": "USD",
            "external_currency": "USD",
            "channel": "MARKETPLACE",
            "app_order_id": "ishan-dos-sandbox",
            "platform": "SHOPIFY",
            "fulfillments": [],
            "discounts": [],
            "wallet_based_checkout": false,
            "bag_status": "ACCEPTED",
            "bag_id": 118380,
            "merchant_name": "Space Drinks"
        }
    ],
    "shipping_address": { ... },
    "billing_address": { ... },
    "sub_total": 200000,
    "shipping_total": 10000,
    "tax_total": 10000,
    "duty_total": 0,
    "total": 220000,
    "app_order_id": "ishan-dos-sandbox",
    "status": "COMPLETED",
    "is_guest": true,
    "date_created": "2024-12-13T00:08:56+0000",
    "date_last_modified": "2024-12-13T00:09:01+0000",
    "payment_transactions": [ ... ],
    "order_status": "COMPLETED",
    "order_id": 99400
}
```

</details>

#### Duties

For cross-border orders, you can submit import duties using `type: "DUTY"` in the `rates` array. You can calculate duties using HS codes from the product catalog with a third-party service, or apply a fixed rate or amount from the merchant.

```json
"rates": [
  {
    "name": "Import Duty (IT→US)",
    "type": "DUTY",
    "amount": 3268
  }
]
```

Duties and taxes can be combined on the same SKU when both apply:

```json
"rates": [
  {
    "name": "NY Sales Tax",
    "type": "TAX",
    "amount": 1527
  },
  {
    "name": "Import Duty (IT→US)",
    "type": "DUTY",
    "amount": 3268
  }
]
```

Duty amounts from `DUTY`-type rates are automatically summed into the `duty_total` field on the Bag and Order objects, and included in the `total` calculation. You can also set `duty_total` directly on a Bag; if both a `duty_total` value and `DUTY`-type SKU rates are provided, the computed value from the rates takes precedence. Duties are also reflected in distributions and settlement.

{% hint style="info" %}
Violet does not calculate duties. Channels are responsible for determining duty amounts — either from merchant-provided rates or by using trade compliance data with a third-party calculation service. See the [Cross-Border Duties guide](/prism/checkout-guides/guides/cross-border-duties) for a complete walkthrough.
{% endhint %}

### Creating the Order

Call the Violet [Create Order](/api-reference/orders-and-checkout/orders/create-order) endpoint with the information collected above to create an Order:

{% hint style="warning" %}
The following information must be included to create an Order:

1. First Name
2. Last Name
3. Email
4. Shipping Address
5. Bag(s)

For a multi-merchant Order, multiple bags must be created in the Order payload. Each Bag must contain items from only one merchant and have its own shipping method.
{% endhint %}

{% hint style="info" %}
**Discounts** can be included at the bag level when creating orders. See the [Discounts section](#discounts) above for full implementation details.
{% endhint %}

<details>

<summary>Sample Request</summary>

```jsx
POST /orders

{
 "payment_method": {
   "type": "SINGLE_USE_CARD_TOKEN",
   "payment_provider": "STRIPE",
   "token": "tok_1289y1ishakj12h31kj212kh"
 },
  "order": {
    "app_order_id": "mario-test-1",
    "customer": {
      "first_name": "Ultra",
      "last_name": "Violet",
      "email": "super@mar.io"
    },
    "bags": [
      {
        "skus": [
          {
            "sku_id": 80455,
            "price": 100000
          }
        ],
        "shipping_method": {
          "carrier": "OTHER",
          "label": "Teleportation",
          "price": 10000
        },
        "tax_total": 10000
      }
    ],
    "shipping_address": {
      "address_1": "2815 Elliott Ave",
      "address_2": "Unit 100",
      "city": "Seattle",
      "state": "WA",
      "country": "US",
      "postal_code": "98121"
    },
    "billing_address": {
      "address_1": "200 West Street",
      "city": "New York",
      "state": "NY",
      "country": "US",
      "postal_code": "10282"
    },
    "currency": "USD"
  }
}
```

</details>

{% hint style="info" %}
`billing_address` is optional in the request above. If left out, the `shipping_address` will be used as the `billing_address` for the Order.
{% endhint %}

If Order submission succeeds, Violet will respond with a completed Cart.

<details>

<summary>Sample Response</summary>

```jsx
{
    "id": 54609,
    "token": "f9bd116404dc4441838a94f31a942d5f",
    "errors": [],
    "app_id": 10193,
    "developer_id": 10122,
    "customer": {
        "first_name": "Ultra",
        "last_name": "Violet",
        "email": "super@mar.io",
        "name": "Ultra Violet"
    },
    "bags": [
        {
            "id": 64579,
            "order_id": 54609,
            "merchant_id": 10064,
            "status": "ACCEPTED",
            "fulfillment_status": "PROCESSING",
            "financial_status": "PAID",
            "skus": [
                {
                    "id": 60509,
                    "merchant_id": 10064,
                    "app_id": 10193,
                    "product_id": "815b064726de41d9a21de4bfc029416f",
                    "sku_id": 80445,
                    "external_id": "42519630413999",
                    "name": "Lunar Lemonade - 10 oz.",
                    "brand": "Space Drinks",
                    "thumbnail": "https://cdn.shopify.com/s/files/1/0621/1849/4383/files/wealthy_lunar_lemonade_4a9c0731-8758-4847-91e1-d6d37d6ace22.png",
                    "quantity": 1,
                    "price": 100000,
                    "weight": 3.0,
                    "available": true,
                    "status": "PROCESSING",
                    "product_type": "PHYSICAL",
                    "line_price": 100000
                }
            ],
            "shipping_method": {
                "type": "FLAT_RATE_PRICE",
                "carrier": "OTHER",
                "label": "Teleportation",
                "price": 10000,
                "custom": false,
                "id": 21839,
                "merchant_id": 10064
            },
            "taxes": [
                {
                    "order_id": 54609,
                    "merchant_id": 10064,
                    "state": "WA",
                    "rate": 10.0,
                    "amount": 10000
                }
            ],
            "sub_total": 100000,
            "shipping_total": 10000,
            "tax_total": 10000,
            "duty_total": 0,
            "total": 120000,
            "taxes_included": false,
            "transactions": [],
            "external_checkout": false,
            "commission_rate": 0.0,
            "date_created": "2024-06-28T20:31:56+0000",
            "date_last_modified": "2024-06-28T20:31:56.000+00:00",
            "remorse_period_ends": "2024-07-28T20:31:56+0000",
            "currency": "USD",
            "external_currency": "USD",
            "channel": "MARKETPLACE",
            "app_order_id": "ishan-test-1",
            "platform": "SHOPIFY",
            "fulfillments": [],
            "discounts": [],
            "wallet_based_checkout": false,
            "bag_id": 64579,
            "bag_status": "ACCEPTED",
            "merchant_name": "Space Drinks"
        }
    ],
    "shipping_address": {
        "name": "Ultra Violet",
        "city": "Seattle",
        "state": "WA",
        "country": "US",
        "postal_code": "98121",
        "type": "BILLING",
        "address_1": "2815 Elliott Ave",
        "address_2": "Unit 100",
        "first_name": "Ultra",
        "last_name": "Violet"
    },
    "billing_address":{
        "name": "Ultra Violet",
        "city": "New York",
        "state": "NY",
        "country": "US",
        "postal_code": "10282",
        "type": "BILLING",
        "address_1": "200 West Street",
        "first_name": "Ultra",
        "last_name": "Violet"
    },
    "payment_transactions": [
        {
            "id": 31464,
            "order_id": 54627,
            "payment_provider": "STRIPE",
            "payment_provider_transaction_id": "pi_3PXoWvK29KDiBVld1n7ym4B0",
            "payment_method_id": 10630,
            "payment_provider_payment_method_id": "pm_1PXoWvK29KDiBVldLNqe04Oi",
            "payment_intent_client_secret": "pi_3PXoWvK29KDiBVld1n7ym4B0_secret_tB77zb3BoTCKigUe5R38hrCKS",
            "amount": 120000,
            "metadata": {
                "payment_intent_client_secret": "pi_3PXoWvK29KDiBVld1n7ym4B0_secret_tB77zb3BoTCKigUe5R38hrCKS",
                "payment_intent_id": "pi_3PXoWvK29KDiBVld1n7ym4B0"
            },
            "currency": "USD",
            "status": "CAPTURED",
            "errors": [],
            "date_created": "2024-07-01T18:00:45+0000",
            "date_last_modified": "2024-07-01T18:00:48+0000"
        }
    ],
    "sub_total": 0,
    "shipping_total": 0,
    "tax_total": 0,
    "duty_total": 0,
    "total": 0,
    "app_order_id": "mario-test-1",
    "status": "COMPLETED",
    "is_guest": true,
    "date_created": "2024-06-28T20:31:56+0000",
    "date_last_modified": "2024-06-28T20:31:56+0000",
    "priced": true,
    "wallet_based_checkout": false,
    "currency": "USD",
    "channel": "MARKETPLACE",
    "currency_symbol": "$",
    "intent_based_checkout": true,
    "order_status": "COMPLETED",
    "order_id": 54609,
    "guest": true
}
```

</details>

If there are any issues with submission, they will be returned to instead of the Order above. A new payment token will need to be sent with each Create Order request.

### Submission Date

At the time of order submission a `date_submitted` property on the Order and Bag objects will be populated with [**ISO 8601**](https://en.wikipedia.org/wiki/ISO_8601) datetime values that reflect the submission time. On the Order object this value will capture the last time the Order was submitted to Violet. Each Bag object within the Order object will reflect the last time an attempt was made to submit the Bag to the external commerce platform.

## Zero-Dollar ($0) Orders

Violet fully supports $0 orders through Direct Order Submission, enabling scenarios such as fully discounted orders, promotional campaigns, loyalty rewards, or free product samples where products may have zero monetary value while still requiring order processing and fulfillment tracking.

### When $0 Orders Occur

A $0 order can occur when:

* All SKUs in the order have a price of $0 (e.g., free promotional items)
* Discounts fully offset the order subtotal (e.g., 100% discount code)
* A combination of discounts brings the total to $0

### How Violet Handles $0 Orders

#### Payment Processing

When the order total equals $0:

* **No payment method is required** — You can omit `payment_method` from your Create Order request
* **Payment authorization is skipped** — Violet does not attempt to charge the shopper
* The `PaymentTransaction` will have:
  * `capture_status`: `NOT_REQUIRED`
  * `payment_provider`: Your app name (not a payment provider like Stripe)

{% hint style="info" %}
If you include a payment method on a $0 order, Violet will accept the request but will not process any payment. The payment method is essentially ignored.
{% endhint %}

<details>

<summary>Sample $0 Order Request (No Payment Method)</summary>

```json
POST /orders

{
  "order": {
    "app_order_id": "promo-order-001",
    "customer": {
      "first_name": "Jane",
      "last_name": "Doe",
      "email": "jane@example.com"
    },
    "bags": [
      {
        "skus": [
          {
            "sku_id": 12345,
            "price": 0,
            "quantity": 1
          }
        ],
        "shipping_method": {
          "label": "Free Shipping",
          "price": 0
        },
        "tax_total": 0
      }
    ],
    "shipping_address": {
      "address_1": "123 Main St",
      "city": "Seattle",
      "state": "WA",
      "country": "US",
      "postal_code": "98101"
    },
    "currency": "USD"
  }
}
```

</details>

#### Tax Handling

For $0 orders, tax is calculated as follows:

* **$0 price SKUs** — Tax amount and tax rate are automatically set to $0
* **Zero bag subtotal** — When the bag subtotal is $0 (even if individual SKU prices were reduced by discounts), no tax liability exists

This is consistent with standard tax treatment: when the taxable base is $0, there is no tax to collect.

{% hint style="warning" %}
If you are responsible for tax calculation and remittance, ensure your tax provider is configured to handle $0 taxable amounts. Most tax providers will return $0 tax for a $0 taxable base, but verify this behavior in your integration.
{% endhint %}

#### Commission Handling

Violet does not apply commission on $0 orders:

* When order total is $0 or negative, commission calculation is skipped
* No distribution records are created for commission amounts
* This prevents negative commission scenarios

### Discounts and $0 Orders

Discounts can reduce an order to $0. When using [Custom Discounts](/prism/checkout-guides/guides/direct-order-submission-with-discounts):

* A discount cannot exceed the bag subtotal (you'll receive a validation error)
* When a discount equals the subtotal exactly, the order becomes a $0 order
* All $0 order behaviors described above apply when discounts bring the total to $0

<details>

<summary>Sample Request: Discount Bringing Order to $0</summary>

```json
POST /orders

{
  "order": {
    "app_order_id": "full-discount-001",
    "customer": {
      "first_name": "John",
      "last_name": "Smith",
      "email": "john@example.com"
    },
    "bags": [
      {
        "skus": [
          {
            "sku_id": 12345,
            "price": 5000,
            "quantity": 1
          }
        ],
        "discounts": [
          {
            "type": "CUSTOM",
            "target_type": "ORDER",
            "amount": 5000,
            "code": "FREEGIFT"
          }
        ],
        "shipping_method": {
          "label": "Free Shipping",
          "price": 0
        },
        "tax_total": 0
      }
    ],
    "shipping_address": {
      "address_1": "456 Oak Ave",
      "city": "Portland",
      "state": "OR",
      "country": "US",
      "postal_code": "97201"
    },
    "currency": "USD"
  }
}
```

</details>

### Order Lifecycle for $0 Orders

$0 orders follow the same lifecycle as regular orders:

1. **Order Status** — Progresses through `PROCESSING` → `COMPLETED` as normal
2. **Bag Status** — Moves through `ACCEPTED` → fulfillment states as the merchant processes the order
3. **Fulfillment** — Merchants still receive and fulfill $0 orders through their commerce platform
4. **Webhooks** — All standard order webhooks are emitted (ORDER\_COMPLETED, BAG\_FULFILLED, etc.)

### Refunds on $0 Orders

If a merchant initiates a refund on a $0 order:

* Violet creates a refund record with `status`: `EXTERNAL`
* No funds are moved since no payment was captured
* The `ORDER_REFUNDED` webhook is still emitted
* Your system should update order status accordingly but no financial reversal is needed

### Best Practices for $0 Orders

1. **Validate pricing upstream** — Ensure your pricing logic is correct before submitting to Violet
2. **Track promotional orders** — Use `app_order_id` to identify promotional or $0 orders in your system
3. **Set appropriate fulfillment expectations** — Merchants will still see and fulfill these orders
4. **Monitor for abuse** — Implement rate limiting or other controls to prevent abuse of $0 order functionality


# Discounts with Direct Order Submission

Direct Order Submission supports **two** powerful discount mechanisms to give you maximum flexibility in your pricing strategy:

1. **Synced Discounts (Promo Codes)** — merchant-managed codes validated against the merchant's e-commerce platform
2. **Custom Discounts** — channel-defined amounts/percentages that Violet applies without merchant validation

Whether you want to honor existing merchant promotions or create your own channel-specific deals, we've got you covered.

## Quick Overview

* **One discount per merchant per request** for both synced codes and custom discounts
* **Target different parts of the Order**: Apply discounts at order level, shipping level, or SKU level
* **Apply amount or percentage-based Discounts**: Pass in fixed amount discounts (in fractional currency unit, e.g. cents) or percentage-based discounts (e.g. 15% off)
* **Preview Discounts using Estimate Cart**: Use Estimate Cart to evaluate discount impact before creating orders

### Choosing Synced vs Custom

| Aspect            | Synced Discounts (Promo Codes)                       | Custom Discounts                                                                                  |
| ----------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| Who defines logic | Merchant platform                                    | Channel                                                                                           |
| Validation source | Merchant platform                                    | Violet (no merchant validation)                                                                   |
| Targets           | As platform rules allow                              | `ORDER`, `SKU`, `SHIPPING`                                                                        |
| Typical use       | Honor existing promos                                | Channel-led campaigns, subsidies                                                                  |
| Failure Scenarios | `INVALID`, `EXPIRED`, `NOT_SUPPORTED` discount codes | Failures due to discount amounts being greater than specified target; `NOT_SUPPORTED` by platform |

## Synced Discounts (Promo Codes)

Synced discounts let you honor merchant-managed promo codes while applying them to your custom pricing. Violet validates these codes against the merchant's platform and applies the resulting discount according to their rules.

### Key Benefits

* **Honor merchant promotions** while using your own pricing
* **Automatic validation** against the merchant's platform
* **Correct application** at the right level (bag/SKU) based on merchant rules

### Requirements

* **One code per merchant per request** — multiple codes for the same merchant will result in a `400 Bad Request`
* **`merchant_id` is required** for Estimate Cart requests to identify which merchant the code belongs to.
* **Code must exist** and be valid in the merchant's platform.

### Platform Support

**Supported Platforms**

* **Shopify**
* **WooCommerce**
* **BigCommerce**
* **Magento**
* **Ecwid**

**Platforms Coming Soon**

* **Wix**

### Estimate Cart with Promo Codes

Pass promo codes at the top level of your request:

```json
{
  "base_currency": "USD",
  "skus": [
    {
      "quantity": 1,
      "sku_id": 1,
      "price": 1000
    },
    {
      "quantity": 1,
      "sku_id": 2,
      "price": 2000
    }
  ],
  "discounts": [
    {
      "merchant_id": 11111,
      "code": "PIEDPIPERCLUB"
    }
  ],
  "shipping_address": {
    "city": "Seattle",
    "state": "WA",
    "postal_code": "98109",
    "country": "US",
    "address_1": "456 Terry Ave N"
  }
}
```

**Request Fields**

| Field         | Type    | Required | Description                                                                                                   |
| ------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------- |
| `merchant_id` | Integer | Yes      | Violet Merchant ID that the discount code belongs to. Must match a merchant ID from the SKUs in your request. |
| `code`        | String  | Yes      | The promo code to validate against the merchant's platform.                                                   |

#### Valid Promo Code Response

When a promo code is valid, you'll see it applied with full details:

```json
{
  "estimated_carts": [
    {
      "merchant_id": 11111,
      "platform": "SHOPIFY",
      "base_currency": "USD",
      "sub_total": 20000,
      "shipping_total": 0,
      "discount_total": 2000,
      "tax_total": 2000,
      "total": 20000,
      "skus": [...],
      "discounts": [
        {
          "status": "VALID",
          "type": "CODE",
          "value_type": "PERCENTAGE", 
          "target_type": "ORDER",
          "code": "PIEDPIPERCLUB",
          "percentage": 15.0,
          "amount_total": 2000,
          "merchant_id": 11111
        }
      ],
      "available_shipping_methods": [...],
      "has_shipping_methods": true
    }
  ]
}
```

#### Invalid Promo Code Response

When a promo code doesn't work, you'll get clear feedback:

```json
{
  "estimated_carts": [
    {
      "merchant_id": 11111,
      "platform": "SHOPIFY",
      "base_currency": "USD",
      "sub_total": 20000,
      "shipping_total": 0,
      "discount_total": 0,
      "tax_total": 2000,
      "total": 22000,
      "skus": [...],
      "discounts": [
        {
          "status": "INVALID",
          "type": "CODE",
          "code": "PIEDPIPERFAKEDISCOUNT"
        }
      ],
      "available_shipping_methods": [...],
      "has_shipping_methods": true,
      "external_error_messages": [
        "Invalid discount code: PIEDPIPERFAKEDISCOUNT"
      ]
    }
  ]
}
```

**Response Fields**

**BagDiscount Object in Estimate Cart:**

| Field          | Type    | Description                                                                                                                                                   |
| -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`       | String  | <p><code>VALID</code> - Code is valid and discount applied<br><code>INVALID</code> - Code failed validation<br><code>ERROR</code> - System error occurred</p> |
| `type`         | String  | Always `CODE` for synced discounts                                                                                                                            |
| `value_type`   | String  | `AMOUNT` or `PERCENTAGE` - How the discount is calculated                                                                                                     |
| `target_type`  | String  | `ORDER`, `SKU`, or `SHIPPING` - What the discount applies to                                                                                                  |
| `code`         | String  | The promo code that was validated                                                                                                                             |
| `amount`       | Integer | Fixed discount amount in cents (when `value_type` is `AMOUNT`)                                                                                                |
| `percentage`   | Double  | Percentage discount value (when `value_type` is `PERCENTAGE`)                                                                                                 |
| `amount_total` | Integer | Total discount applied in cents                                                                                                                               |
| `merchant_id`  | Integer | Merchant ID this discount belongs to                                                                                                                          |

**Cart totals are automatically updated:**

* `discount_total` - Total discount amount applied across all discounts
* `tax_total` - Recalculated after discount is applied
* `total` - Final cart total including discount

### Create Order with Promo Codes

For Create Order, pass promo codes at the bag level within each bag's `discounts` array:

```json
{
  "payment_method": {
    "type": "SINGLE_USE_CARD_TOKEN",
    "payment_provider": "STRIPE",
    "token": "tok_amex"
  },
  "order": {
    "app_order_id": "piedpiper-1881",
    "customer": {
      "first_name": "Richard",
      "last_name": "Hendricks",
      "email": "richard@piedpiper.com"
    },
    "billing_address": {...},
    "shipping_address": {...},
    "bags": [
      {
        "skus": [
          { "sku_id": 12345, "quantity": 1, "price": 10000 }
        ],
        "shipping_method": {
          "carrier": "OTHER",
          "label": "Economy",
          "price": 5000,
          "shipping_method_id": "DOLLARFIFTYSHIPPING"
        },
        "tax_total": 5000,
        "discounts": [
          { "code": "PIEDPIPERCLUB" }
        ]
      }
    ],
    "currency": "USD"
  }
}
```

**Request Fields**

| Field  | Type   | Required | Description                           |
| ------ | ------ | -------- | ------------------------------------- |
| `code` | String | Yes      | The promo code to validate and apply. |

> **Note:** For Create Order with promo codes, `merchant_id` is inferred from the bag context; omit it from the discount object.

**Response Fields**

**BagDiscount Object in Create Order:**

| Field                | Type    | Description                                                                                                                                                |
| -------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                 | Integer | Unique identifier for this discount                                                                                                                        |
| `bag_id`             | Integer | ID of the bag this discount belongs to                                                                                                                     |
| `status`             | String  | <p><code>APPLIED</code> - Discount successfully applied<br><code>INVALID</code> - Code failed validation<br><code>ERROR</code> - System error occurred</p> |
| `type`               | String  | Always `CODE` for synced discounts                                                                                                                         |
| `value_type`         | String  | `AMOUNT` or `PERCENTAGE` - How the discount is calculated                                                                                                  |
| `target_type`        | String  | `ORDER`, `SKU`, or `SHIPPING` - What the discount applies to                                                                                               |
| `code`               | String  | The promo code that was applied                                                                                                                            |
| `amount`             | Integer | Fixed discount amount in cents (when `value_type` is `AMOUNT`)                                                                                             |
| `percentage`         | Double  | Percentage discount value (when `value_type` is `PERCENTAGE`)                                                                                              |
| `amount_total`       | Integer | Total discount applied in cents                                                                                                                            |
| `date_created`       | String  | ISO timestamp when discount was created                                                                                                                    |
| `date_last_modified` | String  | ISO timestamp when discount was last updated                                                                                                               |

#### Differences between Estimate Cart and Create Order for Synced Discounts

| Aspect                | Estimate Cart               | Create Order                                         |
| --------------------- | --------------------------- | ---------------------------------------------------- |
| **Purpose**           | Preview discount impact     | Apply discount permanently                           |
| **merchant\_id**      | Required in discount object | Not required (inferred from bag)                     |
| **Status Values**     | `VALID`, `INVALID`, `ERROR` | `APPLIED`, `INVALID`, `ERROR`                        |
| **Persistence**       | Temporary evaluation only   | Discount persisted with order                        |
| **Additional Fields** | None                        | `id`, `bag_id`, `date_created`, `date_last_modified` |
| **Error Handling**    | Shows as status in response | Creates error objects in `errors` array              |

> **Platform behavior (synced codes):** If the platform accepts the order but the code is inapplicable, the discount returns as `INVALID` and the bag may still be `ACCEPTED` (totals reflect no discount). Check the `discounts` array and `errors` for context.

## Custom Discounts

Custom discounts give you complete control over your promotional strategy. Define your own discount amounts or percentages, and Violet applies them without needing to validate against merchant platforms. Merchants will then see these discounts applied in Orders on their side.

### Key Benefits

* **Full control** over discount logic and amounts
* **Flexible targeting** — apply to orders, specific SKUs, or shipping
* **Perfect for marketplace-led promotions** that don't exist in merchant stores

### Discount Targets

Choose where your discount applies:

* **`ORDER`** — Apply to the entire bag/order subtotal
* **`SKU`** — Apply to specific line items
* **`SHIPPING`** — Apply to shipping charges only

### Platform Support

**Supported Platforms**

* **Shopify**
* **BigCommerce**
* **Ecwid**

**Platforms Coming Soon**

* **Magento**
* **WooCommerce**
* **Wix**

### Understanding the `BagDiscount` object

The `BagDiscount` object represents a discount applied to a bag. It contains all the necessary information about the discount, including its type, value, target, and status.

#### Common Fields (Both APIs)

| Field          | Type    | Description                                                      | Example      |
| -------------- | ------- | ---------------------------------------------------------------- | ------------ |
| `sku_id`       | Integer | SKU this discount applies to (null for order/shipping discounts) | `67890`      |
| `type`         | String  | Discount mechanism: `CODE` or `CUSTOM`                           | `CUSTOM`     |
| `value_type`   | String  | How discount is calculated: `AMOUNT` or `PERCENTAGE`             | `PERCENTAGE` |
| `target_type`  | String  | What the discount applies to: `ORDER`, `SKU`, or `SHIPPING`      | `ORDER`      |
| `amount`       | Integer | Fixed discount in cents (when `value_type` is `AMOUNT`)          | `500`        |
| `percentage`   | Double  | Percentage discount (when `value_type` is `PERCENTAGE`)          | `20.0`       |
| `amount_total` | Integer | Final discount applied in cents                                  | `1580`       |

#### Estimate Cart Only Fields

| Field         | Type    | Description                                       |
| ------------- | ------- | ------------------------------------------------- |
| `status`      | String  | `VALID`, `INVALID`, `ERROR`, `NOT_SUPPORTED`      |
| `merchant_id` | Integer | Required for bag-level discounts in Estimate Cart |

#### Create Order Only Fields

| Field                | Type    | Description                                    |
| -------------------- | ------- | ---------------------------------------------- |
| `id`                 | Integer | Unique discount identifier                     |
| `bag_id`             | Integer | Bag this discount belongs to                   |
| `status`             | String  | `APPLIED`, `INVALID`, `ERROR`, `NOT_SUPPORTED` |
| `date_created`       | String  | ISO timestamp when created                     |
| `date_last_modified` | String  | ISO timestamp when updated                     |

## Using Custom Discounts

### Estimate Cart

You can apply custom discounts at two levels:

* **Bag level** — In the main `discounts` array
* **SKU level** — Inside individual SKU objects

#### Order-Level Custom Discount

Apply a discount to the entire bag:

```json
{
  "base_currency": "USD",
  "skus": [
    { "quantity": 1, "sku_id": 1, "price": 5000 },
    { "quantity": 1, "sku_id": 2, "price": 3000 }
  ],
  "discounts": [
    {
      "merchant_id": 11111,
      "type": "CUSTOM",
      "target_type": "ORDER",
      "amount": 800
    }
  ],
  "shipping_address": {
    "city": "Seattle",
    "state": "WA",
    "postal_code": "98109",
    "country": "US",
    "address_1": "456 Terry Ave N"
  }
}
```

**Request Fields**

**Top-level discount (bag-level):**

| Field         | Type    | Required | Description                                                  |
| ------------- | ------- | -------- | ------------------------------------------------------------ |
| `merchant_id` | Integer | Yes      | Violet Merchant ID that this discount applies to             |
| `type`        | String  | Yes      | Must be `CUSTOM` for custom discounts                        |
| `target_type` | String  | Yes      | `ORDER`, `SKU`, or `SHIPPING` - what the discount applies to |
| `amount`      | Integer | No\*     | Fixed discount amount in cents                               |
| `percentage`  | Double  | No\*     | Percentage discount (e.g., `15.0` for 15%)                   |

\*Either `amount` OR `percentage` must be provided, not both.

**Response:**

```json
{
  "estimated_carts": [
    {
      "merchant_id": 11111,
      "platform": "SHOPIFY",
      "base_currency": "USD",
      "sub_total": 8000,
      "shipping_total": 0,
      "discount_total": 800,
      "tax_total": 720,
      "total": 7920,
      "skus": [...],
      "discounts": [
        {
          "type": "CUSTOM",
          "value_type": "AMOUNT",
          "target_type": "ORDER",
          "status": "VALID",
          "amount": 800,
          "amount_total": 800,
          "merchant_id": 11111
        }
      ],
      "available_shipping_methods": [...],
      "has_shipping_methods": true
    }
  ]
}
```

#### SKU-Level Custom Discount

Apply a discount to a specific product:

```json
{
  "base_currency": "USD",
  "skus": [
    {
      "quantity": 1,
      "sku_id": 1,
      "price": 5000,
      "discount": { 
        "type": "CUSTOM", 
        "percentage": 15.0 
      }
    },
    { "quantity": 1, "sku_id": 2, "price": 3000 }
  ],
  "shipping_address": {
    "city": "Seattle",
    "state": "WA", 
    "postal_code": "98109",
    "country": "US",
    "address_1": "456 Terry Ave N"
  }
}
```

**Request Fields**

**SKU-level discount (inline):**

| Field        | Type    | Required | Description                                |
| ------------ | ------- | -------- | ------------------------------------------ |
| `type`       | String  | Yes      | Must be `CUSTOM` for custom discounts      |
| `amount`     | Integer | No\*     | Fixed discount amount in cents             |
| `percentage` | Double  | No\*     | Percentage discount (e.g., `15.0` for 15%) |

\*Either `amount` OR `percentage` must be provided, not both. Note: `target_type` is implied as `SKU` when discount is inline with a SKU.

**Response:**

```json
{
  "estimated_carts": [
    {
      "merchant_id": 11111,
      "platform": "SHOPIFY",
      "base_currency": "USD",
      "sub_total": 8000,
      "shipping_total": 0,
      "discount_total": 750,
      "tax_total": 725,
      "total": 7975,
      "skus": [...],
      "discounts": [
        {
          "type": "CUSTOM",
          "value_type": "PERCENTAGE", 
          "target_type": "SKU",
          "status": "VALID",
          "percentage": 15.0,
          "amount_total": 750,
          "sku_id": 1
        }
      ],
      "available_shipping_methods": [...],
      "has_shipping_methods": true
    }
  ]
}
```

#### Shipping Discount

Apply a discount specifically to shipping costs:

```json
{
  "base_currency": "USD",
  "skus": [
    { "quantity": 1, "sku_id": 1, "price": 5000 }
  ],
  "discounts": [
    {
      "merchant_id": 11111,
      "type": "CUSTOM",
      "target_type": "SHIPPING",
      "percentage": 50.0
    }
  ],
  "shipping_address": {
    "city": "Seattle",
    "state": "WA",
    "postal_code": "98109", 
    "country": "US",
    "address_1": "456 Terry Ave N"
  }
}
```

**Response Fields**

**BagDiscount Object for Custom Discounts (Estimate Cart):**

| Field          | Type    | Description                                                                                                                                                                                                                               |
| -------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`       | String  | <p><code>VALID</code> - Discount is valid and applied<br><code>INVALID</code> - Discount failed validation<br><code>ERROR</code> - System error occurred<br><code>NOT\_SUPPORTED</code> - Platform doesn't support this discount type</p> |
| `type`         | String  | Always `CUSTOM` for custom discounts                                                                                                                                                                                                      |
| `value_type`   | String  | `AMOUNT` or `PERCENTAGE` - How the discount is calculated                                                                                                                                                                                 |
| `target_type`  | String  | `ORDER`, `SKU`, or `SHIPPING` - What the discount applies to                                                                                                                                                                              |
| `amount`       | Integer | Fixed discount amount in cents (when `value_type` is `AMOUNT`)                                                                                                                                                                            |
| `percentage`   | Double  | Percentage discount value (when `value_type` is `PERCENTAGE`)                                                                                                                                                                             |
| `amount_total` | Integer | Total discount applied in cents                                                                                                                                                                                                           |
| `sku_id`       | Integer | Present for SKU-level discounts, null for order/shipping discounts                                                                                                                                                                        |
| `merchant_id`  | Integer | Merchant ID this discount belongs to (bag-level discounts only)                                                                                                                                                                           |

**Cart totals are automatically updated:**

* `discount_total` - Total discount amount applied across all discounts
* `tax_total` - Recalculated after discount is applied
* `total` - Final cart total including discount

### Create Order

For Create Order, you can pass custom discounts at the bag level or inline with SKUs, just like in Estimate Cart.

**Request Fields**

**Bag-level discount:**

| Field         | Type    | Required | Description                                                  |
| ------------- | ------- | -------- | ------------------------------------------------------------ |
| `type`        | String  | Yes      | Must be `CUSTOM` for custom discounts                        |
| `target_type` | String  | Yes      | `ORDER`, `SKU`, or `SHIPPING` - what the discount applies to |
| `amount`      | Integer | No\*     | Fixed discount amount in cents                               |
| `percentage`  | Double  | No\*     | Percentage discount (e.g., `15.0` for 15%)                   |

**SKU-level discount (inline with SKU):**

| Field        | Type    | Required | Description                                |
| ------------ | ------- | -------- | ------------------------------------------ |
| `type`       | String  | Yes      | Must be `CUSTOM` for custom discounts      |
| `amount`     | Integer | No\*     | Fixed discount amount in cents             |
| `percentage` | Double  | No\*     | Percentage discount (e.g., `15.0` for 15%) |

\*Either `amount` OR `percentage` must be provided, not both. Note: `target_type` is implied as `SKU` for inline discounts, and `merchant_id` is inferred from the bag context.

**Response Fields**

**BagDiscount Object for Custom Discounts (Create Order):**

| Field          | Type    | Description                                                                                                                                                                                                                                 |
| -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`           | Integer | Unique identifier for this discount                                                                                                                                                                                                         |
| `sku_id`       | Integer | Present for SKU-level discounts, null for order/shipping discounts                                                                                                                                                                          |
| `status`       | String  | <p><code>APPLIED</code> - Discount successfully applied<br><code>INVALID</code> - Discount failed validation<br><code>ERROR</code> - System error occurred<br><code>NOT\_SUPPORTED</code> - Platform doesn't support this discount type</p> |
| `type`         | String  | Always `CUSTOM` for custom discounts                                                                                                                                                                                                        |
| `value_type`   | String  | `AMOUNT` or `PERCENTAGE` - How the discount is calculated                                                                                                                                                                                   |
| `target_type`  | String  | `ORDER`, `SKU`, or `SHIPPING` - What the discount applies to                                                                                                                                                                                |
| `amount`       | Integer | Fixed discount amount in cents (when `value_type` is `AMOUNT`)                                                                                                                                                                              |
| `percentage`   | Double  | Percentage discount value (when `value_type` is `PERCENTAGE`)                                                                                                                                                                               |
| `amount_total` | Integer | Total discount applied in cents                                                                                                                                                                                                             |

#### Bag-Level Custom Discount

```json
{
  "payment_method": {
    "type": "SINGLE_USE_CARD_TOKEN",
    "payment_provider": "STRIPE",
    "token": "tok_visa"
  },
  "order": {
    "app_order_id": "channel-order-123",
    "customer": {
      "first_name": "John",
      "last_name": "Doe", 
      "email": "john.doe@example.com"
    },
    "bags": [
      {
        "skus": [ 
          { "sku_id": 12345, "quantity": 2, "price": 5000 } 
        ],
        "shipping_method": { 
          "carrier": "OTHER", 
          "label": "Standard", 
          "price": 1000 
        },
        "tax_total": 1100,
        "discounts": [ 
          { 
            "type": "CUSTOM", 
            "target_type": "ORDER", 
            "percentage": 10.0 
          } 
        ]
      }
    ],
    "shipping_address": {
      "address_1": "123 Main St",
      "city": "Seattle",
      "state": "WA",
      "country": "US", 
      "postal_code": "98101"
    },
    "currency": "USD"
  }
}
```

**Response:**

```json
{
  "id": 145970,
  "bags": [
    {
      "id": 176283,
      "discounts": [
        {
          "id": 12784,
          "status": "APPLIED",
          "type": "CUSTOM",
          "value_type": "PERCENTAGE",
          "target_type": "ORDER", 
          "percentage": 10.0,
          "amount_total": 1000
        }
      ],
      "sub_total": 10000,
      "shipping_total": 1000,
      "tax_total": 1100,
      "discount_total": 1000,
      "total": 11100
    }
  ],
  "total": 11100,
  "status": "COMPLETED"
}
```

#### SKU-Level Custom Discount

```json
{
  "payment_method": {
    "type": "SINGLE_USE_CARD_TOKEN",
    "payment_provider": "STRIPE",
    "token": "tok_visa"
  },
  "order": {
    "app_order_id": "channel-order-124",
    "customer": {
      "first_name": "Jane",
      "last_name": "Smith",
      "email": "jane.smith@example.com"
    },
    "bags": [
      {
        "skus": [
          {
            "sku_id": 12345,
            "quantity": 1,
            "price": 8000,
            "discount": {
              "type": "CUSTOM",
              "amount": 500
            }
          }
        ],
        "shipping_method": {
          "carrier": "OTHER",
          "label": "Express",
          "price": 1500
        },
        "tax_total": 750
      }
    ],
    "shipping_address": {
      "address_1": "456 Oak Ave",
      "city": "Portland", 
      "state": "OR",
      "country": "US",
      "postal_code": "97201"
    },
    "currency": "USD"
  }
}
```

**Response:**

```json
{
  "id": 145971,
  "bags": [
    {
      "id": 176284,
      "skus": [...],
      "discounts": [
        {
          "id": 12785,
          "sku_id": 12345,
          "status": "APPLIED", 
          "type": "CUSTOM",
          "value_type": "AMOUNT",
          "target_type": "SKU",
          "amount": 500,
          "amount_total": 500
        }
      ],
      "sub_total": 18000,
      "shipping_total": 1500,
      "tax_total": 750,
      "discount_total": 1500,
      "total": 18750
    }
  ],
  "total": 18750,
  "status": "COMPLETED"
}
```

## Understanding BagDiscount Fields

The `BagDiscount` objects in responses contain all the information about applied discounts. Here's what each field means:

### Core Fields (Both APIs)

| Field          | Type    | Description                                                      | Example      |
| -------------- | ------- | ---------------------------------------------------------------- | ------------ |
| `sku_id`       | Integer | SKU this discount applies to (null for order/shipping discounts) | `67890`      |
| `type`         | String  | Discount mechanism: `CODE` or `CUSTOM`                           | `CUSTOM`     |
| `value_type`   | String  | How discount is calculated: `AMOUNT` or `PERCENTAGE`             | `PERCENTAGE` |
| `target_type`  | String  | What the discount applies to: `ORDER`, `SKU`, or `SHIPPING`      | `ORDER`      |
| `amount`       | Integer | Fixed discount in cents (when `value_type` is `AMOUNT`)          | `500`        |
| `percentage`   | Double  | Percentage discount (when `value_type` is `PERCENTAGE`)          | `20.0`       |
| `amount_total` | Integer | Actual discount applied in cents                                 | `1580`       |

### Estimate Cart Only

| Field    | Type   | Description                     | Values                                       |
| -------- | ------ | ------------------------------- | -------------------------------------------- |
| `status` | String | Whether discount can be applied | `VALID`, `INVALID`, `ERROR`, `NOT_SUPPORTED` |

### Create Order Only

| Field                | Type    | Description                    | Values                                         |
| -------------------- | ------- | ------------------------------ | ---------------------------------------------- |
| `id`                 | Integer | Unique discount identifier     | `12784`                                        |
| `bag_id`             | Integer | Bag this discount belongs to   | `176283`                                       |
| `status`             | String  | Current discount state         | `APPLIED`, `INVALID`, `ERROR`, `NOT_SUPPORTED` |
| `date_created`       | String  | When discount was created      | `2025-08-15T17:16:34+0000`                     |
| `date_last_modified` | String  | When discount was last updated | `2025-08-15T17:16:34+0000`                     |

### Status Values Explained

| Status          | Meaning                                         | When You'll See It                                                                                  |
| --------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `PENDING`       | Discount is in processing state                 | Interim processing state (iterative checkout). In DOS, this is internal and generally not surfaced. |
| `VALID`         | Discount is valid and ready to apply            | Estimate Cart when discount passes validation                                                       |
| `APPLIED`       | Discount has been successfully applied          | Create Order when discount is active on the order                                                   |
| `INVALID`       | Discount failed validation or rules             | Bad promo code, over-amount discount, etc.                                                          |
| `EXPIRED`       | Discount was not applied because it has expired | Merchant platform says the promo has expired (synced codes)                                         |
| `ERROR`         | System error during processing                  | Platform communication issues                                                                       |
| `NOT_SUPPORTED` | Discount type not supported                     | Platform doesn't support this discount type                                                         |

## Validation & Error Handling

We validate discounts thoroughly to prevent issues and provide error messages in the `errors` array .

### Over-Amount Protection

Discounts cannot exceed their applicable base amount:

* **Order-level**: Cannot exceed bag subtotal
* **SKU-level**: Cannot exceed line price (price × quantity)
* **Shipping-level**: Cannot exceed shipping method price

#### Single-Bag Order Error

If a discount exceeds limits in a single-bag order, the entire order fails with a bad-request exception:

```json
{
  "error": "bad_request",
  "error_message": "Discount total (\"$300.00\") cannot exceed bag subtotal (\"$200.00\").",
  "error_code": 1001
}
```

#### Multi-Bag Order Error

In multi-bag orders, only the offending bag fails while others may succeed:

```json
{
  "id": 145973,
  "errors": [
    {
      "id": 26695,
      "bag_id": 176286,
      "type": "EXTERNAL_ADD_DISCOUNT_ERROR",
      "message": "SKU-level discount (\"$120.00\") exceeds line price (\"$100.00\").",
      "date_created": "2025-08-15T17:16:34+0000"
    }
  ],
  "bags": [
    {
      "id": 176286,
      "bag_status": "REJECTED",
      "discounts": [
        { 
          "status": "INVALID", 
          "type": "CUSTOM", 
          "target_type": "SKU", 
          "sku_id": 12345 
        }
      ]
    },
    { 
      "id": 176285, 
      "bag_status": "ACCEPTED", 
      "discounts": [...] 
    }
  ]
}
```

### Common Error Scenarios

| Error                           | HTTP Code | Description                                  | Example                                                                               |
| ------------------------------- | --------- | -------------------------------------------- | ------------------------------------------------------------------------------------- |
| Multiple discounts per merchant | 400       | More than one discount for the same merchant | `"Multiple discounts cannot be passed in for the same merchant (merchant_id=10186)."` |
| Negative discount               | 400       | Discount amount is negative                  | `"Discount total cannot be negative. Provided value: -$50.00"`                        |
| Platform not supported          | 422       | Platform doesn't support custom discounts    | `"Custom discounts are not supported by SFCC."`                                       |

## Best Practices

### Always Include Shipping Address

A shipping address (at minimum the `country` field) is required in Estimate Cart requests.

```json
{
  "shipping_address": {
    "country": "US"
  }
}
```

### Pre-validate Discount Amounts

Before sending requests, ensure your discount amounts don't exceed their applicable base:

* For order discounts: Check against subtotal
* For SKU discounts: Check against line price (price × quantity)
* For shipping discounts: Check against shipping method price

### Discounts That Reduce Orders to $0

When discounts equal the order subtotal exactly, the order becomes a **$0 order**. This is fully supported and has specific behaviors:

* **No payment method required** — You can omit `payment_method` from your request
* **Payment processing is skipped** — Violet does not charge the shopper
* **Tax is $0** — No tax liability exists when the taxable base is $0
* **No commission** — Commission is not applied to $0 orders

See the [Zero-Dollar Orders section](/prism/checkout-guides/guides/direct-order-submission#zero-dollar-0-orders) in the main DOS guide for complete details on $0 order handling.

### Use Estimate Cart First

Always use Estimate Cart to preview discount application before creating orders. This helps you catch issues early and provides a better user experience.

## Platform Considerations

### SKU-Level Discount Support

Some ecommerce platforms don't support SKU-level custom discounts. When this happens:

* Violet automatically applies the discount at the Bag level instead
* Merchants will see the discount applied in their ecommerce platform, but not tied to specific SKUs. Since this is a platform limitation, all the other discounts on their platform would appear the same way.
* Violet data will still reflect the SKU-level details associated with the discount.
* Only one discount is permitted per merchant per request, regardless of level. This means that multiple SKU-level discounts for the same merchant in a single request will result in a `400 Bad Request`.

## Summary

With Direct Order Submission's discount support, you have the flexibility to:

* **Honor merchant promotions** with synced promo codes
* **Create channel-specific deals** with custom discounts
* **Apply targeted discounts** at order, SKU, or shipping level
* **Ensure accuracy** with comprehensive validation and clear error handling

This ensures you can confidently design discount strategies that work seamlessly across merchants and platforms and serve your marketplace needs.


# Custom Commission Rates

{% hint style="warning" %}
**Beta Feature:** Custom commission rates on order creation is currently in beta. Functionality and API surface may change.
{% endhint %}

## Overview

When you create an order with the Create Order endpoint (`POST /v1/orders`), you can optionally set the commission rate that applies to that specific order — either as a single rate for an entire bag, or individually per line item.

By default, every order uses the standard commission rate configured for your relationship with the merchant. Custom rates let you adjust that on a per-order basis without changing your merchant configuration. Common use cases include:

* Applying a negotiated rate to a one-off promotional order
* Charging different commission on different product lines in the same bag — for example, a higher rate on high-margin luxury items and a lower rate on low-margin commodity items
* Running a zero-commission order for testing or partner arrangements

{% hint style="info" %}
Custom commission rates apply **only to orders created through the Create Order endpoint** (Direct Order Submission). Orders created through the multi-step cart and checkout flow always use your standard configured rate.
{% endhint %}

## Rate Format

Commission rates are expressed as **percentages**: `15.0` means 15%. Valid values are `0` through `100`, inclusive. A rate of `0` is valid and means no commission is collected for that item.

## How Rates Are Resolved

You can provide a `commission_rate` at two levels of the order request, and each line item resolves its rate independently using the most specific value available:

1. **Line-item rate** — a `commission_rate` set directly on a SKU always wins.
2. **Bag rate** — if the SKU has no rate of its own, it uses the bag's `commission_rate`.
3. **Standard rate** — if neither is provided, the SKU uses the standard commission rate configured for your merchant connection.

Omitting the field and passing `null` behave identically: the item simply falls through to the next level. Only an explicit numeric value sets a custom rate.

Because each line item resolves independently, you can freely mix the levels — set a blanket bag rate and override just one SKU, set rates on every SKU with no bag rate, or provide nothing at all and keep today's behavior. Each bag in a multi-bag order also resolves independently; a custom rate on one bag never affects another.

## The Effective Bag Rate

Commission for payout purposes is calculated at the bag level. When the line items in a bag have different rates, the bag's effective rate is the **weighted average** of the line-item rates, weighted by each line's total (price x quantity).

**Example:** a bag contains item A at $1,000.00 with a 25% rate and item B at $3,000.00 with a 10% rate. The effective bag rate is:

```
(25.0 x 100000 + 10.0 x 300000) / 400000 = 13.75%
```

This effective rate is what appears on the bag, drives your earnings calculation, and is used for any future refunds on that bag.

{% hint style="info" %}
**Note on discounts:** the weighted average assumes discounts are distributed proportionally across the bag. If you apply a SKU-targeted discount to an item whose rate differs from the rest of the bag, the effective commission can diverge from an exact per-item calculation by a small amount (typically cents).
{% endhint %}

## Reading Rates Back

Order responses include the resolved rate and its origin on every bag and line item, so you can always confirm what was applied:

* Each **line item** has `commission_rate` and a `commission_rate_source` of:
  * `SKU` — you set the rate directly on this line item
  * `BAG` — the rate was inherited from the bag-level rate you provided
  * `SYSTEM` — the standard rate for your merchant connection was used
* Each **bag** has `commission_rate` (the effective rate described above) and a `commission_rate_source` of:
  * `BAG` — you provided a uniform bag-level rate and no line items overrode it
  * `WEIGHTED` — at least one line item had its own rate, so the bag rate is the weighted average
  * `SYSTEM` — no custom rates were provided anywhere in the bag

`commission_rate_source` is always determined by Violet based on how the rate was resolved. It is a read-only audit field — any value you include for it in a request is ignored.

If you provide a custom rate that happens to equal your standard rate, it is still recorded as `SKU` or `BAG`, so your records accurately reflect that you set the rate explicitly.

## Request Examples

### Uniform Rate for a Whole Bag

Every item in the bag uses 15%. This example omits `payment_method`, which is valid when you are bypassing Violet payment orchestration:

```json
{
  "order": {
    "app_order_id": "order-1042",
    "customer": {
      "first_name": "Ultra",
      "last_name": "Violet",
      "email": "customer@example.com"
    },
    "bags": [
      {
        "commission_rate": 15.0,
        "skus": [
          { "sku_id": 12335, "price": 100000, "quantity": 1 },
          { "sku_id": 12336, "price": 50000, "quantity": 2 }
        ],
        "tax_total": 10000,
        "shipping_method": { "carrier": "OTHER", "label": "Standard", "price": 1000 }
      }
    ],
    "shipping_address": {
      "address_1": "2815 Elliott Ave",
      "city": "Seattle",
      "state": "WA",
      "country": "US",
      "postal_code": "98121"
    },
    "currency": "USD"
  }
}
```

### Per-Item Rates

Each line item carries its own rate; the bag's effective rate becomes the weighted average:

```json
{
  "order": {
    "app_order_id": "order-1043",
    "customer": {
      "first_name": "Ultra",
      "last_name": "Violet",
      "email": "customer@example.com"
    },
    "bags": [
      {
        "skus": [
          { "sku_id": 12335, "price": 100000, "quantity": 1, "commission_rate": 25.0 },
          { "sku_id": 12336, "price": 300000, "quantity": 1, "commission_rate": 10.0 }
        ],
        "tax_total": 10000,
        "shipping_method": { "carrier": "OTHER", "label": "Standard", "price": 1000 }
      }
    ],
    "shipping_address": {
      "address_1": "2815 Elliott Ave",
      "city": "Seattle",
      "state": "WA",
      "country": "US",
      "postal_code": "98121"
    },
    "currency": "USD"
  }
}
```

### Mixed: Bag Rate with One Item Overridden

The first item uses its own 30% rate; the second inherits the bag's 15%:

```json
{
  "order": {
    "app_order_id": "order-1044",
    "customer": {
      "first_name": "Ultra",
      "last_name": "Violet",
      "email": "customer@example.com"
    },
    "bags": [
      {
        "commission_rate": 15.0,
        "skus": [
          { "sku_id": 12335, "price": 100000, "quantity": 1, "commission_rate": 30.0 },
          { "sku_id": 12336, "price": 100000, "quantity": 1 }
        ],
        "tax_total": 10000,
        "shipping_method": { "carrier": "OTHER", "label": "Standard", "price": 1000 }
      }
    ],
    "shipping_address": {
      "address_1": "2815 Elliott Ave",
      "city": "Seattle",
      "state": "WA",
      "country": "US",
      "postal_code": "98121"
    },
    "currency": "USD"
  }
}
```

### Response Excerpt

```json
{
  "bags": [
    {
      "commission_rate": 22.5,
      "commission_rate_source": "WEIGHTED",
      "skus": [
        { "sku_id": 12335, "commission_rate": 30.0, "commission_rate_source": "SKU" },
        { "sku_id": 12336, "commission_rate": 15.0, "commission_rate_source": "BAG" }
      ]
    }
  ]
}
```

## Validation

Every rate in the request must be between 0 and 100 inclusive. If any rate is out of range, the request is rejected with a `400` error identifying the exact field, for example:

```
bag[0].skus[1].commission_rate must be between 0 and 100
```

No part of the order is created when validation fails.

## Lifecycle Behavior

* **Rates are immutable.** The resolved rates are fixed when the order is created and cannot be changed afterward. To use a different rate, create a new order.
* **Earnings use the effective rate automatically.** Your payout for the order is calculated from the bag's effective rate — no additional configuration or follow-up call is required.
* **Refunds use the same rate.** When a bag is refunded (in full or in part), the refund is calculated with the same effective bag rate that was set at order creation. Partial refunds of a specific item use the bag's effective rate rather than that item's individual rate.
* **Existing integrations are unaffected.** If you don't send any `commission_rate` fields, orders behave exactly as they do today, using your standard configured rate. Orders created before this feature report their rates as standard (`SYSTEM`).

## Notes and Limitations

* **Submitting totals net of commission:** if your app is configured to submit order totals with commission already deducted, the rate you provide must match the deduction you applied when calculating your totals. Violet cannot detect a mismatch between the two, and an inconsistent rate will produce incorrect gross amounts.
* **A 100% rate is valid** — the merchant receives no payout for the bag.
* **Rate precision:** rates are accepted with decimal precision (e.g. `12.5`); they are not rounded to whole percentages.
* Custom rates do not change your standard merchant configuration. They apply only to the individual order they were submitted with.


# Utilizing Quick Checkout

## Intro

Violet utilizes `e-commerce` platforms to natively facilitate orders for merchants. Nearly all e-commerce platforms have rate limits on the API’s Violet uses in this process. During normal e-commerce use it is unlikely that your application will hit the rate limits of the e-commerce platforms Violet integrates with. However, there are moments and sales styles where spikes in traffic happen for a single merchant and hitting the rate limit becomes more likely. This is why we introduced Quick Checkout, processing more sales in times of higher traffic.

{% hint style="warning" %}
Currently Violet passes all failures in checkout relating to surpassing rate limits downstream. When integrating with Violet you must consider and prepare for such scenarios in all API calls to Violet. [Handling rate limits with Violet](/concepts/rate-limits)
{% endhint %}

## Why and When

**Why use Quick Checkout?** The primary benefit of Quick Checkout is reducing the number of requests to external platforms, allowing you to process more sales before hitting the e-commerce API rate limits that exist beyond Violet's control. The standard checkout can require 8 or more calls to e-commerce APIs. By consolidating the amount of calls, Quick Checkout reduces this number to 4 (and even less with some platforms). This allows you to process twice as many orders before reaching the platform's rate limit for that merchant connection.

As an example, Shopify has a rate limit of 40 request bucket per second per merchant, once the bucket is empty it refills at 2 requests per second. So when doing a Product Drop with a single merchant you could make 10 sales with Quick Checkout before hitting the rate limit versus 5 sales with standard Checkout options.

**When should I use Quick Checkout?** As you may have figured from our examples above, we recommend using Quick Checkout anytime you expect spikes in traffic for a merchant.

Example times to consider using Quick Checkout

* Product Drops
* New Merchant Launch
* Holiday Sales
* Single Product Orders
* Merchant Sales consistently exceeding rate limits.

## Considerations for Quick Checkout

**Dynamic price information**

During checkout Violet doesn’t handle monetary calculations, instead we retrieve the information from the e-commerce platform itself. Subtotal, Tax, Shipping Costs, Total, all are calculated by the e-commerce platform making orders as native as possible. During checkout when using the `?price_cart=true` param on the end of checkout requests they will call out to the e-commerce platform. So by removing this property, we can avoid these calls for cart pricing; however, the cart is still priced after applying shipping methods for the final time, so the user will be shown and charged the correct amount at the end. Until the shipping methods have been applied and final price information has been retrieved, it is possible that cart totals will not be entirely accurate and in-sync with the e-commerce platform.

## Step by Step Implementation

If you are thinking “this looks like the standard checkout flow”, that’s because it contains all the same elements consolidated into fewer calls. Quick Checkout is fully compatible with the standard checkout flow, it is more a way to structure the calls when doing specific sales types.

### 1. Create Cart (+1 E-Comm Request)

`POST /v1/checkout/cart`

[Create Cart](/api-reference/orders-and-checkout/carts/create-cart)

Using the create cart endpoint to pass more information is the primary difference for the Quick Checkout flow, it allows you to pass in customer info, both addresses, and one or more items that will be in the cart instead of separating this into potentially 5 requests like the standard checkout flow would. Saving at minimum 4 requests to the e-commerce platform. Any additional Add SKU, Update SKU, or Remove SKU will add to the number of e-commerce requests that are being made.

When including the customer data in the cart creation request. It follows the same schema as the `POST /v1/checkout/cart/{cart_id}/customer` endpoint (Apply Guest Customer to Cart, Set Billing Address).

```
    {
    "skus": [
        {
            "sku_id": 00000,
            "quantity": 1
        }
    ],
    "customer": {
        "first_name": "First",
        "last_name": "Last",
        "email": "example@violet.io",
        "shipping_address": {
            "address_1": "2815 Elliott Ave",
            "address_2": "Unit 100",
            "city": "Seattle",
            "state": "WA",
            "country": "US",
            "postal_code": "98121"
        },
        "same_address": true
    }
}
```

### 2. Get Shipping Methods (+1 E-Comm Request)

`GET /v1/checkout/cart/{cart_id}/shipping/available`

[Get Available Shipping Methods](/api-reference/orders-and-checkout/cart-shipping/get-available-shipping-methods)

### 3. Apply Shipping Method (+1 E-Comm Request)

`POST /v1/checkout/cart/{cart_id}/shipping`

[Set Shipping Methods](/api-reference/orders-and-checkout/cart-shipping/set-shipping-methods)

### 4. Apply Payment Method

`POST /v1/checkout/cart/{cart_id}/payment`

[Apply Payment Method](/api-reference/orders-and-checkout/cart-payment/apply-payment-method)

### 5. Submit Cart (+1 E-Comm Request)

`POST /v1/checkout/cart/10720/submit`

[Submit Cart](/api-reference/orders-and-checkout/cart-completion/submit-cart)

## Supported Platforms

* Shopify
* WooCommerce
* BigCommerce
* Magento
* Salesforce Commerce Cloud
* Ecwid
* Prestashop

## Quick Checkout FAQs

<details>

<summary>Is it possible for me to use quick checkout with guest orders who have to enter their address and info?</summary>

Yes, one of the main ways quick checkout is optimized is that you send all customer information along with SKU information in the initial create cart request. Simply create the cart with Violet after having gathered all the required information and you will be set.

</details>




---

[Next Page](/llms-full.txt/1)

