aov-bundle-upsell
🤖 MCP
Tool guide

Tool guide

14 read tools, available on every connection. 12 more write tools, available only on a Read and write connection. Every one is scoped to the single store its connection belongs to.

For the compact list, see the tools reference.


Read tools

get_setup_status

Purpose: Report whether the bundle widget is actually live on the storefront, and if not, why.

When to use: First, whenever a bundle, a volume table or an upsell is described as "not showing". It reaches a conclusion rather than handing back raw data.

Parameters: none

Returns: the store's name, domain, plan and install date; the theme embed state; whether settings have been saved; offer counts by type and status; and issues, a list of codes, in the order worth acting on.

CodeMeansFix
APP_EMBED_DISABLEDThe app embed is off on the live theme, so nothing can renderTurn it on in the theme editor, on the live theme
NO_BLOCK_ADDEDThe theme supports app blocks, and none of ours is placedAdd the block where the widget should appear
NO_ACTIVE_OFFERSNothing is currently active, every offer is draft, scheduled or expiredActivate one, or check its schedule
THEME_NOT_OS2The live theme does not support app blocksSwitch to an Online Store 2.0 theme
NO_SETTINGSThe store has no saved widget settingsOpen and save the settings once

The list is in priority order, fix the first one. The rest are usually noise until it is done.


get_offers

Purpose: List and search this store's offers.

Parameters:

NameTypeRequiredNotes
querystringNoSearches the offer name
typeenumNoOne offer type, see accepted values
statusenumNoactive, scheduled, expired, draft, all
sortenumNonewest or oldest by creation date; newest by default
limitnumberNoUp to 50. Defaults to 10
afterstringNonext_cursor from the previous page; not combined with query

Returns: each offer's id, name, type, status, discount, additional_revenue_usd, whether it is limit_reached (held off by the free-plan revenue cap), and next_cursor for paging.

The default limit is 10, not "all". On a store with fifty offers, "list my offers" answers with ten of them unless a higher limit is asked for, or the result is paged with after.


get_offer

Purpose: Read the full configuration of one offer. (The original tool was named get_offer_details; connections made before September 2026 still use that name.)

Parameters:

NameTypeRequiredNotes
offer_idstringYesThe id returned by get_offers

Returns: id, type, status, admin_url, additional_revenue_usd, the store's timezone, and fields, every field in exactly the shape update_offer accepts. A Product Fixed Bundle also returns bundle_status (whether Shopify has finished building the bundle product: processing, ready or failed). A Mix & Match or Bundle Builder offer also returns bundle_discount_source: discount_code means the offer owns a Shopify discount code the widget applies after add-to-cart, bundle_price means the saving is built into the bundle's own price. This is fixed when the offer is created.

The id has to come from get_offers, it is not the offer's name and not anything visible in the app's URL bar. An unknown id answers Offer not found rather than guessing.


get_offer_fields

Purpose: The fields one offer type has, as this store allows them, before reading or writing one.

Parameters:

NameTypeRequiredNotes
offer_typeenumYesOne of the six offer types

Returns: each field's kind, allowed values, range, whether it is required, whether the store's plan locks it, and the text keys its translations take.

Read this before update_offer or a create tool's fields, both of which follow it exactly. A field marked plan-locked can only keep its current value until the store upgrades.


get_offer_timeline

Purpose: The change history the app keeps for one offer.

Parameters:

NameTypeRequiredNotes
offer_idstringYesA Fixed Bundle offer id from get_offers
afterstringNonext_cursor from the previous page

Returns: up to 20 events per page, newest first: created, edited, switched on or off, and product changes Shopify synced in. An event made through an AI connection is marked by: "assistant".

⚠️

Only Product Fixed Bundle offers keep this timeline. The other five offer types answer no_timeline.


get_analytics

Purpose: Bundle performance over a date range.

Parameters:

NameTypeRequiredNotes
startYYYY-MM-DDNoDefaults to 30 days before end
endYYYY-MM-DDNoDefaults to today
offer_idstringNoNarrows the totals to one offer

Returns:

FieldWhat it is
additional_revenueExtra revenue attributed to bundles in the range
bundle_ordersOrders that included a bundle
total_ordersAll orders in the range
attach_ratebundle_orders ÷ total_orders, as a decimal
top_offersThe five offers that earned most, with their revenue and order counts
currencyAlways USD
⚠️

Figures are in USD, whatever currency your store sells in. Orders are converted when they are recorded.

