---
title: "Analyze experience"
method: POST
path: "/v25-10-beta/analytics/resource/{experienceId}"
tags: ["Fetch Experience Data"]
---

# Analyze experience

`POST /v25-10-beta/analytics/resource/{experienceId}`

## Request

- Base URL: `https://api.intelligems.io`
- URL: `https://api.intelligems.io/v25-10-beta/analytics/resource/{experienceId}`
- Auth: API key in header `intelligems-access-token`
- TypeScript: <https://skmtc.dev/intelligems/apis/intelligems-external-api-v25-10-beta/docs/v25-10-beta/analytics/resource/:experienceId/post.ts> (a function with typed inputs; its response is checked against the schema)

Analyze analytics data for a specific experience using a POST request body for filters and request settings.

The legacy `GET /analytics/resource/{experienceId}` endpoint remains available only as a beta compatibility path for existing integrations. It is deprecated, limited to its original query-parameter contract, and will be removed when the beta version ends.

`view` is **optional** and defaults to `overview`; a body of `{}` returns the same payload as `{"view": "overview"}`. Valid values are `overview`, `audience`, and `post_test`. The value `summary` is not supported. When `view` is `audience`, you must also provide the `audience` field. When `view` is `post_test`, the `audience` field is optional (supply it to break the post-test metrics down by that dimension). The `audience` field is not allowed when `view` is `overview` — including when `view` is omitted and therefore defaulted, which rejects `audience` with a `400`.

A request body is required even when every field is optional: sending no body at all returns `400` with `{ "errors": ["Invalid input: expected object, received undefined"] }`. Send `{}`.

Use `startTs` and `endTs` in the request body to match the backend contract. These values must be 10-digit Unix epoch timestamps in seconds, not milliseconds. Use the `filters` object for all advanced filtering instead of query parameters.

### Audience breakdowns (`view=audience`)

When `view` is `audience`, metrics are segmented by the selected `audience` dimension — one row per (variation × segment) — ordered by visitor count.

Accepted `audience` dimensions are `device_type`, `visitor_type`, `source_channel`, `source_site`, `country_code`, `landing_page_full_path`, and `purchase_likelihood`.

Only the **high-cardinality** dimensions `country_code` and `landing_page_full_path` are limited by default: when you omit `topN`, they return the **top 10 segments** by visitor count. The other dimensions — `device_type`, `visitor_type`, `source_channel`, `source_site`, and `purchase_likelihood` — are low-cardinality and are **not** limited by default; they return all their segments.

Segment values in the response are **display-cased**, not the lowercase wire values used by the request filters: `device_type` returns `"Mobile"` / `"Desktop"`, `visitor_type` returns `"New"` / `"Returning"`. Match on those exact strings, not on the `filters.deviceType` enum values.

Use the `topN` field to control this. It accepts an **integer between 1 and 1000**:

- **Omit `topN`** — `country_code` and `landing_page_full_path` return their top 10; all other dimensions return every segment.
- **Set `topN` to a value between 1 and 1000** — caps the selected dimension at that many top segments (applies to any dimension). Values above 1000 are rejected.

The `1000` maximum bounds the response size and query cost, so a breakdown can never degrade into the unbounded scan that caused earlier timeouts. This is why `landing_page_full_path`, which can have thousands of distinct URLs, is never returned in full — request the top segments you need (up to 1000).

### Upsell metrics (`includeUpsellMetrics`)

Set `includeUpsellMetrics: true` (boolean, default `false`) with `view=overview` to add per-variation upsell performance to the `metrics` array. This answers whether a variation drove a higher upsell take rate, not just higher overall revenue.

`view=overview` is the supported combination. The flag is currently also honoured under `view=audience`, where it adds the same fifteen fields to every (variation × segment) row, but that is **not a guaranteed behaviour** — the request schema documents the flag as overview-only, so treat the audience case as incidental and do not build on it. Under `view=post_test` the flag is ignored and no upsell fields are returned.

Metrics are returned for each of the three Intelligems upsell surfaces, which are distinct and reported separately:

| Surface               | What it is                                                                   |
| --------------------- | ---------------------------------------------------------------------------- |
| `checkout_upsell`     | An upsell block in the checkout extension.                                   |
| `onsite_upsell`       | The onsite upsell widget, which renders on the product page **or** the cart. |
| `post_purchase_offer` | An offer presented after checkout completed.                                 |

For each surface `<s>`, five metrics are added:

| Metric                                       | Definition                                                                                   |
| -------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `net_revenue_from_<s>`                       | Net revenue from lines added by that surface.                                                |
| `pct_orders_with_<s>`                        | Share of orders containing at least one line from that surface (the upsell take rate).       |
| `pct_revenue_from_<s>`                       | That surface's revenue as a share of total net revenue.                                      |
| `n_units_from_<s>`                           | Units sold through that surface.                                                             |
| `net_revenue_from_<s>_per_order_with_upsell` | AOV contribution — revenue divided by the orders that **took** the offer, not by all orders. |

Note the denominator in `net_revenue_from_<s>_per_order_with_upsell`: it divides by the orders that **took** the offer, not by every order. It answers "how much does an upsell add when it lands", not "how much does this surface add per order overall".

The all-orders variant, `net_revenue_from_<s>_per_order`, exists in the internal metric catalogue but is **not reachable through the external API** — `includeUpsellMetrics: true` returns only the fifteen fields listed above, and `_per_order` is not a valid `graphs.ids` value either. To get a per-all-orders figure, divide `net_revenue_from_<s>` by `n_orders` from the same response.

This is off by default because computing it adds per-line-item aggregation that stores without upsells should not pay for on every request.

To see which individual line items an upsell added, use the `order_line_items` export and its `upsell_type` column.

### Post-test metrics (`view=post_test`)

Post-test metrics look at customers who converted **during** the test and track their purchase behavior **after** that conversion, split by variation — answering "which variation produced more valuable customers over time?". Tracking is at the customer level (not cookie). Order filters narrow the in-test customer set only; they do not constrain the post-test orders.

The `includeInTestOrders` field (boolean, default `true`) controls whether in-test orders are folded into the metrics:

- `true` (default) — returns all three families. `total_*` is the LTV view (post-test + in-test combined), and the in-test `eso_*` family is included.
- `false` — the `eso_*` family is omitted entirely, and `total_*` collapses to equal `post_*` (since no in-test orders are folded in). The `post_*` family and headcounts are returned as usual.

Headcounts and rates are always present: `n_visitors`, `n_customers`, `customers_per_visitor`, `pct_repeat_customers`.

Every metric is `{ value }`. There is no `pct_change` field.

**`uplift` is only present on rate metrics.** On a **non-control** variation, per-visitor and per-customer rate metrics additionally carry `uplift: { value }` — the ratio vs control as a fraction. Two rules govern it:

1. The control variation never carries `uplift`.
2. Raw counts and absolute totals never carry `uplift`, on any variation. That covers `n_visitors`, `n_customers`, `n_post_orders`, `n_eso_orders`, `n_total_orders`, `post_net_revenue`, `post_gross_profit`, `eso_net_revenue`, `eso_gross_profit`, `total_net_revenue`, and `total_gross_profit` — all of which are always bare `{ value }`. Compute a comparison on those yourself if you need one.

The metrics that do carry `uplift` are the eighteen `*_per_visitor` / `*_per_customer` rates across the three families (six per family — orders, revenue, and profit, each per visitor and per customer), plus `customers_per_visitor` and `pct_repeat_customers`. That is twenty uplift-carrying fields on a non-control variation when `includeInTestOrders` is `true`, and fourteen when it is `false` (the `eso_*` family drops out, taking six of the rates with it).

Metric families:

