Nothing goes live until a real cart agrees.

A publish creates the offer's discounts and option maps, then builds a real Storefront cart for every visible option. The version goes live only if every one of them matched, and live offers are re-checked on real carts on a daily rotation.

Publish: a real cart proves the priceIn production

What publish does

In production

One publish call starts a durable workflow on the store. It runs these steps in order:

  1. Create the Shopify discount codes for options that use one.
  2. Rewrite the option maps the discount function reads at checkout.
  3. Write the cart transform's map, where an option needs it and the store has registered the transform.
  4. Build a real Storefront cart for every visible option, plus the no-pointer, forged-pointer, landing-page and free-shipping checks, and, for subscription options, read the renewals discount that prices every later billing cycle.
  5. Go live, but only if every visible option matched.

Offer Suite creates no order tags and no gift products: a gift is a product the store already sells, priced to $0 at checkout. Over MCP, publish_offer needs confirm: true and refuses without it. Over the API, the POST /offers/{id}/publish call is the approval. Each run can be read back with get_publish_run.

What every visible option is checked for

In production

The verifier builds each option's cart on the store's own Storefront API, reads what Shopify charged and abandons the cart. It compares each line with the offer document and prices the expectation with the same line-pricing module the buy box's prices come from.

The checks the verifier runs on each visible option, and the names a publish run reports them under. A check that does not apply to the option (no codes, no bundle, no presentation) is not run, and a presentation's line_override check is always skipped.