Zero and "unavailable" are different answers. If the analytics warehouse cannot be queried, the tool returns analytics_unavailable rather than zeros, so a temporary outage is never reported as "you earned nothing".


get_plan_status

Purpose: Report your plan and how much of it you have used this cycle.

Parameters: none

Returns:

FieldWhat it is
planThe plan this store is on
additional_revenue_usedBundle-attributed revenue this billing cycle, in USD
reset_dateWhen the cycle rolls over
free_capThe cap block, or null on plans with no cap

When free_cap is present it carries cap, used, is_capped, near_limit (true from 80% of the cap) and reset_date.

⚠️

is_capped: true is the answer to "my bundles stopped mid-month". Once a capped plan reaches its cap, running offers are switched off automatically until reset_date.


get_widget_settings

Purpose: Read the storefront widget design of one offer type, as the merchant sees it on Widget display.

Parameters:

NameTypeRequiredNotes
offer_typeenumYesOne of the six offer types

Returns: every setting with its id, group, kind, limits and current value, colors, font sizes, texts, layout and display options, plus color_style (basic or advanced), text translations by locale, and the store's published languages besides the default.

Labels repeat inside a widget (several colors are called "Background"), so an assistant quoting one back should pair the label with its group. With a Read and write connection, the ids here are what update_widget_settings takes.


search_products

Purpose: Find products in the Shopify catalogue by name, to use in an offer.

Parameters:

NameTypeRequiredNotes
querystringYesProduct name or part of it
limitnumberNoCapped server-side

Returns: each product's numeric id and handle, both required when building an offer, plus has_more. Only active products published to the Online Store are returned; an out-of-stock product is still returned. A product this app generated for a bundle is excluded.

Boolean operators (AND, OR, NOT) are stripped from the query; every remaining word must match. This never picks for the merchant, it returns matches for the merchant to choose from.


search_collections

Purpose: Find collections in the store by name, to scope an offer to one.

Parameters:

NameTypeRequiredNotes
querystringYesCollection name or part of it
limitnumberNoCapped server-side

Returns: each collection's numeric id, handle, and how many products it holds.


get_discounts

Purpose: List the store's active Shopify discounts, including ones this app created for its own offers.

Parameters:

NameTypeRequiredNotes
limitnumberNoUp to 100. Defaults to 50

Returns: each discount's details, including whether it combines with product, order and shipping discounts.

Check combinability here before telling a merchant a new bundle discount will stack with a discount they already run.


search_customer_segments

Purpose: Find the store's Shopify customer segments by name, for an offer's audience targeting.

Parameters:

NameTypeRequiredNotes
querystringNoPart of a segment name; omit to list them all
afterstringNonext_cursor from the previous page

Returns: {id, name} pairs, 20 at a time, in the shape an offer's customerSegments and excludeSegments fields take. Segment names only, no customer data.


get_markets

Purpose: The store's Shopify markets.

Parameters: none

Returns: {id, name} for each market. A Frequently Bought Together or Volume Discount offer's marketId field takes one of these ids; null shows the offer in every market.


get_product_variants

Purpose: The variants of one product, to scope an offer to specific variants.

Parameters:

NameTypeRequiredNotes
product_idstringYesFrom search_products

Returns: each variant's id, title, price, compare_at_price, available, and its options. A product with more than 250 variants lists only the first 250; total_variants says how many it really has.


Write tools

Every tool below needs a Read and write connection. A request to any of them on a Read-only connection is refused with "This connection is read-only. Create a new connection with write access to change offers or design."

⚠️

