Tool reference
All eleven tools, their inputs, and what comes back. Every tool is read-only.
The same data is available over plain HTTPS — each tool maps to one endpoint of the Store API.
On every result
| Field | Meaning |
|---|---|
shopDomain | The *.myshopify.com these numbers belong to, stamped from the connection itself so the answer can never name the wrong store |
currency | The store's currency, present wherever money is |
appliedWindow | On date-range tools: the start, end and source actually used — source tells you whether you chose the range or it defaulted |
appliedFilter | On list tools: scope is shop or filtered, plus whichever of name, placement, status, abTest narrowed it |
appliedWindow and appliedFilter exist so a short list or a small number can never be read as the whole store. If Claude tells you "you have 3 offers", the payload it read said whether that was 3 in total or 3 matching a filter.An offer row in any list carries: id, name, status, type (the placement), abTest, a url that opens the offer in your Shopify admin, and — where they apply — revenue, claims, acceptanceRate, priority, createdAt, isDeleted.
Offers
search_offers
Find or list offers by name, placement, or status.
| Input | Type | Notes |
|---|---|---|
query | string | Matches against the offer name |
status | enum | active, scheduled, expired |
type | enum | One of the four placements |
page | integer | 20 per page, 1-based. An empty page means the end |
sort | enum | newest (default), oldest, revenue, revenue_low |
abTest | boolean | true returns only offers running an A/B test |
Returns offers, total, hasMore, currency, appliedFilter.
revenue_low is the way to reach offers that never earned — they are absent from revenue rankings entirely.
list_offers_by_priority
One placement's offers in display order, 1 shown first.
| Input | Type | Notes |
|---|---|---|
placement | enum | Required. Priority restarts per placement, so there is no shop-wide order |
page | integer | 20 per page, 1-based |
Returns offers (each with priority), total, hasMore, currency, appliedFilter.
count_offers
Offer counts per placement, broken down by status.
| Input | Type | Notes |
|---|---|---|
type | enum | One placement. Omit to count all four plus a grand total |
Returns total and byType — one row per placement with count and a byStatus breakdown of Active, Scheduled and Expired.
get_offer_detail
One offer's setup: who sees it and when.
| Input | Type | Notes |
|---|---|---|
id | string | Required. The offer id, or the resource uri returned by search_offers |
Returns offerName, status, type, startDate and endDate (only when a schedule is set), triggerCriteria (no-condition or set-conditions), triggerConditions, the offer-level discountType / discountValue when one applies, plus the offer's own stats and url.
What the offer sells is not here — that is get_offer_stages.
get_offer_stages
What an offer offers, stage by stage.
| Input | Type | Notes |
|---|---|---|
id | string | Required. Offer id or resource uri |
Returns offerName, currency, and stages. Each stage carries:
products— each with its owndiscountTypeanddiscountValue, stated even when there is nonebundleDeal—type,discountType, andtiers, when a bundle is liveabTest— when a stage is being tested, it replaces that stage's products and bundle
Only Post-purchase upsell runs a multi-stage funnel; each of its stages names the one it follows and whether it was accepted or declined. The other three placements have exactly one stage.
Results
get_offer_summary
One shop-wide roll-up for a date range, matching the Analytics dashboard.
| Input | Type | Notes |
|---|---|---|
start | date | YYYY-MM-DD, inclusive |
end | date | YYYY-MM-DD, inclusive |
Returns totalUpsoldValue, totalUpsoldOrders, totalOrders, upsellSuccessRate, averageUpsoldValue, offerViews, currency, appliedWindow.
upsellSuccessRate is upsold orders over total orders — every order the store took, not only those that saw an offer.
No per-placement breakdown; that is get_offer_stats.
get_offer_stats
Impressions, revenue and claims for a date range, one row per placement.
| Input | Type | Notes |
|---|---|---|
start | date | YYYY-MM-DD, inclusive |
end | date | YYYY-MM-DD, inclusive |
type | enum | One placement. Omit for all four |
Returns placements (each with placement, impressions, claims, and revenue), shopOfferCount, currency, appliedWindow.
revenue entirely, because they reward a future order the app cannot attribute.shopOfferCount is there so an all-zero result can be told apart from a store that has never created an offer.
get_top_offers
Offers ranked by revenue earned in a date range.
| Input | Type | Notes |
|---|---|---|
start | date | YYYY-MM-DD, inclusive |
end | date | YYYY-MM-DD, inclusive |
order | enum | highest (default) or lowest |
Returns offers — each with revenue, claims and acceptanceRate — plus shopOfferCount, currency, appliedWindow.
There is no row cap here: the ranking comes back three deep, and Claude cannot ask for more. The Store API endpoint takes a limit for that.
The ranking is built from claim history, so:
- an offer that earned nothing in the period is absent, not last — reach those with
search_offersandsort: revenue_low - a top earner can be an offer already deleted, marked
isDeletedand carrying no link claimsandacceptanceRateare facts about that one row, not a second ranking
get_shop_lifetime_stats
All-time totals, matching the Statistics card on Home. No inputs.
Returns totalRevenue, offerViews, upsoldOrders, conversionRate, revenuePerVisit, currency.
Here conversionRate is measured against offer views — unlike the date-range success rate above.
get_offer_coverage
Which placements have an active offer and which do not. No inputs at all.
Returns placements — each with placement, hasActive, activeCount, totalCount, and recentRevenue — plus currency, appliedWindow.
The counts are current-state, so there is nothing to date. recentRevenue is the one windowed column, and it runs the default last 30 days — appliedWindow says so. Ask for coverage "last quarter" and you will get the same answer as today's, dated the last 30 days. The Store API endpoint does take start and end, deliberately: a script knows what window it asked for.
totalCount alongside activeCount is what separates "nothing created here" from "offers exist but none are active". Coupon offers omit recentRevenue.
Products
recommend_products
Upsell suggestions ranked by real bought-together history, padded with same-category best sellers when that history is thin.
| Input | Type | Notes |
|---|---|---|
offerId | string | Preferred. The app reads that offer's own trigger products, so nothing has to be named |
productId | string | A Shopify product gid |
productName | string | A product title, resolved on the server |
Pass none of them and you get the store's best sellers.
The reply takes one of four shapes, each naming its own cause in fields rather than by absence:
| Shape | Meaning |
|---|---|
triggers[] with boughtTogether and sameCategoryPicks | The normal answer. boughtTogether rows carry coPurchasedOrders and pastRevenue; sameCategoryPicks are padding and carry neither |
shopBestSellers with bestSellersOnly: true | No usable product trigger, or nothing named — a real answer, not an error |
candidates | The product title was ambiguous; pick one and ask again |
holdsUpsellProducts: false | A Coupon offer has no product slot to fill |
boughtTogether list is a real answer — this store has no co-purchase history for that product yet. It never silently becomes a best-seller list.Related
- Tool guide — which question reaches which tool
- API resources — the same payloads over HTTPS