CheckWhat it provesOn which cart
Linesline_present, line_quantity, line_net, line_allocation, line_properties, no_extra_linesEach line is in the cart at the promised quantity, nets the promised price, and its discount came from the mechanism the offer names. No line the option does not promise is in the cart.The option's cart
Cart attributespointer_attribute_present, tracking_attributes_presentThe cart carries the offer's pointer and tracking attributes.The option's cart
Discount codescode_applicableEvery code the option uses applies to the lines it should.The option's cart
Selling planselling_planA subscription line carries the brand's selling plan.The option's cart
Bundle componentsbundle_present, bundle_components, bundle_net, bundle_allocation, line_componentsA merged bundle's parent holds its components at the promised price, or an expanded line splits into them.The option's cart
Shopify cart warningsline_warning, cart_warningShopify changed nothing: a warning on any line, or on the cart, fails the option.The option's cart
Promised first chargepromised_first_charge, presentment_currencyThe cart total equals the first charge the offer promises, in the store's currency.The option's cart
No pointer, no discountno_pointer_no_allocation, no_pointer_no_transformThe same lines without the offer's pointer get nothing from the discount function, and no line is merged, expanded or repriced.A second cart, no pointer
Forged pointerforged_pointer_nothingFor an option with a presentation, a cart carrying a forged pointer gets nothing.A third cart, forged pointer
Free shippingfree_shipping, free_shipping_warningThe rates the option frees charge $0 on a real delivery cart, with no Shopify warning. US markets only.A delivery cart, US address
Renewalpromised_renewal, recurring_discount, free_shipping_renewalsThe renewal price (the plan's adjustment less the recurring rule) equals the promise, and the renewals discount is active on every cycle.The option's cart's selling plan, and the renewals discount's settings
Landing pagepage_bindAn optional landing page, fetched, references the offer.No cart: the page is fetched
Resultmatched when every check passes on every visible option. Only then can the version go live.

Offers

OfferStatusVersionCart checkOrdersNet revenueMarginvs forecast30 days
OF_DEV_KITSchoose-your-kit-v1Livev3 · draft v4Match3/31,284$71,420.00$31,206.40+$2,628.409.2%
OF_DEV_RITUALritual-set-sub-v1Livev1Match1/1612$35,863.20$11,738.16−$617.805.0%
OF_MUG_GWPgift-with-purchase-v2Draftv2Not cart-verifiable2/3–––––
OF_FROTHER_BUNDLEbundle-and-save-v1Livev2Mismatch1/2208$14,559.00$4,021.30−$884.1018.0%
OF_BFCM_TRIPLEtiered-quantity-v1Draftv1Unverified0/3–––––
OF_SUMMER_STARTERchoose-your-kit-v0Retiredv5Match3/33,940$201,104.00$84,249.50––
OfferStatusCart check
OF_DEV_KITSlive · v3 · draft v4matched3 of 3
OF_DEV_RITUALlive · v1matched1 of 1
OF_MUG_GWPdraft · v2unverifiable2 of 3
OF_FROTHER_BUNDLElive · v2mismatched1 of 2
OF_BFCM_TRIPLEdraft · v1not checked yet0 of 3
OF_SUMMER_STARTERretired · v5matched3 of 3
The dashboard's offers list. Cart check counts the visible options that matched, in the verifier's words: matched, mismatched, unverifiable or not checked yet (the dashboard's own chips read Match, Mismatch, Not cart-verifiable and Unverified). A draft that did not match stays a draft; a live offer that fails a later check shows it here (OF_FROTHER_BUNDLE) while the theme block stops selling the unmatched option. Specimen data.

878 carts

The shared line-pricing module the verifier uses matched what Shopify charged on 878 real dev-store carts.

Dev store, 28 September 2026

Statuses

In production
matchedEvery check passed on a real cart.
mismatchedShopify refused the cart, or a check failed: the cart charges, carries or links to something other than what the offer promises.
unverifiableA check of the promise could not run, so the price is not proven. Presentation checks (line_override) are the exception: they are always skipped and never block. A landing page that cannot be fetched, or that does not reference the offer, fails the option.

A version goes live, or becomes a verified experiment arm, only if every visible option is matched. Otherwise it stays a draft and the live version keeps selling.

Shopify can take about 10 seconds to apply a new map, so a mismatch is checked again after 10, 20 and 40 seconds before it counts.

The theme block, through the SDK build it bundles, refuses to sell an option whose latest real-cart check did not match. Other selections are priced by the same line-pricing module the check uses.

48 of 48

One category-builder offer had 48 of 48 options matched and 377 of 377 audit carts, and test order #1023 charged $154.06.

Dev store, 29 September 2026

What Shopify enforces at checkout

In production

The offer's pointer rides on the cart as an attribute, and any storefront script can write one. So the discount function and the cart transform trust it only as far as the cart backs it up:

  • An option's price, gifts and free shipping apply only when the cart holds its required lines, in enough units, bought the same way (subscription or one-time), and never to more units than the option sells.
  • A gift is zeroed only up to the units the option includes.
  • Free shipping applies to shipping rates only, never to pickup or local delivery, and the store's shipping settings are never changed.
  • On a subscription, the first charge is priced by the "Offer Suite" app discount, which applies once. Recurring discounts and every-shipment free shipping sit on "Offer Suite renewals", which Shopify saves on the subscription contract for every billing cycle.
  • When the order arrives, a line role the shopper wrote counts only when the published offer gives that product that role, so a paid line cannot be costed as a gift.

Limits, stated plainly. Category-builder options have no required lines, so any cart that carries a builder's pointer gets the builder's own capped price. The check proves which lines the cart holds, not which option or experiment arm the shopper was shown: a shopper can apply another option's or arm's pointer when the cart already holds that option's lines.

Capacity

In production

The option map is compacted and sharded over five metafields, each kept under Shopify's 10,000-byte input limit. That is room for a few hundred simple options per store, fewer for large builders or entries that name many variants.

A publish is refused up front if it would push a shard past the limit, or if the measured instruction budget says it would leave room for fewer than 10 priced cart lines within Shopify's limit. The refusal names the cause, so a brand retires offers instead of finding out at checkout that a cart was charged list price.

The dev store's own map holds every test offer published there, large category builders among them, so it runs fuller than a single offer's would. It is measured in the evidence below.

After launch

In production
  • Re-verify on demand with POST /offers/{id}/verify, the MCP tool verify_offer or the dashboard's Re-verify button. Only the live version can be verified; any other answers 409 not_live.
  • Every day, each store's app discounts and option maps are checked and rebuilt in place if they are missing or out of date, with no republish and no change to any offer. A discount someone deactivated, or a map too large to write, is reported, not fixed.
  • On the same run, the two live offers per store verified least recently are checked again on real carts, so every live offer comes round again in turn (a store with ten live offers, every five days). A red experiment arm pauses its experiment.
  • When a store's pricing status changes, every team member gets one email when it breaks and one when it is fixed. The alert names the offer, the option and the cart checks that failed.
  • Rebuild by hand with POST /stores/{id}/pricing (rebuild_store_pricing): the same check and rebuild, run now.
  • The dashboard and Shopify App Home show each store's pricing status and when it was last checked.

Evidence

Read from the dev API: the last publish of OF_DEV_KITS on the dev store, then the latest real-cart check of each of its options. They are two events, dated apart.

OF_DEV_KITS, dev store, captured 2 October 2026. The publish run was requested 27 September 2026.

Publish runComplete: the version went live and the version it replaced was retired.
Visible optionsmatched 6 of 6, with no failed check.
Discount codes createdNone: no option uses a code.
First-order option map126 entries across every offer on the store, 18,247 bytes over 5 shards; room for 14 priced cart lines.
Renewals map23 entries, 1,446 bytes over 5 shards; room for 66 priced cart lines.

Each option at the publish run, then at its latest real-cart check, 2 October 2026, a separate event after launch.

OptionPublish run, 27 September 2026Latest check, 2 October 2026What the latest check covered
Single Bag · Subscribematchedmatched14 of 14 checks passedlines, selling plan, first charge, cart attributes, no-pointer cart, free shipping, renewal
Single Bag · Buy oncematchedmatched10 of 10 checks passedlines, first charge, cart attributes, no-pointer cart, free shipping
Starter Kit · Subscribematchedmatched18 of 18 checks passedlines, selling plan, first charge, cart attributes, no-pointer cart, free shipping, renewal
Starter Kit · Buy oncematchedmatched10 of 10 checks passedlines, first charge, cart attributes, no-pointer cart, free shipping
Ritual Set · Subscribematchedmatched22 of 22 checks passedlines, selling plan, first charge, cart attributes, no-pointer cart, free shipping, renewal
Ritual Set · Buy oncematchedmatched10 of 10 checks passedlines, first charge, cart attributes, no-pointer cart, free shipping

What it does not do yet

  • Free shipping can be verified only in US markets, where the verifier has a delivery address. Elsewhere the check is skipped, so a version with free shipping is not published.
  • Renewals are checked against the selling plan and the renewals discount's configuration, not against an observed renewal charge.
  • The verifier proves each option's default cart, not every selection a shopper can make.
  • Rebuilding a store's pricing is API and MCP only. The dashboard has Re-verify; App Home shows the pricing status.

Questions

What if Shopify changes my discounts after launch?

Every day Offer Suite checks each store's app discounts and option maps and rebuilds them in place when they are missing or out of date, without a republish or a change to any offer. A discount someone deactivated, or a map too large to write, is reported rather than fixed. The same run checks the two least recently verified live offers on real carts. A mismatch marks the store's pricing as broken, names the offer, the option and the failed checks, and every team member gets one email. You can run the check and rebuild at any time with POST /stores/{id}/pricing, or the MCP tool rebuild_store_pricing.

Can a shopper edit the cart pointer to get a better price?

Not beyond what the cart holds. The pointer is a cart attribute any storefront script can write, so the discount function applies an option's price, gifts or free shipping only when the cart holds that option's required lines, bought the same way, and never to more units than the option sells. Two limits remain: a category-builder option has no required lines, so a cart carrying its pointer gets the builder's capped price; and a shopper can apply another option's or experiment arm's pointer when the cart already holds that option's lines.