- `post_*` — post-test orders only (after the customer's in-test conversion): `n_post_orders`, `post_net_revenue`, `post_gross_profit`, `post_orders_per_visitor`, `post_revenue_per_visitor`, `post_profit_per_visitor`, `post_orders_per_customer`, `post_revenue_per_customer`, `post_profit_per_customer`.
- `eso_*` — in-test ("experiment span") orders, only when `includeInTestOrders=true`: `n_eso_orders`, `eso_net_revenue`, `eso_gross_profit`, `eso_orders_per_visitor`, `eso_revenue_per_visitor`, `eso_profit_per_visitor`, `eso_orders_per_customer`, `eso_revenue_per_customer`, `eso_profit_per_customer`.
- `total_*` — post + in-test combined (LTV view): `n_total_orders`, `total_net_revenue`, `total_gross_profit`, `total_orders_per_visitor`, `total_revenue_per_visitor`, `total_profit_per_visitor`, `total_orders_per_customer`, `total_revenue_per_customer`, `total_profit_per_customer`. Always present, but when `includeInTestOrders=false` these values equal the corresponding `post_*` values.

When `view=post_test` is combined with `audience`, each metric row additionally carries an `audience` key (the bucket value, e.g. `"mobile"`), with one row per (variation × audience value), and `audienceOrder` is populated.

### Graphs

When requesting graphs via the `graphs` object, `graphs.ids` accepts an array of metric identifiers.

**The authoritative list of valid values is the `graphs.ids` enum in this endpoint's request schema**, which is generated from the metric catalogue — see the schema for the current set. It is deliberately not duplicated in prose here: the previous hand-maintained list had fallen four values behind the enum (`net_revenue_from_upsell`, `pct_orders_with_upsell`, `net_revenue_from_post_purchase_offer`, `pct_orders_with_post_purchase_offer` were all accepted but undocumented).

Note: `revenue_per_visitor` is **not** a valid graph ID — use `net_revenue_per_visitor` instead.

Invalid IDs are rejected with a `400` validation error on this endpoint. The deprecated `GET /analytics/resource/{experienceId}` instead silently drops them and returns `graphs: []`.

`graphs.outputFormat` is optional and defaults to `"png"`, so `{"graphs": {"ids": [...]}}` returns CDN URLs.

Each graph object in the response includes `id` (string), `key` (the original metric key), `type` (chart type, e.g. `"bar"`), `title` (display title), and either `url` (CDN URL when `outputFormat` is `"png"`) or `data` (base64-encoded PNG when `outputFormat` is `"base64"`).

The `graphs` key is omitted from the response entirely when the request does not ask for graphs; it is only present (possibly as `[]`) when `graphs` was sent. A valid `graphs.ids` value for a surface this store has no data for yields `graphs: []` rather than an error.

### Additional Response Fields

Response payloads include `impact` (object with `est_monthly_revenue_increase`: the projected 30-day revenue lift from the best non-control variation vs. control, or `null` when there is insufficient data) plus the ordering helper `audienceOrder` (segment display ordering, populated only for `view=audience` and for `view=post_test` with an `audience`; an empty array otherwise).

`impact` is calculated from whole-variation overview metrics with the same filters and time window, including when `view=audience`. Audience segmentation and `topN` do not change this experience-level calculation. Under `view=post_test`, the estimate is `null`.

`histogram`, `kde`, and `cdf` are also always present alongside the primary `metrics` and `variations` arrays, but this endpoint does not currently populate them — they are returned as empty arrays regardless of `view`, `analyticsViewType`, or date range. Do not build on them here. For an order-value distribution, use `POST /analytics/sitewide/order-distribution`, which returns a populated `orderValueDistribution.kernel_density_estimate` and `orderValueDistribution.cumulative_distribution_function`.

#### `audienceOrder`

`audienceOrder` is a **display ordering hint, not the order of the `metrics` array.** The `metrics` rows come back in the order the analytics store returned them, so do not assume the two line up — sort or index by the `audience` key if you need them to.

The ordering is by **total visitors summed across all variations**, descending. Two consequences:

- It will not match a descending sort of any single variation's `n_visitors`, because the sort key is the cross-variation total.
- `"Other"` and `"Unknown"` are pinned to the end regardless of size, in that order, so they can appear after segments with fewer visitors.

**Rate Limit:** 50 requests per 30s window, refilling 25 tokens every 30s.

## Path parameters

- `experienceId` string, uuid, required

## Request body

- object
  - `view` 'overview' | 'audience' | 'post_test': Resource view to analyze. Supported values are 'overview' for variation-level metrics, 'audience' for a breakdown by the selected audience dimension, and 'post_test' for post-test metrics (customers who converted during the test, tracked by their purchase behavior after that conversion, split by variation).
  - `audience` 'device_type' | 'visitor_type' | 'source_channel' | 'source_site' | 'country_code' | 'landing_page_full_path' | 'purchase_likelihood': Audience breakdown dimension. Required when `view` is `audience`. Optional when `view` is `post_test` (returns the post-test breakdown by the selected dimension). Not allowed when `view` is `overview`. Use one of the supported audience fields such as `device_type`, `visitor_type`, or `source_channel`.
  - `includeInTestOrders` boolean: Only applies when `view` is `post_test`. Controls whether in-test orders are folded into the metrics. When `true` (default), the in-test `eso_*` family is included and `total_*` is the LTV view (post-test + in-test combined). When `false`, the `eso_*` family is omitted and `total_*` collapses to equal `post_*`. The `post_*` family and headcounts/rates are always returned.
  - `analyticsViewType` 'test_orders_only' | 'sitewide_orders' | 'none': Optional analytics view preset used by the backend when building the analysis request.
  - `includeUpsellMetrics` boolean: When true, adds the per-variation upsell metric families to the response for all three Intelligems upsell surfaces — checkout upsell, onsite upsell (rendered on the PDP or cart), and post-purchase offer. Each surface contributes revenue (`net_revenue_from_<surface>`), take rate (`pct_orders_with_<surface>` — the share of orders containing at least one line from that surface), revenue share (`pct_revenue_from_<surface>`), units (`n_units_from_<surface>`), and AOV contribution (`net_revenue_from_<surface>_per_order_with_upsell` — revenue divided by the orders that actually took the offer, not by all orders). Off by default because computing them adds per-line-item aggregation that stores without upsells should not pay for. Only applies when `view` is `overview`.
  - `endTs` string: Optional analysis end timestamp as a 10-digit Unix epoch string in seconds (not milliseconds). Maps directly to the backend `endTs` field.
  - `startTs` string: Optional analysis start timestamp as a 10-digit Unix epoch string in seconds (not milliseconds). Maps directly to the backend `startTs` field.
  - `graphs` object
    - `ids` string[]: Array of graph IDs to render in the response. Valid values (32): conversion_rate, add_to_cart_rate, abandoned_cart_rate, abandoned_checkout_rate, checkout_begin_rate, checkout_enter_contact_info_rate, checkout_address_submitted_rate, view_product_page_rate, view_collection_page_rate, net_revenue_per_visitor, net_revenue_per_order, net_product_revenue_per_order, net_shipping_revenue_per_order, avg_units_per_order, avg_product_revenue_per_unit, profit_per_visitor, subscription_product_revenue_per_order, subscription_revenue_per_order, subscription_orders_per_visitor, subscription_revenue_per_visitor, subscription_profit_per_visitor, profit_per_order, pct_orders_free_shipping, avg_discount_per_discounted_order, avg_discount_per_all_orders, pct_subscription_orders, pct_orders_with_post_purchase_offer, net_revenue_from_post_purchase_offer, pct_orders_with_upsell, net_revenue_from_upsell, pct_orders_with_onsite_upsell, net_revenue_from_onsite_upsell. Note that 'revenue_per_visitor' is NOT valid — use 'net_revenue_per_visitor'.
    - `outputFormat` 'png' | 'base64': Graph output format. Use `png` for signed image URLs or `base64` to inline the PNG data in the response.
  - `filters` object: Structured analytics filters object for `POST /analytics/resource/{experienceId}`. This replaces the deprecated GET endpoint's query-parameter filter pattern and supports device, visitor, traffic source, URL, user behavior, revenue, custom event, product, and targeting filters. Analytics filters object for narrowing experience/experiment result data.
    - `deviceType` 'any' | 'mobile' | 'desktop', nullable: Filter by device type. Options: 'any' (disables filter), 'mobile', 'desktop'. Omit or null to include all devices.
    - `visitorType` 'any' | 'new' | 'returning', nullable: Filter by visitor type. Options: 'any' (disables filter), 'new', 'returning'. Omit or null to include all visitors.
    - `customerType` 'new' | 'returning', nullable: Filter experiment analytics by customer type. Options: 'new', 'returning'. Omit or null to include all customers.
    - `sourceSitesOrChannels` string[]: Filter by traffic source channels. These 25 values are the complete accepted set — the channels the analytics service buckets sessions and orders into — and any other value is rejected with a 400: 'Instagram', 'Facebook', 'Google', 'Twitter', 'TikTok', 'Youtube', 'Klaviyo', 'Attentive', 'Postscript', 'Paid Shopping', 'Paid Search', 'Paid Social', 'Paid Video', 'Display', 'Paid Other', 'Organic Shopping', 'Organic Social', 'Organic Video', 'Organic Search', 'Other', 'Referral', 'Affiliate', 'SMS', 'Email', 'Direct'. Omit or pass an empty array for all channels — there is no 'any' sentinel.
    - `urlParam` object: Filter by URL query parameter. Object with: queryParam (string|null — the parameter name), queryParamValue (string|null — the value to match), queryParamFilterType (match operator|null: 'equals', 'contains', 'startsWith', 'endsWith', 'doesNotEqual', 'doesNotContain', 'doesNotStartWith', 'doesNotEndWith', 'isNull', 'isNotNull'). REQUIRED COMBINATIONS (enforced with a 400): when queryParamFilterType is set, queryParam must be a non-empty string; every operator except 'isNull'/'isNotNull' also requires a non-empty queryParamValue; 'isNull'/'isNotNull' take no value, so leave queryParamValue null. Omit all three fields to apply no query-parameter filter.
      - `queryParam` string, nullable, required
      - `queryParamValue` string, nullable, required
      - `queryParamFilterType` 'equals' | 'contains' | 'startsWith' | 'endsWith' | 'doesNotEqual' | 'doesNotContain' | 'doesNotStartWith' | 'doesNotEndWith' | 'isNull' | 'isNotNull', nullable, required
    - `landingPage` object, nullable: DEPRECATED — use landingPageFilters instead, which supports multiple values and an and/or operator. This single-path filter is retained for backwards compatibility and still works, but new integrations should use landingPageFilters. Filter by landing page URL path. Object with: landingPageUrlPath (string|null — the path to match), landingPageUrlPathFilterType (match operator|null: 'equals', 'contains', 'startsWith', 'endsWith', 'doesNotEqual', 'doesNotContain', 'doesNotStartWith', 'doesNotEndWith', 'isNull', 'isNotNull'). REQUIRED COMBINATIONS (enforced with a 400): every operator except 'isNull'/'isNotNull' requires a non-empty landingPageUrlPath; 'isNull'/'isNotNull' take no path, so leave landingPageUrlPath null; and a landingPageUrlPath with no landingPageUrlPathFilterType is rejected. Omit both fields to apply no landing-page filter.
      - `landingPageUrlPath` string, nullable, required
      - `landingPageUrlPathFilterType` 'equals' | 'contains' | 'startsWith' | 'endsWith' | 'doesNotEqual' | 'doesNotContain' | 'doesNotStartWith' | 'doesNotEndWith' | 'isNull' | 'isNotNull', nullable, required
    - `landingPageFilters` object[]: Filter by landing page URL path with multi-value support. Recommended landing page filter (supersedes the deprecated landingPage field). Array of filter items, each with: filterType (match operator: 'equals', 'contains', 'startsWith', 'endsWith', 'doesNotEqual', 'doesNotContain', 'doesNotStartWith', 'doesNotEndWith', 'isNull', 'isNotNull') and values (array of strings to match against). REQUIRED COMBINATIONS (enforced with a 400): every operator except 'isNull'/'isNotNull' requires at least one non-empty entry in values — an omitted, empty, or blank-only values array is rejected rather than silently matching nothing. 'isNull'/'isNotNull' take no values; omit the field (an empty array is tolerated, real values are rejected). Multiple values within a single item are OR'd. How items in the array are combined is controlled by landingPageFiltersOperator.
      - `values` string[]
      - `filterType` 'equals' | 'contains' | 'startsWith' | 'endsWith' | 'doesNotEqual' | 'doesNotContain' | 'doesNotStartWith' | 'doesNotEndWith' | 'isNull' | 'isNotNull', required
    - `landingPageFiltersOperator` 'or' | 'and': How multiple items in landingPageFilters are combined. 'or' (default) — session matches if any filter item matches. 'and' — session must match every filter item.
    - `userBehavior` object: Filter by visitor browsing behavior. Object with optional boolean flags: viewedCheckout, addedToCart, viewedProductPage, viewedCollectionPage. Set a flag to true to include only visitors who performed that action. Omit or null for flags you don't want to filter on. Multiple true flags are combined with AND logic.
      - `viewedCheckout` boolean, nullable
      - `addedToCart` boolean, nullable
      - `viewedProductPage` boolean, nullable
      - `viewedCollectionPage` boolean, nullable
    - `countryCodes` string[]: Filter by ISO 3166-1 alpha-2 country codes (e.g. ['US', 'GB', 'CA']). Omit or pass empty array for all countries.
    - `countryCodesFilterType` 'include' | 'exclude': How countryCodes should be matched: 'include' (only visitors in the listed countries) or 'exclude' (visitors in any country except the listed ones). Defaults to 'include' when omitted. Requires countryCodes to be a non-empty array.
    - `maxZScore` union: Maximum Z-score threshold for outlier filtering on order revenue. Visitors with orders whose Z-score exceeds this value are excluded. Accepts number or numeric string. Null or omit to disable outlier filtering.
      - number
      - string
    - `triggeredCustomEvents` string[]: Filter by custom event identifiers that visitors must have triggered. Requires customEventsFilterType to be set to control matching logic. Has no effect without customEventsFilterType. Pull merchant-defined identifiers from the GET https://api.intelligems.io/v25-10-beta/experiences/{experienceId} endpoint > experienceCustomMetrics > customEvent > identifier field. Three additional identifiers are always available with no Events Manager setup, synthesized server-side rather than looked up from a stored custom event: 'checkout_block_viewed', 'onsite_upsell_viewed', 'post_purchase_offer_viewed'. Note: the analytics UI's filter drawer groups these three visually under 'Reached Checkout Stage' alongside the checkout funnel-stage options, but they are NOT reachedCheckoutStage values — pass them here, in triggeredCustomEvents, not in reachedCheckoutStage.
    - `customEventsFilterType` 'any' | 'all' | 'none': How triggeredCustomEvents should be matched: 'any' (visitor triggered at least one), 'all' (visitor triggered every listed event), 'none' (visitor triggered none of the listed events). Requires triggeredCustomEvents to be a non-empty array.
    - `reachedCheckoutStage` 'started' | 'contact_info_submitted' | 'address_info_submitted', nullable: Filter to visitors who reached at least the given checkout stage. Options: 'started', 'contact_info_submitted', 'address_info_submitted'. Omit or null to not filter by checkout stage. Note: 'checkout_block_viewed', 'onsite_upsell_viewed', and 'post_purchase_offer_viewed' are NOT valid values here for experience-level analytics — despite appearing next to these stages in the analytics UI's filter drawer, filter on them via triggeredCustomEvents instead (see that field's description).
    - `minNetRevenue` union: Minimum order net revenue to include (inclusive). Accepts number or numeric string. Omit or null to not apply a minimum.
      - number
      - string
    - `maxNetRevenue` union: Maximum order net revenue to include (inclusive). Accepts number or numeric string. Omit or null to not apply a maximum.
      - number
      - string
    - `minShippingRevenue` union: Minimum shipping revenue to include (inclusive). Accepts number or numeric string. Omit or null to not apply a minimum.
      - number
      - string
    - `maxShippingRevenue` union: Maximum shipping revenue to include (inclusive). Accepts number or numeric string. Omit or null to not apply a maximum.
      - number
      - string
    - `shippingMethods` string[]: Filter by shipping method names. Only orders using one of these methods are included.
    - `onlyProductIds` string[], nullable: Filter to only include specific Shopify product IDs (numeric strings).
    - `landingPageTypes` string[]: Filter sessions by landing page types. An array of values from: 'PDP', 'Collection', 'Content', 'Blog', 'Homepage', 'Search', 'Cart', 'Other'. Omit or null to include all landing page types.
    - `experimentProductsOnly` boolean, nullable: When true, only include products that are part of the experiment. Only applies when analyzing an experience/experiment.
    - `onlyProductHandles` string[], nullable: Filter to only include specific Shopify product handles.
  - `topN` integer: Only applies when `view` is `audience`. Caps the breakdown to the top N segments by visitor count, where N is an integer between 1 and 1000. By default, only the high-cardinality dimensions `country_code` and `landing_page_full_path` are capped at 10; the other dimensions (`device_type`, `visitor_type`, `source_channel`, `source_site`) are low-cardinality and returned in full. Set a value between 1 and 1000 to override the cap for any dimension. The 1000 maximum bounds the response size and query cost — this is why `landing_page_full_path`, which can have thousands of distinct URLs, is never returned in full.
  - `testResult` boolean: When true, compute and return the opt-in test verdict alongside the overview. The verdict is returned on the response as `testResult`. Only an unfiltered verdict is persisted in DynamoDB for re-use on later requests. If any filter is set, the verdict is computed fresh on that filtered subset for this request only — it is neither read from nor written to the stored verdict — so it can differ from the unfiltered verdict for the same experience. A filter that narrows the population — including a `startTs`/`endTs` that covers less than the whole experience — means the verdict no longer describes the full randomized group the thresholds were validated on, so it is not a test result: the label comes back prefixed (`filtered_directional_win`, `filtered_not_ready`, …) and `action_to_take` is a refusal naming the filters it was computed under. The one exception is a price test scoped to its own target products, which narrows the metric rather than the population: it keeps its normal label and recommendation, but is still not persisted. Every computed verdict, filtered or not, is recorded in Snowflake for analysis.