Nothing is created, changed or deleted until the merchant has approved it. The assistant is instructed to summarize what it is about to send (offer type, products, discounts, or a setting's old value and new value) and wait for a yes before calling any tool in this section. That rule lives in the assistant's own instructions, not in the server, so it's worth reading what an assistant proposes before approving it.

The six create tools

Each of the six create tools takes a name plus the fields specific to that offer type, and any other setting (advanced settings, texts, translations, schedule) goes in a fields object, in the same shape update_offer takes (see get_offer_fields). Every one of them:

  • Creates an offer the store does not have yet. To change one that already exists, use update_offer, never delete-and-recreate.
  • Starts switched off. Turn it on with set_offer_status once the merchant agrees.
  • Calls once per offer the merchant confirmed, never to "try out" a template or show an example.
ToolOffer typeKey parameters
create_fbt_offerFrequently Bought TogetherTrigger as product or collection ids, plus the products to offer alongside it
create_volume_discount_offerVolume Discountscope (all products or specific ids), either tiers with a discount_type, or one of six template presets (classic-volume, buy-x-get-x, volume-gift, mix-match-volume, table-layout, mystery-tier) and a color_scheme
create_mix_match_offerMix & Match Bundleoptions, each with a name and at least one product with a quantity
create_bundle_builder_offerBundle BuilderA pool of products or collections (not mixed), layout (list or category), a quantity-ladder discount
create_fixed_bundle_offerProduct Fixed Bundleproduct_ids (up to 30), at most 3 options to choose between, at most 2048 resulting variants
create_upsell_offerProduct RecommendationWhere it shows (store-wide, products, or collections) and what it recommends

Volume Discount templates bring their whole ladder. Never re-type a template's tiers by hand, send the template key and let it fill in the discounts and widget layout. Using a template or preset also sets the shared Volume widget style (corner radius, spacing, title size), which changes every Volume offer's widget in the store, not only the new one.

⚠️

Product Fixed Bundle and Mix & Match offers build a Shopify bundle product in the background. For a Fixed Bundle, check get_offer's bundle_status is ready before turning it on.


update_offer

Purpose: Change fields of one existing offer, the way the merchant edits it in the app. Works for every offer type, there is no per-type update tool.

Parameters:

NameTypeRequiredNotes
offer_idstringYesFrom get_offers
fieldsobjectYes{<field>: value}, in the shapes get_offer returns; see get_offer_fields

An object field merges key by key; a list field (tiers, options, categories) replaces the whole list, so changing one item means sending the whole list back with that one item changed. Dates are store-local time, YYYY-MM-DDTHH:mm. The storefront follows within seconds.

Turning an offer on or off is set_offer_status, not a field here.


set_offer_status

Purpose: Turn 1 to 10 offers on or off.

Parameters:

NameTypeRequiredNotes
offer_idsarray of stringYes1 to 10 ids from get_offers
statusenumYesactive or paused

The storefront follows within seconds. Turning on is refused for the whole call, and nothing changes, when the store is past its free-plan revenue limit, when an offer is past its end date, when its start date is still ahead, or when the plan does not include that offer type; the reply names each offer and why.


duplicate_offer

Purpose: Copy one offer to start a second, similar one.

Parameters:

NameTypeRequiredNotes
offer_idstringYesFrom get_offers

Returns: the new offer's id. The copy is named "Copy of <name>", keeps its schedule, texts, translations and every setting, gets its own new Shopify discount or bundle product, and starts switched off.


delete_offers

Purpose: Permanently delete 1 to 10 offers.

Parameters:

NameTypeRequiredNotes
offer_idsarray of stringYes1 to 10 ids from get_offers

Deletes each offer's Shopify discount or bundle product along with it. There is no undo from inside the app. A deleted bundle product disappears from the storefront at once. An id that is not one of this store's offers refuses the whole call.

⚠️

Always confirm the exact offers with the merchant before calling this. Deleting and recreating is never how an offer is edited, update_offer changes one in place.


update_widget_settings

Purpose: Change storefront widget design for one offer type, colors, font sizes, texts, layout and display options, and their translations.

Parameters:

NameTypeRequiredNotes
offer_typeenumYesOne of the six offer types
changesobjectNo{id: value} with ids from get_widget_settings, colors as "#1A2B3C"
translationsobjectNo{locale: {text id: text}}; an empty string removes that translation

Every change is checked first, if one is refused, nothing is written. Setting colorStyle to "basic" also applies the Basic colors preset and lists every value it overwrote. Each change comes back with its previous_value, send that value back to undo it. storefront in the result is "live" when shoppers already see the change, or "syncing" when it lands within about a minute.


import_image

Purpose: Copy an image from a public URL into the store's Shopify Files, for use in an offer or widget image field.

Parameters:

NameTypeRequiredNotes
urlstringYesA public https:// URL
altstringNoAlt text for the image

Returns: the Shopify CDN URL. Offer image fields (a Volume tier image, a Bundle Builder banner, the Mix & Match volume button image) only accept a Shopify CDN URL, so an image from elsewhere needs to go through this tool first. The file stays in the store's Files even if no offer ends up using it.


Related

Product
Install AppWebsiteAvada Apps
Resources
DocumentationFAQPrivacy Policy
Company
Avada GroupContact
© 2026 Avada Group. All rights reserved.