get-account-rollup
ChatGPTThe whole-account headline for a weekly or monthly marketing report: total spend across paid AND organic, store revenue net of refunds, the order-level cost basis, orders, clicks, plus ROAS and POAS - for THREE periods in a single call. Use this for "how did the business do last week", "what is our blended ROAS", "are we profitable on ad spend", or the opening summary of any performance report. Returns current, previous_period and last_year side by side, with the deltas between them computed server-side. Do NOT make three calls and subtract - the change block here is the only set of deltas you should report, and the windows used are echoed back in windows so you can state exactly what was compared. By default previous_period is the window immediately before the current one and last_year is the same window 364 days earlier - 364, not 365, so a weekly report lands on the same weekdays. Override any of them with the optional date parameters. REVENUE HERE IS STORE REVENUE, NOT ATTRIBUTED REVENUE. It is net of refunds processed inside the period, plus Meta and TikTok in-platform purchase value (returned separately as in_platform_revenue). It will NOT equal the sum of get-blended-channel-data revenue, and it should never be divided by one channel's spend. spend, by contrast, IS the blended total across paid (including Klaviyo) and organic, so the ROAS reported here is a blended ROAS. paid_spend is the ad-platform part of it alone. clicks counts paid (including Klaviyo) and organic clicks. product_cost is net of the COGS of refunded items. orders INCLUDES Meta and TikTok in-platform purchases, returned separately as in_platform_orders. For any "store revenue" or "store orders" figure use the returned store_revenue (revenue - in_platform_revenue) and store_orders (orders - in_platform_orders), and take their change from change like every other metric. Never subtract them yourself. POAS = (store_revenue - product_cost - transaction_cost - shipping_cost) / paid_spend. That is store profit over ad-platform spend, the same POAS as the dashboard's Store P&L. Use the returned poas; do not recompute it from spend. ROAS is null when a period had no spend and POAS is null when it had no paid spend - report null as "no ad spend in this period", never as a ratio of zero.
get-blended-channel-data
ChatGPTRevenue, spend, orders and clicks grouped by MARKETING CHANNEL across paid AND non-paid traffic - Organic Social, Organic Search, Email, Referral, Direct and each paid platform side by side. Use this for "which channel drove revenue", "where should we shift budget", "how does organic compare to paid", or any channel-mix or blended question. THIS IS NOT get-channel-data. That tool takes one of seven AD PLATFORMS and breaks it down by campaign/adset/ad. This tool takes no channel at all: it returns every channel at once, grouped by utm_medium and source, and it is the only way to see traffic that did not come from an ad platform. Numbers from the two tools are not interchangeable and should not be combined in one table. ATTRIBUTION IS FIXED AND NOT A PARAMETER, and it is the same on all four grains. Paid channels (Meta, Google, Bing, Tiktok, Pinterest) report paid-linear, matching the Optimize page; Snapchat, Reddit, organic, email and referral report linear-exclude-direct. This is deliberate - applying a single model to every source put Google about 12% below Optimize. Do NOT present these figures alongside a get-channel-data result taken under one explicit model, and say which tool a number came from. FOUR GRAINS, which answer different questions: - medium (default) - one row per channel for the whole range, keyed on utm_medium alone. This is the channel leaderboard: use it for spend, budget, ROAS and "which channel won". - trend - one row per DATE for the whole account, every channel combined. Use for "how did the month go", pacing and day-over-day movement. - total - one row per utm_medium AND source. Use ONLY when the source split is itself the question ("which search engine", "which referring site"). - daily - one row per date per utm_medium. Use when the question needs BOTH axes. SPEND IS ONLY WHOLE AT THE medium GRAIN. A tenant's custom cost - the spend they type in by hand for channels with no ad platform behind them - is keyed on (utm_medium, source) with whatever source THEY typed, which is not the source attributed revenue is keyed on. At the total grain the cost and the revenue for one channel therefore land on two different rows: the cost row shows revenue 0, sorts last, and falls off the row cap, leaving the channel reading "$0 spend". On one real account that hid $5,646 of January spend and reported a blended $39,151 against an actual $44,798. Never read a total row's spend as a channel's whole spend. ALWAYS take account-level figures from totals, which is computed in SQL across every channel BEFORE the row cap. Summing the returned rows gives a number short by whatever the cap dropped. Under the fixed per-source attribution one order with a paid and an organic touch is credited on both rows, so the revenue, orders, ROAS, POAS and new/returning split in totals, and every trend row, are read under linear_exclude_direct (totals.attribution_model), which counts every order once. The channel rows keep their per-source figures, so they add up to MORE than totals, and channel shares of totals need not add up to 100%. ATTRIBUTED POAS (total_poas) is on every medium, trend and daily row, and totals.poas is the account's: summed attributed revenue minus summed COGS, transaction and shipping cost, over summed spend - a ratio of sums, null without spend. Paid Social revenue includes Meta and TikTok in-platform purchase value, which has no cost basis, and spend includes custom cost, so this is NOT Store P&L POAS: that is get-account-rollup poas. Label it attributed POAS. Use medium for attributed POAS by channel and trend for it by day. The total grain joins no order-level cost basis and has no POAS, and summing daily will not reproduce total's source split. NEW VS RETURNING CUSTOMERS. Every row on every grain, and totals, also carries new_customers_orders, new_customers_revenue, old_customers_orders and old_customers_revenue - the attributed orders and revenue split by customer cohort. They are AdBeacon-attributed only: Meta/TikTok platform-reported pur…
get-channel-data
ChatGPTGet detailed advertising metrics for campaigns, ad sets, or ads from a specific channel. Returns paginated data including performance metrics like spend, revenue, ROAS, orders, etc. Use the list-channels tool first to see available channels, breakdowns, and metrics.
get-coupon-data
ChatGPTWhich discounts drove orders, what they were worth, and what they cost - each split into new and returning customers. Use this for "which promo codes worked", "are discounts bringing in new customers or subsidising repeat buyers", "how much margin did BFCM give away", or any question about coupons, promo codes or discounts. This is the ONLY tool on this server that exposes discount data: get-channel-data, the order tools and the product tools never carry a coupon. To see coupons against products or marketing channels, use group_by here. THREE GRAINS, chosen with group_by; rows always come back under coupons, every grain returns the same coverage block, and grain_note says what a row is. sort_by depends on the grain. group_by: coupon (the default) is one row per discount, described in full below. group_by: product splits the same discounted orders into their line items: one row per coupon x product with orders (DISTINCT orders under that coupon containing the product), units, line_revenue (line price x quantity) and line_discount, both in the reporting currency, and the new/returning ORDER split. Line amounts carry no shipping or tax, so they never equal coupon-grain revenue, and one order with three products sits on three rows: never sum orders across product rows. group_by: channel reads AdBeacon ATTRIBUTION, not store orders: one row per coupon x marketing channel (the utm_medium, as on the medium grain of get-blended-channel-data) with attributed_orders (fractional credit), attributed_revenue and its new/returning split, under attribution_model and attribution_window - the only grain that reads them. Under lighthouse and full_impact one order is credited to SEVERAL channels, so never sum channels into a coupon total; take coupon totals from group_by: coupon. coupon IS THE DISCOUNT TITLE, NOT A CODE. Every raw code is mapped back to the Shopify discount it belongs to, so a promotion issued under fifty unique codes is one row. Do not present these as codes a customer can redeem. Set resolve_titles to false to group on the raw code instead - which is also the only way a WooCommerce or BigCommerce store returns anything, since the title catalogue is Shopify-only. coverage comes back even when there are no rows: an empty result with coverage.discounted_orders above 0 means the codes did not resolve to a Shopify discount title (or none matched the search), never "this account ran no promotions"; coverage.discounted_orders of 0 means no order in the window used a code. TWO KINDS OF COUNT. new_customer_orders / returning_customer_orders are ORDER counts and sum to orders. new_customers / returning_customers are DISTINCT customers and do NOT sum to customers. Never add those two together. REVENUE IS THE FULL ORDER VALUE THE CODE WAS ATTACHED TO, not the discount and not the value net of it. revenue is GROSS - refunds not deducted - so that it agrees with the in-app New vs Returning by Coupon Code report; net_revenue is the same orders after refunds. The cohort split sums to revenue, never to net_revenue. discount_amount is what was actually taken off and discount_rate is that as a percentage of revenue - that pair is the cost of the promotion. These orders are CORRELATED with the code, not proven to be caused by it: some share would have happened anyway, so never describe a coupon's revenue as revenue it generated. TOTALS FOR A TOP-N. coverage.returned_orders and coverage.returned_revenue are the totals OF THE ROWS THIS CALL RETURNED and are what a "top N coupons" KPI header must print. coverage.period_* and coverage.discounted_* describe the whole account and belong in a coverage sentence, never on a card beside the table. new_customer_order_share is the acquisition signal - a code with a high share is recruiting, a code with a low one is discounting people who were going to buy. coverage says what share of ALL orders in the period used any discount at all, which is usually the first number a promotion question actually wants.
get-creative-data
ChatGPTList creative performance rows for one channel — the Creative Dashboard's grid. A row is one CREATIVE ASSET, not a campaign, ad set or ad. breakdown chooses what an asset means: image, video, copy, image-and-copy or video-and-copy. Each row carries the ad ids and names it was assembled from, so the same image running in twenty ads is one row, not twenty. Use get-channel-data instead when the question is about campaigns, ad sets or ads. Notes: - Call list-creative-channels first. The vocabulary is per channel: YouTube has no image breakdown, Pinterest has no thumbstop, and google (Google Assets) takes no breakdown, attribution or tags at all. - start_date and end_date must be YYYY-MM-DD. - Metrics come in two families and they are NOT interchangeable: reported_* are the platform's own numbers, ab_* are AdBeacon-attributed. State which you used. - columns selects which metrics come back. Ask for the ones the question needs — the full set is large and every row carries all of them. - Results are paginated; read pageInfo.hasNextPage before assuming you have them all. - Sorting and paging happen after the query, so page 2 costs no extra BigQuery scan.
get-creative-summary-data
ChatGPTGet the totals across every creative asset for one channel and date range — the TOTAL row under the Creative Dashboard grid. Returns a single aggregate object, not a list. Use it for "how did our creative do overall" before paging through get-creative-data, and to check whether a page of rows you already have accounts for most of the spend. Notes: - The filters are the same as get-creative-data, and they change the total: it is the total OVER THE FILTERED ROWS, not the account total. - breakdown still matters. The same spend regrouped by video and by copy yields the same totals, but a breakdown-specific column (anything video-only) exists in one and not the other. - There is no page, limit or sort here; sending one is an error rather than a silent no-op.
get-cross-channel-campaigns
ChatGPTEvery campaign from EVERY ad platform in one ranked list - Meta, Google, Bing, TikTok, Pinterest, Snapchat and Reddit together, with the channel named on each row. Use this for "what are our top campaigns", "where is budget being wasted", or any question that ranks campaigns without naming a platform first. WHY NOT SEVEN CALLS TO get-channel-data: those return one platform each, unranked, and merging them yourself cannot produce a correct top-N - the per-channel results are paged arbitrarily, so the biggest campaign on a platform may not be on the page you received. This tool ranks across all seven IN SQL before any row cap applies. Returns spend, revenue, orders, clicks, impressions, budget, ROAS, POAS, AOV and the platform-reported figures per campaign, plus the new/returning customer split (new_customers_orders, new_customers_revenue, old_customers_orders, old_customers_revenue, also in totals). POAS is included here, unlike get-channel-data. The new/returning split is AdBeacon-attributed only. Meta and TikTok revenue / orders also fold in platform-reported purchases, which carry no customer type, so on those rows new + old can be below the total. The split cannot be used as sort_by. See cohort_note in the response. THIS IS PAID ONLY, and deliberately so - a campaign is a paid concept. It cannot see organic, email or direct traffic. For the full channel mix including those, use get-blended-channel-data. ATTRIBUTION IS FIXED AND NOT A PARAMETER, exactly as on get-blended-channel-data: Meta, Google, Bing, TikTok and Pinterest report paid-linear; Snapchat and Reddit report linear-exclude-direct. Do not present these numbers beside a get-channel-data result taken under one explicit model.
get-ga4-data
ChatGPTGet Google Analytics 4 data for every GA4 property connected to the account — the same figures as the Custom Dashboard's GA4 tiles. breakdown decides what a row is: - a dimension (channel, source, device, landing_page, product, path, ...): one row per value, busiest first - day, week or month: one row per period, oldest first — a trend - none: ONE row of totals for the whole period — a scorecard Notes: - Call list-ga4-reports first. Columns depend on the report (traffic, landing_page, product, path) and filter fields depend on the breakdown. - GA4 reports its own numbers: there is no attribution model, window or customer type here. Do not compare GA4 figures with AdBeacon-attributed revenue as if they were the same thing. - start_date and end_date must be YYYY-MM-DD, at most 425 days apart. - Totals differ by grain: device, country, city, browser and new_vs_returning read city-level data and count more sessions and users than channel or none. Say which breakdown you used. - Results are paginated; read pageInfo.hasNextPage before assuming you have every row.
get-geography-data
ChatGPTWhere the store's orders actually ship to: cities, regions or countries ranked by revenue, each split into new and returning customers. Use this for "which cities buy the most", "where are our new customers coming from", "should we run a regional campaign", "which markets are growing", or any question naming a place. This is the ONLY tool on this server that returns a geographic dimension. No channel, creative or order tool can be grouped by location. These numbers tie out, to the cent, against the City tab of the in-app New vs Returning Customers report. Do not reconcile them against any other source. grain decides what a row IS: city (the city NAME alone, so every Portland rolls into one row and a city row has no region or country column - this is what the report does), region (state / province), or country. Ask for region when same-named places must stay apart. Add country to narrow a city or region list to one market. revenue is GROSS store revenue - refunds NOT deducted - in the account's reporting currency, because that is what the report prints. net_revenue is the same orders after refunds. The new/returning revenue split and aov are on the gross basis and tie to revenue. None of it is attributed revenue: never divide it by a channel's spend, and never put it in the same table as a get-channel-data revenue figure. COUNTS ARE ORDER-GRAIN, matching the report. customers, new_customers and returning_customers count order rows, so new + returning = customers and a three-time buyer counts three times. Use them for anything that must tie out, including a new-vs-returning stacked bar. distinct_customers and its distinct_new_customers / distinct_returning_customers siblings are true distinct-shopper counts, and the latter two do NOT sum to distinct_customers - a shopper whose first order and a repeat both land in the window is in both. Never add those two together, and never mix them into a table built on the headline counts. Orders with no shipping address at the requested grain are excluded, so the rows do not sum to the account total. coverage says how much of the period the returned rows represent. When you present a top-N of places, its KPI totals are coverage.returned_revenue and coverage.returned_orders - the totals of THESE rows. coverage.period_revenue and coverage.period_orders are the WHOLE ACCOUNT including every place not listed; use them only to state coverage, never as the headline beside a top-N table. coverage.period_net_revenue is that same whole-account revenue after refunds. When no order in the window has a place, places is empty but coverage still carries the period figures.
get-goals
ChatGPTThe account's own monthly targets from the Goal & Pacing page: Spend, Revenue, ROAS, POAS, CAC, CPC and MER goals, set for the whole account or for one channel. Use this whenever a question compares performance with a plan, budget or target: "are we on pace", "how much of the November budget is left", "did we hit our ROAS goal". It is the ONLY tenant-entered plan on this server. Platform budgets from get-channel-data are a different thing: the ad platform's current daily or lifetime setting, not what the account planned to spend in a month. Each goal returns name, level (account or channel), channel (null on an account-level goal), metric, condition (equals, less_than, less_than_or_equal_to, greater_than, greater_than_or_equal_to), deviation (the +/- percent tolerance around the value, set only when condition is equals), cycle_start_day, and months: one entry per goal month as YYYY-MM with its value and exact period_start / period_end. GOALS ARE MONTHLY. Pass start_date and end_date to keep only the goal months that window overlaps; a window that covers part of a month still returns that month's FULL monthly value, with days_in_window and days_in_period so you can say how much of it the window covers. Never pro-rate a monthly goal silently. Goals with no month in the window are left out, and an account with no goals returns an empty list rather than an error.
get-growth-intelligence
ChatGPTIs the business acquiring customers, at what cost, and is it keeping them - for two periods side by side, with the deltas computed server-side. Use this for "are we growing", "what is our CAC", "are we just discounting repeat buyers", "is acquisition getting more expensive", "how much are we spending outside the ad platforms", or the growth section of any business review. It is the only tool that puts customer ACQUISITION next to total marketing cost. get-account-rollup gives blended spend and store revenue but no customer counts; the channel tools give spend per platform but cannot see a new customer. THREE THINGS THAT DECIDE WHETHER THE REPORT IS RIGHT: 1. TWO KINDS OF COUNT. new_customer_orders / returning_customer_orders are ORDER counts and sum to orders. new_customers / returning_customers are DISTINCT customers and do NOT sum to customers - a shopper whose first order and a repeat both land in the window is in both. Never add them together. 2. CAC IS BLENDED, AND DELIBERATELY CONSERVATIVE. new_customer_cac is TOTAL marketing spend (seven paid platforms plus manual and organic costs) divided by new customers. It charges retention spend to acquisition, which is the standard blended CAC. It is not comparable to get-channel-data's attributed per-channel CAC - never put the two in one table. 3. revenue IS STORE REVENUE, net of refunds, not attributed revenue. So blended_roas is a blended ROAS and will not match any channel's ROAS. new_customer_roas is new-customer GROSS store revenue (before refunds, the same basis as the cohort split) / total spend, so compare it with gross_revenue / total_spend, never with blended_roas, which is net. returning_customer_revenue_share is the complement of new_customer_revenue_share. Both appear in the change block when both periods have a value; report their period change from there rather than labelling it "calculated". custom_costs is the manual and organic channel spend - the money that never appears in an ad platform and is therefore missing from every other tool on this server. paid_spend is the per-platform breakdown that makes up the rest. Report the change block verbatim; do not recompute it and do not derive a change for a metric that is not in it. A percent of null means the earlier period was zero - say "no comparable figure", never 0% or 100%. Ratios (cac, roas, rates) move in their own units: a CAC going 40 to 50 is an absolute change of 10, not 10%. DAILY SERIES. Set daily to true to also get days.current / days.previous: one entry per date with orders or spend, sorted by date, carrying the same keys as the period blocks. It is the store-basis daily series for "best acquisition days", "lowest CAC days", yesterday's figures or momentum. There is no change block per day, and per-day distinct-customer counts do NOT add up to the period's - read daily_note before using days.
get-meta-ad-performance
ChatGPTMeta ads compared against a previous period, per ad, with the creative thumbnail and the period-over-period changes already calculated. Use this for "which Meta ads are declining", "what changed week over week on Meta", or any Meta ad review that needs a before-and-after rather than a snapshot. Returns, for each ad: the current period (spend, cpm, ctr, impressions, clicks, reach, frequency, revenue, roas), the same nine for the previous period as prev_*, six ready-made change columns, image_url - the ad's actual creative thumbnail - and media_type. NOT A CREATIVE TOOL. A row is an AD, and ads carry images, videos and carousels, so an unfiltered result MIXES them. Any question with the word "image" or "video" in it belongs to get-creative-data at breakdown: image or breakdown: video, which groups by the creative ASSET - one image running in twenty ads is one row there, and twenty here. Do not build an "image ads" or "video ads" table from this tool: a real report did, and listed a 1m47s video as its top image ad because every number in the row was individually correct. media_type (image / video / carousel / unknown) is available as both a column and a filter for the cases where an AD-level answer really is wanted for one kind of creative. FIVE THINGS TO GET RIGHT, all of which produce confident wrong numbers if ignored: 1. frequency is the AVERAGE of Meta's own daily frequency, NOT impressions / reach. Reach is de-duplicated by Meta within a day, so summing it across days double-counts people. The same ad measures 1.47 one way and 1.28 the other. reach is a plain SUM for volume context, so impressions / reach will NOT reproduce frequency. Report the column as given; never recompute it. 2. revenue and roas are META-REPORTED, not AdBeacon-attributed. Label them "Meta Revenue" / "Meta ROAS". Never sum or table them alongside attributed revenue from get-channel-data. For attributed revenue per ad, use get-channel-data with breakdown: ad. 3. Every *_change_pct is a RATIO, not a percentage: 0.25 means +25%. Multiply by 100 before presenting. A null means the ad did not run in the previous period - report that as "no comparable figure", not as 0%. 4. Rows are ordered by sort_by and THEN capped at limit (default 50), so a ranking really is the account's top N under that ordering. When truncated is true, say the figures cover the top N rather than implying account-wide. 5. media_type is the ad's creative kind, classified the same way the Creative Dashboard classifies it. Unfiltered, every kind comes back together. The filter is applied BEFORE the row cap, so media_type: image with limit: 5 is the account's five biggest image ads, not the image ads among its five biggest ads. State the filter you used, or that you used none. The comparison period defaults to the window immediately before the one you ask for, of the same length. Both windows come back in windows - state them.
get-order-attribution
ChatGPTShow how each order's credit was split ACROSS every channel, one row per order. This is the cross-channel view: for each order you get the date, customer email, order total, and the fraction of that order credited to meta, tiktok, pinterest, snapchat, googleAds, bingAds, chatgptAds, direct, googleSearch, bingSearch, klaviyo_email and attentive_email — plus others for everything unnamed (including any other email platform, e.g. Mailchimp). Use it to answer "which channels contributed to this order?" or "how much of last week's revenue did Meta actually drive per order?". Choosing between the order tools: - get-order-attribution (this one) — every channel's share of each order. NOT channel-scoped. - get-order-list — orders attributed to ONE channel. Use when the user names a channel. - get-order-journey — the individual touchpoints behind ONE order. Notes: - start_date and end_date must be YYYY-MM-DD. - For the fractional models the channel shares plus others sum to 1 per order. For full_impact each channel counts whole orders instead, so they do NOT sum to 1 and others is null. - lighthouse is NOT available here, unlike the other order tools. - attribution_window does NOT accept 0/lifetime. - Results are paginated; read pagination.has_next_page before assuming you have them all. Every page costs the same scan, so prefer a large limit over many pages. - Data comes from the hourly attribution summary, so orders placed in the last hour may not appear yet. This matches the Optimize screens exactly. - An account with no connected store is refused with an explicit error rather than an empty result, so an empty orders array always means "no orders matched", never "this account has no store connected". FOR ANY TOTAL, READ totals. NEVER ADD UP orders YOURSELF. The response carries a totals object holding each channel's credit, the residual and the revenue summed across the WHOLE filtered set — every matching order, not just this page. Those figures are computed in the database and are exact. Summing the rows by hand is not: a week can hold hundreds of orders, and adding them up produces confident, wrong answers. totals is the whole result set regardless of page or limit, so one call answers "how did my channels do" without paging at all. Page through orders only when you need the individual orders themselves. DO NOT VOLUNTEER A SUMMARY OF A SUBSET. When you list some orders, present the rows and stop. Do not append a count or a value total for "these N orders" — nothing in the response provides it, so you would be adding the rows up yourself, and that is exactly the arithmetic that produces confident wrong answers. A real example: asked for 25 orders under last-click, a summary was appended whose channel counts totalled 27 and whose value was $100 out. If a total for a NARROWER slice is wanted, do not compute it — re-query with filters that describe that slice (a tighter date range, a different customerType) and read totals again. If that is not possible, say the figure is your own count of the rows shown rather than presenting it as data.
get-order-journey
ChatGPTGet the cross-channel customer journey for one order — every attributed touch-point that led to the purchase, ordered from the most recent (converting) touch back to the first, plus a derived time-to-convert. This endpoint is keyed by order_id, not by channel: a single call returns every channel's touch-points for that one order, so there is no channel parameter. Use get-order-list first to find order ids for a channel and date range. Notes: - attribution_model changes WHICH touch-points come back — it is not just a labelling choice, so never compare touch-point counts across two different models. last_click drops Direct-source touches for stores configured to exclude direct traffic; paid_linear keeps only touches whose utm_medium is in the account's paid-linear medium list; linear_exclude_direct keeps only non-Direct touches unless the whole journey is Direct. full_impact, first_click, linear and lighthouse apply no such filter. The converting touch is always returned, so count is never 0 for a real order. State which model you used whenever you report a count. - attribution_window is in days, measured back from the order's own date — there is no date range to pass. Unlike get-order-list there is no lifetime option, so 0 is rejected. - Touch-points carry ad and campaign metadata only: no customer PII and no landing-page URL. - ad fields a channel does not have stay null (Pinterest has no campaign id; Klaviyo has no adset or campaign, and uses ad_type to say whether the touch was a campaign or a flow).
get-order-list
ChatGPTList the individual orders attributed to one advertising channel over a date range. Returns one row per order — order id, order date, customer email and name, and the order total both formatted and as a raw number for arithmetic. Use it to answer questions about specific purchases; use get-summary-data instead for channel totals. Notes: - start_date and end_date must be YYYY-MM-DD. - attribution_window is in days, and 0 means lifetime (no look-back limit). - By default this lists EVERY attributed order for the channel, which on a busy account is a very large result. When the user is asking about a particular campaign, ad set or ad, pass breakdown + entity_id to scope it — that is both faster and what they meant. - search matches the start of an order id, and also the customer email and name — but for accounts that mask customer details it silently narrows to the order id alone, so a name or email search will legitimately return nothing on those accounts. - Results are paginated; read pagination.has_next_page before assuming you have them all.
get-product-cohort-performance
ChatGPTStore-wide product performance with profitability and a new-vs-returning customer split: units, orders, customers, gross and net revenue, gross margin, COGS, discounts, tax, refunds and inventory - per product, variant, SKU, category, product type or collection. Use this for "which products make us money", "what are our best sellers", "which products do new customers buy", or any catalogue, margin or inventory question. THIS IS STORE-WIDE, NOT CHANNEL-ATTRIBUTED. It counts every order however the customer arrived. get-product-list is scoped to ONE ad channel's attributed orders and answers a different question - the two will not tie out, and dividing this revenue by a channel's ad spend produces a ROAS that means nothing. Always say which tool a product figure came from. THE COHORT IS THE ORDER'S CUSTOMER TYPE. "New" means that order was the shopper's first ever with this store. The split has an asymmetry you must not "fix": - The ORDER counts partition exactly. new_customer_orders / returning_customer_orders are ORDER counts and sum to orders. - The CUSTOMER counts do NOT partition. new_customers / returning_customers are DISTINCT customers and do NOT sum to customers - a shopper who bought the product as a first-timer and again later is in both. That is not double counting and must not be reconciled; never add those two together. Use the ORDER counts when two numbers have to add up. new_customer_order_share is the acquisition signal: a high share means the product recruits, a low one means it sells to people who already shop here. GRAINS. grain is product (default), variant, sku, category_name, product_type or collections. At category_name and product_type a product with no value is grouped under "(none)". At collections a product in two collections is counted in both rows, so those rows sum to more than the catalogue, and a product in no collection is grouped under "(none)". MONEY COLUMNS: gross_revenue is the pre-discount, tax-exclusive LINE subtotal - it is NOT a charged order total and will not reconcile against an order-level figure from any other tool. net_revenue takes off the line discount and this product's pro-rata share of the order's refund, and it is the headline. gross_margin is a PERCENTAGE of net revenue, not an amount, and is null when net revenue is zero or negative - report null as "no margin can be calculated", never as 0%. cost comes from the Shopify variant cost, so margin is overstated for any variant with no cost recorded. ORDER COUNTS DO NOT ADD UP ACROSS ROWS: one order holding three products is counted once on each of those three rows. coverage therefore reports period totals only for items sold and revenue, which do partition, and no period order count at all. SHARES ARE NET: revenue_share is this row's net revenue / the period's net revenue, and coverage.returned_net_revenue_share is the returned rows' share of net revenue. Label both "of net revenue" - never "of gross revenue", and never print one beside a gross revenue figure as if it were that figure's share. COHORT REVENUE: each product row also carries new_customer_revenue / returning_customer_revenue (split of gross revenue), new_customer_net_revenue / returning_customer_net_revenue (split of net revenue) and new_customer_aov / returning_customer_aov (cohort revenue / cohort orders, 0 when the cohort has no orders). An order with no recorded customer type is in neither cohort, so each pair sums to at most the total. The AOVs are this product's line value per order that contained it, not a whole-basket AOV. The four revenue splits are sortable. All of this is store basis - the attribution model does not apply. Only products with at least one order come back by default. Set include_zero_sales to true to see unsold catalogue rows - that plus sort_by=inventory_quantity is the dead-stock question. Shopify stores only. Ranking is applied across the whole catalogue before the row cap, so a top-N really is the account's top N; truncated says whether the cap was reached. An em…
get-product-list
ChatGPTList the products sold in the orders attributed to one advertising channel over a date range. Returns one row per product variant — name, product id, SKU, units sold, order count, distinct customers, average units per order, and revenue both formatted and as a raw number for arithmetic. Use it to answer "what did this channel actually sell"; use get-order-list for the individual orders behind those totals. Notes: - start_date and end_date must be YYYY-MM-DD. - attribution_window is in days, and 0 means lifetime (no look-back limit). - Revenue is the raw product basket for the attributed orders, not a re-weighted attribution share, so it will not tie out to the channel's attributed revenue. - There is deliberately no search parameter — filter the returned rows instead. - By default this covers EVERY attributed order for the channel. When the user is asking about a particular campaign, ad set or ad, pass breakdown + entity_id to scope it. - Results are paginated; read pagination.has_next_page before assuming you have them all.
get-store-data
ChatGPTGet store profit-and-loss figures — sales, orders, refunds, cost of goods, profit, ad spend and new versus returning customers — added together across every connected store (Shopify, WooCommerce, BigCommerce, Custom Store; not Amazon). These are the figures of a Store P&L tile on the Custom Dashboard. breakdown: - none: one row for the whole period (a scorecard) - day, week or month: one row per period, newest first; send sort_by "date" with sort_direction "asc" for a trend, oldest first Every response also carries totals for the whole period, whatever page you read. A week or month row is labelled with the start of its period, so the first label can fall before start_date — but only days between start_date and end_date are counted, and the rows add up exactly to totals. Notes: - These are store figures, not attributed to any ad channel. Spend is the connected Meta, Google, TikTok, Snapchat, Pinterest and Bing accounts; Amazon Ads and organic are excluded. - customer_type filters orders and refunds but never spend, so CAC, NCAC, ROAS, MER and POAS then compare all spend with part of the orders. - COGS is the product cost on the order date, 0 when no cost is set, and always 0 for WooCommerce, BigCommerce and Custom Store. Transaction cost is Shopify only. - start_date and end_date must be YYYY-MM-DD, at most 425 days apart. - Money is in the account's reporting currency; a division by zero is null.
get-summary-data
ChatGPTGet aggregated summary metrics for a specific advertising channel. Returns total/average metrics across all campaigns, ad sets, or ads for the specified date range. Useful for getting overall performance snapshots without detailed breakdowns.
get-top-creatives
ChatGPTRank the top creatives for one channel by a single metric — the Creative Dashboard's bar chart. Returns the top N creative assets over the whole date range (not a time series), ordered by metric descending, each carrying its rank. Use it for "which creatives are our best/worst by X"; use get-creative-data when you need many metrics per row, or more rows than a chart would show. Notes: - metric is restricted to the metrics the chart can actually render, and the set differs by channel — Pinterest has no thumbstop. Check list-creative-channels. - The google channel does not implement this tool; its dashboard has no chart. Use get-creative-data with sort_by there instead. - limit is the bar count, defaulting to 8 to match the dashboard. - The rows carry start_date and end_date because a bar has no other period marker.
get-trend-data
ChatGPTGet performance trend data over time for a specific advertising channel. Returns time-series data aggregated by day, week, or month. Useful for analyzing performance patterns, identifying trends, and comparing periods.
list-accounts
ChatGPTList all advertising accounts the authenticated user has access to. Returns account names that can be used with other tools. IMPORTANT: You must call this tool first and ask the user to select an account before using any data tools.
list-channels
ChatGPTList all available advertising channels supported by AdBeacon with their breakdowns and available metrics.
list-creative-channels
ChatGPTList the advertising channels that have creative data, and the exact vocabulary each one accepts. Call this BEFORE the first get-creative-* call in a conversation. It returns, per channel: which of the three creative tools the channel implements, its breakdowns (creative asset types), its selectable and sortable columns, the columns that exist only on the video breakdowns, its chart metrics, and its text- and metric-filter vocabularies. The channels differ from each other more than the Optimize channels do — a column or breakdown that is valid on one is frequently rejected on another — so do not carry a parameter set from one channel to the next without checking it here.
list-ga4-reports
ChatGPTList the Google Analytics 4 reports and the exact vocabulary each one accepts. Call this BEFORE the first get-ga4-data call in a conversation. It returns, per report (traffic, landing_page, product, path): its breakdowns, the breakdowns that read it by default, its selectable columns, the fields each breakdown may filter on, and the column rows are ordered by. Also the filter operators, paging limits and the rules a request must follow.