## Response `200`

OK

- object
  - `datasetId` 'order_line_items' | 'orders' | 'aiProfit' | 'variation_overview' | 'variation_audience' | 'variation_timeseries_discrete' | 'variation_timeseries_cumulative' | 'experience_countries' | 'variation_shipping_method' | 'variation_histogram' | 'variation_products' | 'variation_product_groups' | 'variation_order_unit_mix' | 'custom_events_plugin' | 'custom_events_server' | 'order_reconciliation' | 'order_reconciliation_export' | 'experience_session_order' | 'timeseries' | 'country_codes' | 'snapshots' | 'experience_shipping_methods' | 'timeseries_audience' | 'snapshots_audience' | 'holiday_benchmarking_single_day' | 'holiday_benchmarking_multiple_days' | 'order_distribution_histogram' | 'order_distribution_unit_mix' | 'conversion_snapshots' | 'conversion_funnel' | 'conversion_timeseries' | 'variation_post_metrics' | 'variation_post_metrics_audience', required
  - `latestRunTs` number, required
  - `cogsConfigured` boolean: Whether cost of goods sold (COGS) is configured for the store (any revenue has COGS data). When false, all profit metric values are null because they cannot be computed; use revenue metrics instead. Only present when the request includes a profit metric.
  - `cogsCoveragePct` number: Fraction of revenue (0-1) backed by line items that have COGS data. 0 means profit metrics are unavailable and returned as null. A value between 0 and 1 means profit is based on partial COGS coverage; 1 means full coverage. Only present when the request includes a profit metric.
  - `metrics` unknown[], required: Array of metric objects. Each metric object may contain the following fields (all optional): **Dimension Fields:** - variation_id (string, UUID): The variation identifier - dt (string): Timestamp for time series data - audience (string): Audience segment identifier **Metric Fields (alphabetical):** - abandoned_cart_rate: Rate of abandoned carts - abandoned_checkout_rate: Rate of abandoned checkouts - add_to_cart_rate: Add to cart rate - avg_discount_per_all_orders: Average discount amount across all orders - avg_discount_per_discounted_order: Average discount amount for orders with discounts - avg_product_revenue_per_unit: Average revenue per product unit - avg_units_per_order: Average number of units per order - checkout_address_submitted_rate: Rate of checkouts with address submitted - checkout_begin_rate: Checkout initiation rate - checkout_enter_contact_info_rate: Rate of checkouts with contact info entered - conversion_rate: Conversion rate metric with statistical details - gross_profit_per_order: Gross profit per order. Requires COGS to be configured. Null when COGS are not configured (cogsConfigured is false). Based on partial COGS coverage when cogsCoveragePct is between 0 and 1. - gross_profit_per_visitor: Gross profit per visitor. Requires COGS to be configured. Null when COGS are not configured (cogsConfigured is false). Based on partial COGS coverage when cogsCoveragePct is between 0 and 1. - n_orders: Number of orders - n_visitors: Number of visitors - net_product_revenue_per_order: Average product revenue per order - net_revenue: Total net revenue - net_revenue_per_order: Average revenue per order - net_revenue_per_visitor: Average revenue per visitor (RPV). - net_shipping_revenue_per_order: Average shipping revenue per order - pct_orders_free_shipping: Percentage of orders with free shipping - pct_subscription_orders: Percentage of orders that are subscriptions - subscription_gross_profit_per_visitor: Gross profit from subscriptions per visitor. Requires COGS to be configured. Null when COGS are not configured (cogsConfigured is false). - subscription_orders_per_visitor: Subscription orders per visitor - subscription_revenue_per_order: Revenue from subscriptions per order - subscription_revenue_per_visitor: Revenue from subscriptions per visitor - view_collection_page_rate: Collection page view rate - view_product_page_rate: Product page view rate **Funnel visitor counts (returned by view=overview):** - n_visitors_viewed_product_page: Visitors who viewed a product page - n_visitors_viewed_collection_page: Visitors who viewed a collection page - n_visitors_added_to_cart: Visitors who added to cart - n_visitors_checkout_started: Visitors who started checkout - n_visitors_checkout_contact_info_submitted: Visitors who submitted contact info - n_visitors_checkout_address_info_submitted: Visitors who submitted address info - n_visitors_abandoned_cart: Visitors who abandoned a cart - n_visitors_abandoned_checkout: Visitors who abandoned a checkout - n_visitors_ordered: Visitors who placed an order **Absolute totals (returned by view=overview):** - net_product_revenue: Total net product revenue - gross_profit: Total gross profit. Requires COGS to be configured; null when cogsConfigured is false. - total_units: Total units sold - total_discount: Total discount amount - n_orders_discounted: Number of orders carrying a discount - pct_revenue_with_cogs: Fraction of revenue backed by line items with COGS data - n_subscription_orders: Number of subscription orders - subscription_product_revenue: Product revenue from subscription orders - subscription_units: Units sold in subscription orders NOTE: this list documents the commonly returned fields, but the response is driven by the store's configured metric catalogue and by the requested view, so additional metric keys may be present. Clients should tolerate unknown keys rather than validating against a closed set. Statistical metric objects can contain the fields below. Numeric fields can be null when a value or statistic is unavailable; null does not mean zero. A metric can have a value without confidence intervals or probabilities. - value (number or null): The metric value - ci_low (number or null): Lower bound of the 95% confidence interval - ci_high (number or null): Upper bound of the 95% confidence interval - plus_minus (number or null): Half-width of the 95% confidence interval, i.e., (ci_high - ci_low) / 2 - p2bb (number, 0-1, or null): Probability to be Best - p2bc (number, 0-1, or null): Probability to Beat Control - uplift (object): Relative lift over the control variation. Contains: - value (number or null): The relative lift (e.g., 0.12 = +12%) - ci_low (number or null): Lower bound of the 95% confidence interval for the uplift - ci_high (number or null): Upper bound of the 95% confidence interval for the uplift - plus_minus (number or null): Half-width of the uplift's 95% confidence interval Note: p2bc and uplift are relative to the control variation and appear only on non-control variations; they are absent on the control.
    - unknown
  - `audienceOrder` unknown, required
  - `histogram` unknown, required
  - `kde` unknown, required
  - `cdf` unknown, required
  - `variations` object[]
    - `id` string, uuid, required: Server-generated. Read-only.
    - `experienceId` string, uuid, required: References the parent experience.
    - `name` string, required: Display name (e.g., 'Control', 'Variant A'). Unique within the experience.
    - `percentage` number, required: Traffic allocation weight. All percentages across sibling variations must sum to 100.
    - `isControl` boolean, required: The baseline variation all others are measured against. Exactly one per experience.
    - `order` integer, required: Display order in the analytics dashboard. 0-indexed.
    - `priceChange` string, nullable: Price adjustment amount for pricing-type experiences. Positive increases price, negative discounts. Use priceChange for simple price A/B tests; use offer for structured discount campaigns (tiered, BOGO, free shipping).
    - `priceChangeUnit` 'percent' | 'dollar', nullable: How priceChange is applied: as a percentage of the original price or a fixed monetary amount.
    - `priceRoundingType` 'none' | 'nearest' | 'up' | 'down', nullable: Rounding strategy applied after priceChange (e.g., round up, round down, charm pricing).
    - `priceRoundingAmount` string, nullable: Target value for rounding (e.g., 0.99 for charm pricing like $X.99).
    - `onsiteEdits` object[], required: DOM content modifications (text, HTML, image swaps, element removal). For CSS styling changes, use onsiteInjections instead.
      - `id` string, uuid, required: Server-generated. Read-only.
      - `onsiteEditType` 'html' | 'text' | 'image' | 'hide', nullable: Content modification strategy (html, text, image, or hide).
      - `variationId` string, uuid, required: References the parent variation.
      - `find` string, nullable, required: Pattern to locate on the page. Interpreted as regex when isRegex is true.
      - `title` string, nullable: Dashboard label for identifying this edit.
      - `isRegex` boolean, required: When true, 'find' is treated as a regular expression.
      - `replace` string, required: Replacement content. Interpretation depends on onsiteEditType: HTML markup, plain text, or image URL.
      - `querySelectors` string[], required: CSS selectors scoping which DOM elements this edit targets (e.g., '.product-title').
      - `skip` boolean, required: When true, this edit is temporarily disabled without being deleted.
      - `remove` boolean, required: When true, the matched element is removed from the DOM instead of having its content replaced.
      - `groupId` string: Groups related edits together so they can be managed as a unit.
      - `isHtml` boolean, required
      - `isImage` boolean, required
      - `insertType` 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend', nullable, required: DOM insertion position relative to the target (beforebegin, afterbegin, beforeend, afterend). Null means content replacement.
      - `createdAtUrl` string, nullable: Server-generated. Read-only. Storefront URL where this edit was originally created via the visual editor.
      - `createdAtTs` number, nullable: Server-generated. Read-only. Unix timestamp in seconds.
      - `imageSearchUrl` string, nullable: URL pathname for locating images to replace. When set, images are found by URL match; when null, querySelectors is used instead.
      - `source` 'ai', nullable
    - `onsiteInjections` object, nullable: CSS styling and custom JS injection. At most one per variation. For DOM content changes (text, images, HTML), use onsiteEdits instead.
      - `id` string, uuid, required: Server-generated. Read-only.
      - `variationId` string, uuid, required: References the parent variation.
      - `customCss` string, nullable: CSS injected globally on the page when this variation is active.
      - `customJs` string, nullable: JavaScript executed on the page. Execution timing controlled by jsInjectionMode.
      - `jsInjectionMode` object, required: Controls when customJs runs: immediately on load, after window load, or after a configurable delay.
        - `type` 'immediately' | 'onWindowLoad' | 'timeout', required: Execution timing for injected JS. When 'timeout', the timeout field specifies the delay.
        - `timeout` union: Delay in milliseconds before JS execution. Only relevant when type is 'timeout'.
          - number
          - string
      - `source` 'ai', nullable
    - `offer` object, nullable: Structured discount configuration (tiered volume discounts, cart-level discounts, gift-with-purchase, free shipping). Use offer for campaign/discount experiences; use priceChange for simple price A/B tests.
      - `id` string, uuid, required: Server-generated. Read-only.
      - `variationId` string, uuid, required: References the parent variation this offer belongs to.
      - `enabled` boolean, required: Whether the offer is actively applying discounts to customers on the storefront.
      - `isTest` boolean, required: Set on some offers the app copied between test groups. It doesn't mean draft and doesn't change who gets the discount; an offer saved with it true is renamed 'Volume Offer Test Group'. The external API always saves false.
      - `isArchived` boolean, required: Whether the offer has been archived and is no longer active.
      - `name` string, required: Internal label for identifying the offer in dashboards.
      - `unitType` 'unit' | 'dollar', required: Threshold basis for tiered discounts: per-item quantity or monetary amount spent.
      - `discountType` 'percentage' | 'dollar', required: How the discount value is calculated (e.g., percentage off, fixed amount off).
      - `tiers` object[], required: Volume discount tiers ordered by threshold ascending (e.g., buy 2 = 10% off, buy 3 = 15% off).
        - `id` string, uuid, required
        - `minimumUnits` number, required
        - `maximumUnits` number, required
        - `unitDiscount` number, required
        - `bxgyGetQuantity` integer, required
        - `discountTitle` string, nullable, required
        - `giftWithPurchaseTitle` string, nullable, required
        - `isFreeShipping` boolean, required
        - `isGiftWithPurchase` boolean, required
        - `giftWithPurchaseProductId` string, nullable
        - `giftWithPurchaseVariantId` string, nullable
        - `giftWithPurchaseVariantIds` string[], required
        - `autoAddGiftWithPurchase` boolean, required
        - `giftWithPurchaseHandle` string, nullable
      - `maximumDollarDiscount` number, nullable: Hard cap on the total dollar discount. Null means no cap is applied.
      - `discountApplicationType` 'tieredDiscount' | 'cartDiscount' | 'freeGift' | 'freeShipping' | 'buyXGetY' | '', required: Core discount mechanic (tiered volume, flat cart-level, gift-with-purchase, or free shipping).
      - `discountApplicationMethod` 'perItem' | 'perOrder', required: Whether the discount applies per individual item or to the entire order.
      - `combinesWithIntelligems` boolean, required: Whether this offer stacks with other active Intelligems discounts.
      - `combinesWithShopify` boolean, required: Whether this offer stacks with native Shopify discount codes.
      - `shouldRejectCodes` boolean, required: When true, manual discount codes entered at checkout are rejected while this offer is active.
      - `shippingDiscount` object, nullable, required: Shipping discount details. Only present when discountApplicationType is freeShipping.
        - `id` string, uuid, required
        - `discountType` 'percentage' | 'dollar', required
        - `unitDiscount` number, required: Percent off the shipping rate. 100 is free shipping.
        - `rateFilter` union, required
          - object
            - `type` 'amount', required
            - `amount` number
          - object
            - `type` 'name', required
            - `rules` object[], required
              - …
        - `countryFilter` object, nullable, required
          - `allow` string[]
          - `exclude` string[]
        - `discountLabel` string, nullable, required
      - `requireSameItem` boolean, required: For tiered discounts: when true, only multiples of the same product count toward thresholds.
      - `bxgyGetProductScope` 'all' | 'list', nullable: For Buy X Get Y: where the free units come from. Null means the products bought; 'list' means the offer's get products; 'all' means any product.
      - `subscriptionApplicationType` 'oneTime' | 'firstSub' | 'oneTimeAndFirstSub', required: Controls which purchase types this offer applies to: 'oneTime' (one-time purchases only), 'firstSub' (first subscription orders only), or 'oneTimeAndFirstSub' (both one-time and first subscription orders). Free shipping offers (discountApplicationType 'freeShipping') always apply to both and are saved as 'oneTimeAndFirstSub'.
    - `offerId` string, uuid, nullable: Server-generated. Read-only. References the associated offer. Populated when offer is set.
    - `shippingRateGroups` object[]: Shipping rate overrides. Only populated for shipping test experiences.
      - `id` string, uuid, required
      - `groupType` 'flatRate' | 'flatRateWithThreshold' | 'thresholdOnly' | 'tieredByPriceOrWeight' | 'custom', required
      - `position` number, required
      - `rates` object[], required
        - `id` string, uuid
        - `name` string, required
        - `amount` number, required
        - `rateCode` string, nullable
        - `rateType` 'amount' | 'threshold' | 'tier', required
        - `currency` 'AED' | 'AFN' | 'ALL' | 'AMD' | 'ANG' | 'AOA' | 'ARS' | 'AUD' | 'AWG' | 'AZN' | 'BAM' | 'BBD' | 'BDT' | 'BGN' | 'BIF' | 'BMD' | 'BND' | 'BOB' | 'BRL' | 'BSD' | 'BWP' | 'BZD' | 'CAD' | 'CDF' | 'CHF' | 'CLP' | 'CNY' | 'COP' | 'CRC' | 'CVE' | 'CZK' | 'DJF' | 'DKK' | 'DOP' | 'DZD' | 'EGP' | 'ETB' | 'EUR' | 'FJD' | 'FKP' | 'GBP' | 'GEL' | 'GIP' | 'GMD' | 'GNF' | 'GTQ' | 'GYD' | 'HKD' | 'HNL' | 'HRK' | 'HTG' | 'HUF' | 'IDR' | 'ILS' | 'INR' | 'ISK' | 'JMD' | 'JPY' | 'KES' | 'KGS' | 'KHR' | 'KMF' | 'KRW' | 'KYD' | 'KZT' | 'LAK' | 'LBP' | 'LKR' | 'LRD' | 'LSL' | 'MAD' | 'MDL' | 'MGA' | 'MKD' | 'MMK' | 'MNT' | 'MOP' | 'MUR' | 'MVR' | 'MWK' | 'MXN' | 'MYR' | 'MZN' | 'NAD' | 'NGN' | 'NIO' | 'NOK' | 'NPR' | 'NZD' | 'PAB' | 'PEN' | 'PGK' | 'PHP' | 'PKR' | 'PLN' | 'PYG' | 'QAR' | 'RON' | 'RSD' | 'RUB' | 'RWF' | 'SAR' | 'SBD' | 'SCR' | 'SEK' | 'SGD' | 'SHP' | 'SLL' | 'SRD' | 'STD' | 'SZL' | 'THB' | 'TJS' | 'TOP' | 'TRY' | 'TTD' | 'TWD' | 'TZS' | 'UAH' | 'UGX' | 'USD' | 'UYU' | 'UZS' | 'VND' | 'VUV' | 'WST' | 'XAF' | 'XCD' | 'XOF' | 'XPF' | 'YER' | 'ZAR' | 'ZMW', required
        - `condition` object, nullable
          - `id` string, uuid
          - `min` union, required
            - number
            - string
          - `max` union
            - number
            - string
          - `conditionType` 'currency' | 'weight', required
          - `unit` 'g' | 'kg' | 'lb' | 'oz', nullable
        - `description` string, nullable
      - `variationId` string, uuid, required
      - `scopes` object[], nullable
        - `marketId` string, required
        - `collectionIds` string[], nullable, required
        - `originLocationIds` string[], required
    - `excludeProducts` boolean: When true, specific products are excluded from price changes. Use excludeProducts when most products should be tested and only a few excluded. Mutually exclusive with includeProducts.
    - `includeProducts` boolean: When true, only specific products receive price changes. Use includeProducts when only a few products should be tested. Mutually exclusive with excludeProducts.
    - `testExperienceId` string, nullable: Links to another experience for advanced multi-experience configurations.
    - `functionSyncError` boolean, required: Server-generated. Read-only. Indicates a sync failure with Shopify Functions for this variation's discount.
    - `redirects` object[]: URL redirect rules for content/url experiences.
      - `id` string, uuid, required: Server-generated. Read-only.
      - `group` number, required: Numeric group for organizing related redirects. Redirects sharing an originUrl should share a group number.
      - `variationId` string, uuid, required: References the parent variation.
      - `originUrl` string, required: URL pattern matched against visitor page URLs. Matching behavior depends on the 'filter' field.
      - `destinationUrl` string, nullable: Target URL visitors are sent to. Used when redirectType is 'fullReplacement'.
      - `queryParams` object[], required: Key-value pairs appended to the destination URL as query parameters.
        - `key` string, required: Query parameter name appended to the destination URL.
        - `value` string, required: Query parameter value.
      - `skip` boolean, required: When true, this redirect is temporarily disabled.
      - `isThemeTest` boolean, required: True when this redirect tests alternate Shopify themes. Used with content/theme experiences.
      - `isTemplateTest` boolean, required: True when this redirect tests alternate Shopify templates. Used with content/template experiences.
      - `templateType` '404' | '' | 'article' | 'blog' | 'cart' | 'collection' | 'index' | 'list-collections' | 'page' | 'password' | 'product' | 'search', nullable: Shopify template type being tested (e.g., product, collection).
      - `templateSuffixes` string[], nullable, required: Alternate Shopify template suffixes being tested (e.g., 'alternate', 'new-layout').
      - `redirectOnce` boolean, required: When true, the redirect fires only once per visitor session to avoid redirect loops.
      - `filter` 'matchesExactly' | 'contains' | 'endsWith' | 'matchesRegex' | 'none', required: Matching strategy for originUrl (e.g., exact match, contains, endsWith, regex).
      - `find` string, nullable: Pattern to locate within the URL for partial replacement. Only used when redirectType is 'partialReplacement'.
      - `redirectType` 'fullReplacement' | 'partialReplacement', required: fullReplacement navigates to destinationUrl; partialReplacement swaps only the 'find' match within the current URL.
    - `userInterfaces` object[]: UI widget configurations displayed for this variation.
      - `id` string, uuid, required
      - `isEnabled` boolean
      - `isArchived` boolean, required
      - `widget` object
        - `id` string, uuid, required
        - `name` string, required
        - `enabledSitewide` boolean, required
        - `parentId` string, uuid, nullable
        - `widgetType` 'messageBoxPopup' | 'messageBoxSlideOut' | 'quantityButtons' | 'discountProgressBar' | 'shippingProgressBar' | 'gwpVariantPicker', required
        - `config` object, required
          - `desktop` unknown
          - `mobile` unknown
      - `widgetId` string, required
      - `category` 'quantityButtons' | 'progressBar' | 'messageBox' | 'gwpVariantPicker'
      - `variationId` string, uuid, nullable
      - `desktopVariables` unknown
      - `mobileVariables` unknown
      - `styleOverrides` unknown
    - `checkoutBlocks` union[]: Shopify checkout extensibility block configurations for this variation.
      - union
        - object
          - `id` string, uuid, required: Server-generated. Read-only.
          - `variationId` string, uuid, required: References the parent variation.
          - `locationId` string, required: Shopify checkout extensibility target location where the block renders.
          - `blockType` 'trustBadge', required
          - `blockTemplate` 'badgeList' | 'badgeTiles' | 'callOut' | 'grid' | 'header' | 'images' | 'brandLogo' | 'textOnly', nullable: The template preset this block was created from, within its block type. Null on blocks saved before templates were persisted, which callers must treat as unknown rather than assuming a default.
          - `name` string, required: Display name for identifying this block in the dashboard.
          - `displayConditions` object: Optional cart-based conditions; the block renders only when the expression evaluates true against the current cart.
            - `id` string, uuid, required
            - `expression` object[], required
              - …
          - `variables` object, required: Configurable content for the trust badge (e.g., badge images, guarantee text).
            - `headerText` union, required
              - …
            - `items` object[], required
              - …
          - `styles` object, required: CSS styling overrides for the trust badge appearance.
            - `typography` object, required
              - …
            - `backgroundColors` object, required
              - …
            - `colors` object, required
              - …
            - `layout` object, required
              - …
            - `appearance` object, required
              - …
        - object
          - `id` string, uuid, required: Server-generated. Read-only.
          - `variationId` string, uuid, required: References the parent variation.
          - `locationId` string, required: Shopify checkout extensibility target location where the block renders.
          - `blockType` 'upsell', required
          - `blockTemplate` 'productTiles' | 'productList' | 'singleProduct' | 'singleProductCheckbox', nullable: The template preset this block was created from, within its block type. Null on blocks saved before templates were persisted, which callers must treat as unknown rather than assuming a default.
          - `name` string, required: Display name for identifying this block in the dashboard.
          - `displayConditions` object: Optional cart-based conditions; the block renders only when the expression evaluates true against the current cart.
            - `id` string, uuid, required
            - `expression` object[], required
              - …
          - `variables` object, required: Configurable content for the upsell block (e.g., product selection, heading text, CTA label).
            - `headerText` union, required
              - …
            - `maxProductLimit` integer, required
            - `excludeItemsInCart` boolean, required
            - `excludeOutOfStock` boolean, required
            - `buttonText` string, required
            - `imageSize` number, required
            - `imageSizeUnit` 'pixels' | 'percentage', required
            - `imageAspectRatio` string, required
            - `mediaSpacing` string, required
            - `discount` object
              - …
          - `styles` object, required: CSS styling overrides for the upsell block appearance.
            - `typography` object, required
              - …
            - `backgroundColors` object, required
              - …
            - `colors` object, required
              - …
            - `layout` object, required
              - …
            - `appearance` object, required
              - …
          - `upsellProductRules` object[], required: Product selection and recommendation rules that determine which products to show in this upsell block.
            - `id` string, uuid, required
            - `checkoutBlockId` string, uuid, required
            - `priority` integer, required
            - `cartTargeting` object, required
              - …
            - `action` Schema0, required
              - …
            - `variationId` string, uuid, required
          - `agenticLogicPlacementId` string, uuid, nullable: Agentic Logic placement this block evaluates through. Absent means the legacy rule engine serves it — clearing the mapping is the per-surface rollback.
          - `agenticLogicRuleId` string, uuid, nullable: WRITE-SIDE intent: the Agentic Logic rule this block should serve. The experience save upserts the placement and the (placement, variation) assignment from it and stamps `agenticLogicPlacementId`, so callers never assemble that pair themselves. Null detaches the block and returns it to the legacy engine. Reads echo the rule currently assigned.
        - object
          - `id` string, uuid, required: Server-generated. Read-only.
          - `variationId` string, uuid, required: References the parent variation.
          - `locationId` string, required: Shopify checkout extensibility target location where the block renders.
          - `blockType` 'shippingProgressBar', required
          - `blockTemplate` 'minimal' | 'milestones', nullable: The template preset this block was created from, within its block type. Null on blocks saved before templates were persisted, which callers must treat as unknown rather than assuming a default.
          - `name` string, required: Display name for identifying this block in the dashboard.
          - `displayConditions` object: Optional cart-based conditions; the block renders only when the expression evaluates true against the current cart.
            - `id` string, uuid, required
            - `expression` object[], required
              - …
          - `variables` object, required
            - `headerText` union
              - …
            - `currency` string, required
            - `template` 'minimal' | 'milestones', required
            - `tiers` object[], required
              - …
          - `styles` object, required
            - `typography` object, required
              - …
            - `backgroundColors` object, required
              - …
            - `colors` object, required
              - …
            - `layout` object, required
              - …
            - `appearance` object, required
              - …
        - object
          - `id` string, uuid, required: Server-generated. Read-only.
          - `variationId` string, uuid, required: References the parent variation.
          - `locationId` string, required: Shopify checkout extensibility target location where the block renders.
          - `blockType` 'timer', required
          - `blockTemplate` 'textCountdown' | 'digitalClock' | 'inlinePill', nullable: The template preset this block was created from, within its block type. Null on blocks saved before templates were persisted, which callers must treat as unknown rather than assuming a default.
          - `name` string, required: Display name for identifying this block in the dashboard.
          - `displayConditions` object: Optional cart-based conditions; the block renders only when the expression evaluates true against the current cart.
            - `id` string, uuid, required
            - `expression` object[], required
              - …
          - `variables` object, required
            - `timerMode` 'fixedDate' | 'perVisitor' | 'recurring', required
            - `endDateTime` string, nullable
            - `durationMinutes` integer, required
            - `resetIntervalUnit` 'hour' | 'day' | 'week', nullable
            - `resetTimeOfDay` string, nullable
            - `resetDayOfWeek` union
              - …
            - `resetMinuteOfHour` integer, nullable
            - `resetTimezone` string, nullable
            - `expiredBehavior` 'remove' | 'showText', required
            - `timerTemplate` 'textCountdown' | 'digitalClock' | 'inlinePill', required
            - `showDays` boolean, required
            - `showHours` boolean, required
            - `showMinutes` boolean, required
            - `showSeconds` boolean, required
            - `countdownText` union, required
              - …
            - `expiredText` union, required
              - …
            - `headline` union, required
              - …
          - `styles` object, required
            - `typography` object, required
              - …
            - `backgroundColors` object, required
              - …
            - `colors` object, required
              - …
            - `layout` object, required
              - …
            - `appearance` object, required
              - …
            - `digits` object, required
              - …
        - object
          - `id` string, uuid, required: Server-generated. Read-only.
          - `variationId` string, uuid, required: References the parent variation.
          - `locationId` string, required: Shopify checkout extensibility target location where the block renders.
          - `blockType` 'faqs', required
          - `blockTemplate` 'faqsAccordion', nullable: The template preset this block was created from, within its block type. Null on blocks saved before templates were persisted, which callers must treat as unknown rather than assuming a default.
          - `name` string, required: Display name for identifying this block in the dashboard.
          - `displayConditions` object: Optional cart-based conditions; the block renders only when the expression evaluates true against the current cart.
            - `id` string, uuid, required
            - `expression` object[], required
              - …
          - `variables` object, required
            - `headerText` union
              - …
            - `showDivider` boolean, required
            - `allowMultipleOpen` boolean, required
            - `questions` object[], required
              - …
          - `styles` object, required
            - `typography` object, required
              - …
            - `backgroundColors` object, required
              - …
            - `colors` object, required
              - …
            - `layout` object, required
              - …
            - `appearance` object, required
              - …
        - object
          - `id` string, uuid, required: Server-generated. Read-only.
          - `variationId` string, uuid, required: References the parent variation.
          - `locationId` string, required: Shopify checkout extensibility target location where the block renders.
          - `blockType` 'postPurchaseUpsell', required
          - `blockTemplate` unknown
          - `name` string, required: Display name for identifying this block in the dashboard.
          - `displayConditions` object: Optional cart-based conditions; the block renders only when the expression evaluates true against the current cart.
            - `id` string, uuid, required
            - `expression` object[], required
              - …
          - `variables` object, required
            - `headerText` string, required
            - `discountType` 'none' | 'percentage' | 'fixed', required
            - `discountValue` number, nullable
            - `compareAtPriceDisplay` 'none' | 'compareAtPrice' | 'regularPrice', required
            - `imageAspectRatio` string, required
            - `excludeOutOfStock` boolean, required
            - `excludeItemsInCart` boolean, required
            - `maxProductLimit` integer, required
            - `bannerEnabled` boolean, required
            - `bannerTitle` string
            - `bannerSubtitle` string
            - `customerFirstNameFallback` string
            - `compareAtPriceEnabled` boolean, required
            - `descriptionEnabled` boolean, required
            - `quantitySelectorEnabled` boolean, required
            - `quantityLabel` string
            - `maxQuantityType` string
            - `maxQuantity` integer
            - `moneyLineEnabled` boolean, required
            - `moneyLineSubtotal` boolean, required
            - `moneyLineShipping` boolean, required
            - `moneyLineTaxes` boolean, required
            - `primaryButtonText` string, required
            - `secondaryButtonEnabled` boolean, required
            - `secondaryButtonText` string, required
            - `headingLevel` string, required
            - `countdownTimerEnabled` boolean
            - `timerCheckout` object
              - …
            - `offerTimeout` number
            - `discount` object
              - …
          - `styles` object, required
            - `typography` object, required
              - …
            - `backgroundColors` object, required
              - …
            - `colors` object, required
              - …
            - `appearance` object, required
              - …
          - `upsellProductRules` object[], required: Product selection and recommendation rules that determine which products to show in this upsell block.
            - `id` string, uuid, required
            - `checkoutBlockId` string, uuid, required
            - `priority` integer, required
            - `cartTargeting` object, required
              - …
            - `action` Schema0, required
              - …
            - `variationId` string, uuid, required
          - `agenticLogicPlacementId` string, uuid, nullable: Agentic Logic placement this block evaluates through. Absent means the legacy rule engine serves it — clearing the mapping is the per-surface rollback.
          - `agenticLogicRuleId` string, uuid, nullable: WRITE-SIDE intent: the Agentic Logic rule this block should serve. The experience save upserts the placement and the (placement, variation) assignment from it and stamps `agenticLogicPlacementId`, so callers never assemble that pair themselves. Null detaches the block and returns it to the legacy engine. Reads echo the rule currently assigned.
    - `cartTargeting` object[]: Cart-based targeting rules that determine when this variation is shown based on cart contents.
      - `id` string, uuid, required
      - `expression` object[], required
        - `query` object
          - `key` 'anything' | 'productId' | 'collection' | 'tag' | 'cartSubtotal' | 'cartItemCount' | 'subscription', required
          - `type` 'anything' | 'productId' | 'collection' | 'tag' | 'cartSubtotal' | 'cartItemCount' | 'subscription', required
          - `filter` 'includes' | 'doesNotInclude' | 'greaterThan' | 'lessThan' | 'equalTo' | 'greaterThanOrEqual' | 'lessThanOrEqual' | 'between', required
          - `value` union
            - string
            - number
            - object
        - `operator` 'and' | 'or' | 'start_paren' | 'end_paren'
    - `components` object[]: Onsite component configurations (e.g. onsite upsells) rendered on the storefront for this variation.
      - `id` string, uuid, required: Server-generated. Read-only.
      - `variationId` string, uuid, required: References the parent variation this component belongs to.
      - `config` union, required: The saved upsell: its type, look, products, targeting, and discount.
        - object
          - `type` 'onsiteUpsell', required: Discriminator for the component kind.
          - `placement` object, required: Where in the DOM the rendered upsell is injected.
            - `selector` string: Selector-mode placement: CSS selector for the anchor element the upsell is inserted near. Unset when anchorKey is used.
            - `insertType` 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend': Selector-mode placement: where, relative to the anchor element, the upsell is inserted (before/after, inside start/end). Unset when anchorKey is used.
            - `anchorKey` string: Anchor-mode placement: the key a merchant gave the Intelligems Content theme app block. The upsell renders inside every block on the page carrying this key. Unset when selector is used.
            - `location` 'pdp' | 'cart', required: Semantic page context this upsell renders in (pdp or cart). Drives the plugin's activation/re-render strategy and labels/groups the upsell in analytics.
          - `template` string, required: HTML for the upsell, including all static copy written inline. The per-product card is the markup between {{#each products}} and {{/each}}. May only reference declared slots: product.* data slots and the named slots (atc, variant-select); everything else is literal HTML.
          - `maxProductLimit` integer, required: Maximum number of products to render.
          - `excludeOutOfStock` boolean, required: Exclude products whose variants are all out of stock. Defaults to true.
          - `excludeItemsInCart` boolean, required: Exclude products already in the shopper's cart. Defaults to true.
          - `excludePdpProduct` boolean, required: On a PDP, exclude the product being viewed. Defaults to true; turn it off when the viewed product belongs in the result, e.g. a bundle built around it.
          - `discount` object: Optional discount applied to products added from this upsell.
            - `discountType` 'none' | 'percentage' | 'fixed', required
            - `discountValue` number, nullable
            - `compareAtPriceDisplay` 'none' | 'compareAtPrice' | 'regularPrice', required
          - `rules` object[], required: Prioritized list of rules. Each pairs an action (which products) with targeting (when to show). v1 ships a single rule.
            - `id` string, required: Stable identifier for this rule. Owns the rule's targeting row(s) in the targeting table.
            - `priority` integer, required: Evaluation order. Lower numbers are checked first; the first rule whose targeting matches wins.
            - `action` object[], required: Which products to load when this rule matches (Shopify recommendations, specific products, collection, or tag).
              - …
            - `targeting` union, required: When this rule shows. Boolean expression over the chosen domain, evaluated to decide whether the upsell renders.
              - …
          - `agenticLogicPlacementId` string, uuid, nullable: Agentic Logic placement this upsell evaluates through. Absent means the legacy rule engine serves it — clearing the mapping is the per-surface rollback.
          - `agenticLogicRuleId` string, uuid, nullable: WRITE-SIDE intent: the Agentic Logic rule this upsell should serve. The experience save upserts the placement and the (placement, variation) assignment from it and stamps `agenticLogicPlacementId`, so callers never assemble that pair themselves. Null detaches the component and returns it to the legacy engine. Reads echo the rule currently assigned; the field is never persisted in the stored config.
        - object
          - `type` 'bundleOnsiteUpsell', required: Discriminator for the component kind.
          - `placement` object, required: Where in the DOM the rendered bundle is injected.
            - `selector` string: Selector-mode placement: CSS selector for the anchor element the upsell is inserted near. Unset when anchorKey is used.
            - `insertType` 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend': Selector-mode placement: where, relative to the anchor element, the upsell is inserted (before/after, inside start/end). Unset when anchorKey is used.
            - `anchorKey` string: Anchor-mode placement: the key a merchant gave the Intelligems Content theme app block. The upsell renders inside every block on the page carrying this key. Unset when selector is used.
            - `location` 'pdp' | 'cart', required: Semantic page context this upsell renders in (pdp or cart). Drives the plugin's activation/re-render strategy and labels/groups the upsell in analytics.
          - `template` string, required: HTML for the bundle card. The per-product row is the markup between {{#each products}} and {{/each}}; the surrounding shell holds the copy slots ({{heading}}, {{subheading}}) and the footer the whole selection shares ({{bundle.price}}, {{bundle.comparePrice}}, {{bundle.atc}}). Each row holds {{checkbox}}, {{product.image}}, {{product.url}}, {{product.title}}, {{product.price}}, {{product.compareAtPrice}} and {{variant-select}}. Every slot is required, even when editing. May only reference declared slots; everything else is literal HTML. No `<script>` tags or inline JavaScript.
          - `copy` object, required: Shopper-facing text, edited in the panel rather than inline in the template.
            - `heading` string, required: Headline above the bundle's products.
            - `subheading` string: Optional line under the heading, shown when no discount tier is active.
            - `buttonText` string, required: Label on the bundle's single add-to-cart button.
            - `rowBadgeLabel` string: Per-product discount chip. Accepts #placeholders (see BUNDLE_COPY_FIELD_VARIABLES); defaulted when omitted.
            - `savedLabel` string: Footer 'amount saved' badge. Accepts #placeholders (see BUNDLE_COPY_FIELD_VARIABLES); defaulted when omitted.
            - `sublineToNextTier` string: Subheading while adding products unlocks a better tier. Accepts #placeholders (see BUNDLE_COPY_FIELD_VARIABLES); defaulted when omitted.
            - `sublineAtTopTier` string: Subheading once the top tier is reached. Accepts #placeholders (see BUNDLE_COPY_FIELD_VARIABLES); defaulted when omitted.
          - `maxProductLimit` integer, required: Number of products the bundle offers.
          - `allowItemSelection` boolean, required: Whether the shopper can choose which of the bundle's products to add. When false every rendered product is included; exclusions can still trim how many render, so lower tiers stay reachable.
          - `excludeOutOfStock` boolean, required: Exclude products whose variants are all out of stock. Defaults to true.
          - `excludeItemsInCart` boolean, required: Exclude products already in the shopper's cart. Defaults to true.
          - `excludePdpProduct` boolean, required: On a PDP, exclude the product being viewed. Defaults to true; turn it off when the viewed product belongs in the result, e.g. a bundle built around it.
          - `discount` object: Optional count-tiered discount applied to the products added from this bundle.
            - `discountType` 'none' | 'percentage' | 'fixed', required: How the bundle discount is expressed: a percentage off, or a fixed amount off each product.
            - `discountTiers` object[], required: The discount ladder. Each tier's minimumProducts is a threshold, so a tier applies at that many selected products or more, and the highest qualifying tier wins — tiers are not cumulative. A selection below every threshold earns nothing, and a flat discount is a single tier at one product.
              - …
            - `compareAtPriceDisplay` 'none' | 'compareAtPrice' | 'regularPrice', required: Which reference price to strike through next to the discounted price.
          - `rules` object[], required: Prioritized list of rules. Each pairs an action (which products) with targeting (when to show).
            - `id` string, required: Stable identifier for this rule. Owns the rule's targeting row(s) in the targeting table.
            - `priority` integer, required: Evaluation order. Lower numbers are checked first; the first rule whose targeting matches wins.
            - `action` object[], required: Which products to load when this rule matches (Shopify recommendations, specific products, collection, or tag).
              - …
            - `targeting` union, required: When this rule shows. Boolean expression over the chosen domain, evaluated to decide whether the upsell renders.
              - …
          - `agenticLogicPlacementId` string, uuid, nullable: Agentic Logic placement this bundle selects its products through. Absent means the legacy rule engine serves it — clearing the mapping is the per-surface rollback. The engine chooses PRODUCTS only: a bundle's tiered discount always comes from `discount` below, never from the result envelope, which can only carry one flat value.
          - `agenticLogicRuleId` string, uuid, nullable: WRITE-SIDE intent: the Agentic Logic rule this bundle should serve. The experience save upserts the placement and the (placement, variation) assignment from it and stamps `agenticLogicPlacementId`, so callers never assemble that pair themselves. Null detaches the component and returns it to the legacy engine. Reads echo the rule currently assigned; the field is never persisted in the stored config. The engine chooses PRODUCTS only — a bundle's tiers always come from its own `discount`.
  - `graphs` object[]: Pre-rendered graph images. Only included when graphs are requested. When the requested output format is 'base64' (`graphs.outputFormat` on the POST endpoint, or the `graphOutput` query parameter on the deprecated GET variant), each graph includes a 'data' field with the base64-encoded PNG. Otherwise, each graph includes a 'url' field with the image URL (expires after 30 days).
    - `id` string, required
    - `key` string: The original graph key from the query parameter (e.g., 'conversion_rate', 'net_revenue_per_visitor').
    - `url` string: URL of the rendered graph image. Included when the requested output format is 'png' (the default) — that is `graphs.outputFormat` on POST /analytics/resource/{experienceId}, or the `graphOutput` query parameter on the deprecated GET variant. Expires after 30 days — download and store externally if you need to retain it longer.
    - `data` string: Base64-encoded PNG image data. Included when the requested output format is 'base64' — that is `graphs.outputFormat` on POST /analytics/resource/{experienceId}, or the `graphOutput` query parameter on the deprecated GET variant.
    - `type` string, required: Chart type for the rendered graph (e.g. 'bar').
    - `title` string, required: Display title of the rendered graph.
  - `experienceId` string, uuid
  - `experienceName` string
  - `downsample` object
    - `from` 'HOUR' | 'DAY' | 'WEEK', required
    - `to` 'HOUR' | 'DAY' | 'WEEK', required
  - `impact` object
    - `est_monthly_revenue_increase` number, nullable, required: Estimated monthly revenue increase for the best-performing non-control variation compared to the control, extrapolated to a 30-day period. Calculated as: Math.round((treatment_rpv - control_rpv) * total_visitors * (30 / test_days)), where rpv is net_revenue_per_visitor. Uses whole-variation overview metrics with the same filters and time window, including for audience views. Null for post_test views or when insufficient data is available.
  - `testResult` union: Test verdict object (verdict plus supporting fields). Present only when the testResult request param is true and a verdict is available.
    - object
      - `verdict` 'strong_win' | 'directional_win' | 'directional_loss' | 'strong_loss' | 'mixed_signals', required
      - `action_to_take` string, required
      - `runtime_days` number, required
      - `orders_per_variant` object, required
      - `primary_metric` object, required
        - `key` string, required
        - `best_challenger` object, required
          - `variant` string, required
          - `p2bb` number, nullable, required
          - `uplift` number, nullable, required
          - `uplift_ci_width` number, nullable, required
          - `stability` object, required
            - `days_held` number, nullable, required
            - `p2bb_stable` boolean, required
            - `uplift_ci_converged` boolean, required
      - `conflicting_metrics` object[], required
        - `key` string, required
        - `uplift` number, nullable, required
        - `p2bb` number, nullable, required
    - object
      - `verdict` 'filtered_strong_win' | 'filtered_directional_win' | 'filtered_directional_loss' | 'filtered_strong_loss' | 'filtered_mixed_signals', required
      - `action_to_take` string, required
      - `runtime_days` number, required
      - `orders_per_variant` object, required
      - `primary_metric` object, required
        - `key` string, required
        - `best_challenger` object, required
          - `variant` string, required
          - `p2bb` number, nullable, required
          - `uplift` number, nullable, required
          - `uplift_ci_width` number, nullable, required
          - `stability` object, required
            - `days_held` number, nullable, required
            - `p2bb_stable` boolean, required
            - `uplift_ci_converged` boolean, required
      - `conflicting_metrics` object[], required
        - `key` string, required
        - `uplift` number, nullable, required
        - `p2bb` number, nullable, required
    - object
      - `verdict` 'not_ready' | 'filtered_not_ready', required
      - `runtime_days` number, required
      - `orders_per_variant` object, required
    - object
      - `verdict` 'error', required
      - `reason` string, required

## Other responses

- `429`: Too Many Requests

---

[API](https://skmtc.dev/intelligems/apis/intelligems-external-api-v25-10-beta.md) - [All operations](https://skmtc.dev/intelligems/apis/intelligems-external-api-v25-10-beta/llms.txt) - [OpenAPI document](https://skmtc.dev/intelligems/apis/intelligems-external-api-v25-10-beta/revisions/7b769b2f90b1?raw)
