# Kuudo - Full Knowledge Base Kuudo connects Amazon Ads, AMC, SP-API, and Vendor Central to ChatGPT, Claude, Cursor, and any MCP client so teams can run governed Amazon workflows from chat. This document contains the complete text of our guides and documentation for AI crawlers. ## Guides ### Launch a DSP Campaign Without Half-Built Entities URL: https://www.kuudo.com/guides/amazon-ads-create-dsp-campaign/ Launching a DSP (demand-side platform) Performance+ or Brand+ campaign end to end is one ordered write sequence: every write is read back before the next step depends on it, every entity is created paused, and activation runs parent-first. Our **create-DSP-campaign Skill** runs that sequence through the [Amazon Ads MCP](/features/amazon-ads-mcp/), grounded by [Amazon Agent Atlas](/features/agent-atlas/) where a retrieved rule decides what a step is even allowed to send, and it confirms real delivery in [Amazon Marketing Cloud](/features/amc/)'s DSP traffic tables rather than trusting a create response. The ask arrived as a Slack message on a Thursday: *"Can you spin up a Performance+ campaign for the Q4 ASINs? Display and streaming TV, five thousand dollars, starts Monday."* Straightforward request. The last time someone ran it by hand we ended up with a campaign that existed, ad groups that did not, and an activation call returning NOT_FOUND on an ad group the API had confirmed creating seconds earlier. Half-built and live is worse than not built at all, because the spend starts before anyone notices the gap. Why not just ask [ChatGPT or Claude](/features/ai-clients/) to do it? A plain chat hits the same three walls on any Amazon job. It has **no access to your data**, so it cannot resolve your DSP advertiser ID or ask Amazon which tactics your campaign is actually eligible for. It has **no way to take action**, so it cannot create a campaign, create an ad group, or flip anything to ENABLED; the most it can do is hand you JSON to paste into an API client yourself. And it runs on **generic knowledge, not Amazon's**, so it does not know that the inventory type you set on the campaign is spelled differently one level down. What you get is disconnected, generic, manual work that ships silent mistakes. The Amazon Ads MCP supplies your account plus the tools to act on it, [Skills](/features/skills/) supply the ordered workflow, and Atlas supplies the rule book. ## Create every entity paused and read each write back before anything depends on it Nothing in this workflow is born live. The campaign is created with `state: "PAUSED"`, every ad group is created paused, and activation is a deliberate final step. That ordering is what makes a failure halfway through recoverable instead of expensive. The budget lives on the flight, not the campaign. There is no campaign-level budget field, so the single budget, start date, and end date the operator gave us map to one flight inside the campaign: ```json { "Amazon-Ads-AccountId": "", "campaigns": [ { "adProduct": "AMAZON_DSP", "name": "DSP|PB|Campaign 2026-08-20_14-02-11", "countries": ["US"], "state": "PAUSED", "flights": [ { "startDateTime": "2026-08-24T00:00:00Z", "endDateTime": "2027-08-24T00:00:00Z", "budget": { "budgetType": "MONETARY", "budgetValue": { "monetaryBudgetValue": { "monetaryBudget": { "value": "5000" } } } } } ], "optimizations": { "bidSettings": { "bidStrategy": "SPEND_BUDGET_IN_FULL" }, "goalSettings": { "kpi": "ROAS" }, "primaryInventoryTypes": ["DISPLAY", "VIDEO_STV"] } } ] } ``` Every datetime carries the `Z` suffix because the API rejects naive datetimes outright. Then the part that turns this from racy into deterministic: the Skill does not move on. It waits 100 milliseconds, queries the campaign it just created, and retries up to three times at one-second intervals if the record is not visible yet. The Amazon Ads API v1 makes no read-after-write guarantee, so a create can return successfully and the very next call can fail to find what it created. Worst case this adds about 3.1 seconds per step, which is a fair trade against a half-built campaign. > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT cannot query your account to find the DSP advertiser ID that every later call depends on. It will confidently leave you a `` placeholder, and you get to go find the real value yourself. > - **No way to take action.** Claude cannot create the campaign or read it back afterwards. If you paste its payload into an API client by hand, you also inherit the verification step, which means you are the one retrying on an eventually consistent API at the exact moment you thought you were done. > - **Generic knowledge, not Amazon's.** Ask where the budget goes and you will likely be told to put it on the campaign. There is no campaign-level budget field, so Amazon rejects that shape and you debug a payload that was wrong before you sent it. ## Zero eligible tactics is a goal-KPI mismatch, not an outage Once the campaign exists, ASIN conversion tracking gets attached: between 1 and 2,000 products per call, with a campaign ceiling of 500,000 products. Each entry carries the product ID, a domain derived as `AMAZON_` plus the country code, and a product association of `FEATURED`. That step has to land before the next one is meaningful, and it gets its own verification read for a specific reason. Eligible tactics are computed asynchronously, and the recomputation has its own propagation lag on top of the products landing. So the Skill verifies the products are present, then re-queries the campaign for `eligibleAutomatedTargetingTactics`, and retries three times at one-second intervals if the list comes back empty. When the list is still empty after retries, the cause is almost never an outage. It is that the campaign's goal KPI cannot produce the tactic you asked for: | Tactic | Compatible KPIs | Goal | |---|---|---| | CUSTOMER_ACQUISITION (P+) | ROAS | Conversions | | REMARKETING (P+) | ROAS | Conversions | | RETENTION (P+) | ROAS | Conversions | | MAXIMIZE_PERFORMANCE (P+) | COST_PER_DETAIL_PAGE_VIEW, DETAIL_PAGE_VIEW_RATE | Conversions | | PROSPECTING (B+) | REACH, FREQUENCY_AVERAGE, COST_PER_VIDEO_COMPLETION, VIDEO_COMPLETION_RATE | Awareness | ROAS there is return on ad spend, and the KPI is set back at campaign creation, which is why this failure surfaces two steps after the decision that caused it. Ask for Brand+ prospecting on a campaign built with a ROAS goal and the eligible list is empty, correctly, forever. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** Ask ChatGPT why your eligible tactics list is empty and you get generic API troubleshooting: check your credentials, check your permissions, try again later. The actual answer is a compatibility table it has never seen. > - **No access to your data.** Claude cannot see that your campaign was created with a ROAS goal while you are asking for PROSPECTING, because it cannot read the campaign. You would have to know to paste that detail in, which means knowing the answer already. > - **No way to take action.** A chat cannot retry the eligibility query for you, so it cannot tell the difference between propagation lag and a permanent mismatch. Those two look identical in a single response and need opposite fixes. ## The ad group renames the inventory type the campaign just used This is the single most common rejection in the whole workflow, and it is pure API naming inconsistency rather than anything conceptual. The same inventory type has one spelling at the campaign level and another at the ad-group level: | Intent | Campaign field | Ad group field | |---|---|---| | Display | DISPLAY | DISPLAY | | Streaming TV | VIDEO_STV | STREAMING_TV | | Online video | VIDEO_OLV | ONLINE_VIDEO | | Live events | LIVE_EVENTS | LIVE_EVENTS | | Audio | AUDIO | AUDIO | The eligible-tactics response hands back campaign-level names, so the value you receive is not the value you send one call later. The Skill translates on the way through, which is exactly the kind of mechanical rule that should live in a workflow rather than in someone's memory. The second trap is the field allowlist. A Performance+ or Brand+ tactic ad group accepts six fields and nothing else: ```json { "Amazon-Ads-AccountId": "", "adGroups": [ { "adProduct": "AMAZON_DSP", "campaignId": "", "name": "DSP|PB|STREAMING_TV|CUSTOMER_ACQUISITION 2026-08-20_14-02-11", "state": "PAUSED", "inventoryType": "STREAMING_TV", "targetingSettings": { "automatedTargetingTactic": "CUSTOMER_ACQUISITION" } } ] } ``` Bid, budgets, pacing, optimization, start and end times, creative rotation, viewability: all of them are auto-managed for tactic ad groups, and all of them are rejected if you send them. When this returns `INVALID_ARGUMENT`, the fix is to strip fields, not to correct values. That distinction saves a long debugging session, because the error text reads like a validation failure on the values you did send. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** Ask Claude to write the ad-group payload and it will helpfully include a bid and a budget, because that is what ad groups take everywhere else in advertising. Send that by hand and Amazon rejects the whole call. > - **No access to your data.** ChatGPT cannot read the eligible-tactics response, so it cannot know which inventory types came back for your campaign or that they need translating before you send them onward. > - **No way to take action.** A chat cannot create the ad group, so it cannot see the rejection and correct itself. You paste, you get INVALID_ARGUMENT, you paste the error back, and you iterate by hand against an API that is telling you something specific. ## Activate parent-first, or the ad groups fail against a campaign Amazon cannot see Activation is two moves in a fixed order: the campaign flips to `ENABLED` first, then each ad group flips to `ENABLED`. Never the reverse, and never in parallel. If the campaign fails to activate, the Skill stops and does not touch the ad groups at all. Activating children under a parent that is still paused produces either an outright failure or, worse, a confusing half-state where some entities are live and the thing that governs them is not. Reporting what did succeed is more useful than pushing on and leaving someone to reconstruct the order afterwards. This is also where the verification reads from every earlier step pay off. Activation immediately follows creation, and an update against a record the API cannot see yet is precisely how NOT_FOUND appears on an entity you watched get created. > **In plain ChatGPT or Claude** > - **No way to take action.** Neither ChatGPT nor Claude can flip anything to ENABLED. The activation sequence is something you execute manually, in order, while remembering which ad group IDs came back from which create call. > - **No access to your data.** A chat cannot check whether the campaign actually reached ENABLED before you activate the ad groups, so it cannot stop you from creating the half-state it just advised you to avoid. > - **And your data is now exposed.** To get a chat this far you have pasted advertiser IDs, campaign IDs, ASINs, and budget figures into a conversation history you do not control. The Skill never copies your account into a prompt; the MCP reads and writes over an authorized connection. ## Confirm delivery in the DSP tables, not in the create response A successful activation call means the entities are enabled. It does not mean a single impression has served. Those are different claims, and only one of them is what the operator actually asked for. Amazon Marketing Cloud carries three DSP traffic tables that answer the delivery question: `dsp_impressions`, `dsp_views`, and `dsp_clicks`. They cover all Amazon DSP campaigns across ad product types including display, online video, streaming TV, and audio. `dsp_clicks` is a subset of `dsp_impressions` that captures the impressions that were clicked, so a campaign with rows in impressions and none in clicks is delivering and not being clicked, which is a very different problem from not delivering. The dimension that makes this readable per tactic is `line_item`, which holds the name of the DSP line item responsible for the event, in the shape `'Widgets - DISPLAY - O&O - RETARGETING'`. Amazon's own example encodes the inventory type and the tactic directly in that name, which is the same grain the Skill created against: one entity per inventory type and tactic pair. Read delivery at that grain and a tactic that never served shows up immediately instead of hiding inside a campaign total. Check how your own line item names resolve the first time you run it, because the create surface and the reporting surface are different systems and nothing guarantees the strings match. Attributed conversions are a separate question again, and come from `amazon_attributed_events` rather than the traffic tables. One caveat worth knowing before you panic at an empty result. The DSP traffic tables contain inputs only from the DSP advertising accounts that have been added to that Marketing Cloud instance. A campaign can be delivering perfectly and still return nothing if its advertiser was never added. > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT cannot query your Marketing Cloud instance, so it cannot tell you whether your new campaign delivered. It can only describe what DSP reporting generally looks like. > - **Generic knowledge, not Amazon's.** Ask Claude why your instance returns no DSP rows and it will suggest a date range or a typo. The real answer, that the advertiser account was never added to the instance, is instance configuration it cannot see and has no reason to guess. > - **No way to take action.** A chat cannot run the check on a schedule, so nobody finds out that a tactic never delivered until someone thinks to look. ## What happens next The launch is the easy half. What makes it durable is that the whole sequence is a [Skill](/features/skills/) rather than a runbook, so it re-runs the same way for the next campaign, and the delivery check re-runs on a schedule instead of when someone remembers. The [Amazon Agent Data layer](/features/amazon-agent-flow/) is what turns that check into something standing: the DSP tables land next to the rest of your Amazon data, alongside the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) pulls behind your catalog and order history, so a per-tactic delivery question is a query rather than a project. The decision rule we run on is simple. Give a tactic a defined window after activation, then check `line_item` delivery. A tactic with no impressions in that window is not a slow start, it is a signal to look at eligibility and inventory rather than to wait longer. A tactic delivering impressions with no clicks is a creative problem, not a targeting one, and those two findings route to different people. Once the campaign has enough delivery to compare against everything else running, the next question is usually how much of it is incremental rather than overlapping what your sponsored ads already reached. *Next: the [four-way sponsored ads and DSP overlap audit](/guides/amc-sponsored-ads-dsp-overlap-4way/), which measures exactly that.* ### The Data-Mode Router That Stops Bad ACoS Math URL: https://www.kuudo.com/guides/rules-data-mode-router/ The nonsense ACoS numbers show up because your SQP export has no cost or revenue columns in it, and Amazon's own export doesn't flag that gap for you, nothing in the raw Ads or Selling Partner APIs tags a dataset as ads-backed or organic. Any report that hands you ACoS anyway skipped a check our **data-mode-router Skill** runs before every metric: a reusable, structured process, grounded by [Amazon Agent Atlas](/features/agent-atlas/)'s Keyword Analysis Decision Framework, that inspects the columns actually present in a dataset before it lets ACoS, ROAS (return on ad spend), or any spend-based number get computed. I asked our agent why a batch of n-gram reports kept returning ACoS on exports that never carried a spend column, and the answer was structural, not a bug. The Skill tags every dataset `ads`, `organic`, or `mixed` from its column set and hard-blocks ACoS/ROAS outside `ads`-backed data. Search Query Performance exports, pulled through the [Selling Partner MCP](/features/amazon-selling-partner-mcp/), are organic by construction. There's no spend column in there to blend. Why not just paste that export into [ChatGPT or Claude](/features/ai-clients/) and ask for ACoS? A plain chat hits the same three walls on any Amazon job. It has **no access to your data**, so it only sees the columns you pasted and can't check whether `total_median_click_price` is real spend or a market proxy. It has **no way to take action**, so the best it can do is hedge in prose instead of blocking the computation outright. And it runs on **generic knowledge, not Amazon's**, so it has no idea ACoS in organic mode is a codified Amazon violation. What you get is disconnected, generic, manual work that ships silent mistakes. [Amazon Ads MCP](/features/amazon-ads-mcp/) and the Selling Partner MCP give an agent your data and the tools to act, Atlas supplies the rule book, [Skills](/features/skills/) packages the workflow. ## The router tags every dataset ads, organic, or mixed before a metric runs Before our agent computes anything, the data-mode-router Skill runs its Quick Router logic to look at which columns a dataset actually has. This step doesn't exist in the raw Amazon data, it's the Skill applying Atlas's codified rules as a structured process, the same way every time. Ad signals are cost or spend, `campaign_id`, `ad_group_id`, keyword, match type, placement, the columns that exist because the Amazon Ads MCP mirrors those fields straight out of your live account, not because someone typed labels into a spreadsheet. Organic signals are `search_query`, `total_impressions`, `asin_impression_share`, and the rest of the Search Query Performance schema. If a dataset has ad signals and no organic ones, it's tagged `ads`. If it has organic signals and no ad ones, like every SQP export, it's tagged `organic`. Both together, it's `mixed`. That tag isn't a note in a log somewhere, it's the first field on every record the Skill emits. Here's what an ads-mode row looks like coming out of the n-gram rollup: ```json { "data_mode": "ads", "ngram": "wireless headset", "n": 2, "imp": 12450, "clk": 386, "cost": 782.14, "orders": 41, "revenue": 4312.0, "metrics": { "ctr": 0.031, "cvr": 0.1061, "cpc": 2.027, "roas": 5.514, "acos": 0.181 } } ``` Notice `data_mode` comes before the metrics that depend on it, not after. This is also the point where the router's job ends and a different rulebook picks up. Once a keyword resolves to `ads`, whether to actually change a bid on it is a separate question, governed by a different Quick Router keyed on `bidding_state`, not `data_mode`, over in the Sponsored Ads Bidding Configuration Decision Framework. The `data_mode` router decides what a signal even means. That framework decides whether to act on it. > **In plain ChatGPT or Claude** > - **No access to your data.** You paste one export into ChatGPT or Claude, and that's the only schema they'll ever see, neither one has a standing check that would catch you accidentally blending two different report exports into a single paste. > - **No way to take action.** Even when ChatGPT or Claude correctly guesses "this looks like SQP," you get a sentence back, not a machine-readable `data_mode` field your dashboard or next automation step can route on. > - **Generic knowledge, not Amazon's.** Ask ChatGPT or Claude why a column belongs to "ads" versus "organic" and you get a plausible guess built from header names, not the actual Amazon report taxonomy. ## ACoS in organic mode isn't a style nitpick, it's priority #1 forbidden Our data-mode-router Skill doesn't treat "don't compute ACoS on organic data" as a soft preference, it enforces it as code, every run. It's rule one of seven in the decision-precedence ladder the Skill applies, grounded by Atlas, ranked above thin-data holds, safety negatives, pull-back actions, scale moves, and mining or hygiene work. Invalid computations get dropped and repaired before any other business rule even gets evaluated. Nothing outranks it, and nothing in Amazon's own reporting enforces this ranking for you. The Skill's config defaults reinforce the same rule structurally, not just procedurally: `target_acos`, `target_roas`, and `break_even_acos` only exist under the ads branch of the targets config. There's no organic branch for an ACoS target to live in, because organic data was never going to have spend to target against. Those same three constants (0.25, 4.0, 0.30 in our defaults) are actually anchored at the ad-group level by the Sponsored Ads Bidding Configuration Decision Framework mentioned above, the data-mode-router Skill just reads them, it doesn't own them. ```yaml precedence: 1: invalid_computation # drop/repair, e.g. ACoS computed in organic mode 2: hold_thin_data 3: safety_negative 4: pull_back 5: scale_unlock 6: mining_hygiene 7: creative_ops targets: ads: target_acos: 0.25 target_roas: 4.0 break_even_acos: 0.30 # organic has no target_acos / target_roas key at all ``` > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT and Claude can't verify whether the "cost" or "revenue" figure you pasted is real ad spend or a market estimate, they have no route into your account data to check its provenance. > - **No way to take action.** ChatGPT or Claude can warn you in a sentence, but they can't drop the computation and substitute a repair action the way a rule ranked above every other business rule does. > - **Generic knowledge, not Amazon's.** ChatGPT and Claude have no concept of "ACoS in organic mode is an invalid computation, priority one." That's a severity ranking our Skill enforces, grounded in real Amazon operational patterns, and neither one can derive it from the ACoS formula alone. ## Mixed data doesn't get blended into one number, it gets split into two Some exports carry both column families at once, a keyword report joined against a campaign report, say. When that happens, the Skill's mixed-dataset guardrail doesn't average the two into one blended figure. It computes ads metrics only where ads-backed cost and revenue actually exist, applies organic rules only to signals backed by SQP, and emits two separate records for the same keyword, each carrying its own `data_mode` tag, with no cross-mixing of numerators and denominators between them. For "wireless headset," that looks like this: ```json [ { "data_mode": "ads", "ngram": "wireless headset", "n": 2, "imp": 12450, "clk": 386, "cost": 782.14, "orders": 41, "revenue": 4312.0, "metrics": { "ctr": 0.031, "cvr": 0.1061, "cpc": 2.027, "roas": 5.514, "acos": 0.181 } }, { "data_mode": "organic", "ngram": "wireless headset", "search_query": "wireless headset", "total_impressions": 58210, "total_clicks": 1904, "conversion_performance_index": 96, "share_funnel_gaps": { "impression_to_click_gap_pp": -0.4, "click_to_purchase_gap_pp": 0.6 } } ] ``` Two records, two tags, nothing shared between their numerators and denominators. The alternative, one blended row with an ACoS computed against a mix of real spend and organic volume, is exactly the invalid computation rule one exists to catch. > **In plain ChatGPT or Claude** > - **No access to your data.** You'd have to manually label which rows in a combined export are ads-backed and which are organic-backed, ChatGPT and Claude have no cross-reference to your actual campaign IDs to do it for you. > - **No way to take action.** Ask ChatGPT or Claude to "split this out" and you get a one-time answer for that message, next week's paste starts from zero with no consistency guarantee across reports. > - **Generic knowledge, not Amazon's.** The generic instinct is to hand you one clean, helpful number per keyword. ChatGPT and Claude don't know Amazon operational convention treats that single blended number as the invalid output, not the goal. ## Organic mode routes to Conversion Performance Index, not ACoS Blocking ACoS on organic data is only half the rule, the Skill also has to route to something valid, and for `organic` that's Conversion Performance Index and the impression-to-click-to-purchase share funnel. Neither is a field Amazon's Search Query Performance report gives you directly, the Skill calculates both from the shares Amazon does report. CPI is `(your_purchase_rate / market_purchase_rate) x 100`, banded under 80 as underperforming, 80 to 120 as competitive, and above 120 as outperforming. Alongside it, `impression_to_click_gap_pp` and `click_to_purchase_gap_pp` show exactly where your ASIN is losing share against the market baseline for that query. Below the CPI sufficiency floor (`asin_clicks >= 20` and `total_clicks >= 100`), the Skill holds the decision instead of guessing on thin data. The ASIN-level diagnostic layer downstream adds its own floor (`total_impressions >= 200`) before it turns a share gap into a strong claim, and cooldowns run 7 to 14 days per query and ASIN so the same finding doesn't refire every day. Here's a full routed decision for one query, including the guardrail check that blocked ACoS on the way in: ```json { "report_id": "sqp-ngram-2026-08-07", "routing": { "columns_detected": ["search_query", "total_impressions", "total_clicks", "asin_impression_share", "asin_click_share", "asin_purchase_share", "total_median_click_price"], "ads_signals_present": false, "organic_signals_present": true, "resolved_data_mode": "organic" }, "guardrail_checks": [ { "rule": "invalid_computation", "precedence_rank": 1, "trigger": "ACoS/ROAS requested but data_mode=organic (no cost/spend columns)", "result": "blocked", "action": "drop_and_repair", "repair": "substitute Conversion Performance Index + share funnel gaps" } ], "decisions": [ { "data_mode": "organic", "search_query": "dog bed large", "asin": "B00XYZ...", "market": { "total_impressions": 123456, "total_clicks": 3456, "purchase_rate": 0.018 }, "asin_metrics": { "impression_share": 0.024, "click_share": 0.031, "purchase_share": 0.020 }, "conversion_performance_index": 64.5, "share_funnel_gaps": { "impression_to_click_gap_pp": 0.7, "click_to_purchase_gap_pp": -1.1 }, "flags": { "thin_data": false }, "recommendations": ["pdp_update"] } ] } ``` A CPI of 64.5 lands below 80, underperforming the market, which is exactly why `recommendations` queues `pdp_update` rather than a bid change. Behind that field sits the ASIN-level diagnostic layer, running its own IF-THEN rules on top of the share funnel: high query volume with low impression share routes to `seo_update` plus `pdp_update`, purchase share trailing click share alongside slow shipping routes to `shipping_speed_fix`. ACoS was never going to point you at any of that. > **In plain ChatGPT or Claude** > - **No access to your data.** CPI needs a market denominator, total purchases over total clicks across every seller on that query. ChatGPT and Claude only have what you pasted, they can't hold that baseline steady from one report to the next. > - **No way to take action.** Even if ChatGPT or Claude computes CPI once in chat, neither can enforce your data-sufficiency floor or turn a share-gap into a queued `pdp_update`, you're back to opening a ticket by hand. > - **Generic knowledge, not Amazon's.** Ask "how's my organic doing" and ChatGPT and Claude both gravitate back toward ACoS, because neither one knows a metric built for this exact dataset already exists. ## What happens next When I run this against a fresh batch of reports, our agent doesn't just resolve `data_mode`, fire the guardrail check, and hand back a JSON blob to stop there. It pushes the routed decision into [Amazon Agent Flow](/features/amazon-agent-flow/), the data layer that holds routed decisions alongside the raw SP-API (Selling Partner API) and Ads API pulls they came from, so next week's report starts from the same schema instead of guessing again. The recommendation it queued, `pdp_update`, `seo_update`, `shipping_speed_fix`, becomes a scheduled run of the same Skill that reruns on the 7-to-14-day cooldown instead of a one-off answer you have to remember to ask for again. If the resolved mode had come back `ads` instead, the same decision hands off to a different ladder entirely, applied by a different Skill: the bid-thrash precedence covered in [the bidding rulebook guide](/guides/rules-agent-bidding-rulebook/), which decides whether to actually move a bid once the signal underneath it is already confirmed valid. The data-mode-router Skill decides what a number means. The bidding rulebook's Skill decides what to do about it once it does. That's the pattern underneath the whole rulebook: validate the signal before you ever act on it, structured Skill logic doing work Amazon's raw reports never do on their own, and never let the two ladders answer each other's questions. *Next in the series: how the ASIN-level diagnostic decision object turns a Conversion Performance Index gap into a queued PDP or SEO fix.* ### Auditing FBA Reimbursements: What Amazon Owes You URL: https://www.kuudo.com/guides/seller-fba-reimbursement-audit/ Grounded by [Amazon Agent Atlas](/features/agent-atlas/), the [fba-reimbursement-audit Skill](/features/skills/) is what actually answers "how much in FBA (Fulfillment by Amazon) loss and damage reimbursements has Amazon already paid us, and how much are we missing," because Amazon's own Inventory Defect and Reimbursement portal can't: it lists individual defect events across its Eligible, In Progress, and Resolved tabs, but it never classifies an event into a claim type, checks it against that type's own window, or applies the correct valuation rule. I went looking for this number after our reconciliation spreadsheet fell three months behind the portal. Once I asked our agent to pull every eligible event through [Selling Partner MCP](/features/amazon-selling-partner-mcp/), classify it, and check it against Amazon's actual policy, the picture changed: real money sitting unclaimed, and real deadlines closing on it. Before building anything, I asked [ChatGPT and Claude](/features/ai-clients/) the same question. Both hit the same three walls: **no access to your data** (they've never seen our Inventory Defect and Reimbursement portal or Ledger report), **no way to take action** (they can't file a claim or submit a sourcing cost), and **generic knowledge, not Amazon's** specific rules (they default to textbook reimbursement logic, not FBA policy). The answer stayed a guess. MCP supplies the data and the tools to act, Atlas supplies the cited rule book, the Skill runs the workflow safely. ## A loss or damage event isn't one claim, it's three claim types with three different windows Every lost or damaged unit Amazon owes us for falls into one of three claim types, and each type carries its own deadline, not a shared one. Shipment to Amazon claims (units lost or damaged in transit to a fulfillment center or third-party facility) have to be filed no later than nine months after the verified delivery date. Fulfillment Center Operations claims (units lost or damaged inside Amazon's own operations) have to be filed no later than sixty days after the item was reported lost or damaged in the Inventory Defect and Reimbursement portal or the Inventory Ledger report. Customer Return claims are the one most sellers get wrong: file no sooner than sixty days and no later than 120 days after the refund or replacement, a window with a floor as well as a ceiling. Classifying comes first. The Skill sorts every raw defect and return event by type, then computes each one's window status, open, closing soon, or expired, as a flagged field in the audit report. That's the step the portal skips: it'll show an event happened, but it won't say which of the three clocks is running on it, let alone how many days are left. ```json { "event_id": "EVT-00113", "classified_claim_type": "fulfillment_center_operations", "reported_date": "2026-06-12", "window": { "end": "2026-08-11", "status": "closing_soon", "days_remaining": 4 } } ``` > **In plain ChatGPT or Claude** > - **No access to your data.** Ask ChatGPT which of your events is approaching deadline and you're the one pasting them in, and you'd already need to know which of the three windows applies before it can check the math. > - **No way to take action.** Even a correct window calculation from Claude doesn't file anything for you. You still have to go into Seller Central and submit the claim before it closes. > - **Generic knowledge, not Amazon's.** Ask either one for "the reimbursement deadline" and you're as likely to get one universal answer as three separate ones, with no particular reason to know the customer-return window has a sixty-day floor, not just a limit. ## Eligibility isn't a spectrum, it's seven gates that all have to hold Amazon doesn't reimburse partial eligibility. A unit has to be FBA-registered at the time of loss, compliant with FBA restrictions, shipped in the exact quantities on the shipping plan, part of a shipment that wasn't canceled or deleted, not pending or actioned for disposal, not customer-damaged or defective, and tied to an account that stays in normal status all the way through the claim and any appeal. Seven gates, and every single one has to be true. Fail one and the claim is void, no matter what the item was worth. The Skill checks all seven gates automatically before an event counts toward the "recoverable" total, splitting the result into eligible-and-unclaimed versus ineligible, and naming the specific gate that failed on each ineligible event instead of just marking it "no." That distinction matters when we're deciding whether to spend appeal time on a claim that was never going to qualify. > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT can recite the seven rules from memory, but ChatGPT can't check your actual account status, your shipping-plan quantities, or whether a given shipment was canceled. > - **No way to take action.** If your account drops out of normal status while a claim is under review, the claim voids, and Claude has no visibility into your account health to warn you. > - **Generic knowledge, not Amazon's.** It's easy to assume "lost is lost." Ask ChatGPT and it's unlikely to flag that a disposal-pending or customer-damaged item is excluded categorically, no matter how clearly the loss was Amazon's fault otherwise. ## Valuation depends on when the loss happened, not what the item is worth Pre-order events pay differently than post-order ones, and that split runs through every lost unit on the sheet. Shipment-to-Amazon losses, removals, and fulfillment center operations events pay our sourcing cost: what we paid to source the unit, not what we'd have sold it for. Customer return events pay the refund or replacement amount minus applicable fees instead. Either way, $5,000 per unit is the ceiling: Amazon caps a single unit's reimbursement at that amount regardless of which of the two rules set the value. Most sellers, including me before I looked closely, mentally price every lost unit at retail. The policy doesn't work that way, and the gap between the two numbers is where the missed money hides. Inside the Skill, the valuation engine applies the correct rule per event based on its classified claim type, and for every pre-order event it checks whether we've actually submitted our own sourcing cost or whether Amazon is still defaulting to its own estimate. The audit report shows both numbers side by side, Amazon's likely valuation against our sourcing-cost-corrected valuation, with the $5,000 cap applied wherever it binds. ```json { "artifact_type": "audit_report", "skill": "fba-reimbursement-audit", "grounded_by": "amazon-agent-atlas", "summary": { "events_audited": 214, "reimbursed_total_usd": 8420.15, "eligible_unclaimed_total_usd": 1180.40, "at_risk_window_closing_usd": 340.00, "disputable_valuation_total_usd": 265.75 }, "events": [ { "event_id": "EVT-00113", "classified_claim_type": "fulfillment_center_operations", "order_relationship": "pre_order", "valuation": { "rule_applied": "sourcing_cost", "sourcing_cost_submitted": false, "amazon_estimate_usd": 14.20, "unit_cap_usd": 5000 }, "status": "eligible_not_filed", "flags": ["window_closes_in_4_days", "sourcing_cost_not_submitted"] }, { "event_id": "EVT-00087", "classified_claim_type": "customer_return", "order_relationship": "post_order", "valuation": { "rule_applied": "refund_minus_fees", "refund_amount_usd": 42.00, "fees_deducted_usd": 6.30 }, "reimbursement_actual": { "issued": true, "amount_usd": 30.00, "variance_vs_expected_usd": -5.70 }, "status": "disputable", "flags": ["eligible_for_valuation_dispute"] } ] } ``` > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT doesn't know your actual sourcing cost, your actual refund amounts, or which events were pre-order versus post-order. > - **No way to take action.** Even when Claude correctly says "this should be sourcing cost, not retail," you still have to go submit the figure on the Manage Your Sourcing Cost page yourself and validate it if Amazon asks. > - **Generic knowledge, not Amazon's.** ChatGPT's training-data instinct says reimbursement equals what you'd have made on the sale, and without the policy text right in front of ChatGPT, it will confidently give you the wrong valuation logic. ## Reimbursement isn't a one-shot event, it's a loop most sellers never run Getting paid once isn't the end of it. There's a recovery loop layered on top of the three windows and seven gates: submitting our own sourcing cost instead of accepting Amazon's estimate, respecting the thirty-day cooldown before resubmitting without new information, disputing a valuation within sixty days of an issued reimbursement, and handling the customer-return special case correctly. If a customer is refunded but never returns the item to a fulfillment center within sixty days, Amazon typically charges the customer and reimburses us. If the item does come back within sixty days and it's sellable, it goes back into inventory and we get no reimbursement. If it comes back unsellable and Amazon caused the damage, we get reimbursed and the item isn't restocked. Tracking doesn't stop at filing. The Skill follows every event's reimbursement status across its full lifecycle, not just at the moment a claim gets filed, flagging "sourcing cost not yet submitted," "eligible for valuation dispute, window closes in nine days," and "resubmission blocked until August 20th, no new information supplied," so the backlog of things we could still do doesn't quietly age out. > **In plain ChatGPT or Claude** > - **No access to your data.** Neither ChatGPT nor Claude knows which of your reimbursements were already issued, on what date, at what amount, or which ones are still inside their sixty-day dispute window. > - **No way to take action.** Filing the dispute, submitting sourcing-cost documentation, or waiting out the thirty-day cooldown are all Seller Central actions. Claude can draft the dispute language, but it can't track the clock or click submit for you. > - **Generic knowledge, not Amazon's.** The sellable-versus-unsellable branching logic on customer returns is easy to get backwards from memory. Ask ChatGPT and it's as likely to say "you get reimbursed either way" as to correctly explain that a sellable return within sixty days forfeits reimbursement entirely. ## What happens next Once the audit report is built, it doesn't sit still. We feed it into [Amazon Agent Flow](/features/amazon-agent-flow/), the same data layer that holds [Amazon Ads MCP](/features/amazon-ads-mcp/) and Selling Partner MCP pulls side by side, so recovered reimbursement dollars sit next to the ad spend they help offset. The Skill schedules the same pass weekly and hands off anything newly flagged: a window closing inside seven days, a sourcing cost still unsubmitted, a dispute that just opened, so it shows up as a task instead of a line buried in a spreadsheet. Recovery is only half the ledger. The other half, what we pay out rather than what Amazon owes back, is covered in the [FBA inventory health guide](/guides/seller-fba-inventory-health-post-2024/): storage fees, capacity limits, aged-inventory surcharges. Running both audits is how we see the full ledger instead of half of it. Same pattern every time: Amazon publishes the rule, leaves the classifying and window-checking to the seller, and pays out only what gets claimed correctly and on time. *Next in the series: what happens when Amazon denies a valid claim outright, and the appeal window most sellers let expire.* ### The ARA Report and Metric Glossary for Vendors URL: https://www.kuudo.com/guides/vendor-ara-reports-metric-glossary/ The ARA report router [Skill](/features/skills/), grounded by [Amazon Agent Atlas](/features/agent-atlas/), is what actually answers which ARA report answers a given question, and what the metric inside it actually measures. Amazon's Vendor Central UI doesn't do that: it hands you a dashboard tab. Raw SP-API (Selling Partner API) reports don't do it either: they hand you a payload full of fields, not an interpretation of which field you needed or what its number means. I run into this constantly. Someone on my team asks why sell-through dropped, or what "Conversion" means in the export we're staring at, and the honest answer depends on which report, which account view, and which section of Amazon's own help docs you're reading, not on which tab happened to be open when you logged in. Why not just ask [ChatGPT or Claude](/features/ai-clients/) the same question? A plain chat hits the same three walls on any Amazon job. It has **no access to your data**, so neither knows if your login has Sourcing or Manufacturing view, or whether you're Brand Registry enrolled, and can't name your dashboard. It has **no way to take action**, so neither can call SP-API to verify a report type actually exists. And it runs on **generic knowledge, not Amazon's**, so the answer is uncited and primed to ship a silent mistake. What you get is disconnected, generic, manual work. MCP is your data and the tools to act, Atlas is the cited rule book, the Skill is the safe workflow. ## Every ARA dashboard has a mirrored SP-API report type, so naming the dashboard is only half the job Sales maps to `GET_VENDOR_SALES_REPORT`. Inventory maps to `GET_VENDOR_INVENTORY_REPORT`. Forecasting maps to `GET_VENDOR_FORECASTING_REPORT`. Traffic maps to `GET_VENDOR_TRAFFIC_REPORT`. Net PPM maps to `GET_VENDOR_NET_PURE_PRODUCT_MARGIN_REPORT`. Knowing the dashboard name gets you nowhere near an API call, and knowing a report type string with no dashboard context doesn't tell you which metric definition governs it. The ARA report router Skill resolves both in a single lookup, calling through [Selling Partner MCP](/features/amazon-selling-partner-mcp/) to fetch the report once it knows which one you actually need. When I asked our agent why sell-through dropped on a set of ASINs, the Skill didn't guess. It resolved the question to the Inventory dashboard, the `GET_VENDOR_INVENTORY_REPORT` report type, and the `sellThroughRate` field inside it, then pulled the report through the same call path. It's also the reason the Skill catches a retirement most operators don't think to check: the Sales and Inventory EDI transactions (X12 852, EDIFACT SLSRPT) and the Forecast EDI transaction (X12 830, EDIFACT DELFOR) were retired after June 30, 2022, so API is now required to pull them. Traffic and Net PPM never had an EDI form at all; they've been API-only from day one. If the question resolves to Net PPM specifically, that's where [the margin-leakage guide](/guides/vendor-net-ppm-margin-leakage/) picks up. This guide is upstream of it: once the router names the dashboard and the report type, that guide is where you go hunting for the actual leak. ```json { "operator_question": "Which report do I pull to find products dragging my margin?", "resolution": { "dashboard": "Net PPM", "sp_api_report_type": "GET_VENDOR_NET_PURE_PRODUCT_MARGIN_REPORT", "view_required": "manufacturing", "metric": { "name": "Net pure product margin (Net PPM)", "definitions": [ { "formula": "(shipped revenue - shipped PCOGS + CCOGS - sales discounts) / shipped revenue", "cited_section": "Net PPM dashboard" } ], "conflicting_definition": false } }, "caveat_flags": ["excludes_warehouse_deals", "manufacturer_only_dashboard"] } ``` > **In plain ChatGPT or Claude** > - **Generic knowledge.** Ask ChatGPT or Claude which SP-API report matches a dashboard and you'll often get retired EDI-era vocabulary back, because that's what dominates older training data, not the current API-first framing. > - **No way to take action.** ChatGPT or Claude can describe a report type name in prose, but neither can verify the literal enum string against Amazon's schema or confirm it against a live call on your account. > - **No access to your data.** ChatGPT or Claude doesn't know whether your integration is still EDI-based or already migrated to API, so neither can tell you if the 2022 retirement even applies to your account. ## ARA and ABA are different products gated by different rules, so "I can't find my dashboard" means two different problems Every vendor gets ARA. No Brand Registry requirement, no enrollment gate, it's part of the vendor relationship. ABA, Amazon Brand Analytics, is a different product entirely: it requires Brand Registry enrollment and being the brand-selling party on the ASINs in question. Before the Skill routes an operator's question to a dashboard, it classifies the question against those access rules first, so it doesn't send you looking for a dashboard your account structurally cannot have. Beyond the access gate, the two products measure different things entirely. ABA's Search feature covers search popularity, click share, and conversion share for a search term. Its market basket analysis shows co-purchased products. Its repeat purchase behavior tracks order counts and unique customers over time. None of that lives in ARA, which is built around sales and operational dashboards, not search or purchase-pattern analytics. Conflating the two doesn't just point you at the wrong tab, it points you at a feature set that doesn't exist in the product you're looking at. > **In plain ChatGPT or Claude** > - **No access to your data.** Neither ChatGPT nor Claude can see your account's Brand Registry status, so neither can tell you which of the two products you should even expect to see. > - **Generic knowledge.** "Brand Analytics" and "Retail Analytics" sound like variants of the same phrase, so if you ask ChatGPT or Claude to tell them apart, expect ABA's market basket analysis attributed to ARA. > - **No way to take action.** Even when ChatGPT or Claude correctly names Brand Registry as the gate, checking your actual enrollment status is an account action on Amazon's side. You have to go look yourself. ## Amazon's own ARA docs define "Conversion" two different ways on the same overview page This is the one that made me stop trusting my own memory of ARA definitions. The Traffic dashboard section of Amazon's ARA overview defines Conversion as ordered revenue divided by glance views. The General dashboard information section, on the same overview page, defines Conversion as ordered units divided by glance views. Not a typo in one section and a fix in the other, both are live, current documentation. Amazon's own help content disagrees with itself two sections apart, and neither section says so. Rather than pick a side, the Skill attaches both formulas to the resolution whenever it resolves a question to Conversion, citing each one's exact source section and flagging the metric as having a conflicting definition instead of silently returning one number as "the" answer. That flag matters more than it sounds: if your internal reporting was built against one formula and a teammate pulled a number using the other, you'd see two different Conversion rates and no obvious reason why, unless something told you to check. ROOS and Rep OOS get the same treatment, for a related reason: they sound interchangeable and aren't. ROOS, procurable product out-of-stock, considers procurable ASINs, a broader cohort than Rep OOS's replenishable-ASINs-only scope. Because the ROOS cohort is larger, ROOS usually reads as a lower percentage than Rep OOS on the same account, which is exactly the kind of thing that looks like an error until you know it's a definitional difference. Sourceable Product OOS is a third, related but distinct glossary entry, not a synonym for either: OOS glance views on sourceable ASINs divided by total glance views, also Manufacturing view only. The Skill keeps all three as separate glossary entries so it never treats one as a stand-in for another. Sell Through Rate gets its own definition too: shipped units minus customer returns, divided by on-hand units plus received units, a formula with no ambiguity but plenty of adjacent metrics it gets confused with. ```json { "operator_question": "What does Conversion mean in my ARA dashboard, and which report is it in?", "resolution": { "dashboard": "Traffic", "sp_api_report_type": "GET_VENDOR_TRAFFIC_REPORT", "view_required": "manufacturing", "metric": { "name": "Conversion", "definitions": [ { "formula": "ordered revenue / glance views", "cited_section": "Traffic dashboard" }, { "formula": "ordered units / glance views", "cited_section": "General dashboard information" } ], "conflicting_definition": true, "resolution_note": "Amazon's ARA overview defines Conversion two different ways in two sections of the same page. Both sections are current, confirm which formula your internal reporting matches before comparing numbers across teams." } }, "caveat_flags": ["manufacturer_only_dashboard", "conflicting_definition"] } ``` > **In plain ChatGPT or Claude** > - **Generic knowledge, and this is the flagship problem.** Ask ChatGPT or Claude what the Conversion formula in ARA is and you'll get one formula stated with full confidence. Neither can notice that Amazon's own help page disagrees with itself two sections apart. > - **No access to your data, compounded by generic knowledge.** Two people on your team asking ChatGPT or Claude the same question a week apart could get genuinely different formulas back and never know to reconcile them. > - **No way to take action.** If ChatGPT or Claude conflates ROOS, Rep OOS, and Sourceable Product OOS, neither can pull your actual account data and check which cohort your number is scoped to, that's a live-data check only you can run. ## Four recurring distortions make an ARA number look complete when it isn't Warehouse Deals sales are excluded from the Sales and Net PPM dashboards, so if your internal reporting reconciles against ARA and includes Warehouse Deals in its own totals, the two will never match, by design, not by error. Sourcing view versus Manufacturing view changes which ASINs and even which metrics appear at all: Traffic, Net PPM, Forecasting, Sourceable Product OOS, and ROOS are Manufacturing-view-only, so a Sourcing-view login won't show them regardless of what the operator asked for. Customer returns and cancellations get booked against the original date of the sale, not the date the return happened, which means a return processed this month can quietly revise a number from three months ago. And ASIN mapping issues, once corrected, can take up to fourteen days to actually show up in the dashboards, so a "fixed" product can look missing for two more weeks. Net PPM itself is (shipped revenue minus shipped PCOGS plus CCOGS minus sales discounts) divided by shipped revenue, and the Warehouse Deals exclusion applies to it the same way it applies to Sales. The decision_plan the Skill produces carries these as caveat flags attached to the resolution itself, not buried in a footnote: `excludes_warehouse_deals: true` on Sales and Net PPM, `view_required: manufacturing` on Traffic, Net PPM, Forecasting, Sourceable OOS, and ROOS. The flag travels with the number, so whoever reads the resolution sees the caveat before they build a decision on the metric, not after. > **In plain ChatGPT or Claude** > - **No access to your data.** Neither ChatGPT nor Claude can see which view your Vendor Central login has. You have to go check. > - **No way to take action.** If your internal reporting reconciles against ARA and includes Warehouse Deals, neither ChatGPT nor Claude can pull both numbers and diff them, that's an action against live data, not a description of one. > - **Generic knowledge.** The return-date attribution rule is easy to get backwards, so if you ask ChatGPT or Claude, you're as likely to get the intuitive-but-wrong version, booked to the return date, as the correct one. ## What happens next A decision_plan isn't a one-off answer, it's structured output the Skill can hand off downstream. Once the Skill has resolved a question to a dashboard, a report type, and a set of caveat flags, that resolution feeds into [Amazon Agent Flow](/features/amazon-agent-flow/), the same data layer that holds [Amazon Ads MCP](/features/amazon-ads-mcp/) and Selling Partner MCP pulls side by side, so a routed ARA answer sits next to the ad-spend numbers it eventually gets compared against. The Skill can schedule the same lookup as a recurring check instead of a one-time query, useful for anything with a mapping delay attached, since a "missing" ASIN today might just need another look in two weeks. For questions that resolve to Net PPM, the handoff goes straight to the margin-leakage guide, because routing tells you where to look and that guide is where you actually go digging for the leak itself. The pattern underneath all four sections is the same: get the question routed to a cited, current answer before you build anything on top of it, not after you've already shipped a number that was wrong in a way nobody flagged. *Next in the series: ARA vs. ABA, which dashboard actually answers which question.* ### Listing Suppression Diagnosis: Stranded or Buyable URL: https://www.kuudo.com/guides/seller-listing-suppression-diagnosis/ Create this workflow as a reusable Skill called `silent-asin-diagnosis`. It reads live `BUYABLE` and `DISCOVERABLE` status through the [Selling Partner MCP](/features/amazon-selling-partner-mcp/), uses [Amazon Agent Atlas](/features/agent-atlas/) to interpret the exact suppression or stranded-inventory rule, and returns the reason-specific fix plus its deadline before anyone edits the listing. I start there when a top ASIN suddenly has no orders or impressions. Search suppression, a non-buyable offer, a block, a deletion, and stranded Fulfillment by Amazon (FBA) stock can look identical from the sales graph, but each demands a different repair. A plain ChatGPT or Claude conversation hits three walls: **no access to your data**, including the live SKU, `ListingsItemStatus`, FBA units, listing issues, or current report; **no way to take action**, such as requesting evidence or applying an approved fix; and **generic knowledge, not Amazon's** exact reason fields and deadlines. You must paste disconnected snapshots, expose account data, and carry out every step yourself. Connected [AI clients](/features/ai-clients/) get past those walls through the MCP's reads and actions, Atlas-grounded rules, reusable [Skills](/features/skills/), and the [Amazon Agent Data layer](/features/amazon-agent-flow/) that records the decision. | Live state | Diagnosis | Next evidence | |---|---|---| | `BUYABLE` + `DISCOVERABLE` | Listing is live | Diagnose traffic and demand | | `BUYABLE`, not `DISCOVERABLE` | Search suppressed | Pull reason and issues | | Not `BUYABLE`; FBA units | Possible stranded stock | Confirm no active offer | | Not `BUYABLE`; no stranded units | Offer-side failure | Check quantity, window, restrictions | ## `BUYABLE` and `DISCOVERABLE` separate suppression from stranding When a listing is search suppressed, Amazon removes discoverability but can leave the offer buyable; stranded inventory is FBA stock in a fulfillment center that does not have an active offer. That distinction is the first branch, not a semantic detail. The Skill reads `ListingsItemStatus`, whose relevant values are `BUYABLE`, `DISCOVERABLE`, and `DELETED`. `BUYABLE` without `DISCOVERABLE` points to search suppression. An absent `BUYABLE` status establishes that the offer is not buyable, but it does not establish stranding until the agent also finds FBA units and no active offer. If both status flags are healthy, I move the investigation away from catalog repair. > **In plain ChatGPT or Claude** > - **No access to your data:** ChatGPT or Claude cannot read the live status, offer, or FBA unit count. You can paste a search result, but that does not prove buyability or inventory state. > - **No way to take action:** ChatGPT or Claude can give you a checklist. You must retrieve each status and compare the records by hand; the Selling Partner MCP performs the connected read. > - **Generic knowledge, not Amazon's:** ChatGPT or Claude can collapse “suppressed” and “stranded” into one diagnosis. Atlas keeps the branch tied to Amazon's status definitions. ## The suppression reason chooses the repair `GET_MERCHANTS_LISTINGS_FYP_REPORT` contains only suppressed listings, the reason for each suppression, and instructions for removing it. It can be requested for a current investigation or scheduled for continuous monitoring. I use the report to identify the affected SKU, then add its live listing issues to the evidence. The **Suppressed Listings Management** playbook routes the result through Fix Your Products: image failures go to image requirements, missing attributes expose the absent value, and newly required compliance attributes get patched directly. Rewriting unrelated copy or adding stock does not repair those causes. The bulk report is not real-time proof. Later report calls can be 1 to 6 hours old, and the stock-data freshness commitment is three hours, so the Skill pairs that evidence with the live listing read before proposing a patch. > **In plain ChatGPT or Claude** > - **No access to your data:** ChatGPT or Claude cannot request the suppressed-listings report or inspect the SKU's current issues. You would have to paste a manual snapshot into the chat. > - **No way to take action:** ChatGPT or Claude can draft replacement text only. You must find the named field and apply the correction yourself; the Selling Partner MCP can execute an approved, scoped patch. > - **Generic knowledge, not Amazon's:** ChatGPT or Claude may suggest a broad rewrite. Atlas distinguishes image, attribute, and compliance causes, including the exact missing value. ## The stranded reason chooses relist, restore, or removal `Stranded reason` determines whether the operator should relist the SKU, restore an offer, correct price or condition, fix the fulfillment channel, or remove the units. The Fix stranded inventory page is the most accurate source when Manage Inventory and stranded status disagree. Until the active offer returns, those FBA units cannot sell and continue to accumulate storage fees. The **Resolve stranded inventory issues** playbook reads `Stranded reason` and the accompanying `Additional information` or Recommendations. Common evidence includes a missing listing, a missing price or condition, or a merchant-fulfilled listing attached to FBA units. For a catalog-wide repair, the same playbook uses the Bulk Fix Stranded Inventory workflow. The clock matters. If the seller does not create a listing or order removal within 30 days of Amazon's notice, Amazon designates the inventory unsellable and it must be removed. The deadline begins with Amazon's notice, not with the day I diagnose it. > **In plain ChatGPT or Claude** > - **No access to your data:** ChatGPT or Claude cannot see your FBA units, active-offer state, `Stranded reason`, or recommended action. You must collect and paste those facts. > - **No way to take action:** ChatGPT or Claude can describe relisting or removal. You must complete the selected Seller Central step yourself; the connected workflow runs supported MCP actions and keeps any Seller Central-only step explicit for you. > - **Generic knowledge, not Amazon's:** ChatGPT or Claude may tell you to create a second listing when price, condition, offer state, or fulfillment channel is the actual fault. Atlas supplies the reason-specific path and 30-day rule. ## A repair is complete only when status returns A submitted change is not a completed repair. Suppression closes when discoverability returns; stranded stock closes when buyability and an active offer return. The Skill watches `LISTINGS_ITEM_STATUS_CHANGE`, schedules `GET_MERCHANTS_LISTINGS_FYP_REPORT`, and re-reads the affected SKU after Amazon's processing window. It records the branch, approved action, evidence, and stranded deadline in the run log. If `BUYABLE` and `DISCOVERABLE` are both healthy but demand is still absent, the workflow hands the ASIN to the [Amazon Ads MCP](/features/amazon-ads-mcp/) instead of misclassifying a traffic problem as a listing problem. > **In plain ChatGPT or Claude** > - **No access to your data:** ChatGPT or Claude cannot observe a later status change or verify that the active offer returned. You must collect another snapshot. > - **No way to take action:** ChatGPT or Claude can remind you to check. You must schedule and perform every recheck; the Skill monitors the expected status and preserves the deadline. > - **Generic knowledge, not Amazon's:** ChatGPT or Claude can stop at “submitted.” Atlas keeps the completion test tied to discoverability, buyability, and the active offer. ## What happens next I route the completed diagnosis to one owner. Product-data issues go to the team approving an image, attribute, or compliance patch. Offer and FBA issues go to the inventory team with the reason-specific action packet. A healthy listing with no demand moves to the advertising team with its catalog state already cleared. That handoff can run as one recurring Skill through [Amazon Agent Flow](/features/amazon-agent-flow/), so each new silent-ASIN alert arrives with its evidence and owner instead of becoming another unclassified ticket. The pattern is status, reason, scoped action, and verified return. That keeps a silent ASIN from turning into an expensive guess. *Next, use the [listing audit-to-patch guide](/guides/seller-listing-agentic-audit-to-patch/) to turn a verified attribute issue into the smallest safe catalog change.* ### The Agent Bidding Rulebook That Prevents Bid Thrash URL: https://www.kuudo.com/guides/rules-agent-bidding-rulebook/ A bidding rulebook stops thrashing when a bid can only move after three independent gates agree: the n-gram clears data sufficiency, its ACoS sits outside a deadband around target, and the resulting change fits inside a hard daily clamp. That is the whole answer. I handed the question to [our agent](/features/ai-clients/), which runs it as a [Skill](/features/skills/) over the [Amazon Ads MCP](/features/amazon-ads-mcp/), grounded by [Amazon Agent Atlas](/features/agent-atlas/) in two corpus playbooks: the Keyword Analysis Decision Framework (N-Grams) and the Sponsored Ads Bidding Configuration Decision Framework. The question that sent me looking came from our PPC lead, in Slack, on a Tuesday: every tool she had used either overcorrected or undercorrected, and she wanted to know what a sane rulebook actually looks like underneath. Ask a plain ChatGPT or Claude chat and you hit three walls on any Amazon job. It has no access to your data: it cannot read your search-term report, your ad group configuration, or your trailing 30-day spend, so you paste a CSV that is stale the moment you paste it. It has no way to take action: it cannot change a bid, set a placement multiplier, or add a negative, so the most you get is text you retype into Campaign Manager by hand. And it runs on generic public knowledge, not Amazon's: it will produce thresholds that sound right and are not. The result is disconnected, generic, manual work that ships silent mistakes into a live account. The [Amazon Ads MCP](/features/amazon-ads-mcp/) supplies your data and the tools to act on it, Atlas supplies the private rule book, and the Skill supplies the bounded workflow that keeps the two honest. ## Thin data gets a hold, not a bid change Most thrash is not a bad threshold, it is a threshold applied to a sample too small to mean anything. The rulebook gates on sufficiency before any rule is allowed to evaluate. For 1-grams that means `IMP_g >= 50` and either `CLK_g >= 10` or `ORD_g >= 2`. Longer n-grams need proportionally more: 2-grams require `IMP_g >= 100`, 3-grams `IMP_g >= 150`, with the same click-or-order condition. There is a second gate one level up, at the ad group. The starvation guard in the Sponsored Ads Bidding Configuration Decision Framework holds everything when `CLK_l30d < 50` and `ORD_l30d < 5`. The prescribed action is `hold_thin_data` with no destructive change, and the advice is to consolidate or extend the observation window rather than act early. An agent that respects both gates spends most of its first run reporting that it is not going to do anything yet. > **In plain ChatGPT or Claude** > - **No access to your data.** It cannot see impression counts per n-gram, so it cannot tell a 4,000-impression term from a 40-impression one. Paste a top-50 rows sample and it will confidently rank terms that have no statistical business being ranked. And your search-term data is now sitting in someone else's chat log. > - **No way to take action.** Even when it correctly says "this needs more data," it cannot set a hold, record a cooldown, or stop a downstream job. Nothing enforces the wait except you remembering. > - **Generic knowledge, not Amazon's.** Ask for a minimum impression threshold and you get a plausible round number. The real gates are versioned per n-gram length in the corpus playbook, and they are not the numbers a public model guesses. ## Scale and pull-back fire at fixed distances from target This is the part that actually prevents thrash. The scale rule and the pull-back rule do not trigger at target ACoS, they trigger at fixed distances on either side of it, leaving a gap where nothing happens at all. A scale decision needs `ORD_g >= 10` **and** `ACOS_g <= 0.9 x TARGET_ACOS`, and produces `increase_bid` at +5 to 10% on keywords containing that n-gram. A pull-back needs `ORD_g >= 10` **and** `ACOS_g > 1.1 x TARGET_ACOS`, and produces `decrease_bid` at -10%, plus a 10% reduction to the Top-of-Search multiplier if one is in use. Both re-evaluate in 5 days. Between 0.9x and 1.1x of target, no bid rule fires. That deadband is the single most load-bearing number in the rulebook. A bidder without one sits exactly at target and oscillates forever, correcting every run in whichever direction last week's noise pointed. | Condition | Action | Re-eval | |---|---|---| | `ORD_g >= 10`, `ACOS_g <= 0.9x target` | `increase_bid` +5 to 10% | 5 days | | `ORD_g >= 10`, `ACOS_g > 1.1x target` | `decrease_bid` -10% | 5 days | | ACoS inside the deadband | none | next run | | `ROAS_g >= target`, impressions bottom quartile | `increase_bid` +5 to 8%, TOS +10% | 5 days | > **In plain ChatGPT or Claude** > - **No access to your data.** It does not know your `TARGET_ACOS`, so it cannot compute a deadband around it. Tell it your target and it will still evaluate against the single number rather than a band, which is the behavior that thrashes. > - **No way to take action.** It can describe a +8% bid increase. It cannot apply one. If you retype that change into Campaign Manager yourself, nothing records that the entity is now in a 5-day review window, so next week you may well move it again. > - **Generic knowledge, not Amazon's.** The 0.9 and 1.1 multipliers, the +5 to 10% magnitudes, and the 5-day re-evaluation are all specified in the retrieved playbook. A public model has no reason to produce those particular numbers and generally does not. ## Every lever is clamped before it ships Gates decide whether a rule fires. Clamps decide how far it can go when it does. The global controls are short enough to memorize: a daily bid change clamp of plus or minus 20%, a Top-of-Search placement cap of 1.50, and a standard review window of 5 days for Ads and 7 to 14 days for Organic and Ops work. The clamp matters most in the case where the rulebook is most confident. An n-gram at half of target ACoS with 200 orders is a genuinely strong signal, and the temptation is to move the bid a long way at once. The clamp refuses. Twenty percent per day, then look again in five days. Every decision record the agent emits carries its own `max_change_pct` and `cooldown_days`, the latter defaulting to 5 to 14 depending on the action type, so the bounds travel with the decision rather than living in a settings page nobody re-reads. ```json { "decision_category": "scale_winner", "action_id": "increase_bid", "action_scope": ["ADS"], "selector": { "ngram": "stainless steel", "n": 2, "match_type": "phrase" }, "magnitude_pct": 8, "max_change_pct": 20, "cooldown_days": 5, "confidence": "high", "reason": "ORD_g=31, ACOS_g=0.19 <= 0.9 x TARGET_ACOS(0.25); sufficiency met", "badges": { "data_sufficient": true, "cooldown_ok": true, "thin_data_reason": null } } ``` > **In plain ChatGPT or Claude** > - **No access to your data.** It cannot see what the bid was yesterday, so it cannot tell you whether a proposed change is inside the daily clamp. Apply its suggestion by hand two days running and you can move a bid 40% without noticing. > - **No way to take action.** Placement multipliers are a good example: it can tell you to raise Top-of-Search by 10%, but it cannot read the current multiplier, so neither of you knows whether that crosses the 1.50 cap until you are in the console. > - **Generic knowledge, not Amazon's.** Ask for safe bid-change bounds and you get advice, not a contract. The clamp here is a field on the decision record, which means a downstream job can reject anything that violates it. ## Precedence decides which rule wins Real accounts produce conflicts. A keyword can look wasteful on one metric and efficient on another, and two rules will match the same entity in the same run. Rather than letting whichever rule evaluated last take the entity, the framework fixes an order: invalid computations first, then thin data, then safety negatives, then pull back, then scale, then mining and hygiene, and creative or ops work last. The tiebreak is explicit and conservative. When a rule suggests both scale and pull-back, prefer pull-back, unless credible intervals support scaling with high confidence. That is where the reliability layer earns its place: the recommended signals are Bayesian credible intervals at 95%, Beta for CTR and CVR, Gamma for spend and revenue ratios, alongside recency weighting with a 14-day half-life and peer medians computed with trimming. The interval, not the point estimate, is what lets a scale decision beat a pull-back decision. > **In plain ChatGPT or Claude** > - **No access to your data.** With no click and order counts it cannot compute a credible interval at all, so the one mechanism that resolves a scale-versus-pull-back tie is unavailable to it. > - **No way to take action.** Ask it to arbitrate two conflicting recommendations and it will pick one in prose. Nothing stops both from reaching the account if you work through its list by hand and apply each item as you read it. > - **Generic knowledge, not Amazon's.** A seven-level precedence ladder with a documented tiebreak is not something a public model reconstructs. It will produce a reasonable-sounding ordering that differs from the one your rulebook actually uses, which is worse than no ordering because it looks authoritative. ## What happens next The output is a decision plan, not an applied change. Each record names the entity, the bounded action, the clamp, the cooldown, and the reason it fired, which makes it reviewable before anything reaches the account. That review step is the same pattern as a [human approval gate](/guides/human-approval-for-amc-activation/) on [Amazon Marketing Cloud](/features/amc/) activation: the agent assembles the artifact, a person signs it, the platform ships it. Once a plan is approved, the review windows do the pacing. Ads actions re-evaluate in 5 days, Organic and Ops in 7 to 14, and each record's `cooldown_days` prevents the next run from touching an entity still inside its window. Wired as a recurring Skill over the [Amazon Agent Data layer](/features/amazon-agent-flow/), the agent reads a fresh rollup, skips everything on cooldown, and emits a much shorter plan the second week. A rulebook that is working produces fewer decisions over time, not more. The [Selling Partner MCP](/features/amazon-selling-partner-mcp/) covers the catalog side of the same account when a decision turns out to be a listing problem rather than a bidding one. The pattern is worth stating plainly: bounded actions with explicit gates beat continuous optimization because they are auditable, and an agent that can explain why it did nothing is more trustworthy than one that always has a change to make. *Next: the data-mode router, and why computing ACoS on organic search-query data is the fastest way to poison a rulebook.* ### Recover Featured Offer Eligibility Without Guessing URL: https://www.kuudo.com/guides/seller-buy-box-eligibility-recovery/ The fastest way to recover a missing Featured Offer is to identify the failed gate first: account eligibility, price health, or competition among eligible offers. The agent reads the live Fulfillment by Amazon (FBA) inventory offer for the Amazon Standard Identification Number (ASIN) through the [Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/), applies a reusable [Skill](/features/skills/), and uses [Amazon Agent Atlas](/features/agent-atlas/) to ground the diagnosis in Amazon's Featured Offer rules. The same evidence can flow through [Amazon Agent Flow](/features/amazon-agent-flow/) and the [Amazon Agent Data layer](/features/amazon-agent-flow/) when the recovery check spans selling and advertising signals. That distinction matters because “we lost the Buy Box” describes two different situations. An offer can be ineligible before Amazon ranks it, or it can be eligible and still lose the placement to another offer. Amazon also announced a gradual July 2026 rollout removing the seller-eligibility step, so a historical rule cannot be treated as universal across every store yet. If the offer's demand context matters, the [Amazon Ads MCP](/features/amazon-ads-mcp/) can add campaign-side evidence without turning a plain chat into a live data connection. Why not ask [ChatGPT](/features/ai-clients/) or Claude? A disconnected chat has **no access to your data**, **no way to take action**, and **generic knowledge, not Amazon's**. It cannot read the live offer, inspect a `PRICING_HEALTH` notification, or verify which eligibility rollout applies to your store. The human can paste facts into a chat, but the result is still manual and easy to misclassify. The workflow below keeps the MCP, Skill, Atlas, and your approval step connected. ## Eligibility is a gate, not proof of placement The first check is whether Amazon currently allows the offer to compete. The Atlas-grounded Featured Offer Eligibility playbook says a Professional selling account and performance-based requirements have historically been part of that gate, while Amazon's July 2026 announcement says the seller-eligibility step is being removed gradually. The agent should therefore read the current account state and store rollout status instead of returning a fixed yes/no from old rules. ```json { "asin": "B0EXAMPLE12", "account_type": "Professional", "store": "US", "eligibility_gate": "verify_current_policy", "performance_evidence": { "status": "read_live_account_metrics", "source": "Seller Central account health" }, "rollout_note": "Eligibility rules are changing during the July 2026 rollout" } ``` > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT or Claude cannot read your current account type, performance state, or store-level rollout. It can only reason from what you paste. > - **Generic knowledge, not Amazon's.** A chat may repeat the Professional-account rule as if it were permanent. The agent checks the current policy context and labels uncertainty instead of treating a historical gate as universal. > - **No way to take action.** The chat cannot inspect the account or confirm the offer's current eligibility. You still have to verify the state in Seller Central yourself. ## `PRICING_HEALTH` isolates a price-driven ineligibility When the agent receives `PRICING_HEALTH`, the immediate question is not “did a competitor undercut me?” Amazon says the notification means the offer is ineligible at its current price, independent of competitor changes. Compare the offer's total price, including shipping, with the Competitive External Price and the `referencePrices` values such as `averageSellingPrice`, `msrpPrice`, and `competitivePriceThreshold`. ```json { "status": "price_ineligible", "notification": "PRICING_HEALTH", "total_price": 32.98, "competitive_external_price": 29.99, "reference_prices": { "averageSellingPrice": 30.49, "msrpPrice": 34.99, "competitivePriceThreshold": 29.99 }, "recommended_action": "review price and shipping; approval required" } ``` > **In plain ChatGPT or Claude** > - **No access to your data.** A chat cannot inspect the notification payload or the live shipping charge, so it may compare the wrong number. > - **Generic knowledge, not Amazon's.** It may treat `ANY_OFFER_CHANGED` as the same signal. `PRICING_HEALTH` means Amazon considers this offer ineligible; `ANY_OFFER_CHANGED` reports offer changes and can include different context. > - **No way to take action.** ChatGPT or Claude cannot validate a proposed price against Amazon. You must check the evidence and apply any change yourself. ## Eligible offers still compete on price, shipping, and experience Passing the gate does not win the placement. The Atlas playbooks describe the next stage as a competition among eligible offers; Amazon evaluates competitive price and compelling shipping options, and the detail page can show one New and one Used Featured Offer where applicable. The **Get to Know the Product Detail Page** playbook is the reference for how those offers appear and compete. The recovery artifact should label this state `eligible_not_featured`, not `eligibility_failure`. ```yaml # Skill: featured-offer-recovery read: - offer: live price, shipping, condition, fulfillment - account: current eligibility and performance state - notifications: PRICING_HEALTH, ANY_OFFER_CHANGED compare: - total_price_plus_shipping - competitive_external_price - reference_prices - delivery_and_availability classify: - account_gate - price_ineligible - eligible_not_featured - insufficient_evidence ``` > **In plain ChatGPT or Claude** > - **No access to your data.** A chat cannot see the competing offers, shipping promises, or availability that shape the ranking. > - **Generic knowledge, not Amazon's.** It may promise that matching one price guarantees the placement. Amazon says eligibility does not guarantee being featured. > - **No way to take action.** The chat cannot monitor the next offer change or confirm that a price adjustment changed the placement. ## The recovery artifact should recommend, not silently reprice The Skill turns the evidence into a small decision plan. It names the failed gate, cites the notification or account evidence, proposes the narrowest next step, and keeps approval on any price or fulfillment change. If evidence is incomplete, it returns `insufficient_evidence` instead of guessing. For related operational context, compare the same evidence-first pattern in the [FBA inventory health guide](/guides/seller-fba-inventory-health-post-2024/) and use [Agent Crawl](/features/agent-crawl/) only when the workflow explicitly needs current external-market evidence. ```json { "asin": "B0EXAMPLE12", "status": "price_ineligible", "evidence": [ "PRICING_HEALTH", "total price $32.98 > competitive threshold $29.99" ], "recommended_action": "review price and shipping options", "requires_approval": true, "monitor": ["PRICING_HEALTH", "ANY_OFFER_CHANGED"] } ``` > **In plain ChatGPT or Claude** > - **No access to your data.** It cannot produce a trustworthy evidence trail from the live offer, so its “fix” is usually a generic repricing suggestion. > - **Generic knowledge, not Amazon's.** It cannot distinguish a price-health failure from an eligible offer that simply lost the ranking. > - **No way to take action.** You remain the operator applying and monitoring the change by hand. The Skill keeps the approval step explicit and watches the relevant notification stream. ## What happens next Once the artifact identifies the gate, the team can approve one narrow change, continue monitoring, or route an account issue to Seller Central support. The Skill rechecks `PRICING_HEALTH` and `ANY_OFFER_CHANGED` after the decision so a recovered offer is measured instead of assumed. Featured Offer recovery is a diagnosis problem before it is a pricing problem: verify the gate, read the evidence, then approve the smallest action that addresses it. *Next in the series: diagnosing a listing that is suppressed or stranded before its inventory keeps accruing storage cost.* ### FBA Inventory Health After the 2024 Fee Change URL: https://www.kuudo.com/guides/seller-fba-inventory-health-post-2024/ The post-2024 Fulfillment by Amazon (FBA) inventory playbook is not “stop watching capacity.” It is to separate three signals before the next fee cycle: cubic-foot capacity usage, monthly storage cost, and units approaching the aged-inventory threshold. An agent can run that review through the [Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/) as a reusable [Skill](/features/skills/), grounded by [Amazon Agent Atlas](/features/agent-atlas/) so the policy window and report fields are not guessed. Amazon ended FBA inventory storage overage fees effective July 1, 2024 in the United States, Europe, United Kingdom, and Canada stores. That change does not remove monthly inventory storage fees or the aged inventory surcharge. The operator question is therefore narrower and more useful: which inventory is consuming capacity, which inventory is accumulating storage cost, and which inventory is close to the next age threshold? The same review can join Amazon Standard Identification Number (ASIN) inventory context to the campaign and demand signals available through the [Amazon Ads MCP](/features/amazon-ads-mcp/). Why not just ask [ChatGPT](/features/ai-clients/) or Claude? A disconnected chat has **no access to your data**, **no way to take action**, and **generic knowledge, not Amazon's**. It cannot see your current FBA inventory, retrieve the reports, or apply the store-specific rules that determine which fee is relevant. The workflow below keeps those boundaries explicit: read live data, ground the interpretation, then decide what action deserves approval. ## Separate the fee policy from the inventory decision The first move is a policy check, not a removal recommendation. The FBA Inventory Storage Overage Fees playbook says the overage fee stopped being charged in the named stores on July 1, 2024. The same source still describes monthly storage fees and an aged inventory surcharge as separate charges. Atlas returns that distinction with the retrieval context, so the agent does not collapse “overage fee removed” into “storage is free.” > **In plain ChatGPT or Claude** > A chat can repeat a fee announcement, but it cannot verify which store, date, or fee family the announcement applies to. The agent reads the current seller context and Atlas-grounded policy before it labels an inventory issue. The output should be a short policy record: store scope, effective date, fee families still in play, and the source playbooks used. That record becomes the explanation for every downstream recommendation. ## Measure capacity in cubic feet, not units Capacity is a volume problem. The report exposes `capacity_usage_volume`, `capacity_limit`, `overage_volume`, and `volume_unit`; the unit is cubic feet. A unit count can rise while volume stays flat, or a small number of bulky units can create the larger constraint. The agent should read the Capacity Monitor or Inventory Performance view, then reconcile the report fields before ranking action. ```yaml inventory_health_snapshot: storage_type: oversize capacity_usage_volume: 600 capacity_limit: 500 overage_volume: 100 volume_unit: cubic feet decision: investigate slow-moving bulky inventory ``` > **In plain ChatGPT or Claude** > A chat usually turns “too much inventory” into a unit count because that is what a seller pasted into the prompt. The MCP can read the capacity fields and preserve the volume unit, while the Skill keeps a bulky ASIN from being hidden inside an account-wide average. The useful artifact is not a generic “reduce stock” list. It is a ranked queue by storage type, cubic-foot contribution, velocity, and removal or replenishment option. Keep `volume_unit` attached to every number so a later operator does not mistake volume for units. ## Review monthly storage separately Monthly storage fees remain a distinct operating signal after the overage-fee change. Review the Monthly Storage Fee report by ASIN, then identify the SKUs whose storage cost is persistent without a matching sell-through or replenishment need. Atlas retrieval also surfaces storage-utilization surcharge and AWD waiver context, so the agent can mark a fee as a policy exception rather than treating every charge as a capacity breach. > **In plain ChatGPT or Claude** > A chat can suggest liquidation, but it cannot tell whether a SKU is driving base storage, a utilization surcharge, or a fee covered by a program benefit. The agent reads the relevant report and explains which cost layer moved before anyone chooses a removal order. This is where the operator separates diagnosis from action. A high monthly storage charge may justify a sell-through, liquidation, return, or replenishment change, but the action belongs after the evidence review. The Skill should present the report rows, the decision rule, and the expected trade-off together. ## Catch aged inventory before the fifteenth-day snapshot The aged inventory surcharge applies to units stored 181 days or longer and is assessed using an inventory snapshot on the fifteenth day of each month. The FBA Inventory tool can show inventory that is already subject or will become subject within 60 days. The review should therefore sort by days-to-threshold, cubic-foot exposure, and available action window. ```text next_snapshot: 2026-08-15 asin: B0EXAMPLE12 age_days: 176 days_to_181_day_threshold: 5 per_unit_volume: 0.102 cubic feet recommended_review: removal, sell-through, or return economics ``` > **In plain ChatGPT or Claude** > A chat can calculate “181 days” from a pasted date, but it cannot see the current age distribution or the next snapshot. The agent reads live FBA inventory, grounds the threshold in Atlas, and gives the team time to act before the charge is assessed. The Aged Inventory Surcharge report is the evidence layer after the decision. It provides itemized SKU quantities, per-unit volume, surcharge tier, and amount charged. Keep the pre-snapshot queue and the post-charge report together so the team can compare the avoided cost with the action it chose. For a related report-driven workflow, see [FBA order and report review](/guides/seller-fbm-orders-reports/). ## What happens next Run the review on a schedule: policy check first, capacity volume second, monthly storage third, and aged-inventory countdown last. The agent should return a compact report with source playbooks, report fields, affected ASINs, and proposed actions. A human then approves removals, returns, liquidation, or replenishment changes through the [Selling Partner MCP](/features/amazon-selling-partner-mcp/). The [Amazon Agent Data layer](/features/agent-atlas/) keeps the policy context attached to the decision, and the [Amazon Agent Flow](/features/amazon-agent-flow/) can carry the approved workflow forward. If your FBA review still asks only whether the overage fee exists, it is looking at one policy line instead of inventory health. Separate volume, storage, and age, then decide with the evidence in front of you. *Next in the series: turning the same age and volume queue into a controlled removal recommendation without losing the audit trail.* ### Find ASIN Margin Leakage with Net PPM URL: https://www.kuudo.com/guides/vendor-net-ppm-margin-leakage/ Run an Amazon Standard Identification Number (ASIN)-level Net PPM comparison, rank each negative rate contribution, then decompose the largest drags into shipped COGS/PCOGS, CCOGS, and sales-discount pressure where the connected report exposes those fields. The ranking is Kuudo-derived, not an Amazon metric. Amazon's dashboard identifies products driving profitability up or down after costs, funding, and discounts. That answers my question: *"Our Vendor Central revenue looks fine but margin is sliding. Which ASINs are actually dragging down our pure product margin?"* Revenue cannot show which equation term changed. The report must answer materiality first, then cause where the component fields support it. | Question | Test | Report output | | --- | --- | --- | | Biggest drag? | Rate-leakage proxy | Ranked ASINs | | Cost pressure? | PCOGS/revenue up | Cost flag | | Funding pressure? | CCOGS/revenue down | Funding flag | | Discount pressure? | Discounts/revenue up | Discount flag | The rate-leakage proxy and driver tests are Kuudo-derived from the sourced equation. Amazon does not name these fields. A plain [ChatGPT and Claude chat](/features/ai-clients/) hits three walls: **No access to your data**, **No way to take action**, and **Generic knowledge, not Amazon's**. [Selling Partner MCP](/features/amazon-selling-partner-mcp/) supplies vendor-account context, a [Skill](/features/skills/) produces the repeatable report and review queue, and [Amazon Agent Atlas](/features/agent-atlas/) supplies the metric definitions, access rules, exclusions, and timing caveats. Without those pieces, the work stays disconnected, generic, and manual, which ships silent mistakes. ## The Net PPM dashboard identifies products driving profitability up or down The Net PPM dashboard identifies products that raise or lower profitability. It lives in Amazon Retail Analytics, which Amazon's reports index separates from Brand Analytics. An ABA customer or search dashboard is not the source. The retrieved **Amazon Retail Analytics and Reports Overview** defines Net PPM around cost of goods, vendor funding, and sales discounts. That keeps the Skill focused on profitability instead of treating revenue as a margin answer. | Run field | Bound value | | --- | --- | | Skill | `vendor-net-ppm-margin-leakage` | | Input | Account and two periods | | Scope | Selected ASIN set | | Connector | Selling Partner MCP | | Grounding | Atlas `amazon_vendors` | | Output | `analysis_report` | | Report header | Recorded value | | --- | --- | | Report | ASIN Net PPM analysis | | Vendor scope | Connected account or group | | Marketplace | Connected marketplace | | View | Manufacturing | | Current period | Selected closed period | | Comparison period | Selected comparable period | | Data as of | Close and refresh status | | Warehouse Deals | Excluded | | Material move | `{{material_ratio_move_pp}}` pp | | Residual tolerance | `{{residual_tolerance_pp}}` pp | The report renders its executive answer instead of hiding it in a notebook: | Executive result | Bound result | | --- | --- | | ASINs reviewed | `{{asins_reviewed}}` | | Negative PPM changes | `{{negative_change_count}}` | | Top-five leakage share | `{{top_five_leakage_share}}` | | Largest flagged driver | `{{largest_driver}}` | | Boundary warnings | `{{boundary_warnings}}` | Only the connected run populates those values. When a component field is unavailable, the executive answer keeps the ASIN ranking and marks the driver analysis incomplete. > **In plain ChatGPT or Claude** > Without a connected account, you must export and paste the dashboard data. ChatGPT or Claude can discuss margin, but neither can inspect the current ASIN rows or determine whether the selected account exposes the Net PPM dashboard. ## Net PPM separates revenue, PCOGS, CCOGS, and sales-discount pressure Net PPM separates four signed components, so each available ratio's direction supports a first-pass driver flag. The normalized equation is: ```text Net PPM = (shipped revenue - shipped COGS [PCOGS] + CCOGS - sales discounts) / shipped revenue ``` The **Amazon Retail Analytics Metric Glossary** defines Shipped COGS as Amazon's item procurement price, also called Product Cost of Goods Sold (PCOGS). Contra-COGS (CCOGS) is vendor funding collected for agreements tied to purchases, customer sales, or marketing. CCOGS includes Vendor Allowance, Quick Pay Discounts, and Discretionary COOP, but excludes display-ads Contra-COGS. One glossary rendering says "shipped CCOGS" in the subtraction term. The report normalizes it to shipped COGS/PCOGS because CCOGS is separately defined as the added funding term. | Type | Report field | Meaning | | --- | --- | --- | | Observed | Shipped revenue | Shipment-item price | | Observed | Shipped COGS/PCOGS | Amazon procurement cost | | Observed | CCOGS | Collected vendor funding | | Observed | Sales discounts | Discount formula term | | Derived | PCOGS ratio | PCOGS divided by revenue | | Derived | CCOGS ratio | CCOGS divided by revenue | | Derived | Discount ratio | Discounts divided by revenue | The run records a material-move threshold and a residual tolerance. Those are operator inputs, not Amazon thresholds. | Driver flag | Derived rule | Interpretation | | --- | --- | --- | | PCOGS pressure | Cost magnitude clears threshold | Procurement cost drag | | Funding pressure | Funding magnitude clears threshold | Less vendor funding | | Discount pressure | Discount magnitude clears threshold | More sales discount | | Mixed | Two magnitudes clear threshold | Shared cause | | Unclassified | No clear or complete cause | Check scope or rounding | Each component effect is signed: a negative value reduces Net PPM. Its pressure magnitude is `max(-component_effect_pp, 0)`. A single-driver label requires exactly one pressure magnitude greater than or equal to `{{material_ratio_move_pp}}` percentage points, and that magnitude must be the largest. **Mixed** requires two or more pressure magnitudes to clear the same threshold. **Unclassified** covers a missing component, no magnitude that clears the threshold, or an absolute residual greater than `{{residual_tolerance_pp}}` percentage points. The output records both inputs beside every label so another run can reproduce the classification. > **In plain ChatGPT or Claude** > A pasted topline-revenue prompt can produce a plausible but unverified formula. You still have to supply current PCOGS, CCOGS, discounts, and revenue, and generic chat can conflate Product Cost of Goods Sold with Contra-COGS unless you provide the definitions. ## A rate-leakage proxy ranks material ASIN deterioration before investigation Holding current revenue constant and multiplying it by a negative Net PPM rate change prioritizes ASINs with material sales and worsening margin. A large swing on a tiny ASIN cannot automatically outrank a larger drag. **Kuudo-derived calculations, not Amazon metrics** ```text net_ppm_delta_pp = current_net_ppm_pct - prior_net_ppm_pct current_margin_dollars_proxy = current_shipped_revenue * current_net_ppm_pct / 100 rate_leakage_dollars_proxy = current_shipped_revenue * max(prior_net_ppm_pct - current_net_ppm_pct, 0) / 100 pcogs_ratio_delta_pp = current_pcogs_ratio_pct - prior_pcogs_ratio_pct ccogs_ratio_delta_pp = current_ccogs_ratio_pct - prior_ccogs_ratio_pct discount_ratio_delta_pp = current_discount_ratio_pct - prior_discount_ratio_pct pcogs_effect_pp = -pcogs_ratio_delta_pp ccogs_effect_pp = ccogs_ratio_delta_pp discount_effect_pp = -discount_ratio_delta_pp component_pressure_magnitude_pp = max(-component_effect_pp, 0) explained_delta_pp = pcogs_effect_pp + ccogs_effect_pp + discount_effect_pp residual_delta_pp = net_ppm_delta_pp - explained_delta_pp ``` Holding revenue constant isolates rate deterioration from volume. The dollar fields are prioritization proxies, not booked loss, reimbursement value, or Amazon-calculated fields. Rounding and unavailable components can prevent reconciliation. The report sorts `rate_leakage_dollars_proxy` descending and fills five rows from the connected periods. The bindings contain no sample ASINs or percentages. | Rank | ASIN | Current revenue | Prior revenue | Prior PPM | Current PPM | Delta | Leakage | | --- | --- | --- | --- | --- | --- | --- | --- | | 1 | `{{rank_1_asin}}` | `{{rank_1_revenue}}` | `{{rank_1_prior_revenue}}` | `{{rank_1_prior_ppm}}` | `{{rank_1_current_ppm}}` | `{{rank_1_delta_pp}}` | `{{rank_1_leakage}}` | | 2 | `{{rank_2_asin}}` | `{{rank_2_revenue}}` | `{{rank_2_prior_revenue}}` | `{{rank_2_prior_ppm}}` | `{{rank_2_current_ppm}}` | `{{rank_2_delta_pp}}` | `{{rank_2_leakage}}` | | 3 | `{{rank_3_asin}}` | `{{rank_3_revenue}}` | `{{rank_3_prior_revenue}}` | `{{rank_3_prior_ppm}}` | `{{rank_3_current_ppm}}` | `{{rank_3_delta_pp}}` | `{{rank_3_leakage}}` | | 4 | `{{rank_4_asin}}` | `{{rank_4_revenue}}` | `{{rank_4_prior_revenue}}` | `{{rank_4_prior_ppm}}` | `{{rank_4_current_ppm}}` | `{{rank_4_delta_pp}}` | `{{rank_4_leakage}}` | | 5 | `{{rank_5_asin}}` | `{{rank_5_revenue}}` | `{{rank_5_prior_revenue}}` | `{{rank_5_prior_ppm}}` | `{{rank_5_current_ppm}}` | `{{rank_5_delta_pp}}` | `{{rank_5_leakage}}` | I would not hand operations a rank-only table. The same rows continue into the causal review and ownership queue: | ASIN | Cost effect | Funding effect | Discount effect | Residual | Driver | | --- | --- | --- | --- | --- | --- | | `{{rank_1_asin}}` | `{{rank_1_pcogs_effect}}` | `{{rank_1_ccogs_effect}}` | `{{rank_1_discount_effect}}` | `{{rank_1_residual}}` | `{{rank_1_driver}}` | | `{{rank_2_asin}}` | `{{rank_2_pcogs_effect}}` | `{{rank_2_ccogs_effect}}` | `{{rank_2_discount_effect}}` | `{{rank_2_residual}}` | `{{rank_2_driver}}` | | `{{rank_3_asin}}` | `{{rank_3_pcogs_effect}}` | `{{rank_3_ccogs_effect}}` | `{{rank_3_discount_effect}}` | `{{rank_3_residual}}` | `{{rank_3_driver}}` | | `{{rank_4_asin}}` | `{{rank_4_pcogs_effect}}` | `{{rank_4_ccogs_effect}}` | `{{rank_4_discount_effect}}` | `{{rank_4_residual}}` | `{{rank_4_driver}}` | | `{{rank_5_asin}}` | `{{rank_5_pcogs_effect}}` | `{{rank_5_ccogs_effect}}` | `{{rank_5_discount_effect}}` | `{{rank_5_residual}}` | `{{rank_5_driver}}` | | ASIN | Investigation note | Owner | Evidence request | | --- | --- | --- | --- | | `{{rank_1_asin}}` | `{{rank_1_note}}` | `{{rank_1_owner}}` | `{{rank_1_evidence}}` | | `{{rank_2_asin}}` | `{{rank_2_note}}` | `{{rank_2_owner}}` | `{{rank_2_evidence}}` | | `{{rank_3_asin}}` | `{{rank_3_note}}` | `{{rank_3_owner}}` | `{{rank_3_evidence}}` | | `{{rank_4_asin}}` | `{{rank_4_note}}` | `{{rank_4_owner}}` | `{{rank_4_evidence}}` | | `{{rank_5_asin}}` | `{{rank_5_note}}` | `{{rank_5_owner}}` | `{{rank_5_evidence}}` | If components are unavailable, the rank still ships, the driver reads **Unclassified**, and the queue requests the missing evidence rather than fabricating a cause. > **In plain ChatGPT or Claude** > ChatGPT or Claude can suggest ranking logic after you paste data. You must still assemble comparable periods, normalize percentages, run the calculations, and carry the ranked result into a separate work queue. ## Manufacturing-view access and Warehouse Deals exclusions define the report boundary ARA access does not guarantee Net PPM access. All vendors have Sourcing views; manufacturers also receive a Manufacturing view for ASINs they manufacture. Amazon displays Traffic, Net PPM, and Forecasting only to manufacturers. If an eligible manufacturer cannot see Net PPM, contact retail partners or open a Contact Us case. Amazon's wording says Brand Analytics, including ARA, excludes Warehouse Deals because vendors do not collect the proceeds. Retail-partner tools may include those sales, so a vendor-facing and internal number can legitimately differ. | Boundary check | Report status | Next step | | --- | --- | --- | | View | Manufacturing required | Check entitlement | | Period | Closed and populated | Rerun after refresh | | Data as of | Status recorded | Avoid instant-data claim | | Warehouse Deals | Excluded consistently | Reconcile internal scope | | Metric labels | PCOGS differs from CCOGS | Re-map before ranking | | Derived fields | Explicitly labeled | Keep separate from Amazon | Amazon aims to update weekly reports within 72 hours, but reports can take up to a week after period close. The report records its period and as-of status instead of calling the data instantaneous. The provenance footer records exact evidence instead of counts: | Evidence type | Identifier | | --- | --- | | Source ref | `3dff9404cf730721` | | Source ref | `42c4d79b31a1eefd` | | Source ref | `285ce9ce068d666c` | | Content hash | `f334dd577810b7ca` | | Content hash | `647fba2b2a4cc729` | | Content hash | `927f70d802757798` | | Content hash | `2d8af27996d3f246` | | Content hash | `8e9bd73e5f629c0a` | | Content hash | `33460c203219fb4b` | | Content hash | `5dde3db908638908` | It also records Atlas collection `amazon_vendors`, corpus version `794a9c3de8380dfa`, connected periods, run timestamp, and the exact titles **Amazon Retail Analytics and Reports Overview**, **Amazon Retail Analytics Metric Glossary**, and **Vendor Reports and Analytics Overview**. Derived prioritization fields remain labeled as non-native Amazon metrics. > **In plain ChatGPT or Claude** > Generic chat cannot inspect view entitlements or reconcile a vendor export with an internal retail-partner number. You must supply both scopes, and any answer that omits the Warehouse Deals boundary can misdiagnose a legitimate difference. ## What happens next Turn the ranked report into an investigation queue, not an automatic commercial decision. Review the top ASINs and, where PCOGS, CCOGS, and sales-discount fields are exposed, confirm the largest component effect. When they are not, preserve the rank, mark the driver unclassified, and request the missing evidence. Then assign an owner. Run the workflow on closed, comparable periods and preserve the as-of status. If Warehouse Deals or an internal retail-partner scope explains a mismatch, flag the row for reconciliation instead of rewriting the vendor-facing metric. Amazon did not supply remediation thresholds or an automatic action policy in the retrieved material, so the operator reviews the evidence before changing terms or escalating. The [Amazon Agent Data layer](/features/amazon-agent-flow/) combines [Amazon Ads MCP](/features/amazon-ads-mcp/), [Selling Partner MCP](/features/amazon-selling-partner-mcp/), [Amazon Agent Atlas](/features/agent-atlas/), and [Skills](/features/skills/) so the report can be grounded, rerun, reviewed, and handed to an operator as one workflow. Revenue can stay stable while ASIN economics deteriorate; a sourced Net PPM decomposition turns that ambiguity into a ranked investigation queue. *Next, use the same evidence-first pattern when [disputing PO on-time accuracy chargebacks](/guides/vendor-po-chargeback-disputes/).* ### Brand Registry: Fix 'Trademark Already Enrolled' URL: https://www.kuudo.com/guides/seller-brand-registry-trademark-conflict/ The "trademark is already enrolled" error is a role-request problem, not an enrollment problem: someone already holds the Administrator role for your brand, and the fix is getting added as an additional user, not filing again from scratch. [Our agent](/features/ai-clients/) produced that answer, and the resolution plan behind it, by running a [Skill](/features/skills/) on the [Selling Partner MCP](/features/amazon-selling-partner-mcp/), grounded in the Brand Registry rules [Amazon Agent Atlas](/features/agent-atlas/) retrieves. That plan exists because of a message from our brand manager: *"We're trying to enroll our brand in Amazon Brand Registry and getting the 'trademark is already enrolled' error. What do we do?"* Nobody on the team had enrolled anything; the person who set the brand up left last year. So I asked the agent before anyone opened a support case blind. Why not just paste the error into ChatGPT or Claude? A plain chat hits three walls on any Amazon job. **No access to your data**: it can't see who holds the brand or where your application stands. **No way to take action**: it can't file anything on Amazon; you drive every screen. **Generic knowledge, not Amazon's**: it answers from public training data, not Amazon's current role rules. That's disconnected, generic, manual work that ships silent mistakes. The MCP reads the live state, the Skill runs the decision tree, and Atlas supplies the rule book. ## "Trademark is already enrolled" means an Administrator already exists, and the fix is becoming an additional user The first thing the Skill pulled was the rule the error actually points at. Atlas retrieves it from the **Brand Registry FAQ** playbook in the `amazon_sellers` corpus: if a trademark is already enrolled in Brand Registry, you contact the brand's Administrator and request to be added as an **additional user**. An Administrator always exists: the **Brand Registry Protection Roles** playbook says the user who enrolls a brand is automatically assigned the Administrator and Rights Owner roles, and only Administrators can assign roles to others. Three protection roles exist in total, Administrator, Rights Owner, and Registered Agent, and the last two are mutually exclusive. Amazon's own routing for this message is its Brand Registry Access: Troubleshooting Guide; the fix mechanics live in the FAQ and role playbooks the agent retrieved. The diagnosis: not a trademark dispute, not a second enrollment. A role request, aimed at whoever enrolled first. > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT can't see whether your trademark number is already enrolled in Brand Registry or under whose account; you only discover the conflict when the enrollment flow throws the error. The MCP-connected agent reads the live state before you burn an application. > - **Generic knowledge, not Amazon's.** Ask Claude about the error and it reaches for trademark-office advice: dispute the mark, call your attorney. The grounded answer is a role request to the existing Administrator, a rule that lives in Amazon's documentation, not public training data. > - **And your data is now exposed.** To get even the wrong answer, you pasted your trademark number and account details into a chat history you don't control. The MCP reads them over an authorized connection, and they stay inside your account. ## Request an invitation from a known Administrator, or continue to apply and share your contact information Branch one is the shortcut: if you know the identity of a current Administrator, reach out to them directly and request an invitation to the brand. On their side the flow is **Invite a user to your brand**, then **Send invitation**, and you have to accept the invitation before anything changes. We had no name to call, which is the branch the Brand Registry FAQ covers next: if you're unsure who to contact, or the current Administrator is inactive, you can **continue to apply** for Brand Registry with the same trademark. If you're an eligible user, the application gives you a step to **share your contact information** with the Administrator. Approval is discretionary by design: an active Administrator will use that information to add your Brand Registry account to the brand, *if they choose to do so*. The Brand Registry Protection Roles playbook shows where the request lands: in the Administrator's **User Permissions** tool under **Access requests**, where they approve or decline each request at their discretion. The Skill assembled all of it into the decision plan, every branch traced to a retrieved rule: ```yaml decision_plan: trigger: error_message: "Trademark is already enrolled" surface: "Brand Registry enrollment flow" facts_to_gather: - administrator_known: "Do you know the identity of a current Administrator?" - administrator_active: "Is that Administrator active and reachable?" - other_brand_enrolled: "Do you have another brand enrolled in Brand Registry?" branches: - id: administrator-known-active condition: "You know a current Administrator and they are active" action: "Reach out directly and request an invitation as an additional user" admin_side: "Invite a user to your brand > Send invitation; you accept it" outcome: "Added to the brand with the assigned protection role" - id: administrator-unknown condition: "Unsure who the Administrator is, or cannot reach them" action: "Continue to apply with the same trademark" during_flow: "Share your contact information (step shown to eligible users)" admin_side: "Request lands in User Permissions > Access requests" decision_rule: "Approved or declined at their discretion (if they choose to do so)" outcome_if_approved: "Your Brand Registry account is added to the brand" outcome_if_no_response: "Fall through to administrator-inactive" - id: administrator-inactive condition: "No active Administrator (inactive, or left the company)" paths: - id: appeal-form entry: "Same flow: a warning links to the Share Contact Information form" action: "Click 'use this form'; the bottom link opens Appeal Submission" gate: "Appeal Submission link is visible only to eligible users" outcome: "Success adds you with Administrator and Rights Owner roles" - id: brand-registry-support gate: "One other enrolled brand plus Brand Registry site access" action: "Open a case; select 'Update brand ownership' as the topic" outcome: "Request reviewed; response follows" while_waiting: review_sla: "Average 10 business days; identity checks can extend it" deadlines: - "Complete the application within three days or it shows Expired" - "Reply to the case within 10 days with the verification code and case ID" watch: "Brand applications page for status changes" statuses: [Approved, Rejected, Pending submission, Expired, Ineligible, Pending review, Withdrawn, Removed from Brand Registry] if_rejected: "Rejected can't be edited: click Copy, correct, resubmit" ``` > **In plain ChatGPT or Claude** > - **No way to take action.** ChatGPT can't submit the Brand Registry application or complete the share-contact step for you; the most it produces is a draft message. The Skill scripts the exact click path, continue to apply and then share contact information, so you execute it correctly the first time. > - **No access to your data.** Claude can't see the Administrator's **Access requests** queue, so it can't tell you whether your request is pending, approved, or declined. Silence from Amazon reads like rejection when it may just be an Administrator who hasn't opened **User Permissions** yet. ## An inactive Administrator opens two escalation paths: the "use this form" appeal and an "Update brand ownership" support case If the Administrator is inactive, the FAQ's instruction is literal: click **use this form** to submit your request form. The label undersells what's behind it. You re-enter the already-registered trademark number during the application, a warning appears offering a link to a form for sharing your contact information, and that link opens the **Share Contact Information** form. At the bottom of that form sits one more link, available only to eligible users, leading to an **Appeal Submission** form. Neither playbook defines who counts as eligible, so if you've hunted for the appeal form and never found it, that gate is why. When an appeal succeeds, you're added to the brand with the Administrator and Rights Owner roles, which makes you the brand's new front door. There's a parallel escalation path with its own gate. If you have at least one other brand already enrolled in Brand Registry and you can access the Brand Registry site, you can submit the request through Brand Registry Support and select **Update brand ownership** as the topic. Amazon asks that you identify the nature of the error before contacting support, and that's exactly the triage the plan encodes: it checks the gates and routes you to the path your account qualifies for, instead of letting you file a case that bounces. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** Neither ChatGPT nor Claude knows the **use this form** fallback exists, that it hides at the bottom of the **Share Contact Information** form, or that the **Appeal Submission** link is eligibility-gated. You get routed to generic Seller Support and never see the appeal path. Atlas carries the exact rule. > - **No access to your data.** The support path is gated on having at least one other brand already enrolled under your account. A chat can't read your Brand Registry account, so it can't tell you which of the two escalation paths you qualify for. One MCP read settles it. ## Once you reapply, the clock is Amazon's: 10 business days of review, a 3-day completion deadline, a 10-day reply window Reapplying starts a review that takes an average of **10 business days**, and Amazon may need additional information to verify your identity, which can extend the review period. Two more deadlines ride along, both pulled from the **Brand Registry Application Process** playbook and both easy to miss. An application that isn't completed within three days flips to **Expired**. And when Amazon sends a verification code, you reply to the case within 10 days with the code and the case ID. Those are two different tens: ten business days is how long Amazon takes on average; ten days is how long you get to reply. Every application surfaces on the **Brand applications** page with one of eight statuses: **Approved**, **Rejected**, **Pending submission**, **Expired**, **Ineligible**, **Pending review**, **Withdrawn**, or **Removed from Brand Registry**. A rejected application can't be edited. You locate it on the **Brand applications** page, click **Copy**, correct the details, and resubmit. Before that resubmission, the Skill runs the decline-reason pre-checks from the **Manage Brand Registry Application Issues** playbook: expired trademarks aren't eligible, supplemental trademarks aren't accepted (the Principal Register is required), and Amazon currently accepts only text-based marks or image-based marks with words, letters, or numbers. > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT can't check the **Brand applications** page, so it can't tell **Pending review** from **Expired**, and it can't warn you that an incomplete application dies after three days. The MCP-connected agent watches the page for you. > - **Generic knowledge, not Amazon's.** Claude doesn't know the verification-code reply window is 10 days against the case ID. Miss it and the enrollment silently stalls, with nobody telling you why. ## What happens next The plan isn't a document the agent hands over and forgets; it's a watch list. The agent monitors the **Brand applications** page through the Selling Partner MCP and reports status changes instead of letting the team infer them from silence. It flags the three-day completion deadline the moment an application sits in **Pending submission**, and it counts down the 10-day verification-code window against the case ID so the reply goes out with days to spare. If the outreach branch stalls with no Administrator response, the plan falls through to the appeal branch instead of waiting for someone to remember. The complete workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): the Selling Partner MCP supplies the live Brand Registry and application state, [Amazon Ads MCP](/features/amazon-ads-mcp/) covers the advertising side of the same account when it's needed, and Atlas grounds every branch of the plan. Scheduled as a recurring Skill, the same triage re-runs until the application lands on **Approved**, and every Amazon-facing step, the outreach message, the appeal submission, waits for a person to say yes, the gate pattern from [human approval for agent activation](/guides/human-approval-for-amc-activation/). That's the whole pattern: read the live state first, walk Amazon's real decision tree, and put the deadlines on a clock the agent owns instead of a person's memory. *Next in the series: [letting the agent fix a failing listing without editing it blind](/guides/seller-listing-agentic-audit-to-patch/), the same read-first, approve-before-ship discipline pointed at your live catalog.* ### Dispute a PO On-Time Accuracy Chargeback URL: https://www.kuudo.com/guides/vendor-po-chargeback-disputes/ Dispute a PO on-time accuracy chargeback with evidence that directly contradicts Amazon's recorded data, and file it through Operational Performance within 30 days of the notification. The strongest submission is not a long explanation. It names the wrong field, supplies the matching PO or carrier record, and asks Amazon to reverse the specific chargeback. | Situation | Evidence | Route | Deadline | | --- | --- | --- | --- | | Wrong CRDD or PRO | Appointment or PRO record | Dispute by data | 30 days | | External event | Event evidence | External exception | 30 days | | Duplicate amount | Chargeback IDs | Raise dispute | 30 days | | First refusal | New contrary evidence | Second dispute | 30 days | That is the answer to the message that landed in our queue: *"Vendor Central just hit us with a PO on-time accuracy chargeback we believe is wrong. How do we dispute it before the 30-day window closes?"* I gave the chargeback record and PO context to our agent through the [Selling Partner MCP](/features/amazon-selling-partner-mcp/), with [Amazon Agent Atlas](/features/agent-atlas/) grounding the dispute rules. A plain [ChatGPT or Claude chat](/features/ai-clients/) hits three walls. It has **no access to your data**, so it cannot compare the chargeback with the PO, appointment, or dispute history. It has **no way to take action**, so a person still has to find the record and submit the response. It has **generic knowledge, not Amazon's**, so it can confuse this Vendor Central operational chargeback with a consumer payment dispute. The result is disconnected, generic, manual work that ships silent mistakes. ## The first dispute is a 30-day evidence deadline, not a support case Amazon's **How to Dispute a Chargeback in Vendor Operational Performance** says the initial dispute is due within 30 days of the notification date. If Amazon rejects it, the second dispute is due within 30 days of the first refusal notification. Those are separate clocks, so the agent records both dates instead of treating the first deadline as the whole lifecycle. Start in **Reports > Operational Performance**, open the full chargeback list, locate the chargeback ID, and confirm that **Dispute this chargeback** is available. The same help content limits a chargeback to two disputes. After two rejections, it is no longer eligible, and a Contact Us case cannot substitute for those two dashboard submissions. The practical rule is simple: preserve the first attempt. Submit the cleanest contrary record you have, keep the dispute ID and attachments together, and reserve the second attempt for new evidence or a precise correction to Amazon's refusal reason. > **In plain ChatGPT or Claude** > - **No access to your data.** Chat cannot see whether the button is available, whether the charge is pending, or whether a prior dispute already used one attempt. > - **Generic knowledge, not Amazon's.** A generic answer may tell you to open support immediately, even though Amazon's policy requires two dashboard disputes first. > - **No way to take action.** Plain chat cannot create the deadline, attach the evidence, or submit through Operational Performance. ## The evidence must contradict the exact PO on-time data point Amazon's **Vendor Central Chargebacks Support and Policies** says PO on-time accuracy covers confirmed products that miss the PO window, including items placed on backorder. The indexed policy measures the prepaid case against the carrier requested delivery date (CRDD). A statement that the shipment was "on time" is weak; an appointment record showing the CRDD inside the delivery window directly contests Amazon's recorded value. Smart Aggregation gives the agent four routes, and choosing the wrong one can end the review before the evidence is considered. | Problem | Correct route | Core input | | --- | --- | --- | | Wrong Amazon field | Dispute by data | PRO or contrary value | | Severe external event | External exception | Event evidence | | Other non-data concern | Non-data problem | Issue explanation | | Not in Smart Aggregation | Legacy dispute | Chargeback record | The **Vendor Central Chargebacks - Smart Aggregation Dashboard** says Dispute by data can validate a core attribute such as a PRO and return a near-real-time indication of whether the evidence is sufficient. External-events exceptions are for circumstances such as severe weather; an unrelated accuracy complaint submitted there is automatically denied. Smart Aggregation is also limited to supported vendors and chargeback types, so the agent falls back to the legacy dashboard when the record is not present. > **In plain ChatGPT or Claude** > - **No access to your data.** Chat cannot compare Amazon's CRDD or PRO with the appointment record in your account. > - **Generic knowledge, not Amazon's.** Claude may recommend a persuasive narrative when the workflow expects one contrary data point. > - **No way to take action.** Chat cannot choose the live dispute route or verify that Smart Aggregation is available for the record. ## A useful dispute letter names one error and one contrary record The agent produced the following dispute letter after matching the chargeback ID, PO, defect field, and attachment names. Keep the merge fields intact until the corresponding record has been verified. Do not submit a field whose evidence you cannot attach. ```text Subject: PO on-time accuracy dispute for chargeback {{CHARGEBACK_ID}} We dispute PO on-time accuracy chargeback {{CHARGEBACK_ID}} for PO {{PO_NUMBER}}, notified on {{NOTIFICATION_DATE}}, in the amount of {{DISPUTED_AMOUNT}}. Amazon's chargeback record shows: - Defect type: {{DEFECT_TYPE}} - Recorded value: {{AMAZON_RECORDED_VALUE}} Our source record shows: - Correct value: {{VENDOR_SOURCE_VALUE}} - Source: {{SOURCE_SYSTEM_OR_DOCUMENT}} - Record date: {{SOURCE_RECORD_DATE}} The attached {{ATTACHMENT_NAME}} ties the PO and shipment to the correct {{CONTESTED_FIELD}}. It contradicts the value shown in the chargeback record. Please review the attached evidence and reverse chargeback {{CHARGEBACK_ID}}. If another field is controlling the decision, please name that field and its recorded value in the resolution. ``` For a duplicate, replace the source-record paragraph with both chargeback IDs and state which amount is duplicated. Amazon's Smart Aggregation guidance explicitly says to raise a dispute when duplicate chargebacks appear so the duplicate can be reversed. For a second dispute, lead with the first dispute ID and Amazon's refusal reason, then identify the new evidence that answers that reason. The letter stays short because the evidence carries the claim. Every sentence either identifies the disputed record, links the contrary evidence to it, or requests a correction. > **In plain ChatGPT or Claude** > - **No access to your data.** Chat can fill the template only with values a person pastes into the conversation. > - **Generic knowledge, not Amazon's.** A generic letter often argues fairness without naming the controlling field or dashboard route. > - **No way to take action.** Plain chat cannot attach the source record, preserve the dispute ID, or route a refusal into a second review. ## Smart Aggregation separates previews, confirmed charges, and reversals The **Vendor Central Chargebacks - Smart Aggregation Dashboard** surfaces unconfirmed chargebacks in the **Processing** tab every seven days. Those rows are projections, not invoices. Once confirmed, a chargeback moves to **Confirmed**. Starting April 30, 2024, Amazon's indexed guidance gives 30 days' notice before invoicing PO on-time accuracy chargebacks. That preview creates useful working time. The agent can open an evidence task while the item is still processing, pull the PO and carrier references, and flag a likely duplicate before the confirmed amount reaches the dispute queue. Smart Aggregation groups chargebacks at the most granular available attribute, shows the final confirmed amount, and removes duplicates from that view. If a duplicate still appears, the guidance says to dispute it. The status is part of the workflow. **Under review** means wait for the dispute team. **Reversed** means the payment returns in the next payment cycle. **Waived** means Amazon did not charge it. **Charged** means the amount was enforced and remains eligible for the dispute process if the button is available. > **In plain ChatGPT or Claude** > - **No access to your data.** Chat cannot distinguish a Processing preview from a confirmed or already reversed charge in the account. > - **Generic knowledge, not Amazon's.** An ungrounded answer can treat every row as money already deducted and start the dispute too late. > - **No way to take action.** Plain chat cannot monitor the seven-day preview cycle or reconcile a reversal with the next payment cycle. ## What happens next Turn the dispute into a reviewed recurring [Skill](/features/skills/), not an auto-submit rule. On each seven-day Processing refresh, the Skill identifies new PO on-time records, collects the controlling PO and carrier fields through the Selling Partner MCP, checks the deadline and prior-attempt count, then prepares the letter and attachments for human approval. The complete workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): the Selling Partner MCP supplies live PO and catalog context, [Amazon Ads MCP](/features/amazon-ads-mcp/) supplies the advertising side of the same business when needed, Atlas grounds the chargeback rules, and Skills preserve the evidence and approval trail. The final submission remains a deliberate operator action. The letter is the last step; the winning work is matching one chargeback data point to one contrary record before the clock expires. *Next, see why [MCP workflows need run logs](/guides/why-mcp-needs-run-logs/) when a reversal, refusal, or second dispute depends on what the agent did the first time.* ### Measure Off-Amazon Conversions in AMC URL: https://www.kuudo.com/guides/amc-off-amazon-conversion-events-manager/ Yes, [Amazon Marketing Cloud](/features/amc/) (AMC) can measure DTC web, app, store, and offline conversions once Events Manager receives them through Amazon Ad Tag (AAT), Conversions API (CAPI), or a Mobile Measurement Partner (MMP), the event is defined in the Amazon demand-side platform (DSP), and it is associated with a DSP order. The practical difference from Amazon conversions is the setup and taxonomy: off-Amazon subtypes arrive as numeric codes, purchase sales and non-purchase value mean different things, and the complete history starts on October 20, 2023. I handed the question to our agent through the [Amazon Ads MCP](/features/amazon-ads-mcp/), grounded by [Amazon Agent Atlas](/features/agent-atlas/), and asked it to prove each gate before running AMC SQL. | Question | Answer | | --- | --- | | Can AMC read DTC events? | Yes, through Events Manager | | Required ingestion | AAT, CAPI, or MMP | | Required DSP setup | Define event; link DSP order | | Purchase revenue | `off_amazon_product_sales` | | Non-purchase value | `off_amazon_conversion_value` | | Total product sales | `combined_sales` | | Complete history | `10/20/2023` onward | That answers the Slack question: *"We're running DSP ads to our DTC site. Can we measure those conversions inside AMC the same way we measure Amazon conversions?"* A plain [ChatGPT or Claude chat](/features/ai-clients/) hits three walls. It has **no access to your data**, so it cannot inspect the advertiser's Events Manager or AMC instance. It has **no way to take action**, so a human must copy, validate, and run its SQL. It has **generic knowledge, not Amazon's**, so it can miss the DSP-order gate, numeric subtype map, or coverage date. That becomes disconnected, generic, manual work that ships silent mistakes. The MCP supplies account access, Atlas supplies Amazon's current rules, and [Skills](/features/skills/) make the checks repeatable. ## Events Manager data reaches AMC only after the event is linked to a DSP order Sending an event to Amazon DSP is necessary but not sufficient. The **Introduction to Events Manager** instructional query names three prerequisites: set up AAT, CAPI, or MMP; define the event in Amazon DSP; and associate that event with an Amazon DSP order. If the order association is missing, the data does not flow into AMC. The empty result can look like zero customer activity even though the failure is configuration. The agent therefore runs a preflight before SQL. It checks the ingestion source, event definition, order association, AMC instance, and requested start date, then returns a pass or a named setup failure. That sequence also keeps the claim precise: Events Manager covers off-Amazon web, offline, and app events used for attribution, reporting, optimization, and targeting, but the event must pass the DSP setup gate first. All Events Manager signals are available in AMC whether ad-exposed or not, and the playbook says the paid `conversions_all` subscription is not required to query non-ad-exposed Events Manager signals. That makes non-ad-exposed analysis possible without making it causal proof. It is a comparison and audience-discovery input, not evidence that advertising created an outcome in a user who was never exposed. > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT cannot see whether the event definition is actually linked to the order. You would have to inspect DSP yourself and paste the result back into chat. > - **Generic knowledge, not Amazon's.** Claude can write plausible AMC SQL while omitting the order-association gate. The query then returns no rows, and the setup failure is mistaken for zero conversions. > - **No way to take action.** Plain chat cannot run the preflight or execute the AMC workflow. The Amazon Ads MCP can perform those account-bound checks through an authorized connection. ## Purchase sales and non-purchase conversion value are different measurements `off_amazon_product_sales` is monetary sales from off-Amazon purchases. `off_amazon_conversion_value` is an advertiser-defined, unitless value for non-purchase events such as a page view, app install, lead, or form submission. Do not add the second field to revenue or use it in return on ad spend (ROAS) unless the advertiser has explicitly documented a monetary scoring convention outside the schema. Events Manager also represents off-Amazon `conversion_event_subtype` values as numeric codes. The retrieved mapping is: | Event | Code | Monetary | | --- | ---: | --- | | Subscribe | `5` | No | | Application | `7` | No | | Sign-up | `21` | No | | App first start | `37` | No | | Add to cart | `53` | No | | Off-Amazon purchase | `54` | Yes | | Other | `133` | No | | Page view | `134` | No | | Search | `135` | No | | Contact | `136` | No | | Checkout | `140` | No | | Lead | `141` | No | The event formerly labeled **Product purchased** is now **Off-Amazon purchase**. The Skill keeps the mapping versioned and leaves an unknown code visible instead of coercing it to a familiar label. That is safer than silently converting an unrecognized future subtype into revenue. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** ChatGPT may compare the subtype to `purchase` or `add_to_cart`, but Events Manager sends the numeric codes `54` and `53` for those off-Amazon events. > - **Generic knowledge, not Amazon's.** Claude may call every configured value revenue or reuse the old Product purchased label. That inflates ROAS and hides a renamed event. > - **No access to your data.** Plain chat cannot see the advertiser-defined event names or determine whether an unknown subtype has entered the instance. The agent checks the returned taxonomy before labeling the output. ## The canonical Total Impact query joins campaign delivery to conversion outcomes Amazon's canonical **Total Impact Analysis** query from **Introduction to Events Manager** joins campaign cost, impressions, and unique reach from `dsp_impressions` to Amazon and off-Amazon outcomes from `amazon_attributed_events_by_traffic_time`. It keeps purchase sales, non-purchase value, combined sales, and conversion counts separate, then calculates Amazon and off-Amazon ROAS from the corresponding monetary sales fields. Set the workflow's date range in the AMC query editor to October 20, 2023 or later before running it. ```sql -- Instructional Query: How to query Events Manager Signals - Total Impact Analysis -- -- AD PRODUCTS: Amazon DSP /* ------- Customization Instructions ------- 1) Set the "Date range" in the Query Editor to define the time range. 1a) It is recommended to query events after 10/20/2023, as events before this date may be missing dimensions and metrics. */ -- Gather campaign cost and impression data WITH traffic AS ( SELECT campaign_id_string, campaign, SUM(impressions) AS impressions, SUM(total_cost / 100000) AS total_cost, COUNT(DISTINCT user_id) AS unique_reach FROM dsp_impressions WHERE user_id IS NOT NULL GROUP BY 1, 2 ), -- Gather Amazon and off-Amazon (Events Manager events) conversion data conversions AS ( SELECT campaign_id_string, conversion_event_source_name, conversion_event_name, conversion_event_category, CASE conversion_event_subtype WHEN 53 THEN 'Add to shopping cart' WHEN 7 THEN 'Application' WHEN 140 THEN 'Checkout' WHEN 136 THEN 'Contact' WHEN 141 THEN 'Lead' WHEN 54 THEN 'Off-Amazon purchase' WHEN 133 THEN 'Other' WHEN 134 THEN 'Page View' WHEN 135 THEN 'Search' WHEN 21 THEN 'Sign-up' WHEN 5 THEN 'Subscribe' ELSE conversion_event_subtype END amazon_conversion_event, SUM(off_amazon_conversion_value) AS off_amazon_conversion_value, SUM(off_amazon_product_sales) AS off_amazon_product_sales, SUM(conversions) AS conversions, SUM(total_product_sales) AS total_product_sales, SUM(total_purchases) AS total_purchases, SUM(combined_sales) AS combined_sales FROM amazon_attributed_events_by_traffic_time GROUP BY 1, 2, 3, 4, 5 ) -- Join cost and impressions with conversions SELECT t.campaign, c.conversion_event_category, c.conversion_event_source_name, c.conversion_event_name, c.amazon_conversion_event, SUM(t.impressions) AS impressions, SUM(t.total_cost) AS total_cost, SUM(t.unique_reach) AS unique_reach, SUM(COALESCE(c.off_amazon_conversion_value, 0)) AS off_amazon_conversion_value, SUM(COALESCE(c.off_amazon_product_sales, 0)) AS off_amazon_product_sales, SUM(COALESCE(c.conversions, 0)) AS conversions, SUM(COALESCE(c.total_product_sales, 0)) AS total_product_sales, SUM(COALESCE(c.total_purchases, 0)) AS total_purchases, SUM(COALESCE(c.combined_sales, 0)) AS combined_sales, CASE WHEN SUM(t.total_cost) > 0 THEN SUM(COALESCE(c.total_product_sales, 0)) / SUM(t.total_cost) ELSE 0 END AS amazon_roas, CASE WHEN SUM(t.total_cost) > 0 THEN SUM(COALESCE(c.off_amazon_product_sales, 0)) / SUM(t.total_cost) ELSE 0 END AS off_amazon_roas FROM traffic t LEFT JOIN conversions c ON t.campaign_id_string = c.campaign_id_string GROUP BY 1, 2, 3, 4, 5 ``` The query stays faithful to the retrieved instructional query, including Amazon's `total_cost / 100000` normalization and campaign-ID join. Inspect the returned source names and event definitions before operationalizing it; unknown subtype codes stay visible through the `ELSE` branch instead of being silently relabeled. `combined_sales` is Amazon `total_product_sales` plus `off_amazon_product_sales`; it does not include the unitless value assigned to non-purchase conversions. The query reports Amazon and off-Amazon ROAS separately, so leads and page views never enter either monetary numerator. A combined-sales return can be derived downstream only after the output grain and cost allocation have been reviewed. > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT cannot discover the source names and custom event names in your AMC instance. You would have to run the query, export the result, and paste it back. > - **Generic knowledge, not Amazon's.** Claude may calculate total impact from Amazon sales alone or add `off_amazon_conversion_value` to the numerator. Both change what ROAS means. > - **No way to take action.** Plain chat cannot execute or schedule the AMC workflow. The Amazon Ads MCP runs the canonical query, while the Skill validates returned codes before downstream calculation. ## Events Manager history is complete only from October 20, 2023 onward Treat October 20, 2023 as the completeness boundary for the named Events Manager dimensions and metrics in `amazon_attributed_events_by_*` and `conversions*` tables. Earlier periods can be missing those fields. A range before the boundary can also omit 30-day ad-unexposed events from `conversions` and `conversions_with_relevance`, so a lower historical count is not safely interpreted as lower customer activity. The **Off-Amazon Conversions Playbook** carries the result beyond reporting into campaign measurement, segmentation, and separately reviewed audience creation. Examples include users who added to cart off Amazon but did not purchase, converters who were not ad-exposed, and non-ad-exposed purchasers of product A who may be candidates for product B. Those are useful hypotheses. They do not prove incrementality, and measurement SQL does not activate an audience by itself. AMC only returns aggregated, pseudonymized outputs that meet its aggregation thresholds. The agent keeps the output at campaign and event grain, avoids `SELECT *`, rejects unsafe start dates, and reports suppressed or unknown results instead of turning them into zeros. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** ChatGPT may query the advertiser's full history and interpret missing pre-boundary data as zero. The agent applies the `10/20/2023` guard before execution. > - **No access to your data.** Claude cannot see whether sparse event groups were suppressed by AMC thresholds or whether the requested window crosses the completeness boundary. > - **No way to take action.** Plain chat cannot schedule a corrected run or route a reviewed segment into a separate audience workflow. The Skill can stop the run, explain the guard, and continue only with an approved window. ## What happens next After the preflight and subtype checks pass, schedule the total-impact analysis as a recurring Skill. Keep Amazon product sales, DTC purchase sales, and non-purchase conversion value in separate output columns; use `combined_sales` for the Amazon-plus-DTC product-sales view; and review any unknown subtype before the run reaches a dashboard or optimization rule. The complete workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): the [Amazon Ads MCP](/features/amazon-ads-mcp/) supplies live AMC access, the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) adds catalog or retail context when the decision needs it, [Skills](/features/skills/) make the checks recurring, and Amazon Agent Atlas grounds the taxonomy, date rule, and setup gates. If a segment is worth activating, hand it to a separate reviewed audience workflow rather than making activation an invisible side effect of measurement. Events Manager turns DTC outcomes into dependable AMC measurement only when ingestion, DSP association, event taxonomy, and revenue semantics are all correct. *Next, place those captured outcomes inside [the full AMC path across DSP and sponsored ads](/guides/amc-path-to-conversion-sankey/).* ### Rebuild Your Listing Images From Your Own Photos URL: https://www.kuudo.com/guides/seller-listing-image-regeneration-seeded/ Rebuilding a thin listing gallery is one conversation: the [Amazon Agent Iris](/features/amazon-agent-iris/) Skill seeds new images from your own product photos, fills factual details from the listing's own catalog data, grades every image against Amazon's rules through [Amazon Agent Atlas](/features/agent-atlas/), and waits for you to approve before it publishes a single one through the [Selling Partner MCP](/features/amazon-selling-partner-mcp/). One photo in, a full compliant set out, nothing live until you say yes. That sequence exists because of a Slack message I get some version of every month: *"Can the agent use our existing product photos as seeds to make better listing images that still pass Amazon's image rules, and let me approve before anything publishes?"* The pain underneath is the long tail. Most catalogs stay underbuilt because fixing every laggard meant a photographer, a studio, a designer, and a round of manual uploads, and that was never worth it for a SKU doing twelve units a month. Good imagery used to mean picking two of fast, cheap, and safe. So I handed a thin water-bottle listing to [our agent](/features/ai-clients/) with one rule: seed from our real photos, check before you publish, and stop at my approval. Why not just do this in ChatGPT or Claude? A generic chat hits the same three walls on any Amazon job. It has **no access to your data**, so it cannot read your live listing or your existing photos and works only from what you paste in. It has **no way to take action**, so it cannot check an image against Amazon's policy, publish it, or confirm it landed; the most it can do is hand you a file to upload by hand in Seller Central, where images can take up to 24 hours to appear and uploading does not guarantee display. And it runs on **generic knowledge, not Amazon's**, public training data rather than Amazon's current, in-depth image rules (white background, the zoom threshold, per-category main-image rules, suppression triggers). What you get is disconnected, generic, manual work that ships silent mistakes, and a non-compliant image can suppress the listing from search until you fix it. Each section below clears one of those walls with the Selling Partner MCP (your data, plus the tools to act and publish), Atlas (the private Amazon image rule book), and the Amazon Agent Iris Skill (the seed, check, approve, publish loop). ## Seeding from your own product photos turns a photographer-studio-designer-upload chain into one conversation The benefit first: you get studio-quality images without a studio, and the time and cost of that whole chain collapse into a single run. The Amazon Agent Iris Skill on the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) reads the listing and its existing images, then generates new images seeded from the seller's own product photos, so the real product identity, logos, and printed text stay intact rather than becoming generic stock. It fills factual details, like size-guide measurements, from the listing's own catalog data, so the specs are exact and not invented. The whole loop runs in one conversation with no manual Seller Central uploads. Here is what it looked like. The water-bottle listing started with one image and ended with four candidates in a single run: a sharpened white-background main shot, a true lifestyle scene of the bottle in use, a precise size guide whose measurements came straight from the listing's own data, and a detail shot the validator bounced for falling under the zoom threshold. That gate is the point, and the surviving set still cleared the four-image target shape, which is not arbitrary. It follows the recommended set in Amazon's image guidance: one image of the product on a white background, one in an environment, and one with product information such as dimensions. The Skill seeded all of it from photos we already owned. > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT cannot see your listing or your existing photos, so it cannot seed from your real product. You would have to describe it or paste images, and it invents a generic-looking product that is not quite yours. The Skill reads your real photos through the MCP and seeds from them. > - **No way to take action.** Even if Claude drafts an image, it cannot get it onto Amazon. You export it and upload it by hand in Seller Central, where it can take up to 24 hours to appear and may not display at all. The Skill publishes through the MCP and confirms it. > - **And your data is now exposed.** To get this far you pasted product photos and account context into a chat history you do not control. The Skill never copies your data into a prompt; the MCP reads it over an authorized connection and it stays in your account. ## When cost-per-image and effort-per-listing crater, the math flips: every listing gets brought up to standard, not just the heroes The benefit here is catalog-wide quality that was never economically possible before. Because the loop is a reusable [Skill](/features/skills/), the same seed, check, approve, publish run scales across the catalog. The long tail of thin and single-image listings was never worth a studio shoot, so it stayed underbuilt and under-converting. When the per-listing cost collapses, the recovered conversion from that long tail becomes reachable, and the recommended set (white-background main, an environment image, a product-information image, ideally six or more images per the **Product Image Requirements for Amazon Listings** guidance) is now within reach for a SKU doing twelve units a month, not just the flagship. The standard each listing is brought up to is Amazon's, not a house style. I run it as a recurring Skill across the catalog, often kicked off when the [audit-to-patch workflow](/guides/seller-listing-agentic-audit-to-patch/) flags an image laggard, so a thin gallery gets re-merchandised the same week it is found instead of next quarter. > **In plain ChatGPT or Claude** > - **No way to take action.** A chat cannot run the same fix across 400 ASINs (Amazon Standard Identification Numbers). You would repeat the paste, export, upload dance by hand for each one, which is exactly why the long tail never gets fixed. The Skill re-runs the loop unattended up to the approval gate. > - **Generic knowledge, not Amazon's.** Ask a chat to batch-improve listings and it gives the same generic advice for every product type, missing that a Fashion main image follows different rules from a shoe or a kids' item. The Skill grades each against the per-category rule (next section). > - **No access to your data.** A chat cannot tell which of your listings are actually underbuilt, because it cannot see your catalog. The MCP reads which listings are thin and worth upgrading. ## Every generated image is graded against Amazon's image rules before it can publish, and a human approves the final set This is the part that makes the speed safe: nothing publishes that breaks Amazon's rules or that you did not approve. The Skill checks each generated image against Amazon's image policy before anything publishes, a policy validator that returns a per-image verdict, grounded by Atlas against the **Product Image Requirements for Amazon Listings**, **Suppressed Listings Management**, and the per-category style guides such as the **Fashion Category Style Guide** (the `listing_categories_style_guide` set). That verdict set is the audit report the Skill produces: ```json { "asin": "B0EXAMPLE34", "sku": "BOTTLE-32OZ", "seeded_from": "existing main product photo + 1 detail photo", "starting_images": 1, "proposed_images": [ { "slot": "main", "kind": "white-background product shot", "verdict": "pass", "checks": ["pure white background (255,255,255)", "product ~85% of frame", "no text/logos", ">1,000 px longest side"], "grounded_in": "Product Image Requirements for Amazon Listings" }, { "slot": "secondary-1", "kind": "lifestyle / environment scene", "verdict": "pass", "checks": ["represents real product", "no added accessories not included"], "grounded_in": "Product Image Requirements for Amazon Listings" }, { "slot": "secondary-2", "kind": "size guide (measurements from catalog data)", "verdict": "needs changes", "fix": "specs pulled from listing's own catalog data; confirm dimensions before approve", "grounded_in": "Product Image Requirements for Amazon Listings (product-information image)" }, { "slot": "secondary-3", "kind": "detail / texture shot", "verdict": "reject", "fix": "longest side under 1,000 px; regenerate at higher resolution for zoom", "grounded_in": "Product Image Requirements for Amazon Listings (1,000 pixels)" } ], "suppression_risk_if_published_uncorrected": true, "awaiting": "human approval before publish" } ``` Read the verdicts left to right. **Pass** means compliant and ready. **Needs changes** is a human judgment call, like confirming the size-guide dimensions the Skill pulled from the catalog. **Reject plus fix** is a hard rule failure with the exact remedy attached. The rules behind those verdicts are Amazon's, retrieved through Atlas, not paraphrased from training data. The main image must have a pure **white background** (RGB 255,255,255), the product must fill about 85 percent of the frame, and there can be no text, logos, or watermarks. Images over **1,000 pixels** on the longest side enable the zoom Amazon prioritizes, with all images between 500 and 10,000 pixels. The image must accurately represent the product's real scale, quantity, and color. And the reason the check runs before publish rather than after: a non-compliant image will suppress the listing from search until compliant images are provided, the rule grounded in **Suppressed Listings Management**. Which rule applies to the main image depends on the category, so the validator grades a Fashion item against the **Fashion Category Style Guide** and a different product type against its own guide. The agent never makes the judgment call of whether an image truly represents the product; a human signs off, and only then does the Skill publish through the MCP and verify ingestion. > **In plain ChatGPT or Claude** > - **No way to take action.** A chat cannot test an image against Amazon's validator, so nothing catches a bad image before it is live. You only learn it failed when the listing gets suppressed from search and stops converting. The Skill grades each image before publish and ships only what passed. > - **Generic knowledge, not Amazon's.** Claude does not know the 1,000-pixel zoom threshold, the pure-white-background rule, or that a category like Fashion has its own main-image rules, so if you upload its output by hand, Amazon can reject or suppress it. The agent is grounded in Amazon's current image rules through Atlas. > - **Generic knowledge, not Amazon's.** A chat will happily invent measurements for a size-guide image. The Skill pulls them from your listing's own catalog data, and a human approves that the image truly represents the product before it ships, the call a machine should not make alone. ## What happens next Once the verdicts are clean and the human approves the set, the Skill publishes the approved images through the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) and then confirms ingestion. It verifies the images actually went live rather than assuming success, the opposite of the manual path where images can take up to 24 hours and may never display. Anything that cannot clear forks off: an image marked reject goes back through the seed-and-check loop at higher resolution, and an underlying suppression that no image can fix is the audit-to-patch concern. I run the whole thing as a recurring [Skill](/features/skills/) across the catalog so newly thin or newly suppressed listings get re-merchandised, with the same approval gate in front of every run. Run this way, the loop is one lane of the [Amazon Agent Data layer](/features/amazon-agent-flow/): the same Amazon Agent Flow fabric that wires the Selling Partner MCP, the [Amazon Ads MCP](/features/amazon-ads-mcp/), and Atlas into automation your team approves rather than babysits. This is the image side of the [audit-to-patch workflow](/guides/seller-listing-agentic-audit-to-patch/), which forks an image-suppression finding straight into this loop. The pattern is the same one that makes any of this safe: seed from your own truth, check before publish, approve before live. That is not model cleverness. It is the product surface doing its job. *Next in the series: bringing a suppressed FBA (Fulfillment by Amazon) listing back into search when the problem is not the image but the inventory state behind it.* ### Amazon FBM Orders Reports: What to Request and Why URL: https://www.kuudo.com/guides/seller-fbm-orders-reports/ Use Seller Central FBM Order Reports for fulfillment data, and use the [Amazon Selling Partner API (SP-API) MCP](/features/amazon-selling-partner-mcp/) to request SP-API All Orders reports when the job is tracking, support, reconciliation, or a finance period cut. Those are different files with different risk profiles, even though operators often call both "FBM orders." | Operator need | Request | Why | | --- | --- | --- | | Fulfill seller-fulfilled packages | Seller Central `FBM Order Reports` | Includes buyer information needed to fulfill FBM orders. | | Catch changed orders since the last sync | `GET_FLAT_FILE_ALL_ORDERS_DATA_BY_LAST_UPDATE_GENERAL` | Returns all Merchant Fulfilled Network (MFN) and Fulfillment by Amazon (FBA) orders updated in the period. | | Cut orders by purchase period | `GET_FLAT_FILE_ALL_ORDERS_DATA_BY_ORDER_DATE_GENERAL` | Returns all MFN and FBA orders placed in the period. | | Backfill older placed orders | `GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE` | Retrieves archived orders by order date. | The practical question came from an ops lead: *"We need a daily FBM order file for the warehouse and a support file for changed orders. Can the agent just pull the FBM report through SP-API?"* The answer is yes for the support file, not by that name for the warehouse file. [Amazon Agent Atlas](/features/agent-atlas/) retrieved the Seller Central **FBM Order Reports** article and Amazon's **SP-API order report type values** reference, and the distinction matters: one is a fulfillment file with buyer data; the other is an order-tracking report family that Amazon explicitly says is not for driving seller fulfillment. A plain [ChatGPT or Claude client](/features/ai-clients/) hits the same three walls on this job. It has **no access to your data**, so it cannot see your seller account, marketplaces, or last successful report window. It has **no way to take action**, so it cannot call `createReport`, poll `getReport`, or retrieve the report document. And it runs on **generic knowledge, not Amazon's**, so it easily collapses Seller Central FBM reports, restricted fulfillment reports, and SP-API All Orders tracking reports into one imaginary endpoint. The MCP brings account access and report tools; Atlas brings the exact Amazon rule corpus; Skills make the request, polling, download, and archival loop repeatable. ## Start with the fulfillment question, not the API endpoint Amazon's Seller Central **FBM Order Reports** article says the FBM order report is a tab-delimited text file for seller-fulfilled products sold during a selected period. It includes the buyer information needed to fulfill orders, but not confidential billing or credit-card information. It can be generated manually for the past 1, 2, 7, 15, or 30 days, and it can be scheduled. Because Seller Central does not generate those reports beyond 30 days, the operational pattern is simple: archive the daily file if it is your warehouse record. The SP-API All Orders report family answers a different question. In Amazon's **order report type values** reference, Amazon describes the All Orders reports as order-tracking reports available in all regions and for all sellers. They return all orders regardless of fulfillment channel or shipment status, but they are intended for tracking, not fulfillment, because they do not include customer-identifying information and scheduling is not supported. For a warehouse, that distinction is not academic. A warehouse dispatch queue needs shipment-ready buyer data. A support or operations queue often needs "what changed since yesterday" and can safely operate from order ID, SKU, status, channel, quantities, city/state/postal/country, and prices. The agent should branch on that intent before it asks the SP-API MCP for anything. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** Ask for an "FBM orders report" and it may invent one endpoint or hand you the All Orders report for fulfillment. Atlas surfaces the Seller Central FBM report and the SP-API All Orders report family as separate sources, so the agent does not confuse dispatch data with tracking data. > - **No access to your data.** The chat cannot inspect your marketplaces, fulfillment mix, or last archive date. The Selling Partner MCP reads the seller context through an authorized connection before choosing the report. > - **No way to take action.** It cannot schedule or request anything. It can only tell an operator to click around, which is exactly where daily report archives get missed. ## Request all-orders by last update when operations need changed orders When support asks "what changed since the last sync," the MCP should request `GET_FLAT_FILE_ALL_ORDERS_DATA_BY_LAST_UPDATE_GENERAL`. Amazon's reference says this report contains all orders updated in the specified period, covers MFN and FBA, is available to sellers, and returns a tab-delimited flat file. It is a requested report, not a scheduled one, and the date range is limited to 30 days. For self-fulfilled pending orders, Amazon also notes that item price is not shown, so do not use this report as a pending-order revenue ledger. This is the right operational feed for support queues, warehouse exception review, cancellations, shipment-status changes, and downstream systems that reconcile on `last-updated-date`. It also avoids a common off-by-one mistake: if a customer changes or cancels an older order today, an order-date report for today's placed orders will miss it, but a last-updated report will catch it. ```json { "mcp": "amazon-spapi", "tool": "reports.createReport", "arguments": { "reportType": "GET_FLAT_FILE_ALL_ORDERS_DATA_BY_LAST_UPDATE_GENERAL", "marketplaceIds": ["ATVPDKIKX0DER"], "dataStartTime": "2026-06-21T00:00:00Z", "dataEndTime": "2026-06-22T00:00:00Z" } } ``` The agent should store the successful window boundary with the run log, then make the next request from the prior `dataEndTime`. That is a [Skill](/features/skills/) responsibility, not something an operator should remember in a prompt. > **In plain ChatGPT or Claude** > - **No access to your data.** A chat cannot know your last completed report window or whether yesterday's run failed halfway through download. The MCP-backed Skill can read the run log and request only the missing window. > - **Generic knowledge, not Amazon's.** It often chooses order date because that sounds natural. Amazon's reference says last update is the report type for orders updated in the period, which is the support and exception-management question. > - **No way to take action.** Even with the right report type, a chat cannot submit `createReport` or watch processing status. The agent can. ## Request all-orders by order date when finance needs a period cut When finance or planning asks "what orders were placed in this period," request `GET_FLAT_FILE_ALL_ORDERS_DATA_BY_ORDER_DATE_GENERAL`. The same SP-API order type values reference says this report contains all orders placed in the specified period, with MFN and FBA rows in a tab-delimited file. Use it for daily sales cuts, month-to-date order extracts, reconciliation against BI tables, and date-based audits. For FBM-only analysis, do not request a different report just because the business says "FBM." Request the All Orders period cut, then filter the rows where the fulfillment channel is merchant fulfilled. The report's value is that it holds both MFN and FBA orders, so the same extract can support FBM exception analysis and whole-account reporting. ```json { "mcp": "amazon-spapi", "tool": "reports.createReport", "arguments": { "reportType": "GET_FLAT_FILE_ALL_ORDERS_DATA_BY_ORDER_DATE_GENERAL", "marketplaceIds": ["ATVPDKIKX0DER"], "dataStartTime": "2026-06-01T00:00:00Z", "dataEndTime": "2026-06-22T00:00:00Z" } } ``` If the request is a historical backfill by order date, Amazon's archived order report reference identifies `GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE` as the archived-orders report type. Keep that as a deliberate backfill path, not the default daily workflow. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** It may tell you "order date" and "last update" are interchangeable. They are not. The report names encode different selection rules, so the wrong one silently drops the orders you meant to include. > - **No access to your data.** It cannot see whether the finance period crosses marketplaces, whether a run was already completed, or whether the extract should be filtered to MFN after download. > - **No way to take action.** It cannot request the period cut or retrieve the tab-delimited file. The SP-API MCP can submit the request and pass the result into the next workflow. ## Let the SP-API MCP handle polling, retrieval, and storage discipline Atlas also pulled Amazon's Reports API tutorials for requesting a report, verifying report processing, and retrieving a report document. The sequence is mechanical, which is exactly why it belongs in a Skill. 1. Call `createReport` with `reportType`, `marketplaceIds`, and optional `dataStartTime` / `dataEndTime`. 2. Poll `getReport` with the returned `reportId` until `processingStatus` is `DONE`, `CANCELLED`, or `FATAL`. 3. If `DONE` includes `reportDocumentId`, call `getReportDocument`. 4. Download the returned pre-signed `url` before it expires, applying `compressionAlgorithm` if present. 5. Keep encryption at rest; Amazon's retrieve tutorial warns against storing unencrypted report content on disk, even temporarily. ```json { "mcp": "amazon-spapi", "tool": "reports.getReport", "arguments": { "reportId": "amzn1.spapi-report.example" } } ``` ```json { "mcp": "amazon-spapi", "tool": "reports.getReportDocument", "arguments": { "reportDocumentId": "amzn1.spdoc.example" } } ``` The failure states matter. `CANCELLED` can mean Amazon found no eligible data. `FATAL` can still include a document that explains the failure. `IN_QUEUE` and `IN_PROGRESS` are not terminal, so the agent should keep polling instead of telling the operator the report is missing. > **In plain ChatGPT or Claude** > - **No way to take action.** A chat cannot poll `getReport`, retrieve a pre-signed URL, or download before expiry. It will leave the operator with a checklist. > - **Generic knowledge, not Amazon's.** It often misses the terminal states and treats any non-DONE status as an error. Amazon distinguishes queued, in-progress, cancelled, done, and fatal states. > - **No access to your data.** It cannot apply the seller's storage policy or write the artifact to the approved encrypted location. The MCP workflow can route the document through the account's governed path. ## What happens next In production, the [Amazon Ads MCP](/features/amazon-ads-mcp/), the [Selling Partner MCP](/features/amazon-selling-partner-mcp/), [Skills](/features/skills/), and the [Amazon Agent Data layer](/features/amazon-agent-flow/) sit behind one agent surface, so a support request can pull the right SP-API order report, archive it, and hand downstream teams the same audited artifact. The same pattern powers the approval loop in [Preview Listing Patches Before They Go Live](/guides/seller-listing-agentic-audit-to-patch/): retrieve the governed source, perform the narrow action, write the run log, and keep the operator out of manual repeat work. For this guide, the narrow action is report selection. A warehouse dispatch workflow needs the Seller Central FBM fulfillment file or a restricted fulfillment path. A support, finance, or reconciliation workflow should ask the SP-API MCP for the All Orders report type that matches the date logic. *Next in the series: using SP-API order status changes to decide when an agent should notify support, warehouse operations, or finance without turning every report row into an alert.* ### Find Your Optimal DSP Frequency Cap in AMC URL: https://www.kuudo.com/guides/amc-optimal-frequency-cap/ Your optimal Amazon demand-side platform (DSP) frequency cap is not the bucket with the highest purchase rate. That rate climbs forever (0.48% at one impression, 1.10% at two, 3.86% at three, 5.10% at four), so it always says never cap. The cap is the frequency bucket where cumulative return % stops outrunning cumulative cost %. The [Amazon Marketing Cloud](/features/amc/) (AMC) Optimal Frequency Analysis method finds it, the agent runs it on your `amazon_attributed_events_by_traffic_time` conversions through the [Amazon Ads MCP](/features/amazon-ads-mcp/), and hands you a single number to set in DSP, grounded by [Amazon Agent Atlas](/features/agent-atlas/). That sequence came out of one Slack question: *"What's our optimal DSP frequency cap, and at what impression count are we paying for ad fatigue instead of conversions?"* It is easy to ask and easy to answer wrong. I trusted the best-converting bucket until the cost column flipped it. So I handed it to [our agent](/features/ai-clients/) with one instruction: don't read the cap off the rate column, run the cumulative cost-and-return method and show me where it crosses. A plain ChatGPT or Claude chat hits the same three walls on this job. It has **no access to your data**, so it can't read your DSP impression logs or your attributed conversions, and has no per-user frequency distribution to bucket. It has **no way to take action**, so it can't run the AMC query and can't push a cap to your DSP line item or campaign; the most it does is hand you a number to type in by hand. And it runs on **generic knowledge, not Amazon's**, so it doesn't know the cumulative cost-and-return method or that AMC's aggregation thresholds quietly suppress your sparse high-frequency tail. The platform pieces get past each wall: the [Amazon Ads MCP](/features/amazon-ads-mcp/) is your impression-and-conversion data plus the query runner, Amazon Agent Atlas is the Optimal Frequency Analysis rule book, Skills are the recurring re-check, and the Amazon Agent Data layer unifies it all into one grounded surface. ## Optimal frequency analysis starts by bucketing every user by impression count, not by reading one average The raw shape every later step reads from is a per-bucket table, not a single average frequency. The Amazon Ads MCP runs the bucketing query and the agent grades the columns against the rules Atlas retrieves. Frequencies group into buckets `frequency_01` through `frequency_25+`, where `25+` means exposed 25 or more times. The output schema is the AMC convention verbatim: `frequency_bucket`, `users_in_bucket`, `impressions_in_bucket`, `purchases`, and purchase rate. Conversions attach through `amazon_attributed_events_by_traffic_time`, the corpus-backed source for attributed purchases and product sales. This step is the **"Measuring Optimal Impression Frequency for Amazon DSP Campaigns"** playbook joined to the bucketing schema, with the reach distribution from **"Calculating Reach and Impression Frequency in AMC."** The data pull below is an illustrative scaffold, not a query retrieved from Atlas. The corpus guarantees the output schema and the method, not these exact table and column names, so it carries the skip marker and ships unverified by design (the canonical runnable query is the linked Amazon instructional query). ```sql WITH impressions AS ( SELECT user_id, SUM(impressions) AS impressions, SUM(total_cost) AS cost FROM dsp_impressions_by_user_segments GROUP BY 1 ), conversions AS ( SELECT user_id, SUM(purchases) AS purchases, SUM(total_product_sales) AS product_sales FROM amazon_attributed_events_by_traffic_time GROUP BY 1 ), by_user AS ( SELECT i.user_id, i.impressions, i.cost, LEAST(i.impressions, 25) AS frequency, COALESCE(c.purchases, 0) AS purchases, COALESCE(c.product_sales, 0) AS product_sales FROM impressions i LEFT JOIN conversions c USING (user_id) ) SELECT CONCAT('frequency_', LPAD(CAST(frequency AS VARCHAR), 2, '0'), IF(frequency = 25, '+', '')) AS frequency_bucket, COUNT(user_id) AS users_in_bucket, SUM(impressions) AS impressions_in_bucket, SUM(cost) AS cost, SUM(purchases) AS purchases, SUM(product_sales) AS product_sales FROM by_user GROUP BY 1 ORDER BY 1 ``` > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT can't read your impression logs, so it can't build a single frequency bucket. You'd have to hand-export and paste a table, and your account data would land in a chat history you don't control. The Amazon Ads MCP reads it over an authorized connection and the data stays inside your account. > - **Generic knowledge, not Amazon's.** Ask Claude how to bucket and it invents a column. AMC's convention is `frequency_01` through `frequency_25+`, and conversions attach through `amazon_attributed_events_by_traffic_time`. Get the table or the bucket scheme wrong and the query returns nothing. The agent reads the real schema first. ## The highest purchase-rate bucket is the wrong cap, because it always tells you to never cap Purchase rate rises monotonically with frequency: 0.48% at one impression, 1.10% at two, 3.86% at three, 5.10% at four across the first four buckets. Cap at the highest-rate bucket and you would cap at the top, which is the same as never capping at all. Atlas surfaces the **"Measuring Optimal Impression Frequency for Amazon DSP Campaigns"** result table that shows the climb, and the playbook's own warning that optimal frequency on Amazon may not be optimal across all advertising channels. The agent flags the trap unprompted rather than chasing the best-looking number. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** Ask ChatGPT "which frequency converts best?" and it points at the top bucket, the trap. Rate never stops rising, so that answer is "never cap," which is how you keep paying for fatigue. The agent knows the optimum lives on the cost side, not the rate column. > - **No way to take action.** Even if you spotted the trap, Claude can't compute the cost-side correction. It has no cost-per-bucket and no way to run the cumulative math. The Amazon Ads MCP has both, run over your real campaign window. ## The cap is the last bucket where Percent Change is still above zero Set the cap at the last frequency bucket where Percent Change (cumulative return % minus cumulative cost %, differenced bucket-over-bucket) is still above zero. Past that bucket, each added impression costs more than it returns. This is the **"Optimal Frequency Analysis in Amazon Marketing Cloud"** method, and it is the analysis report the agent produces. Per bucket it computes cumulative cost, cumulative return, cumulative cost %, cumulative return %, Percent Difference (cumulative return % minus cumulative cost %), and Percent Change (this bucket's Percent Difference minus the prior bucket's). The cap is the last bucket where Percent Change is above zero. You can gloss it as the inflection point where the curve of added value goes flat, but the mechanical rule is the zero-crossing, not a fitted curve. The post-processing table is the artifact. Here is the playbook's worked example, with the cap read off where Percent Change first goes negative: | frequency_bucket | conversions | cumul. conversions | cost | cumul. cost | cumul. return % | cumul. cost % | Pct Difference | Pct Change | |---|---|---|---|---|---|---|---|---| | 1 | 9,203 | 9,203 | $7,801 | $7,801 | 19% | 9% | 9.90% | n/a | | 2 | 6,532 | 15,735 | $7,933 | $15,734 | 32% | 18% | 14.18% | 4.28% | | 3 | 5,024 | 20,759 | $7,492 | $23,226 | 43% | 27% | 15.87% | 1.69% | | 4 | 4,157 | 24,916 | $7,060 | $30,286 | 51% | 35% | 16.28% | 0.41% (last >0) | | 5 | 3,569 | 28,485 | $6,621 | $36,907 | 58% | 42% | 15.99% | -0.29% (crosses) | Bucket 5's -0.29% is the first negative, so the cap is frequency 4. The ROAS (return on ad spend) sanity check confirms it: at this cap cumulative ROAS is about $1.17, and a looser cap of 9 dropped cumulative ROAS to $0.95, where overall spend exceeded sales. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** ChatGPT doesn't know this method exists. No cumulative cost %, no Percent Change column, no zero-crossing rule. It guesses a round number like "cap at 3." The agent runs the exact AMC Optimal Frequency Analysis bookkeeping and the table is auditable. > - **No way to take action.** The whole method needs per-bucket cost and conversion volume run over your real campaign window. Claude can't query it and can't carry the cumulative sums across buckets. The Amazon Ads MCP runs it and the result is reproducible. ## Your high-frequency tail is too thin to trust Roughly 90% of users are exposed three times or fewer, so the high-frequency buckets thin out fast and fall below AMC's aggregation thresholds. Read the cap off where the data is dense, not off a noisy tail. This is where the **"Calculating Reach and Impression Frequency in AMC"** distribution and the prerequisites from **"Optimal Frequency Analysis in Amazon Marketing Cloud"** land. The prerequisites are an AMC instance, at least 7 days of backfilled data, and 4 or more active campaigns, plus the AMC concept of data aggregation thresholds. Atlas carries both, and the agent surfaces them unprompted along with the caveat that optimal frequency is not one size fits all: it depends on the goal (awareness versus conversion), campaign length, audience size, and whether the campaign is a new launch or steady state. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** ChatGPT will happily compute a cap off your `frequency_18` bucket as if it were solid, never warning that about 90% of users sit at three or fewer and the tail is statistically empty, or that AMC won't even return rows below its aggregation threshold. The agent knows the distribution and the threshold and reads the cap off dense buckets. > - **No access to your data.** Claude can't see that your campaign only ran 5 days or has 2 active campaigns, below the playbook's 7-day, 4-campaign floor, so it can't tell you the answer isn't ready yet. The Amazon Ads MCP knows your real backfill and campaign count. ## What happens next The artifact is a decision: one cap number. You set it in Amazon DSP at the line-item or campaign level, the lever the playbook names as the actionable output. Then schedule the analysis as a recurring [Skill](/features/skills/) so the cap re-checks itself as spend shifts and campaigns evolve, rather than going stale after one run. Amazon's point-and-click Optimal Frequency solution is a fine quick read, but the AMC SQL path wins on campaign-level control and custom KPIs (key performance indicators). The whole thing rides the [Amazon Agent Data layer / Agent Flow](/features/amazon-agent-flow/) that unifies the Amazon Ads MCP and the [Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/) under one grounded surface, so the conversions you join here come from the same place the rest of your Amazon work reads from. A frequency cap is one number, but it only means anything when it sits on the cost side of the math instead of the rate side. Set it there and you stop paying for impressions past the point where added cost outruns added return. *Next in the series: where that capped DSP impression actually sits in the full conversion path, mapped end to end in [the path-to-conversion Sankey](/guides/amc-path-to-conversion-sankey/).* ### Map AMC Paths Across DSP and Sponsored Ads URL: https://www.kuudo.com/guides/amc-path-to-conversion-sankey/ Ask the agent in [your AI client](/features/ai-clients/) to map the customer journey, and the [Amazon Ads MCP](/features/amazon-ads-mcp/) runs the path-to-conversion workflow live in your [Amazon Marketing Cloud](/features/amc/) (AMC) instance: it joins `dsp_impressions`, `sponsored_ads_traffic`, and `amazon_attributed_events_by_traffic_time` on `user_id`, groups campaigns the way the current "Path to Conversion by Campaign Groups" pattern prescribes, and returns a Sankey-ready source-to-destination dataset. [Amazon Agent Atlas](/features/agent-atlas/) keeps it honest by surfacing that pattern from the **Customer Journey Analytics Playbook** instead of letting the agent guess. The answer exists because our media lead asked in Slack: *"What's the actual journey our customers take across demand-side platform (DSP), Sponsored Products, Sponsored Brands, and Sponsored Display before they convert?"* Everyone had an opinion about which campaign deserved credit. Nobody had the path. A plain ChatGPT or Claude chat hits the same three walls here. **No access to your data**: the journey lives in pseudonymized, instance-scoped AMC tables. **No way to take action**: a chat cannot submit an AMC workflow or re-pull it when attribution closes. **Generic knowledge, not Amazon's**: it does not know which journey query is current. That adds up to disconnected, generic, manual work that ships silent mistakes. The MCP brings your data plus the tools to act, Atlas the private rule book, Skills the repeatable run. ## The whole journey lives in exactly three AMC tables, joined on user_id The Customer Journey Analytics Playbook's "Tables used" list has exactly three entries: `dsp_impressions`, `sponsored_ads_traffic`, and `amazon_attributed_events_by_traffic_time`. Not one table per ad product. `sponsored_ads_traffic` carries the traffic events, impressions and clicks, for Sponsored Products, Sponsored Brands, Sponsored Display, and Sponsored Television in one table; you split it by `ad_product_type` (`'sponsored_products'`, `'sponsored_brands'`, `'sponsored_display'`). The third table holds the conversion events: purchases, new_to_brand_purchases, detail page views. The join rule comes straight from Amazon's guidance: join on `user_id` when you are interested in understanding user behavior. Every branch of the query filters `user_id IS NOT NULL` so the paths stay user-level. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** Ask ChatGPT for the journey SQL and it invents per-product tables, an `sp_impressions` here, an `sb_traffic` there, that do not exist in AMC. All sponsored ads traffic lives in one table split by `ad_product_type`; the agent reads the real schema through the MCP before writing a line. > - **No access to your data.** Even with correct table names, the joined journey only exists inside your AMC instance after the query runs there. You cannot paste `user_id`-level impression rows into a chat, so the chat never sees a single path. > - **Generic knowledge fails again on the third table.** The classic miss is joining the two traffic tables and stopping. Without `amazon_attributed_events_by_traffic_time` there is no conversion endpoint, only exposure. Atlas surfaces the exact three-table list, so the query lands complete. ## Group your campaigns, or aggregation thresholds swallow most of the path as NULL rows The old "Path to Conversion by Campaign" instructional query (IQ) is retired. Amazon's notice reads: "As of August 31, 2022, an improved version of this IQ has been made available in AMC. We recommend advertisers to use the new version: Path to Conversion by Campaign Groups." The improvements are operator-facing: grouping reduces the likelihood of violating aggregation thresholds so "users will see a smaller number of NULL rows," campaign and Amazon Standard Identification Number (ASIN) filters exist, and Sponsored Display conversions are included. The grouping mechanism is a small `VALUES` mapping: list each campaign with its group, then `COALESCE` everything ungrouped into `'DSP-Others'`, `'SP-Others'`, `'SD-Others'`, or `'SB-Others'` so no row falls below the thresholds. (The playbook also ships a campaign-category variant that maps campaign names to funnel stages with `CASE ... SIMILAR TO`, but those categories depend on each advertiser's naming conventions.) Here is the workflow the agent submitted through the Amazon Ads MCP: ```sql -- Path to conversion across DSP + sponsored ads, Sankey-ready output -- Pattern: "Path to Conversion by Campaign Groups" IQ (supersedes the -- "Path to Conversion by Campaign" IQ as of 2022-08-31) WITH campaign_group (campaign, campaign_group) AS ( VALUES -- placeholder campaign names/IDs; ungrouped rows fall back to -- '-Others' so aggregation thresholds aren't violated ('111111111111111111', 'group 1'), ('222222222222222222', 'group 1'), ('SP_campaign', 'group 2'), ('SD_campaign', 'group 3'), ('SB_campaign', 'group 4') ), impressions AS ( SELECT COALESCE(g.campaign_group, 'DSP-Others') AS campaign_group, 'DSP' AS product_type, i.user_id, MIN(i.impression_dt) AS impression_dt_first, MAX(i.impression_dt) AS impression_dt_last, SUM(i.impressions) AS impressions, SUM(i.total_cost) AS total_cost FROM dsp_impressions i LEFT JOIN campaign_group g ON g.campaign = i.campaign WHERE i.user_id IS NOT NULL GROUP BY 1, 2, 3 UNION ALL SELECT COALESCE(g.campaign_group, 'SP-Others') AS campaign_group, 'SP' AS product_type, a.user_id, MIN(a.event_dt) AS impression_dt_first, MAX(a.event_dt) AS impression_dt_last, SUM(a.impressions) AS impressions, SUM(a.spend) AS total_cost FROM sponsored_ads_traffic a LEFT JOIN campaign_group g ON g.campaign = a.campaign WHERE a.user_id IS NOT NULL AND a.ad_product_type = 'sponsored_products' GROUP BY 1, 2, 3 UNION ALL SELECT COALESCE(g.campaign_group, 'SD-Others') AS campaign_group, 'SD' AS product_type, a.user_id, MIN(a.event_dt) AS impression_dt_first, MAX(a.event_dt) AS impression_dt_last, SUM(a.impressions) AS impressions, SUM(a.spend) AS total_cost FROM sponsored_ads_traffic a LEFT JOIN campaign_group g ON g.campaign = a.campaign WHERE a.user_id IS NOT NULL AND a.ad_product_type = 'sponsored_display' GROUP BY 1, 2, 3 UNION ALL SELECT COALESCE(g.campaign_group, 'SB-Others') AS campaign_group, 'SB' AS product_type, a.user_id, MIN(a.event_dt) AS impression_dt_first, MAX(a.event_dt) AS impression_dt_last, SUM(a.impressions) AS impressions, SUM(a.spend) AS total_cost FROM sponsored_ads_traffic a LEFT JOIN campaign_group g ON g.campaign = a.campaign WHERE a.user_id IS NOT NULL AND a.ad_product_type = 'sponsored_brands' GROUP BY 1, 2, 3 ), converted AS ( -- conversions attributed to in-window traffic; events can land up to -- 30 days after the window, so totals move until attribution closes SELECT user_id, SUM(conversions) AS conversions FROM amazon_attributed_events_by_traffic_time WHERE user_id IS NOT NULL GROUP BY 1 ), ranked AS ( SELECT user_id, campaign_group, ROW_NUMBER() OVER ( PARTITION BY user_id ORDER BY impression_dt_first ) AS path_rank FROM impressions ), steps AS ( -- explode the path into source -> destination pairs: QuickSight's -- Sankey visual needs one source and one destination dimension per row SELECT r1.user_id, r1.campaign_group AS path_step_source, r2.campaign_group AS path_step_destination FROM ranked r1 LEFT JOIN ranked r2 ON r2.user_id = r1.user_id AND r2.path_rank = r1.path_rank + 1 ) SELECT s.path_step_source, s.path_step_destination, COUNT(DISTINCT s.user_id) AS path_occurrences, SUM(c.conversions) AS conversions FROM steps s LEFT JOIN converted c ON c.user_id = s.user_id GROUP BY 1, 2 -- NO ORDER BY here: AMC rejects ORDER BY in the outer query of a -- workflow ("ORDER BY unexpected"). Sort downstream, post-export. ``` Swap the placeholder `VALUES` rows for your own campaign names or IDs and the rest runs as-is. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** A chat reproduces the deprecated by-campaign pattern from stale training data. Run campaign-level paths in an instance of any real size and the aggregation thresholds NULL the small rows, exactly what the 2022 notice says grouping fixes. > - **No way to take action.** The chat hands you SQL to carry by hand. The first hand-carried draft of this exact analysis died in AMC's parser with "ORDER BY unexpected" because it sorted in the outer query. The agent submits through the MCP, sees the parser's verdict immediately, and corrects the workflow; the version above sorts downstream, after export. ## Conversions keep landing for 30 days after your window, so day-zero numbers are not final `amazon_attributed_events_by_traffic_time` has a property that surprises people: the traffic events all sit inside your query window, but the attributed conversions "may have occurred up to 30 days after the time window." Amazon extends the conversion range automatically and says plainly that "the output of a workflow that uses this table may change over time." The lookback itself is fixed per campaign and cannot be changed in AMC: 14 days for Brands, 7 days for Sellers' Sponsored Products. I was skeptical when the agent flagged this, so we re-pulled the identical workflow later in the attribution window. The conversion column grew, and nothing was wrong; attribution was still filling in. Run the analysis the morning after your window closes and you under-count whatever is still inside that 14-day lookback, which is why the agent derives a safe re-pull date from the lookback rather than treating day-zero output as final. One eligibility wrinkle from the Custom Attribution Overview is worth knowing too: DSP conversions require a viewable impression and Sponsored Products require a click, so impression-only SP exposures never appear in the attributed datasets at all. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** ChatGPT treats your query window as the whole story. It will not warn you that the same by_traffic_time workflow returns different numbers tomorrow, or that a path analysis run too early under-counts conversions still in flight. > - **No way to take action.** A chat cannot wait out the attribution window and re-pull. You rerun by hand, if you remember to. The agent schedules the re-run for after attribution closes and compares the two outputs side by side. ## Sankey-ready means source-to-destination rows, and the agent returns the dataset already in that shape Amazon's path output arrives as ranked arrays, paths like `[[1, DSP-Display], [2, DSP-Video], [3, BSI], [4, SB-Others]]` with `path_occurrences` and `impressions` alongside. QuickSight cannot chart that directly. The playbook is explicit: the "Sankey diagram is a visual type within Amazon QuickSight and requires a one dimension in source and one dimension in destination." A four-element path "will 'explode into' 3 separate steps/rows," metrics repeated on every exploded row; the playbook does this in a notebook ending with `df_final.to_csv('Sankey-Diagram_Input.csv', index=False)`. The query above skips the notebook step. The `ROW_NUMBER` self-join in the `steps` CTE emits the exploded pairs directly, one row per hop, ordered by first impression time. A user's terminal step carries a NULL destination (single-exposure users keep one row); label that terminal node from the `converted` join and the diagram shows where each journey ends. Read the `conversions` column as the conversion total of users who traversed that hop, not as credit attributed to the hop itself. > **In plain ChatGPT or Claude** > - **Generic knowledge, not Amazon's.** Ask a plain chat for "path to conversion" and you get a flat table, one row per campaign. No source/destination pairs means nothing QuickSight's Sankey visual can ingest. > - **No way to take action.** Even when Claude explains the explode correctly, the chat cannot apply it to results it never had. You re-shape rows by hand in a spreadsheet; the agent hands back rows that already are the chart's input. ## What happens next Reading the diagram is the fast part. The playbook's worked example charts the top 20 paths by purchase, with high-purchase users usually exposed to loyalty and consideration campaign categories and awareness overlap comparatively lower. The move: reuse what the high-overlap groups share (impression frequency, cost, line items) in the next campaign, and seed lookalikes from those audiences. One row to ignore: the "none" exposure group, purchasers with no impression recorded under their `user_id`; Amazon says to skip it. From there I have the agent re-run the workflow as a recurring [Skill](/features/skills/), timed past attribution close, so each month's diagram compares settled numbers to settled numbers. When the fixed 14-day window is the wrong lens, the custom attribution IQs (First Touch, Last Touch, Linear, Position Based) extend the lookback to 28 days and re-credit the same journey; that choice is its own guide: [choosing a custom attribution model in AMC](/guides/amc-custom-attribution-models/). The path query is one surface of [Amazon Agent Flow](/features/amazon-agent-flow/), the Amazon Agent Data layer connecting the Amazon Ads MCP, the [Selling Partner MCP](/features/amazon-selling-partner-mcp/), Atlas, and Skills into end-to-end workflows. The pattern is the one this series keeps landing on: the agent runs Amazon's current query in your instance, grounded in Amazon's own playbook, and returns an artifact you can act on the same day. The journey was always in your data. The walls were in the chat. *Next up: how much your DSP and sponsored ads audiences actually overlap, and what that says about incrementality, in [the four-way sponsored ads and DSP overlap analysis](/guides/amc-sponsored-ads-dsp-overlap-4way/).* ### Preview Listing Patches Before They Go Live URL: https://www.kuudo.com/guides/seller-listing-agentic-audit-to-patch/ The Slack message came in right before a weekend push: *"Our luggage listing is converting badly, the bullets read like a wall of text, and one image got rejected last week. Can the agent just fix it? But I don't want it quietly editing a live listing without me seeing what changed first."* That last clause is the whole job. Fixing a listing is easy to ask for and dangerous to automate, because a single wrong attribute name can wipe a field you never meant to touch. So I handed it to [our agent](/features/ai-clients/), backed by [Amazon Agent Atlas](/features/agent-atlas/), with one rule: audit first, show me the diff, and do not write anything live until I say yes. ## What a model without Atlas gets wrong I gave the same prompt to a frontier model with no retrieval. The plan it produced looked reasonable and would have caused real damage. > **Four failure modes in a single un-grounded response** > 1. It proposed a full `putListingsItem` replace instead of a `patchListingsItem` partial update. A full replace requires every attribute to be resent; the omitted ones get wiped. The agent only wanted to change two bullets. > 2. It submitted the change directly, with no validation step. The Listings Items API offers `mode=VALIDATION_PREVIEW`, which runs the real validation and returns errors without committing. Skipping it means the first time you learn the patch is malformed is after the listing breaks. > 3. It rewrote the bullets with an emoji and the phrase "eco-friendly." Amazon removes bullets containing emojis, trademark symbols, and prohibited phrases like eco-friendly or anti-microbial. The model had no idea the copy would be silently stripped. > 4. It assumed a generic `bullets` attribute. Attribute names are product-type specific. The correct path is `/attributes/bullet_point`, and the model would have gotten a rejected patch for an unknown attribute. None of this is exotic. It is all in Amazon's own documentation, scattered across the Selling Partner API (SP-API) reference and a handful of Seller Central help pages that only surface when you already know the exact term to search. ## What Atlas retrieves When the agent gets the question, it runs a semantic search across the `amazon_sellers` collection and pulls the governing documents before it writes a single attribute: - The **Partially Update a Listing** reference, which establishes that `patchListingsItem` applies a JSON Patch to one or more attributes without disturbing the rest of the listing. - The **Preview Errors Before Partially Updating a Listing** tutorial, the source of the `mode=VALIDATION_PREVIEW` parameter that turns a blind submission into a dry run. - The **Catalog Items API** reference, whose `getCatalogItem` call returns the live `attributes`, `images`, and `summaries` for an ASIN (Amazon Standard Identification Number), keyed to the product type definition. - **Suppressed Listings Management**, which explains how to download the suppressed listings report and why a listing is hidden from search in the first place. - **Product Image Requirements for Amazon Listings**, which states plainly that non-compliant images suppress the listing from search until compliant images are provided. - **Suggest Changes to Your Product Detail Page**, Amazon's own surface for recommended detail-page improvements, which the agent reads as a second opinion on what to fix. Atlas does not write the patch. It surfaces the rules the patch has to obey, wired through [the Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/), and the agent adapts them to this specific listing. ## The agent's working output The agent did not start by editing anything. It pulled the live listing state through `getCatalogItem` and produced an audit report that names each finding, its severity, and the document it is grounded in: ```json { "asin": "B0EXAMPLE12", "sku": "LUG-HARDSIDE-28", "listing_status": "active", "findings": [ { "field": "bullet_point", "severity": "high", "finding": "Two bullets exceed 255 characters and one contains an emoji", "source": "Product Bullet Points Requirements" }, { "field": "main_image", "severity": "medium", "finding": "Main image background is not pure white; at risk of suppression", "source": "Product Image Requirements for Amazon Listings" }, { "field": "item_name", "severity": "low", "finding": "Title repeats the brand token three times", "source": "Suggest Changes to Your Product Detail Page" } ] } ``` From that audit, the agent built a JSON Patch that touches only the bullet points, leaving every other attribute untouched. This is the body it would send to `patchListingsItem`: ```json { "productType": "LUGGAGE", "patches": [ { "op": "replace", "path": "/attributes/bullet_point", "value": [ { "value": "Hardside shell resists scuffs and cracking on checked flights", "marketplace_id": "ATVPDKIKX0DER" }, { "value": "Spinner wheels roll in four directions for tight gate turns", "marketplace_id": "ATVPDKIKX0DER" }, { "value": "TSA-approved combination lock built into the side panel", "marketplace_id": "ATVPDKIKX0DER" } ] } ] } ``` Then the part the operator actually asked for. The agent submitted that body with `mode=VALIDATION_PREVIEW`, read the returned `issues` array, and refused to go live until a human approved: ```python import requests SPAPI = "https://sellingpartnerapi-na.amazon.com" MARKETPLACE = "ATVPDKIKX0DER" SELLER_ID = "A1EXAMPLESELLER" def preview_patch(sku, body, token): response = requests.patch( f"{SPAPI}/listings/2021-08-01/items/{SELLER_ID}/{sku}", params={"marketplaceIds": MARKETPLACE, "mode": "VALIDATION_PREVIEW"}, headers={"x-amz-access-token": token}, json=body, ) return response.json() def submit_patch(sku, body, token): response = requests.patch( f"{SPAPI}/listings/2021-08-01/items/{SELLER_ID}/{sku}", params={"marketplaceIds": MARKETPLACE}, headers={"x-amz-access-token": token}, json=body, ) response.raise_for_status() return response.json() def run(sku, patch_body, token, approver): preview = preview_patch(sku, patch_body, token) errors = [i for i in preview.get("issues", []) if i.get("severity") == "ERROR"] if errors: return {"status": "blocked", "errors": errors} if not approver.approves(sku, patch_body, preview): return {"status": "declined"} return submit_patch(sku, patch_body, token) ``` The design choice that matters is that the preview call and the live call send the *same* body. The only difference is the `mode` query parameter. That means the thing the human approves is byte-for-byte the thing that ships, with no second translation step where a new error can creep in. The agent also kept the patch scoped to `/attributes/bullet_point` rather than rewriting the whole listing, so an approval reviewer reads one diff instead of auditing the entire item. And because the audit flagged the main image as a suppression risk, the agent explicitly declined to claim the copy fix would lift a suppression. It cannot, and saying so is part of being honest about what a patch can do. ## The footnotes the agent surfaced unprompted This is where retrieval grounding pulls away from fluent guessing. Without being asked, the agent attached the caveats an operator needs but rarely thinks to request: > **Things Atlas surfaced that the operator didn't ask for** > - **Preview error codes are changing.** The `VALIDATION_PREVIEW` error codes are being revised; Amazon supports both old and new codes during the transition, so match on issue meaning, not just the literal code string. > - **Bullet rules are strict.** Each bullet must be 10 to 255 characters, carry no end punctuation, and exclude emojis, the registered or trademark symbols, and prohibited phrases like eco-friendly or anti-microbial. Include at least three. > - **An image-suppressed listing will not un-suppress from a copy edit.** Fix the non-compliant image first; a clean bullet patch on a suppressed listing changes nothing a shopper can see. > - **Throttle is five requests per second per operation.** Submit only items with material changes. Resubmitting unchanged attributes inflates processing backlogs and slows the whole queue. > - **Prefer notifications over polling.** Subscribe to `LISTINGS_ITEM_ISSUES_CHANGE` to get near-real-time SKU, severity, and enforcement-action updates instead of repeatedly calling the API to check whether the issue cleared. > - **An ASIN must represent one product.** Editing a detail page to describe a different product is a policy violation, not an optimization. The agent will refuse a patch that changes what the listing fundamentally is. Any one of these would have cost an afternoon to rediscover after a failed submission. ## What happens next Once `VALIDATION_PREVIEW` returns a clean `issues` array and the human approves, the agent resends the identical body without the `mode` parameter and the change goes live. It then watches the `LISTINGS_ITEM_ISSUES_CHANGE` notification stream to confirm the issue actually cleared, rather than assuming success. For the findings a text patch cannot solve, the path forks: the image flagged as a suppression risk is handed to the seeded image-regeneration workflow, and recurring audits are wired up as a scheduled [Skill](/features/skills/) so the listing is re-checked after every catalog change instead of once a quarter. The same approval gate applies every time, which is the pattern explored in [human approval for agent activation](/guides/human-approval-for-amc-activation/). The full workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): [Selling Partner MCP](/features/amazon-selling-partner-mcp/) reads and previews listing changes, the [Amazon Ads MCP](/features/amazon-ads-mcp/) can add [Amazon Marketing Cloud](/features/amc/) (AMC) campaign-side performance context, Atlas grounds the catalog rules, and Skills keep every recurring patch behind a reviewable approval gate. ## Why this matters A foundation model can draft a better bullet point. What it cannot reliably do is read the live product-type schema, scope the edit to a JSON Patch that leaves the rest of the listing intact, run it through Amazon's own validation before committing, and tell you that the real problem was the image all along. That sequence is not model cleverness. It is a corpus of Amazon's own listing rules, indexed and addressable by an agent at the moment it is about to act, with a human holding the final yes. If your agent can edit a live listing, it should be able to show you the diff first. --- *Next in the series: using your current product photos as seeds for OpenAI image generation to regenerate listing visuals that still pass Amazon's image requirements, with the same approve-before-publish gate sitting in front of every upload.* ### Count New-to-Brand Customers in AMC URL: https://www.kuudo.com/guides/amc-ntb-customers/ ## What is the NTB customer question? A Slack from our paid team last Tuesday: *"Of all the customers our campaigns reached who actually bought, how many were buying our brand for the first time?"* The honest answer is: nobody at the agency knows, the Amazon Ads console gives a partial number that excludes Amazon's demand-side platform (DSP), and ChatGPT will hand back a SQL query that compiles and counts the wrong table. The right answer lives in three [Amazon Marketing Cloud](/features/amc/) (AMC) instructional queries plus a schema doc, none of which a model has cleanly in its training data. I handed the question to [our agent](/features/ai-clients/), backed by [Amazon Agent Atlas](/features/agent-atlas/). The matrix the agent grounded in before writing a line of SQL: | Source | Use it for | Don't use it for | |---|---|---| | `amazon_attributed_events_by_conversion_time` | Recurring NTB measurement, by promoted Amazon Standard Identification Number (ASIN) | Anything time-of-impression | | `amazon_attributed_events_by_traffic_time` | Same-day pacing only | Recurring workflows | | `amazon_retail_purchases` (NTB gateway IQ) | Custom NTB lookback (e.g. 1095 days) | Ad-attribution analysis | | `conversions` (custom attribution) | Pixel + off-Amazon NTB | Sponsored Ads NTB counts | The IQ behind the answer is **New to brand customers**. ## What a model without Atlas gets wrong > **Four failure modes I watched in a single un-grounded draft of this query** > 1. It picked `amazon_attributed_events_by_traffic_time` because the name sounds neutral. That table re-extends the conversion window by up to 30 days after the query, so the output changes after the workflow runs. A recurring NTB report pinned to it drifts. > 2. It forgot `purchases > 0` and counted every user the campaign reached, not just buyers. The denominator was wrong and so was the percentage. > 3. It put `SELECT user_id` in the final output and the query ran but the column came back blocked. `user_id` carries an aggregation threshold and can only live inside a CTE that aggregates it away. > 4. It confused the **New-to-brand customers** IQ with the **New-to-brand purchases** IQ. They use the same table but different denominators. The first counts distinct users; the second counts orders. The model swapped them and the answer to "how many first-time buyers did we acquire" came back as a purchase count inflated by repeat NTB orders. None of these failures throw an error. The query runs. The number is wrong. ## What Atlas retrieves The agent didn't write SQL from training data. It pulled five chunks from Atlas and grounded the query in them: - The **New to brand customers** instructional query: the canonical AMC IQ for this exact operator question, including the requirement language ("ASINs must be tracked to campaigns") and the policy window ("previous 365 day period"). - The **Amazon Attributed Events Overview** schema doc: defines the `new_to_brand` boolean column and the stability difference between `amazon_attributed_events_by_conversion_time` and the traffic-time variant. This is the source for the "use conversion_time for recurring workflows" rule. The table is wired through the [Amazon Ads MCP](/features/amazon-ads-mcp/), so the agent could resolve the column without resorting to a live web fetch via [Amazon Agent Crawl](/features/agent-crawl/). - The **New to brand purchases analysis** IQ, adjacent to the customer IQ and the one a model would otherwise confuse with this one. Atlas surfaced it so the agent could write Section 8 distinguishing the two. - The **Understanding New-to-Brand ASINs on Amazon** IQ, the natural follow-up. Once the operator knows the portfolio-level NTB%, the question becomes "which ASINs are the front door for NTB acquisition." - The **Data aggregation thresholds in AMC** reference: the privacy-safeguard doc that explains why `user_id` SELECTs get blocked at a final-output grain. ## How the agent's NTB SQL output works The SQL the agent returned, copy-pasteable into the AMC query editor: ```sql -- New-to-brand customers: count and percentage by campaign. -- Source IQ: New to brand customers (AMC instructional query). -- NTB lookback: 365 days (Amazon-managed; not parameterizable in this IQ). -- Run on the analytics table, NOT the for_audiences variant. WITH ad_buyers AS ( SELECT advertiser, campaign, user_id, MAX(new_to_brand) AS new_to_brand_flag FROM amazon_attributed_events_by_conversion_time WHERE purchases > 0 GROUP BY 1, 2, 3 ), ntb_only AS ( SELECT user_id, advertiser, campaign FROM ad_buyers WHERE new_to_brand_flag = TRUE ) SELECT b.advertiser, b.campaign, COUNT(DISTINCT b.user_id) AS users_that_purchased, COUNT(DISTINCT n.user_id) AS ntb_users_that_purchased, COUNT(DISTINCT n.user_id) * 1.0 / NULLIF(COUNT(DISTINCT b.user_id), 0) AS ntb_users_percentage FROM ad_buyers b LEFT JOIN ntb_only n ON b.user_id = n.user_id AND b.advertiser = n.advertiser AND b.campaign = n.campaign GROUP BY 1, 2 ORDER BY ntb_users_percentage DESC ``` Three decisions in this query would otherwise cost an operator an afternoon. The table choice is `amazon_attributed_events_by_conversion_time`, not the traffic-time variant. The Atlas chunk for `Amazon Attributed Events Overview` is explicit: traffic-time will re-extend the conversion window by up to 30 days *after* the query runs, so a recurring NTB report pinned to it produces a different answer each time. Conversion-time is the only safe table for a recurring measurement workflow. The `WITH` CTE exists because `user_id` carries an aggregation threshold. AMC will block any final SELECT that tries to expose `user_id` directly. The CTE collapses each user into a single row tagged with their NTB flag, and the outer SELECT operates only on COUNT DISTINCT. That is legal; it is also why the IQ template uses a CTE rather than a single-pass SELECT. The grouping is by `campaign`, not by `advertiser` alone. A portfolio-level NTB% hides the campaigns doing the actual acquisition work. If three campaigns are running and one is a loyalty-retargeting campaign with deliberately low NTB%, the aggregate percentage drops and looks like a problem. Grouping by campaign separates the loyalty workload from the acquisition workload so each campaign gets judged on its own goal. ## What NTB footnotes the agent surfaced > **Five things the agent surfaced unprompted, the ones an un-grounded model wouldn't include because it didn't know to** > 1. Amazon's docs phrase the NTB window two ways: the IQ chunk says "previous 365 day period" and the events table schema doc says "previous 12 months." Same definition, different wording. The IQ language is the authoritative one for this query; surface the inconsistency to the reader so nobody chases a ghost. > 2. The pixel-only path is a different query. Advertisers without a promoted ASIN that resulted in an ad-attributed purchase cannot run this IQ at all. The Atlas retrieval surfaced the `amazon_retail_purchases` NTB gateway IQ as the alternative, with a custom-lookback parameter (1095 days = 3 years is a common pick). > 3. The DSP NTB count includes only promoted-ASIN purchases. Sponsored Ads NTB also includes Brand Halo (related ASINs). A mixed-product portfolio measured by this IQ under-counts NTB on the DSP side relative to Sponsored Ads. The contrast with the [custom-attribution data sources](/guides/amc-custom-attribution-models/) is sharper here than the IQ doc admits. > 4. The column is `tracked_asin`. The IQ doc prose refers to "promoted ASIN." Same thing. Operators who grep the table schema for `promoted_asin` come up empty and assume the data isn't there. > 5. If a campaign was deliberately set up as existing-only (a Subscribe & Save win-back, for example), NTB% will be near zero. That is correct, not a bug. The IQ explicitly requires campaigns to "target both new and existing customers" for the result to be interpretable, and an existing-only campaign violates that requirement on purpose. ## What happens next The single-run query is the first step. The repeatable workflow is what the operator actually wanted. Activate this query as a recurring [Skill](/features/skills/) on a weekly cadence. Push the per-campaign NTB% to a BI dashboard so brand managers can read the trend without re-running SQL. Wire the underlying retrieval through the [Amazon Ads MCP](/features/amazon-ads-mcp/) so the agent surfaces the same context to a human reviewer mid-month that it had at compose time. The full workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): Amazon Ads MCP brings campaign and AMC signals, the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) can add catalog context, Atlas grounds the table choice, and Skills turn the query into a reviewed recurring automation. The rule that fires off this measurement: campaigns below the brand's target NTB% get re-allocated toward upper-funnel placements (DSP awareness inventory, Sponsored Display NTB audiences). Campaigns above target hold steady. Campaigns dramatically below target with no upper-funnel exposure are the strongest signal that the budget is being spent on existing customers who would have purchased anyway. The natural follow-on is the per-ASIN NTB breakdown. The portfolio number tells you whether acquisition is happening. The ASIN-level number tells you which products are doing the work. ## Why this NTB count matters If your acquisition number is just "total buyers," you are not measuring acquisition. *Next up: the per-ASIN NTB gateway analysis, which ASINs are the front door for new-customer purchases, and how to find them in the [path-to-conversion data](/guides/amc-path-to-conversion-sankey/).* ### Sponsored Ads x DSP Overlap: The 4-Way AMC Analysis URL: https://www.kuudo.com/guides/amc-sponsored-ads-dsp-overlap-4way/ The Slack question was blunt: *"When a shopper sees both our demand-side platform (DSP) ads and our Sponsored Products ads, does the combination actually move purchase rate, or are we paying twice for the same conversion?"* That is not a campaign-reporting question. Standard reports can show spend, clicks, impressions, and attributed sales by product line. They cannot tell you whether exposure to multiple ad products changes the purchase rate versus exposure to one. The answer lives in [Amazon Marketing Cloud](/features/amc/) (AMC), but the wrong query gives a very confident wrong answer. I handed the question to our agent, backed by [Amazon Agent Atlas](/features/agent-atlas/), and asked it to build the overlap analysis before we made a budget call. The decision matrix it used before writing SQL: | Question | Use this query | Why | |---|---|---| | DSP plus Sponsored Products only | Sponsored Products and DSP Display Overlap | Narrow legacy comparison | | Sponsored Display plus DSP only | Sponsored Display and DSP Overlap | Older two-way comparison | | DSP plus Sponsored Products, Brands, or Display | Sponsored Ads and DSP Overlap | Improved 2/3/4-way query | | Ordered touch sequence | Path-to-conversion sankey | Sequence, not overlap | For this operator question, the right artifact is **Analyzing Sponsored Ads and DSP Overlap**, run through the [Amazon Ads MCP](/features/amazon-ads-mcp/) so the agent can keep the table names, filters, and waiting rules intact. ## What a model without Atlas gets wrong > **Four silent failure modes showed up in the un-grounded version** > 1. It used the older Sponsored Display and DSP overlap query even though the newer Sponsored Ads and DSP overlap IQ supersedes it for broader full-funnel analysis. > 2. It treated Sponsored Products exposure as clicks. The IQ says exposure means impressions, including Sponsored Products impressions. > 3. It skipped the 14-day attribution-close rule and produced a report that would undercount conversions if run immediately after the media window. > 4. It compared campaigns that had not run for the same products in the same period. That makes the overlap group look like a performance difference when it is really a campaign-design difference. None of those mistakes has to fail at runtime. The SQL can compile. The chart can look clean. The budget call that follows can still be wrong. ## What Atlas retrieves Atlas pulled the relevant chunks before the agent wrote the query: - **Analyzing Sponsored Ads and DSP Overlap**: the improved instructional query. It states that the IQ measures 2-way, 3-way, and 4-way overlap and is an improved version of the older Sponsored Display and DSP overlap query. - **Sponsored Products and DSP Display Overlap Analysis**: the narrower prior IQ. Atlas surfaced it as a contrast case so the agent could avoid using the two-product template for a broader Sponsored Ads question. - **Joining and Unioning Sponsored Ads Traffic with Conversions**: the join pattern that points overlap queries at `SPONSORED_ADS_TRAFFIC` and `AMAZON_ATTRIBUTED_EVENTS_BY_TRAFFIC_TIME` through `user_id`. - **Creating Audiences from Clicked Sponsored Ads Without Purchases**: the adjacent audience workflow. It reminded the agent that overlap measurement can become an activation workflow later, but measurement comes first. - **Analyzing the Overlap of Amazon DSP Display, Streaming TV, and Sponsored Products**: the three-way precedent. It has the same one-week co-running and 14-day waiting logic, which is useful when the operator expands from two products to a larger full-funnel plan. The important thing is not just that Atlas found a query. It found the older query, the improved query, the join pattern, and the timing constraints together. That bundle is what keeps an agent from solving the wrong version of the problem. ## The agent's working output The agent returned the AMC SQL as a measurement query, not as an audience. I kept the campaign filters in place but commented, matching the IQ style. Run it unfiltered first to validate the exposure groups, then narrow it to the campaign IDs you actually want to compare. ```sql -- Instructional Query: Sponsored Ads and DSP Overlap -- Use after all compared ad products ran for at least one week -- in the same period. Wait 14 full days after the query end date. WITH dsp_campaigns (campaign_id_string) AS ( VALUES ('1111111111111'), ('2222222222222') ), sa_campaigns (campaign_id_string) AS ( VALUES ('3333333333333'), ('4444444444444') ), impressions_cte AS ( SELECT user_id, ARRAY_SORT(COLLECT(DISTINCT ad_product_type)) AS exposure_group, MIN(impression_dt) AS min_impression_dt, SUM(impressions) AS impressions FROM ( SELECT i.user_id, 'DSP' AS ad_product_type, i.impressions, i.impression_dt FROM dsp_impressions i /* Optional DSP filter: WHERE i.campaign_id_string IN ( SELECT campaign_id_string FROM dsp_campaigns ) */ UNION ALL SELECT i.user_id, i.ad_product_type, i.impressions, i.event_dt AS impression_dt FROM sponsored_ads_traffic i /* Optional Sponsored Ads filter: WHERE i.campaign_id_string IN ( SELECT campaign_id_string FROM sa_campaigns ) */ ) GROUP BY 1 ), reach_by_group AS ( SELECT exposure_group, COUNT(DISTINCT user_id) AS ad_exposed_users FROM impressions_cte GROUP BY 1 ), purchases_by_group AS ( SELECT i.exposure_group, COUNT(DISTINCT p.user_id) AS users_purchased, SUM(p.total_purchases) AS total_purchases, SUM(p.total_product_sales) AS total_product_sales FROM amazon_attributed_events_by_traffic_time p INNER JOIN impressions_cte i ON i.user_id = p.user_id WHERE p.total_purchases > 0 AND p.conversion_event_dt > i.min_impression_dt /* Optional matched campaign filter: AND ( p.campaign_id_string IN (SELECT campaign_id_string FROM dsp_campaigns) OR p.campaign_id_string IN (SELECT campaign_id_string FROM sa_campaigns) ) */ GROUP BY 1 ) SELECT r.exposure_group, r.ad_exposed_users AS unique_reach, COALESCE(p.users_purchased, 0) AS users_that_purchased, COALESCE(p.total_purchases, 0) AS total_purchases, COALESCE(p.total_product_sales, 0) AS total_product_sales, COALESCE(p.users_purchased, 0) * 1.0 / NULLIF(r.ad_exposed_users, 0) AS purchase_rate FROM reach_by_group r LEFT JOIN purchases_by_group p ON r.exposure_group = p.exposure_group ORDER BY purchase_rate DESC; ``` The output is a table of exposure groups. A row might be `['DSP']`, `['sponsored_products']`, or `['DSP','sponsored_products']`, depending on what the shopper saw during the window. The comparison that matters is not total sales. It is purchase rate by exposure group after the same products, same period, and attribution-close rules are satisfied. The `ARRAY_SORT(COLLECT(DISTINCT ad_product_type))` choice matters. Without sorting and distinct collection, the same set of exposures can appear as different labels depending on event order. The agent grouped the exposures as a set, not as a sequence. If you need sequence, that is a different guide: the [path-to-conversion sankey](/guides/amc-path-to-conversion-sankey/). The conversion join uses `AMAZON_ATTRIBUTED_EVENTS_BY_TRAFFIC_TIME` because this is an exposure-window analysis. The query asks whether users who saw an ad product later purchased, so the conversion event has to occur after the user's minimum impression timestamp. That `conversion_event_dt > min_impression_dt` predicate is the line that turns a raw join into a causal sanity check. ## The footnotes the agent surfaced > **Five caveats the agent brought back before I asked** > 1. The improved Sponsored Ads and DSP overlap IQ is not the same as the older Sponsored Display and DSP overlap IQ. Use the improved one when Sponsored Products or Sponsored Brands are part of the comparison. > 2. Sponsored Products exposure in this IQ means impressions. If the team expects click-only logic, say that before anyone interprets the result. > 3. Every ad type in the comparison should advertise the same products during the same period and run for at least one week. Otherwise the exposure groups are not comparable. > 4. Wait at least 14 full days after the query end date. Running earlier makes the multi-exposure group look weaker because conversions have not fully closed. > 5. The result is set overlap, not touch order. If the business question is "which touch came first," use the path-to-conversion workflow instead. Those are the guardrails that make the chart reviewable. A generic model can write a join. The hard part is knowing which join should not be trusted yet. ## What happens next Run the unfiltered query once to see whether the overlap groups exist at a usable volume. If the `['DSP','sponsored_products']` row is tiny, do not make a purchase-rate call yet. Extend the window, widen the campaign set, or accept that the campaigns did not create enough overlap to measure. If the overlap group is large enough, package the query as a recurring [Skill](/features/skills/) with an approval gate. The agent should check the three preconditions before each run: same products, at least one week of co-running media, and 14 full days since query end date. If one fails, the Skill should report "not ready" instead of sending a chart to Slack. The full workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): Amazon Ads MCP brings the DSP, Sponsored Products, Sponsored Brands, and Sponsored Display signals; the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) can add Amazon Standard Identification Number (ASIN) and catalog context; Atlas grounds the timing rules; and Skills keep the recurring run reviewable. The budget action comes after review. If the combined exposure group has materially higher purchase rate than either single-exposure group, the DSP and Sponsored Ads plan is doing real full-funnel work. If the combined group is flat and reach is duplicated, move budget toward the ad product that drives incremental reach or test new audience definitions before increasing spend. ## The point Overlap analysis is only useful when the setup rules are as visible as the result. *Next up: use the same exposure groups as inputs to a [path-to-conversion sankey](/guides/amc-path-to-conversion-sankey/) so the agent can separate overlap from sequence.* ### Choose the Right AMC Attribution Source URL: https://www.kuudo.com/guides/amc-custom-attribution-models/ The Slack message came in mid-afternoon, from our paid-media lead: *"Our attribution model defaults are leaving us blind. Can we build a custom attribution view in AMC, and which data source do we use?"* This is the kind of ask that sounds like one question and is really three. There is not "one" [Amazon Marketing Cloud](/features/amc/) (AMC) attribution table. There are several, they are not interchangeable, and the obvious moves get you the wrong one. Ask ChatGPT for the AMC attribution table and you get back a single name with no context. Search Amazon's docs and the Custom Attribution Overview instructional query (IQ) surfaces, but the data-source comparison is buried in section 3.6 where most readers never scroll. Ping the agency and they default to `amazon_attributed_events_by_conversion_time` because that is the standard reporting source used by the Amazon DSP (demand-side platform) UI. So I handed it to our agent, which has [Amazon Agent Atlas](/features/agent-atlas/) behind it. Atlas indexes the AMC documentation, the instructional queries, the schema reference for every Amazon Standard Identification Number (ASIN) the catalog tracks, and the privacy framework that governs which columns you can put in a SELECT. Here is what came back. ## What a model without Atlas gets wrong I ran the same prompt through a frontier model with no retrieval. The output looked plausible. It was wrong in five specific, silent ways. > **Five failure modes I saw on a single un-grounded prompt** > - It treated `amazon_attributed_events_by_conversion_time` as a custom-attribution source. That table is the standard-reporting source: competition-aware, 14-day last-touch, de-duped across campaigns. You cannot build a custom model on it. > - It wrote `SELECT user_id` from `conversions_with_relevance` for an audience-building query. `user_id` carries the aggregation threshold "Very high" and can never appear in the final SELECT of an analytics table. The only data source that permits audience-building semantics is `conversions_with_relevance_for_audiences`. > - It filtered `WHERE engagement_scope = 'PROMOTED'` against `conversions`. `engagement_scope` lives on `conversions_with_relevance`; the plain `conversions` table excludes every campaign-dependent column. > - It assumed `conversions` and `conversions_with_relevance` have the same row counts. They do not. In `conversions_with_relevance`, a single conversion can appear on multiple rows, one per relevant campaign. The IQ example splits conversion_id 123456 across campaign_a and campaign_b. > - It quoted a 14-day pixel lookback to size pixel volume in custom attribution. That is the standard-reporting lookback. Inside custom attribution, the pixel lookback is bounded only by when the pixel was tracked to the campaign, or by the query time window. None of these failures throw an error. The query runs. The numbers look like attribution numbers. They are the wrong ones, and you only find out when the downstream model contradicts a sanity check. ## What Atlas retrieves When the agent gets the question, it does a semantic search across the `amazon_ads` collection, which is the corpus that backs the [Amazon Ads MCP](/features/amazon-ads-mcp/). It pulls six chunks before it writes anything: - The **Custom Attribution Overview** (dataset `conversions`) defines the two custom-attribution data sources, the 28-day ASIN relevancy rules, and the section 3.6 comparison table that names all four AMC attribution sources. - The **Amazon Ads Conversions with Relevance** chunk (dataset `conversions_with_relevance`) names both physical variants: the Analytics table (`conversions_with_relevance`) and the Audience table (`conversions_with_relevance_for_audiences`). - The **Amazon Attributed Events Overview** (dataset `amazon_attributed_events`) is the schema reference for the standard-reporting attribution data, including the LOW-threshold dimension columns. - The **Data Aggregation Thresholds in AMC** chunk (dataset `amazon_attributed_events_by_conversion_time`) classifies every column as None, Low, Medium, High, or Very high, and explains why `user_id` cannot be SELECTed from a normal analytics table. - The **Custom Attribution Linear Model** IQ template shows how a chosen base table plugs into the standard-vs-custom comparison. - The **Joining and Unioning Sponsored Ads Traffic with Conversions** chunk (dataset `sponsored_ads_traffic`) demonstrates that `sponsored_ads_traffic` joins to `conversions_with_relevance`, not `conversions`, because campaign columns are required. Atlas does not pick the table for you. It surfaces the rules and lets the agent make the call. ## The agent's output The artifact for this kind of question is not SQL. It is a decision plan: a matrix of every AMC attribution data source side by side, then a rule set keyed off the operator's actual use case. Here is the machine-readable form the agent returned, before the prose write-up: ```json { "artifact": "decision_plan", "topic": "amc-custom-attribution-base-table", "rules": [ {"use_case": "align with Amazon DSP / Sponsored Ads UI numbers", "pick": "amazon_attributed_events_by_conversion_time", "why": "standard-reporting source; custom attribution will not reconcile by design"}, {"use_case": "Prime Day delivered-impression effect on conversions", "pick": "amazon_attributed_events_by_traffic_time", "why": "anchors on traffic time, matching the campaign window"}, {"use_case": "de-duped pixel volume across all campaigns, exposed and un-exposed users", "pick": "conversions", "why": "excludes campaign columns; one row per conversion"}, {"use_case": "linear / position-based / first-touch / last-touch multi-touch model with per-campaign credit", "pick": "conversions_with_relevance", "why": "campaign columns + engagement_scope required to split credit; one row per (conversion x relevant campaign)"}, {"use_case": "build an audience from users satisfying a custom-attribution rule", "pick": "conversions_with_relevance_for_audiences", "why": "only data source permitting SELECT user_id for audience materialization"}, {"use_case": "measure halo lift specifically", "pick": "conversions_with_relevance", "why": "filter engagement_scope = 'BRAND_HALO' vs 'PROMOTED' on the relevance table"} ] } ``` The JSON is the compact answer the Skill can hand to an operator or downstream workflow. The matrix below is the human review layer for the same decision: every row shows where the source is safe, where it silently drifts, and whether it can materialize users for activation. ## Which AMC attribution source should you choose? | Data source | What it is | ASIN coverage | Pixel coverage | `engagement_scope`? | `SELECT user_id`? | Lookback | Dedup behavior | Use it for | |---|---|---|---|---|---|---|---|---| | `amazon_attributed_events_by_conversion_time` | Standard-reporting attribution, by conversion time | Ad-attributed only | Ad-attributed only | N/A | No (`user_id` is Very high) | 14-day last-touch (pixel) | De-duped across campaigns | Aligning with the standard Amazon DSP and Sponsored Ads reports | | `amazon_attributed_events_by_traffic_time` | Standard-reporting attribution, by traffic time | Ad-attributed only | Ad-attributed only | N/A | No | 14-day last-touch (pixel) | De-duped across campaigns | Campaign-window analyses, like Prime Day delivered impressions | | `conversions` | Custom-attribution base; relevant conversions only, no campaign columns | Promoted plus brand halo | All pixel conversions tracked to the campaign, exposed and un-exposed users | No | No | 28-day ASIN relevancy; pixel lookback bounded by tracking start | De-duped | Volume questions and de-duped pixel performance across campaigns | | `conversions_with_relevance` (Analytics table) | Custom-attribution base plus campaign and advertiser columns | Same conversions as `conversions`, one row per relevant campaign | Same conversions as `conversions`, one row per relevant campaign | Yes (PROMOTED, BRAND_HALO, null) | No | Same as `conversions` | Duplicated across relevant campaigns | Multi-touch and split-credit custom models (linear, position-based, first-touch, last-touch) | | `conversions_with_relevance_for_audiences` (Audience table) | Audience-table variant of `conversions_with_relevance` | Same as `conversions_with_relevance` | Same as `conversions_with_relevance` | Yes | Yes, the only data source that permits `SELECT user_id` for audience-building | Same as `conversions_with_relevance` | Same | Materializing custom-attribution audiences for activation | A note on framing: Atlas's section 3.6 comparison lists four AMC attribution data sources by splitting `amazon_attributed_events` into the `_by_conversion_time` and `_by_traffic_time` variants. Other framings collapse those two into one and treat `conversions_with_relevance_for_audiences` as the fourth distinct surface. The matrix above shows all five rows so both views are visible; the decision rules below collapse to the four-way operator choice. ### Decision rules - If the use case is "align my custom model output with the numbers in the Amazon DSP or Sponsored Ads UI," pick `amazon_attributed_events_by_conversion_time`, because it is the standard-reporting source and custom attribution will not reconcile by design. - If the use case is "Prime Day delivered-impression effect on conversions," pick `amazon_attributed_events_by_traffic_time`, because it anchors on traffic time and matches the campaign window. - If the use case is "de-duped pixel volume across all campaigns the pixel is tracked to, exposed and un-exposed users," pick `conversions`, because it excludes campaign columns and emits one row per conversion. - If the use case is "linear, position-based, first-touch, or last-touch custom model with per-campaign credit," pick `conversions_with_relevance`, because campaign columns and `engagement_scope` are required to split credit; expect one row per (conversion x relevant campaign). - If the use case is "build an audience from the users who satisfy a custom attribution rule," pick `conversions_with_relevance_for_audiences`, because it is the only data source that permits `SELECT user_id` for audience materialization. - If the use case is "measure halo lift specifically," pick `conversions_with_relevance` and filter on `engagement_scope = 'BRAND_HALO'` versus `'PROMOTED'`. A few things to notice about how the agent broke this apart. The `amazon_attributed_events_*` family is not a custom-attribution base table. It is competition-aware, de-duped across campaigns, and follows fixed last-touch logic. Use it when you need to align with standard reporting numbers. Never use it when you are modeling, because the model logic is already baked in and you cannot unbake it. The split between `conversions` and `conversions_with_relevance` is a row-shape difference, not a coverage difference. Both tables cover the same set of relevant conversions. `conversions_with_relevance` adds campaign and advertiser dimensions, and as a consequence it emits one row per relevant campaign per conversion. A dedup-aware question like "how many users converted in the window, period" uses `conversions`. A multi-touch model that splits credit across campaigns uses `conversions_with_relevance` because the per-campaign rows are exactly what gets weighted. The audience-table variant exists because of aggregation thresholds, not because someone wanted three tables instead of two. `user_id` is classified Very high, which means a normal analytics table cannot put it in a final SELECT, cannot filter it against a literal value, and cannot use it as a join or group-by key against literals. The `_for_audiences` companion is the data source that allows audience-building semantics, and it is the only one. Anything materializing user-level audiences from custom attribution flows through it. The `engagement_scope` column on `conversions_with_relevance` is the lever for halo measurement. Values are `PROMOTED` for the promoted ASIN, `BRAND_HALO` for halo conversions to other ASINs from the same brand, and null for pixel conversions. Any custom model that wants to isolate halo lift filters on this column. Any custom model that ignores it is silently treating halo and promoted as the same thing. ## The footnotes the agent surfaced unprompted This is the part where retrieval grounding earns its keep. None of these were asked for. All of them mattered. > **Six things the agent surfaced that the operator did not ask about** > - The 28-day ASIN relevancy window for custom attribution is double the brand-based 14-day window in `amazon_attributed_events_by_conversion_time` and `_by_traffic_time`. Higher per-ASIN conversion counts in custom attribution are expected, not a bug. > - The custom-attribution data sources are not competition-aware and include both viewable and non-viewable impressions. Two more reasons custom-attribution conversion counts run higher than the attributed-events numbers. > - Pixel conversions in `conversions` and `conversions_with_relevance` do not require an ad impression or click to be relevant. If a pixel was tracked to a DSP campaign, all pixel conversions appear, including from users who were never exposed. > - Pixel lookback inside custom attribution is bounded by when the pixel was tracked to the campaign, or by the query time window. It is not the 14-day last-touch lookback that `amazon_attributed_events_*` uses. Sizing pixel volume with the wrong lookback is a common silent error. > - `engagement_scope` is always `PROMOTED` for pixel conversions (when `event_category = 'pixel'`), and `halo_code` is null for pixels. Both columns are LOW-threshold dimensions and both live only on `conversions_with_relevance`. > - `user_id` (aggregation threshold Very high) can never appear in the final SELECT, cannot be filtered with literal values, and cannot be used as a join or group-by key against literals. It can, however, be COUNT or COUNT DISTINCTed, which is how reach, optimal-frequency, and customer-journey queries get written. The `_for_audiences` audience table exists as a separate physical surface precisely because the analytics tables cannot do the audience-shaped thing. Most of these would have cost an hour each to discover the hard way. Compounded across a quarter, they are the difference between a custom attribution program that ships and one that gets quietly abandoned. ## What happens next The decision plan is the input, not the output. Once you have picked the base table, the operational moves diverge. If you picked `conversions_with_relevance` for a multi-touch model, the next step is to schedule the linear or position-based IQ as a recurring AMC workflow. Package it as a verified [Skill](/features/skills/) and export the campaign-weighted credit to a dashboard. If you picked `conversions_with_relevance_for_audiences`, the next step is to activate the resulting user set as an AMC audience, following the same pattern documented in the [cart-abandoner audience guide](/guides/amc-cart-abandoner-audience/). If you picked `conversions` for de-duped pixel volume across campaigns, feed it into the same pipeline pattern used in the [Subscribe & Save lift workflow](/guides/amc-subscribe-and-save-lift/), substituting your custom-attribution filters. The full workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): [Amazon Ads MCP](/features/amazon-ads-mcp/) brings AMC and campaign signals, the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) can add catalog context when ASIN eligibility matters, Atlas grounds the source selection, and Skills keep the attribution model on a reviewable schedule. If you picked `amazon_attributed_events_by_conversion_time` or `_by_traffic_time`, stop. You are doing standard reporting alignment, not custom modeling. Route the work to the standard-reports surface and save AMC for the questions standard reports cannot answer. ## Why this matters Pick the wrong base table and every downstream model inherits the wrong numbers, silently, for as long as the workflow runs. --- *Next in the series: building a path-to-conversion view in AMC that stitches DSP, Sponsored Products, Sponsored Brands, and Sponsored Display into a single touch-ordered timeline. Custom attribution sets the base table; path analysis is what you do with it.* ### Evaluate Prime Day AMC Lookalikes URL: https://www.kuudo.com/guides/amc-lookalike-audience-evaluation/ The Slack message came in two days after the Prime Day campaign closed: *"The lookalike audience shipped. Did it actually beat last year's rule-based audience, or did we just add a new prospecting line item?"* That question should not be answered from an Amazon DSP screenshot. The operator needs a matched-window read in [Amazon Marketing Cloud](/features/amc/): same promotional period, comparable spend, and the same conversion definition. If the lookalike audience reached more shoppers but bought new-to-brand customers at a worse cost, it did not win. It scaled noise. If it held cost per new-to-brand customer while expanding reach, the seed is worth keeping. So I asked our agent in Claude. The agent has [Amazon Agent Atlas](/features/agent-atlas/) behind it: a corpus of AMC playbooks, instructional queries, reporting patterns, and audience notes. The same prompt would work in ChatGPT because Kuudo exposes that Amazon context through standards-based [Model Context Protocol (MCP)](/features/mcp/), not through one chat app. If the follow-up belongs in code, Cursor or Codex can use the same server. If it needs to run weekly, n8n or Make can call the same workflow. The [AI client](/features/ai-clients/) changes; the grounded Amazon context does not. ## What ChatGPT or Claude without Atlas gets wrong in lookalike evaluation I ran the same ask without retrieval. The answer sounded reasonable: pull conversions, compare totals, report lift. That is not enough for a Prime Day audience decision. > **Five failure modes in the un-grounded response** > 1. It compared the lookalike audience to total campaign performance instead of to last year's rule-based audience baseline. That makes the lookalike inherit credit from every other tactic in the flight. > 2. It treated reach as the win condition. For Prime Day prospecting, reach only matters if new-to-brand efficiency holds. > 3. It ignored the attribution settling period. Reading the audience too early undercounts late conversions and can make the model look worse than the baseline. > 4. It did not normalize for spend. A line item with 40% more spend should produce more conversions; the question is whether it produced cheaper or more incremental customers. > 5. It did not create a next action. The operator needs a keep, rotate, or rebuild decision, not a dashboard summary. This is the same problem as the seed post in reverse. The model can write the query-shaped thing. The Atlas-grounded agent knows which comparison decides the next Prime Day seed. ## What Atlas retrieves for Prime Day lookalike measurement When the agent gets the question, it pulls the audience-building post's downstream playbook pieces before writing SQL: - The **AMC Lookalike Audiences for Promotional Events** playbook: the source of the Prime Day lead-in and lead-out logic, plus the expectation that performance is evaluated after activation rather than at seed creation. - The **Introduction to AMC Lookalike Audiences** instructional query: the expansion-type context that explains why Balanced, Similar, and Broad should be evaluated differently. - The **Customer Journey Analytics** playbook: the follow-on analysis path for checking whether the lookalike is creating new conversion journeys or entering journeys the rule-based audience already covered. - The **DSP and AMC conversion reporting table notes**: the table-shape reminders for `dsp_impressions`, `dsp_clicks`, and `amazon_attributed_events_by_traffic_time`. - The **Subscribe & Save lift analysis** pattern: the upstream check that tells the operator whether SnS behavior was strong enough to be a seed in the first place. The seed can also be rebuilt around Amazon Standard Identification Number (ASIN) behavior if the evaluation shows that subscription buyers reached well but did not produce enough new customers. The retrieved set matters because this is not just a measurement query. It is a decision about whether the next seed should stay SnS, rotate to multi-ASIN purchasers, or use a spend threshold. ## The agent's working output: AMC lookalike lift SQL The agent produced an evaluation skeleton that compares the activated lookalike line item with a prior rule-based audience baseline. The placeholder IDs are intentionally visible so the operator can audit what is being compared before running it. ```sql /* AMC lookalike audience evaluation skeleton Run after the promotional flight closes and attribution has settled. Last verified: 2026-05-13. Replace: - LOOKALIKE_CAMPAIGN_ID with the Prime Day lookalike line item/campaign - BASELINE_CAMPAIGN_ID with last year's rule-based audience campaign - flight windows with matched Prime Day periods */ WITH comparison_windows AS ( SELECT 'lookalike_2026' AS cohort, TIMESTAMP '2026-07-01 00:00:00' AS window_start, TIMESTAMP '2026-07-15 23:59:59' AS window_end, 'LOOKALIKE_CAMPAIGN_ID' AS campaign_id UNION ALL SELECT 'rule_based_2025' AS cohort, TIMESTAMP '2025-07-01 00:00:00' AS window_start, TIMESTAMP '2025-07-15 23:59:59' AS window_end, 'BASELINE_CAMPAIGN_ID' AS campaign_id ), impressions AS ( SELECT w.cohort, i.user_id, COUNT(*) AS impressions, SUM(i.total_cost) AS spend FROM comparison_windows w JOIN dsp_impressions i ON i.campaign_id = w.campaign_id AND i.impression_dt_utc BETWEEN w.window_start AND w.window_end WHERE i.user_id IS NOT NULL GROUP BY 1, 2 ), conversions AS ( SELECT w.cohort, a.user_id, COUNT(*) AS orders, SUM(a.total_product_sales) AS sales, SUM(CASE WHEN a.new_to_brand = TRUE THEN 1 ELSE 0 END) AS ntb_orders FROM comparison_windows w JOIN amazon_attributed_events_by_traffic_time a ON a.campaign_id = w.campaign_id AND a.event_dt_utc BETWEEN w.window_start AND w.window_end WHERE a.conversion_event_subtype = 'order' AND a.user_id IS NOT NULL GROUP BY 1, 2 ), cohort_rollup AS ( SELECT i.cohort, COUNT(DISTINCT i.user_id) AS reached_users, SUM(i.impressions) AS impressions, SUM(i.spend) AS spend, COUNT(DISTINCT c.user_id) AS converting_users, SUM(c.orders) AS orders, SUM(c.sales) AS sales, SUM(c.ntb_orders) AS ntb_orders FROM impressions i LEFT JOIN conversions c ON i.cohort = c.cohort AND i.user_id = c.user_id GROUP BY 1 ) SELECT cohort, reached_users, spend, orders, sales, ntb_orders, orders / NULLIF(reached_users, 0) AS conversion_rate, ntb_orders / NULLIF(orders, 0) AS ntb_share, spend / NULLIF(ntb_orders, 0) AS cost_per_ntb_order, sales / NULLIF(spend, 0) AS roas FROM cohort_rollup ORDER BY cohort; ``` Three choices matter in that SQL. First, the comparison is campaign-scoped, not account-scoped. The lookalike line item should not borrow credit from branded search, retargeting, or other Prime Day tactics. Second, the windows are explicit. If you compare a 2026 lead-in window to a 2025 full-event window, the result will look precise and be useless. The agent forces both cohorts into matched promotional periods. Third, the output includes `cost_per_ntb_order`, not just return on ad spend (ROAS). For a lookalike audience, the question is not only whether it sold product. The question is whether it found new customers at a cost worth repeating in Amazon demand-side platform (DSP) activation. ## The footnotes the agent surfaces before you trust the lift read > **Things Atlas surfaced that the operator did not ask for** > 1. **Do not evaluate before attribution settles.** A same-day read can undercount late attributed conversions and distort the lookalike result. > 2. **Spend-normalize before calling lift.** More spend usually means more orders. Efficiency metrics decide whether the audience actually improved the plan. > 3. **Compare to the right baseline.** Last year's rule-based audience is a better baseline than total Prime Day performance because it isolates audience strategy. > 4. **Treat expansion type as a test variable.** If Balanced scaled reach but lost new-to-brand efficiency, test Similar next. If Similar is efficient but too small, test Broad. > 5. **Use path analysis as the next diagnostic.** If the lookalike appears in the same journeys as existing retargeting, it may not be creating new demand. The footnotes change the shape of the readout. Without them, the operator gets a table. With them, the operator gets a decision tree. ## What happens next: keep, rotate, or rebuild the seed The agent turns the output into three possible decisions. If the lookalike improves new-to-brand share and lowers cost per new-to-brand order, keep the seed and test a tighter expansion type. If reach improves but efficiency falls, rotate the seed from SnS subscribers to multi-ASIN purchasers or a spend threshold. If the rule-based audience still wins on conversion rate and cost, keep lookalikes in the lead-in phase and use rule-based audiences for lead-out retargeting. This is where the standards-based setup matters operationally. If you are in Claude, ask for the recommendation in plain language. If your team works in ChatGPT, ask the same question there. If the marketing analyst wants to inspect the SQL, open it in Cursor or Codex. If the read should run every Monday after a promotional flight, schedule it in n8n or Make. Kuudo speaks MCP, so the same Amazon context follows the work into whichever standards-supporting client your team prefers. The full workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): [Amazon Ads MCP](/features/amazon-ads-mcp/) brings AMC and DSP signals, the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) can add catalog and ASIN context, Atlas grounds the baseline comparison, and [Skills](/features/skills/) keep the post-flight read on a repeatable schedule. The follow-on analysis is the conversion path. If the lookalike wins, use the [path-to-conversion Sankey workflow](/guides/amc-path-to-conversion-sankey/) to see whether it is creating new journeys or merely joining paths your existing campaigns already owned. ## Why standards-based AI clients make this more useful This is not a Claude workflow, a ChatGPT workflow, or a Cursor workflow. It is an Amazon Marketing Cloud workflow exposed through a standard interface. The useful part is the stable context: the tables, playbooks, thresholds, and audience history. The chat or coding tool is just where the operator happens to be working. That is the same reason the evaluation produces an action instead of a report. The agent can move from question to SQL to scheduling because the context is portable. It can answer in chat, edit in code, and run in a workflow tool without rewriting the operating logic. If your lookalike readout stops at reach and ROAS, it has not answered the Prime Day question. *Next: use path-to-conversion analysis to see whether the lookalike audience created new customer journeys or just overlapped with existing retargeting paths.* ### Segment AMC Customers by CLTV URL: https://www.kuudo.com/guides/amc-cltv-cohort-segmentation/ "Which of our customer cohorts are actually worth the most over time, and which look profitable but aren't?" — that was my Slack question on a Tuesday, and I handed it to our [Amazon Agent Atlas](/features/agent-atlas/) with a strict brief: no fluffy summaries, just a query-first proof of concept. I already tried three obvious approaches: a ChatGPT-style single-shot which ignored [Amazon Marketing Cloud](/features/amc/)'s 12-month customer lifetime value (CLTV) cohort window, the AMC docs alone that described CLTV but didn't surface the exact AVG(... ) OVER () CASE pattern we needed, and an agency pitch deck that happily swapped segment labels and ignored activation timing. I asked the agent to return a per-user labeling of High Value / Growth Potential / Revenue Potential / Low Value ready for a 48-hour Amazon demand-side platform (DSP) activation window for resulting audiences. ## What a model without Atlas gets wrong I ran the same prompt through a frontier model with no retrieval. The output read confidently. It was wrong in five places, each subtle enough that an operator would only catch the failures at activation time, when the DSP audience comes back empty or the segment labels don't match the deck. > **Five failure modes I saw in a single un-grounded response** > - used `conversions` rather than `conversions_for_audiences` (the audience-build table variant), which produces the wrong user set for RBA exports. > - omitted `AVG(lifetime_score) OVER ()` and `AVG(value_score) OVER ()` semantics, producing non-comparable thresholds across the two axes. > - failed to include the 48-hour DSP activation window, so audiences can't be scheduled correctly in DSP. > - returned generic tiers instead of the four AMC segments: High Value, Growth Potential, Revenue Potential, Low Value. > - omitted the year-over-year diagnostic dimension for cohort migration. This is the differentiator. The model isn't lying. It is producing a plausible-looking artifact that fails against the AMC playbook's actual mechanics: the audience-build table variant, the composite window-function semantics, the activation timing, the named segment taxonomy, and the diagnostic dimension that catches drift over time. ## What Atlas retrieves - "Understanding Customer Long-Term Value (CLTV)" playbook: the canonical AMC CLTV reference that explains CLTV versus return on ad spend (ROAS) and reminds us the AMC long-term window is bounded to 12 months. (source: Customer long-term value (CLTV): Amazon Marketing Cloud) - "Lifetime * Value CLTV SQL Export Logic": the composite-score template that defines the Lifetime Ratio and the overall Lifetime × Value construct. This includes the formula Lifetime Ratio = Purchase Frequency × Purchase Quantity × User Lifetime ratios. (source: Lifetime * Value CLTV SQL Export Logic) - "Audience Labeling" CASE statement for the four segments: the exact AVG(...) OVER () CASE pattern you need to convert scores into High Value, Growth Potential, Revenue Potential, and Low Value labels. (source: Audience segmentation (based on CLTV)) - "Identify high value customer segments": a data-interpretation guide with percentile examples and audience-size guidance so you can pick seed thresholds and respect rule-based audience (RBA) and lookalike (LAL) guardrails. (source: Identifying High Value Customer Segments: Flexible Amazon shopping insights) - "CLTV Audience Segmentation (Year-Over-Year)": the diagnostic view and recommended recurring check to detect cohort migration between segments over time. (source: Customer long-term value (CLTV): Year-over-year guidance) ## The agent's output ```sql -- Per-user CLTV segmentation skeleton for AMC WITH -- 1) base events: filter to the 12-month AMC window and to the audience build table events AS ( SELECT user_id, event_time, tracked_asin, -- optional: later join to ASIN->category mapping for descriptive stats quantity, sale_price, -- revenue per event (use Paid Features mappings if available) ad_spend -- spend attributed to the event (nullable; a proxy may be filled for off-Amazon) FROM conversions_for_audiences -- use conversions_all for sizing/coverage experiments WHERE event_time BETWEEN DATE_ADD('month', -12, CURRENT_DATE) AND CURRENT_DATE ), -- 2) per-user purchase aggregates user_purchases AS ( SELECT user_id, COUNT(DISTINCT event_time) AS purchase_count, SUM(quantity) AS total_units, SUM(COALESCE(sale_price,0) * COALESCE(quantity,0)) AS total_revenue, SUM(COALESCE(ad_spend,0)) AS total_ad_spend, MIN(event_time) AS first_purchase_ts, MAX(event_time) AS last_purchase_ts FROM events GROUP BY user_id ), -- 3) derived per-user metrics required by the playbook user_metrics AS ( SELECT user_id, purchase_count, total_units, total_revenue, total_ad_spend, -- user lifetime in days within the 12-month window (inclusive) DATE_DIFF('day', first_purchase_ts, last_purchase_ts) + 1 AS user_lifetime_days, -- purchase frequency: purchases per active 30-day period (approx) CASE WHEN DATE_DIFF('day', first_purchase_ts, last_purchase_ts) >= 30 THEN purchase_count / (GREATEST(DATE_DIFF('day', first_purchase_ts, last_purchase_ts),1) / 30.0) ELSE purchase_count END AS purchase_frequency, -- purchase quantity per purchase CASE WHEN purchase_count > 0 THEN total_units / CAST(purchase_count AS DOUBLE) ELSE 0 END AS purchase_quantity, -- customer cost: currently only ad spend; retention_cost can be added to this field (total_ad_spend) AS customer_cost FROM user_purchases ), -- 4) cohort selection: cohort_month as a simple acquisition cohort; replace with channel or category as needed cohorted AS ( SELECT um.*, DATE_FORMAT(first_purchase_ts, '%Y-%m') AS cohort_month FROM user_metrics AS um ), -- 5) cohort-level means used to normalize into ratios cohort_stats AS ( SELECT cohort_month, AVG(purchase_frequency) AS avg_purchase_frequency, AVG(purchase_quantity) AS avg_purchase_quantity, AVG(user_lifetime_days) AS avg_user_lifetime_days, AVG(total_revenue) AS avg_revenue, AVG(customer_cost) AS avg_cost, COUNT(*) AS cohort_size FROM cohorted GROUP BY cohort_month ), -- 6) per-user ratios (Lifetime and Value components) ratios AS ( SELECT c.user_id, c.cohort_month, -- Lifetime Ratio = Purchase Frequency Ratio × Purchase Quantity Ratio × User Lifetime Ratio (COALESCE(c.purchase_frequency,0) / NULLIF(s.avg_purchase_frequency,0)) * (COALESCE(c.purchase_quantity,0) / NULLIF(s.avg_purchase_quantity,0)) * (COALESCE(c.user_lifetime_days,0) / NULLIF(s.avg_user_lifetime_days,0)) AS lifetime_ratio, -- Value side: revenue vs cost ratios (higher revenue and lower cost should increase value) (COALESCE(c.total_revenue,0) / NULLIF(s.avg_revenue,0)) AS revenue_ratio, (COALESCE(c.customer_cost,0) / NULLIF(s.avg_cost,1)) AS cost_ratio FROM cohorted c JOIN cohort_stats s USING (cohort_month) ), -- 7) per-user scores: lifetime_score (product) and value_score (revenue - cost composite) scores AS ( SELECT r.user_id, r.cohort_month, r.lifetime_ratio AS lifetime_score, (r.revenue_ratio - r.cost_ratio) AS value_score FROM ratios r ) -- Final: label users using global AVG(...) OVER () thresholds so both legs compare to the same population SELECT s.user_id, s.cohort_month, s.lifetime_score, s.value_score, CASE WHEN s.lifetime_score >= AVG(s.lifetime_score) OVER () AND s.value_score >= AVG(s.value_score) OVER () THEN 'High Value' WHEN s.lifetime_score >= AVG(s.lifetime_score) OVER () AND s.value_score < AVG(s.value_score) OVER () THEN 'Growth Potential' WHEN s.lifetime_score < AVG(s.lifetime_score) OVER () AND s.value_score >= AVG(s.value_score) OVER () THEN 'Revenue Potential' WHEN s.lifetime_score < AVG(s.lifetime_score) OVER () AND s.value_score < AVG(s.value_score) OVER () THEN 'Low Value' ELSE 'Unlabeled' END AS customer_segment FROM scores s; ``` I kept the SQL intentionally modular so the parts are pluggable into our pipeline. The agent used the composite formula from the "Lifetime * Value CLTV SQL Export Logic": Lifetime Ratio = Purchase Frequency × Purchase Quantity × User Lifetime ratios, and modeled value_score as a revenue-minus-cost composite so that higher revenue and lower cost increase value. Cohorting is done by first_purchase month as a placeholder; replace cohort_month with acquisition_channel or tracked_asin category if that's more meaningful for your ops. I also made two operational choices: use conversions_for_audiences for the canonical audience build exports and run the same query against conversions_all only when you need a sizing or coverage experiment. Finally, ensure the AVG(...) OVER () comparisons are computed over the same population so the thresholds are comparable. ## The footnotes the agent surfaced unprompted > **Agent footnotes added without asking** > - audiences ready for DSP activation have a 48-hour activation window. > - AMC long-term = one-year window; cohorts are bounded to 12 months. > - use percentile examples (e.g., top 71-100, ~748k out of 2.5M) and audience-size guardrails when creating RBA/LAL; avoid seed sizes below the platform minimum. > - AVG(lifetime_score) OVER () and AVG(value_score) OVER () must use the SAME population to produce comparable thresholds. > - run the year-over-year cohort migration check to spot cohorts moving from Growth Potential into High Value or sliding to Low Value. > - include non-ad-attributed conversions (Paid Features shopping insights) for a fuller revenue picture when available. ## What happens next - Export the four labeled audiences as rule-based audience manifests and activate into Amazon DSP with differentiated bidding: Higher bid for High Value, conversion-first creatives for Growth Potential, revenue-focused bids for Revenue Potential while excluding low-margin ASINs, and exclude or suppress Low Value audiences from high-cost buys. (See Swim Lane #3 and #4 from the Off-Amazon Conversions Playbook.) - Schedule this query as a recurring AMC job monthly, aligned to cohort_month granularity, and push audiences after respecting the 48-hour DSP activation window for resulting audiences. - Run the year-over-year diagnostic at the same cadence and produce cohort-migration charts that bucket users by percentile so you can detect movement between Growth Potential and High Value or slides toward Low Value. - For ops handoff: publish an audience manifest with Amazon Standard Identification Number (ASIN) category mappings, provide audience sizes and seed counts, and filter out cohorts under minimum seed thresholds before requesting DSP activation. Consider running overlap scoring against Persona Builder API outputs to avoid audience saturation. The full workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): [Amazon Ads MCP](/features/amazon-ads-mcp/) brings AMC and campaign signals, the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) can add catalog context for ASIN grouping, Atlas grounds the CLTV taxonomy, and [Skills](/features/skills/) turn the segment export into a reviewed recurring automation. ## Why this matters A foundation model can write CLTV-shaped SQL. What it cannot reliably do is produce a query that compiles against the AMC table variants Audiences actually accepts, uses the exact composite window-function pattern the CLTV playbook prescribes, labels users with the four-segment taxonomy operators downstream are already wired for, and bakes in the 48-hour activation window plus the year-over-year diagnostic. The agent didn't have to remember any of that. It had to know where to look. Composite Lifetime × Value cohorting. *Next guide in the series: moving from segmentation to actual bidding rules. What `amazon_rules` says you should do once you have a High Value cohort: [Path to conversion sankey](/guides/amc-path-to-conversion-sankey/).* ### Build High-Value AMC Audience Seeds URL: https://www.kuudo.com/guides/amc-high-value-audience-segmentation/ The Slack ping landed on a Thursday from our CRM lead: *"Who are our actual best customers, and can we build a demand-side platform (DSP) audience that targets people who look like them?"* It sounds like a five-minute question. Ask ChatGPT and you get a single "high value" SQL block, almost always a total-spend filter, usually against the wrong table variant, almost never inside the seed-size band [Amazon Marketing Cloud](/features/amc/) actually requires. Search the AMC console's Instructional Query library and you find the answer, except it lives in two separate playbooks you have to stitch together yourself. By the time you've reconciled them, the campaign launch has slipped a day. So I asked our agent. It runs on [Amazon Agent Atlas](/features/agent-atlas/), a curated corpus of AMC playbooks, DSP activation guides, and event-subtype references indexed for semantic retrieval. The answer came back in the shape the IQ library actually recommends: three seed audiences, tested separately, each sized into the 1,000 to 450,000 buffer before activation. ## What a model without Atlas gets wrong I ran the same prompt through a frontier model with no retrieval first. The SQL it produced looked competent. It would have failed at audience creation in at least four distinct ways. > **Five failure modes I saw in a single un-grounded response** > - It selected `user_id` from `conversions_all`. Audience-build queries that return user IDs must run against the `_for_audiences` variant, in this case `conversions_all_for_audiences`. The sizing wrapper does the opposite: it counts user IDs against `conversions_all`. The Atlas chunk is explicit, "change `user_id` to `count(user_id)`, remove the suffix of `_for_audiences` in the table name." > - It returned one blended seed that combined SnS, multi-purchase, and a spend threshold joined with `AND`. The result was an overly specific cohort of around 300 users. The IQ guidance is the opposite, "we recommend testing these audiences separately to avoid overly specific seeds." > - It hallucinated the event filter as `event_subtype = 'SnS'`. The real values are `event_subtype IN ('firstSnSOrder', 'repeatSnSOrder')`. The `repeatSnSOrder` value was added to Flexible Shopping Insights on 02/05/2024, so any model with a training cutoff before that date does not know it exists and will quietly miss every recurring SnS shipment. > - It said nothing about the 500 to 500,000 hard sizing bound. Audience refresh fails outside that range, silently for the operator until the DSP line item runs empty. > - It left a comment as the final line of the SQL. AMC's audience pusher rejects any query whose last line is a comment, with an error message that does not tell you which line. Any one of these would have cost the launch day. The combination would have looked like a working audience right up until the DSP line item failed to spend. ## What Atlas retrieves When the agent gets the question, it does a semantic search across the `amazon_ads` collection and pulls six chunks before writing a single line of SQL: - The **Introduction to AMC Lookalike Audiences** playbook, section 3.2, which enumerates the three high-value seed strategies (Subscribe and Save, Multiple Purchases, Total Purchase Value) and gives the verbatim recommendation to test them separately to avoid overly specific seeds. - The same **Introduction to AMC Lookalike Audiences** chunk on the companion measurement query template, the 500 to 500,000 hard bound, and the recommended 1,000 to 450,000 seed-size buffer. - The **Understanding Amazon's Subscribe & Save Repeat Purchases** chunk, which documents the `firstSnSOrder` and `repeatSnSOrder` event subtypes, the 02/05/2024 enhancement date when repeat signals were added, and the Sandbox restriction on SnS data. - The **Flexible Shopping Insights Trial Guide** chunk, which carries the working `conversions_all_for_audiences` template for the SnS seed and the audience-vs-sizing table-name swap pattern. - The **Identifying High Value Customer Segments** chunk, which frames Total Spend seeds through percentile rank (top 71-100, top 96-100) rather than a flat dollar threshold, and endorses these segments specifically as lookalike seeds. - The **AMC Lookalike Audiences for Promotional Events** chunk, which explains the gap lookalikes fill (the high-value new-to-brand and impulse buyers that DSP rule-based audiences miss) and warns against using lookalikes in the lead-out phase of a promotion. Atlas does not generate the SQL. It surfaces the playbooks with the right caveats attached, and the agent adapts them. ## The agent's output The agent returned four SQL blocks: three seed audience queries and one companion sizing wrapper. The seed queries go into the AMC Audiences query editor, the sizing wrapper runs in the main query editor against the non-`_for_audiences` table. ```sql -- ========================================================================= -- Companion measurement query (sizing): runs in the MAIN AMC query editor -- against conversions_all (not _for_audiences). Use this BEFORE pushing each -- seed to audience creation. Hard fail: <500 or >500,000. -- Recommended buffer: 1,000 to 450,000. -- ========================================================================= SELECT COUNT(user_id) AS user_count FROM ( {UPDATE: paste one of the three seed queries below here, but swap conversions_all_for_audiences -> conversions_all and SELECT DISTINCT user_id -> SELECT user_id } ) GROUP BY 1 -- ========================================================================= -- SEED 1: Subscribe & Save subscribers -- Run in the AMC AUDIENCES query editor (NOT the main editor) because it -- selects individual user_id values. -- STRIP ALL COMMENT LINES before pushing to audience creation. The trailing -- GROUP BY 1 at the very end is what makes the push succeed. -- ========================================================================= WITH sns_users AS ( SELECT user_id, COUNT(DISTINCT conversion_id) AS sns_purchase_times FROM conversions_all_for_audiences WHERE event_subtype IN ('firstSnSOrder', 'repeatSnSOrder') -- Optional: scope to your ASIN(s). Remove this AND clause to capture -- all SnS purchasers across the brand. AND tracked_asin IN ('{ASIN_1}', '{ASIN_2}') -- {UPDATE} or remove GROUP BY user_id ) SELECT DISTINCT user_id FROM sns_users WHERE sns_purchase_times >= 1 GROUP BY 1 -- ========================================================================= -- SEED 2: Multi-Purchase (users with multiple distinct ASIN orders) -- ========================================================================= WITH multi_asin_users AS ( SELECT user_id, COUNT(DISTINCT tracked_asin) AS distinct_asin_count FROM conversions_all_for_audiences WHERE event_subtype = 'order' AND tracked_asin IN ('{ASIN_1}','{ASIN_2}','{ASIN_3}') -- {UPDATE} GROUP BY user_id ) SELECT DISTINCT user_id FROM multi_asin_users WHERE distinct_asin_count >= 2 -- {UPDATE: raise to 3+ if seed > 450k} GROUP BY 1 -- ========================================================================= -- SEED 3: Total Spend threshold -- Threshold is configurable. Atlas recommends a percentile-rank approach -- (e.g., top 71-100 percentile) rather than a hardcoded dollar value. -- A flat dollar threshold is shown here for simplicity. -- ========================================================================= WITH spend_by_user AS ( SELECT user_id, SUM(purchase_amount) AS total_spend FROM conversions_all_for_audiences WHERE event_subtype = 'order' AND tracked_asin IN ('{ASIN_1}','{ASIN_2}','{ASIN_3}') -- {UPDATE} GROUP BY user_id ) SELECT DISTINCT user_id FROM spend_by_user WHERE total_spend >= {SPEND_THRESHOLD} -- {UPDATE: configurable, e.g., 200} GROUP BY 1 ``` Three queries, not one. The IQ library explicitly recommends testing these audiences separately to avoid overly specific seeds, and the math agrees: combining filters with `AND` collapses the overlap into a cohort that often falls under the 500-user hard bound. The operator runs all three through the companion sizing query first, confirms each lands in the 1,000 to 450,000 buffer, and only then optionally unions them. The agent does not start by unioning. The table name swaps between the seed and the sizing wrapper: `conversions_all_for_audiences` is required for the seed queries because AMC's audience builder only permits `SELECT user_id` against the `_for_audiences` table variants, while the sizing wrapper runs in the main query editor against the regular `conversions_all` table. The agent stages the swap inside the wrapper so the operator cannot paste the wrong table name into the wrong editor. The SnS filter includes both `firstSnSOrder` and `repeatSnSOrder`. Limiting to `repeatSnSOrder` alone would exclude users on their first scheduled subscription order, which is exactly the cohort you want to lookalike against. Both values together capture the full SnS-engaged audience that became available on 02/05/2024 when Flexible Shopping Insights was enhanced to include repeat purchase signals. The Multi-Purchase and Total Spend queries are not verbatim Atlas snippets. The agent adapted the SnS template pattern, swapping the WHERE filter to `event_subtype = 'order'` and the aggregation to either `COUNT(DISTINCT tracked_asin)` or `SUM(purchase_amount)` per user. The Total Spend threshold is a placeholder. The right number is corpus-specific. Atlas points at a percentile-rank approach (top 71-100 percentile, or the tighter top 96-100 for premium-spend seeds) rather than a hardcoded dollar value. The `{SPEND_THRESHOLD}` token in the SQL is operator-configurable, and the parenthetical "e.g., 200" is illustrative only, not a recommendation. ## The footnotes the agent surfaced unprompted This is the part that separates retrieval-grounded responses from fluent guesses. Without being asked, the agent attached a short list of caveats to the artifact. > **What Atlas surfaced that the operator didn't ask for** > - **Hard sizing bounds: 500 and 500,000.** Audience refresh fails if the seed size falls below 500 or above 500,000. Aim for the 1,000 to 450,000 buffer to keep refreshes alive as the cohort drifts. > - **Sandbox gap.** The `sns_subscription_id` field and the repeat SnS purchase signals are not available in AMC Sandbox. You cannot dry-run the SnS seed there. Run against production, or you will see zero rows and assume the seed is broken. > - **Version cliff on 02/05/2024.** Repeat SnS purchase signals were added to Flexible Shopping Insights on that date. Any model whose training data predates it will produce a SnS seed that returns zero rows. This is one of the cleanest examples of what Atlas catches that an ungrounded model cannot. > - **Comment-line trap.** Per the IQ playbook, we recommend removing all comment lines from the query before pushing to audience creation. The trailing `GROUP BY 1` works as a safe terminator because the audience pusher will not accept a query whose last line is a comment, but only if the comments above are also stripped. > - **Category eligibility.** Only certain product categories (Beauty, Grocery, and a handful of others) are eligible for Subscribe & Save. If your catalog sits outside those categories, the SnS seed will undersize regardless of how broad you make the ASIN filter. > - **Not for the lead-out phase.** Lookalike audiences are not appropriate for the lead-out phase of a promotional campaign, where the NTB mix shifts. For lead-out, switch to AMC rule-based audiences instead. Each of these would have cost the operator at least an hour to discover by hitting the failure first. ## What happens next Once each seed lands inside the 1,000 to 450,000 buffer, the operator pushes it to AMC Audiences from the Audiences query editor. AMC compiles the audience and activates it to Amazon DSP. The standard DSP activation lag is around 48 hours before the audience materializes and becomes targetable in line items, so the push has to land at least two days before the campaign launch, not on the day of. The agent also recommends setting each seed query as a recurring AMC workflow so the lookalike model rebuilds on a cadence. Weekly is typical for high-value cohorts, because the SnS seed in particular grows as repeat purchase signals accumulate week over week. Static lookalikes age out fast. For the DSP build, the agent targets each lookalike in a separate line item rather than stacking them in one. Three line items, one per seed, gives a clean read on NTB rate and return on ad spend (ROAS) by seed strategy after the first 14 days. The Total Spend lookalike usually wins on order value, the Multi-Purchase lookalike on order frequency, and the SnS lookalike on retention. Knowing which is which informs the next round of seeds. The full workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): [Amazon Ads MCP](/features/amazon-ads-mcp/) brings AMC and DSP signals, the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) can add catalog and Amazon Standard Identification Number (ASIN) context, Atlas grounds the seed rules, and [Skills](/features/skills/) keep each seed test on a reviewable cadence. ## Why this matters Three seeds, three sizes, one DSP activation: the difference between a good guess and a working audience. The seed strategies are not novel, but the constraints around them are, and most of those constraints are not in any single playbook. The agent's value is not that it wrote better SQL than a model could write from memory. The agent's value is that it pulled the right two playbooks, applied the right table swap, surfaced a six-month-old `event_subtype` that most models still do not know about, and attached the activation timing the operator needed before they hit it. If your agents are guessing at AMC high-value seeds, they don't have to be. --- *Part of an ongoing series on how agents grounded in Amazon Agent Atlas approach real AMC workflows. Next: [lookalike audiences for Prime Day](/guides/amc-lookalike-audience-prime-day/), taking these three seeds through the promotional-event activation playbook, including the lead-in versus lead-out split that determines whether a lookalike belongs in the line item at all.* ### Re-Engage Lapsed AMC Loyalists URL: https://www.kuudo.com/guides/amc-lapsed-customer-reengagement/ The Slack message landed during a retention review: *"We have customers who bought from us three or more times last year, and we haven't heard from them in 90 days. Can we get them into a demand-side platform (DSP) campaign before they churn for good?"* It sounds like a five-minute audience build. In practice the trap is in the tables, the lookback, and the size floor. [Amazon Marketing Cloud](/features/amc/) (AMC) Audiences uses a different set of tables than the main query editor. The lookback you actually want is a 180-day rolling window, not a calendar quarter. The audience won't activate at all if it resolves to fewer than 2,000 distinct users, and you find that out only after pushing it. So I asked our agent, which has [Amazon Agent Atlas](/features/agent-atlas/) behind it. Here is what came back. ## What a model without Atlas gets wrong I ran the same prompt through a frontier model with no retrieval. The response looked workable. It wasn't. > **Four failure modes in a single un-grounded response** > 1. It pulled from `conversions_all`. The Audiences editor only accepts the `_for_audiences` variants for `SELECT user_id` queries. The right table for this workflow is `conversions_all_for_audiences`, and pasting the un-suffixed name produces a "user_id not selectable" rejection in the AMC Audiences UI. > 2. It built the 180-day lookback by hardcoding `event_dt_utc >= CURRENT_DATE - INTERVAL '180 day'`. The Atlas playbook uses `TABLE(EXTEND_TIME_WINDOW('conversions_all_for_audiences', 'P180D', 'P0D'))`, which is the only construct that reaches outside the AMC Audiences query editor's default analysis window. Without it, your "180-day lookback" is silently truncated. > 3. It dropped the `exposure_type = 'non-ad-exposed'` filter. The lapsed-loyalist audience is the one Atlas explicitly recommends building from organic repeat buyers, customers who came back on their own. Without the filter, the audience scoops up everyone you already retargeted, which is exactly the population you don't need to spend on. > 4. It didn't mention the 2,000-user activation floor. AMC Audiences refuses to push an audience smaller than 2,000 distinct users to Amazon DSP. The query returns no error in that case; the audience appears to compile, then quietly fails to land in DSP. You discover the floor by missing a campaign launch. Every one of these would have produced a query that runs without complaint and an audience that never activates. The combination would have eaten a week of debugging. ## What Atlas retrieves When the agent gets the question, it does a semantic search across the `amazon_ads` collection and pulls a handful of chunks before writing any SQL: - The **Flexible Shopping Insights Trial Guide**, section 4.2 "Engage lapsed customers": the canonical AMC template for exactly this workflow, complete with the `EXTEND_TIME_WINDOW` lookback, the `conv_cnt > 2` filter on repeat purchases, and the `BUILT_IN_PARAMETER('TIME_WINDOW_START')` exclusion that defines "haven't bought recently." - The **AMC Audiences table-variant rule**, indexed from "Creating an Audience for Wishlist or Registry Additions": why `conversions_all_for_audiences` is the only table that permits `SELECT user_id`, and the suffix pattern that distinguishes Audiences-editor tables from main-editor tables. - The **Engage non-ad-exposed audience** section of the same FSI Trial Guide: the sister query in section 4.1 that establishes the `count(user_id)` sizing trick, run in the main editor against the un-suffixed table, before any audience is pushed. - The **Introduction to AMC Lookalike Audiences** playbook: the downstream activation path if the seed turns out to be too small to use directly, with the 500-to-500,000 lookalike seed constraint and the model-expansion behavior. Atlas doesn't generate the SQL. It surfaces the playbook with its constraints intact, and the agent adapts the template to the operator's hero ASINs and window. ## The agent's output Here is the audience query the agent produced. It pastes directly into the AMC Audiences query editor, uses the 180-day extended window, and filters to customers with three or more organic purchases who have gone silent inside the current analysis window: ```sql -- Audience Instructional Query: Re-engage lapsed three-time buyers -- Source: AMC FSI Trial Guide, section 4.2 "Engage lapsed customers" -- Run in: AMC Audiences query editor (not the main editor) -- Table: conversions_all_for_audiences (_for_audiences variant required) WITH purchase AS ( -- Count distinct organic conversions per user over the trailing 180 days, -- and capture each user's most recent purchase date. SELECT user_id, COUNT(DISTINCT conversion_id) AS conv_cnt, MAX(event_date_utc) AS event_max FROM TABLE(EXTEND_TIME_WINDOW('conversions_all_for_audiences', 'P180D', 'P0D')) WHERE event_subtype = 'order' AND exposure_type = 'non-ad-exposed' AND user_id IS NOT NULL GROUP BY user_id ), multiple_purchase AS ( -- Keep only the customers with three or more organic orders in the lookback. SELECT user_id, event_max FROM purchase WHERE conv_cnt > 2 ) -- Final seed: three-plus buyers whose most recent order predates the analysis -- window. With a 90-day window, that means no purchase in the last 90 days. SELECT user_id FROM multiple_purchase WHERE user_id NOT IN ( SELECT user_id FROM multiple_purchase WHERE event_max > BUILT_IN_PARAMETER('TIME_WINDOW_START') ) ``` Three things to notice about what the agent chose to do. First, the lookback uses `EXTEND_TIME_WINDOW('conversions_all_for_audiences', 'P180D', 'P0D')`, not a hand-rolled date filter. Inside the AMC Audiences editor, the default analysis window is shorter than the 180 days this audience needs, and `EXTEND_TIME_WINDOW` is the only mechanism that opens it. The `P180D` is an ISO-8601 duration; `P0D` means the window ends at the current analysis-window boundary. The agent inherited this directly from the FSI playbook. The `exposure_type = 'non-ad-exposed'` filter is the entire point of the audience. The retention lead wanted organic loyalists, the customers who came back without seeing ads, because those are the ones whose silence is a churn signal rather than ad fatigue. Without the filter, the seed is contaminated with customers you've already retargeted, and the DSP campaign you build from it overlaps with campaigns you're already running. Finally, the lapsed condition is expressed as a `NOT IN` against the same `multiple_purchase` CTE, gated on `BUILT_IN_PARAMETER('TIME_WINDOW_START')`. That parameter resolves to the start of the analysis window the operator sets in the editor, so a 90-day analysis window automatically defines "lapsed" as "no order in the last 90 days." Change the window in the editor, and the lapsed definition shifts with it. No code edits required. ## The footnotes the agent surfaced unprompted This is the part that separates a retrieval-grounded response from a fluent guess. Without being asked, the agent attached a short list of things the retention lead needed to know but didn't think to ask about: > **What Atlas surfaced that the operator didn't ask for** > - **Size the audience before you push it.** AMC Audiences refuses to activate any audience under 2,000 distinct users. Run the query in the main editor first with `user_id` swapped for `count(user_id)` and the `_for_audiences` suffix removed from the table name; that returns the seed size without creating anything. > - **Loosen the conditions when the floor isn't met.** The FSI playbook calls out the relaxation order explicitly: change `conv_cnt > 2` to `conv_cnt > 1` first (two-plus buyers instead of three-plus), then extend the lookback from 180 to 270 days. Both are documented adjustments, not hacks. > - **Don't end the query on a comment line.** AMC's audience editor rejects any submission whose last non-blank line is a `--` comment. Strip trailing annotations before pasting, or the editor will swallow the query without a useful error. > - **`event_subtype = 'order'` is required.** `conversions_all_for_audiences` carries every conversion subtype Amazon tracks, not just purchases. Without the `'order'` filter, detail-page views, wishlist adds, and Subscribe & Save subscription events count toward the `conv_cnt` and inflate the seed with users who never actually bought. > - **Flexible Shopping Insights is a paid feature.** The `exposure_type` column and the non-ad-exposed signal only populate when FSI is enabled on the AMC instance. Without it, the filter returns zero rows and the audience appears empty for reasons the editor will not surface. Any one of these would have cost the operator a half-day to discover. The compounding effect is why this kind of audience normally takes a week to ship and not an afternoon. ## What happens next Once the seed sizes above 2,000 users, the agent flips into activation mode and routes the audience through the standard AMC Audiences-to-DSP path: paste the query into the Audiences editor, push it to a named audience, wait for the activation window to close, and verify the audience appears as targetable in Amazon DSP. If the seed comes back undersized even after both relaxations, the agent recommends pivoting to AMC Lookalike Audiences, using the lapsed loyalists as a seed (even a small one) and letting the lookalike model expand it. That path uses the same workflow we walked through for [cart abandoners](/guides/amc-cart-abandoner-audience/), but with the loyalist seed in place of the cart-abandoner seed and a 500-to-500,000 lookalike size band instead of the 2,000-user activation floor. Either way, the agent doesn't stop at SQL: it carries the audience to the activation handoff and tells you which path it took and why. The full workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): [Amazon Ads MCP](/features/amazon-ads-mcp/) brings AMC and DSP signals, the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) can add catalog context, Atlas grounds the lapsed-loyalist rules, and [Skills](/features/skills/) keep the reengagement audience on a reviewed refresh cadence. ## Why this matters The lapsed-loyalist workflow is the kind of audience build that is easy to ask for, hard to ship, and impossible to debug after the fact. The query has to use the right table variant, the right time-window construct, the right exposure filter, and the right size floor; miss any one of them and the audience either fails to compile, fails to activate, or activates against the wrong population. None of this is exotic knowledge, but it lives in four different sections of two different playbooks, and a model without retrieval has to guess at all of it. If your retention agents are guessing at AMC Audiences, they don't have to be. --- *Part of an ongoing series on how agents grounded in Amazon Agent Atlas approach real AMC workflows. Next: turning a too-small loyalist seed into an activated audience through [AMC Lookalike Audiences](/guides/amc-cart-abandoner-audience/), and the rules the lookalike model uses to expand a seed without diluting it.* ### Build Prime Day AMC Lookalikes URL: https://www.kuudo.com/guides/amc-lookalike-audience-prime-day/ The Slack message landed six weeks before Prime Day: *"Can we build a lookalike audience of customers similar to our best buyers, sized correctly so it actually activates?"* This sounds like one SQL query. It is really four decisions: which customers count as "best," which [Amazon Marketing Cloud](/features/amc/) table variant allows `SELECT user_id`, which Amazon Standard Identification Number (ASIN) filters belong in the seed, how large the seed can be before the lookalike model refuses it, and how to size the seed before spending two days waiting on a refresh. Get one of those wrong and the audience either fails silently or trains on the wrong population. So I asked our agent. The agent has [Amazon Agent Atlas](/features/agent-atlas/) behind it: a corpus of AMC playbooks, instructional queries, and audience patterns indexed for semantic retrieval. Here's what came back. ## What a model without Atlas gets wrong in AMC lookalike seed generation I ran the same prompt through a frontier model with no retrieval. The output was confident, would have compiled in the wrong query editor, and was wrong about every threshold that decides whether the audience activates. > **Five failure modes in the un-grounded response** > 1. It picked one seed definition, "top 20% of spenders," and committed to it. The actual playbook recommends three distinct seed strategies tested separately first: Subscribe & Save (SnS) subscribers, multi-ASIN purchasers, and a total-spend threshold. > 2. It quoted a seed size minimum of "a few thousand users" and no upper bound. The real guardrail is specific: the seed should contain between 500 and 500,000 distinct `user_id` values. > 3. It wrote the seed query against `conversions` and used `SELECT DISTINCT user_id` in the outer query. AMC Audiences requires the `_for_audiences` table family, specifically `conversions_for_audiences`, for this seed shape. > 4. It did not size the seed before submission. The playbook has a companion measurement query that runs in the main editor against `conversions_all` and returns the seed count before the audience refresh starts. > 5. It ended the query on a `--` comment line. AMC Audiences can reject submissions whose last line is a comment, so the template intentionally ends on executable SQL. None of these failures look wrong on a casual read. They are the kind of mistakes you catch after submitting an audience, waiting for refresh, and watching the status sit there. ## What Atlas retrieves for an AMC Prime Day lookalike audience When the agent gets the question, it does a semantic search across the `amazon_ads` collection and pulls five chunks before writing a line of SQL: - The **AMC Lookalike Audiences for Promotional Events** playbook, version-tagged `2023-10-01`: the canonical Prime Day and Black Friday workflow covering ASIN selection, seed creation, flight-time analysis, and activation. - The **Introduction to AMC Lookalike Audiences** instructional query (IQ): the mechanics behind seed scoring, the five expansion types, and the three-seed template for high-value customers. - The **Companion measurement query** chunk from the lookalike audiences IQ: the `SELECT COUNT(user_id) FROM (...)` pattern that runs in the main AMC editor. - The **Creating Audiences Based on High Value Customer Segments** playbook: the percentile-rank variant for "top X% by spend" seeds. - The **Flexible Shopping Insights Trial Guide** Section 5: SnS-specific seed patterns, including `firstSnSOrder` and `repeatSnSOrder` event subtype notes for advertisers with Flexible Shopping Insights (FSI). The agent does not invent the SQL. It surfaces the right template with the right caveats, then adapts it. ## Seed strategies and expansion types for AMC lookalike audiences The playbook gives the operator two taxonomies to make explicit before submission. | Taxonomy | Option | When to use it | |----------|--------|----------------| | Seed strategy | SnS subscribers | Use when repeat subscription behavior is the clearest signal of loyalty. | | Seed strategy | Multi-ASIN purchasers | Use when cross-catalog buying is more important than a single-product purchase. | | Seed strategy | Total spend threshold | Use when revenue concentration matters more than purchase frequency. | | Expansion type | Most Similar | Start here when performance matters more than reach. | | Expansion type | Similar | Use when the seed is strong but the campaign needs more scale. | | Expansion type | Balanced | Practical default for Prime Day prospecting when you need both reach and relevance. | | Expansion type | Broad | Use when the seed is valid but projected audience size is too constrained. | | Expansion type | Most Broad | Use for reach-first testing, not for the first high-efficiency launch. | This block matters because it prevents the model from collapsing three separate operator decisions into one vague "high-value lookalike" audience. ## The agent's working output: AMC seed SQL for Subscribe & Save The agent produced two artifacts. First, the seed query, lifted from the three-seed template in the **Introduction to AMC Lookalike Audiences** instructional query with the optional clauses set for the SnS strategy: ```sql /* Audience instructional query: Introduction to lookalike audiences (High Value Customers) Run in the AMC Audiences query editor, not the main editor. Last verified: 2026-05-13. Three seed strategies are supported below. Test them separately first: [1 of 4]: ASIN filter [2 of 4]: SnS subscribers [3 of 4]: Multi-ASIN purchasers [4 of 4]: Total purchase value threshold Keep the final GROUP BY 1 as executable SQL so the query does not end on a comment line. */ WITH user_sales_cte AS ( SELECT user_id, CASE WHEN event_subtype = 'snsSubscription' THEN 1 ELSE 0 END AS sns_flag, SUM(total_units_sold) AS total_purchases, SUM(total_product_sales) AS total_product_sales, COUNT(DISTINCT tracked_item) AS unique_items_purchased FROM conversions_for_audiences WHERE event_subtype IN ('snsSubscription', 'order') /* AND tracked_asin IN ('B0HERO0001','B0HERO0002') */ AND user_id IS NOT NULL GROUP BY 1, 2 ), user_aggregate AS ( SELECT user_id, CASE WHEN unique_items_purchased > 1 THEN 1 ELSE 0 END AS multi_purchase_flag, MAX(sns_flag) AS sns_flag, SUM(total_purchases) AS total_purchases, SUM(total_product_sales) AS total_product_sales, SUM(unique_items_purchased) AS unique_items_purchased FROM user_sales_cte GROUP BY 1, 2 ), audience_grouping AS ( SELECT user_id, sns_flag, MAX(multi_purchase_flag) AS multi_purchase_flag, SUM(total_purchases) AS total_purchases, SUM(total_product_sales) AS total_product_sales, SUM(unique_items_purchased) AS unique_items_purchased FROM user_aggregate GROUP BY 1, 2 ) SELECT user_id FROM audience_grouping WHERE sns_flag = 1 -- AND multi_purchase_flag = 1 -- AND total_product_sales >= 250 GROUP BY 1; ``` The `event_subtype IN ('snsSubscription', 'order')` filter keeps the inner CTE focused on purchase behavior. That prevents cart additions, wishlist saves, or other engagement events from diluting the seed. Filtering there is cheaper and cleaner than trying to fix the population at the final `WHERE`. The `audience_grouping` CTE looks redundant, and the agent kept it anyway. The playbook leaves that pass in place because the model trainer expects a clean row-grain. Stripping it can still work, but the failure mode is opaque enough that the safer version is worth the extra CTE. The optional clauses stay visible because the operator should run SnS, multi-ASIN, and spend-threshold seeds separately before combining anything. Pre-baking that comparison into the template matches the way operators actually test seeds. ## How to size an AMC seed audience before submission Before submitting any seed to AMC Audiences, the agent produced the sizing companion. This is the part the un-grounded model skipped. ```sql /* Companion measurement query. Run in the main AMC query editor, not the Audiences editor. Last verified: 2026-05-13. Change conversions_for_audiences to conversions_all for sizing. Keep SELECT user_id inside the subquery; COUNT() wraps it outside. */ SELECT COUNT(user_id) AS user_count FROM ( WITH user_sales_cte AS ( SELECT user_id, CASE WHEN event_subtype = 'snsSubscription' THEN 1 ELSE 0 END AS sns_flag, SUM(total_units_sold) AS total_purchases, SUM(total_product_sales) AS total_product_sales, COUNT(DISTINCT tracked_item) AS unique_items_purchased FROM conversions_all WHERE event_subtype IN ('snsSubscription', 'order') AND user_id IS NOT NULL GROUP BY 1, 2 ), user_aggregate AS ( SELECT user_id, MAX(sns_flag) AS sns_flag FROM user_sales_cte GROUP BY 1 ) SELECT user_id FROM user_aggregate WHERE sns_flag = 1 ) GROUP BY 1; ``` The query returns one number: the distinct `user_id` count of the seed. If it is under 500, the audience refresh can fail. If it is over 500,000, the refresh can also fail. The practical habit is to stay comfortably inside the band so a seasonal data swing does not push the audience across either edge. The diagnostic table above is the operator checkpoint. The fourth row, `Total spend >= $500` returning 470 users, is the negative result that saves the most time. Without the sizing companion, the operator would discover that failure only after submitting the audience. ## The footnotes the agent surfaces for AMC Audiences This is the part that separates an Atlas-grounded agent from a fluent one. The agent did not wait to be asked. It surfaced the caveats the operator was about to need: > **Things Atlas surfaced that the operator did not ask for** > 1. **Seed size has hard boundaries.** The seed should contain 500 to 500,000 `user_id` values. Always run the sizing query first. > 2. **Test the three seed strategies separately.** Combining SnS, multi-ASIN, and spend thresholds too early can create a seed that is technically valid but strategically empty. > 3. **Expansion type is a decision, not a default.** Balanced is a practical starting point, but Most Similar, Similar, Broad, and Most Broad change the reach-performance tradeoff. > 4. **Lookalikes address the non-ad-exposed gap.** Rule-based audiences are useful for remarketing; Prime Day prospecting usually needs users who share seed traits but were not already in the ad-exposed pool. > 5. **The query should not end on a comment line.** Keep an executable final line such as `GROUP BY 1`. > 6. **The promotional-event variant uses a fixed window.** For Prime Day, the API payload should use the prior promotional window rather than a rolling relative window. Any one of these can eat an afternoon after submission. Getting all six before the first API call is the difference between a day-one launch and a day-three debugging thread. ## What happens next: submit the AMC Audiences API payload The seed query, sizing query, and diagnostic table close the loop on creation but not activation. The next move is to flatten the chosen seed SQL into an AMC Audiences API payload, submit it with `audienceName`, `advertiserId`, `timeWindowStart`, `timeWindowEnd`, `refreshRateDays`, `timeWindowRelative`, and `lookalikeAudienceExpectedReach`, then wait for the audience to become available for Amazon demand-side platform (DSP) activation. For Prime Day, `timeWindowRelative` should be `false` because the seed is tied to a fixed promotional window. `refreshRateDays: 7` keeps the audience fresh without turning the seed into a rolling interpretation of last year's event. `lookalikeAudienceExpectedReach: "BALANCED"` is a defensible first pass because it gives the team enough scale to test without starting at the loosest expansion setting. The evaluation pass comes after activation. Compare the lookalike audience against last year's rule-based audience baseline, then decide whether to keep the SnS seed, rotate to multi-ASIN purchasers, or loosen the spend threshold. The full workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): [Amazon Ads MCP](/features/amazon-ads-mcp/) brings AMC and DSP signals, the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) can add catalog and ASIN context, Atlas grounds the sizing and payload rules, and [Skills](/features/skills/) keep the audience refresh reviewable. ## Why this matters for Prime Day audience activation A lookalike audience that fails silently is worse than no audience. The operator has staged creative and media against an audience assumption, and the refresh can still be pending when the event opens. The rules that decide success are knowable, but they are scattered across a playbook, an instructional query, an API reference, and paid-feature notes. Atlas is not a model upgrade. It is the corpus made available at the moment of need. The agent did not have to remember the 500-to-500,000 band, the `_for_audiences` suffix rule, the fixed-window payload, or the comment-line restriction. It looked them up. If your agents are guessing at AMC seed sizes, they do not have to be. *Next: use the [lookalike evaluation workflow](/guides/amc-lookalike-audience-evaluation/) to test whether the shipped audience outperformed the rule-based audience from the previous Prime Day.* ### Build an AMC Cart-Abandoner Audience URL: https://www.kuudo.com/guides/amc-cart-abandoner-audience/ The Slack message came in on a Tuesday: *"Can you build me a demand-side platform (DSP) audience of people who added one of our hero Amazon Standard Identification Numbers (ASINs) to cart in the last 30 days but never bought? I want to retarget them before the next promotion."* This is the kind of ask that should take ten minutes. In practice, it eats an afternoon - not because the SQL is hard, but because [Amazon Marketing Cloud](/features/amc/) has a dozen quiet rules that aren't in any one place. The query has to hit the right table. The user-level fields have to come from the variant table that AMC Audiences will actually accept. The seed has to land between 500 and 500,000 users or the audience refresh fails silently. Attribution windows have to close before the numbers stop lying to you. So I asked our agent instead. The agent has [Amazon Agent Atlas](/features/agent-atlas/) behind it - a curated corpus of AMC playbooks, instructional queries, audience patterns, and decision rules indexed for semantic retrieval. Here's what came back. ## What a model without Atlas gets wrong I tested this same prompt against a frontier model with no retrieval. The response looked confident. It wasn't. > **Four failure modes in a single un-grounded response** > 1. It pulled from `conversions` instead of `conversions_for_audiences`. AMC Audiences requires the `_for_audiences` table variants - they're the only ones that permit `SELECT user_id`. Pasting the wrong one into the Audiences query editor produces a "user_id not selectable" error that doesn't tell you which table to switch to. > 2. It used `event_type = 'add_to_cart'`. The real value is `event_subtype = 'shoppingCart'`. Close enough to look right; wrong enough to return zero rows. > 3. It didn't mention the seed-size constraint. An audience that resolves to 380 users will *appear* to compile and then quietly fail to activate. > 4. It didn't mention the 48-hour activation lag in Amazon DSP. The operator was planning to launch retargeting "tomorrow." None of this is exotic knowledge. It's all in Amazon's public docs. But it's scattered across a dozen pages, half of which surface in search rankings only when you already know what to type. ## What Atlas retrieves When the agent gets the question, it does a semantic search across the `amazon_ads` collection and pulls four chunks before it writes a single line of SQL: - The **Audience that added to cart but did not purchase** instructional query - the canonical AMC template for this exact use case - The **AMC Audiences table-variant rule** - why `conversions_for_audiences` is the only table that allows `SELECT user_id`, and the corresponding `_for_audiences` suffix pattern across other AMC datasets - The **AMC Audiences activation guide** - the 500 to 500,000 seed-size constraint and the ~48-hour DSP activation window - The **Introduction to AMC Audiences companion measurement query** - the trick of changing `user_id` to `COUNT(user_id)` and dropping the `_for_audiences` suffix to size your audience *before* you try to create it Atlas doesn't generate the SQL. It surfaces the playbook, and the agent adapts it. ## The agent's output Here's the query the agent produced. It compiled on the first try and resolved to a seed of just over 12,000 users - comfortably inside the activation window: ```sql /* AMC Audiences IQ: Added to cart but did not purchase Adapted for hero-ASIN retargeting, 30-day window. Run in the AMC Audiences query editor (not the main editor) - _for_audiences table variants are required for SELECT user_id. */ WITH asins (asin) AS ( VALUES ('B0XXXXXXX1'), -- hero ASIN #1 ('B0XXXXXXX2'), -- hero ASIN #2 ('B0XXXXXXX3') -- hero ASIN #3 ), purchase AS ( SELECT user_id, MAX(event_dt_utc) AS purchase_dt_max FROM conversions_for_audiences WHERE event_subtype = 'order' AND tracked_item IN (SELECT asin FROM asins) GROUP BY 1 ), atc AS ( SELECT user_id, MAX(event_dt_utc) AS atc_dt_max FROM conversions_for_audiences WHERE event_subtype = 'shoppingCart' AND tracked_item IN (SELECT asin FROM asins) GROUP BY 1 ) SELECT atc.user_id FROM atc LEFT JOIN purchase ON atc.user_id = purchase.user_id WHERE atc_dt_max > purchase_dt_max OR purchase_dt_max IS NULL; ``` Three things to notice about what the agent chose to do: - The **ASIN filter is in the CTEs, not the final `SELECT`**. Filtering at the CTE level is the difference between a query that scans a focused slice of the conversions table and one that scans everything and discards 99% of it. AMC's compute budget isn't infinite, and the Atlas playbook flagged this explicitly. - The **`OR purchase_dt_max IS NULL`** clause matters. Without it, the audience would only include people who *previously* bought and then abandoned again, missing every first-time prospect who added to cart and walked. The agent inherited this from the AMC IQ template, which spells out the join semantics. - The **outer query is a plain `SELECT user_id`**, not `SELECT DISTINCT`. AMC Audiences expects user IDs and de-duplicates internally. Adding `DISTINCT` doesn't help performance and occasionally trips the audience compiler. ## The companion sizing query - run this first Before the agent suggested pushing the audience to DSP, it produced a sizing check. This is the part most ad-hoc workflows skip, and it's why most "build me an audience" requests fail their first activation: ```sql /* Audience sizing check - run this in the MAIN AMC query editor (not Audiences). Note the table name change: conversions_all, not conversions_for_audiences. */ SELECT COUNT(DISTINCT atc.user_id) AS audience_size FROM ( SELECT user_id, MAX(event_dt_utc) AS atc_dt_max FROM conversions_all WHERE event_subtype = 'shoppingCart' AND tracked_item IN ('B0XXXXXXX1','B0XXXXXXX2','B0XXXXXXX3') GROUP BY 1 ) atc LEFT JOIN ( SELECT user_id, MAX(event_dt_utc) AS purchase_dt_max FROM conversions_all WHERE event_subtype = 'order' AND tracked_item IN ('B0XXXXXXX1','B0XXXXXXX2','B0XXXXXXX3') GROUP BY 1 ) purchase ON atc.user_id = purchase.user_id WHERE atc.atc_dt_max > purchase.purchase_dt_max OR purchase.purchase_dt_max IS NULL; ``` If this returns less than 500, the audience won't activate. If it returns more than 500,000, the audience won't refresh. The agent knows both thresholds and tells you to widen or tighten the ASIN list accordingly. ## The footnotes the agent surfaced unprompted This is the part that separates a retrieval-grounded agent from a fluent one. Without being asked, the agent included a short list of things the operator needed to know but didn't think to ask about: > **Things Atlas surfaced that the operator didn't ask for** > - **Seed size: 500 to 500,000.** Outside that range, the audience either refuses to activate or refuses to refresh. Always run the sizing query first. > - **DSP activation lag: ~48 hours.** Build the audience two days before the campaign launch, not the day of. > - **Sandbox limitations.** AMC Sandbox doesn't populate certain event types reliably - including some Subscribe & Save signals. For audience work, run against production. > - **Comment-line restriction.** AMC Audiences queries cannot end on a comment line. Strip trailing `--` annotations before pushing to audience creation, or the editor will reject the query. > - **Upstream variants.** Swap `event_subtype = 'shoppingCart'` for `'detailPageView'` to reach further up the funnel, or for `'wishlist'` to capture lower-intent interest. The agent will adjust the seed-size expectations accordingly. Any one of these would have cost the operator an hour to discover. The compounding effect is why the workflow took ten minutes instead of an afternoon. ## What happens next The agent doesn't stop at SQL. Once the audience compiles and the sizing check passes, Atlas's activation playbook covers the next two hops: pushing the audience definition to AMC Audiences from the Audiences query editor, waiting for the activation window to close, and verifying the audience appears as targetable in Amazon DSP. The agent also flags that the audience is *static at creation time* - it doesn't auto-refresh as new users add to cart. For a retargeting program you'd want to run continuously, the agent recommends scheduling the audience as a recurring AMC workflow with a 7-day refresh cadence, and points to the corresponding Atlas playbook chunk on workflow scheduling. The full workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): [Amazon Ads MCP](/features/amazon-ads-mcp/) brings AMC and DSP context, the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) can add catalog and ASIN context, Atlas grounds the audience rules, and [Skills](/features/skills/) keep the refresh cadence reviewable. That's the loop closed: ask, retrieve, build, size, activate, monitor. ## Why this matters A foundation model can write SQL. So can a junior analyst with a textbook. What neither can reliably do is produce a query that compiles against the specific table variants AMC exposes, respects the seed-size constraints DSP enforces, and bakes in the timing assumptions Amazon's attribution model requires - all without being told to. Atlas isn't a magic upgrade to model capability. It's a corpus of *Amazon's own playbook content*, indexed and addressable by an agent at the moment of need. The agent doesn't have to remember any of this. It has to know where to look. That's a lower bar - and a much more reliable one. If your agents are guessing at AMC, they don't have to be. --- *This is the first in a series on how agents grounded in Amazon Agent Atlas approach real Amazon Marketing Cloud workflows. Next: [building a Subscribe & Save lift analysis](/guides/amc-subscribe-and-save-lift/) that quantifies the spend gap between subscribers and one-off buyers, including the February 2024 `repeatSnSOrder` signal that most ungrounded models still don't know exists.* ### Measure Subscribe & Save Lift in AMC URL: https://www.kuudo.com/guides/amc-subscribe-and-save-lift/ The question came up in a quarterly review: *"Is Subscribe & Save actually doing anything for us, or are we just discounting the same customers who would have bought anyway?"* It's the kind of question that sounds answerable in five minutes and isn't. Amazon's Subscribe & Save program - auto-replenishment with a small discount - generates a stream of conversion events that look like ordinary purchases in most reports. The standard Sponsored Ads reporting doesn't separate them. Brand Analytics doesn't separate them. The Business Reports in Seller Central treat an SnS unit the same as a one-off unit. To actually measure SnS lift - the spend gap between subscribers and one-off buyers - you have to query [Amazon Marketing Cloud](/features/amc/), against the right tables, with the right event subtypes, over the right window. So I asked our agent. The agent has [Amazon Agent Atlas](/features/agent-atlas/) behind it, and Atlas has the AMC Flexible Shopping Insights playbook indexed in full. Here's what came back. ## What a model without Atlas gets wrong I ran the same prompt through a frontier model with no retrieval. The output was confident and wrong in a way that would have looked right until the numbers didn't make sense. > **Four things the un-grounded model missed** > 1. It didn't know `repeatSnSOrder` exists. Amazon added this `event_subtype` to Flexible Shopping Insights on **February 5, 2024**. Without it, you only count the initial subscription event and the first SnS purchase - missing every recurring shipment, which is where the actual lift lives. Most models' training data predates this change, so they confidently produce queries that undercount SnS revenue by 60–80%. > 2. It used `conversions` instead of `conversions_all`. AMC has multiple conversion tables and they don't carry the same fields. `conversions_all` is the table Flexible Shopping Insights writes the SnS signals to. > 3. It didn't mention that Flexible Shopping Insights is a **paid AMC feature** with regional availability. Running the query without an active FSI subscription returns empty results with no error - the table exists but contains no SnS rows for your account. > 4. It quoted a 30-day analysis window. The playbook recommends a **minimum of 3 months** to capture SnS cadence, because subscription cycles run on 1, 2, 3, or 6-month schedules and a 30-day query misses the majority of repeat orders entirely. Any one of these would silently corrupt the lift number. The combination would tank a quarterly business case. ## What Atlas retrieves When the agent gets the question, it does a semantic search across the `amazon_ads` collection and pulls four chunks before writing any SQL: - The **Subscribe and Save repeat purchases** instructional query - the canonical AMC template, version-tagged `2024-02-05` - The **Flexible Shopping Insights trial guide** - the surrounding context on which AMC tables FSI writes to and which event subtypes are exposed - The **FSI access requirements note** - that FSI is a paid feature with regional restrictions, and Sandbox doesn't populate the repeat-SnS signals reliably - The **AMC query window guidance** - the 3-month minimum recommendation, the ASIN filter performance tip, and the join-grain rules for analyses that span event-level and weekly aggregations Atlas doesn't write the SQL. It surfaces the right playbook with the right caveats, and the agent adapts. ## The agent's output Here's the lift comparison query the agent produced. It runs against the main AMC query editor (not the Audiences editor - we're measuring, not building an audience), uses the three event subtypes that together capture the full SnS lifecycle, and treats every other purchaser as the comparison group: ```sql -- Subscribe & Save lift: average spend by user type -- Source: AMC IQ "Subscribe and save repeat purchases" (v 2024-02-05) -- Run window: last full 90 days (set Date range in Query Editor) -- Table: conversions_all (main editor, not _for_audiences) SELECT CASE WHEN event_subtype IN ( 'snsSubscription', -- initial subscription event 'firstSnSOrder', -- first scheduled order after subscribing 'repeatSnSOrder' -- recurring orders (added 2024-02-05) ) THEN 'subscriber' ELSE 'non-subscriber' END AS user_type, COUNT(DISTINCT user_id) AS users_that_purchased, SUM(total_product_sales) AS total_sales, SUM(total_product_sales) / COUNT(DISTINCT user_id) AS average_spend_per_user FROM conversions_all WHERE tracked_item IN ( 'B0XXXXXXX1', 'B0XXXXXXX2', 'B0XXXXXXX3' -- restrict to ASINs in SnS program for perf ) GROUP BY 1 ORDER BY 1; ``` Three things to notice about what the agent chose to do: - The **three event subtypes are an `IN` list, not a chain of `OR`s**. The IQ template uses this exact pattern because it's the most readable way to express "any of these three states means the user is in the subscriber bucket." If you swap in `event_subtype = 'snsSubscription' OR event_subtype = 'firstSnSOrder'`, you'll get the same result and a query that's harder to maintain, and a future you will forget which subtypes you included. - The **ASIN filter goes in the `WHERE` clause of the main query**, not in a CTE. SnS lift analyses are usually run against the subset of your catalog that's actually enrolled in the SnS program; there's no reason to scan the rest of conversions_all and discard 90% of it. The Atlas playbook explicitly flags this as a performance pattern. - The **comparison bucket is "every other purchaser,"** not "purchasers who explicitly opted out of SnS." Amazon doesn't expose an opt-out signal; the inverse of an SnS subscriber is just any user whose purchase event doesn't carry one of the three SnS event subtypes. The agent inherited this from the IQ template and didn't try to over-engineer it. ## The companion ASIN-level query The lift number is the headline, but the question that follows it is always *"which Amazon Standard Identification Numbers (ASINs) are pulling their weight in SnS?"* - and the playbook has a companion query for exactly that: ```sql -- SnS purchases by ASIN: volume + percentage of total purchases -- Run alongside the lift query, same window, same ASIN scope WITH sns AS ( SELECT tracked_item AS asin, COUNT(*) AS sns_purchases FROM conversions_all WHERE event_subtype IN ('firstSnSOrder', 'repeatSnSOrder') AND tracked_item IN ('B0XXXXXXX1','B0XXXXXXX2','B0XXXXXXX3') GROUP BY 1 ), total AS ( SELECT tracked_item AS asin, COUNT(*) AS total_purchases FROM conversions_all WHERE event_subtype = 'order' AND tracked_item IN ('B0XXXXXXX1','B0XXXXXXX2','B0XXXXXXX3') GROUP BY 1 ) SELECT total.asin, sns.sns_purchases, total.total_purchases, ROUND(100.0 * sns.sns_purchases / NULLIF(total.total_purchases, 0), 2) AS sns_share_pct FROM total LEFT JOIN sns ON sns.asin = total.asin ORDER BY sns_share_pct DESC NULLS LAST; ``` The `NULLIF` is the agent being defensive - a recently launched ASIN with zero recorded `order` events would otherwise divide by zero. Small thing. Saves a re-run. ## How to read the numbers The lift query returns two rows. Subscriber `average_spend_per_user` divided by non-subscriber `average_spend_per_user` is the headline lift ratio. A ratio of 2.4x means subscribers spend 2.4 times more than one-off buyers on the same ASIN set over the same window. The ASIN-level query then shows where that lift is concentrated - typically a handful of consumables (coffee, supplements, pet food, household goods) drive the majority of subscriber revenue, and the long tail of one-time products contributes almost nothing to the SnS program. The decision the marketing director was actually trying to make - *do we push more aggressively into SnS?* - turns on whether the high-lift ASINs already have full SnS enrollment, or whether there's headroom. If your top-5 lift ASINs are already at 60%+ `sns_share_pct`, the upside is in expanding the catalog. If they're at 15%, the upside is in conversion campaigns targeting existing buyers of those ASINs. ## The footnotes the agent surfaced unprompted This is the part that separates retrieval-grounded responses from fluent guesses. Without being asked, the agent included a short list of things the operator needed to know but didn't think to ask about: > **What Atlas surfaced that the operator didn't ask for** > - **Flexible Shopping Insights subscription required.** If FSI isn't enabled on your AMC instance, the query will return empty results with no error message. Check the Paid Features tab in AMC, or talk to your AdTech account executive. Regional availability varies. > - **Sandbox doesn't carry repeat-SnS signals.** `sns_subscription_id` and `repeatSnSOrder` rows are not populated in AMC Sandbox. Run this against production, or you'll see a lift ratio of 1.0x and assume SnS is doing nothing. > - **Three-month minimum window.** SnS cycles run on 1, 2, 3, or 6-month schedules. Anything shorter than 90 days will under-represent recurring orders. Six months is better if you have the data depth. > - **Household-level inflation.** AMC translates household purchases to user-level purchases by crediting the household event to each linked user. For total-sales analyses (like this one), be aware that subscriber totals may be slightly inflated when a single subscription serves a multi-person household. Adjust at the user level if precision matters. > - **Don't end the query on a comment line.** AMC's query editor will reject any submission whose last line is a `--` comment. Strip trailing annotations before running. The household-inflation footnote is the kind of thing that takes most operators a year of using AMC to discover. Atlas had it indexed from the start. ## What happens next The lift number is the input to a series of decisions, not the output of the analysis. The agent's next step - and the next guide in this series - is to take the high-lift ASINs identified here and build an AMC audience of non-subscribed buyers of those ASINs, then activate it as a Subscribe & Save promotion campaign in Amazon demand-side platform (DSP). That workflow uses the same `conversions_all_for_audiences` table variant pattern we covered in the [cart-abandoner audience guide](/guides/amc-cart-abandoner-audience/), with a different filter and a different activation playbook. The point is that no single query closes the loop. The agent runs the lift analysis, surfaces the high-lift ASINs, builds the audience, and pushes it to DSP - each step grounded in a different playbook, each playbook indexed and retrievable at the moment of need. The full workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): [Amazon Ads MCP](/features/amazon-ads-mcp/) brings the AMC and DSP signals, the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) can add catalog and inventory context, Atlas grounds the signal list, and [Skills](/features/skills/) keep the analysis and follow-up audience refresh on schedule. ## Why this matters The Subscribe & Save lift question is a perfect case for retrieval-grounded agents because the answer literally did not exist in most models' training data. Amazon added the `repeatSnSOrder` signal in February 2024. Models with knowledge cutoffs before that - which is most of them, even now, for the depth of detail required - will produce queries that compile, run, return data, and quietly undercount SnS revenue by the majority of its actual contribution. The operator gets a number. The number is wrong. There's no error to debug. An agent grounded in Atlas doesn't have this problem. It doesn't know SnS analysis from training data - it reads Amazon's own current IQ template and adapts it. When Amazon updates the playbook again (and they will), the corpus updates, and the agent gets the new answer without anyone retraining a model. If your agents are giving you confident SnS numbers that don't include `repeatSnSOrder`, they're giving you the wrong numbers. --- *Part of an ongoing series on how agents grounded in Amazon Agent Atlas approach real AMC workflows. Next: turning a high-lift ASIN list into a DSP-activated audience of non-subscribed buyers - the activation half of the workflow this post leaves open.* ### Turn AMC Workflows into Agent Skills URL: https://www.kuudo.com/guides/amc-agent-workflows/ The operator question was practical: *"We keep asking for the same AMC analyses. Can the agent remember the workflow instead of improvising every time?"* Yes, but the reusable unit should be a Skill, not a prompt snippet. A prompt remembers wording. A Skill remembers the steps: retrieve the right [Amazon Marketing Cloud](/features/amc/) (AMC) playbook, choose the table, run the privacy or size check, produce the artifact, route the decision, and log what happened. ## What a model without Atlas gets wrong > **Four ways an un-grounded workflow turns brittle** > 1. It stores a generic "run AMC analysis" prompt with no table-selection rule. > 2. It forgets that measurement and audience activation can require different table variants. > 3. It treats every output as read-only, even when the next step changes a DSP audience or budget. > 4. It has no run log, so the team cannot reproduce which parameters or rules produced the result. That is how a helpful demo becomes an unreviewable production process. ## What Atlas retrieves The agent starts by pulling the relevant Amazon Marketing Cloud playbooks from [Amazon Agent Atlas](/features/agent-atlas/). For an audience workflow, it retrieves: - The audience-source rule that decides whether the Skill can use an audience-safe table. - The sizing pattern that tells the operator whether the seed can activate. - The activation timing and companion measurement guidance that belong beside the output. - The **AMC synthetic data** playbook context when the Skill needs a safe test surface before it touches production workflows. For a measurement workflow, it retrieves the attribution table, lookback rule, and caveats that belong in the output. The [Amazon Ads MCP](/features/amazon-ads-mcp/) gives the Skill live access to the Ads and AMC surfaces. Atlas tells it what the current playbook says before it acts. ## The agent's working output The useful output is a workflow contract: ```json { "skill": "amc_audience_workflow", "mode": "read_then_approve", "steps": [ "retrieve_atlas_playbook", "resolve_table_window_filters", "run_privacy_and_seed_checks", "produce_sql_or_payload", "request_approval_for_writes", "write_run_log" ], "writeBoundary": "approval_required_before_dsp_activation" } ``` That contract is deliberately more boring than an open-ended chat. Boring is what makes it repeatable. ## The footnotes the agent surfaces > **The Skill should preserve these details every time it runs** > - Which Atlas chunks grounded the workflow. > - Which MCP tools were called and with which parameters. > - Whether the output was read-only or write-capable. > - Which approval policy applied. > - Which user approved or rejected the action. Those details are the difference between "the agent said so" and "we can audit the workflow." ## What happens next The full workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): Amazon Ads MCP brings AMC and demand-side platform (DSP) campaign signals, the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) can add catalog context, Atlas grounds the operating procedure, and [Skills](/features/skills/) turn the workflow into a reviewed recurring automation. Once the Skill exists, the same workflow can run from chat, code, or an automation tool. The interface changes; the source rules and approval gates do not. ## The point A Skill is how an agent stops improvising an operating procedure. *Next: use durable [run logs](/guides/why-mcp-needs-run-logs/) to make every Skill execution reviewable after the fact.* ### Why MCP Needs Run Logs URL: https://www.kuudo.com/guides/why-mcp-needs-run-logs/ The operator question was not about a single Amazon workflow: *"If an MCP-connected agent calls tools for us, how do we know what happened afterward?"* The answer is a run log. [Model Context Protocol](/features/mcp/) (MCP) gives agents a clean way to call tools. Production teams need the durable record around those calls: who asked, which tool ran, what parameters were passed, what policy checks fired, what changed, and who approved the change. ## What a model without Atlas gets wrong > **Four run-log gaps show up when tool access is treated like a demo** > 1. Read and write calls are logged at the same level, so risky actions do not stand out. > 2. Approval state is stored outside the run, making the final artifact hard to reproduce. > 3. Retrieved source context is omitted, so nobody knows which playbook or rule grounded the action. > 4. Errors are recorded as chat text instead of structured failure states. That makes the agent hard to trust even when the output is correct. ## What Atlas retrieves Atlas is one of the sources a run log must name. If an agent uses [Amazon Agent Atlas](/features/agent-atlas/) to ground an [Amazon Marketing Cloud](/features/amc/) (AMC) query, listing patch, or decision rule, the run log should capture: - The Atlas corpus version used for the answer. - The chunk identifiers that grounded the rule. - The tool inputs, outputs, and policy checks from the MCP server. The same principle applies to live data called through an MCP server: capture the tool, inputs, outputs, and policy checks in the same run. For Amazon workflows, the [Amazon Ads MCP](/features/amazon-ads-mcp/) and [Selling Partner MCP](/features/amazon-selling-partner-mcp/) provide the live data surfaces. The run log is the connective record that explains why the agent used them. ## The agent's working output A production run log should answer five questions: ```json { "event": "mcp_tool_run", "riskTier": "write", "initiator": {"user": "required", "workspace": "required"}, "execution": {"skillId": "required", "skillVersion": "required"}, "toolCall": {"server": "required", "tool": "required", "parametersHash": "required"}, "grounding": {"atlasCorpusVersion": "required", "chunkIds": ["required"]}, "controls": {"checks": ["privacy", "permission", "approval"], "approvalState": "required"}, "result": {"artifactHash": "required", "destination": "required", "rollbackContext": "required"} } ``` If a field cannot be logged, the agent should treat that as a product gap before write access expands. ## The footnotes the agent surfaces > **The run log details that matter most in production** > - Read-only runs can log lighter context, but write-capable runs need the exact artifact hash. > - Approval belongs in the run record, not in a separate chat transcript. > - Failed policy checks should be first-class states, not unstructured explanation text. > - Tool output should be redacted where needed, but the redaction itself should be visible. > - Rollback context should be captured before the write, not reconstructed afterward. Those details are mundane until something goes wrong. Then they are the product. ## What happens next The full workflow runs through the [Amazon Agent Data layer](/features/amazon-agent-flow/): Amazon Ads MCP and Selling Partner MCP supply live Amazon context, Atlas grounds the answer, and [Skills](/features/skills/) make the tool sequence repeatable. The run log records every step so a human can review the decision after the agent acts. When a workflow graduates from analysis to activation, the run log becomes the audit surface for approval, debugging, and customer trust. ## The point If a tool call cannot be reconstructed, it should not be trusted in production. *Next: use the [AMC Skill workflow](/guides/amc-agent-workflows/) pattern to decide which tool calls need approval before they write.* ### Human Approval for AMC Activation URL: https://www.kuudo.com/guides/human-approval-for-amc-activation/ Run the read-only half of an AMC workflow hands-off, and stop in one place: audience activation waits inside a [Skill](/features/skills/) until a human approves the exact creation payload. The [Amazon Ads MCP](/features/amazon-ads-mcp/) runs the sizing reads automatically and holds the gated submission, while [Amazon Agent Atlas](/features/agent-atlas/) supplies the rules the approver checks against: the 2000-user rule-based floor, the 500 to 500,000 lookalike seed band, the 24-to-36-hour DSP lag. The policy answers a Slack message from our media lead: *"If the agent builds an [Amazon Marketing Cloud](/features/amc/) audience and the SQL compiles, does it push it into the demand-side platform (DSP) on its own, or does one of us sign off first?"* [Our agent](/features/ai-clients/) could do either. It stops. Why not paste the audience SQL into ChatGPT or Claude for review? A plain chat hits three walls here. **No access to your data**: it cannot run a sizing query against your AMC instance. **No way to take action**: it cannot submit or watch anything on Amazon; you do every step by hand. **Generic knowledge, not Amazon's**: it does not carry the activation thresholds. That is disconnected, generic, manual work that ships silent mistakes. The MCP closes the first two walls, Atlas the third; the Skill makes the gate repeatable. ## An AMC audience query returns nothing you can review, so the gate must come before the POST One line of shared playbook boilerplate settles where the gate goes: "Unlike standard AMC queries, AMC Audience queries do not return visible results that you can download. Instead, the audience defined by the query is pushed directly to Amazon DSP." A rule-based audience query selects `user_id` values and nothing else; once submitted, there is no artifact left to inspect. Review after submission is not late, it is impossible. Activation queries even run on their own table surface: the `_for_audiences` variants, `conversions_for_audiences`, `conversions_all_for_audiences`, `dsp_impressions_for_audiences`, `sponsored_ads_traffic_for_audiences`, `amazon_attributed_events_by_traffic_time_for_audiences`. That suffix in a FROM clause is a machine-checkable signal that a query is an activation, not an analysis. One nuance: `conversions_all_for_audiences` is the audience copy of `conversions_all`, and the high-value-segments query built on it lists a Flexible Amazon shopping insights subscription as a requirement, so the runnable seed below stays on `conversions_for_audiences`. Cost lands on the same line. The **Off-Amazon Conversions Playbook** is explicit: "Submitting an audience to be created is not charged. There is no cost until the audience is activated in Amazon DSP." In the console the write is a paste into the Audiences query editor; through the Amazon Ads MCP it is the POST method of the AMC rule-based Audience API, which the Skill refuses to send unsigned. > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT drafts plausible audience SQL without knowing that submission returns nothing reviewable; you paste it into the Audiences query editor and find out after the audience exists. > - **Generic knowledge, not Amazon's.** Claude will not reliably flag that a `_for_audiences` table makes the query an activation, so the one query that needed a gate looks like all the others. > - **And your data is now exposed.** Getting that draft meant pasting instance details and audience logic into a chat history you do not control. ## Approval is a numbers check: 2000 distinct user_ids for a rule-based audience, a 500 to 500,000 seed for a lookalike Two thresholds decide approvability, and they never blend. For rule-based audiences the **Off-Amazon Conversions Playbook** states that "the minimum is 2000 distinct user_ids for a rules-based audience to be activated in the market," a floor the **Programmatic Audience Framework Playbook** repeats. Lookalikes answer to a different band: **Introduction to AMC Lookalike Audiences** requires a seed of between 500 and 500,000 user_ids, warns that refresh "will fail if the size falls below 500 or goes above 500k," and recommends 1,000 to 450,000 as the working range. A correct approval card names the one threshold that applies and puts the measured number beside it. Measurement runs automatically. Before submission, the agent wraps the seed in the corpus's companion pattern, `SELECT COUNT(user_id) AS user_count FROM (seed query) GROUP BY 1`, run as an ordinary measurement query. Sizing needs no approval because it changes nothing. The seed we gated most recently, purchasers from the standard audience table, built with the same query shape the [cart-abandoner workflow](/guides/amc-cart-abandoner-audience/) assembles upstream: ```sql SELECT user_id FROM conversions_for_audiences WHERE event_subtype = 'order' ``` That seed's companion COUNT came back at 12,480 distinct user_ids: above the 2000 floor with room to decay across weekly refreshes. On a lookalike, the same COUNT places the seed inside the 500 to 500,000 band; DSP's expansion tiers then run from roughly 300K to 1M members (most similar) up to 900K to 10M (most broad), region-dependent and subject to change. The corpus suggests starting balanced; a seed pinned to a tier's edge should be revised, not shipped. > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT cannot run that companion COUNT against your AMC instance, so the seed size the approval hinges on is a guess, not a measurement. > - **Generic knowledge, not Amazon's.** Claude does not carry the 2000-user floor or the 500/500k band; it blesses an 1,800-user audience that never activates, or a 600,000-user seed whose refresh fails, and blends both rules into "make sure it's big enough." > - **No way to take action.** Neither chat can hold the submission until the checks pass; you carry every figure between tabs yourself. ## The approver signs the JSON that ships: audienceName, advertiserId, the flattened query, the window, and refreshRateDays In front of the human sits the creation payload itself, not a summary. The fields match the promotional-events lookalike playbook's example: `audienceName`, `audienceDescription`, `advertiserId`, the seed SQL flattened into `query`, `timeWindowStart`, `timeWindowEnd`, `timeWindowRelative`, and `refreshRateDays`; lookalike submissions add `lookalikeAudienceExpectedReach`, `"BALANCED"` in the corpus example. The same playbook scopes two recommendations to its pattern: `refreshRateDays: 7` "to ensure optimal performance," and `timeWindowRelative: FALSE` to keep each refresh looking at individuals from the previous event. Shipped text is not drafted text. **Introduction to AMC Lookalike Audiences** recommends removing all comment lines from the query before pushing to audience creation, and the seed gets flattened into the JSON regardless, so what a human eyeballed in an editor is not automatically what ships. The Skill closes that gap by hashing the flattened, comment-stripped query and binding the approval to the hash: change `query` by one character and the gate reopens. ```json { "artifact": "audience_definition", "workflow": "amc-activation-approval", "requiresApproval": true, "activation": { "audienceName": "AMC_Purchasers_Weekly_2026Q3", "audienceDescription": "Purchasers, June 2026 order window", "advertiserId": "123456789", "query": "SELECT user_id FROM conversions_for_audiences WHERE event_subtype='order'", "timeWindowStart": "2026-06-01T00:00:00Z", "timeWindowEnd": "2026-07-01T00:00:00Z", "timeWindowRelative": "FALSE", "refreshRateDays": 7 }, "checks": { "seedCount": { "measured": 12480, "threshold": "2000 distinct user_ids rule-based activation floor" }, "tableVariant": "FROM uses _for_audiences tables only", "destination": { "advertiserId": "123456789", "instanceId": "amcinstance01" }, "querySha256": "5b3c9f1e0a4b2d83c56a1908d7e5bc2a4f8e6d0b1a9c8e7f5d3b2a1c0e9f8d7b", "atlasChunks": [ "6e39ff4c3e1ed64b", "3592514e4137c936", "9e1e29903178da48", "9fadd181160a41e4" ] }, "decision": "approve | revise | cancel", "records": { "audienceExecutionId": null, "status": null, "statusReason": null, "audienceCount": null, "dspAudienceId": null, "lastRefreshedTime": null, "approvedBy": null, "approvedAt": null } } ``` Two fields deserve more attention than the SQL. `advertiserId` is the destination: the DSP seat the audience lands in, confirmed, not assumed. And `refreshRateDays` makes activation a standing write, not a one-off: the query re-runs on cadence under this single approval, so the human is approving a recurring behavior, which is why the hash check stays live after the yes. > **In plain ChatGPT or Claude** > - **No way to take action.** ChatGPT can format a payload that looks exactly like this, but it cannot bind your approval to what ships; what you read and what you later paste can silently differ. > - **No access to your data.** Claude cannot see your DSP seat, so `advertiserId` is a string it copies from your prompt, not a destination it verifies. > - **Generic knowledge, not Amazon's.** Both read `refreshRateDays: 7` as a field, not a standing weekly write running under a one-time approval. ## "Successful" in AMC is not "active" in DSP: allow 24 to 36 hours and keep your own run log The clock after the approved POST belongs to Amazon. The **Programmatic Audience Framework Playbook** is precise: "Once an audience creation status is returned as 'successful' in the AMC API, it can take between 24 and 36 hours to be 'active' and ready for use in Amazon DSP." I nearly resubmitted after one quiet day; the playbook says that quiet day is the system working. Amazon also leaves a hole in the audit trail. The same playbook admits there is currently "no unique id field that is common for both the AMC endpoint and Amazon DSP endpoint"; the only mapping for now is "by name and by the approximate creation date." The monitoring output does include `dspAudienceId` and `dspCanonicalId` columns, but by the playbook's own statement those values cannot join the two systems, so lean on neither. Copy its working practice instead: filter the DSP audience list by `audienceName` prefix, category "Custom-built," subCategory "AMC," which only works if the naming convention was enforced at approval time. So the run log is the join key, not bookkeeping. Per audience, the agent logs what it watches by `audienceExecutionId`: `status`, `statusReason`, `audienceCount`, `lastRefreshedTime`, the query, and the window, next to the approval record itself, the same argument that makes [run logs non-negotiable for MCP writes](/guides/why-mcp-needs-run-logs/). > **In plain ChatGPT or Claude** > - **No access to your data.** ChatGPT cannot watch the 24-to-36-hour window between AMC "successful" and DSP "active"; you refresh the console and wonder whether it failed or is not there yet. > - **Generic knowledge, not Amazon's.** Claude does not know the two endpoints share no common ID, so it cannot reconstruct which live DSP audience came from which approved payload. > - **No way to take action.** When a refresh stalls, no chat flags the line item still targeting the stale audience; a human has to notice on their own. ## What happens next Approval closes the gate once; the Skill keeps watching. It expects the DSP entry inside the 24-to-36-hour window and logs execution metadata on every refresh, keeping the name-plus-creation-date mapping current. When an audience stops refreshing, the playbook's diagnosis is blunt: "it is most likely the audience size has dropped below 2,000 unique users," flagged after a one-day buffer past `refreshRateDays`. After several failed refreshes the instruction turns operational: decrease or stop spending on that line item, because it keeps targeting the same users as they move down the funnel. Each refresh is also the moment to re-measure overlap against segments already live in Amazon DSP (via `conversions_all`), at launch and mid-campaign, since affinity and size metrics do not necessarily indicate overlap. The loop runs on the [Amazon Agent Data layer](/features/amazon-agent-flow/): the Amazon Ads MCP carries the AMC sizing reads, the gated submission, and the refresh monitoring, and the [Selling Partner MCP](/features/amazon-selling-partner-mcp/) joins when audience logic depends on catalog facts, like which ASINs a promotion actually covers. That is the whole pattern: reads run free, the one write stops at a person, and the approval binds to the exact artifact that ships. *Next: turning gated analyses like this one into [repeatable AMC agent workflows](/guides/amc-agent-workflows/), where the approval step is part of the Skill rather than a manual afterthought.* ### Everyone in Your Category Has the Same AI Now URL: https://www.kuudo.com/guides/everyone-has-the-same-ai/ If you sell on Amazon, something quietly changed underneath you in the last two years, and most of your competitors haven't noticed what it actually means. Every seller in your category now has access to the same frontier AI you do. The same models, the same chat window, the same "analyze this search term report" prompt. The tools got extraordinary, and they got extraordinary for everyone at exactly the same moment. When the most powerful tool in your business is also sitting on your competitor's desk, the tool stops being the difference. So what is the difference? ## The model knows *about* Amazon. You *know* Amazon. Ask a frontier model how to structure a Sponsored Products campaign and it will give you a competent answer. It will give your competitor the same competent answer. It has read everything ever written about Amazon: the help docs, the blog posts, the courses, the conference talks, the prompt packs. But that's the tell. It knows *about* Amazon the way someone who read a book about swimming knows about water. That knowledge is now the floor: table stakes, priced at twenty dollars a month. Because Amazon doesn't run on what's written down. It runs on unwritten rules, and those were never in anyone's training data. The gap between what Seller Central says and what Amazon actually does. What genuinely gets a suppressed listing reinstated, versus the case wording that earns you another canned bot reply. Why your attribute update silently loses to an upstream contribution, and which "errors" you can safely ignore. How the algorithm really behaves after a price move, how enforcement really works, how long things really take. The internals, the quirks, the behaviors, the operational know-how you only earn by running the machine for years and paying tuition every time it surprises you. ### The layer that's only yours And stacked on top of that sits the layer that's exclusively yours: the size-chart rewrite that cut your bestseller's return rate 40%, the fifty thousand dollars of wasted spend encoded in your negative keyword lists, why you never run deals on that one ASIN in Q3, the campaign structure you arrived at after three years of expensive lessons. That's your DNA. Some people call it tribal knowledge. It's the reason a customer chose you over the four identical-looking listings above and below you, and in the most literal sense, it's your IP. In a marketplace as brutally commoditized as Amazon, it may be the *only* IP you have that can't be copied, undercut, or bought. We're not the only ones who see it this way. In late June 2026, Alex Karp's Palantir posted [a nine-point manifesto on AI sovereignty](https://thenextweb.com/news/palantir-ai-sovereignty-manifesto-tokenmaxxing): data as treasure, knowledge as the asset that compounds, ownership as the precondition for having a future at all. He argues it from the world of defense and statecraft. We didn't need the confirmation, but we'll take it: it's the same signal we built Kuudo on. If it's existential for nations, believe that it's existential for a business fighting for the buy box. ## Why are Amazon sellers walking into this trap faster than anyone? The path of least resistance on a busy afternoon is to paste it all into a public chatbot. The search term report. The business report. The P&L. The strategy doc for your Q4 push. Every hard-won correction, typed into a tool you don't control. Do that long enough and your edge stops being yours. It gets absorbed into the same model your competitor opens tomorrow morning. The advantage that took years to earn doesn't fade. It gets donated. ### Read the pitches yourself And you don't have to squint to see the machine, because a whole product category now advertises it right on the homepage. Look at the wave of AI listing-optimization tools and read their pitches carefully: ListingOptimization.ai leads with AI ["trained on thousands of winning listings"](https://listingoptimization.ai/) and a template library for cloning A/B test winners. Whose winning listings? Who paid for the losing variants? Pixii grades your listing against [a database of 100,000 top-performing listings](https://www.pixii.ai/) and offers proven templates drawn from high-converting ones. Somebody earned those conversions. Nozam sells [review mining on any ASIN](https://www.nozam.io/), yours or your competitor's, to surface exactly what customers hate about them. Clicco promises visuals and copy that learn from top competitors. And Selluna says it plainest of all: upload any competitor's image and it recreates the style with your product: ["Their inspiration, your listing."](https://www.selluna.ai/) None of this is hidden. It's the value proposition. These are redistribution engines: they harvest what worked (the winning image, the converting layout, the review insight) and hand the distillation to the next subscriber for a monthly fee. Every one of those "winning listings" in the training data was some seller's tuition: the photoshoots, the failed variants, the split tests, the years of learning what actually converts in one category. That edge is now a template, available to the four listings above and below yours for a monthly fee. ### The flywheel only spins one way Here's the part to sit with: the flywheel only spins one way. **They learn from you, and they offer that learning to the next user.** Today you're the customer. The day your listing starts winning, you're the inventory. One of these tools even answers "Is my data private?" in its FAQ with *yes, for paid plans*. Privacy as an upsell. That's the market telling you, in writing, what your knowledge is worth to them. But don't stop at the upsell, because a privacy line, even a sincere one, answers a narrower question than the one that matters. Several of these tools do promise they won't sell your data, and that promise can be entirely true while the flywheel spins anyway. The thing that compounds isn't your file. It's the learning stacked on top of it: which of the six generated main images you shipped, which template you cloned, which headline you kept and which you threw away, which "winner" you took into your split test. That's your operator judgment, years of expensive lessons, compressed into clicks, and it's exactly the signal a system like this needs to get smarter for the next subscriber in your category. Read the pitches again: a grader scored against "100,000 top-performing listings," AI "trained on thousands of winning listings," libraries of "proven templates from high-converting listings." Proven by whom? Somebody's photoshoots, somebody's failed variants, somebody's tuition. The learning travels even when your name doesn't. They anonymize *you*. They don't anonymize what they learned from you. That's the product. ### This isn't new. It's just faster now Sellers should recognize the pattern, because the Amazon software industry ran this play long before AI: tools that pooled your data into "category benchmarks" and sold the aggregate back to you and everyone you compete with. The new crowd is faster and slicker, but the business model is identical: build the product on top of your knowledge until your knowledge becomes the thing they sell. Take it to its end and they don't need you at all. The next seller just pays for access to the expertise you handed over. That isn't being out-competed. It's commoditizing yourself, one upload at a time. The brands still donating their edge to someone else's flywheel will look up one day and find they no longer have one. ## The answer isn't less AI. It's AI in a private place. This is [the conviction Kuudo is built on](/why-kuudo/), and it's worth saying plainly: **when everyone runs the same models, your advantage is the private knowledge only you have, and keeping it yours is no longer a matter of discipline. It's a choice.** The wrong response to the leak is abstinence. Refusing to use frontier AI while your category compounds with it isn't protecting your edge; it's forfeiting the game to protect the ball. The right response is to give AI your knowledge *and a private place to do the work*, where your years of order history, campaign judgment, and catalog-specific wisdom accelerate the business instead of leaking out of it. ### That's what Kuudo is A private place for AI to work on what only you know. It runs in your cloud, not ours. Nothing inside it trains anyone else's model: Google, Meta, Anthropic, and OpenAI can't learn from what you never gave them. There's no fine print about what counts as "your data," because in your own cloud the definition is total: the inputs, the outputs, the choices, and everything the system learns from them are yours, the learning included. And if you ever walk away, what you built stays yours, because it lives in your cloud. Private. Trusted. Owned. In that order, always together. And because you supply what no vendor can (your choices, your judgment, the calls only your team would make), no two Kuudo deployments look alike. It isn't a finished product you rent. It's the ingredients: the [data layer](/features/amazon-agent-flow/), with [Amazon Ads MCP](/features/amazon-ads-mcp/) steering spend and [Selling Partner MCP](/features/amazon-selling-partner-mcp/) touching your catalog; the [Amazon Agent Atlas](/features/agent-atlas/) grounding, and the [tools and skills](/features/skills/) your agents run. You keep the IP. You own the means of production. ## Why Amazon first We start with Amazon deliberately, because it's where some of the densest, most defensible operator knowledge in the world already lives, and where the stakes of giving it away are highest. Millions of sellers, one search results page, and a customer who can't tell you apart until *something* tells them to. That something was never the model. It was never the clever prompt. It was the unwritten rules, the hard-won know-how, the accumulated judgment about how the machine actually behaves and what actually works, earned by you, running your business, one expensive lesson at a time. Everyone has the same AI now. Your edge is what it doesn't know. Keep it that way. Build your moat, and let your competition give theirs away. *For how this plays out in practice (an agent doing real listing work with your knowledge staying yours), start with [how a suppressed listing gets diagnosed and fixed](/guides/seller-listing-agentic-audit-to-patch/).* ## Documentation ### Quick Start: ChatGPT URL: https://www.kuudo.com/docs/quick-start/chatgpt/ Ask for the Amazon work in plain language and get it back done: pull a Sponsored Products report, find why a listing went suppressed, check yesterday's orders, size an Amazon Marketing Cloud (AMC) audience. Answers come from your live Amazon Ads, Seller Central, and Vendor Central data rather than the model's training set, and every action stays scoped to the credentials you grant. Connect ChatGPT to your private MCP server in a few minutes. Use ChatGPT's Apps or custom connector flow when you want ChatGPT to call tools and retrieve live context from your own MCP deployment. Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace `{your-private-mcp-host}` with the private host shown in your dashboard. ## Prerequisites - A connected workspace with access to your private MCP server. - A dashboard API key or signed connector URL from the dashboard **Keys** tab. - A ChatGPT plan that supports apps, connectors, or custom MCP connectors. - Developer mode or workspace permission to create custom connectors, if your ChatGPT plan requires it. ## ChatGPT custom app or connector Use this path for ChatGPT on the web. ChatGPT's interface may call this an **app**, **custom app**, or **custom connector**, depending on your plan and workspace settings. ### Copy prompt Paste this into ChatGPT if you want it to walk you through setup: ```text Walk me through setting up my private MCP server in ChatGPT, step by step. Use ChatGPT's Settings > Apps or Apps & Connectors flow for a custom MCP app or connector. If developer mode or admin permission is required, tell me where to check before continuing. Do not ask me to paste my raw API key into this chat. If ChatGPT needs authentication, tell me to copy the key or signed connector URL from my dashboard Keys tab and paste it only into the ChatGPT connector setup form. Keep each step short, tell me what to click, and wait for me after each step. The MCP server URL will look like: https://{your-private-mcp-host}/mcp ``` ### 1. Confirm custom connectors are enabled In ChatGPT, open **Settings > Apps** or **Settings > Apps & Connectors**. If you do not see an option to create a custom app or custom connector, check developer mode or workspace permissions: - Plus and Pro accounts may need developer mode enabled before custom MCP connectors appear. - Business, Enterprise, and Edu workspaces may require an owner or admin to allow custom connectors. ### 2. Copy your MCP server details In your dashboard, open the **Keys** tab. Create a key if needed, then copy the endpoint and authentication value for ChatGPT. Use the normal MCP endpoint unless your dashboard provides a ChatGPT-specific signed connector URL: ```text https://{your-private-mcp-host}/mcp ``` Do not paste your raw API key into a chat conversation. Use the ChatGPT connector setup form or your workspace's approved secret flow. ### 3. Add the custom app or connector In ChatGPT: 1. Open **Settings > Apps** or **Settings > Apps & Connectors**. 2. Choose the option to create or add a custom app or connector. 3. Name it something clear, such as `private-mcp`. 4. Paste your MCP server URL. 5. Configure authentication using the value from your dashboard. 6. Save or connect the app. If ChatGPT asks what type of server this is, choose the MCP or remote MCP option. ### 4. Enable it in a chat Start a new ChatGPT conversation. Add the connector from the composer, usually through the **+** button, **More**, or by mentioning the app by name if your workspace supports app mentions. If ChatGPT shows a tool approval setting, start with approval enabled until you have verified the tools and behavior. ### 5. Verify the connection Ask ChatGPT to list the available tools without calling write actions: ```text What tools are available from my private MCP connector? ``` If the connector is active, ChatGPT should enumerate the tools exposed by your private MCP server. ## Troubleshooting ### The custom connector option is missing Check whether your ChatGPT plan supports custom apps or custom MCP connectors. If you are in a workspace, ask an owner or admin to enable custom connectors and developer mode permissions. ### The MCP server does not meet ChatGPT requirements ChatGPT may reject an MCP server that does not implement the required MCP shape for custom connectors. Confirm that your server exposes the expected MCP endpoint, tool discovery, and any required search or fetch tools for your ChatGPT plan. ### Unauthorized or 401 errors Create a fresh key in the dashboard and re-enter the authentication value in ChatGPT's connector setup form. Make sure the server URL ends with `/mcp` and that the key belongs to the same workspace as the MCP server. ### Tools not appearing Start a new chat after saving the connector. Add the connector from the composer or mention it by name, then ask for the available tools again. ### Slow responses Check your network path to the private host and confirm the cloud deployment is healthy. The hostname is specific to your environment, so connectivity issues are usually tied to your cloud provider, DNS, firewall, or deployment status. ## Start using tools Try read-only prompts first: - "What tools are available from my private MCP server?" - "Show me the account or workspace context this server can access." - "List the read-only tools before calling any write actions." - "Summarize the last 7 days of available advertising, inventory, or operational data." For write-capable workflows, ask ChatGPT to explain the proposed action and wait for approval before it calls any mutating tool. ## Add reusable workflows After ChatGPT can reach your MCP server, install ChatGPT skills for repeatable workflows and task-specific instructions. See the [ChatGPT Skills quick start](/docs/quick-start/chatgpt-skills/). ### Quick Start: Claude URL: https://www.kuudo.com/docs/quick-start/claude-ai/ Ask Claude for the Amazon job in plain language — reprice a set of SKUs, patch a listing that failed validation, pull last week's campaign performance, build an Amazon Marketing Cloud (AMC) audience — and it works against your live Amazon accounts instead of guessing from training data. Writes stay scoped to the credentials you grant, and the packaged Skills gate activation on your approval. Connect Claude to your private MCP server in a few minutes. Use Claude's custom connector flow for Claude on the web or Claude Desktop, and use bearer-header configuration for Claude Code. Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace `{your-private-mcp-host}` with the private host shown in your dashboard. ## Prerequisites - A connected workspace with access to your private MCP server. - A dashboard API key, or a signed Claude connector URL from the dashboard **Keys** tab. - Claude on the web, Claude Desktop, or Claude Code. ## Claude custom connector Use this path for Claude on the web and Claude Desktop. Claude's custom connector UI accepts a single MCP server URL, so use the signed connector URL from your dashboard instead of a raw bearer token. ### Copy prompt Paste this into Claude if you want it to walk you through setup: ```text Walk me through setting up my private MCP server in Claude using the custom connector flow, step by step. Use Claude's Customize > Connectors flow, not claude_desktop_config.json and not a local Node or mcp-remote workaround. If I need a Claude connector URL, tell me to copy it from my dashboard Keys tab instead of pasting my API key into chat. Keep each step short, tell me what to click, and wait for me after each step. The connector URL will look like: https://{your-private-mcp-host}/mcp/connect/{signed-token} ``` ### 1. Copy your Claude connector URL In your dashboard, open the **Keys** tab. Create a key if needed, then copy the Claude connector URL. That URL is already signed for Claude. You do not need to paste your raw API key into Claude. ```text https://{your-private-mcp-host}/mcp/connect/{signed-token} ``` ### 2. Add the custom connector In Claude, open the official connectors UI: 1. Open **Customize > Connectors**. 2. Click the **+** button. 3. Choose **Add custom connector**. 4. Name it something clear, such as `private-mcp`. 5. Paste the signed Claude connector URL. 6. Click **Add**. Claude's custom connector UI does not let you manually attach an `Authorization` header. If you only have the normal `/mcp` endpoint, go back to the dashboard and copy the Claude connector URL. ### 3. Enable it in a chat Start a new Claude chat, open **Connectors** from the composer, and toggle the connector on for that conversation. If Claude shows a **Tool access** setting, leave it on **Auto** unless you specifically want on-demand approvals. ### 4. Verify the connection Ask Claude to list the available tools without calling write actions: ```text What tools are available from my private MCP connector? ``` If the connector is active, Claude should enumerate the tools exposed by your private MCP server. ## Claude Code Use this path when you want Claude Code to call your private MCP server from a local project or user profile. For a deeper reference on Claude Code MCP transports, scopes, authentication, JSON config, plugins, and managed settings, see the [Claude Code MCP quick start](/docs/quick-start/claude-code-mcp/). ### Copy prompt Paste this into a Claude Code conversation if you want Claude Code to handle setup: ```text Add my private MCP server so I can use its tools from Claude Code. Use the private host from my dashboard: https://{your-private-mcp-host}/mcp Use my local MCP_API_KEY environment variable. Do not ask me to paste or share the raw key in chat. If MCP_API_KEY is not set in this shell, tell me to export it from my dashboard first. Run the Claude Code setup command using the literal env-var header: 'Authorization: Bearer ${MCP_API_KEY}' ``` ### 1. Set your local key Set the API key in the shell that launches Claude Code: ```bash export MCP_API_KEY="mcp_live_..." ``` For repeated use, store it in your shell profile or secret manager. Do not commit the raw value to `.mcp.json`. ### 2. Add the MCP server Add the remote HTTP MCP server: ```bash claude mcp add --transport http private-mcp https://{your-private-mcp-host}/mcp \ --header 'Authorization: Bearer ${MCP_API_KEY}' ``` Keep the single quotes around the header so Claude Code stores the environment-variable reference, not your raw key. ### Scope options - **Local scope**: Available only in the current local project. - **Project scope**: Shared through `.mcp.json` in the project root. Add `--scope project` to the command. - **User scope**: Available across all projects. Add `--scope user` to the command. Project scope is useful when each collaborator should use the same server entry but their own local `MCP_API_KEY`. ### Alternative: JSON config If you prefer adding the full JSON definition: ```bash claude mcp add-json private-mcp '{ "type": "http", "url": "https://{your-private-mcp-host}/mcp", "headers": { "Authorization": "Bearer ${MCP_API_KEY}" } }' ``` ### 3. Verify the connection Type `/mcp` in any Claude Code session. You should see `private-mcp` listed with its tools. You can also inspect the saved config: ```bash claude mcp get private-mcp ``` ## Troubleshooting ### The custom connector will not add Make sure you pasted the full signed Claude connector URL from the dashboard, not the raw `/mcp` endpoint. Claude custom connectors use `/mcp/connect/{signed-token}` and do not accept a separate bearer header. ### Unauthorized or 401 errors For Claude custom connectors, create a fresh key in the dashboard and copy the Claude connector URL again. Rotated or revoked keys invalidate old connector URLs. For Claude Code, make sure `MCP_API_KEY` is exported in the shell Claude Code uses, then double-check that your server URL ends with `/mcp`. ### Tools not appearing In Claude on the web or Claude Desktop, the connector must be enabled per conversation. Open **Connectors** in the current chat and make sure your connector is toggled on. In Claude Code, run `/mcp` to check server status. If the server shows an error, verify the private hostname and local `MCP_API_KEY` value. ### Slow responses Check your network path to the private host and confirm the cloud deployment is healthy. The hostname is specific to your environment, so connectivity issues are usually tied to your cloud provider, DNS, firewall, or deployment status. ## Start using tools Try read-only prompts first: - "What tools are available from my private MCP server?" - "Show me the account or workspace context this server can access." - "List the read-only tools before calling any write actions." - "Summarize the last 7 days of available advertising, inventory, or operational data." For write-capable workflows, ask Claude to explain the proposed action and wait for approval before it calls any mutating tool. ## Add reusable workflows After Claude can reach your MCP server, install Claude Code skills for repeatable workflows and task-specific instructions. See the [Claude Code Skills quick start](/docs/quick-start/claude-skills/). ### Quick Start: Claude Code MCP URL: https://www.kuudo.com/docs/quick-start/claude-code-mcp/ From Claude Code you can wire live Amazon data into the loop you already work in — query Ads, Seller Central, and Vendor Central while you build, prototype an agent against real campaigns, or debug a listing without leaving the terminal. Use Claude Code MCP when you want Claude Code to connect directly to tools, databases, APIs, monitoring systems, issue trackers, or your private MCP server. For the official reference, see [Connect Claude Code to tools via MCP in the Claude Code docs](https://code.claude.com/docs/en/mcp). Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace `{your-private-mcp-host}` with the private host shown in your dashboard. ## Add a remote HTTP server Remote HTTP is the recommended transport for cloud-hosted MCP servers. ```bash export MCP_API_KEY="mcp_live_..." claude mcp add --transport http private-mcp https://{your-private-mcp-host}/mcp \ --header 'Authorization: Bearer ${MCP_API_KEY}' ``` Keep the single quotes around the header so Claude Code stores the environment-variable reference instead of your raw key. When you configure MCP servers through `.mcp.json`, `~/.claude.json`, or `claude mcp add-json`, the `type` field can use either `http` or `streamable-http`. ## Add a remote SSE server SSE is deprecated. Use HTTP when the server supports it. If you must connect an older SSE server: ```bash claude mcp add --transport sse legacy-api https://api.example.com/sse \ --header 'Authorization: Bearer ${MCP_API_KEY}' ``` ## Add a local stdio server Stdio servers run as local processes. Use them for tools that need local system access or custom scripts. ```bash claude mcp add --transport stdio --env TOOL_API_KEY="${TOOL_API_KEY}" local-tool \ -- npx -y local-tool-mcp-server ``` All Claude flags such as `--transport`, `--env`, `--scope`, and `--header` must come before the server name. The `--` separator marks the start of the command and arguments passed to the MCP server. Claude Code sets `CLAUDE_PROJECT_DIR` in the spawned server's environment to the project root. Local servers can read it to resolve project-relative paths. ## Manage servers Use the Claude Code CLI for saved configuration: ```bash claude mcp list claude mcp get private-mcp claude mcp remove private-mcp ``` Use `/mcp` inside Claude Code to inspect live server status, authenticate with OAuth servers, retry failed connections, and see connected tool counts. Claude Code refreshes tool, prompt, and resource lists when servers send MCP `list_changed` notifications. HTTP and SSE servers reconnect automatically with backoff after transient disconnects. Stdio servers are local processes and are not automatically reconnected. ## Choose a scope The `--scope` flag controls where the server is stored and who can use it. | Scope | Loads in | Shared with team | Stored in | | --- | --- | --- | --- | | `local` | Current project only | No | `~/.claude.json` under the current project path | | `project` | Current project only | Yes | `.mcp.json` in the project root | | `user` | All your projects | No | `~/.claude.json` | Local scope is the default. Use it for personal or experimental servers. Use project scope for team-shared server entries that should be checked into version control. Use user scope for personal tools you want across projects. Examples: ```bash claude mcp add --transport http private-mcp --scope local https://{your-private-mcp-host}/mcp claude mcp add --transport http private-mcp --scope project https://{your-private-mcp-host}/mcp claude mcp add --transport http private-mcp --scope user https://{your-private-mcp-host}/mcp ``` When the same server name exists in more than one scope, Claude Code uses the highest-precedence definition: local, project, user, plugin-provided servers, then Claude.ai connectors. ## Use project JSON Project-scoped MCP servers live in `.mcp.json`: ```json { "mcpServers": { "private-mcp": { "type": "http", "url": "https://{your-private-mcp-host}/mcp", "headers": { "Authorization": "Bearer ${MCP_API_KEY}" } } } } ``` Claude Code supports environment-variable expansion in `.mcp.json` values: - `${VAR}` expands to the environment variable value. - `${VAR:-default}` uses a default when the variable is unset. Expansion works in `command`, `args`, `env`, `url`, and `headers`. If a required variable is missing and no default is provided, Claude Code fails to parse the config. For project-scoped servers, Claude Code prompts for approval before using servers from `.mcp.json`. To reset those choices, run: ```bash claude mcp reset-project-choices ``` ## Add JSON directly Use `claude mcp add-json` when you already have a JSON server definition: ```bash claude mcp add-json private-mcp '{ "type": "http", "url": "https://{your-private-mcp-host}/mcp", "headers": { "Authorization": "Bearer ${MCP_API_KEY}" } }' ``` ## Authenticate remote servers For bearer-token servers, pass a header when adding the server or store it in JSON config. For OAuth servers, add the server first, then run `/mcp` inside Claude Code and follow the authentication flow. Claude Code can use fixed OAuth callback ports and preconfigured OAuth settings when your environment requires them. ## Plugin-provided MCP servers Claude Code plugins can bundle MCP servers. Plugin servers start when the plugin is enabled and appear alongside manually configured servers in `/mcp`. If you enable or disable a plugin during a session, run: ```text /reload-plugins ``` Plugin-provided MCP servers are managed through plugin installation rather than `claude mcp` commands. ## Output limits Claude Code warns when MCP tool output exceeds 10,000 tokens. To raise the limit for a session: ```bash MAX_MCP_OUTPUT_TOKENS=50000 claude ``` Keep tool outputs focused when possible. Large tool responses increase context pressure and make later turns harder to reason about. ## Tool search and prompts Claude Code can defer large MCP tool lists through tool search, which helps scale when many servers expose many tools. If a server is still connecting when a request needs it, Claude waits while the relevant server becomes available. MCP prompts can also appear as Claude Code commands. Use prompt commands when the server provides reusable workflows in addition to tools. ## Managed configuration Enterprise admins can manage MCP configuration through managed settings. Managed configuration can exclusively control available servers or use allowlists and denylists to restrict which command-based or URL-based servers users may add. Use managed configuration for organization-wide compliance, approved server catalogs, and consistent access rules. ## Troubleshooting ### Server does not appear Run `claude mcp list`, then open `/mcp` inside Claude Code. If the server name is `workspace`, rename it; Claude Code reserves that name for internal use. ### Authentication fails Confirm `MCP_API_KEY` is exported in the shell that launches Claude Code, or re-authenticate OAuth servers through `/mcp`. ### Project server prompts for approval That is expected for servers loaded from `.mcp.json`. Review the config and approve the server if you trust it. ### Tool output is too large Filter the tool call if possible, or start Claude Code with a larger `MAX_MCP_OUTPUT_TOKENS` value. ### Remote server disconnects Open `/mcp` and retry the server. HTTP and SSE transports reconnect automatically for transient errors, but authentication and not-found errors require config changes. ## Next steps For a shorter setup path focused only on your private MCP server, see the [Claude quick start](/docs/quick-start/claude-ai/). For reusable Claude Code workflows, see the [Claude Code Skills quick start](/docs/quick-start/claude-skills/). ### Quick Start: Claude Cowork for Amazon Workflows URL: https://www.kuudo.com/docs/quick-start/claude-cowork-amazon/ Use Claude Cowork with Kuudo's Amazon MCP servers and Amazon Skills to read Amazon data, run analyses, and produce client-ready files from one conversation. This page covers how connectors, MCP servers, and Skills fit together inside Cowork; how to connect the Kuudo Amazon servers; how to manage permissions on Team and Enterprise plans; and which Amazon workflows to try first. Replace the placeholder URLs below with the values from your Kuudo deployment: ```text {kuudo-amazon-ads-mcp-url} {kuudo-amazon-selling-partner-mcp-url} {kuudo-openbridge-mcp-url} ``` ## What Cowork does Claude Cowork is a Claude Desktop workspace for file and task work. It can work with folders you grant it access to, run code in a sandboxed environment, use remote connectors, and apply Skills for repeatable workflows. For Amazon work, the useful part is not file organization. It is that Cowork can combine a folder of client files with Kuudo's Amazon MCP servers and Skills, then produce a report, spreadsheet, listing audit, SQL query, or workflow plan without switching tools. ## The building blocks Kuudo's Amazon workflow stack uses three related concepts. | Layer | What it does | | --- | --- | | Connectors | Let Claude reach approved apps, services, and data sources. | | MCP servers | Expose tools and data through the Model Context Protocol. A connector is backed by an MCP server. | | Skills | Package task-specific expertise so Claude knows how to use the tools correctly. | In practice, the MCP server gives Claude access and the Skill gives Claude the operating playbook. For example, the [Amazon Ads MCP](/features/amazon-ads-mcp/) can pull campaign and search-term data. A search-term mining Skill knows how to separate negative candidates, generic scale terms, branded defense terms, and rising-star queries. ## Kuudo Amazon servers Connect only the servers your workflow needs. Keep write tools approval-gated unless the workflow is deliberately automated. | Server | Connects Cowork to | Common uses | | --- | --- | --- | | [Amazon Ads MCP](/features/amazon-ads-mcp/) | Amazon Ads API, Sponsored Products, Sponsored Brands, Sponsored Display, DSP (demand-side platform), and reporting | Pull campaign, keyword, search-term, targeting, and AMC-related reporting data. | | [Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/) | SP-API (Selling Partner API) surfaces such as catalog, listings, returns, A+ Content, orders, and reports | Audit listings, diagnose suppressed ASINs, inspect returns, and propose controlled listing edits. | | [Amazon Vendor Central MCP](/features/amazon-vendor-central-mcp/) | Vendor Central functions such as retail analytics, direct fulfillment, procurement, and chargebacks | Run vendor reporting, operational checks, and Vendor Central workflows when your deployment includes this surface. | | [Amazon Agent Data layer](/features/amazon-agent-flow/) | Openbridge pipelines and warehouse-backed Amazon data | Query durable Amazon data, inspect subscriptions, validate SQL, and build repeatable reporting workflows. | ## Kuudo Amazon Skills Skills can activate automatically when your request matches their purpose. You can also ask Cowork to use one explicitly by name. | Skill | What it produces | | --- | --- | | `search-term-gold-miner` | Sponsored Products search-term mining with negatives, generic gold terms, branded terms, and rising-star queries. | | `campaign-structure-auditor` | Portfolio health analysis with budget utilization, dead campaigns, ghost campaigns, auto/manual balance, and naming-pattern checks. | | `amazon-ads-reporting` | Amazon Ads report request bodies and report-field mapping. | | `amazon-listing-optimizer` | Listing and A+ Content audits, suppressed-listing diagnosis, and controlled edit suggestions. | | `refund-return-rate-monitor` | Returns reports by ASIN/SKU, reason, disposition, and risk category. | | `amc` and `amc-sql` | Amazon Marketing Cloud SQL, audiences, attribution, and cross-channel analyses. | | `openbridge-mcp` | Table discovery, schema inspection, validated SQL, backfills, and pipeline health checks. | If live MCP access is unavailable, several Skills can still work from a CSV or Seller Central export mounted into the Cowork folder. ## Before you start You need: 1. Claude Cowork access in Claude Desktop. 2. A Kuudo account with active Amazon connections. 3. The remote MCP URLs for the Kuudo servers you want to connect. 4. Owner approval on Team or Enterprise plans when connectors must be enabled organization-wide. Permissions are inherited from the connected source. Cowork does not get more Amazon or Kuudo access than the authenticated user already has. ## Add a Kuudo remote connector Use the custom remote connector path for Kuudo servers unless your deployment appears in a connector marketplace. 1. Open Claude's connector settings. 2. Choose **Add custom connector**. 3. Name the connector clearly, such as `Kuudo Amazon Ads`. 4. Paste the remote MCP URL from your Kuudo deployment. 5. Add OAuth client details if your deployment requires them. 6. Complete the authentication flow. Repeat for each server you need: ```text Amazon Ads MCP: {kuudo-amazon-ads-mcp-url} Amazon Selling Partner MCP: {kuudo-amazon-selling-partner-mcp-url} Openbridge MCP: {kuudo-openbridge-mcp-url} ``` ## Network requirements Cowork may run locally, but remote connectors are reached through Claude's cloud connector path. That means a Kuudo MCP server must be reachable from Claude's connector infrastructure, not just from your laptop. If a server is behind a VPN, private network, or corporate firewall, Cowork will not be able to connect unless your network team exposes an approved remote endpoint or allowlists the required cloud traffic. ## Team and Enterprise setup On Team and Enterprise plans, an Owner or Primary Owner may need to enable custom connectors before members can connect them. Owner flow: 1. Open organization connector settings. 2. Add a custom web connector. 3. Enter the Kuudo remote MCP URL. 4. Configure OAuth details if required. 5. Save the connector for the organization. Member flow: 1. Open personal connector settings. 2. Find the Kuudo connector. 3. Connect it with your own Amazon or Kuudo credentials. Each member authenticates individually. Enabling a connector does not grant shared access to every account. ## Restrict write actions Amazon workflows often mix read-only reporting tools with live write tools. Keep those modes separate. Recommended defaults: | Tool class | Setting | | --- | --- | | Amazon Ads read/report tools | Allow, when the workflow is reporting-only. | | Openbridge read/query tools | Allow, when the workflow only inspects data or runs SQL. | | Listing, catalog, A+ Content, subscription, or job mutation tools | Needs approval. | | Any tool your team never wants run from chat | Blocked. | Use **Needs approval** for listing and catalog changes unless the workflow has a separate human approval gate. ## Enable connectors in a Cowork conversation After the connector is added: 1. Open the Cowork conversation. 2. Open the connector menu from the composer. 3. Toggle on the Kuudo servers for that task. 4. Ask Cowork to list available tools before calling write actions. Example verification prompt: ```text List the Kuudo Amazon tools available in this conversation. Group them by server. Do not call any write actions. ``` If you have many connectors enabled, use on-demand tool access so Cowork loads tool definitions only when needed. ## Use Skills with live data or files Cowork can combine live MCP data with files you mount into the workspace. Useful patterns: | Pattern | How to ask | | --- | --- | | Live data first | "Use the Amazon Ads MCP to pull the latest Sponsored Products search-term report, then run search-term-gold-miner." | | CSV fallback | "Use this Seller Central export and run the campaign-structure-auditor Skill. Do not call live tools." | | File output | "Write the final report as an xlsx and a markdown summary in this folder." | | Controlled write | "Prepare the listing patch, but do not submit it until I approve the exact diff." | ## Example Amazon workflows ### Search-term mining Ask: ```text Pull the last 60 days of Sponsored Products search-term data and find negative candidates, generic gold keywords, branded defense terms, and rising queries. ``` Cowork uses the Amazon Ads MCP to gather the report, then applies the search-term mining Skill to produce an action list. ### Campaign structure audit Ask: ```text Audit my Sponsored Products portfolio for dead campaigns, budget concentration, and auto/manual balance. ``` The Skill checks the available fields, validates thresholds, and returns a portfolio-health report. ### Listing optimization Ask: ```text Review ASIN B0XXXXXXXX. Check title, bullets, images, and A+ Content. Propose a patch, but do not write anything live without approval. ``` Cowork reads listing context through the Selling Partner MCP and uses the listing optimizer Skill to produce a controlled diff. ### Returns analysis Ask: ```text Build a Q1 returns report by ASIN with top return reasons, dispositions, controllable issues, and red-flag products. Save it as a spreadsheet. ``` The returns Skill classifies issues and writes the deliverable to the mounted folder. ### Warehouse SQL through the Agent Data layer Ask: ```text Use the Amazon Agent Data layer to find my Amazon Ads tables, inspect the schema, and run SQL for spend by campaign last month. ``` The Openbridge Skill discovers tables, checks schema rules, and runs validated SQL through the query layer. ### Amazon Marketing Cloud analysis Ask: ```text Write an AMC query for new-to-brand reach across Sponsored Products and DSP last month. Explain which tables the query uses and why. ``` The AMC Skill produces SQL and explains the table choices before you schedule or export the workflow. ## Recurring work After Cowork builds a repeatable workflow, ask it to turn the steps into a recurring report or documented Skill: ```text Turn this search-term mining workflow into a weekly report. Keep write actions approval-gated. Save the runbook and output template in this folder. ``` For durable, data-backed automation, combine the Amazon Ads MCP or Selling Partner MCP with [Skills](/features/skills/) and the [Amazon Agent Data layer](/features/amazon-agent-flow/). ## Security checklist - Connect only servers you trust. - Review OAuth scopes before signing in. - Keep write tools on **Needs approval** by default. - Disable write tools before unattended or research-style runs. - Do not paste API keys, OAuth secrets, or client credentials into chat. - Use mounted folders deliberately; Cowork can only work with folders you grant. - Treat MCP tool output as untrusted input when it comes from unfamiliar servers. ## Troubleshooting | Symptom | Check | | --- | --- | | Connector does not connect | Confirm the remote MCP URL is reachable from Claude's connector path, not just your laptop. | | Authentication fails | Disconnect and reconnect with the correct Amazon or Kuudo account. | | A Skill does not activate | Name the Skill explicitly and make sure the matching MCP server is enabled. | | Tool names do not match the prompt | Ask Cowork to list available tools by server before running the task. | | Live write action appears unexpectedly | Move that tool category to **Needs approval** or **Blocked**. | ## Quick reference | Task | Connect | Skill | | --- | --- | --- | | Search-term mining | Amazon Ads MCP | `search-term-gold-miner`, `amazon-ads-reporting` | | Campaign audit | Amazon Ads MCP | `campaign-structure-auditor` | | Listing fixes | Amazon Selling Partner MCP | `amazon-listing-optimizer` | | Returns analysis | Amazon Selling Partner MCP | `refund-return-rate-monitor` | | Warehouse SQL | Amazon Agent Data layer / Openbridge MCP | `openbridge-mcp` | | AMC analysis | Amazon Ads MCP with AMC access | `amc`, `amc-sql` | ### Quick Start: Codex URL: https://www.kuudo.com/docs/quick-start/codex/ From Codex you get live Amazon data in the repository you are already working in: pull real campaign or catalog data while you build, prototype an Amazon agent against it, and keep the same scoped auth in both the CLI and the IDE extension. Connect Codex to your private MCP server so it can use your tools while working in a local repository. Codex shares MCP configuration between the CLI and IDE extension, so you only need to add the server once. Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace `{your-private-mcp-host}` with the private host shown in your dashboard. ## Prerequisites - Codex CLI installed and signed in. - A connected workspace with access to your private MCP server. - A dashboard API key from the **Keys** tab. - The private MCP host assigned to your deployment. ## Copy prompt Paste this into Codex if you want it to walk you through setup: ```text Walk me through setting up my private MCP server in Codex, step by step. Use the Codex CLI MCP configuration, not a local wrapper or one-off script. Use the private host from my dashboard: https://{your-private-mcp-host}/mcp Use my local MCP_API_KEY environment variable. Do not ask me to paste or share the raw key in chat. If MCP_API_KEY is not set in this shell, tell me to export it from my dashboard first. Add the server with: codex mcp add private-mcp --url https://{your-private-mcp-host}/mcp --bearer-token-env-var MCP_API_KEY Then verify it with: codex mcp list In the Codex TUI, verify the active server with: /mcp ``` ## 1. Set your local key Set the API key in the shell that launches Codex: ```bash export MCP_API_KEY="mcp_live_..." ``` For repeated use, store it in your shell profile or secret manager. Do not commit the raw value to the repository. ## 2. Add the MCP server Add the remote HTTP MCP server: ```bash codex mcp add private-mcp \ --url https://{your-private-mcp-host}/mcp \ --bearer-token-env-var MCP_API_KEY ``` Codex reads the bearer token from `MCP_API_KEY` at runtime. This keeps the raw key out of `~/.codex/config.toml`. ## 3. Verify the server List configured MCP servers: ```bash codex mcp list ``` Inspect the saved entry: ```bash codex mcp get private-mcp ``` In the Codex TUI, use `/mcp` to see active MCP servers for the current session. If the server is configured, Codex can expose its tools in CLI sessions and in the Codex IDE extension. ## Alternative: config file You can also add the server directly in `~/.codex/config.toml`. For trusted projects, you can scope configuration to the repository with `.codex/config.toml`. ```toml [mcp_servers.private-mcp] url = "https://{your-private-mcp-host}/mcp" bearer_token_env_var = "MCP_API_KEY" ``` Restart any running Codex session after editing the config file. ## Optional controls Codex supports extra controls for Streamable HTTP MCP servers. Add them only when you need tighter behavior: ```toml [mcp_servers.private-mcp] url = "https://{your-private-mcp-host}/mcp" bearer_token_env_var = "MCP_API_KEY" enabled_tools = ["search", "fetch"] disabled_tools = ["delete_record"] default_tools_approval_mode = "prompt" tool_timeout_sec = 60 [mcp_servers.private-mcp.tools.fetch] approval_mode = "approve" ``` Use `enabled_tools` for allow lists, `disabled_tools` for deny lists, and `default_tools_approval_mode` to control whether Codex calls tools automatically or prompts first. Supported approval modes are `auto`, `prompt`, and `approve`. If your MCP server uses OAuth instead of bearer-token authentication, add the server first, then run: ```bash codex mcp login private-mcp ``` ## Troubleshooting ### Unauthorized or 401 errors Make sure `MCP_API_KEY` is exported in the shell or environment that launches Codex. The key must belong to the same workspace as the private MCP server. ### Server not listed Run `codex mcp list`. If `private-mcp` is missing, add it again with the CLI command above or check `~/.codex/config.toml`. ### Tools not available in a session Restart Codex after changing MCP config. If you are using the IDE extension, restart the extension or reload the editor window. In the Codex TUI, run `/mcp` to confirm the server is active. ### CLI flags differ from your installed version Run `codex mcp add --help` and `codex mcp --help`. Codex versions can differ, but Streamable HTTP servers should be represented by a URL in `config.toml`, and bearer auth should use `bearer_token_env_var`. ### Slow responses Check your network path to the private host and confirm the cloud deployment is healthy. The hostname is specific to your environment, so connectivity issues are usually tied to your cloud provider, DNS, firewall, or deployment status. ## Start using tools Try read-only prompts first: - "What MCP tools are available from `private-mcp`?" - "List the read-only tools before calling any write actions." - "Use `private-mcp` to inspect the current workspace context." For write-capable workflows, ask Codex to explain the proposed action and wait for approval before it calls any mutating tool. ## Add reusable workflows After Codex can reach your MCP server, install Codex skills for repeatable workflows and task-specific instructions. See the [Codex Skills quick start](/docs/quick-start/codex-skills/). ### Quick Start: OpenClaw MCP URL: https://www.kuudo.com/docs/quick-start/openclaw/ OpenClaw runs long Amazon jobs end to end. Give it a goal — pull the week's Sponsored Products performance, find the ASINs losing the Buy Box, draft the listing fixes — and it plans, calls the Amazon tools in order, and hands back the result with every tool call traced. Use OpenClaw's MCP client registry when you want an OpenClaw-managed runtime to know about your private MCP server. For the official reference, see [OpenClaw `mcp`](https://docs.openclaw.ai/cli/mcp). Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace `{your-private-mcp-host}` with the private host shown in your dashboard. ## Before you start - Install and configure OpenClaw. - Create an API key from the dashboard **Keys** tab. - Keep the key in `MCP_API_KEY` or another local secret source. - Confirm the private MCP endpoint ends with `/mcp`. ```text https://{your-private-mcp-host}/mcp ``` ## Understand OpenClaw MCP modes OpenClaw's MCP command has two different modes: | Command shape | What it does | | --- | --- | | `openclaw mcp serve` | Runs OpenClaw itself as a stdio MCP server for another MCP client. | | `openclaw mcp set/list/show/unset` | Manages outbound MCP server definitions saved under `mcp.servers`. | Use `openclaw mcp set` to register your existing private MCP server. This saves configuration only; it does not open a live MCP session or validate that the remote server is reachable. ## Register the server Set your key in the environment OpenClaw or its runtime adapter will use: ```bash export MCP_API_KEY="mcp_live_..." ``` Add the remote MCP server definition: ```bash openclaw mcp set private-mcp '{"transport":"streamable-http","url":"https://{your-private-mcp-host}/mcp","headers":{"Authorization":"Bearer ${MCP_API_KEY}"}}' ``` Keep the single quotes around the JSON so OpenClaw stores the literal environment-variable reference. ## Inspect the saved definition List saved MCP servers: ```bash openclaw mcp list ``` Show the saved server: ```bash openclaw mcp show private-mcp --json ``` If the entry appears, OpenClaw has saved the registry definition. A runtime adapter still has to load that definition and open a connection before tools are available. ## Manual config form OpenClaw stores MCP definitions under `mcp.servers`. The manual shape is: ```json { "mcp": { "servers": { "private-mcp": { "transport": "streamable-http", "url": "https://{your-private-mcp-host}/mcp", "headers": { "Authorization": "Bearer ${MCP_API_KEY}" } } } } } ``` OpenClaw supports stdio, SSE/HTTP, and streamable HTTP definitions. For a modern remote MCP endpoint, set `"transport": "streamable-http"`. If `transport` is omitted, OpenClaw treats a URL-based entry as SSE/HTTP. ## Troubleshooting ### The server is saved but tools do not appear `openclaw mcp set` only writes configuration. Restart or reload the OpenClaw runtime adapter that consumes MCP registry entries, then check whether it opens the saved server. ### Authentication fails Confirm `MCP_API_KEY` is set in the environment that launches the runtime adapter, not only in a separate terminal. If you changed the variable while OpenClaw was already running, restart the process. ### The endpoint does not connect Confirm the endpoint uses your private host and the normal bearer-auth MCP path: ```text https://{your-private-mcp-host}/mcp ``` Do not use a Claude-only signed connector URL such as `/mcp/connect/{signed-token}` for OpenClaw. ## Related docs - [MCP Client Configuration](/docs/mcp-client-configuration/) - [Claude Code MCP](/docs/quick-start/claude-code-mcp/) - [Codex MCP](/docs/quick-start/codex/) ### Quick Start: Hermes MCP URL: https://www.kuudo.com/docs/quick-start/hermes/ Agent runtimes are where multi-step Amazon work actually finishes. Hand Hermes a goal — audit a catalog and patch the listings that fail validation, build an Amazon Marketing Cloud (AMC) audience and stage it for activation, reconcile a month of Fulfillment by Amazon (FBA) reimbursements — and it plans the work, calls the Amazon tools in order, and returns the artifact. That is the autonomous Amazon operator teams go looking for, running in the agent runtime you chose, against accounts you already own. Use Hermes Agent's MCP client support when you want Hermes to discover and call tools from your private MCP server. For the official reference, see [Hermes Agent MCP](https://hermes-agent.nousresearch.com/docs/user-guide/features/mcp). Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace `{your-private-mcp-host}` with the private host shown in your dashboard. ## Before you start - Install Hermes Agent. - Confirm MCP support is installed. Standard installs include it, but the Hermes docs show `uv pip install -e ".[mcp]"` when needed. - Create an API key from the dashboard **Keys** tab. - Store the key in `MCP_API_KEY` or another local secret source. - Confirm the private MCP endpoint ends with `/mcp`. ```text https://{your-private-mcp-host}/mcp ``` ## Understand Hermes MCP modes Hermes supports both directions: | Mode | What it does | | --- | --- | | Hermes as an MCP client | Hermes connects to local stdio servers or remote HTTP MCP servers listed under `mcp_servers`. | | Hermes as an MCP server | `hermes mcp serve` exposes Hermes messaging capabilities to another MCP client over stdio. | Use `mcp_servers` when you want Hermes to connect to your existing private MCP server. ## Add the remote MCP server Store the key in the environment that launches Hermes. You can use `~/.hermes/.env` or your process manager's secret mechanism: ```dotenv MCP_API_KEY=mcp_live_... ``` Add the server under the top-level `mcp_servers` key in `~/.hermes/config.yaml`: ```yaml mcp_servers: private-mcp: url: "https://{your-private-mcp-host}/mcp" headers: Authorization: "Bearer ${MCP_API_KEY}" enabled: true timeout: 120 connect_timeout: 60 ``` Hermes reads remote HTTP MCP servers from `url` and `headers`. It discovers MCP tools at startup and registers them into the normal Hermes tool registry. ## Reload Hermes After saving config, restart Hermes or reload MCP config from a Hermes session: ```text /reload-mcp ``` If `MCP_API_KEY` is unset in the environment that launches Hermes, the placeholder may remain literal and authentication will fail. ## Tool names and filtering Hermes prefixes MCP tools to avoid name collisions: ```text mcp__ ``` For a server named `private-mcp`, a tool named `search` is registered as something like: ```text mcp_private_mcp_search ``` You can limit which tools Hermes exposes from a server: ```yaml mcp_servers: private-mcp: url: "https://{your-private-mcp-host}/mcp" headers: Authorization: "Bearer ${MCP_API_KEY}" tools: include: [search, fetch] resources: false prompts: false ``` Use `include` for a small allowlist, `exclude` to hide dangerous tools, and `resources: false` or `prompts: false` when you do not want Hermes to expose MCP resource or prompt utility wrappers for that server. ## Optional parallel tool calls Hermes runs MCP tools sequentially by default. Only enable parallel execution when the server's tools are safe to run concurrently: ```yaml mcp_servers: private-mcp: url: "https://{your-private-mcp-host}/mcp" headers: Authorization: "Bearer ${MCP_API_KEY}" supports_parallel_tool_calls: true ``` Do not enable this for tools that write shared state, mutate records, or depend on strict call order. ## Troubleshooting ### Tools do not appear Check that Hermes can connect to the server, that discovery succeeds, and that your `tools.include` or `tools.exclude` settings did not filter everything out. If the server is set to `enabled: false`, Hermes skips it entirely. ### Authentication fails Confirm `MCP_API_KEY` is present in the Hermes process environment. Restart Hermes after changing environment variables. ### Resource or prompt helpers are missing Hermes only registers resource and prompt utility wrappers when the MCP server supports those capabilities and your config allows them. ### You want Hermes to be the MCP server That is a different flow. Use: ```bash hermes mcp serve ``` This starts a stdio MCP server that another MCP client manages. It is not the path for connecting Hermes to your private remote MCP server. ## Related docs - [MCP Client Configuration](/docs/mcp-client-configuration/) - [OpenClaw MCP](/docs/quick-start/openclaw/) - [Codex MCP](/docs/quick-start/codex/) ### Quick Start: n8n MCP URL: https://www.kuudo.com/docs/quick-start/n8n/ Workflow builders are where Amazon work gets scheduled instead of asked for. From n8n you can run the same Amazon operations on a cron or an upstream event — the nightly Sponsored Products pull, a listing patch when a feed lands, an Amazon Marketing Cloud (AMC) audience staged for the demand-side platform (DSP) — with the same scoped auth and audit trail as chat. Use n8n's **MCP Client Tool** node when you want an n8n AI Agent workflow to call tools exposed by your private MCP server. For the official reference, see [n8n MCP Client Tool node](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.toolmcp/). Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace `{your-private-mcp-host}` with the private host shown in your dashboard. ## Before you start - An n8n instance with AI Agent nodes available. - A workflow with an AI Agent or model node that can use tools. - A dashboard API key from the **Keys** tab. - The private MCP endpoint assigned to your deployment. ```text https://{your-private-mcp-host}/mcp ``` ## Understand n8n MCP modes n8n has two different MCP surfaces: | Node | What it does | | --- | --- | | MCP Client Tool | Connects an n8n AI Agent workflow to tools exposed by an external MCP server. | | MCP Server Trigger | Exposes n8n workflow tools to external AI agents. | Use **MCP Client Tool** when connecting n8n to your private MCP server. ## Add the MCP Client Tool node In n8n: 1. Open the workflow that contains your AI Agent. 2. Add a tool node to the agent. 3. Choose **MCP Client Tool**. 4. Connect the MCP Client Tool node to the AI Agent's tool input. The node acts as an MCP client. It discovers tools from the external MCP server and makes the selected tools available to the agent. ## Configure the endpoint In the MCP Client Tool node, set **SSE Endpoint** to the MCP endpoint from your dashboard: ```text https://{your-private-mcp-host}/mcp ``` n8n's field label is **SSE Endpoint**. Use the endpoint format your MCP server supports for n8n. If your dashboard provides a separate n8n or SSE-compatible URL, use that value instead of the generic `/mcp` endpoint. ## Configure authentication The MCP Client Tool node supports bearer, generic header, and OAuth2 authentication. For a bearer token from your dashboard: 1. Set **Authentication** to **Bearer** if available in your n8n version. 2. Paste only the API key value into n8n's credential form. 3. Save the credential. If your n8n version uses generic header authentication instead: | Field | Value | | --- | --- | | Header name | `Authorization` | | Header value | `Bearer ` | Do not paste the raw API key into prompts, sticky notes, or workflow descriptions. Store it in n8n credentials. ## Choose which tools to expose Use **Tools to Include** to control the tool surface the AI Agent can see: | Option | Effect | | --- | --- | | All | Exposes every tool returned by the MCP server. | | Selected | Exposes only the tools you select. | | All Except | Exposes every tool except the tools you exclude. | Start with **Selected** for production workflows. Give the agent only the read or action tools needed for that workflow. ## Test the workflow Run a manual execution and ask the AI Agent for a read-only check first: ```text List the available MCP tools and explain what each one can do. Do not call write actions. ``` If the tools appear, test one low-risk read action. Add human approval or review steps before giving the workflow access to mutating tools. ## Troubleshooting ### The node cannot connect Confirm the endpoint matches the private host in your dashboard and that it is reachable from the n8n runtime. Self-hosted n8n instances may need outbound network access to the private host. ### Authentication fails Create a fresh dashboard API key and update the n8n credential. Make sure the credential sends either bearer auth or an `Authorization: Bearer ...` header, not both. ### Tools do not appear Check that the MCP server exposes tools, the endpoint supports the transport expected by n8n, and **Tools to Include** is not filtering everything out. ### You want n8n to be the MCP server That is the **MCP Server Trigger** node, not the MCP Client Tool node. Use MCP Server Trigger when another agent should call n8n workflows as tools. ## Related docs - [MCP Client Configuration](/docs/mcp-client-configuration/) - [OpenClaw MCP](/docs/quick-start/openclaw/) - [Hermes MCP](/docs/quick-start/hermes/) ### Quick Start: Activepieces MCP URL: https://www.kuudo.com/docs/quick-start/activepieces/ From Activepieces the Amazon work runs on a trigger rather than a prompt: schedule the report pull, patch listings when an upstream event fires, stage an audience once a threshold is crossed. Same scoped auth as every other client, no prompt required. Use the **Run Agent** step's **Agent Tools** area when you want an Activepieces agent to connect to your private MCP server. Activepieces also has built-in MCP server features for exposing Activepieces to MCP clients. That is the opposite direction. For the official server-side reference, see [Activepieces MCP Server](https://www.activepieces.com/docs/mcp/overview). Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace `{your-private-mcp-host}` with the private host shown in your dashboard. ## Before you start - Access to an Activepieces workspace where you can edit flows. - A flow with a **Run Agent** step, or permission to add one. - A private MCP server endpoint from your dashboard. - An API key from the dashboard **Keys** tab, if your server requires bearer or header authentication. - Confirmation of which authentication modes your Activepieces workspace exposes after opening the **Authentication Type** dropdown. ```text https://{your-private-mcp-host}/mcp ``` ## Understand the direction Activepieces can appear in MCP workflows in two different ways: | Flow | What it does | | --- | --- | | Run Agent > Agent Tools > Add MCP Server | Activepieces connects an agent step to an external MCP server and can use its tools. | | Activepieces MCP Server | Activepieces exposes its own tools to external MCP clients such as Claude, Cursor, or Windsurf. | Use **Run Agent > Agent Tools** when connecting Activepieces to your private MCP server. ## Open Run Agent In your Activepieces flow, add or open a **Run Agent** step. The observed Run Agent step includes: | Area | What to configure | | --- | --- | | Prompt | Describe what you want the assistant to do. | | AI Model | Choose the provider and model, such as OpenAI and `gpt-5-mini`. | | Agent Tools | Connect apps, flows, MCPs, and other tools the agent can use. | The **Agent Tools** area may show installed app icons, such as YouTube, Slack, GitHub, Notion, and a `+500` indicator for additional integrations. Use **Add** from this area to connect more tools. ## Add an MCP tool From **Run Agent > Agent Tools**, click **Add**, then choose the MCP option. The current MCP form is **Add MCP Server**. The form has four visible fields and two action buttons. **Validate Server** stays disabled until required fields are filled. | Field | Required | Input type | Expected input | | --- | ---: | --- | --- | | MCP Name | Yes | Text input | A short identifier, such as `private-mcp` or `my-mcp-server`. | | Server URL | Yes | Text input | Your private MCP endpoint, such as `https://{your-private-mcp-host}/mcp`. | | Protocol | Yes | Dropdown / combobox | Select **Streamable HTTP** unless your dashboard provides a different Activepieces-specific endpoint. | | Authentication Type | Yes | Dropdown / combobox | Select the auth mode that matches your server. The observed default is **None**. | Recommended generic values: ```text MCP Name: private-mcp Server URL: https://{your-private-mcp-host}/mcp Protocol: Streamable HTTP Authentication Type: Bearer or header-based auth, if available ``` ## Configure authentication The observed form only shows **Authentication Type = None** while the dropdown is closed. It does not confirm which auth modes are available or whether choosing an auth mode reveals header fields. If Activepieces supports bearer authentication, store the API key in the credential or secret field Activepieces provides. If Activepieces supports custom headers, use this header shape: ```text Authorization: Bearer ${MCP_API_KEY} ``` Do not paste a raw live key into labels, descriptions, prompts, or workflow notes. Use Activepieces' credential or secret storage if the form provides one. ## Validate the server After the required fields and authentication details are set, click **Validate Server**. Validation should confirm that Activepieces can reach the MCP endpoint, negotiate the selected protocol, and authenticate if required. After validation succeeds, save or add the MCP server so it appears in the Run Agent step's **Agent Tools** list. ## Troubleshooting ### Validate Server is disabled Fill every required field: **MCP Name**, **Server URL**, **Protocol**, and **Authentication Type**. The button should remain disabled while any required field is empty. ### Authentication Type only shows None Open the dropdown and check for bearer, header, OAuth, or custom authentication options. If none are available, the current Activepieces surface may only support unauthenticated MCP servers in that form. ### The server URL fails Confirm the URL uses the private host from your dashboard and the MCP path: ```text https://{your-private-mcp-host}/mcp ``` If your dashboard provides an Activepieces-specific or SSE-compatible endpoint, use that URL instead. ### Validation succeeds but tools do not appear Check whether Activepieces requires a second step to choose tools, enable the server, or attach the MCP server to the **Run Agent** step. Also confirm the server exposes tools over the selected protocol. ## Related docs - [MCP Client Configuration](/docs/mcp-client-configuration/) - [n8n MCP](/docs/quick-start/n8n/) - [Hermes MCP](/docs/quick-start/hermes/) ### MCP Client Configuration URL: https://www.kuudo.com/docs/mcp-client-configuration/ Use these examples to connect MCP clients and custom agents to your private MCP server. Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace every example host below with the private host shown in your dashboard. ```text https://{your-private-mcp-host}/mcp ``` For example, your endpoint might look like a private application hostname from AWS, GCP, Azure, Cloudflare, or your internal DNS. Do not assume any public example hostname is your production host unless your dashboard explicitly shows it. ## Before you start Create an API key from the dashboard **Keys** tab. Header-capable clients authenticate with an `Authorization` bearer header. Prefer injecting `MCP_API_KEY` from your local environment or secret manager instead of pasting keys into chat, screenshots, repositories, or shared config. Claude custom connectors are different: they use the signed Claude connector URL from the same **Keys** tab. | Client | Auth shape | | --- | --- | | Claude custom connector | Signed `/mcp/connect/{token}` URL | | Claude Code | Bearer header from `MCP_API_KEY` | | Codex | `codex mcp add` with bearer token environment variable | | OpenClaw | `mcp.servers` entry with bearer header. See [OpenClaw MCP](/docs/quick-start/openclaw/). | | Hermes Agent | `mcp_servers` entry with bearer header. See [Hermes MCP](/docs/quick-start/hermes/). | | n8n | MCP Client Tool node with bearer, header, or OAuth2 auth. See [n8n MCP](/docs/quick-start/n8n/). | | Activepieces | Run Agent > Agent Tools > Add MCP Server with Streamable HTTP and optional auth. See [Activepieces MCP](/docs/quick-start/activepieces/). | | Cursor | Bearer header from `MCP_API_KEY` | | Custom agent | Remote HTTP MCP endpoint plus bearer header | ## Hostname placeholders Use these placeholders consistently: | Placeholder | Meaning | | --- | --- | | `{your-private-mcp-host}` | The private MCP hostname assigned to your deployment by your cloud provider. | | `{signed-token}` | The dashboard-generated token embedded in the Claude connector URL. | | `MCP_API_KEY` | Your local environment variable or secret-manager value for bearer auth. | Use the normal `/mcp` endpoint for bearer-auth clients. Reserve `/mcp/connect/{signed-token}` for Claude custom connectors. ## Claude custom connector Copy the Claude connector URL from the dashboard, then add it in Claude through **Customize > Connectors > Add custom connector**. Name the connector something clear, such as `private-mcp`. ```text https://{your-private-mcp-host}/mcp/connect/{signed-token} ``` Use the signed connector URL for this flow. The Claude custom connector UI does not accept a separate `Authorization` header. ## Claude Code Set your key once, then add the remote HTTP MCP server from any Claude Code session. ```bash export MCP_API_KEY="mcp_live_..." claude mcp add --transport http private-mcp https://{your-private-mcp-host}/mcp \ --header 'Authorization: Bearer ${MCP_API_KEY}' ``` Add `--scope project` to share the server through the repository's `.mcp.json`, or `--scope user` for your local Claude Code profile. JSON form: ```bash claude mcp add-json private-mcp '{ "type": "http", "url": "https://{your-private-mcp-host}/mcp", "headers": { "Authorization": "Bearer ${MCP_API_KEY}" } }' ``` ## Codex Set your key once, then add the remote HTTP MCP server with the Codex CLI. Codex shares MCP configuration between the CLI and IDE extension. ```bash export MCP_API_KEY="mcp_live_..." codex mcp add private-mcp \ --url https://{your-private-mcp-host}/mcp \ --bearer-token-env-var MCP_API_KEY ``` Config file form: ```toml [mcp_servers.private-mcp] url = "https://{your-private-mcp-host}/mcp" bearer_token_env_var = "MCP_API_KEY" ``` Verify with `codex mcp list`. In the Codex TUI, run `/mcp` to see active servers for the current session. For trusted projects, you can scope configuration to the repository with `.codex/config.toml`. Optional controls: ```toml [mcp_servers.private-mcp] url = "https://{your-private-mcp-host}/mcp" bearer_token_env_var = "MCP_API_KEY" enabled_tools = ["search", "fetch"] disabled_tools = ["delete_record"] default_tools_approval_mode = "prompt" tool_timeout_sec = 60 ``` If your server uses OAuth instead of bearer-token authentication, add the server first, then run `codex mcp login private-mcp`. ## OpenClaw For a dedicated walkthrough, see [Quick Start: OpenClaw MCP](/docs/quick-start/openclaw/). OpenClaw's MCP command has two different modes: - `openclaw mcp serve` runs OpenClaw itself as a stdio MCP server for another client. - `openclaw mcp set`, `list`, `show`, and `unset` manage OpenClaw-owned outbound MCP server definitions under `mcp.servers`. Use the `set` path when you want an OpenClaw-managed runtime to know about your private MCP server. This saves the server definition in OpenClaw config; it does not start a live MCP session or prove the remote server is reachable. Set your key in the environment OpenClaw uses, then register the private server with OpenClaw's `mcp.servers` config shape. ```bash export MCP_API_KEY="mcp_live_..." openclaw mcp set private-mcp '{"transport":"streamable-http","url":"https://{your-private-mcp-host}/mcp","headers":{"Authorization":"Bearer ${MCP_API_KEY}"}}' ``` Keep the single quotes around the JSON so OpenClaw stores the literal environment-variable reference. Inspect the saved definition: ```bash openclaw mcp list openclaw mcp show private-mcp --json ``` OpenClaw supports stdio, SSE/HTTP, and streamable HTTP definitions. For a modern remote MCP endpoint, set `"transport": "streamable-http"`. If `transport` is omitted, OpenClaw treats a URL-based entry as SSE/HTTP. If you set `MCP_API_KEY` after OpenClaw or a runtime adapter is already running, restart that process before expecting it to read the new environment variable. Runtime adapters decide which saved MCP definitions they consume and when they open a connection. Manual config form: ```json { "mcp": { "servers": { "private-mcp": { "transport": "streamable-http", "url": "https://{your-private-mcp-host}/mcp", "headers": { "Authorization": "Bearer ${MCP_API_KEY}" } } } } } ``` For the official OpenClaw reference, see [OpenClaw `mcp`](https://docs.openclaw.ai/cli/mcp). ## Hermes Agent For a dedicated walkthrough, see [Quick Start: Hermes MCP](/docs/quick-start/hermes/). Store your key in `~/.hermes/.env` or the environment that launches Hermes, then add the private server under the top-level `mcp_servers` key in `~/.hermes/config.yaml`. ```dotenv MCP_API_KEY=mcp_live_... ``` ```yaml mcp_servers: private-mcp: url: "https://{your-private-mcp-host}/mcp" headers: Authorization: "Bearer ${MCP_API_KEY}" enabled: true timeout: 120 connect_timeout: 60 ``` Hermes expands `${MCP_API_KEY}` from its local environment. If the variable is unset, the placeholder remains literal and authentication fails. Restart Hermes or run `/reload-mcp` after saving config changes. Hermes discovers tools at startup or reload time and prefixes them as `mcp__`. ## n8n For a dedicated walkthrough, see [Quick Start: n8n MCP](/docs/quick-start/n8n/). Use n8n's **MCP Client Tool** node when an n8n AI Agent workflow should call tools from your private MCP server. n8n also has an **MCP Server Trigger** node, but that is the opposite direction: it exposes n8n workflows to external agents. In the MCP Client Tool node: | n8n field | Value | | --- | --- | | SSE Endpoint | `https://{your-private-mcp-host}/mcp` | | Authentication | Bearer, generic header, or OAuth2 | | Tools to Include | `Selected` for narrow production workflows, or `All` while testing | For generic header auth, use: | Header | Value | | --- | --- | | `Authorization` | `Bearer ` | Store the key in n8n credentials. Do not paste raw keys into workflow descriptions, sticky notes, or prompts. ## Activepieces For a dedicated walkthrough, see [Quick Start: Activepieces MCP](/docs/quick-start/activepieces/). Use the **Run Agent** step's **Agent Tools** area when an Activepieces agent should connect to your private MCP server. Click **Add** under Agent Tools, then choose the MCP option. This is separate from Activepieces' own MCP server feature, which exposes Activepieces tools to external MCP clients. Current visible Add MCP Server fields: | Field | Value | | --- | --- | | MCP Name | `private-mcp` | | Server URL | `https://{your-private-mcp-host}/mcp` | | Protocol | `Streamable HTTP` | | Authentication Type | Bearer or header-based auth if available; otherwise the observed default is `None` | If the form exposes custom headers, use: ```text Authorization: Bearer ${MCP_API_KEY} ``` Use Activepieces credential or secret storage for the key if the form provides it. Do not paste raw live keys into labels, descriptions, prompts, or workflow notes. ## Cursor For repository scope, save this as `.cursor/mcp.json`. For user scope, save it as `~/.cursor/mcp.json`. ```json { "mcpServers": { "private-mcp": { "url": "https://{your-private-mcp-host}/mcp", "headers": { "Authorization": "Bearer ${MCP_API_KEY}" } } } } ``` Restart Cursor or reload the MCP server list after saving the file. ## Header-capable clients Most MCP clients use an `mcpServers` object with a remote URL and request headers. ```json { "mcpServers": { "private-mcp": { "url": "https://{your-private-mcp-host}/mcp", "headers": { "Authorization": "Bearer ${env:MCP_API_KEY}" } } } } ``` Check your client documentation for its exact environment-variable interpolation syntax. Some clients use `${MCP_API_KEY}`; others use `${env:MCP_API_KEY}`. ## Custom agent If your agent owns its MCP client layer, store the endpoint and header in your agent configuration and inject the API key from a secret manager or environment variable. ```json { "name": "private-mcp", "transport": "http", "url": "https://{your-private-mcp-host}/mcp", "headers": { "Authorization": "Bearer ${MCP_API_KEY}" }, "capabilities": { "tools": true, "resources": true } } ``` Use `https://{your-private-mcp-host}/mcp` for normal bearer auth. Reserve `https://{your-private-mcp-host}/mcp/connect/{signed-token}` for Claude custom connectors. ## Verify the connection After adding the server, restart or reload the MCP client and ask it to list the available tools. If the server does not appear, check three things first: 1. The hostname matches the private host in your dashboard. 2. `MCP_API_KEY` is set in the environment that launches the client. 3. The client is using `/mcp` for bearer auth or `/mcp/connect/{signed-token}` for Claude custom connectors, not both. ### Quick Start: NanoClaw MCP URL: https://www.kuudo.com/docs/quick-start/nanoclaw/ NanoClaw puts that agent in a messaging app. Ask from WhatsApp, Telegram, Slack, or Discord and it runs the Amazon work on hardware you control — inventory checks, campaign pulls, listing fixes — and answers in the thread. Use NanoClaw when you want a personal agent that answers from a messaging app rather than a terminal, and you want it running on hardware you control. NanoClaw is open source (MIT), runs each agent inside a container, and is built on Anthropic's Agents SDK. For the official reference, see [NanoClaw](https://nanoclaw.dev/), the [skills index](https://nanoclaw.dev/skills), and the [repository](https://github.com/nanocoai/nanoclaw). Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace `{your-private-mcp-host}` with the private host shown in your dashboard. ## Before you start - Install Node.js 20+, pnpm 10+, Docker, and Claude Code. - Use macOS, Linux, or Windows with WSL2. - Create an API key from the dashboard **Keys** tab. - Keep the key in `MCP_API_KEY` or another local secret source. - Confirm the private MCP endpoint ends with `/mcp`. ```text https://{your-private-mcp-host}/mcp ``` ## Install NanoClaw ![Terminal showing the three NanoClaw install commands: git clone into nanoclaw-v2, cd into it, then bash nanoclaw.sh, followed by prerequisite checks and container build output.](/assets/images/docs/nanoclaw-install.svg) ```bash git clone https://github.com/nanocoai/nanoclaw.git nanoclaw-v2 cd nanoclaw-v2 bash nanoclaw.sh ``` The installer resolves missing dependencies, registers credentials, builds the container, and walks you through connecting a first messaging channel. Channels are added on demand with their own skills, such as `/add-telegram` or `/add-slack`. ## Know which config you are editing NanoClaw has two separate MCP surfaces, and they are easy to confuse. | Surface | Who reads it | Shape | | --- | --- | --- | | `.mcp.json` in the repo root | Claude Code, while you work in the repo | Standard `mcpServers` client config | | `container/agent-runner` | The running agent, inside its container | Registered stdio servers plus forwarded env vars | Editing the repo root file gives *you* the tools while customizing. It does not give them to the agent answering in your messaging app. That agent loads servers registered in the container runner, whose config takes `command`, `args`, and `env` — a stdio contract, with no field for a remote URL or headers. So a remote HTTPS endpoint reaches the agent through a stdio bridge. That is what the fast path below sets up for you, and what the manual form spells out. ## Fast path: the customize skill Run Claude Code from the cloned repository and start the interactive skill: ```bash cd nanoclaw-v2 claude ``` ```text /customize ``` Ask for a remote MCP integration and give it three things: - the endpoint, `https://{your-private-mcp-host}/mcp` - the auth header, `Authorization: Bearer ${MCP_API_KEY}` - which agents should get the tools The skill writes the bridge into the agent-runner tree, registers the server, and forwards the key into the container. It is an interactive skill, so the prompts adapt to what you ask for rather than following a fixed menu. ## Manual form Use this when you want to script the setup, review the diff before it lands, or debug a fast-path run that did not take. Register the server with a stdio bridge. `mcp-remote` speaks stdio to the agent and HTTP to your endpoint: ```json { "mcpServers": { "kuudo": { "command": "npx", "args": [ "-y", "mcp-remote", "https://{your-private-mcp-host}/mcp", "--header", "Authorization: Bearer ${MCP_API_KEY}" ], "env": { "MCP_API_KEY": "mcp_live_..." } } } } ``` Two details decide whether this works: - **The key has to reach the container.** Setting `MCP_API_KEY` in your shell is not enough. The host process forwards named variables into the container, so the variable must be forwarded there as well as set locally. - **The tool allow-pattern follows the server name.** Registering the server as `kuudo` exposes its tools as `mcp__kuudo__*`. Rename the server and the pattern changes with it. ## Verify Ask the agent something only your account can answer, from whichever messaging app you connected: ```text List my Amazon advertising campaigns and show the three with the highest spend last week. ``` A grounded answer means the bridge, the key, and the endpoint are all correct. A generic answer, or a refusal that mentions missing tools, means the server registered but its tools never loaded. ## Troubleshooting ### The agent replies but has no tools The server was registered in the repo root rather than the container runner, or the container was not rebuilt after the change. Rebuild, then confirm the agent lists tools under `mcp__kuudo__*`. ### Authentication fails inside the container `MCP_API_KEY` is set on the host but not forwarded. Confirm the variable is in the forwarding list, not only in the shell that launched the installer, then restart the container. ### The endpoint does not connect Confirm the endpoint uses your private host and the normal bearer-auth path: ```text https://{your-private-mcp-host}/mcp ``` Do not use a Claude-only signed connector URL such as `/mcp/connect/{signed-token}` here. The bridge sends a standard `Authorization` header. ### Tools work in Claude Code but not from the messaging app That is the two-surfaces problem. Claude Code is reading the repo root config; the messaging agent is reading the container runner. Register the server in the runner. ## Related docs - [MCP Client Configuration](/docs/mcp-client-configuration/) - [OpenClaw MCP](/docs/quick-start/openclaw/) - [Claude Code MCP](/docs/quick-start/claude-code-mcp/) ### Quick Start: OpenAI API URL: https://www.kuudo.com/docs/quick-start/openai-api/ This is the path for building your own product on top of Amazon data. Your application calls the Responses API, the model calls Kuudo's Amazon tools, and you keep scoped auth, tool allow-lists, and approval behavior without writing an integration per Amazon API. Connect the OpenAI Responses API to your private MCP server when you are building a custom agent, workflow, or application that should call MCP tools programmatically. Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace `{your-private-mcp-host}` with the private host shown in your dashboard. ## Prerequisites - A connected workspace with access to your private MCP server. - A dashboard API key from the **Keys** tab. - An `OPENAI_API_KEY` for the OpenAI project that will call the Responses API. - A remote MCP server that supports Streamable HTTP or HTTP/SSE. ## Add your MCP server as a Responses API tool Pass your remote MCP server in the `tools` array with `type: "mcp"` and `server_url`. ```bash export OPENAI_API_KEY="sk-proj_..." export MCP_API_KEY="mcp_live_..." curl https://api.openai.com/v1/responses \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${OPENAI_API_KEY}" \ -d '{ "model": "gpt-5.5", "tools": [ { "type": "mcp", "server_label": "private_mcp", "server_description": "Private workspace tools and data exposed through MCP.", "server_url": "https://{your-private-mcp-host}/mcp", "authorization": "'"${MCP_API_KEY}"'", "require_approval": "never" } ], "input": "List the tools available from my private MCP server." }' ``` The OpenAI request uses `OPENAI_API_KEY`. The MCP server uses `MCP_API_KEY` through the MCP tool's `authorization` field. Do not put your private MCP key in the top-level OpenAI `Authorization` header. ## Tool discovery When the request runs, the Responses API lists tools from your MCP server and may return an `mcp_list_tools` output item. If the model calls a tool, the response may also include an `mcp_call` item with the tool name, arguments, output, and any MCP error. For long-running conversations, keep the `mcp_list_tools` item in the conversation context when possible so OpenAI does not have to fetch the same tool definitions on every turn. ## Limit the available tools If your MCP server exposes many tools, restrict the model to the tools this workflow needs: ```json { "type": "mcp", "server_label": "private_mcp", "server_url": "https://{your-private-mcp-host}/mcp", "authorization": "${MCP_API_KEY}", "allowed_tools": ["search", "fetch"], "require_approval": "never" } ``` Use narrow tool sets for lower latency, lower token usage, and clearer tool selection. ## Approval mode The `require_approval` setting controls whether tool calls require your application to approve them before data is sent to the MCP server. - `"never"`: The model can call allowed tools without an approval round trip. - `"always"`: The model emits an approval request before each MCP tool call. - Object form: Use OpenAI's approval controls to require approval only for selected tools. Use approval for write-capable or sensitive tools. Only use `"never"` for servers and tool scopes you trust for that workflow. ## Troubleshooting ### Unauthorized or 401 errors Make sure `OPENAI_API_KEY` is used only for the OpenAI request and `MCP_API_KEY` is passed through the MCP tool's `authorization` field. The MCP key must belong to the same workspace as the private MCP server. ### Tools not discovered Verify that `server_url` points to the reachable remote MCP endpoint and ends with `/mcp` for this deployment. The server must support Streamable HTTP or HTTP/SSE. ### Approval requests appear unexpectedly OpenAI requires approval by default for remote MCP data sharing. Set `require_approval` deliberately for each workflow and handle any `mcp_approval_request` output items in your application. ### Slow responses Filter with `allowed_tools`, keep `mcp_list_tools` in conversation context, and check network latency between OpenAI and your private host. ## When to use this page Use this API setup when you own the application code that calls OpenAI. If you want ChatGPT itself to connect to the MCP server, use the [ChatGPT quick start](/docs/quick-start/chatgpt/). If you want OpenAI Codex to use the MCP server while working in a repository, use the [Codex quick start](/docs/quick-start/codex/). ### Quick Start: Perplexity MCP URL: https://www.kuudo.com/docs/quick-start/perplexity/ Ask in Perplexity's own interface and have it answered from your live Amazon Ads, Seller Central, and Vendor Central data — campaign performance, inventory health, listing status — rather than from the public web. Use Perplexity when you want to ask a question in Perplexity's own interface and have it answer from your Amazon data rather than the public web. Perplexity offers two connector types, and they are at different stages. Its own documentation states that local connectors are available now on macOS, and that remote connectors are rolling out to paid subscribers first. Check the [local and remote overview](https://www.perplexity.ai/help-center/en/articles/11502712-local-and-remote-mcps-for-perplexity) for current availability before you plan a rollout. | Path | Status | Use it when | | --- | --- | --- | | Local connector on macOS | Available now | You want a working connection today, on a Mac | | Custom remote connector | Rolling out | Your organization needs a shared connector with no per-machine setup | Both reach the same private endpoint. The local path runs a small bridge on your machine; the remote path has Perplexity call your endpoint directly. Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace `{your-private-mcp-host}` with the private host shown in your dashboard. ## Before you start - Use a paid Perplexity plan. The free tier cannot add connectors. - Create an API key from the dashboard **Keys** tab. - Keep the key in `MCP_API_KEY` or another local secret source. - Confirm the private MCP endpoint ends with `/mcp`. ```text https://{your-private-mcp-host}/mcp ``` ## Local connector on macOS Perplexity's local connectors run a command on your machine. Your MCP server is remote, so the command runs `mcp-remote`, a standard bridge that speaks stdio to Perplexity and HTTPS to your endpoint. You need the Mac App Store build of Perplexity, and Node.js so that `npx` is available: ```bash brew install node ``` ### 1. Install the helper Open **Account settings → Connectors**. Perplexity prompts you to install **PerplexityXPC**, the helper that lets it talk to local servers. Install it before adding a connector. ### 2. Add the connector Back in **Connectors**, click **Add Connector** and use the **Simple** tab: | Field | Value | | --- | --- | | **Server Name** | Something clear, such as `Kuudo` | | **Command** | The bridge command below | ```bash npx -y mcp-remote https://{your-private-mcp-host}/mcp --header "Authorization: Bearer ${MCP_API_KEY}" ``` Click **Save** and wait for the connector to report **Running** in the list. A connector that never reaches Running has not started, and no amount of asking will reach it. ### 3. Enable and test On the Perplexity homepage, toggle the connector on under **Sources**, then ask something only your account can answer: ```text List my Amazon advertising campaigns and show the three with the highest spend last week. ``` The first tool call prompts you for confirmation. ## Custom remote connector Use this once remote connectors are available on your plan. Perplexity calls your endpoint directly, so there is nothing to install per machine. Open the settings page for the scope you want: | Scope | Where | | --- | --- | | Your account only | **Account settings → Connectors** | | The whole organization (admins) | **Enterprise settings → Permissions → Connectors permissions** | For an organization connector, an admin must first turn on **Allow members to add custom connectors**. It is off by default. Click **+ Custom connector** in the top-right, choose **Remote**, and fill in the form: | Field | Value | | --- | --- | | **Name** | Something clear, such as `Kuudo` | | **MCP Server URL** | `https://{your-private-mcp-host}/mcp` — HTTPS is required | | **Description** | Optional. What the connector reaches, for others in the organization | | **Authentication** | See below | | **Transport** | **Streamable HTTP** | | **Icon** | Optional, 128 KB maximum | Check the acknowledgement box and click **Add**, then click the connector card to run the authentication flow and enable it. The ellipsis (**⋮**) on the card edits or removes it later. Perplexity runs a verification probe when you save. If the connector saves without an error tag, the endpoint answered and the auth path worked end to end. ### Authentication The remote form offers three application-layer methods and no free-form header field, so pick the one your deployment is configured for. | Method | When to use it | | --- | --- | | **API Key** | A static key supplied at setup. Use the key from your dashboard **Keys** tab. | | **OAuth 2.0** | Deployments configured for OAuth. Perplexity discovers endpoints and scopes automatically when the server publishes `/.well-known/oauth-authorization-server`; otherwise supply a Client ID and Client Secret. | | **None** | Only when the endpoint carries its own credential, such as a pre-signed URL. | If you register an OAuth application, the redirect URL is fixed: ```text https://www.perplexity.ai/rest/connections/oauth_callback ``` Organizations on the Enterprise subdomain register this instead: ```text https://enterprise.perplexity.ai/rest/connections/oauth_callback ``` For an organization-scoped OAuth connector, an admin can authenticate once for everyone, or require each member to authenticate individually. ### If your endpoint sits behind Cloudflare Access Because your deployment runs in your own cloud, the MCP hostname is often fronted by a zero-trust edge. Perplexity authenticates to that edge before any application-layer auth runs, so the two stack rather than compete. On the **+ Custom connector** form, set **Network access** to **Cloudflare Access** and supply both values. The key names are exact: ```text CF-Access-Client-Id CF-Access-Client-Secret ``` Perplexity injects these on every request, including the verification probe, so a bad token fails when you save rather than silently later. Values are stored encrypted and redacted in the interface. On the Cloudflare side, do this once in the Zero Trust dashboard: 1. **Create a service token.** Go to **Access → Service Auth → Service Tokens**. Copy the Client ID and Client Secret immediately — the secret is shown only once. 2. **Create an Access application** of type **Self-hosted**, pointed at the public hostname Perplexity will call. 3. **Add a policy with Action set to `Service Auth`.** Include the service token from step 1. Setting the action to **Allow** instead of **Service Auth** is the usual mistake. Allow expects an interactive browser login, which a machine client cannot satisfy, so the verification probe fails. ## Troubleshooting ### The local connector never reaches Running Confirm Node.js is installed and `npx` resolves in the shell Perplexity inherits. Confirm `MCP_API_KEY` is set for that same environment — a variable exported in one terminal is not visible to an application launched from the Dock. ### Verification or tool calls return 403 Work through these in order: - **Incomplete or expired service token.** Re-paste both values in full; the secret is long and partial pastes are easy to miss. Service tokens expire, one year by default. - **Wrong policy action.** The Access policy must use **Service Auth**, not **Allow** or **Bypass**. - **Propagation delay.** New Access applications, policies, and tokens take a few minutes to reach Cloudflare's edge. Wait, then retry before assuming a misconfiguration. - **A challenge is blocking the request.** Perplexity connects from datacenter address ranges. If your zone challenges automated traffic, the endpoint receives a managed challenge no machine client can solve, which surfaces as a 403. Add a firewall skip or bot-management exception for the MCP hostname. Access still gates the endpoint through the service token. If all four check out and it still fails, the problem is in the application layer rather than the edge. ### The connector saved but answers from the web It is not enabled for that thread. Toggle it on under **Sources** before asking. ### Other members cannot see an organization connector Sharing is a separate step. The creator has to share it from the **Permissions** screen in **Enterprise settings**, and newly shared connectors do not always appear immediately. ### The endpoint does not connect Confirm the URL uses your private host, ends with `/mcp`, and is HTTPS. Perplexity rejects plain HTTP. ## Related docs - [MCP Client Configuration](/docs/mcp-client-configuration/) - [ChatGPT MCP](/docs/quick-start/chatgpt/) - [NanoClaw MCP](/docs/quick-start/nanoclaw/) ### Quick Start: Google Antigravity URL: https://www.kuudo.com/docs/quick-start/antigravity/ From Antigravity you get live Amazon data in the agentic editor you are already building in — query Ads, Seller Central, and Vendor Central while you work, prototype an Amazon agent against real campaigns, and hand it multi-step jobs without leaving the IDE. Antigravity reads MCP servers from a JSON config file, and its remote-server field is named `serverUrl` rather than the `url` most clients use. That one difference is the most common reason a working config from another client fails here. Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace `{your-private-mcp-host}` with the private host shown in your dashboard. For the official reference, see [MCP in the Antigravity docs](https://antigravity.google/docs/mcp). ## Prerequisites - Antigravity installed, in either the IDE or CLI form. - A connected workspace with access to your private MCP server. - A dashboard API key from the **Keys** tab. - The private MCP host assigned to your deployment. ## 1. Set your local key Set the API key in the shell that launches Antigravity: ```bash export MCP_API_KEY="mcp_live_..." ``` Store it in your shell profile or secret manager for repeated use. Do not commit the raw value — the workspace config file below is checked in with the repository. ## 2. Add the MCP server Antigravity reads two config locations: | Scope | Path | Use when | | --- | --- | --- | | Global | `~/.gemini/config/mcp_config.json` | The server should be available in every project. | | Workspace | `.agents/mcp_config.json` | Only this repository should see the server. Checked into the repo. | Add the server under the top-level `mcpServers` key: ```json { "mcpServers": { "private-mcp": { "serverUrl": "https://{your-private-mcp-host}/mcp", "headers": { "Authorization": "Bearer YOUR_API_TOKEN" } } } } ``` Use `serverUrl` for remote Streamable HTTP, SSE, and websocket connections. A remote entry that uses `command` and `args` — the stdio shape — will not connect. Prefer the global config when the header carries a live key, so the token never lands in a committed workspace file. ## 3. Verify the server Open the MCP manager for the surface you are using: | Surface | Where | | --- | --- | | Antigravity CLI | Type `/mcp` in the prompt panel for the Interactive MCP Manager. | | Antigravity IDE | Agent side panel **…** > **MCP Servers** > **Manage MCP Servers**. | | Antigravity 2.0 | **Settings** > **Customizations** > **Installed MCP Servers**. | `private-mcp` should be listed with its tools discovered. Ask for a read-only call first: ```text What MCP tools are available from private-mcp? List the read-only ones before calling anything. ``` ## Alternative: OAuth and Google credentials If your deployment fronts the MCP server with OAuth, Antigravity handles dynamic client registration automatically, or accepts a manual `clientId` and `clientSecret` under an `oauth` key. Setting `authProviderType` to `google_credentials` uses your local application-default credentials instead, configured with `gcloud auth application-default login`. Bearer-header auth above is the path for a Kuudo dashboard API key. ## Optional controls MCP tools run in **Ask** mode by default, so Antigravity prompts before calling one. Permissions are expressed as patterns: ```text mcp(private-mcp/list_campaigns) a single tool mcp(private-mcp/*) every tool on this server mcp(*) every MCP tool ``` Grant read tools broadly and keep write tools on Ask until you have watched the agent work. Two further fields help: ```json { "mcpServers": { "private-mcp": { "serverUrl": "https://{your-private-mcp-host}/mcp", "headers": { "Authorization": "Bearer YOUR_API_TOKEN" }, "disabledTools": ["delete_record"], "disabled": false } } } ``` Use `disabledTools` to withhold specific tools from the agent, and `disabled` to switch the whole server off without deleting the entry. ## Troubleshooting ### The server never connects Check that the entry uses `serverUrl` and not `url` or `command`. A config copied from Claude Code or Codex will use a different field name and silently fail to register a remote server. ### Unauthorized or 401 errors Confirm the `Authorization` header reads `Bearer ` followed by a dashboard key that belongs to the same workspace as the MCP server. Rotated keys invalidate the old value. ### Tools are listed but never called MCP tools default to Ask mode. If the agent is running unattended, grant the tools it needs with an `mcp(private-mcp/*)` permission, or approve each prompt as it appears. ### Some tools are missing Check `disabledTools` on the server entry, and confirm the server itself is not `disabled`. ### Config changes are not picked up Restart Antigravity after editing the JSON. The IDE and CLI read the file at startup. ## Start using tools Read-only prompts first: - "Using `private-mcp`, list my Sponsored Products campaigns from the last 7 days." - "Pull the current Buy Box status for these ASINs and show which ones I am losing." - "Summarize yesterday's orders by marketplace." For write-capable work, ask Antigravity to explain the change it intends before it calls a mutating tool. ## Related docs - [MCP Client Configuration](/docs/mcp-client-configuration/) - [Claude Code MCP](/docs/quick-start/claude-code-mcp/) - [Codex MCP](/docs/quick-start/codex/) ### Quick Start: Lovable URL: https://www.kuudo.com/docs/quick-start/lovable/ From Lovable you can build against live Amazon data while you are still designing the app — pull real campaign, order, and catalog data into the chat as you iterate, so the interface you ship is shaped by what your Seller Central and Ads accounts actually return rather than by placeholder JSON. One thing to know before you start: a custom MCP server in Lovable is a **chat connector**. It is personal to your account and is never part of your published app. It shapes what you build; it is not a runtime dependency your users inherit. If the app itself needs Amazon data at runtime, that is a server-side integration you build, not this connector. Your MCP server hostname is private to your deployment. It comes from your cloud provider, belongs to your environment, and is not shared across customers. Replace `{your-private-mcp-host}` with the private host shown in your dashboard. For the official reference, see [Custom MCP in the Lovable docs](https://docs.lovable.dev/integrations/custom-mcp). ## Prerequisites - A Lovable account. Custom MCP servers are available on all plans. - A dashboard API key from the **Keys** tab, unless your deployment fronts the server with OAuth. - The private MCP endpoint assigned to your deployment. ```text https://{your-private-mcp-host}/mcp ``` ## 1. Open the custom MCP form Open the **Connectors** dashboard. Scroll to the bottom of the **All** view and choose the **Custom** card labelled **MCP** — "Connect your own MCP". ## 2. Add the server The form takes two fields: | Field | Value | | --- | --- | | Server name | A descriptive identifier you will name in chat, such as `Kuudo Amazon`. | | Server URL | Your private MCP endpoint, `https://{your-private-mcp-host}/mcp`. | Then pick how Lovable authenticates: | Method | Use when | | --- | --- | | **OAuth** (default) | Your deployment fronts the MCP server with OAuth. Click **Add & authorize** and complete the flow. | | **Bearer token or API key** | The usual path for a Kuudo dashboard key. | | **No authentication** | Only for a server that requires no credentials. | Pick a server name you will actually type. You name the connector in the prompt, so `Kuudo Amazon` reads better mid-sentence than `mcp-prod-1`. ## 3. Verify the connection Ask for something only the connector can answer, naming it directly: ```text Using the Kuudo Amazon connector, list my five most recent orders. ``` If the connector is live, the answer comes back from your account rather than from a guess. Start with reads before letting it write anything. ## Sharing and governance **Chat connections are per-user.** A colleague opening the same project sees the connector suggested but has to connect their own. There is no shared workspace credential, which is usually what you want for Amazon access — each person's calls run under their own key. Workspace admins can turn the whole capability off under **Connectors → Admin settings → Chat connectors**. If the Custom MCP card is missing entirely, check there first. ## Troubleshooting ### The connector works in chat but not in the published app That is the documented behaviour, not a bug. Chat connectors are personal and never ship with a published app. Build the runtime integration server-side if your users need Amazon data. ### A teammate cannot see the data Connections are per-user. Have them add the connector under their own account with their own key. ### The Custom MCP card is not there A workspace admin has disabled chat connectors, or you are looking above the bottom of the **All** view — the Custom card sits at the end of the list. ### Unauthorized errors Confirm the key belongs to the same workspace as the MCP server, and that you chose **Bearer token or API key** rather than leaving the form on OAuth. ## Start using tools Read-only prompts first: - "Using the Kuudo Amazon connector, show my top 10 ASINs by units last week." - "Pull current inventory levels so I can shape the low-stock view." - "What campaign metrics are available? I want to design a dashboard around them." Building a view against the real shape of your data is the point — it saves the round trip where the mock schema and the live response disagree. ## Related docs - [MCP Client Configuration](/docs/mcp-client-configuration/) - [Google Antigravity](/docs/quick-start/antigravity/) - [Cursor and other IDEs](/docs/quick-start/claude-code-mcp/) ### Quick Start: ChatGPT Skills URL: https://www.kuudo.com/docs/quick-start/chatgpt-skills/ Use ChatGPT skills when you want ChatGPT to follow a reusable workflow, apply task-specific instructions, or use bundled examples and resources for a repeatable job. For the official reference, see [Skills in ChatGPT in the OpenAI Help Center](https://help.openai.com/en/articles/20001066-skills-in-chatgpt). ## Availability ChatGPT skills are currently in beta. They are available in supported workspace plans, including Business, Enterprise, Edu, Teachers, and Healthcare plans. Skills are also supported in Codex and the OpenAI API, but skills do not sync across products yet. OpenAI skills follow the open Agent Skills standard, so a skill can be downloaded from one product and installed in another compatible product. ## Open the Skills page In ChatGPT: 1. Click your profile icon. 2. Select **Skills**. The Skills page shows skills that are installed, created by you, and shared with you. ChatGPT includes `skill-creator` by default. When you ask ChatGPT to create, modify, or troubleshoot a skill, it can use `skill-creator` to guide the process. ## Create a skill in chat Use this path when you know the workflow but want ChatGPT to help structure it. ### Copy prompt ```text Create a reusable ChatGPT skill for this workflow: Workflow name: [name] When ChatGPT should use it: [trigger conditions] Inputs the user will provide: [inputs] Steps ChatGPT should follow every time: [steps] Outputs ChatGPT should produce: [output format] Ask me any missing questions first, then generate the skill and tell me how to install it. ``` ChatGPT should ask follow-up questions, generate the skill, and prompt you to install it when it is ready. ## Create a skill in the editor Use the editor when you want to build or manage the skill directly. 1. Open **Skills** from your profile menu. 2. Click **New skill**. 3. Select **Create with editor**. 4. Add the skill instructions, examples, and any supporting resources. 5. Save and install the skill. ## Upload a skill Use upload when you already have a skill file or folder from another product or teammate. 1. Open **Skills** from your profile menu. 2. Click **New skill**. 3. Choose **Upload from your computer**. 4. Select the skill package. 5. Review and install it. ## Install a shared skill Use this path for skills another teammate or workspace owner has shared with you. 1. Open **Skills** from your profile menu. 2. Select **Shared with you**. 3. Hover over the skill. 4. Click the **...** menu. 5. Select **Install**. After installation, ChatGPT can automatically use the skill when your request matches the skill's purpose. ## Share a skill with your workspace Turn strong workflows into shared workspace skills when teammates should use the same process. 1. Open **Skills** from your profile menu. 2. Hover over the skill you want to share. 3. Click the **...** menu. 4. Select **Share**. 5. Search for people or groups, or copy a direct share link. 6. Set access permissions for the skill. Use limited access for workflows that include sensitive instructions, private context, or operational steps. ## Admin controls Enterprise and Edu admins can control ChatGPT skills from **Permissions & roles**. Admins can enable or disable: - Skills usage. - Skills publishing and sharing. - Skills installing for workspace members. While skills are in beta, Enterprise and Edu workspaces may have skills off by default until an admin enables them. ## Compliance notes Workspace admins can use compliance logs to review metadata and audit events such as skill creation, sharing, updates, and installation. ChatGPT conversations that use skills follow the workspace's data residency settings. For ChatGPT business plans, data shared with a skill is not used to improve OpenAI models by default. ## Verify a skill After installing a skill: 1. Start a new ChatGPT conversation. 2. Ask for a task that clearly matches the skill description. 3. Confirm ChatGPT uses the expected workflow. 4. If it does not, update the skill description so the trigger conditions are clearer. For Codex-specific skill installation, see the [Codex Skills quick start](/docs/quick-start/codex-skills/). ### Quick Start: Claude Skills URL: https://www.kuudo.com/docs/quick-start/claude-app-skills/ Use Claude skills when you want Claude on the web or Claude Desktop to follow reusable instructions, work with bundled files, or apply a repeatable workflow inside chat. For the official reference, see [Use Skills in Claude](https://support.claude.com/en/articles/12512180-use-skills-in-claude). Claude app skills are different from Claude Code skills. Claude app skills are managed from **Customize > Skills** in Claude. Claude Code skills are local folders such as `~/.claude/skills/` or `.claude/skills/` and are covered separately in the [Claude Code Skills quick start](/docs/quick-start/claude-skills/). ## Before you start - Use a Claude plan or workspace that supports skills. - Make sure skills are enabled for your account or organization. - Keep skill packages in a trusted location before uploading them. - Review any skill before installing it, especially if it includes files, scripts, or instructions from outside your organization. For team or enterprise workspaces, an admin may need to enable skills before users can add or run them. ## Open Skills In Claude Desktop or Claude on the web: 1. Open **Customize**. 2. Find the **Skills** section. 3. Use the available action to **Add**, **Create**, or **Replace** a skill. If the Skills section is hidden or disabled, check **Settings > Capabilities** and your workspace admin settings. ## Add a skill Use **Add** when you already have a skill package from a trusted source. 1. Open **Customize > Skills**. 2. Select **Add**. 3. Choose the skill package. 4. Review the skill name, description, and contents. 5. Confirm the upload or installation. 6. Toggle the skill on if Claude does not enable it automatically. Do not upload a skill package unless you trust its contents. Skills can influence how Claude interprets requests and may include supporting files. ## Create a skill Use **Create** when you want Claude to help build a new reusable workflow. Start with a concrete prompt: ```text Create a Claude skill for this workflow: Skill name: [name] When Claude should use it: [trigger conditions] Inputs I will provide: [inputs] Steps Claude should follow: [steps] Output format: [format] Ask me any missing questions before creating the skill. ``` After Claude drafts the skill, review the instructions and test it with a low-risk request before relying on it for production work. ## Replace a skill Use **Replace** when you have a newer version of a skill that should take the place of an existing one. 1. Open **Customize > Skills**. 2. Select the existing skill. 3. Choose **Replace**. 4. Upload the new version. 5. Confirm the name and description still match the intended workflow. 6. Test the skill with a known request. Replacing a skill can change Claude's behavior in future chats. Keep a copy of the previous version if your team may need to roll back. ## Enable or disable skills In **Customize > Skills**, toggle individual skills on or off. Keep only the skills you need enabled for a task. Disable old, experimental, or overlapping skills when they are not relevant. ## Verify a skill Start a new Claude chat and ask for the workflow the skill should handle: ```text Use my [skill name] workflow to process this request: [task] ``` If Claude does not appear to use the skill, make the skill description more explicit, confirm the skill is enabled, and start a new chat. ## Troubleshooting ### Skills are not visible Check whether your plan supports skills, whether skills are enabled under **Settings > Capabilities**, and whether your workspace admin has enabled skills. ### Add, Create, or Replace is disabled Your workspace may restrict who can create or upload custom skills. Ask an admin to enable skill creation or to install the skill for the workspace. ### Claude ignores the skill Confirm the skill is enabled and its description clearly matches the request. Start a new conversation after changing skill settings. ### The wrong skill activates Disable overlapping skills or rewrite the descriptions so each skill has a clear trigger condition. ## Related docs - [Claude Code Skills](/docs/quick-start/claude-skills/) - [Claude MCP](/docs/quick-start/claude-ai/) - [MCP Client Configuration](/docs/mcp-client-configuration/) ### Quick Start: Claude Code Skills URL: https://www.kuudo.com/docs/quick-start/claude-skills/ Use Claude Code skills when you want Claude Code to apply a reusable local workflow, load task-specific instructions only when needed, or expose a repeatable command such as `/summarize-changes`, `/deploy`, or `/review-pr`. For Claude Desktop or Claude on the web skills managed through **Customize > Skills**, see the [Claude Skills quick start](/docs/quick-start/claude-app-skills/). For the official reference, see [Extend Claude with skills in the Claude Code docs](https://code.claude.com/docs/en/skills). ## What a Claude Code skill is A skill is a directory with a required `SKILL.md` file and optional supporting files: ```text my-skill/ SKILL.md reference.md examples/ scripts/ ``` Claude sees each skill's name, description, and path up front. The full `SKILL.md` body loads only when Claude invokes the skill or you invoke it directly with `/skill-name`. Skills are the recommended replacement for most custom commands. Existing `.claude/commands/` files still work, but a skill with the same name takes precedence. ## Install a personal skill Use personal skills for workflows you want across all projects. ```bash mkdir -p ~/.claude/skills/summarize-changes ``` Create `~/.claude/skills/summarize-changes/SKILL.md`: ```markdown --- description: Summarizes uncommitted changes and flags anything risky. Use when the user asks what changed, wants a commit message, or asks to review their diff. --- Current changes: !`git diff HEAD` Instructions: Summarize the changes above in two or three bullet points, then list any risks you notice such as missing error handling, hardcoded values, or tests that need updating. If the diff is empty, say there are no uncommitted changes. ``` Start Claude Code in a git project and test it two ways: ```text What did I change? ``` Or invoke it directly: ```text /summarize-changes ``` ## Install a project skill Use project skills when the workflow belongs with the repository and should be shared with the team. ```text .claude/skills//SKILL.md ``` Example: ```bash mkdir -p .claude/skills/release-checklist ``` Project skills load from `.claude/skills/` in the starting directory and parent directories up to the repository root. Claude Code can also discover nested `.claude/skills/` directories as you work in subdirectories, which is useful for monorepos. ## Skill locations | Scope | Path | Applies to | | --- | --- | --- | | Enterprise | Managed settings | All users in the organization. | | Personal | `~/.claude/skills//SKILL.md` | All your projects. | | Project | `.claude/skills//SKILL.md` | The current project. | | Plugin | `/skills//SKILL.md` | Wherever the plugin is enabled. | When skills share a name across levels, enterprise overrides personal, and personal overrides project. Plugin skills use a `plugin-name:skill-name` namespace. Claude Code watches existing skill directories for changes. If you add, edit, or remove a skill in an already-watched directory, the change takes effect in the current session. If you create a top-level skills directory after Claude Code has started, restart Claude Code. ## Frontmatter basics `SKILL.md` starts with YAML frontmatter. Only `description` is recommended, but additional fields control invocation, arguments, tools, model choice, and execution context. ```markdown --- name: deploy description: Deploy the application to production argument-hint: "[environment]" disable-model-invocation: true allowed-tools: Bash(git status *) Bash(npm test *) Bash(npm run build *) --- Deploy $ARGUMENTS to production: 1. Run the test suite. 2. Build the application. 3. Push to the deployment target. 4. Verify the deployment succeeded. ``` Useful fields: | Field | Use | | --- | --- | | `name` | Display name. If omitted, Claude uses the directory name. | | `description` | What the skill does and when Claude should use it. | | `when_to_use` | Extra trigger guidance appended to the description. | | `argument-hint` | Autocomplete hint for expected arguments. | | `arguments` | Named positional arguments for substitutions. | | `disable-model-invocation` | Set `true` when only the user should trigger the skill manually. | | `user-invocable` | Set `false` to hide background knowledge from the `/` menu. | | `allowed-tools` | Tools Claude may use without asking while the skill is active. | | `paths` | File globs that limit automatic activation. | | `context` | Set `fork` to run the skill in a subagent context. | | `agent` | Subagent type to use when `context: fork` is set. | ## Control invocation By default, both you and Claude can invoke a skill: - You can type `/skill-name`. - Claude can load the skill automatically when your request matches the description. Use `disable-model-invocation: true` for workflows with side effects, such as deploys, commits, or messages. Use `user-invocable: false` for background knowledge that Claude may use automatically but users should not run as a command. ## Pass arguments Claude Code passes text after the skill name into `$ARGUMENTS`. ```markdown --- name: fix-issue description: Fix a GitHub issue disable-model-invocation: true --- Fix GitHub issue $ARGUMENTS following our coding standards. ``` Invocation: ```text /fix-issue 123 ``` For positional values, use `$ARGUMENTS[0]`, `$ARGUMENTS[1]`, or shorthand values like `$0` and `$1`. ## Add dynamic context Inline shell injection runs a shell command before Claude sees the skill. The command output replaces the placeholder in the rendered skill. ```markdown Pull request context: - PR diff: !`gh pr diff` - PR comments: !`gh pr view --comments` - Changed files: !`gh pr diff --name-only` ``` Use dynamic context for live diffs, issue data, environment details, or generated reports. To disable shell execution for user, project, plugin, or additional-directory skills, set `disableSkillShellExecution` in Claude Code settings. ## Pre-approve tools carefully The `allowed-tools` field lets Claude use listed tools without per-use approval while the skill is active. It does not restrict all other tools; your normal permission settings still apply. Review project skills before trusting a repository. A project skill can grant broad tool access after you accept the workspace trust dialog. ## Override visibility Use `/skills` to manage skill visibility. Highlight a skill, press `Space` to cycle states, then press `Enter` to save to `.claude/settings.local.json`. The underlying setting is `skillOverrides`: ```json { "skillOverrides": { "legacy-context": "name-only", "deploy": "off" } } ``` States include: | State | Listed to Claude | In `/` menu | | --- | --- | --- | | `on` | Name and description | Yes | | `name-only` | Name only | Yes | | `user-invocable-only` | Hidden | Yes | | `off` | Hidden | Hidden | Plugin skills are managed through `/plugin`, not `skillOverrides`. ## Share skills Share skills at the scope that matches the audience: - Project: Commit `.claude/skills/` to version control. - Plugin: Create a `skills/` directory in a Claude Code plugin. - Managed: Deploy organization-wide through managed settings. ## Verify a skill After installing a skill: 1. Run Claude Code in a project where the skill should be available. 2. Type `/` and confirm the skill appears. 3. Invoke it directly with `/skill-name`. 4. Ask a natural-language request that should match the skill description. 5. If Claude does not select it, tighten the `description` and `when_to_use` fields. For MCP setup in Claude Code, see the [Claude quick start](/docs/quick-start/claude-ai/). ### Quick Start: Codex Skills URL: https://www.kuudo.com/docs/quick-start/codex-skills/ Install Codex skills when you want Codex to follow a reusable workflow, load task-specific instructions, or bring supporting scripts and references into a session. For the official reference, see [Agent Skills in the OpenAI Codex docs](https://developers.openai.com/codex/skills). ## What a skill is A skill is a folder with a required `SKILL.md` file and optional supporting files: ```text my-skill/ SKILL.md scripts/ references/ assets/ agents/ openai.yaml ``` `SKILL.md` contains the skill metadata and instructions. It must include `name` and `description` frontmatter so Codex can decide when to use it. ```markdown --- name: skill-name description: Explain exactly when this skill should and should not trigger. --- Skill instructions for Codex to follow. ``` Codex uses progressive disclosure for skills. It starts with each skill's name, description, and file path, then reads the full `SKILL.md` only when the skill is selected. ## Install curated skills For local setup and experimentation, use the built-in installer from a Codex session: ```text $skill-installer linear ``` You can also ask `$skill-installer` to install skills from another repository: ```text $skill-installer install a skill from github.com/{owner}/{repo} ``` Codex detects newly installed skills automatically. If a skill does not appear, restart Codex. ## Install a repo skill Use repo-scoped skills when the workflow belongs with the codebase and should be shared by the team. Create the folder under the repository root: ```text .agents/skills/my-skill/SKILL.md ``` Example: ```bash mkdir -p .agents/skills/release-checklist ``` Then add `.agents/skills/release-checklist/SKILL.md`: ```markdown --- name: release-checklist description: Use when preparing a release branch, verifying changelog entries, and checking release gates. --- Follow the repository release checklist before marking a release ready. ``` Codex scans `.agents/skills` from the current working directory up to the repository root, so nested projects can have local skills while the root can provide shared team skills. ## Install a user skill Use user-scoped skills for personal workflows that should be available across repositories. ```text $HOME/.agents/skills/my-skill/SKILL.md ``` Example: ```bash mkdir -p ~/.agents/skills/personal-review ``` Then add `~/.agents/skills/personal-review/SKILL.md`. ## Admin and system skills Codex also reads admin and system-level skills: | Scope | Location | Use | | --- | --- | --- | | Repo | `$REPO_ROOT/.agents/skills` | Team or project workflows checked into a repository. | | User | `$HOME/.agents/skills` | Personal workflows available across repositories. | | Admin | `/etc/codex/skills` | Shared machine or container defaults. | | System | Bundled with Codex | OpenAI-provided default skills. | Codex supports symlinked skill folders and follows the symlink target when scanning skill locations. ## Enable or disable a skill Disable a skill without deleting it by adding a `[[skills.config]]` entry to `~/.codex/config.toml`: ```toml [[skills.config]] path = "/path/to/skill/SKILL.md" enabled = false ``` Restart Codex after changing `~/.codex/config.toml`. ## Optional app metadata Add `agents/openai.yaml` when you want Codex app metadata, invocation policy, or declared tool dependencies: ```yaml interface: display_name: "Release Checklist" short_description: "Release readiness workflow" icon_small: "./assets/small-logo.svg" icon_large: "./assets/large-logo.png" brand_color: "#3B82F6" default_prompt: "Run the release checklist." policy: allow_implicit_invocation: false dependencies: tools: - type: "mcp" value: "private-mcp" description: "Private MCP server" transport: "streamable_http" url: "https://{your-private-mcp-host}/mcp" ``` Set `allow_implicit_invocation: false` when the skill should only run after an explicit `$skill-name` mention. ## Skills vs plugins Use direct skill folders for local authoring, repo-scoped workflows, and personal setup. Use plugins when you want to distribute reusable skills, bundle multiple skills together, or ship skills alongside app mappings, MCP server configuration, or presentation assets. ## Verify installation In Codex CLI or the IDE extension: 1. Run `/skills` or type `$` to open the skill selector. 2. Confirm the new skill appears by name. 3. Invoke it directly with `$skill-name`. 4. If it does not appear, restart Codex and check the skill path. For skills that depend on MCP tools, verify the MCP server separately with `/mcp`. See the [Codex MCP quick start](/docs/quick-start/codex/) for MCP setup. ### Kuudo MCP Servers URL: https://www.kuudo.com/docs/mcp-reference/tools/ Kuudo runs one MCP server per Amazon surface. Each server exposes domain-scoped tools so agents can read, analyze, and safely queue changes — this page is the index: what's available today, and where to find the full tool-by-tool reference for each one. ## MCP servers ### Amazon Ads MCP Sponsored Products, Brands, Display, and TV, plus DSP (demand-side platform), AMC (Amazon Marketing Cloud), the unified Ads API v1, attribution, and reporting — see the Ads MCP tool reference for the live resource and tool counts. [See every Amazon Ads MCP tool ->](/docs/mcp-reference/amazon-ads-tools/) ### Amazon Selling Partner MCP Catalog, listings, orders, pricing, FBA (Fulfillment by Amazon), fulfillment, finances, and more across the seller side of the Selling Partner API — see the SP MCP tool reference for the live resource and tool counts. [See every Amazon Selling Partner MCP tool ->](/docs/mcp-reference/amazon-sp-tools/) More servers are on the way, starting with Vendor Central MCP. ## Read vs. write tools Every tool on every server is tagged read or write. Read tools return scoped data and are safe for normal agent use — exploration, diagnostics, reporting. Write tools are guarded: they validate input, apply workspace policy, and may require explicit human approval before changes reach Amazon. ## Auditability Every tool call records the requesting user, agent, workspace, parameters, result summary, and approval state, across every server. Use the run log to reproduce outputs or review changes before activation. ### Amazon Ads MCP Tools URL: https://www.kuudo.com/docs/mcp-reference/amazon-ads-tools/ This page lists every tool the Amazon Ads MCP exposes, grouped by the underlying Amazon Ads API resource. Each entry shows whether it's a read tool (safe to call freely) or a write tool (guarded, may require approval), the tool name, and a short description. See [Kuudo MCP Servers](/docs/mcp-reference/tools/) for the full index of Kuudo MCP servers. Expand any resource below to see its tools. Your browser's find-in-page (Ctrl+F / Cmd+F) searches across every tool on this page, even inside collapsed sections. ## Tool reference 53 resources with tools · 711 tools ### AccountsAccountBudgets | Access | Tool | Description | | --- | --- | --- | | read | `AccountsAccountBudgets_getAccountBudgetFeatureFlags` | Gets account budget feature flags information. | | write | `AccountsAccountBudgets_updateAccountBudgetFeatureFlags` | Creates or Updates account budget feature flags information. | ### AccountsAdsAccounts | Access | Tool | Description | | --- | --- | --- | | write | `AccountsAdsAccounts_RegisterAdsAccount` | Create a new advertising account tied to a specific Amazon vendor, seller or author, or to a business who does not sell on Amazon. | | read | `AccountsAdsAccounts_ListAdsAccounts` | List all advertising accounts for the user associated with the access token. | | read | `AccountsAdsAccounts_GetAccount` | Request attributes of a given advertising account. | | write | `AccountsAdsAccounts_CreateTermsToken` | Create a new UUID terms token for the customer to accept advertising terms Requires one of these permissions: [] | | read | `AccountsAdsAccounts_GetTermsToken` | Get the terms token status for the customer Requires one of these permissions: [] | ### AccountsBilling | Access | Tool | Description | | --- | --- | --- | | read | `AccountsBilling_GetDocument` | Gets billing document(s) with id. | | write | `AccountsBilling_PayInvoices` | Executes payment on a set of or all of an advertisers open invoices. | | read | `AccountsBilling_bulkGetBillingNotifications` | Gets an array of all currently valid billing notifications associated for each advertising account. | | write | `AccountsBilling_CreatePaymentAgreements` | Creates or updates payment agreements. | | read | `AccountsBilling_GetPaymentAgreements` | Gets current payment agreement for a customer. | | read | `AccountsBilling_GetCustomerPaymentMethods` | Retrieves eligible payment methods for a customer. | | write | `AccountsBilling_CreatePaymentProfiles` | Creates or updates payment profiles. | | read | `AccountsBilling_bulkGetBillingStatus` | Gets the current billing status associated for each advertising account. | | read | `AccountsBilling_GetBillingProfileAgreementContent` | User needs to provide consent to certain agreements before creating a billing profile. | | write | `AccountsBilling_ApplyBillingProfile` | API to link one or more countries with a billing profile. | | read | `AccountsBilling_GetBillingProfileUsages` | Lists the billing profiles linked to each country of global ads account. | | write | `AccountsBilling_CreateBillingProfiles` | Creates one or more billing profiles. | | write | `AccountsBilling_UpdateBillingProfiles` | Updates one or more billing profiles under a global account Please note that isBillTo and type are immutable attributes and cannot be updated -- in this case, user can always create a new billing... | | read | `AccountsBilling_GetBillingProfiles` | Fetches billing profiles present under the global account. | | write | `AccountsBilling_CreateBillingStatement` | Request to create billing statement for advertiser advertising in Sponsored Products/Brands/Display segment. | | read | `AccountsBilling_GetBillingStatement` | API to fetch the latest status of Billing Statements creation request and billing statement download link if available. | | read | `AccountsBilling_GetBillingInvoiceSummaries` | Lists the billing invoice summary(s) in a global ads account. | | read | `AccountsBilling_getAdvertiserInvoices` | Requires one of these permissions: ["nemo_transactions_view","nemo_transactions_edit"] | | read | `AccountsBilling_getInvoice` | Requires one of these permissions: ["nemo_transactions_view","nemo_transactions_edit"] | ### AccountsManagerAccounts | Access | Tool | Description | | --- | --- | --- | | read | `AccountsManagerAccounts_getManagerAccountsForUser` | Returns all manager accounts that a user has access to, along with metadata for the Amazon Ads accounts t... | | write | `AccountsManagerAccounts_createManagerAccount` | Creates a new Amazon Advertising Manager account. | | write | `AccountsManagerAccounts_LinkAdvertisingAccountsToManagerAccountPublicAPI` | Link Amazon Advertising accounts or advertisers with a Manager Account. | | write | `AccountsManagerAccounts_UnlinkAdvertisingAccountsToManagerAccountPublicAPI` | Unlink Amazon Advertising accounts or advertisers with a Manager Account. | ### AccountsPortfolios | Access | Tool | Description | | --- | --- | --- | | write | `AccountsPortfolios_CreatePortfolios` | Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AccountsPortfolios_UpdatePortfolios` | Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AccountsPortfolios_portfolioBudgetUsage` | Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | read | `AccountsPortfolios_ListPortfolios` | Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | ### AccountsProfiles | Access | Tool | Description | | --- | --- | --- | | read | `AccountsProfiles_listProfiles` | Note that this operation does not return a response unless the current account has created at least one campaign using the advertising console. | | write | `AccountsProfiles_updateProfiles` | Note that this operation is only used for Sellers using Sponsored Products. | | read | `AccountsProfiles_getProfileById` | This operation does not return a response unless the current account has created at least one campaign using the advertising console. | ### AdsAPIv1All | Access | Tool | Description | | --- | --- | --- | | read | `AdsAPIv1All_ListBrandStoreEdition` | Retrieve brand store page content Requires one of these permissions: ["amazon_stores_edit","amazon_stores_view"] | | read | `AdsAPIv1All_DSPListCommitment` | List commitments Requires one of these permissions: [] | | write | `AdsAPIv1All_CreateAccountCombinationInvitation` | Create an invitation to combine Advertising Accounts under a Single Global Accou... | | write | `AdsAPIv1All_CreateAdAssociation` | Create Ad Association Requires one of these permissions: ["campaign_edit"] | | write | `AdsAPIv1All_CreateAdExtension` | Create ad extensions - API is in open beta Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1All_CreateAdGroup` | Create ad groups Requires one of these permissions: ["advertiser_campaign_e... | | write | `AdsAPIv1All_CreateAd` | Create ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_edit"] | | write | `AdsAPIv1All_CreateAdvertiserAccount` | Create advertiser accounts Requires one of these permissions: [] | | write | `AdsAPIv1All_CreateAdvertiserProductGroupEligibility` | Create request for specific advertiser product group eligibility Requires one... | | write | `AdsAPIv1All_SBCreateAdvertisingDealTarget` | Create advertisingDealTarget Requires one of these permissions: ["advertise... | | write | `AdsAPIv1All_SBCreateAdvertisingDeal` | Create advertisingDeal Requires one of these permissions: ["advertiser_campaign_edit", "advertiser_campaign_view"] | | write | `AdsAPIv1All_SBCreateBrandedKeywordsPricing` | Create brandedKeywords pricing Requires one of these permissions: ["adverti... | | write | `AdsAPIv1All_CreateCampaign` | Create campaigns Requires one of these permissions: ["advertiser_campaign_e... | | write | `AdsAPIv1All_DSPCreateCommitment` | Create commitments Requires one of these permissions: [] | | write | `AdsAPIv1All_CreateEvent` | Create Event Data Requires one of these permissions: ["event_manager_view", "event_manager_edit"] | | write | `AdsAPIv1All_CreateGeoLocation` | Create geo location targeting definitions. | | write | `AdsAPIv1All_DSPAdsApiv1CreateInventoryGroup` | Create inventory groups Requires one of these permissions: ["inventory_edit"] | | write | `AdsAPIv1All_SBCreateKeywordReservationValidation` | Validate keyword reservation Requires one of these permissions: ["advertise... | | write | `AdsAPIv1All_CreateLinearTvIncrementalReachForecast` | Generate Linear TV incremental reach forecast comparing with supported Streaming... | | write | `AdsAPIv1All_CreateLinearTvReachForecast` | Generate Linear TV reach forecast Requires one of these permissions: ["campaign_edit"] | | write | `AdsAPIv1All_CreateLocationIndex` | Create a Smart Location Index. | | write | `AdsAPIv1All_CreateManagerAccount` | Create manager accounts Requires one of these permissions: [] | | write | `AdsAPIv1All_SBCreateRecommendation` | Create recommendations Requires one of these permissions: ["advertiser_campaign_view"] | | write | `AdsAPIv1All_AdsApiv1CreateReport` | Create a report Requires one of these permissions: ["ManagerAccount_Dev", "... | | write | `AdsAPIv1All_DSPAdsApiv1CreateSupplierAdProductPrice` | Create supplier ad product price Requires one of these permissions: ["inventory_view"] | | write | `AdsAPIv1All_DSPAdsApiv1CreateSupplierProposal` | Create supplier proposal Requires one of these permissions: ["inventory_edit"] | | write | `AdsAPIv1All_DSPAdsApiv1CreateSupplierProposedDealForecast` | Create supplier proposed deal forecast Requires one of these permissions: ["inventory_edit"] | | write | `AdsAPIv1All_DSPAdsApiv1CreateSupplierProposedDeal` | Create supplier proposed deal Requires one of these permissions: ["inventory_edit"] | | write | `AdsAPIv1All_CreateTarget` | Create target Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | read | `AdsAPIv1All_DSPListDealPlanningMetrics` | List deal planning metrics for specified deals. | | write | `AdsAPIv1All_DeleteAdAssociation` | Delete Ad Association Requires one of these permissions: ["campaign_edit"] | | write | `AdsAPIv1All_DeleteAdGroup` | Delete ad groups Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1All_DeleteAd` | Delete ads Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1All_SBDeleteAdvertisingDealTarget` | Delete advertisingDealTarget Requires one of these permissions: ["advertise... | | write | `AdsAPIv1All_SBDeleteAdvertisingDeal` | Delete advertisingDeal Requires one of these permissions: ["advertiser_campaign_edit", "advertiser_campaign_view"] | | write | `AdsAPIv1All_DeleteCampaign` | Delete campaigns Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1All_AdsApiv1DeleteReport` | Delete a report by ID Requires one of these permissions: [] | | write | `AdsAPIv1All_DeleteTarget` | Delete target Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | read | `AdsAPIv1All_ListLocationIndex` | List all Smart Location Indexes for the authenticated advertiser. | | read | `AdsAPIv1All_QueryAccountCombinationInvitation` | Query invitations to combine advertising accounts under a Single Global Account. | | read | `AdsAPIv1All_QueryAdAssociation` | Query Ad Association Requires one of these permissions: ["creatives_view", "campaign_view"] | | read | `AdsAPIv1All_QueryAdExtension` | Query ad_extension - API is in open beta Requires one of these permissions:... | | read | `AdsAPIv1All_QueryAdGroup` | List ad groups Requires one of these permissions: ["advertiser_campaign_edi... | | read | `AdsAPIv1All_QueryAd` | List ads Requires one of these permissions: ["advertiser_campaign_edit", "c... | | read | `AdsAPIv1All_QueryAdvertiserAccount` | List advertiser accounts Requires one of these permissions: [] | | read | `AdsAPIv1All_QueryAdvertiserProductGroupEligibility` | Query requests for specific advertiser product group eligibility based on advert... | | read | `AdsAPIv1All_SBQueryAdvertisingDealTarget` | Query advertisingDealTarget Requires one of these permissions: ["advertiser... | | read | `AdsAPIv1All_SBQueryAdvertisingDeal` | Query advertisingDeal Requires one of these permissions: ["advertiser_campaign_edit", "advertiser_campaign_view"] | | read | `AdsAPIv1All_QueryBrandStoreEditionPublishVersion` | Query store edition publish versions Requires one of these permissions: ["amazon_stores_edit","amazon_stores_view"] | | read | `AdsAPIv1All_QueryBrandStorePage` | Retrieve brand store page content Requires one of these permissions: ["amazon_stores_edit","amazon_stores_view"] | | read | `AdsAPIv1All_QueryBrandStore` | Query brand store content Requires one of these permissions: ["advertiser_c... | | read | `AdsAPIv1All_QueryCampaign` | Query campaign Requires one of these permissions: ["advertiser_campaign_edi... | | read | `AdsAPIv1All_DSPQueryDealAvails` | Query deal avails by advertising deal ID. | | read | `AdsAPIv1All_DSPAdsApiv1QueryInventoryGroup` | Query inventory groups with filters Requires one of these permissions: ["inventory_edit", "inventory_view"] | | read | `AdsAPIv1All_QueryLinearTvDaypart` | List all supported Linear TV Daypart Requires one of these permissions: [] | | read | `AdsAPIv1All_QueryManagerAccount` | List manager accounts Requires one of these permissions: [] | | read | `AdsAPIv1All_AdsApiv1QueryPublisher` | List all Publishers Requires one of these permissions: [] | | read | `AdsAPIv1All_SBQueryRecommendationType` | Query RecommendationTypes Requires one of these permissions: ["advertiser_campaign_view"] | | read | `AdsAPIv1All_QuerySellingAccount` | List selling accounts Requires one of these permissions: [] | | read | `AdsAPIv1All_DSPAdsApiv1QuerySupplierAdProduct` | Query supplier ad products Requires one of these permissions: ["inventory_view"] | | read | `AdsAPIv1All_DSPAdsApiv1QuerySupplierProposal` | Query supplier proposal Requires one of these permissions: ["inventory_view"] | | read | `AdsAPIv1All_DSPAdsApiv1QuerySupplierProposedDeal` | Query supplier proposed deals Requires one of these permissions: ["inventory_view"] | | read | `AdsAPIv1All_DSPAdsApiv1QuerySupplierPublisher` | Query supplier publishers Requires one of these permissions: ["inventory_view"] | | read | `AdsAPIv1All_DSPAdsApiv1QuerySupplierTargetItem` | Fetch supplier target items Requires one of these permissions: ["inventory_view"] | | read | `AdsAPIv1All_DSPAdsApiv1QuerySupplier` | Query suppliers Requires one of these permissions: ["inventory_view"] | | read | `AdsAPIv1All_QueryTarget` | List target Requires one of these permissions: ["advertiser_campaign_edit",... | | write | `AdsAPIv1All_DSPRetrieveCampaignForecast` | Retrieve campaign forecast Requires one of these permissions: ["campaign_view", "advertiser_campaign_view"] | | write | `AdsAPIv1All_DSPRetrieveCommitmentSpend` | Retrieve commitment spend Requires one of these permissions: [] | | write | `AdsAPIv1All_DSPRetrieveCommitment` | Get Commitments Requires one of these permissions: [] | | write | `AdsAPIv1All_DSPAdsApiv1RetrieveInventoryGroup` | Retrieve inventory groups by ID Requires one of these permissions: ["inventory_edit", "inventory_view"] | | write | `AdsAPIv1All_RetrieveLocationIndex` | Retrieve one or more Smart Location Indexes by ID. | | write | `AdsAPIv1All_AdsApiv1RetrieveReport` | Retrieve a report by ID Requires one of these permissions: [] | | write | `AdsAPIv1All_UpdateAccountCombinationInvitation` | Update an invitation to combine Advertising Accounts under a Single Global Accou... | | write | `AdsAPIv1All_UpdateAdAssociation` | Update Ad Association Requires one of these permissions: ["campaign_edit"] | | write | `AdsAPIv1All_UpdateAdExtension` | Update ad_extension - API is in open beta Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1All_UpdateAdGroup` | Update ad groups Requires one of these permissions: ["advertiser_campaign_e... | | write | `AdsAPIv1All_UpdateAd` | Update ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_edit"] | | write | `AdsAPIv1All_UpdateAdvertiserAccount` | Update advertiser accounts Requires one of these permissions: [] | | write | `AdsAPIv1All_SBUpdateAdvertisingDeal` | Update advertisingDeal Requires one of these permissions: ["advertiser_campaign_edit", "advertiser_campaign_view"] | | write | `AdsAPIv1All_UpdateBrandStoreEditionPublishVersion` | Update store edition publish versions Requires one of these permissions: ["amazon_stores_edit"] | | write | `AdsAPIv1All_UpdateBrandStorePage` | Update brand store page content Requires one of these permissions: ["amazon_stores_edit"] | | write | `AdsAPIv1All_UpdateCampaign` | Update campaign Requires one of these permissions: ["advertiser_campaign_ed... | | write | `AdsAPIv1All_DSPUpdateCommitment` | Update commitments Requires one of these permissions: [] | | write | `AdsAPIv1All_DSPAdsApiv1UpdateInventoryGroup` | Update inventory groups Requires one of these permissions: ["inventory_edit"] | | write | `AdsAPIv1All_UpdateLocationIndex` | Update the data for an existing Smart Location Index. | | write | `AdsAPIv1All_UpdateManagerAccount` | Update manager accounts Requires one of these permissions: [] | | write | `AdsAPIv1All_UpdateTarget` | Update target Requires one of these permissions: ["advertiser_campaign_edit"] | ### AdsAPIv1Beta | Access | Tool | Description | | --- | --- | --- | | write | `AdsAPIv1Beta_CreateAccountCombinationInvitation` | Create an invitation to combine Advertising Accounts under a Single Global Accou... | | write | `AdsAPIv1Beta_CreateAdvertiserAccount` | Create advertiser accounts Requires one of these permissions: [] | | write | `AdsAPIv1Beta_CreateAdvertiserProductGroupEligibility` | Create request for specific advertiser product group eligibility Requires one... | | write | `AdsAPIv1Beta_CreateEvent` | Create Event Data Requires one of these permissions: ["event_manager_view", "event_manager_edit"] | | write | `AdsAPIv1Beta_CreateGeoLocation` | Create geo location targeting definitions. | | write | `AdsAPIv1Beta_DSPAdsApiv1CreateInventoryGroup` | Create inventory groups Requires one of these permissions: ["inventory_edit"] | | write | `AdsAPIv1Beta_CreateLinearTvIncrementalReachForecast` | Generate Linear TV incremental reach forecast comparing with supported Streaming... | | write | `AdsAPIv1Beta_CreateLinearTvReachForecast` | Generate Linear TV reach forecast Requires one of these permissions: ["campaign_edit"] | | write | `AdsAPIv1Beta_CreateLocationIndex` | Create a Smart Location Index. | | write | `AdsAPIv1Beta_CreateManagerAccount` | Create manager accounts Requires one of these permissions: [] | | write | `AdsAPIv1Beta_AdsApiv1CreateReport` | Create a report Requires one of these permissions: ["ManagerAccount_Dev", "... | | write | `AdsAPIv1Beta_DSPAdsApiv1CreateSupplierAdProductPrice` | Create supplier ad product price Requires one of these permissions: ["inventory_view"] | | write | `AdsAPIv1Beta_DSPAdsApiv1CreateSupplierProposal` | Create supplier proposal Requires one of these permissions: ["inventory_edit"] | | write | `AdsAPIv1Beta_DSPAdsApiv1CreateSupplierProposedDealForecast` | Create supplier proposed deal forecast Requires one of these permissions: ["inventory_edit"] | | write | `AdsAPIv1Beta_DSPAdsApiv1CreateSupplierProposedDeal` | Create supplier proposed deal Requires one of these permissions: ["inventory_edit"] | | read | `AdsAPIv1Beta_DSPListDealPlanningMetrics` | List deal planning metrics for specified deals. | | write | `AdsAPIv1Beta_AdsApiv1DeleteReport` | Delete a report by ID Requires one of these permissions: [] | | read | `AdsAPIv1Beta_ListLocationIndex` | List all Smart Location Indexes for the authenticated advertiser. | | read | `AdsAPIv1Beta_QueryAccountCombinationInvitation` | Query invitations to combine advertising accounts under a Single Global Account. | | read | `AdsAPIv1Beta_QueryAdvertiserAccount` | List advertiser accounts Requires one of these permissions: [] | | read | `AdsAPIv1Beta_QueryAdvertiserProductGroupEligibility` | Query requests for specific advertiser product group eligibility based on advert... | | read | `AdsAPIv1Beta_DSPQueryDealAvails` | Query deal avails by advertising deal ID. | | read | `AdsAPIv1Beta_DSPAdsApiv1QueryInventoryGroup` | Query inventory groups with filters Requires one of these permissions: ["inventory_edit", "inventory_view"] | | read | `AdsAPIv1Beta_QueryLinearTvDaypart` | List all supported Linear TV Daypart Requires one of these permissions: [] | | read | `AdsAPIv1Beta_QueryManagerAccount` | List manager accounts Requires one of these permissions: [] | | read | `AdsAPIv1Beta_AdsApiv1QueryPublisher` | List all Publishers Requires one of these permissions: [] | | read | `AdsAPIv1Beta_QuerySellingAccount` | List selling accounts Requires one of these permissions: [] | | read | `AdsAPIv1Beta_DSPAdsApiv1QuerySupplierAdProduct` | Query supplier ad products Requires one of these permissions: ["inventory_view"] | | read | `AdsAPIv1Beta_DSPAdsApiv1QuerySupplierProposal` | Query supplier proposal Requires one of these permissions: ["inventory_view"] | | read | `AdsAPIv1Beta_DSPAdsApiv1QuerySupplierProposedDeal` | Query supplier proposed deals Requires one of these permissions: ["inventory_view"] | | read | `AdsAPIv1Beta_DSPAdsApiv1QuerySupplierPublisher` | Query supplier publishers Requires one of these permissions: ["inventory_view"] | | read | `AdsAPIv1Beta_DSPAdsApiv1QuerySupplierTargetItem` | Fetch supplier target items Requires one of these permissions: ["inventory_view"] | | read | `AdsAPIv1Beta_DSPAdsApiv1QuerySupplier` | Query suppliers Requires one of these permissions: ["inventory_view"] | | write | `AdsAPIv1Beta_DSPAdsApiv1RetrieveInventoryGroup` | Retrieve inventory groups by ID Requires one of these permissions: ["inventory_edit", "inventory_view"] | | write | `AdsAPIv1Beta_RetrieveLocationIndex` | Retrieve one or more Smart Location Indexes by ID. | | write | `AdsAPIv1Beta_AdsApiv1RetrieveReport` | Retrieve a report by ID Requires one of these permissions: [] | | write | `AdsAPIv1Beta_UpdateAccountCombinationInvitation` | Update an invitation to combine Advertising Accounts under a Single Global Accou... | | write | `AdsAPIv1Beta_UpdateAdvertiserAccount` | Update advertiser accounts Requires one of these permissions: [] | | write | `AdsAPIv1Beta_UpdateBrandStorePage` | Update brand store page content Requires one of these permissions: ["amazon_stores_edit"] | | write | `AdsAPIv1Beta_DSPAdsApiv1UpdateInventoryGroup` | Update inventory groups Requires one of these permissions: ["inventory_edit"] | | write | `AdsAPIv1Beta_UpdateLocationIndex` | Update the data for an existing Smart Location Index. | | write | `AdsAPIv1Beta_UpdateManagerAccount` | Update manager accounts Requires one of these permissions: [] | ### AdsAPIv1DSP | Access | Tool | Description | | --- | --- | --- | | write | `AdsAPIv1DSP_DSPCreateAdAssociation` | Create Ad Association Requires one of these permissions: ["campaign_edit"] | | write | `AdsAPIv1DSP_DSPCreateAdGroup` | Create ad groups Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1DSP_DSPCreateAd` | Create ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_edit"] | | write | `AdsAPIv1DSP_DSPCreateCampaign` | Create campaigns Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1DSP_DSPCreateTarget` | Create target Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1DSP_DSPDeleteAdAssociation` | Delete Ad Association Requires one of these permissions: ["campaign_edit"] | | write | `AdsAPIv1DSP_DSPDeleteTarget` | Delete target Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | read | `AdsAPIv1DSP_DSPQueryAdAssociation` | Query Ad Association Requires one of these permissions: ["creatives_view", "campaign_view"] | | read | `AdsAPIv1DSP_DSPQueryAdGroup` | List ad groups Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view"] | | read | `AdsAPIv1DSP_DSPQueryAd` | List ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_view", "advertiser_campaign_view"] | | read | `AdsAPIv1DSP_DSPQueryCampaign` | Query campaign Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view"] | | read | `AdsAPIv1DSP_DSPQueryTarget` | List target Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1DSP_DSPUpdateAdAssociation` | Update Ad Association Requires one of these permissions: ["campaign_edit"] | | write | `AdsAPIv1DSP_DSPUpdateAdGroup` | Update ad groups Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1DSP_DSPUpdateAd` | Update ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_edit"] | | write | `AdsAPIv1DSP_DSPUpdateCampaign` | Update campaign Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | ### AdsAPIv1SponsoredBrands | Access | Tool | Description | | --- | --- | --- | | write | `AdsAPIv1SponsoredBrands_SBCreateAdGroup` | Create ad groups Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredBrands_SBCreateAd` | Create ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_edit"] | | write | `AdsAPIv1SponsoredBrands_SBCreateCampaign` | Create campaigns Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredBrands_SBCreateTarget` | Create target Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredBrands_SBDeleteAdGroup` | Delete ad groups Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1SponsoredBrands_SBDeleteAd` | Delete ads Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1SponsoredBrands_SBDeleteCampaign` | Delete campaigns Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1SponsoredBrands_SBDeleteTarget` | Delete target Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | read | `AdsAPIv1SponsoredBrands_SBQueryAdGroup` | List ad groups Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view"] | | read | `AdsAPIv1SponsoredBrands_SBQueryAd` | List ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_view", "advertiser_campaign_view"] | | read | `AdsAPIv1SponsoredBrands_SBQueryCampaign` | Query campaign Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view"] | | read | `AdsAPIv1SponsoredBrands_SBQueryTarget` | List target Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredBrands_SBUpdateAdGroup` | Update ad groups Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredBrands_SBUpdateAd` | Update ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_edit"] | | write | `AdsAPIv1SponsoredBrands_SBUpdateCampaign` | Update campaign Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredBrands_SBUpdateTarget` | Update target Requires one of these permissions: ["advertiser_campaign_edit"] | ### AdsAPIv1SponsoredDisplay | Access | Tool | Description | | --- | --- | --- | | write | `AdsAPIv1SponsoredDisplay_SDCreateAdGroup` | Create ad groups Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredDisplay_SDCreateAd` | Create ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_edit"] | | write | `AdsAPIv1SponsoredDisplay_SDCreateCampaign` | Create campaigns Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredDisplay_SDCreateTarget` | Create target Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredDisplay_SDDeleteAdGroup` | Delete ad groups Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1SponsoredDisplay_SDDeleteAd` | Delete ads Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1SponsoredDisplay_SDDeleteCampaign` | Delete campaigns Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1SponsoredDisplay_SDDeleteTarget` | Delete target Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | read | `AdsAPIv1SponsoredDisplay_SDQueryAdGroup` | List ad groups Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view"] | | read | `AdsAPIv1SponsoredDisplay_SDQueryAd` | List ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_view", "advertiser_campaign_view"] | | read | `AdsAPIv1SponsoredDisplay_SDQueryCampaign` | Query campaign Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view"] | | read | `AdsAPIv1SponsoredDisplay_SDQueryTarget` | List target Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredDisplay_SDUpdateAdGroup` | Update ad groups Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredDisplay_SDUpdateAd` | Update ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_edit"] | | write | `AdsAPIv1SponsoredDisplay_SDUpdateCampaign` | Update campaign Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredDisplay_SDUpdateTarget` | Update target Requires one of these permissions: ["advertiser_campaign_edit"] | ### AdsAPIv1SponsoredProducts | Access | Tool | Description | | --- | --- | --- | | write | `AdsAPIv1SponsoredProducts_SPCreateAdGroup` | Create ad groups Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredProducts_SPCreateAd` | Create ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_edit"] | | write | `AdsAPIv1SponsoredProducts_SPCreateCampaign` | Create campaigns Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredProducts_SPCreateTarget` | Create target Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredProducts_SPDeleteAdGroup` | Delete ad groups Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1SponsoredProducts_SPDeleteAd` | Delete ads Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1SponsoredProducts_SPDeleteCampaign` | Delete campaigns Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1SponsoredProducts_SPDeleteTarget` | Delete target Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | read | `AdsAPIv1SponsoredProducts_SPQueryAdExtension` | Query ad_extension - API is in open beta Requires one of these permissions: ["advertiser_campaign_edit", "advertiser_campaign_view"] | | read | `AdsAPIv1SponsoredProducts_SPQueryAdGroup` | List ad groups Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view"] | | read | `AdsAPIv1SponsoredProducts_SPQueryAd` | List ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_view", "advertiser_campaign_view"] | | read | `AdsAPIv1SponsoredProducts_SPQueryCampaign` | Query campaign Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view"] | | read | `AdsAPIv1SponsoredProducts_SPQueryTarget` | List target Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredProducts_SPUpdateAdExtension` | Update ad_extension - API is in open beta Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1SponsoredProducts_SPUpdateAdGroup` | Update ad groups Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredProducts_SPUpdateAd` | Update ads Requires one of these permissions: ["advertiser_campaign_edit", "creatives_edit"] | | write | `AdsAPIv1SponsoredProducts_SPUpdateCampaign` | Update campaign Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredProducts_SPUpdateTarget` | Update target Requires one of these permissions: ["advertiser_campaign_edit"] | ### AdsAPIv1SponsoredTelevision | Access | Tool | Description | | --- | --- | --- | | write | `AdsAPIv1SponsoredTelevision_STCreateAdGroup` | Create ad groups Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredTelevision_STCreateAd` | Create ads Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1SponsoredTelevision_STCreateCampaign` | Create campaigns Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredTelevision_STCreateTarget` | Create target Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredTelevision_STDeleteAd` | Delete ads Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1SponsoredTelevision_STDeleteTarget` | Delete target Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | read | `AdsAPIv1SponsoredTelevision_STQueryAdGroup` | List ad groups Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view"] | | read | `AdsAPIv1SponsoredTelevision_STQueryAd` | List ads Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | read | `AdsAPIv1SponsoredTelevision_STQueryCampaign` | Query campaign Requires one of these permissions: [] | | read | `AdsAPIv1SponsoredTelevision_STQueryTarget` | List target Requires one of these permissions: ["advertiser_campaign_edit", "dsp_campaign_view", "campaign_view", "advertiser_campaign_view", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredTelevision_STUpdateAdGroup` | Update ad groups Requires one of these permissions: ["advertiser_campaign_edit", "campaign_edit", "dsp_campaign_edit"] | | write | `AdsAPIv1SponsoredTelevision_STUpdateAd` | Update ads Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `AdsAPIv1SponsoredTelevision_STUpdateCampaign` | Update campaign Requires one of these permissions: [] | | write | `AdsAPIv1SponsoredTelevision_STUpdateTarget` | Update target Requires one of these permissions: ["advertiser_campaign_edit"] | ### AmazonAttribution | Access | Tool | Description | | --- | --- | --- | | read | `AmazonAttribution_getAdvertisersByProfile` | For sellers, an attribution profile has one associated advertiser. | | read | `AmazonAttribution_getPublishers` | Use the response to determine whether to use either the macroTags or nonMacroTemplateTags resource to get tags for a certain publisher. | | read | `AmazonAttribution_getAttributionTagsByCampaign` | Gets an attribution report for a specified list of advertisers. | | read | `AmazonAttribution_getPublisherAttributionTagTemplate` | Third-party publishers, such as Google Ads, Facebook, Microsoft Ads, and Pinterest support tags that include macro parameters. | | read | `AmazonAttribution_getPublisherMacroAttributionTag` | Some third-party publishers do not support tags that include macro parameters. | ### AmazonDSPAudiences | Access | Tool | Description | | --- | --- | --- | | write | `AmazonDSPAudiences_dspCreateAudiencesPost` | Creates a targeting audience based on an audience definition. | ### AmazonDSPConversions | Access | Tool | Description | | --- | --- | --- | | read | `AmazonDSPConversions_dspAmazonAdTagGetEventsByAdTagId` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manag... | | read | `AmazonDSPConversions_dspAmazonAdTagGetAdTagByAdvertiserId` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manag... | | read | `AmazonDSPConversions_dspAmazonBatchGetConversionDefinitionsForOrders` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["campaign_view"] | | write | `AmazonDSPConversions_dspAmazonCreateConversionDefinitions` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_edit"] | | write | `AmazonDSPConversions_dspAmazonUpdateConversionDefinitions` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_edit"] | | write | `AmazonDSPConversions_dspAmazonDeletionRequest` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_edit"] | | write | `AmazonDSPConversions_dspAmazonIngestConversionData` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_edit"] | | read | `AmazonDSPConversions_dspAmazonListConversionDefinitions` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_view"] | | read | `AmazonDSPConversions_dspAmazonGetAdTagAssociatedEvent` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_view"] | | write | `AmazonDSPConversions_dspAmazonUpdateAdTagAssociatedEvent` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_edit"] | | read | `AmazonDSPConversions_dspAmazonGetAssociatedMobileAppForConversionDefinition` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_view"] | | write | `AmazonDSPConversions_dspAmazonBatchCreateMobileMeasurementPartnerAppRegistration` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_edit"] | | write | `AmazonDSPConversions_dspAmazonBatchUpdateMobileMeasurementPartnerAppRegistration` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_edit"] | | write | `AmazonDSPConversions_dspAmazonDeleteMeasurementPartnerAppRegistrations` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_edit"] | | read | `AmazonDSPConversions_dspAmazonListMobileMeasurementPartnerAppRegistrations` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_view"] | | read | `AmazonDSPConversions_dspAmazonGetAssociatedConversionDefinitionsForOrder` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["campaign_view"] | | write | `AmazonDSPConversions_dspAmazonUpdateAssociatedConversionDefinitionsForOrder` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["campaign_edit"] | ### AmazonDSPMeasurement | Access | Tool | Description | | --- | --- | --- | | write | `AmazonDSPMeasurement_CheckDSPAudienceResearchEligibility` | Checks the DSP AUDIENCE_RESEARCH study type eligibility status against vendor products. | | write | `AmazonDSPMeasurement_CheckDSPBrandLiftEligibility` | Checks the DSP BRAND_LIFT study type eligibility status against vendor products. | | write | `AmazonDSPMeasurement_CheckDSPCreativeTestingEligibility` | Checks the DSP CREATIVE_TESTING study type eligibility status against vendor products. | | write | `AmazonDSPMeasurement_CheckDSPOmnichannelMetricsEligibility` | Checks the DSP OMNICHANNEL_METRICS study type eligibility status against vendor products. | | read | `AmazonDSPMeasurement_GetDSPAudienceResearchStudies` | Gets one or more DSP AUDIENCE_RESEARCH studies with requested study identifiers or an advertiser identifier. | | write | `AmazonDSPMeasurement_CreateDSPAudienceResearchStudy` | Create new DSP AUDIENCE_RESEARCH study. | | write | `AmazonDSPMeasurement_UpdateDSPAudienceResearchStudy` | Update DSP AUDIENCE_RESEARCH study. | | read | `AmazonDSPMeasurement_GetDSPAudienceResearchStudyResult` | Get result of a DSP AUDIENCE_RESEARCH study. | | read | `AmazonDSPMeasurement_GetDSPBrandLiftStudies` | Gets one or more DSP BRAND_LIFT studies with requested study identifiers or an advertiser identifier. | | write | `AmazonDSPMeasurement_CreateDSPBrandLiftStudies` | Create new DSP BRAND_LIFT studies. | | write | `AmazonDSPMeasurement_UpdateDSPBrandLiftStudies` | Update DSP BRAND_LIFT studies. | | read | `AmazonDSPMeasurement_GetDSPCreativeTestingStudies` | Gets one or more DSP CREATIVE_TESTING studies with requested study identifiers or an advertiser identifier. | | write | `AmazonDSPMeasurement_CreateDSPCreativeTestingStudy` | Create new DSP CREATIVE_TESTING study. | | write | `AmazonDSPMeasurement_UpdateDSPCreativeTestingStudy` | Update DSP CREATIVE_TESTING study. | | read | `AmazonDSPMeasurement_GetDSPCreativeTestingStudyResult` | Get result of a DSP CREATIVE_TESTING study. | | read | `AmazonDSPMeasurement_GetDSPOmnichannelMetricsStudies` | Gets one or more DSP OMNICHANNEL_METRICS studies with requested study identifiers or an advertiser identifier. | | write | `AmazonDSPMeasurement_CreateDSPOmnichannelMetricsStudies` | Create new DSP OMNICHANNEL_METRICS studies. | | write | `AmazonDSPMeasurement_UpdateDSPOmnichannelMetricsStudies` | Update DSP OMNICHANNEL_METRICS studies. | | read | `AmazonDSPMeasurement_GetDSPOmnichannelMetricsStudyResult` | Get result of a DSP OMNICHANNEL_METRICS study. | | write | `AmazonDSPMeasurement_CheckPlanningEligibility` | Checks eligibility against all vendor products. | | write | `AmazonDSPMeasurement_CancelMeasurementStudies` | Cancel existing studies. | | read | `AmazonDSPMeasurement_GetStudies` | Gets base study objects given a list of studyIds or a list of advertiserIds. | | read | `AmazonDSPMeasurement_GetDSPBrandLiftStudyResult` | Get result of a DSP BRAND_LIFT study. | | read | `AmazonDSPMeasurement_GetSurveys` | Gets one or more study surveys with requested survey identifiers or a study identifier. | | write | `AmazonDSPMeasurement_CreateSurveys` | Create new study surveys. | | write | `AmazonDSPMeasurement_UpdateSurveys` | Update measurement surveys. | | write | `AmazonDSPMeasurement_vendorProduct` | Lists the supported measurement vendors products. | | read | `AmazonDSPMeasurement_omnichannelMetricsBrandSearch` | Search for brands to be used in the OMNICHANNEL_METRICS vendor product. | | read | `AmazonDSPMeasurement_vendorProductPolicy` | Gets the policies for the specific vendor product(s). | | read | `AmazonDSPMeasurement_vendorProductSurveyQuestionTemplates` | Gets the survey question templates for the specific vendor product(s). | ### AmazonDSPTargetKPIRecommendations | Access | Tool | Description | | --- | --- | --- | | read | `AmazonDSPTargetKPIRecommendations_getGsbTargetKpiRecommendation` | Creates a Target KPI recommendation for advertisers when they are in the process of creating a new campaign (ADSP). | ### AmazonMarketingStreamSubscriptions | Access | Tool | Description | | --- | --- | --- | | read | `AmazonMarketingStreamSubscriptions_ListDspStreamSubscriptions` | List subscriptions Note: trailing slash in request uri is not allowed Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-Account-ID Parameter in:… | | write | `AmazonMarketingStreamSubscriptions_CreateDspStreamSubscription` | Create a new subscription Note: trailing slash in request uri is not allowed Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-Account-ID Parameter… | | read | `AmazonMarketingStreamSubscriptions_GetDspStreamSubscription` | Fetch a specific subscription by Id Note: trailing slash in request uri is not allowed Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-Acc... | | write | `AmazonMarketingStreamSubscriptions_UpdateDspStreamSubscription` | Update an existing subscription Note: trailing slash in request uri is not allowed Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-Account-ID… | | read | `AmazonMarketingStreamSubscriptions_ListStreamSubscriptions` | List subscriptions Note: trailing slash in request uri is not allowed Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in:… | | write | `AmazonMarketingStreamSubscriptions_CreateStreamSubscription` | Create a new subscription Note: trailing slash in request uri is not allowed Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter… | | read | `AmazonMarketingStreamSubscriptions_GetStreamSubscription` | Fetch a specific subscription by Id Note: trailing slash in request uri is not allowed Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-Acc... | | write | `AmazonMarketingStreamSubscriptions_UpdateStreamSubscription` | Update an existing subscription Note: trailing slash in request uri is not allowed Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId… | ### AMCAdAudience | Access | Tool | Description | | --- | --- | --- | | write | `AMCAdAudience_AmcpLinkRemoveConnectionV2` | Delete a connection between the Partner and Advertiser's AMC Instances and/or DSP Advertisers. | | read | `AMCAdAudience_AmcpLinkGetConnectionsV2` | Get a list of connections between the Partner and Advertiser's AMC Instances & DSP Advertisers. | | write | `AMCAdAudience_AmcpLinkAddConnectionV2` | Create a new connection between the Partner and Advertiser's AMC Instances and/or DSP Advertisers. | | read | `AMCAdAudience_AmcpLinkGetTermsV2` | Get the Customer's AMC Terms and Conditions acceptance. | | write | `AMCAdAudience_AmcpLinkSetTermsAcceptanceV2` | Set the Customer's AMC Terms and Conditions acceptance. | | write | `AMCAdAudience_CreateAudienceMetadataV2` | Create a new Advertiser Audience Metadata. | | read | `AMCAdAudience_GetAudienceMetadataV2` | Get an Advertiser Audience Metadata using AudienceId. | | write | `AMCAdAudience_UpdateAudienceMetadataV2` | Update an existing Advertiser Audience Metadata. | | write | `AMCAdAudience_ManageAudienceV2` | Manage Advertiser audiences by adding or removing members from an Audience. | | read | `AMCAdAudience_ManageAudienceStatusV2` | Get the status of a manage audience members request. | ### AMCAdmin | Access | Tool | Description | | --- | --- | --- | | read | `AMCAdmin_AmcpLinkListAmcAccounts` | Get a list of AMC Accounts that the user have access to. | | read | `AMCAdmin_listInstances` | Gets information about all AMC instances that the requesting entity has access to. | | write | `AMCAdmin_createInstance` | Creates a new AMC instance. | | write | `AMCAdmin_deleteInstance` | Deletes the requested AMC instance. | | read | `AMCAdmin_getInstance` | Gets information about the requested AMC instance. | | write | `AMCAdmin_updateInstance` | Updates the requested AMC instance. | | read | `AMCAdmin_getInstanceAdvertisers` | Gets advertisers information about the requested AMC instance. | | read | `AMCAdmin_listAdvertiserUpdates` | Gets advertiser updates for the requested AMC instance. | | write | `AMCAdmin_createAdvertiserUpdate` | Creates a new advertiser update for the requested AMC instance. | | read | `AMCAdmin_getAdvertiserUpdate` | Gets the requested advertiser update for the requested AMC instance. | | read | `AMCAdmin_getInstanceCollaboration` | Gets the collaboration metadata for the requested AMC instance. | | write | `AMCAdmin_createCollaborationIdMappingTable` | Creates an ID Mapping Table in the requested AMC instance collaboration and starts the job to populate the table. | | read | `AMCAdmin_listCollaborationIdMappingTables` | Lists the ID mapping tables in the collaboration in the requested AMC instance. | | write | `AMCAdmin_deleteCollaborationIdMappingTable` | Deletes the given ID Mapping Table in the collaboration for the requested AMC instance. | | read | `AMCAdmin_getCollaborationIdMappingJobForTrackingId` | Retrieves the ID mapping workflow job associated to the tracking ID. | | read | `AMCAdmin_listCollaborationIdMappingJobs` | Lists the jobs associated to the given ID mapping table in the collaboration for the requested AMC instance. | | read | `AMCAdmin_getCollaborationIdMappingJob` | Gets the metadata of the job associated to the ID Mapping Table in the collaboration for the requested AMC instance. | | write | `AMCAdmin_refreshCollaborationIdMappingTable` | Starts a workflow job to refresh the data in the given ID Mapping Table in the collaboration for the requested AMC instance. | | read | `AMCAdmin_listCollaborationIdNamespaces` | Lists the advertiser ID namespaces that are not connected to an ID mapping table in the collaboration in the requested AMC instance. | | write | `AMCAdmin_updateInstanceCustomerAwsAccountMetadata` | Updates customer's AWS account metadata in the requested AMC instance. | ### AMCRuleAudience | Access | Tool | Description | | --- | --- | --- | | write | `AMCRuleAudience_createLookalikeAudience` | Creates a lookalike audience execution metadata. | | read | `AMCRuleAudience_getAllQueryBasedAudiencesByInstanceId` | Returns list of execution metadata information for a given instanceId. | | write | `AMCRuleAudience_createQueryBasedAudience` | Creates a query based audience execution metadata. | | write | `AMCRuleAudience_deleteQueryBasedAudienceByAudienceExecutionId` | Deletes an audience for a given instanceId and audienceExecutionId. | | read | `AMCRuleAudience_getQueryBasedAudienceByAudienceExecutionId` | Returns execution metadata information for a given instanceId and audienceExecutionId. | | write | `AMCRuleAudience_updateQueryBasedAudienceByAudienceExecutionId` | Updates audience configuration for a given audienceExecutionId. | ### AMCWorkflow | Access | Tool | Description | | --- | --- | --- | | read | `AMCWorkflow_listDataSources` | Returns a list of available data sources. | | read | `AMCWorkflow_getDataSource` | Gets information about the requested data source. | | read | `AMCWorkflow_listSchedules` | Returns a list of schedules. | | write | `AMCWorkflow_createSchedule` | Creates a new schedule. | | write | `AMCWorkflow_deleteSchedule` | Deletes the requested schedule. | | read | `AMCWorkflow_getSchedule` | Gets the requested schedule. | | write | `AMCWorkflow_updateSchedule` | Updates the requested schedule. | | read | `AMCWorkflow_listWorkflowExecutions` | Returns a list of workflow executions. | | write | `AMCWorkflow_createWorkflowExecution` | Creates a new, ad-hoc execution of an existing workflow. | | read | `AMCWorkflow_getWorkflowExecution` | Gets status information about the requested workflow execution. | | write | `AMCWorkflow_UpdateWorkflowExecution` | Updates the requested workflow execution. | | read | `AMCWorkflow_getWorkflowExecutionDownloadUrls` | Generates and returns pre-signed S3 URLs for the result files produced by and metadata used by the provided workflow execution. | | read | `AMCWorkflow_listWorkflows` | Returns a list of workflows. | | write | `AMCWorkflow_createWorkflow` | Creates a new workflow. | | write | `AMCWorkflow_deleteWorkflow` | Deletes the requested workflow. | | read | `AMCWorkflow_getWorkflow` | Gets the requested workflow. | | write | `AMCWorkflow_updateWorkflow` | Updates the requested workflow, using the request body directly as the new workflow definition. | ### AudiencesDiscovery | Access | Tool | Description | | --- | --- | --- | | read | `AudiencesDiscovery_listAudiences` | Returns a list of audience segments for an advertiser. | | read | `AudiencesDiscovery_fetchTaxonomy` | Returns a list of audience categories for a given category path Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Advertising-AccountId Param... | | write | `AudiencesDiscovery_DspAudienceDelete` | Deletes an existing targeting audience based on audience ID. | | write | `AudiencesDiscovery_DspAudienceEdit` | Updates an existing targeting audience based on an audience definition and audience ID. | ### BrandBenchmarks | Access | Tool | Description | | --- | --- | --- | | read | `BrandBenchmarks_ListAdvertiserReportMetadata` | Gets all of the report metadata the specified advertiser at the specified marketplace. | | read | `BrandBenchmarks_GetAdvertiserReport` | Gets the download link for an advertiser's metric report in the specified marketplace. | ### BrandMetrics | Access | Tool | Description | | --- | --- | --- | | write | `BrandMetrics_generateBrandMetricsReport` | Generates the Brand Metrics report in CSV or JSON format. | | read | `BrandMetrics_getBrandMetricsReport` | Fetch the location and status of the report for the brands for which the metrics are available. | ### BrandStoresManagement | Access | Tool | Description | | --- | --- | --- | | read | `BrandStoresManagement_ListBrandStoreEdition` | Requires one of these permissions: ["amazon_stores_edit","amazon_stores_view"] | | read | `BrandStoresManagement_QueryBrandStoreEditionPublishVersion` | A search read, allowing use of more complex filters. | | read | `BrandStoresManagement_QueryBrandStorePage` | A search read, allowing use of more complex filters. | | write | `BrandStoresManagement_UpdateBrandStoreEditionPublishVersion` | Updates BrandStoreEditionPublishVersions. | | write | `BrandStoresManagement_UpdateBrandStorePage` | Updates BrandStorePages. | ### CampaignConversionTracking | Access | Tool | Description | | --- | --- | --- | | read | `CampaignConversionTracking_DspGetCampaignConversionTrackingProductsV1` | Gets the conversion tracking products for a given campaign. | | write | `CampaignConversionTracking_DspPostProductConversionTrackingV1` | Adds products to a campaign to enable product-related conversion metrics. | | write | `CampaignConversionTracking_DspDeleteProductConversionTrackingV1` | Removes one or more products from campaign conversion tracking. | ### CampaignManage | Access | Tool | Description | | --- | --- | --- | | write | `CampaignManage_CreateAdAssociation` | Creates AdAssociations. | | write | `CampaignManage_CreateAdGroup` | Creates AdGroups. | | write | `CampaignManage_CreateAd` | Creates Ads. | | write | `CampaignManage_CreateCampaign` | Creates Campaigns. | | write | `CampaignManage_CreateTarget` | Creates Targets. | | write | `CampaignManage_DeleteAdAssociation` | Archives or deletes AdAssociations. | | write | `CampaignManage_DeleteAdGroup` | Archives or deletes AdGroups. | | write | `CampaignManage_DeleteAd` | Archives or deletes Ads. | | write | `CampaignManage_DeleteCampaign` | Archives or deletes Campaigns. | | write | `CampaignManage_DeleteTarget` | Archives or deletes Targets. | | read | `CampaignManage_QueryAdAssociation` | A search read, allowing use of more complex filters. | | read | `CampaignManage_QueryAdGroup` | A search read, allowing use of more complex filters. | | read | `CampaignManage_QueryAd` | A search read, allowing use of more complex filters. | | read | `CampaignManage_QueryCampaign` | A search read, allowing use of more complex filters. | | read | `CampaignManage_QueryTarget` | A search read, allowing use of more complex filters. | | write | `CampaignManage_UpdateAdAssociation` | Updates AdAssociations. | | write | `CampaignManage_UpdateAdGroup` | Updates AdGroups. | | write | `CampaignManage_UpdateAd` | Updates Ads. | | write | `CampaignManage_UpdateCampaign` | Updates Campaigns. | | write | `CampaignManage_UpdateTarget` | Updates Targets. | ### ChangeHistory | Access | Tool | Description | | --- | --- | --- | | read | `ChangeHistory_getHistory` | Returns history of changes for provided event sources that match the filters and time ranges specified. | ### Conversions | Access | Tool | Description | | --- | --- | --- | | read | `Conversions_dspAmazonAdTagGetEventsByAdTagId` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manag... | | read | `Conversions_dspAmazonAdTagGetAdTagByAdvertiserId` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manag... | | read | `Conversions_dspAmazonBatchGetConversionDefinitionsForOrders` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["campaign_view"] | | write | `Conversions_dspAmazonCreateConversionDefinitions` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manag... | | write | `Conversions_dspAmazonUpdateConversionDefinitions` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manag... | | write | `Conversions_dspAmazonDeletionRequest` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_edit"] | | write | `Conversions_dspAmazonIngestConversionData` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_edit"] | | read | `Conversions_dspAmazonListConversionDefinitions` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_view"] | | read | `Conversions_dspAmazonGetAdTagAssociatedEvent` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_view"] | | write | `Conversions_dspAmazonUpdateAdTagAssociatedEvent` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manag... | | read | `Conversions_dspAmazonGetAssociatedMobileAppForConversionDefinition` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_view"] | | write | `Conversions_dspAmazonBatchCreateMobileMeasurementPartnerAppRegistration` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_edit"] | | write | `Conversions_dspAmazonBatchUpdateMobileMeasurementPartnerAppRegistration` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_edit"] | | write | `Conversions_dspAmazonDeleteMeasurementPartnerAppRegistrations` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_edit"] | | read | `Conversions_dspAmazonListMobileMeasurementPartnerAppRegistrations` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["event_manager_view"] | | read | `Conversions_dspAmazonGetAssociatedConversionDefinitionsForOrder` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["campaign_view"] | | write | `Conversions_dspAmazonUpdateAssociatedConversionDefinitionsForOrder` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions: ["campaign_edit"] | ### CreativesAssets | Access | Tool | Description | | --- | --- | --- | | read | `CreativesAssets_getAsset` | Retrieve an asset | | write | `CreativesAssets_assetsBatchRegister` | This is an asynchronous api that provides clients an identifier for their batch registration request. | | read | `CreativesAssets_getAssetsBatchRegister` | Retrieves status of the batch asset registration request, uniquely identified by requestId. | | write | `CreativesAssets_registerAsset` | The API should be called once the asset is uploaded to the location provided by the /asset/upload API endpoint. | | read | `CreativesAssets_searchAssets` | Search assets | | read | `CreativesAssets_getUploadLocation` | Creates an ephemeral resource (upload location) to upload Assets to Creative Assets tool. | ### ExportsSnapshots | Access | Tool | Description | | --- | --- | --- | | write | `ExportsSnapshots_AdGroupExport` | Creates a file-based export of Ad Groups in the account satisfying the filtering criteria. | | write | `ExportsSnapshots_AdExport` | Creates a file-based export of Ads in the account satisfying the filtering criteria. | | write | `ExportsSnapshots_CampaignExport` | Creates a file-based export of Campaigns in the account satisfying the filtering criteria. | | read | `ExportsSnapshots_GetExport` | This API will return a status of the specified export. | | write | `ExportsSnapshots_TargetExport` | Creates a file-based export of Targets in the account satisfying the filtering criteria. | ### Forecasts | Access | Tool | Description | | --- | --- | --- | | write | `Forecasts_DSPRetrieveCampaignForecast` | A retrieve by ID read. | ### Locations | Access | Tool | Description | | --- | --- | --- | | read | `Locations_listLocations` | Note: This endpoint is currently limited to US only. | ### MediaPlanningReachForecasting | Access | Tool | Description | | --- | --- | --- | | write | `MediaPlanningReachForecasting_CreateDeduplicatedReachForecastsV1` | Creates a list of De-duplicated Reach Forecasts. | | write | `MediaPlanningReachForecasting_CreateReachForecastsV1` | Creates a list of new Reach Forecasts in bulk action. | | read | `MediaPlanningReachForecasting_ListReachForecastsV1` | Gets a list of Reach Forecasts by IDs Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these… | | read | `MediaPlanningReachForecasting_ListReachForecastTargetsV1` | Gets a list of targets of a Reach Forecast Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these… | ### ModerationResults | Access | Tool | Description | | --- | --- | --- | | write | `ModerationResults_moderationResults` | API to get the moderation results for the ad. | ### ProductsEligibility | Access | Tool | Description | | --- | --- | --- | | write | `ProductsEligibility_productEligibility` | Gets a list of advertising eligibility objects for a set of products. | | write | `ProductsEligibility_ProgramEligibility` | Checks the advertiser's eligibility to ad programs. | ### ProductsMetadata | Access | Tool | Description | | --- | --- | --- | | write | `ProductsMetadata_ProductMetadata` | Authorized resource type: DSP Rodeo Entity ID, DSP Advertiser Account ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions:… | ### RecommendationsAudienceInsights | Access | Tool | Description | | --- | --- | --- | | read | `RecommendationsAudienceInsights_insightsGetAudiencesOverlappingAudiences` | Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | ### RecommendationsInsightsPartnerOpportunities | Access | Tool | Description | | --- | --- | --- | | read | `RecommendationsInsightsPartnerOpportunities_partnerOpportunitiesListOpportunities` | Gets a list of opportunities specific to the partner making the request. | | read | `RecommendationsInsightsPartnerOpportunities_partnerOpportunitiesSummarizeOpportunities` | Gets aggregated information about all opportunities specific to the partner making the request. | | write | `RecommendationsInsightsPartnerOpportunities_partnerOpportunitiesApplicationStatus` | Retrieves the current status of applied recommendations. | | write | `RecommendationsInsightsPartnerOpportunities_partnerOpportunitiesApply` | Applies a given set of recommendations. | | read | `RecommendationsInsightsPartnerOpportunities_partnerOpportunitiesGetOpportunityFile` | Gets a 307 - TEMPORARY_REDIRECT to an opportunity data file. | ### RecommendationsInsightsPersonaBuilder | Access | Tool | Description | | --- | --- | --- | | write | `RecommendationsInsightsPersonaBuilder_BandedSize` | Get banded size of number of unique customers that are in the input expression. | | write | `RecommendationsInsightsPersonaBuilder_Demographics` | Get demographic insights for the input expression. | | write | `RecommendationsInsightsPersonaBuilder_PrimeVideo` | Get Prime Video insights for the input expression. | | write | `RecommendationsInsightsPersonaBuilder_TopCategoriesPurchased` | Get insights on top retail categories purchased by customers in the input expression. | | write | `RecommendationsInsightsPersonaBuilder_TopOverlappingAudiences` | Get top audiences overlapping with the input expression. | ### RecommendationsInsightsTacticalRecommendations | Access | Tool | Description | | --- | --- | --- | | write | `RecommendationsInsightsTacticalRecommendations_ApplyRecommendations` | Applies one or more recommendations. | | read | `RecommendationsInsightsTacticalRecommendations_ListRecommendations` | Retrieves a paginated list of recommendations with optional filtering. | | write | `RecommendationsInsightsTacticalRecommendations_UpdateRecommendation` | Updates a recommendation. | ### ReportingMarketingMixModeling | Access | Tool | Description | | --- | --- | --- | | read | `ReportingMarketingMixModeling_listMmmBrandGroups` | Lists the predefined brand groups for which reports may be requested. | | write | `ReportingMarketingMixModeling_createMmmReport` | Creates a report. | | write | `ReportingMarketingMixModeling_deleteMmmReport` | Deletes a report by ID. | | read | `ReportingMarketingMixModeling_getMmmReport` | Gets the generation status of a report by ID. | ### ReportingVersion3 | Access | Tool | Description | | --- | --- | --- | | write | `ReportingVersion3_createAsyncReport` | Creates a report request. | | write | `ReportingVersion3_deleteAsyncReport` | Deletes a report by id. | | read | `ReportingVersion3_getAsyncReport` | Gets a generation status of a report by id. | ### SponsoredBrandsV3 | Access | Tool | Description | | --- | --- | --- | | read | `SponsoredBrandsV3_getBrands` | Gets an array of Brand data objects for the Brand associated with the profile ID passed in the header. | | write | `SponsoredBrandsV3_completeUpload` | The API should be called once the media is uploaded to the location provided by the /media/upload API endpoint. | | read | `SponsoredBrandsV3_describeMedia` | API to poll for media status. | | read | `SponsoredBrandsV3_listAsins` | Note that for sellers, the addresss must be a Store page. | | read | `SponsoredBrandsV3_SBGetBudgetRulesRecommendation` | A rule enables an automatic budget increase for a specified date range or for a special event. | | read | `SponsoredBrandsV3_listKeywords` | Note: Keywords associated with BrandVideo ad groups are only available in v3.2 version. | | write | `SponsoredBrandsV3_createKeywords` | Note that state can't be set at keyword creation. | | write | `SponsoredBrandsV3_updateKeywords` | Updates one or more targeting clauses. | | write | `SponsoredBrandsV3_archiveKeyword` | This operation is equivalent to an update operation that sets the status field to 'archived'. | | read | `SponsoredBrandsV3_getKeyword` | Gets a keyword specified by identifier. | | read | `SponsoredBrandsV3_listNegativeKeywords` | Note: Negative keywords associated with BrandVideo ad groups are only available in v3.2 version. | | write | `SponsoredBrandsV3_createNegativeKeywords` | Creates one or more negative targeting clauses. | | write | `SponsoredBrandsV3_updateNegativeKeywords` | Updates one or more targeting clauses. | | write | `SponsoredBrandsV3_archiveNegativeKeyword` | This operation is equivalent to an update operation that sets the status field to 'archived'. | | read | `SponsoredBrandsV3_getNegativeKeyword` | Gets a negative keyword specified by identifier. | | write | `SponsoredBrandsV3_createNegativeTargets` | Create one or more negative targets. | | write | `SponsoredBrandsV3_updateNegativeTargets` | Updates one or more negative targets. | | read | `SponsoredBrandsV3_listNegativeTargets` | Note: Negative targets associated with BrandVideo ad groups are only available in v3.2 version. | | write | `SponsoredBrandsV3_archiveNegativeTarget` | Archives a negative target specified by identifier. | | read | `SponsoredBrandsV3_getNegativeTarget` | Gets a negative target specified by identifier. | | read | `SponsoredBrandsV3_getBidsRecommendations` | Get a list of bid recommendation objects for a specified list of keywords or products. | | read | `SponsoredBrandsV3_getKeywordRecommendations` | Gets an array of keyword recommendation objects for a set of ASINs included either on a landing page or a Stores page. | | read | `SponsoredBrandsV3_getBrandRecommendations` | The Brand suggestions are based on a list of either category identifiers or keywords passed in the request. | | read | `SponsoredBrandsV3_getTargetingCategories` | Recommendations are based on the ASINs that are passed in the request. | | read | `SponsoredBrandsV3_getProductRecommendations` | Recommendations are based on the ASINs that are passed in the request. | | write | `SponsoredBrandsV3_createTargets` | Create one or more targets. | | write | `SponsoredBrandsV3_updateTargets` | Updates one or more targets. | | read | `SponsoredBrandsV3_listTargets` | Gets a list of product targets associated with the client identifier passed in the authorization header, filtered by specified criteria. | | write | `SponsoredBrandsV3_archiveTarget` | The identifier of an existing target. | | read | `SponsoredBrandsV3_getTarget` | Gets a target specified by identifier. | | write | `SponsoredBrandsV3_sbCreateThemes` | Note that this endpoint does not support for Author profiles. | | write | `SponsoredBrandsV3_sbUpdateThemes` | Note that this endpoint does not support for Author profiles. | | read | `SponsoredBrandsV3_sbListThemes` | Note that this endpoint does not support for Author profiles. | | read | `SponsoredBrandsV3_listAssets` | For sellers or vendors, gets an array of assets associated with the specified brand entity identifier. | | write | `SponsoredBrandsV3_createAsset` | Image assets are stored in the Store Assets Library. | | read | `SponsoredBrandsV3_downloadReport` | Gets a 307 Temporary Redirect response that includes a location header with the value set to an AWS S3 path where the report is located. | ### SponsoredBrandsV4 | Access | Tool | Description | | --- | --- | --- | | write | `SponsoredBrandsV4_CreateBrandVideoCreative` | This API creates a new version of an existing creative for given Sponsored Brands Ad by supplying brand video creative content Requires one of these permissions: ["advertiser_campaign_edit"] | | read | `SponsoredBrandsV4_ListCreatives` | This API gets an array of all Sponsored Brands creatives that qualify the given resource identifiers and filters Requires one of these permissions:… | | write | `SponsoredBrandsV4_CreateProductCollectionCreative` | This API creates a new version of creative for given Sponsored Brands ad by supplying product collection creative content Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `SponsoredBrandsV4_CreateExtendedProductCollectionCreative` | This API creates a new version of creative for given Sponsored Brands ad by supplying extended product collection creative content Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `SponsoredBrandsV4_CreateStoreSpotlightCreative` | This API creates a new version of creative for given Sponsored Brands ad by supplying store spotlight creative content Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `SponsoredBrandsV4_CreateVideoCreative` | This API creates a new version of an existing creative for given Sponsored Brands ad by supplying video creative content Requires one of these permissions: ["advertiser_campaign_edit"] | | read | `SponsoredBrandsV4_GetSBBudgetRulesForAdvertiser` | Get budget rules | | write | `SponsoredBrandsV4_CreateBudgetRulesForSBCampaigns` | Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `SponsoredBrandsV4_UpdateBudgetRulesForSBCampaigns` | Requires one of these permissions: ["advertiser_campaign_edit"] | | read | `SponsoredBrandsV4_GetBudgetRuleByRuleIdForSBCampaigns` | Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | read | `SponsoredBrandsV4_GetCampaignsAssociatedWithSBBudgetRule` | Get campaigns associated with budget rule | | write | `SponsoredBrandsV4_sbCampaignsBudgetUsage` | Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | read | `SponsoredBrandsV4_GetBudgetRecommendations` | Provides daily budget recommendations for a list of requested Sponsored Brands campaigns, with context on estimated historical missed opportunities. | | write | `SponsoredBrandsV4_SBInsightsCampaignInsights` | Creates campaign level insights. | | read | `SponsoredBrandsV4_ListAssociatedBudgetRulesForSBCampaigns` | Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | write | `SponsoredBrandsV4_CreateAssociatedBudgetRulesForSBCampaigns` | A maximum of 250 rules can be associated to a campaign. | | write | `SponsoredBrandsV4_DisassociateAssociatedBudgetRuleForSBCampaigns` | Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `SponsoredBrandsV4_SBCampaignPerformanceForecasts` | Returns forecasts for a list of new campaigns specified in SB forecast request. | | read | `SponsoredBrandsV4_SBTargetingGetNegativeBrands` | Returns brands recommended for negative targeting. | | read | `SponsoredBrandsV4_getHeadlineRecommendations` | API to receive creative headline suggestions. | | write | `SponsoredBrandsV4_SBOptimizationRecommendation` | Returns recommended bid value for optimization rule enable campaigns. | | write | `SponsoredBrandsV4_CreateSponsoredBrandsOptimizationRules` | Currently available in beta. | | write | `SponsoredBrandsV4_UpdateSponsoredBrandsOptimizationRules` | Currently available in beta. | | write | `SponsoredBrandsV4_AssociateSponsoredBrandsOptimizationRules` | Currently available in beta. | | write | `SponsoredBrandsV4_DisassociateSponsoredBrandsOptimizationRules` | Currently available in beta. | | read | `SponsoredBrandsV4_ListSponsoredBrandsOptimizationRules` | Currently available in beta. | | read | `SponsoredBrandsV4_SBTargetingGetTargetableCategories` | Returns all targetable categories by default in a list. | | read | `SponsoredBrandsV4_SBTargetingGetRefinementsForCategory` | Returns refinements according to category input. | | read | `SponsoredBrandsV4_SBTargetingGetTargetableASINCounts` | Get number of targetable asins based on refinements provided by the user. | | write | `SponsoredBrandsV4_CreateSponsoredBrandsAdGroups` | Creates Sponsored Brands ad groups. | | write | `SponsoredBrandsV4_UpdateSponsoredBrandsAdGroups` | Updates Sponsored Brands ad groups. | | write | `SponsoredBrandsV4_DeleteSponsoredBrandsAdGroups` | Deletes Sponsored Brands ad groups. | | read | `SponsoredBrandsV4_ListSponsoredBrandsAdGroups` | Lists Sponsored Brands ad groups. | | write | `SponsoredBrandsV4_UpdateSponsoredBrandsAds` | Updates Sponsored Brands ads. | | write | `SponsoredBrandsV4_CreateSponsoredBrandsBrandVideoAds` | Creates Sponsored Brands brand video ads. | | write | `SponsoredBrandsV4_DeleteSponsoredBrandsAds` | Deletes Sponsored Brands ads. | | read | `SponsoredBrandsV4_ListSponsoredBrandsAds` | Lists Sponsored Brands ads. | | write | `SponsoredBrandsV4_CreateSponsoredBrandsProductCollectionAds` | Creates Sponsored Brands product collection ads. | | write | `SponsoredBrandsV4_CreateSponsoredBrandsExtendedProductCollectionAds` | Creates Sponsored Brands product collection ads with collection of custom images[1-5]. | | write | `SponsoredBrandsV4_CreateSponsoredBrandStoreSpotlightAds` | Creates Sponsored Brands store spotlight ads. | | write | `SponsoredBrandsV4_CreateSponsoredBrandsVideoAds` | Creates Sponsored Brands video ads. | | write | `SponsoredBrandsV4_CreateSponsoredBrandsCampaigns` | Creates Sponsored Brands campaigns. | | write | `SponsoredBrandsV4_UpdateSponsoredBrandsCampaigns` | Updates Sponsored Brands campaigns. | | write | `SponsoredBrandsV4_DeleteSponsoredBrandsCampaigns` | Deletes Sponsored Brands campaigns. | | read | `SponsoredBrandsV4_ListSponsoredBrandsCampaigns` | Lists Sponsored Brands campaigns. | | write | `SponsoredBrandsV4_StartMigrationJob` | Creates Migration Job for V3 campaigns. | | write | `SponsoredBrandsV4_MigrationJobResults` | List Migration Results of all Campaign. | | write | `SponsoredBrandsV4_MigrationJobStatus` | List Migration Job Status. | | write | `SponsoredBrandsV4_MigrationResults` | Lists all Campaign Migration results for an advertiser | ### SponsoredDisplay | Access | Tool | Description | | --- | --- | --- | | read | `SponsoredDisplay_listAdGroups` | Gets an array of AdGroup objects for a requested set of Sponsored Display ad groups. | | write | `SponsoredDisplay_createAdGroups` | Creates one or more ad groups. | | write | `SponsoredDisplay_updateAdGroups` | Updates on or more ad groups. | | read | `SponsoredDisplay_listAdGroupsEx` | Gets an array of AdGroupResponseEx objects for a set of requested ad groups. | | read | `SponsoredDisplay_getAdGroupResponseEx` | Gets extended information for a requested ad group. | | write | `SponsoredDisplay_archiveAdGroup` | This operation is equivalent to an update operation that sets the status field to 'archived'. | | read | `SponsoredDisplay_getAdGroup` | Returns an AdGroup object for a requested campaign. | | write | `SponsoredDisplay_associateOptimizationRulesWithAdGroup` | When an optimization rule is associated to an ad group, manual bids for individual targets will be overridden. | | write | `SponsoredDisplay_disassociateOptimizationRulesFromAdGroup` | Only one optimization rule can be disassociated per adGroup. | | write | `SponsoredDisplay_deleteBrandSafetyDenyList` | Archives all of the domains in the Brand Safety Deny List. | | read | `SponsoredDisplay_listDomains` | Gets an array of websites/apps that are on the advertiser's Brand Safety Deny List. | | write | `SponsoredDisplay_createBrandSafetyDenyListDomains` | Creates one or more domains to add to a Brand Safety Deny List. | | read | `SponsoredDisplay_listRequestStatus` | List status of all Brand Safety List requests. | | read | `SponsoredDisplay_getRequestResults` | When a user adds domains to their Brand Safety Deny List, the request is processed asynchronously, and a requestId is provided to the user. | | read | `SponsoredDisplay_getRequestStatus` | When a user modifies their Brand Safety Deny List, the request is processed asynchronously, and a requestId is provided to the user. | | read | `SponsoredDisplay_GetSDBudgetRulesForAdvertiser` | Get all budget rules created by an advertiser | | write | `SponsoredDisplay_CreateBudgetRulesForSDCampaigns` | Creates one or more budget rules. | | write | `SponsoredDisplay_UpdateBudgetRulesForSDCampaigns` | Update one or more budget rules. | | read | `SponsoredDisplay_GetBudgetRuleByRuleIdForSDCampaigns` | Gets a budget rule specified by identifier. | | read | `SponsoredDisplay_GetCampaignsAssociatedWithSDBudgetRule` | Gets all the campaigns associated with a budget rule | | read | `SponsoredDisplay_listCampaigns` | Gets an array of Campaign objects for a requested set of Sponsored Display campaigns. | | write | `SponsoredDisplay_createCampaigns` | Creates one or more campaigns. | | write | `SponsoredDisplay_updateCampaigns` | Updates one or more campaigns. | | write | `SponsoredDisplay_sdCampaignsBudgetUsage` | Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | read | `SponsoredDisplay_getSDBudgetRecommendations` | Given a list of campaigns as input, this API provides the following metrics: 1. | | read | `SponsoredDisplay_listCampaignsEx` | Gets an array of CampaignResponseEx objects for a set of requested campaigns. | | read | `SponsoredDisplay_getCampaignResponseEx` | Returns a CampaignResponseEx object for a requested campaign. | | write | `SponsoredDisplay_archiveCampaign` | This operation is equivalent to an update operation that sets the status field to 'archived'. | | read | `SponsoredDisplay_getCampaign` | Returns a Campaign object for a requested campaign. | | read | `SponsoredDisplay_ListAssociatedBudgetRulesForSDCampaigns` | Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | write | `SponsoredDisplay_CreateAssociatedBudgetRulesForSDCampaigns` | A maximum of 250 rules can be associated to a campaign. | | write | `SponsoredDisplay_DisassociateAssociatedBudgetRuleForSDCampaigns` | Disassociates a budget rule specified by identifier from a campaign specified by identifier. | | read | `SponsoredDisplay_listCreatives` | Gets a list of creatives | | write | `SponsoredDisplay_createCreatives` | A POST request of one or more creatives. | | write | `SponsoredDisplay_updateCreatives` | Updates one or more creatives. | | write | `SponsoredDisplay_postCreativePreview` | Gets creative preview HTML. | | write | `SponsoredDisplay_createSDForecast` | Returns forecasts for a given ad group specified in SD forecast request. | | read | `SponsoredDisplay_listLocations` | Gets a list of Sponsored Display Location objects. | | write | `SponsoredDisplay_createLocations` | This resource is not available when productAds have ASIN or SKU fields and only available for advertisers that do not sell products on Amazon. | | write | `SponsoredDisplay_archiveLocations` | This is a bulk operation that accepts up to a limit of 1000 Location Expression Ids at a time. | | read | `SponsoredDisplay_listCreativeModerations` | Gets a list of creative moderations | | read | `SponsoredDisplay_listNegativeTargetingClauses` | Gets a list of negative targeting clauses objects for a requested set of Sponsored Display negative targets. | | write | `SponsoredDisplay_createNegativeTargetingClauses` | Successfully created negative targeting clauses associated with an ad group are assigned a unique target identifier. | | write | `SponsoredDisplay_updateNegativeTargetingClauses` | Updates one or more negative targeting clauses. | | read | `SponsoredDisplay_listNegativeTargetingClausesEx` | Gets an array of NegativeTargetingClauseEx objects for a set of requested negative targets. | | read | `SponsoredDisplay_getNegativeTargetsEx` | Gets a negative targeting clause with extended fields. | | write | `SponsoredDisplay_archiveNegativeTargetingClause` | Equivalent to using the updateNegativeTargetingClauses operation to set the state property of a targeting clause to archived. | | read | `SponsoredDisplay_getNegativeTargets` | This call returns the minimal set of negative targeting clause fields, but is more efficient than getNegativeTargetsEx. | | read | `SponsoredDisplay_listOptimizationRules` | Gets an array of OptimizationRule objects for a requested set of Sponsored Display optimization rules. | | write | `SponsoredDisplay_createOptimizationRules` | When an optimization rule is associated to an ad group, manual bids for individual targets will be overridden. | | write | `SponsoredDisplay_updateOptimizationRules` | Updates one or more optimization rules. | | read | `SponsoredDisplay_listProductAds` | Gets an array of ProductAd objects for a requested set of Sponsored Display product ads. | | write | `SponsoredDisplay_createProductAds` | Creates one or more product ads. | | write | `SponsoredDisplay_updateProductAds` | Updates one or more product ads. | | read | `SponsoredDisplay_listProductAdsEx` | Gets an array of ProductAdResponseEx objects for a set of requested ad groups. | | read | `SponsoredDisplay_getProductAdResponseEx` | Gets extended information for a product ad. | | write | `SponsoredDisplay_archiveProductAd` | This operation is equivalent to an update operation that sets the status field to 'archived'. | | read | `SponsoredDisplay_getProductAd` | Note that the ProductAd object is designed for performance, and includes a small set of commonly used fields to reduce size. | | read | `SponsoredDisplay_getHeadlineRecommendationsForSD` | You can use this Sponsored Display API to retrieve creative headline recommendations from an array of ASINs. | | read | `SponsoredDisplay_getSnapshot` | Note: Snapshots APIs are deprecated and will be shut off on October 15, 2024. | | read | `SponsoredDisplay_downloadSnapshot` | Note: Snapshots APIs are deprecated and will be shut off on October 15, 2024. | | read | `SponsoredDisplay_listTargetingClauses` | Gets a list of targeting clauses objects for a requested set of Sponsored Display targets. | | write | `SponsoredDisplay_createTargetingClauses` | Successfully created targeting clauses are assigned a unique targetId value. | | write | `SponsoredDisplay_updateTargetingClauses` | Updates one or more targeting clauses. | | read | `SponsoredDisplay_getTargetBidRecommendations` | Provides a list of bid recommendations based on the list of input advertised ASINs and targeting clauses in the same format as the targeting API. | | read | `SponsoredDisplay_listTargetingClausesEx` | Gets an array of TargetingClauseEx objects for a set of requested targets. | | read | `SponsoredDisplay_getTargetsEx` | Gets a targeting clause object with extended fields. | | read | `SponsoredDisplay_getTargetRecommendations` | This API provides product, category and standard audience recommendations to target based on the list of input ASINs. | | write | `SponsoredDisplay_archiveTargetingClause` | Equivalent to using the updateTargetingClauses operation to set the state property of a targeting clause to archived. | | read | `SponsoredDisplay_getTargets` | This call returns the minimal set of targeting clause fields. | | write | `SponsoredDisplay_requestReport` | To understand the call flow for asynchronous reports, see Getting started with sponsored ads reports. | | write | `SponsoredDisplay_createSnapshot` | Note: Snapshots APIs are deprecated and will be shut off on October 15, 2024. | | read | `SponsoredDisplay_getReportStatus` | Uses the reportId value from the response of a report previously requested via POST method of the /sd/{recordType}/report operation. | | read | `SponsoredDisplay_downloadReport` | Gets a 307 Temporary Redirect response that includes a location header with the value set to an AWS S3 path where the report is located. | ### SponsoredProducts | Access | Tool | Description | | --- | --- | --- | | write | `SponsoredProducts_CreateSponsoredProductsAdGroups` | Create ad groups Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_UpdateSponsoredProductsAdGroups` | Update ad groups Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_DeleteSponsoredProductsAdGroups` | Delete ad groups Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | read | `SponsoredProducts_ListSponsoredProductsAdGroups` | List ad groups Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | read | `SponsoredProducts_GetSPBudgetRulesForAdvertiser` | Get all budget rules created by an advertiser | | write | `SponsoredProducts_CreateBudgetRulesForSPCampaigns` | Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `SponsoredProducts_UpdateBudgetRulesForSPCampaigns` | Requires one of these permissions: ["advertiser_campaign_edit"] | | read | `SponsoredProducts_GetBudgetRuleByRuleIdForSPCampaigns` | Authorized resource type: Global Ad Account ID, Profile ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions:… | | read | `SponsoredProducts_GetCampaignsAssociatedWithSPBudgetRule` | Gets all the campaigns associated with a budget rule | | write | `SponsoredProducts_BulkBudgetRulesAssociationForSP` | A maximum of 250 rules can be associated to a campaign. | | write | `SponsoredProducts_BulkBudgetRulesDisAssociationForSP` | Requires one of these permissions: ["advertiser_campaign_edit"] | | read | `SponsoredProducts_getCampaignRecommendations` | Gets the top consolidated recommendations across bid, budget, targeting for SP campaigns given an advertiser profile id. | | write | `SponsoredProducts_CreateSponsoredProductsCampaignNegativeKeywords` | Create campaign negative keywords Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_UpdateSponsoredProductsCampaignNegativeKeywords` | Update campaign negative keywords Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_DeleteSponsoredProductsCampaignNegativeKeywords` | Delete campaign negative keywords Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | read | `SponsoredProducts_ListSponsoredProductsCampaignNegativeKeywords` | List campaign negative keywords Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | write | `SponsoredProducts_CreateSponsoredProductsCampaignNegativeTargetingClauses` | Create campaign negative targeting clauses Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_UpdateSponsoredProductsCampaignNegativeTargetingClauses` | Update campaign negative targeting clauses Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_DeleteSponsoredProductsCampaignNegativeTargetingClauses` | Delete campaign negative targeting clauses Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | read | `SponsoredProducts_ListSponsoredProductsCampaignNegativeTargetingClauses` | List campaign negative targeting clauses Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | write | `SponsoredProducts_CreateSponsoredProductsCampaigns` | Create campaigns Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_UpdateSponsoredProductsCampaigns` | Update campaigns Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_spCampaignsBudgetUsage` | Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | read | `SponsoredProducts_getBudgetRecommendations` | Given a list of campaigns as input, this API provides the following metrics - 1. | | read | `SponsoredProducts_SPGetBudgetRulesRecommendation` | A rule enables an automatic budget increase for a specified date range or for a special event. | | write | `SponsoredProducts_DeleteSponsoredProductsCampaigns` | Delete campaigns Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | read | `SponsoredProducts_getBudgetRecommendation` | Creates daily budget recommendation along with benchmark metrics when creating a new campaign. | | read | `SponsoredProducts_ListSponsoredProductsCampaigns` | List campaigns Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | read | `SponsoredProducts_ListAssociatedBudgetRulesForSPCampaigns` | Authorized resource type: Global Ad Account ID, Profile ID Parameter name: Amazon-Ads-AccountId Parameter in: header Requires one of these permissions:… | | write | `SponsoredProducts_CreateAssociatedBudgetRulesForSPCampaigns` | A maximum of 250 rules can be associated to a campaign. | | write | `SponsoredProducts_DisassociateAssociatedBudgetRuleForSPCampaigns` | Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `SponsoredProducts_AssociateOptimizationRulesToCampaign` | Requires one of these permissions: ["advertiser_campaign_edit"] | | read | `SponsoredProducts_GetMultiCountryThemeBasedBidRecommendationForAdGroup_v1` | The POST /sp/targets/bid/recommendations endpoint returns recommended bids for each target given either A) new ad group (a list of ad ASINs) or B) existing ad group (a campaign ID and ad grou... | | read | `SponsoredProducts_getGlobalRankedKeywordRecommendation` | The POST /sp/global/targets/keywords/recommendations/list endpoint returns recommended keyword targets for a list of countries given either A) a list of ad ASINs per target country or B) a gl... | | write | `SponsoredProducts_CreateSponsoredProductsKeywords` | Create keywords Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_UpdateSponsoredProductsKeywords` | Update keywords Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_DeleteSponsoredProductsKeywords` | Delete keywords Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | read | `SponsoredProducts_ListSponsoredProductsKeywords` | List keywords Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_CreateSponsoredProductsNegativeKeywords` | Create negative keywords Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_UpdateSponsoredProductsNegativeKeywords` | Update negative keywords Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_DeleteSponsoredProductsNegativeKeywords` | Delete negative keywords Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | read | `SponsoredProducts_ListSponsoredProductsNegativeKeywords` | List negative keywords Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | write | `SponsoredProducts_CreateSponsoredProductsNegativeTargetingClauses` | Create negative targeting clauses Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_UpdateSponsoredProductsNegativeTargetingClauses` | Update negative targeting clauses Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | read | `SponsoredProducts_getNegativeBrands` | Returns brands recommended for negative targeting. | | read | `SponsoredProducts_searchBrands` | Returns up to 100 brands related to keyword input for negative targeting. | | write | `SponsoredProducts_DeleteSponsoredProductsNegativeTargetingClauses` | Delete negative targeting clauses Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | read | `SponsoredProducts_ListSponsoredProductsNegativeTargetingClauses` | List negative targeting clauses Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | write | `SponsoredProducts_CreateSponsoredProductsProductAds` | Create product ads Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_UpdateSponsoredProductsProductAds` | Update product ads Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_DeleteSponsoredProductsProductAds` | Delete product ads Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | read | `SponsoredProducts_ListSponsoredProductsProductAds` | List product ads Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | write | `SponsoredProducts_CreateOptimizationRule` | Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `SponsoredProducts_UpdateOptimizationRule` | Requires one of these permissions: ["advertiser_campaign_edit"] | | read | `SponsoredProducts_GetOptimizationRuleEligibility` | Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | read | `SponsoredProducts_GetRuleNotification` | Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | write | `SponsoredProducts_DeleteCampaignOptimizationRule` | Requires one of these permissions: ["advertiser_campaign_edit"] | | read | `SponsoredProducts_GetCampaignOptimizationRule` | Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | write | `SponsoredProducts_CreateOptimizationRules` | Requires one of these permissions: ["advertiser_campaign_edit"] | | write | `SponsoredProducts_UpdateOptimizationRules` | Requires one of these permissions: ["advertiser_campaign_edit"] | | read | `SponsoredProducts_SearchOptimizationRules` | Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | write | `SponsoredProducts_CreateTargetPromotionGroups` | Creates a target promotion group, by grouping the auto-targeting adGroupId and manual-targeting adGroups, divided by keyword targeting adGroups, and product targeting adGroups. | | read | `SponsoredProducts_ListTargetPromotionGroups` | Returns the target promotion groups for an advertiser and / or adGroupId, and / or target promotion group id. | | read | `SponsoredProducts_GetTargetPromotionGroupsRecommendations` | Retrieves keyword and product targets of an auto-targeting campaign as recommendations for promoting to a manual-targeting campaign. | | write | `SponsoredProducts_CreateTargetPromotionGroupTargets` | Creates keyword and/or product targets in the manual adGroup that are part of the target promotion group Requires one of these permissions: ["advertiser_campaign_edit","advertiser_campaign_view"] | | read | `SponsoredProducts_ListTargetPromotionGroupTargets` | Returns the targets created through target promotion groups for an advertiser and / or given target promotion group. | | read | `SponsoredProducts_getKeywordGroupRecommendations` | This API (currently beta) recommends Keyword Group targets for a given list of Ad ASINs. | | write | `SponsoredProducts_CreateSponsoredProductsTargetingClauses` | Create targeting clauses Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | write | `SponsoredProducts_UpdateSponsoredProductsTargetingClauses` | Update targeting clauses Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | read | `SponsoredProducts_GetThemeBasedBidRecommendationForAdGroup_v1` | The POST /sp/targets/bid/recommendations endpoint returns recommended bids for each target given either A) new ad group (a list of ad ASINs) or B) existing ad group (a campaign ID and ad grou... | | read | `SponsoredProducts_getTargetableCategories` | Returns all targetable categories. | | read | `SponsoredProducts_getCategoryRecommendationsForASINs` | Returns a list of category recommendations for the input list of ASINs. | | read | `SponsoredProducts_getRefinementsForCategory` | Returns refinements according to category input. | | write | `SponsoredProducts_DeleteSponsoredProductsTargetingClauses` | Delete targeting clauses Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | read | `SponsoredProducts_getRankedKeywordRecommendation` | The POST /sp/targets/keywords/recommendations endpoint returns recommended keyword targets given either A) a list of ad ASINs or B) a campaign ID and ad group ID. | | read | `SponsoredProducts_ListSponsoredProductsTargetingClauses` | List targeting clauses Requires one of these permissions: ["advertiser_campaign_edit","campaign_proposed"] | | read | `SponsoredProducts_getTargetableASINCounts` | Get number of targetable asins based on refinements provided by the user. | | read | `SponsoredProducts_getProductRecommendations` | Given an advertised ASIN as input, this API returns suggested ASINs to target in a product targeting campaign. | | read | `SponsoredProducts_SPGetAllRuleEvents` | A rule enables an automatic budget increase for a specified date range or for a special event. | ### SPSnapshotsSuggestedKeywords | Access | Tool | Description | | --- | --- | --- | | read | `SPSnapshotsSuggestedKeywords_getAdGroupBidRecommendations` | Deprecation notice: This endpoint will be deprecated on March 27, 2024. | | read | `SPSnapshotsSuggestedKeywords_getAdGroupSuggestedKeywords` | Gets suggested keywords for the specified ad group. | | read | `SPSnapshotsSuggestedKeywords_getAdGroupSuggestedKeywordsEx` | Gets suggested keywords with extended data for the specified ad group. | | read | `SPSnapshotsSuggestedKeywords_bulkGetAsinSuggestedKeywords` | Suggested keywords are returned in an array ordered by descending effectiveness. | | read | `SPSnapshotsSuggestedKeywords_getAsinSuggestedKeywords` | Suggested keywords are returned in an array ordered by descending effectiveness. | | write | `SPSnapshotsSuggestedKeywords_createKeywordBidRecommendations` | Deprecation notice: This endpoint will be deprecated on March 27, 2024. | | read | `SPSnapshotsSuggestedKeywords_getKeywordBidRecommendations` | Deprecation notice: This endpoint will be deprecated on March 27, 2024. | | read | `SPSnapshotsSuggestedKeywords_getSnapshotStatus` | Note: Snapshots APIs are deprecated and will be shut off on October 15, 2024. | | read | `SPSnapshotsSuggestedKeywords_downloadSnapshot` | Note: Snapshots APIs are deprecated and will be shut off on October 15, 2024. | | read | `SPSnapshotsSuggestedKeywords_getBidRecommendations` | Gets a list of bid recommendations for keyword, product, or auto targeting expressions. | | write | `SPSnapshotsSuggestedKeywords_requestSnapshot` | Note: Snapshots APIs are deprecated and will be shut off on October 15, 2024. | ### StoresAnalytics | Access | Tool | Description | | --- | --- | --- | | read | `StoresAnalytics_getAsinEngagementForStore` | Store asin metrics provides information about your store asin performance, including rendered impressions, viewed impressions, clicks and sales. | | read | `StoresAnalytics_getInsightsForStoreAPI` | Stores insights provides information about your store's performance, including traffic and sales. | ### TestAccount | Access | Tool | Description | | --- | --- | --- | | read | `TestAccount_GetAccountInformation` | API to get Account information. | | write | `TestAccount_createAccount` | Submit a account creation request. | ### UnifiedPreModerationResults | Access | Tool | Description | | --- | --- | --- | | write | `UnifiedPreModerationResults_preModeration` | This API will be accepting different components of the ad/page and will be automatically validating the components and send back the policy violations if any. | ### Amazon Selling Partner MCP Tools URL: https://www.kuudo.com/docs/mcp-reference/amazon-sp-tools/ This page lists every tool the Amazon Selling Partner MCP exposes, grouped by the underlying Selling Partner API resource. Each entry shows whether it's a read tool (safe to call freely) or a write tool (guarded, may require approval), the tool name, and a short description. Vendor Central tools aren't included yet — that's a separate MCP surface. See [Kuudo MCP Servers](/docs/mcp-reference/tools/) for the full index of Kuudo MCP servers. Expand any resource below to see its tools. Your browser's find-in-page (Ctrl+F / Cmd+F) searches across every tool on this page, even inside collapsed sections. ## Tool reference 51 resources with tools · 304 tools ### AplusContent | Access | Tool | Description | | --- | --- | --- | | write | `AplusContent_validateContentDocumentAsinRelations` | Checks if the A+ Content document is valid for use on a set of ASINs. | | read | `AplusContent_searchContentDocuments` | Returns a list of all A+ Content documents, including metadata, that are assigned to a selling partner. | | write | `AplusContent_createContentDocument` | Creates a new A+ Content document. | | read | `AplusContent_getContentDocument` | Returns an A+ Content document, if available. | | write | `AplusContent_updateContentDocument` | Updates an existing A+ Content document. | | write | `AplusContent_postContentDocumentApprovalSubmission` | Submits an A+ Content document for review, approval, and publishing. | | read | `AplusContent_listContentDocumentAsinRelations` | Returns a list of ASINs that are related to the specified A+ Content document, if available. | | write | `AplusContent_postContentDocumentAsinRelations` | Replaces all ASINs related to the specified A+ Content document, if available. | | write | `AplusContent_postContentDocumentSuspendSubmission` | Submits a request to suspend visible A+ Content. | | read | `AplusContent_searchContentPublishRecords` | Searches for A+ Content publishing records, if available. | ### AppIntegrations | Access | Tool | Description | | --- | --- | --- | | write | `AppIntegrations_createNotification` | Create a notification for sellers in Seller Central. | | write | `AppIntegrations_deleteNotifications` | Remove your application's notifications from the Appstore notifications dashboard. | | write | `AppIntegrations_recordActionFeedback` | Records the seller's response to a notification. | ### ApplicationManagement | Access | Tool | Description | | --- | --- | --- | | write | `ApplicationManagement_rotateApplicationClientSecret` | Rotates application client secrets for a developer application. | ### Awd | Access | Tool | Description | | --- | --- | --- | | write | `Awd_checkInboundEligibility` | Determines if the packages you specify are eligible for an AWD inbound order and contains error details for ineligible packages. | | write | `Awd_createInbound` | Creates a draft AWD inbound order with a list of packages for inbound shipment. | | read | `Awd_getInbound` | Retrieves an AWD inbound order. | | write | `Awd_updateInbound` | Updates an AWD inbound order that is in DRAFT status and not yet confirmed. | | write | `Awd_cancelInbound` | Cancels an AWD Inbound order and its associated shipment. | | write | `Awd_confirmInbound` | Confirms an AWD inbound order in DRAFT status. | | read | `Awd_listInboundShipments` | Retrieves a summary of all the inbound AWD shipments associated with a merchant, with the ability to apply optional filters. | | read | `Awd_getInboundShipment` | Retrieves an AWD inbound shipment. | | read | `Awd_getInboundShipmentLabels` | Retrieves the box labels for a shipment ID that you specify. | | write | `Awd_updateInboundShipmentTransportDetails` | Updates transport details for an AWD shipment. | | read | `Awd_listInventory` | Lists AWD inventory associated with a merchant with the ability to apply optional filters. | ### CatalogItems | Access | Tool | Description | | --- | --- | --- | | read | `CatalogItems_searchCatalogItems` | Search for a list of Amazon catalog items and item-related information. | | read | `CatalogItems_getCatalogItem` | Retrieves details for an item in the Amazon catalog. | ### CatalogItems20201201 | Access | Tool | Description | | --- | --- | --- | | read | `CatalogItems20201201_searchCatalogItems` | Search for and return a list of Amazon catalog items and associated information. | | read | `CatalogItems20201201_getCatalogItem` | Retrieves details for an item in the Amazon catalog. | ### CatalogItemsV0 | Access | Tool | Description | | --- | --- | --- | | read | `CatalogItemsV0_listCatalogCategories` | Returns the parent categories to which an item belongs, based on the specified ASIN or SellerSKU. | ### CustomerFeedback | Access | Tool | Description | | --- | --- | --- | | read | `CustomerFeedback_getBrowseNodeReturnTopics` | Retrieve the topics that customers mention when they return items in a browse node. | | read | `CustomerFeedback_getBrowseNodeReturnTrends` | Retrieve the trends of topics that customers mention when they return items in a browse node. | | read | `CustomerFeedback_getBrowseNodeReviewTopics` | Retrieve a browse node's ten most positive and ten most negative review topics. | | read | `CustomerFeedback_getBrowseNodeReviewTrends` | Retrieve the positive and negative review trends of items in a browse node for the past six months. | | read | `CustomerFeedback_getItemBrowseNode` | This API returns the associated browse node of the requested ASIN. | | read | `CustomerFeedback_getItemReviewTopics` | Retrieve an item's ten most positive and ten most negative review topics. | | read | `CustomerFeedback_getItemReviewTrends` | Retrieve an item's positive and negative review trends for the past six months. | ### DataKiosk | Access | Tool | Description | | --- | --- | --- | | read | `DataKiosk_getDocument` | Returns the information required for retrieving a Data Kiosk document's contents. | | read | `DataKiosk_getQueries` | Returns details for the Data Kiosk queries that match the specified filters. | | write | `DataKiosk_createQuery` | Creates a Data Kiosk query request. | | write | `DataKiosk_cancelQuery` | Cancels the query specified by the queryId parameter. | | read | `DataKiosk_getQuery` | Returns query details for the query specified by the queryId parameter. | ### DeliveryByAmazon | Access | Tool | Description | | --- | --- | --- | | write | `DeliveryByAmazon_submitInvoice` | Submits a shipment invoice for a given order or shipment. | | read | `DeliveryByAmazon_getInvoiceStatus` | Returns the invoice status for the order or shipment you specify. | ### EasyShip | Access | Tool | Description | | --- | --- | --- | | read | `EasyShip_getScheduledPackage` | Returns information about a package, including dimensions, weight, time slot information for handover, invoice and item information, and status. | | write | `EasyShip_updateScheduledPackages` | Updates the time slot for handing over the package indicated by the specified scheduledPackageId. | | write | `EasyShip_createScheduledPackage` | Schedules an Easy Ship order and returns the scheduled package information. | | write | `EasyShip_createScheduledPackageBulk` | This operation automatically schedules a time slot for all the amazonOrderIds given as input, generating the associated shipping labels, along with other compliance documents according to the… | | read | `EasyShip_listHandoverSlots` | Returns time slots available for Easy Ship orders to be scheduled based on the package weight and dimensions that the seller specifies. | ### ExternalFulfillmentInventory | Access | Tool | Description | | --- | --- | --- | | write | `ExternalFulfillmentInventory_batchInventory` | Make up to 10 inventory requests. | ### ExternalFulfillmentReturns | Access | Tool | Description | | --- | --- | --- | | read | `ExternalFulfillmentReturns_listReturns` | Retrieve a list of return items. | | read | `ExternalFulfillmentReturns_getReturn` | Retrieve the return item with the specified ID. | ### ExternalFulfillmentShipments | Access | Tool | Description | | --- | --- | --- | | read | `ExternalFulfillmentShipments_getShipments` | Get a list of shipments created for the seller in the status you specify. | | read | `ExternalFulfillmentShipments_getShipment` | Get a single shipment with the ID you specify. | | write | `ExternalFulfillmentShipments_processShipment` | Confirm or reject the specified shipment. | | read | `ExternalFulfillmentShipments_retrieveInvoice` | Retrieve invoices for the shipment you specify. | | write | `ExternalFulfillmentShipments_generateInvoice` | Get invoices for the shipment you specify. | | write | `ExternalFulfillmentShipments_createPackages` | Provide details about the packages in the specified shipment. | | write | `ExternalFulfillmentShipments_updatePackageStatus` | Updates the status of the packages. | | write | `ExternalFulfillmentShipments_updatePackage` | Updates the details about the packages that will be used to fulfill the specified shipment. | | write | `ExternalFulfillmentShipments_generateShipLabels` | Generate and retrieve all shipping labels for one or more packages in the shipment you specify. | | read | `ExternalFulfillmentShipments_retrieveShippingOptions` | Get a list of shipping options for a package in a shipment given the shipment's marketplace and channel. | ### FbaInboundEligibility | Access | Tool | Description | | --- | --- | --- | | read | `FbaInboundEligibility_getItemEligibilityPreview` | This operation gets an eligibility preview for an item that you specify. | ### FbaInventory | Access | Tool | Description | | --- | --- | --- | | write | `FbaInventory_createInventoryItem` | Requests that Amazon create product-details in the Sandbox Inventory in the sandbox environment. | | write | `FbaInventory_addInventory` | Requests that Amazon add items to the Sandbox Inventory with desired amount of quantity in the sandbox environment. | | write | `FbaInventory_deleteInventoryItem` | Requests that Amazon Deletes an item from the Sandbox Inventory in the sandbox environment. | | read | `FbaInventory_getInventorySummaries` | Returns a list of inventory summaries. | ### Feeds | Access | Tool | Description | | --- | --- | --- | | write | `Feeds_createFeedDocument` | Creates a feed document for the feed type that you specify. | | read | `Feeds_getFeedDocument` | Returns the information required for retrieving a feed document's contents. | | read | `Feeds_getFeeds` | Returns feed details for the feeds that match the filters that you specify. | | write | `Feeds_createFeed` | Creates a feed. | | write | `Feeds_cancelFeed` | Cancels the feed that you specify. | | read | `Feeds_getFeed` | Returns feed details (including the resultDocumentId, if available) for the feed that you specify. | ### Fees | Access | Tool | Description | | --- | --- | --- | | read | `Fees_getMyFeesEstimates` | Returns the estimated fees for a list of products. | | read | `Fees_getMyFeesEstimateForASIN` | Returns the estimated fees for the item indicated by the specified ASIN in the marketplace specified in the request body. | | read | `Fees_getMyFeesEstimateForSKU` | Returns the estimated fees for the item indicated by the specified seller SKU in the marketplace specified in the request body. | ### Finances | Access | Tool | Description | | --- | --- | --- | | read | `Finances_listTransactions` | Returns transactions for the given parameters. | ### FinancesV0 | Access | Tool | Description | | --- | --- | --- | | read | `FinancesV0_listFinancialEventGroups` | Returns financial event groups for a given date range. | | read | `FinancesV0_listFinancialEventsByGroupId` | Returns all financial events for the specified financial event group. | | read | `FinancesV0_listFinancialEvents` | Returns financial events for the specified data range. | | read | `FinancesV0_listFinancialEventsByOrderId` | Returns all financial events for the specified order. | ### FulfillmentInbound | Access | Tool | Description | | --- | --- | --- | | read | `FulfillmentInbound_listInboundPlans` | Provides a list of inbound plans with minimal information. | | write | `FulfillmentInbound_createInboundPlan` | Creates an inbound plan. | | read | `FulfillmentInbound_getInboundPlan` | Fetches the top level information about an inbound plan. | | read | `FulfillmentInbound_listInboundPlanBoxes` | Provides a paginated list of box packages in an inbound plan. | | write | `FulfillmentInbound_cancelInboundPlan` | Cancels an Inbound Plan. | | read | `FulfillmentInbound_listInboundPlanItems` | Provides a paginated list of item packages in an inbound plan. | | write | `FulfillmentInbound_updateInboundPlanName` | Updates the name of an existing inbound plan. | | read | `FulfillmentInbound_listPackingGroupBoxes` | Retrieves a page of boxes from a given packing group. | | read | `FulfillmentInbound_listPackingGroupItems` | Retrieves a page of items in a given packing group. | | write | `FulfillmentInbound_setPackingInformation` | Sets packing information for an inbound plan. | | read | `FulfillmentInbound_listPackingOptions` | Retrieves a list of all packing options for an inbound plan. | | write | `FulfillmentInbound_generatePackingOptions` | Generates available packing options for the inbound plan. | | write | `FulfillmentInbound_confirmPackingOption` | Confirms the packing option for an inbound plan. | | read | `FulfillmentInbound_listInboundPlanPallets` | Provides a paginated list of pallet packages in an inbound plan. | | read | `FulfillmentInbound_listPlacementOptions` | Provides a list of all placement options for an inbound plan. | | write | `FulfillmentInbound_generatePlacementOptions` | Generates placement options for the inbound plan. | | write | `FulfillmentInbound_confirmPlacementOption` | Confirms the placement option for an inbound plan. | | read | `FulfillmentInbound_getShipment` | Provides the full details for a specific shipment within an inbound plan. | | read | `FulfillmentInbound_listShipmentBoxes` | Provides a paginated list of box packages in a shipment. | | read | `FulfillmentInbound_listShipmentContentUpdatePreviews` | Retrieve a paginated list of shipment content update previews for a given shipment. | | write | `FulfillmentInbound_generateShipmentContentUpdatePreviews` | Generate a shipment content update preview given a set of intended boxes and/or items for a shipment with a confirmed carrier. | | read | `FulfillmentInbound_getShipmentContentUpdatePreview` | Retrieve a shipment content update preview which provides a summary of the requested shipment content changes along with the transportation cost implications of the change that can only be confirmed… | | write | `FulfillmentInbound_confirmShipmentContentUpdatePreview` | Confirm a shipment content update preview and accept the changes in transportation cost. | | read | `FulfillmentInbound_getDeliveryChallanDocument` | Provide delivery challan document for PCP transportation in IN marketplace. | | read | `FulfillmentInbound_listDeliveryWindowOptions` | Retrieves all delivery window options for a shipment. | | write | `FulfillmentInbound_generateDeliveryWindowOptions` | Generates available delivery window options for a given shipment. | | write | `FulfillmentInbound_confirmDeliveryWindowOptions` | Confirms the delivery window option for chosen shipment within an inbound plan. | | read | `FulfillmentInbound_listShipmentItems` | Provides a paginated list of item packages in a shipment. | | write | `FulfillmentInbound_updateShipmentName` | Updates the name of an existing shipment. | | read | `FulfillmentInbound_listShipmentPallets` | Provides a paginated list of pallet packages in a shipment. | | write | `FulfillmentInbound_cancelSelfShipAppointment` | Cancels a self-ship appointment slot against a shipment. | | read | `FulfillmentInbound_getSelfShipAppointmentSlots` | Retrieves a list of available self-ship appointment slots used to drop off a shipment at a warehouse. | | write | `FulfillmentInbound_generateSelfShipAppointmentSlots` | Initiates the process of generating the appointment slots list. | | write | `FulfillmentInbound_scheduleSelfShipAppointment` | Confirms or reschedules a self-ship appointment slot against a shipment. | | write | `FulfillmentInbound_updateShipmentSourceAddress` | Updates the source address of an existing shipment. | | write | `FulfillmentInbound_updateShipmentTrackingDetails` | Updates a shipment's tracking details. | | read | `FulfillmentInbound_listTransportationOptions` | Retrieves all transportation options for a shipment. | | write | `FulfillmentInbound_generateTransportationOptions` | Generates available transportation options for a given placement option. | | write | `FulfillmentInbound_confirmTransportationOptions` | Confirms all the transportation options for an inbound plan. | | read | `FulfillmentInbound_listItemComplianceDetails` | List the inbound compliance details for MSKUs in a given marketplace. | | write | `FulfillmentInbound_updateItemComplianceDetails` | Update compliance details for a list of MSKUs. | | write | `FulfillmentInbound_createMarketplaceItemLabels` | For a given marketplace - creates labels for a list of MSKUs. | | read | `FulfillmentInbound_listPrepDetails` | Get preparation details for a list of MSKUs in a specified marketplace.\n\nNote: MSKUs that contain certain characters must be encoded. | | write | `FulfillmentInbound_setPrepDetails` | Set the preparation details for a list of MSKUs in a specified marketplace. | | read | `FulfillmentInbound_getInboundOperationStatus` | Gets the status of the processing of an asynchronous API call. | ### FulfillmentInboundV0 | Access | Tool | Description | | --- | --- | --- | | read | `FulfillmentInboundV0_getPrepInstructions` | Returns labeling requirements and item preparation instructions to help prepare items for shipment to Amazon's fulfillment network. | | read | `FulfillmentInboundV0_getShipmentItems` | Returns a list of items in a specified inbound shipment, or a list of items that were updated within a specified time frame. | | read | `FulfillmentInboundV0_getShipments` | Returns a list of inbound shipments based on criteria that you specify. | | read | `FulfillmentInboundV0_getBillOfLading` | Returns a bill of lading for a Less Than Truckload/Full Truckload (LTL/FTL) shipment. | | read | `FulfillmentInboundV0_getShipmentItemsByShipmentId` | Returns a list of items in a specified inbound shipment. | | read | `FulfillmentInboundV0_getLabels` | Returns package/pallet labels for faster and more accurate shipment processing at the Amazon fulfillment center. | ### FulfillmentOutbound | Access | Tool | Description | | --- | --- | --- | | write | `FulfillmentOutbound_deliveryOffers` | Returns delivery options that include an estimated delivery date and offer expiration, based on criteria that you specify. | | read | `FulfillmentOutbound_getFeatures` | Returns a list of features available for Multi-Channel Fulfillment orders in the marketplace you specify, and whether the seller for which you made the call is enrolled for each feature. | | read | `FulfillmentOutbound_getFeatureInventory` | Returns a list of inventory items that are eligible for the fulfillment feature you specify. | | read | `FulfillmentOutbound_getFeatureSKU` | Returns the number of items with the sellerSku you specify that can have orders fulfilled using the specified feature. | | read | `FulfillmentOutbound_listAllFulfillmentOrders` | Returns a list of fulfillment orders fulfilled after (or at) a specified date-time, or indicated by the nextToken parameter. | | write | `FulfillmentOutbound_createFulfillmentOrder` | Requests that Amazon ship items from the seller's inventory in Amazon's fulfillment network to a destination address. | | read | `FulfillmentOutbound_getFulfillmentPreview` | Returns a list of fulfillment order previews based on shipping criteria that you specify. | | read | `FulfillmentOutbound_getFulfillmentOrder` | Returns the fulfillment order indicated by the specified order identifier. | | write | `FulfillmentOutbound_updateFulfillmentOrder` | Updates and/or requests shipment for a fulfillment order with an order hold on it. | | write | `FulfillmentOutbound_cancelFulfillmentOrder` | Requests that Amazon stop attempting to fulfill the fulfillment order indicated by the specified order identifier. | | write | `FulfillmentOutbound_createFulfillmentReturn` | Creates a fulfillment return. | | write | `FulfillmentOutbound_submitFulfillmentOrderStatusUpdate` | Requests that Amazon update the status of an order in the sandbox testing environment. | | read | `FulfillmentOutbound_listReturnReasonCodes` | Returns a list of return reason codes for a seller SKU in a given marketplace. | | read | `FulfillmentOutbound_getPackageTrackingDetails` | Returns delivery tracking information for a package in an outbound shipment for a Multi-Channel Fulfillment order. | ### Invoices | Access | Tool | Description | | --- | --- | --- | | read | `Invoices_getInvoicesAttributes` | Returns marketplace-dependent schemas and their respective set of possible values. | | read | `Invoices_getInvoicesDocument` | Returns the invoice document's ID and URL. | | read | `Invoices_getInvoicesExports` | Returns invoice exports details for exports that match the filters that you specify. | | write | `Invoices_createInvoicesExport` | Creates an invoice export request. | | read | `Invoices_getInvoicesExport` | Returns invoice export details (including the exportDocumentId, if available) for the export that you specify. | | read | `Invoices_getGovernmentInvoiceStatus` | Returns the status of an invoice generation request. | | write | `Invoices_createGovernmentInvoice` | Submits an asynchronous government invoice creation request. | | read | `Invoices_getGovernmentInvoiceDocument` | Returns an invoiceDocument object containing an invoiceDocumentUrl . | | read | `Invoices_getInvoices` | Returns invoice details for the invoices that match the filters that you specify. | | read | `Invoices_getInvoice` | Returns invoice data for the specified invoice. | ### ListingsItems | Access | Tool | Description | | --- | --- | --- | | read | `ListingsItems_searchListingsItems` | Search for and return a list of selling partner listings items and their respective details. | | write | `ListingsItems_deleteListingsItem` | Delete a listings item for a selling partner. | | read | `ListingsItems_getListingsItem` | Returns details about a listings item for a selling partner. | | write | `ListingsItems_patchListingsItem` | Partially update (patch) a listings item for a selling partner. | | write | `ListingsItems_putListingsItem` | Creates a new or fully-updates an existing listings item for a selling partner. | ### ListingsItems20200901 | Access | Tool | Description | | --- | --- | --- | | write | `ListingsItems20200901_deleteListingsItem` | Delete a listings item for a selling partner. | | write | `ListingsItems20200901_patchListingsItem` | Partially update (patch) a listings item for a selling partner. | | write | `ListingsItems20200901_putListingsItem` | Creates a new or fully-updates an existing listings item for a selling partner. | ### ListingsRestrictions | Access | Tool | Description | | --- | --- | --- | | read | `ListingsRestrictions_getListingsRestrictions` | Returns listing restrictions for an item in the Amazon Catalog. | ### MerchantFulfillment | Access | Tool | Description | | --- | --- | --- | | read | `MerchantFulfillment_getAdditionalSellerInputs` | Gets a list of additional seller inputs required for a ship method. | | read | `MerchantFulfillment_getEligibleShipmentServices` | Returns a list of shipping service offers that satisfy the specified shipment request details. | | write | `MerchantFulfillment_createShipment` | Create a shipment with the information provided. | | write | `MerchantFulfillment_cancelShipment` | Cancel the shipment indicated by the specified shipment identifier. | | read | `MerchantFulfillment_getShipment` | Returns the shipment information for an existing shipment. | ### Messaging | Access | Tool | Description | | --- | --- | --- | | read | `Messaging_getMessagingActionsForOrder` | Returns a list of message types that are available for an order that you specify. | | read | `Messaging_GetAttributes` | Returns a response containing attributes related to an order. | | write | `Messaging_CreateAmazonMotors` | Sends a message to a buyer to provide details about an Amazon Motors order. | | write | `Messaging_confirmCustomizationDetails` | Sends a message asking a buyer to provide or verify customization details such as name spelling, images, initials, etc. | | write | `Messaging_createConfirmDeliveryDetails` | Sends a message to a buyer to arrange a delivery or to confirm contact information for making a delivery. | | write | `Messaging_createConfirmOrderDetails` | Sends a message to ask a buyer an order-related question prior to shipping their order. | | write | `Messaging_createConfirmServiceDetails` | Sends a message to contact a Home Service customer to arrange a service call or to gather information prior to a service call. | | write | `Messaging_createDigitalAccessKey` | Sends a buyer a message to share a digital access key that is required to utilize digital content in their order. | | write | `Messaging_sendInvoice` | Sends a message providing the buyer an invoice | | write | `Messaging_createLegalDisclosure` | Sends a critical message that contains documents that a seller is legally obligated to provide to the buyer. | | write | `Messaging_createUnexpectedProblem` | Sends a critical message to a buyer that an unexpected problem was encountered affecting the completion of the order. | | write | `Messaging_CreateWarranty` | Sends a message to a buyer to provide details about warranty information on a purchase in their order. | ### Notifications | Access | Tool | Description | | --- | --- | --- | | read | `Notifications_getDestinations` | Returns information about all destinations. | | write | `Notifications_createDestination` | Creates a destination resource to receive notifications. | | write | `Notifications_deleteDestination` | Deletes the destination that you specify. | | read | `Notifications_getDestination` | Returns information about the destination that you specify. | | read | `Notifications_getSubscription` | Returns information about subscription of the specified notification type and payload version. | | write | `Notifications_createSubscription` | Creates a subscription for the specified notification type to be delivered to the specified destination. | | write | `Notifications_deleteSubscriptionById` | Deletes the subscription indicated by the subscription identifier and notification type that you specify. | | read | `Notifications_getSubscriptionById` | Returns information about a subscription for the specified notification type. | ### Orders | Access | Tool | Description | | --- | --- | --- | | read | `Orders_getOrders` | Returns orders that are created or updated during the specified time period. | | read | `Orders_getOrder` | Returns the order that you specify. | | read | `Orders_getOrderAddress` | Returns the shipping address for the order that you specify. | | read | `Orders_getOrderBuyerInfo` | Returns buyer information for the order that you specify. | | read | `Orders_getOrderItems` | Returns detailed order item information for the order that you specify. | | read | `Orders_getOrderItemsBuyerInfo` | Returns buyer information for the order items in the order that you specify. | | read | `Orders_getOrderRegulatedInfo` | Returns regulated information for the order that you specify. | | write | `Orders_updateVerificationStatus` | Updates (approves or rejects) the verification status of an order containing regulated products. | | write | `Orders_updateShipmentStatus` | Update the shipment status for an order that you specify. | | write | `Orders_confirmShipment` | Updates the shipment confirmation status for a specified order. | ### Ordersv2 | Access | Tool | Description | | --- | --- | --- | | read | `Ordersv2_searchOrders` | Returns orders that are created or updated during the time period that you specify. | | read | `Ordersv2_getOrder` | Returns the order that you specify. | ### ProductPricing | Access | Tool | Description | | --- | --- | --- | | read | `ProductPricing_getItemOffersBatch` | Returns the lowest priced offers for a batch of items based on ASIN. | | read | `ProductPricing_getListingOffersBatch` | Returns the lowest priced offers for a batch of listings by SKU. | | read | `ProductPricing_getCompetitivePricing` | Returns competitive pricing information for a seller's offer listings based on seller SKU or ASIN. | | read | `ProductPricing_getItemOffers` | Returns the lowest priced offers for a single item based on ASIN. | | read | `ProductPricing_getListingOffers` | Returns the lowest priced offers for a single SKU listing. | | read | `ProductPricing_getPricing` | Returns pricing information for a seller's offer listings based on seller SKU or ASIN. | ### ProductPricing20220501 | Access | Tool | Description | | --- | --- | --- | | read | `ProductPricing20220501_getCompetitiveSummary` | Returns the competitive summary response, including featured buying options for the ASIN and marketplaceId combination. | | read | `ProductPricing20220501_getFeaturedOfferExpectedPriceBatch` | Returns the set of responses that correspond to the batched list of up to 40 requests defined in the request body. | ### ProductType | Access | Tool | Description | | --- | --- | --- | | read | `ProductType_searchDefinitionsProductTypes` | Search for and return a list of Amazon product types that have definitions available. | | read | `ProductType_getDefinitionsProductType` | Retrieve an Amazon product type definition. | ### Replenishment | Access | Tool | Description | | --- | --- | --- | | read | `Replenishment_listOfferMetrics` | Returns aggregated replenishment program metrics for a selling partner's offers. | | read | `Replenishment_listOffers` | Returns the details of a selling partner's replenishment program offers. | | read | `Replenishment_getSellingPartnerMetrics` | Returns aggregated replenishment program metrics for a selling partner. | ### Replenishment20221107 | Access | Tool | Description | | --- | --- | --- | | read | `Replenishment20221107_listOfferMetrics` | Returns aggregated replenishment program metrics for a selling partner's offers. | | read | `Replenishment20221107_listOffers` | Returns the details of a selling partner's replenishment program offers. | | read | `Replenishment20221107_getSellingPartnerMetrics` | Returns aggregated replenishment program metrics for a selling partner. | ### Reports | Access | Tool | Description | | --- | --- | --- | | read | `Reports_getReportDocument` | Returns the information required for retrieving a report document's contents. | | read | `Reports_getReports` | Returns report details for the reports that match the filters that you specify. | | write | `Reports_createReport` | Creates a report. | | write | `Reports_cancelReport` | Cancels the report that you specify. | | read | `Reports_getReport` | Returns report details (including the reportDocumentId, if available) for the report that you specify. | | read | `Reports_getReportSchedules` | Returns report schedule details that match the filters that you specify. | | write | `Reports_createReportSchedule` | Creates a report schedule. | | write | `Reports_cancelReportSchedule` | Cancels the report schedule that you specify. | | read | `Reports_getReportSchedule` | Returns report schedule details for the report schedule that you specify. | ### Sales | Access | Tool | Description | | --- | --- | --- | | read | `Sales_getOrderMetrics` | Returns aggregated order metrics for given interval, broken down by granularity, for given buyer type. | ### Sellers | Access | Tool | Description | | --- | --- | --- | | read | `Sellers_getAccount` | Returns information about a seller account and its marketplaces. | | read | `Sellers_getMarketplaceParticipations` | Returns a list of marketplaces where the seller can list items and information about the seller's participation in those marketplaces. | ### SellerWallet | Access | Tool | Description | | --- | --- | --- | | read | `SellerWallet_listAccounts` | Get Seller Wallet accounts for a seller. | | read | `SellerWallet_getAccount` | Retrieve a Seller Wallet bank account by Amazon account identifier. | | read | `SellerWallet_listAccountBalances` | Retrieve the balance in a given Seller Wallet bank account. | | read | `SellerWallet_listAccountTransactions` | Retrieve a list of transactions for a given Seller Wallet bank account. | | write | `SellerWallet_createTransaction` | Create a transaction request from a Seller Wallet account to another customer-provided account. | | read | `SellerWallet_getTransaction` | Find a transaction by the Amazon transaction identifier. | | read | `SellerWallet_getTransferPreview` | Retrieve a list of potential fees on a transaction. | | read | `SellerWallet_listTransferSchedules` | Retrieve transfer schedules of a Seller Wallet bank account. | | write | `SellerWallet_createTransferSchedule` | Create a transfer schedule request from a Seller Wallet account to another customer-provided account. | | write | `SellerWallet_updateTransferSchedule` | Update transfer schedule information. | | write | `SellerWallet_deleteScheduleTransaction` | Delete a transaction request that is scheduled from Amazon Seller Wallet account to another customer-provided account. | | read | `SellerWallet_getTransferSchedule` | Find a particular Amazon Seller Wallet account transfer schedule. | ### Services | Access | Tool | Description | | --- | --- | --- | | read | `Services_getAppointmentSlots` | Gets appointment slots as per the service context specified. | | write | `Services_createServiceDocumentUploadDestination` | Creates an upload destination. | | write | `Services_createReservation` | Create a reservation. | | write | `Services_cancelReservation` | Cancel a reservation. | | write | `Services_updateReservation` | Update a reservation. | | read | `Services_getServiceJobs` | Gets service job details for the specified filter query. | | read | `Services_getServiceJobByServiceJobId` | Gets details of service job indicated by the provided serviceJobID. | | read | `Services_getAppointmmentSlotsByJobId` | Gets appointment slots for the service associated with the service job id specified. | | write | `Services_addAppointmentForServiceJobByServiceJobId` | Adds an appointment to the service job indicated by the service job identifier specified. | | write | `Services_rescheduleAppointmentForServiceJobByServiceJobId` | Reschedules an appointment for the service job indicated by the service job identifier specified. | | write | `Services_setAppointmentFulfillmentData` | Updates the appointment fulfillment data related to a given jobID and appointmentID. | | write | `Services_assignAppointmentResources` | Assigns new resource(s) or overwrite/update the existing one(s) to a service job appointment. | | write | `Services_cancelServiceJobByServiceJobId` | Cancels the service job indicated by the service job identifier specified. | | write | `Services_completeServiceJobByServiceJobId` | Completes the service job indicated by the service job identifier specified. | | read | `Services_getFixedSlotCapacity` | Provides capacity in fixed-size slots. | | read | `Services_getRangeSlotCapacity` | Provides capacity slots in a format similar to availability records. | | write | `Services_updateSchedule` | Update the schedule of the given resource. | ### ShipmentInvoicing | Access | Tool | Description | | --- | --- | --- | | read | `ShipmentInvoicing_getShipmentDetails` | Returns the shipment details required to issue an invoice for the specified shipment. | | write | `ShipmentInvoicing_submitInvoice` | Submits a shipment invoice document for a given shipment. | | read | `ShipmentInvoicing_getInvoiceStatus` | Returns the invoice status for the shipment you specify. | ### Shipping | Access | Tool | Description | | --- | --- | --- | | read | `Shipping_getAccessPoints` | Returns a list of access points in proximity of input postal code. | | read | `Shipping_getCarrierAccountFormInputs` | This API will return a list of input schema required to register a shipper account with the carrier. | | read | `Shipping_getCarrierAccounts` | This API will return Get all carrier accounts for a merchant. | | write | `Shipping_linkCarrierAccount` | This API associates/links the specified carrier account with the merchant. | | write | `Shipping_linkCarrierAccount` | This API associates/links the specified carrier account with the merchant. | | write | `Shipping_unlinkCarrierAccount` | This API Unlink the specified carrier account with the merchant. | | write | `Shipping_createClaim` | This API will be used to create claim for single eligible shipment. | | write | `Shipping_generateCollectionForm` | This API Call to generate the collection form. | | read | `Shipping_getCollectionFormHistory` | This API Call to get the history of the previously generated collection forms. | | read | `Shipping_getCollectionForm` | This API reprint a collection form. | | write | `Shipping_submitNdrFeedback` | This API submits the NDR (Non-delivery Report) Feedback for any eligible shipment. | | write | `Shipping_oneClickShipment` | Purchases a shipping service identifier and returns purchase-related details and documents. | | write | `Shipping_purchaseShipment` | Purchases a shipping service and returns purchase related details and documents. | | read | `Shipping_getAdditionalInputs` | Returns the JSON schema to use for providing additional inputs when needed to purchase a shipping offering. | | write | `Shipping_directPurchaseShipment` | Purchases the shipping service for a shipment using the best fit service offering. | | read | `Shipping_getRates` | Returns the available shipping service offerings. | | write | `Shipping_cancelShipment` | Cancels a purchased shipment. | | read | `Shipping_getShipmentDocuments` | Returns the shipping documents associated with a package in a shipment. | | read | `Shipping_getTracking` | Returns tracking information for a purchased shipment. | | read | `Shipping_getUnmanifestedShipments` | This API Get all unmanifested carriers with shipment locations. | ### ShippingLegacy | Access | Tool | Description | | --- | --- | --- | | read | `ShippingLegacy_getAccount` | Verify if the current account is valid. | | write | `ShippingLegacy_purchaseShipment` | Purchase shipping labels. | | read | `ShippingLegacy_getRates` | Get service rates. | | write | `ShippingLegacy_createShipment` | Create a new shipment. | | read | `ShippingLegacy_getShipment` | Return the entire shipment object for the shipmentId. | | write | `ShippingLegacy_cancelShipment` | Cancel a shipment by the given shipmentId. | | write | `ShippingLegacy_retrieveShippingLabel` | Retrieve shipping label based on the shipment id and tracking id. | | write | `ShippingLegacy_purchaseLabels` | Purchase shipping labels based on a given rate. | | read | `ShippingLegacy_getTrackingInformation` | Return the tracking information of a shipment. | ### Solicitations | Access | Tool | Description | | --- | --- | --- | | read | `Solicitations_getSolicitationActionsForOrder` | Returns a list of solicitation types that are available for an order that you specify. | | write | `Solicitations_createProductReviewAndSellerFeedbackSolicitation` | Sends a solicitation to a buyer asking for seller feedback and a product review for the specified order. | ### SupplySources | Access | Tool | Description | | --- | --- | --- | | read | `SupplySources_getSupplySources` | The path to retrieve paginated supply sources. | | write | `SupplySources_createSupplySource` | Create a new supply source. | | write | `SupplySources_archiveSupplySource` | Archive a supply source, making it inactive. | | read | `SupplySources_getSupplySource` | Retrieve a supply source. | | write | `SupplySources_updateSupplySource` | Update the configuration and capabilities of a supply source. | | write | `SupplySources_updateSupplySourceStatus` | Update the status of a supply source. | ### Tokens | Access | Tool | Description | | --- | --- | --- | | write | `Tokens_createRestrictedDataToken` | Returns a Restricted Data Token (RDT) for one or more restricted resources that you specify. | ### Transfers | Access | Tool | Description | | --- | --- | --- | | read | `Transfers_getPaymentMethods` | Returns the list of payment methods for the seller, which can be filtered by method type. | | write | `Transfers_initiatePayout` | Initiates an on-demand payout to the seller's default deposit method in Seller Central for the given marketplaceId and accountType, if eligible. | ### Uploads | Access | Tool | Description | | --- | --- | --- | | write | `Uploads_createUploadDestinationForResource` | Creates an upload destination, returning the information required to upload a file to the destination and to programmatically access the file. | ### Vehicles | Access | Tool | Description | | --- | --- | --- | | read | `Vehicles_getVehicles` | Get the latest collection of vehicles | ### Amazon Agent Flow Documentation URL: https://www.kuudo.com/docs/amazon-agent-flow/ Amazon Agent Flow is Kuudo's AI-native data layer for Amazon operators. It uses proven data-lake patterns - durable ingestion, artifacts, Iceberg tables, scan-budgeted queries, scheduled refreshes, and lineage - but it is designed around agents as the primary users, not dashboards. Traditional analytics tools can still read the lake. Snowflake, Athena, DuckDB, Databricks, Power BI, Tableau, and similar tools can be useful downstream consumers. They are not the center of the system. The center is an agent that needs fresh, governed, account-specific data it can retrieve, reason over, and act on without copying private business data into chat. Use this page when you want to know what to ask, what must be connected first, which tools are involved, and how to tell whether a run actually finished. ## The Bigger Picture Agent Flow is not only a job runner or report exporter. It is the agent-facing data layer between Amazon systems, private lake storage, governed query tools, and the AI clients that need to do work. The foundation is familiar data-lake architecture: - Amazon SP-API (Selling Partner API) and Ads operations ingest source data. - Large outputs land as artifacts instead of chat messages. - Eligible outputs are delivered into open lake tables. - Queries run with filters, result limits, and scan budgets. - Run ids, artifacts, schedules, and delivery records preserve lineage. The product difference is the primary user. A traditional analytics stack usually assumes a human analyst will open Tableau, Power BI, or a warehouse console. Agent Flow assumes an agent will discover operations, inspect contracts, launch durable runs, poll status, read bounded previews, pass result handles into analysis tools, and explain the next action. The practical result is lower interactive latency. Some Amazon reports, exports, and data pulls take minutes or hours to generate. Agent Flow moves that wait into scheduled background work. The agent can refresh orders, listings, inventory, finance, and Ads datasets on a window, land them in the local/private lake, and answer from data already local to the agent's data layer. The user waits for a bounded local query, not for Amazon to generate the report during the chat turn. The data is also available beyond the agent that created it. Because Agent Flow exposes an MCP-native interface, any authorized MCP-native client can schedule flows, inspect deliveries, query lake datasets, or run its own downstream data process against result handles. ChatGPT, Claude, Cursor, workflow tools, or internal agent clients can all work from the same governed agent lake instead of each one pulling from Amazon separately. | Traditional analytics layer | Agent Flow | | --- | --- | | Dashboards and published reports are the main interface. | Agent-accessible operations, artifacts, and bounded data tools are the main interface. | | Humans click through BI views. | Agents discover, run, poll, query, analyze, and summarize. | | Warehouses and BI tools are the center of consumption. | Result handles, compact previews, lake tables, and sandbox analysis are optimized for agent context. | | Data freshness is usually managed around reporting cadence. | Data freshness is managed around agent tasks, schedules, retries, and operational questions. | | The BI user is the principal consumer. | The AI agent is the principal consumer, with BI tools still available downstream. | ## Two Parts: Pipelines and Queries Agent Flow has two connected surfaces. The first creates the data layer. The second lets agents use it. | Surface | What agents do | Typical tools | | --- | --- | --- | | Amazon-to-agent-lake pipelines | Discover Amazon SP-API or Ads operations, inspect schemas, run or schedule durable jobs, persist artifacts, and deliver eligible outputs into the agent lake. | `list_amazon_sp_operations`, `list_amazon_ads_operations`, `run_amazon_sp_operation`, `run_amazon_ads_operation`, `upsert_schedule`, `list_lake_deliveries` | | Agent data consumption | Query delivered datasets, read bounded previews, pass result handles into analysis, and build downstream actions from local governed data. | `query_lake_dataset`, `query_lake_sql`, `read_analysis_result`, `run_sandbox_python`, `run_curated_analysis` | Those surfaces can be used by the same agent or by different authorized clients. One MCP-native client might schedule the daily Amazon reports, another might query the lake for an ads diagnosis, and a third might run a sandboxed analysis over the latest result handle. The shared contract is the Agent Flow MCP surface and the governed lake underneath it. ## What Agent Flow Does Agent Flow turns Amazon work and Amazon data into a layer agents can use repeatedly. The named operations create or refresh the data, schedules keep slow Amazon outputs warm, the lake keeps it cost-effective and scalable, and the query and analysis tools expose only the slices an agent needs for the next decision. Instead of asking an assistant to improvise against Amazon APIs, you ask it to build or use the data layer: 1. Find the right operation. 2. Inspect the operation's required input. 3. Bind the run to a registered Amazon account. 4. Start the durable run. 5. Schedule it if the data should be warm before an agent needs it. 6. Watch status until it completes or needs attention. 7. Deliver or read the result, artifact, or lake table. The runtime is built for work that may take longer than a single chat turn: paginated order pulls, asynchronous Amazon reports, scheduled jobs, report downloads, retries after throttling, and data delivery into Iceberg tables. ## When to Use It Use Agent Flow for Amazon workflows that need durability, auditability, or repeatable data delivery. | Goal | Use Agent Flow? | Why | | --- | --- | --- | | Pull orders, listings, inventory, or finance data | Yes | SP-API calls can paginate, throttle, and produce large artifacts. | | Create and retrieve Amazon Ads reports | Yes | Ads reports are asynchronous and need create, poll, download, and retry handling. | | Schedule recurring Amazon data refreshes | Yes | Schedules launch durable operation runs on a window. | | Query already-delivered Amazon data | Yes | Lake tools expose structured, budgeted reads instead of raw database access. | | Give an agent fresh data for a decision | Yes | Agent Flow returns bounded previews, lineage, and result handles instead of dashboard-only output. | | Reduce latency for slow Amazon reports | Yes | Scheduled flows move report generation into the background so the agent answers from local lake data. | | Share governed Amazon data across AI clients | Yes | Any authorized MCP-native client can consume the same delivered datasets or schedule its own refreshes. | | Feed Tableau, Power BI, or a warehouse | Optional | These tools can consume the lake, but they are downstream of the agent-native flow. | | Rewrite a listing title or analyze a one-off screenshot | Usually no | Use the relevant Skill, Agent Iris, or Atlas unless an operation must run. | | Ask a general Amazon policy question | Usually no | Use [Amazon Agent Atlas](/docs/amazon-agent-atlas/) for grounded operating knowledge. | If your first consumer is a dashboard, the lake can still be useful. If your first consumer is an agent that needs to do work, Agent Flow is the primary interface. ## What You Need First Agent Flow needs at least one connected Amazon capability. The exact requirement depends on the operation. | Operation type | Required connection | Typical account fields | | --- | --- | --- | | Amazon Selling Partner operations | [Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/) | `account_ref`, `identity_id`, `marketplace_id`, credential | | Amazon Ads operations | [Amazon Ads MCP](/features/amazon-ads-mcp/) | `account_ref`, `profile_id`, `region`, credential | | Lake delivery or lake queries | Agent Flow app database plus a lake destination | `destination_id`, dataset, scan budget | | Scheduled operations | Operation, account, app database, and schedule worker | `schedule_name`, cron, window size | For Kuudo Cloud, Kuudo helps provision the runtime and connector MCP servers in your cloud. For self-hosted deployments, the Agent Flow server expects external MCP servers for Amazon SP and Ads. The source runtime uses these default local MCP targets: | Connector | Default local MCP URL | Token environment variable | | --- | --- | --- | | Amazon Selling Partner MCP | `http://localhost:8013/mcp` | `AMAZON_SP_OPENBRIDGE_REFRESH_TOKEN` | | Amazon Ads MCP | `http://localhost:9080/mcp` | `AMAZON_ADS_OPENBRIDGE_REFRESH_TOKEN` | Those connectors still require the underlying Amazon permissions, profiles, marketplaces, and API access. Agent Flow does not create Amazon approvals or bypass Amazon limits. ## How Activation Works Activation means giving Agent Flow enough context to run one durable operation against one registered account. ### 1. Connect the Agent Flow MCP server In Kuudo Cloud, your AI client connects to the Agent Flow MCP endpoint Kuudo provides. For self-hosted local work, start the server from the Agent Flow repo: ```bash uv run agent-flow ``` Then connect your MCP client to that server. If you are using the REST control plane instead of MCP tools, the same concepts are available through `/v1/*` endpoints. ### 2. Register an Amazon account Each run uses an `account_ref`. The account stores the Amazon identity fields that should not be retyped into every prompt. For an SP-API account, the important fields are usually: - `connector_id`: `amazon_sp` - `account_ref`: your stable name, such as `seller-us-main` - `identity_id`: the Openbridge or connector identity id - `marketplace_id`: the Amazon marketplace id, such as `ATVPDKIKX0DER` For an Ads account, the important fields are usually: - `connector_id`: `amazon_ads` - `account_ref`: your stable name, such as `ads-brand-us` - `profile_id`: the Amazon Ads profile id - `region`: the Ads region, such as `na` **Prompt** > Register `seller-us-main` as an Amazon SP account for marketplace `ATVPDKIKX0DER` using identity id `3438`. Then show me the account record and confirm which fields will be bound automatically on future runs. **MCP tools the assistant may use** - `upsert_account` - `get_account` - `list_accounts` If the credential store is enabled, the assistant may also use `create_account_credential`. Credentials are accepted as plaintext input to the tool and stored encrypted at rest; the tool returns redacted metadata, not the secret. ### 3. Find the operation Operations are the stable units of work Agent Flow can run. They are grouped by connector, resource, lifecycle, and risk. Useful filters: - `resource`: examples include `orders`, `reports`, `campaigns` - `lifecycle`: `transactional_query`, `paginated_query`, `async_report`, `mutation` - `risk_level`: `read`, `export`, `mutation`, `financial` **Prompt** > I need orders data for `seller-us-main`. Before you run anything, show me the safe options Agent Flow can use. **MCP tools the assistant may use** - `list_amazon_sp_operations` - `list_amazon_ads_operations` ### 4. Inspect the operation schema Before running an operation, inspect its input schema. Some fields are account-bound and should come from `account_ref`; other fields must be supplied in the run payload. **Prompt** > For the orders option you recommend, tell me what information you need from me and what will be filled in from `seller-us-main`. **MCP tools the assistant may use** - `get_amazon_sp_operation` - `get_amazon_ads_operation` ### 5. Start the run For normal use, start the asynchronous durable run and poll it. Use sync tools only for short smoke tests or local demos. **Prompt** > Show me orders from the last 24 hours for my `seller-us-main` seller account. Use Agent Flow if the data needs to be refreshed. The assistant should translate that plain request into a durable run, return the `run_id` when available, and poll until the run completes or needs attention. **MCP tools the assistant may use** - `run_amazon_sp_operation` - `run_amazon_ads_operation` - `get_flow_run` The REST equivalent is: ```bash curl -X POST http://127.0.0.1:8080/v1/operation-runs \ -H 'X-Agent-Flow-Tenant: tenant-a' \ -H 'content-type: application/json' \ -d '{ "connector_id": "amazon_sp", "operation_id": "", "account_ref": "seller-us-main", "payload": {} }' ``` Then fetch status: ```bash curl http://127.0.0.1:8080/v1/operation-runs/ \ -H 'X-Agent-Flow-Tenant: tenant-a' ``` ## Operation Mechanics Agent Flow operations are not generic prompts. Each operation has a contract. | Field | What it tells the agent | | --- | --- | | `operation_id` | Stable name to run. | | `connector_id` | `amazon_sp` or `amazon_ads`. | | `resource` | Business area such as orders, reports, campaigns, or listings. | | `lifecycle` | How the operation runs: query, paginated query, async report, or mutation. | | `risk_level` | Whether the operation is read-only, export-like, financial, or a mutation. | | `input_model` | Pydantic input contract. | | `output_model` | Result shape returned when the run completes. | | `account_bound_fields` | Fields Agent Flow fills from the registered account. | | `artifact_policy` | Whether large output is persisted as a flow artifact. | | `landing_artifact_policy` | Whether output can land as a lake dataset. | ### Lifecycles | Lifecycle | What happens | | --- | --- | | `transactional_query` | One bounded connector call returns a structured result. | | `paginated_query` | Agent Flow walks pages, writes a larger artifact, and returns a summary. | | `async_report` | Agent Flow creates a report, polls status, downloads the document, and records artifacts. | | `mutation` | Agent Flow performs a change through a connector operation. Use only when your workspace has approved that operation and policy. | ### Durability Agent Flow uses DBOS-backed workflows for operation execution. That means a run can be inspected by `run_id`, resumed after runtime recovery, retried where allowed, and audited through its recorded state. For Amazon reports, equivalent active report requests attach to the same scheduler job instead of creating duplicate Amazon reports. The scheduler owns create, poll, terminal status, and download state. ### Artifacts Large outputs are written as artifacts instead of being pasted into chat. A typical artifact path includes: ```text {artifact_root}/{source}/{flow_id}/{run_id}/{step_name}/{artifact_kind}/{filename} ``` For example, an SP orders run can write raw orders under an `amazon_sp` flow path, while a listings report can write the downloaded Amazon report document as a raw report artifact. ### Lake delivery Lake delivery is the cost and scale layer behind the agent experience. Operations can write local lake-shaped artifacts first, then optionally deliver them to an Iceberg destination. The zero-config floor uses `iceberg_local`. Production deployments can use destinations such as Cloudflare R2 or AWS Glue Iceberg when configured. Open table formats make the data usable by warehouses and BI tools, but the default access path is agent-native: result handles, bounded previews, scan budgets, lineage, and server-side analysis. This is also where Agent Flow changes latency. A scheduled report may still take Amazon minutes or hours to produce, but that wait happens before the agent needs the answer. Once delivered, the data is local to the agent's operating layer, so the next question can use a bounded lake query instead of starting a fresh Amazon report and waiting for it to finish. Client SQL addresses tables uniformly as: ```sql lake.. ``` Agents should query with scan budgets and bounded result sizes, not unbounded raw SQL. For larger analysis, they should keep intermediate data server-side with `read_analysis_result` and `run_sandbox_python` instead of copying raw tables into chat context. ## Tool Map These are the Agent Flow tools users most often need in chat. The tool surface covers both sides of the system: pipeline tools that create or schedule Amazon-to-lake data, and consumption tools that let agents query or process the delivered data. | Task | MCP tools | | --- | --- | | Discover SP operations | `list_amazon_sp_operations`, `get_amazon_sp_operation` | | Discover Ads operations | `list_amazon_ads_operations`, `get_amazon_ads_operation` | | Register accounts | `upsert_account`, `list_accounts`, `get_account`, `update_account`, `deactivate_account` | | Store credentials | `create_account_credential`, `rotate_account_credential`, `get_account_credential_status`, `revoke_account_credential` | | Run operations | `run_amazon_sp_operation`, `run_amazon_ads_operation` | | Local smoke runs | `run_amazon_sp_operation_sync`, `run_amazon_ads_operation_sync` | | Inspect run status | `get_flow_run`, `list_report_scheduler_jobs`, `get_report_scheduler_job` | | Retry or cancel | `retry_operation_run`, `cancel_report_scheduler_job` | | Register lake destinations | `list_lake_providers`, `create_lake_destination`, `list_lake_destinations` | | Track delivery | `list_lake_deliveries`, `get_lake_delivery` | | Query delivered data | `query_lake_dataset`, `query_lake_sql`, `read_analysis_result` | | Run bounded analysis | `run_sandbox_python`, `list_curated_analyses`, `run_curated_analysis` | | Create recurring work | `upsert_schedule`, `list_operation_schedules`, `trigger_operation_schedule` | Different deployments may expose a subset depending on enabled stores, credentials, lake providers, and admin policy. ## Example Prompts Use these as starting points in Claude, ChatGPT, Cursor, or another MCP-capable client connected to Agent Flow. The quoted prompts are written the way an end user can ask. The expected behavior explains the technical work the agent should perform behind the scenes. ### Discover the right SP-API operation > I need last week's Amazon orders for `seller-us-main`. Before you pull anything, tell me what information you need and what data source you will use. Expected behavior: - The assistant filters operations instead of dumping the entire catalog. - It calls `get_amazon_sp_operation` for the likely operation. - It tells you which fields are required and which fields are account-bound. - It waits before starting the run. ### Run a read-only order pull > Show me orders for `seller-us-main` from July 1 through July 7, 2026. Refresh from Amazon if needed and summarize where the data was saved. Expected behavior: - The assistant uses `run_amazon_sp_operation`, not a direct Amazon call. - It tracks the run with `get_flow_run`. - It can return the `run_id` for audit or troubleshooting. - It does not paste a large order payload into chat. - It summarizes artifact metadata and record counts when available. ### Create an Amazon Ads report > Pull Sponsored Products campaign daily performance for `ads-brand-us` from July 1 to July 7, 2026. Include spend, sales, clicks, impressions, and campaign id if available. Expected behavior: - The assistant uses `list_amazon_ads_operations` and `get_amazon_ads_operation`. - It starts `run_amazon_ads_operation`. - It understands that report operations can be asynchronous. - It may use `list_report_scheduler_jobs` when the run attaches to a scheduler job. ### Keep the run read-only > Diagnose campaign performance for `ads-brand-us`, but do not make any changes to campaigns, budgets, or account settings. Expected behavior: - The assistant filters operation discovery by risk. - It refuses or asks for explicit approval if a requested operation is a mutation. - It explains any limitation created by the read-only constraint. ### Register a recurring schedule > Schedule the Amazon SP listings report to pull from Amazon every day at 2 AM America/New_York for my `seller-us-main` seller account. Show me when the next refresh will run. Expected behavior: - The assistant inspects the relevant report operation first. - It creates or updates an operation schedule. - It can call the trigger tool after the schedule exists. - It returns the next due time and schedule name. ### Query delivered lake data > What were order counts by purchase date for `seller-us-main` over the last 7 days? Use the latest delivered orders data and keep the answer short. Expected behavior: - The assistant checks lake destinations and deliveries. - It uses `query_lake_dataset` or `query_lake_sql` with `max_scan_bytes`. - It returns a small table or result handle, not unbounded raw data. ### Check a record count > Show me the record count for the latest delivered `orders` data for `seller-us-main`. Expected behavior: - The assistant finds the latest delivered orders dataset for the account. - It runs a bounded count query against the lake, not a fresh Amazon pull unless the data is missing or stale. - It returns the count, dataset name, delivery timestamp, and any freshness caveat. ### Run a SQL query on delivered data > Run this SQL query on the latest delivered `orders` data: > > `select count(*) as order_count from orders where purchase_date >= date '2026-07-01'` Expected behavior: - The assistant maps the user's logical data name to the governed lake table. - It validates that the query is read-only before running it. - It applies a scan budget and bounded preview size. - It returns a small result, result handle, and lineage instead of dumping raw rows. ### Analyze a result in a sandbox > Which SKUs drove the most revenue for `seller-us-main` in the last 30 days? Use the latest orders data and keep any intermediate data out of chat. Expected behavior: - The assistant runs a governed query first. - It passes the result handle to `run_sandbox_python`. - It returns a bounded table and describes the lineage. ### Retry a failed read/report run > Some Amazon data refreshes failed after throttling. Retry the read-only ones and do not retry anything that changes Amazon data. Expected behavior: - The assistant lists operation runs or relevant scheduler jobs. - It retries only allowed read/report runs. - It does not retry mutation runs. - It includes the new run id and audit reason. ## Activation Checklist Before you ask Agent Flow to run production work, confirm: - The Agent Flow MCP server or REST API is reachable from your AI client. - The relevant connector is installed: Amazon SP MCP for SP-API work, Amazon Ads MCP for Ads work. - The connector has valid credentials and required Amazon permissions. - The account is registered with a stable `account_ref`. - The operation exists and is enabled. - The operation input schema has been inspected. - The operation risk level is acceptable for the task. - Large outputs have an artifact or lake plan. - Mutations and financial-risk operations are covered by your approval policy. ## Common Workflows ### Agent-native data refresh Start here when the agent needs fresh Amazon data before answering an operating question, especially when the underlying Amazon report or export is too slow for an interactive chat turn. **Prompt** > What changed since yesterday for `seller-us-main` and `ads-brand-us`? Refresh the Amazon data if needed, then tell me which datasets are ready to query. Use: - Amazon Selling Partner MCP - Amazon Ads MCP - relevant SP and Ads operations - artifact storage - lake delivery - `query_lake_dataset` or `query_lake_sql` ### Scheduled low-latency agent data Start here when the agent repeatedly needs the same Amazon data and should not wait for Amazon report generation during each conversation. **Prompt** > Schedule the orders, listings, and Ads performance reports to pull from Amazon every day at 2 AM America/New_York for my `seller-us-main` seller account and `ads-brand-us` Ads account. Keep the latest data ready in the agent lake. Use: - Amazon Selling Partner MCP - Amazon Ads MCP - `upsert_schedule` - report or paginated operations - artifact storage - lake delivery - `list_lake_deliveries` ### Orders and sales operations Start here when the task depends on Seller Central orders or selling activity. **Prompt** > Show me orders for `seller-us-main` from the last 48 hours. Refresh from Amazon if needed and summarize order count, earliest purchase date, and latest purchase date. Use: - Amazon Selling Partner MCP - `list_amazon_sp_operations` - `get_amazon_sp_operation` - `run_amazon_sp_operation` - `get_flow_run` ### Listings report Start here when you need listing state as a report, not a one-off catalog lookup. **Prompt** > Get the current merchant listings report for `seller-us-main`. Tell me when it is ready and where the report data was saved. Use: - Amazon Selling Partner MCP - SP reports operation - report scheduler - artifact storage ### Sponsored Products reporting Start here when you need Ads performance over a date range. **Prompt** > Get Sponsored Products campaign daily performance for `ads-brand-us` from July 1 to July 7, 2026. Include spend, sales, clicks, impressions, and campaign id if available. Use: - Amazon Ads MCP - Ads reporting operation - async report scheduler - artifact storage or lake delivery ### Data-lake query Start here after data has been delivered to an Iceberg destination. **Prompt** > Show daily order count and estimated revenue after July 1, 2026 from the latest delivered `orders` data. Keep the answer short. **SQL prompt** > Run this SQL query on the latest delivered `orders` data for `seller-us-main`: > > `select count(*) as order_count from orders` Use: - `list_lake_destinations` - `list_lake_deliveries` - `query_lake_sql` or `query_lake_dataset` - `read_analysis_result` when the result is larger than the preview ## What Good Output Looks Like A good Agent Flow answer includes: - The operation id it chose. - The connector and account ref. - The risk level and lifecycle. - The payload it submitted, with secrets omitted. - The run id. - Current status or terminal status. - The data source it used: operation output, artifact, lake table, or analysis result. - Artifact or lake delivery details when applicable. - A bounded preview or result handle instead of a raw data dump. - Scan budget, filters, and row limits when it queried the lake. - Any Amazon throttling, pending report, missing permission, or retry state. - The next action you should take. It should not: - Call a mutation when you asked for read-only work. - Paste secrets into the response. - Dump hundreds of operation summaries into chat. - Claim a report is complete without checking the run or scheduler status. - Query a lake without a scan budget. - Treat an Amazon API failure as a finished business answer. ## Troubleshooting | Symptom | What to ask | | --- | --- | | "Unknown account" | "List accounts for this tenant and confirm the exact `account_ref`." | | "Unknown operation" | "List operations filtered by connector, resource, and lifecycle before choosing." | | Input validation failed | "Inspect the operation schema and show required fields plus account-bound fields." | | Report stays pending | "Check the flow run and report scheduler job, including `next_poll_after` and terminal status." | | Duplicate report concern | "Check whether this request attached to an existing scheduler job." | | Lake query says dataset not found | "List deliveries for this run and destination, then confirm the dataset name." | | Query budget exceeded | "Narrow the date range, add filters, or increase `max_scan_bytes` if approved." | | Credential error | "Check credential status for the account; do not print the credential." | | Mutation risk | "Show the operation risk level and stop unless the workspace approval policy allows it." | ## Related Material - [Amazon Agent Flow feature page](/features/amazon-agent-flow/) explains the product surface and private lake model. - [Kuudo MCP Servers](/docs/mcp-reference/tools/) maps the broader Kuudo MCP tool model. - [Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/) covers the SP-API connector. - [Amazon Ads MCP](/features/amazon-ads-mcp/) covers the Ads connector. - [Amazon Agent Atlas](/docs/amazon-agent-atlas/) covers grounded Amazon operating knowledge for tasks that need policy, table, or playbook context. ### Amazon Marketing Cloud Workflows URL: https://www.kuudo.com/docs/guides/amazon-marketing-cloud/ Amazon Marketing Cloud work is usually multi-step: gather context, write or select a query, validate privacy thresholds, interpret results, and decide whether to activate an audience. Kuudo turns those steps into reusable skills. ## What the agent can run - Deep campaign findings. - Customer journey illustration. - Media mix and incrementality analysis. - On- and off-Amazon sales attribution. - Audience and engagement insight. - Multi-touch attribution. - Bespoke DSP (demand-side platform) audience builds. - Paid Features enrichment. ## How a run works 1. The agent selects the matching skill. 2. The skill resolves advertiser, campaign, date range, and goal. 3. MCP tools query AMC and connected signal sources. 4. Kuudo applies privacy and activation guardrails. 5. The output is returned with a reproducible run log. ## Privacy model AMC inputs should be pseudonymized. Outputs should be aggregated and anonymous. Kuudo keeps those constraints visible in the run log and prevents activation when minimum-size or policy checks fail. ## Human approval Analysis can complete automatically. Activation, such as pushing a DSP audience, should pass through a human approval step unless your workspace policy explicitly allows automatic execution. ## Operational pattern Start with read-only skills. Once the team trusts the run logs, add activation steps with approval gates. Version each skill like code so analysts and operators can review changes before they become standard workflow. ### Amazon Agent Crawl MCP URL: https://www.kuudo.com/docs/amazon-agent-crawl/ Amazon Agent Crawl MCP lets connected agents search Amazon, open product detail pages, extract listing facts, and compare products from current page data. ## What Agent Crawl Does **Agent Crawl** is a crawling and extraction stack aimed at **real websites**, not static copy-paste. You can run it from a **command line**, **Docker**, or wire it up as an **MCP server** so an AI assistant can call it like any other tool. Under the hood it builds on **crawl4ai**-style browser crawling: it can load pages the way a user’s browser would, respect sensible rate limits, optionally use stealth-friendly settings for difficult sites, and save **RAG-ready** text (markdown, cleaned HTML, chunks) for search and Q&A pipelines. In practice it helps you: - **Crawl** a single page or many linked pages with strategies (breadth-first, depth-first, scored links, adaptive “stop when you know enough” runs). - **Shape output** with topics, search-style filters, chunk sizes, and optional deep-crawl limits so results fit retrieval or summarization. - **Extract structure** where templates exist, so a page becomes **fields** (titles, prices, specs) instead of one big blob of HTML. Packaged flows, including **Amazon** product and search helpers, sit on top of that core: same engine, opinionated defaults for a specific class of pages. ## Why Agents Use It Models are strong at language and reasoning but **weak guarantees** on facts about the live web: training data goes stale, URLs change, and “what I remember about this product” is not the same as “what Amazon shows today.” Agent Crawl gives an agent **repeatable tools** that fetch and normalize **current** pages. That reduces invention on prices, availability, and specs, and turns “describe this URL” into a **grounded** step the user can audit. For agents specifically, the value is: - **Grounding**: answers tied to a fetch the user or tool chain can trace back to a real page. - **Structure**: listings become comparable records, such as search rows or product fields, instead of prose-only summaries. - **Composable workflows**: search, then open several PDPs, then summarize. The same pattern works for docs sites, support portals, or internal wikis when you use the general crawl tools; Amazon is one high-leverage example. The sections below are written for **you in chat**: concrete prompts and outcomes. The assistant is the one invoking Agent Crawl on your behalf when those tools are connected. ## How to Ask You’re in a **normal chat** with an assistant that can use **Amazon lookup tools** on your behalf (for example in Claude, ChatGPT, or another app that supports the same kind of connector). You describe what you want; you do **not** need to know how the tools work under the hood. **What helps every time** - Paste the **full product link** from your browser when you mean one exact listing (the address bar URL from Amazon). - Say **how many** items matter to you (“top three results”, “first dozen hits”). - Say what you care about: **price only**, **full specs**, **reviews**, **questions & answers**, **images**, and so on. Amazon’s pages are built for shoppers, not for robots. Sometimes a field is missing or a page is partly blocked; if that happens, ask again with a narrower question or a different link. **Continuing in the same chat** - You can say **“same link, but now include reviews”** or **“here’s a second URL — compare the two”** without managing anything technical yourself. - If the answer felt thin, say **“open the full listing details”** or **“only the spec table”** so the assistant knows to go deeper on the next pass. --- ## Product Page Prompts Use this when you have a **single** Amazon product URL and want facts from that listing pulled into the conversation. ### Example: “Should I buy this for my desk?” **You might write** > I’m looking at this standing desk converter. Here’s the link: [paste URL]. Pull the title, current price, whether it says in stock, the bullet features, and the weight capacity or size from the details. Summarize in three pros and two cons for someone who works 8 hours a day. **What you should get** - A short summary grounded in that page: price, availability-style wording, key bullets, dimensions or weight limits if the listing shows them, and a balanced opinion framed from those facts. ### Example: “Will this fit in my bag?” **You might write** > [paste URL] - This is a portable monitor. I need the **package dimensions** and **item weight** from the product details, and whether the stand folds flat. Tell me if it’s realistic for a 15" laptop backpack. **What you should get** - Numbers or clear “not listed on the page” answers, plus a plain-English take on carryability. ### Example: “What are people complaining about?” **You might write** > Same link as before. **Include customer reviews** — up to about 20. Group themes: shipping, quality, setup difficulty, anything recurring. Don’t quote long rants; paraphrase. **What you should get** - Themes from recent reviews, not a dump of every star rating. ### Example: “Does anyone answer ‘X’ in the Q&A?” **You might write** > [paste URL] - Turn on **Q&A** if you can. I need to know whether this router works with my ISP’s modem-only setup. Quote or paraphrase only relevant Q&A. **What you should get** - Answers drawn from the Questions & Answers section when the listing has them. ### Example: “Images for a slide deck” **You might write** > [paste URL] — I need **product image links** (main image and gallery if available), plus the official product name as Amazon shows it. One bullet list, no essay. **What you should get** - A tidy list of titles and image URLs you can reuse (respect copyright and Amazon’s rules for how you publish them). ### Example: “Skip the fluff — title, price, Prime?” **You might write** > [paste URL] — Just **title, price, rating, review count**, and whether it looks Prime-eligible. One short paragraph. **What you should get** - A compact fact card, no long spec tables unless you ask for them. --- ## Amazon Search Prompts Use this when you want a **list of options** from a search, like typing into Amazon’s search box, but explained in chat. ### Example: “Shortlist under a budget” **You might write** > Search Amazon for **wireless earbuds under $50** (use whatever filters the search naturally applies). Give me up to **12** results in a **table**: name, price, star rating, approximate review count, Prime yes/no, and mark which ones say **Sponsored** if that’s visible. **What you should get** - A scannable table or list you can sort mentally by price or rating, with sponsored items called out so you’re not comparing ads to organic results by mistake. ### Example: “What exists in this category?” **You might write** > Search for **mechanical keyboard hot swap 75%**. I’m not loyal to a brand — I want **10** options with **price** and **rating**. Highlight any that look like a strong default pick for a first mechanical keyboard. **What you should get** - A curated-feeling shortlist with enough variety to continue in a follow-up message (“now open the top three and compare switches” — see the next section). ### Example: “Find me a gift pattern” **You might write** > Search Amazon for **gifts for a hobby gardener under $30**. List **8** concrete products (not generic categories) with price and one-line “why it’s a nice gift.” **What you should get** - Concrete product names and prices tied to the search, ready to refine (“remove tools they already own” in a follow-up). ### Example: “Compare delivery promises at a glance” **You might write** > Search **USB-C hub pass-through charging MacBook**. Return **15** results; for each, include **price** and any **delivery** snippet the search card shows. **What you should get** - Enough rows to see which listings emphasize fast shipping vs. lowest price. --- ## Search Then Compare Prompts Use this when you want the assistant to **run a search**, then **open the first few product pages** and pull the richer detail you’d get by clicking each listing (spec tables, long descriptions, sometimes reviews depending on what you asked). ### Example: “Pick the best warranty among the top hits” **You might write** > Search **electric kettle glass no plastic contact water**. Then open the **top 4** product pages. For each kettle, extract **warranty** and **materials / BPA-free** language from the listing. End with a recommendation: best for someone who cares about plastic touching hot water. **What you should get** - Side-by-side facts from full pages, not only the thin search snippet. ### Example: “Noise cancelling — battery life battle” **You might write** > Search **over ear noise cancelling headphones** and open the **top 3** results. From each full product page, pull **battery life** claims and **USB-C vs micro-USB** charging. Table + one winner for long flights. **What you should get** - Comparable numbers or quoted phrases as shown on each PDP, with a clear comparison. ### Example: “Monitor arms — will they hold my display?” **You might write** > Search **monitor arm single 32 inch VESA**. Open **top 5** listings. From each page, get **max weight** and **max screen size** if stated. Flag any mismatch with a 32" 9 lb monitor. **What you should get** - A compatibility-oriented matrix and a short “safe / risky / unknown” readout. ### Example: “Baby gear — narrow after reading details” **You might write** > Search **video baby monitor no WiFi**. Open the **top 3** products. From full pages, list **range**, **battery**, and whether **WiFi is required** or optional. Then tell me which one matches “apartment, two rooms, paranoid about hacking.” **What you should get** - Specs that rarely fit in search cards, plus a reasoned pick aligned to your constraints. ### Example: “Same search, but I only trust deep specs” **You might write** > Search **portable SSD 2TB**. Open **top 4** pages. I care about **read/write speeds** and **IP rating** if any. Build a comparison table; if a field isn’t on the page, say “not stated.” **What you should get** - Honest gaps (“not stated”) instead of guessed numbers. --- ## Limits and Expectations - Listings are fetched as Amazon serves them, often **amazon.com (US)**. Prices, wording, and availability are **what the page showed at lookup time**, not a live cart or checkout. - **Sponsored** products appear in search; ask the assistant to **label** them when you’re comparing. - Heavy automation can hit **captchas or empty sections**; retry later, try another product link, or ask for a smaller slice of the page (e.g. title + price only). Use these tools for **personal research and drafting** (gift lists, spec checks, comparison notes). Respect **Amazon’s terms** and **local rules** for scraping or automated access; don’t use this to hammer the site or replace Amazon’s own apps for purchasing. ### Amazon Agent Iris Documentation URL: https://www.kuudo.com/docs/amazon-agent-iris/ Amazon Agent Iris is an MCP server that turns image generation and Amazon listing compliance into one motion. It exposes Google Gemini and OpenAI image models as MCP tools, wraps them in the `amazon-product-image` skill that encodes current Seller Central rules, and hands every result back as a signed URL your assistant or pipeline can use directly. You talk to it in plain language from the AI client you already run — Claude, ChatGPT, Cursor, or your own automation. It generates a compliant main image, builds the rest of the merchandising stack, or audits a photo you already have and tells you exactly what to fix before Amazon ever sees it. This page covers what Iris does, the rules it enforces, what you can ask it for, which model key to bring, and how your images get published to Amazon. Iris runs in your own infrastructure — Docker-ready, like the rest of the Kuudo stack — and you connect it from the AI client you already use. ## What it does The server works in three modes, all driven by natural language: - **Generate** — create a new Amazon-ready image from a prompt (main image, infographic, lifestyle, detail, fashion shot). - **Edit** — modify an existing image to fix a compliance problem or change one element while preserving product identity. - **Audit** — check an image against the current rule set and return a verdict with the exact fix. Generate and audit are the same surface, so you can create an image, audit it, and remediate it without leaving the conversation. ## Example prompts You drive Iris in plain language from your AI client — no tool names, fields, or APIs to remember. Replace bracketed values like `[ASIN]` (Amazon Standard Identification Number), `[SKU]`, or `[brand]` with your own. > **You stay in control** > Image generation and any change that writes to a live listing pause for your review before publishing. Nothing goes live until you approve it. ### Find problems across the catalog Surface what needs attention before you decide where to spend effort. - "Scan my US listings and show me which ones have image problems." - "Which of my live listings have empty image slots — fewer images than Amazon allows?" - "Find my listings that are suppressed and tell me why." - "Show me listings that only have a single image." - "Give me a health check on [parent ASIN] and all its variations." ### Diagnose one listing Zoom in on a specific SKU to understand its current state. - "Pull up [SKU] and tell me what's wrong with it." - "Review the listing for [ASIN] — title, bullets, description, and images." - "Why isn't [SKU] showing in search? What does it need to come back online?" - "How many images does [ASIN] have, and what's missing?" ### Fix listing copy Clean up or rewrite text, grounded in the product's real attributes. - "Rewrite the bullet points for [SKU] — it only has one and it's weak." - "The description for [SKU] has copy-pasted text from another product. Clean it up." - "Improve the bullets for [ASIN] using only what's true from the listing — don't invent features." - "Make the title for [SKU] clearer and keep the brand out of the body copy." ### Generate product imagery Create new images from your real product. Lead with the scene you want. **Lifestyle / in-use shots** - "Create a lifestyle photo of [product] styled on a cream sofa in a bright, neutral living room." - "Show a person using [product] in a warm, natural-light kitchen scene." - "Make a cozy bedroom scene with [product] as the focal point." **Hero / product shots** - "Generate a clean studio shot of [product] on a pure white background." - "Zoom in on the [product] so it fills more of the frame and reads as the hero image." **Infographics** (added text is allowed on these auxiliary images) - "Build a size and dimension graphic for [SKU] using the real measurements from the listing." - "Create a feature-callout image for [product] highlighting its material, stitching, and zipper." - "Make a care-instructions card for [product] — machine washable, etc." - "Create a 'set of 2, covers only — no insert' graphic so buyers know what they're getting." - "Make a color-range image showing all the available colors for this variation family." ### Edit and iterate on an image Refine an image you've already generated, in plain language. - "Zoom in slightly on the pillow in this image." - "Remove the books in the background — keep everything else the same." - "Same scene, but brighter and with more natural light." - "Make the product larger and more centered." - "Try this again on a grey sofa instead of cream." ### Check compliance before publishing Validate against Amazon's image rules before anything goes live. - "Check whether this image meets Amazon's compliance requirements." - "Is text allowed on this image for the slot it's going into?" - "Validate the file format, resolution, and color space on this image." - "Run the policy check on all the images I've generated so far." ### Publish to the listing Write approved changes directly to the live listing. - "Add this image to [SKU] as the first alternate image." - "Put the size graphic into the next open slot on [SKU]." - "Patch [SKU] with this image." - "Apply the rewritten bullets and description to [SKU]." ### Confirm it actually went live Verify the change was accepted and the image was ingested by Amazon. - "Check whether the new image on [SKU] ingested cleanly." - "Did my last change to [SKU] go through, or are there any errors?" - "Re-check [SKU] and confirm the gallery now shows the images I added." ### Reuse imagery within a variation family Fill gaps by borrowing the right images from sibling SKUs — safely. - "This color is missing alternate images. Which images from its sibling colors can I reuse without misrepresenting it?" - "Show me the best-stocked sibling of [SKU] and which of its images are color-neutral enough to copy." - "Fill the empty slots on [SKU] with the generic infographics from the family, but not the color-specific shots." ### Work at scale Move from one listing to many. - "Make a list of every listing missing a main image so I can prioritize them." - "Which listings would benefit most from a lifestyle image? Rank them." - "Walk me through fixing the thinnest listings one at a time." Most real sessions chain these together. A typical one runs: *"Scan my listings for image gaps"* → *"Let's start with [SKU]"* → *"Create a lifestyle photo on a cream sofa"* → *"Zoom in slightly"* → *"Check it for compliance"* → *"Add it to the listing"* → *"Confirm it ingested."* Treat it as a conversation, not a set of one-off commands. ## The audit verdict When you ask for an audit, the skill returns a structured verdict rather than a vague opinion: ```text Status: Compliant | Needs changes | Reject Scope: [main image / alternate / fashion / multipack / ...] Blocking issues: - [issue and the rule category it violates] Non-blocking suggestions: - [quality or conversion improvement] Fix: - [the exact edit instruction or replacement prompt] References checked: - [which rule references were applied] ``` The verdict is graded by rule category, so a near-white background that reads `~254` instead of `255` comes back as a specific, fixable note — not a silent pass that gets your listing suppressed later. ## Compliance rules it enforces The `amazon-product-image` skill carries a distilled rule set from Amazon Seller Central policy. These are the rules applied during generation and checked during audit. ### Main image — hard requirements | Rule | Spec | | --- | --- | | Background | Uniform pure white, RGB 255, 255, 255 | | Product fill | ~85% of the frame, full product visible | | Single view | One unit, one main view (unless a multipack or assortment) | | Props | Product only — no accessories that aren't included | | Text & marks | No added text, logos, borders, watermarks, or badges | | Apparel model rule | Adult apparel on-model and standing; kids, accessories, and multipacks flat (off-model); no mannequins or hangers | | Footwear | Single shoe, left foot, 45° angle | ### Technical file requirements | Spec | Rule | | --- | --- | | Formats | JPEG (preferred), TIFF, PNG, non-animated GIF | | Longest side | 500–10,000 px; 1,000 px+ enables zoom; 1,600–2,000 px+ preferred | | Color | RGB preferred; CMYK may shift tonally; grayscale only for genuinely gray/silver products | | File naming | `ASIN.jpg` or `ASIN.VARIANT.jpg` (periods as separators, no spaces or dashes) | | Image count | Up to 9 (1 main + 8 additional); ~7 gallery thumbnails shown by default | ### All-image content rules These apply to every image in the stack, not just the main: - No reviews, stars, ratings, prices, deals, coupons, or free-shipping claims. - No seller info, email, copyright marks, or watermarks. - No Amazon, Prime, Alexa, "Choice," or "Best Seller" branding or lookalikes. - No promotional, warranty, certification, or unsubstantiated safety/health/regulatory claims. - Every image must match the product title, ASIN, variant, color, quantity, and scale. ### Special cases | Case | Rule | | --- | --- | | Multipacks | Show the total quantity delivered; the title must state the count | | Variety packs | Show representative items plus the total count | | Used / collectible offer photos | Optional, separate from detail images; non-white backgrounds accepted | ### Suppression issues and fixes The skill maps the common suppression and rejection reasons to a concrete fix: | Issue | Fix | | --- | --- | | Non-white background | Use pure white, or normalize the background field to 255 downstream | | Text, logo, or graphics | Remove all non-product overlays | | Cropped product | Reframe so the full product is visible | | Additional items / props | Show the product only | | Mannequin or hanger visible | Flat-lay, or an invisible-mannequin edit that doesn't crop the product | | Model not standing | Use a standing model (wheelchair exception allowed) | | Multiple views in one frame | One main view per image | | Blurry, pixelated, or too small | Replace with a sharp image ≥500 px on the longest side | | Unsupported / corrupted file | Re-export as JPEG/PNG/TIFF, flattened, verified locally | | **Error 100239** | Image and title don't match — correct either the title or the image and resubmit; if they already match, escalate to support with the SKU, `item_name`, and image URL | ### Fashion, apparel, and footwear - Adult apparel on-model and standing; kids, babies, accessories, and multipacks off-model (flat laydown). - Framing by garment: full-length for dresses and suits, top-body for shirts, waist-down for pants and skirts. - Footwear main image: single shoe, left foot, 45°. - Off-model laydowns: white surface, steamed, loose threads removed, square framing. - A 13-point fashion validation checklist covers parent/child coverage, naming (`ASIN.MAIN.jpg`, `ASIN.PT01.jpg`, `ASIN.FL01.jpg`), the image set, and mobile readability. ## The image stack Most listings stop at the main image. The skill helps you build the full stack that actually converts: | Slot | Type | Purpose | | --- | --- | --- | | 1 | Main | Product on pure white; drives the search click | | 2 | Feature | Close-up of the key differentiator | | 3 | Infographic | Labels, dimensions, materials, contents, compatibility | | 4 | Lifestyle | Product in real use; environment and models allowed | | 5–7 | Angles / details | Front, side, back, interior, hardware, texture | | 8 | Instructional | Assembly, fit, usage, or truthful before/after | ## Providers and models One server, two best-in-class image engines. The provider is chosen **per session from the API key on the request** — no lock-in, and the compliance rules apply identically to both. - A Google key (`AIza…`) routes to **Google Gemini**. Default model is `gemini-3.1-flash-image` ("Nano Banana"), with `gemini-3-pro-image` and `gemini-2.5-flash-image` also available. Resolutions `0.5K`, `1K`, `2K`, `4K` and the full aspect-ratio set (`1:1` through `21:9`). - An OpenAI key (`sk-…`) routes to **OpenAI `gpt-image-2`** via the Responses API, with `size`, `quality`, and `background` controls. We recommend Gemini Nano Banana for speed and cost; switch any time by changing the key. ## MCP tools The server exposes a small, clean tool surface. The two generation tools are the ones you'll use most. | Tool | What it does | Key parameters | | --- | --- | --- | | `start_here` | Built-in workflow guide for the LLM | none | | `generate_image` | Generate or edit with Google Gemini | `prompt`, `n` (1–14), `input_images`, `operation`, `aspect_ratio`, `resolution`, `model`, `interaction_id`, `use_grounding` | | `generate_openai_image` | Generate with OpenAI `gpt-image-2` | `prompt`, `n` (1–10), `input_images`, `size`, `quality`, `background`, `output_format`, `previous_response_id` | | `create_upload_url` | Mint a short-lived signed upload URL for your own image bytes (up to 40 MB) | none | | `server_status` | Diagnostics: auth, active providers, models, storage, health | none | | `read_resource` | Read a resource by URI, e.g. `skill://amazon-product-image/SKILL.md` | `uri` | Every generated asset comes back as a **signed download URL** (plus a thumbnail and expiry) and is hosted for you, so it drops straight into a PIM, DAM, or ad campaign — or onto an Amazon listing, which fetches that URL directly. See [Built-in media hosting](#built-in-media-hosting-amazon-pulls-it-doesnt-receive) below for why that matters. ### Chained edits and brand-mark fidelity To iterate without re-uploading the source image, pass the prior interaction back in: - **Gemini:** reuse `interaction_id` from a previous `generate_image` result (valid ~55 days on paid accounts, 1 day on free). - **OpenAI:** reuse `previous_response_id` from a previous `generate_openai_image` result. Brand-mark fidelity is a first-class rule on every edit. Logos, labels, and printed text are reproduced exactly — when you recolor a material, only that material changes; the wording, typography, and logo artwork stay identical to the source. A re-lettered or garbled label is treated as a compliance failure. ## Built-in media hosting: Amazon pulls, it doesn't receive Amazon's listing system is **pull-based, not push-based**. You never upload image bytes to Amazon. You hand it a URL, and Amazon's content pipeline runs its own `GET` against that URL, fetches the asset, and copies it into its CDN. The consequence is strict: an image exists to Amazon only if Amazon can reach it over the public internet, **unauthenticated**, at the moment it fetches. That is why Iris hosts your media for you. A freshly generated image otherwise lives nowhere addressable — it has no point of egress, so there is literally nothing for Amazon to pull. Iris gives every generated (or uploaded) asset a public, fetchable URL the instant it is created, which is exactly the contract Amazon's pull model expects. Why this matters more than it looks: - **It speaks Amazon's protocol natively.** Amazon expects an unauthenticated, `GET`-able asset; the host serves precisely that, so the integration meets the requirement instead of approximating it. - **It removes the most common failure point.** Without an integrated host you bolt on separate hosting — buckets, credentials, public-read policies, URL signing — each a chance to misconfigure. The classic listing-image failure is exactly this: the asset isn't reachable, Amazon's fetch fails, and the image silently never appears. - **It makes "generate and publish" one continuous motion.** Because the asset is born already addressable, the handoff from "image exists" to "Amazon can fetch it" is instant. There is no manual upload step in the middle. > **You don't host anything** > Public egress, the URL, and how long it stays alive are all handled for you. Iris keeps each image reachable through Amazon's fetch window, so the asset is still there when Amazon's pipeline comes to ingest it. Built-in egress is the headline; staying reachable long enough is the part Iris takes care of so a fetch never silently fails. Bottom line: an image with no public point of egress is, to Amazon, an image that doesn't exist. The built-in media host is the reachable front door that lets the whole pipeline meet Amazon's pull model natively, rather than relying on fragile, hand-rolled hosting. ## Limits and honest framing - **Amazon makes the final call.** The skill materially de-risks and accelerates compliance, but it does not guarantee acceptance — Amazon does. - **The ~254 vs 255 white-background caveat.** Current image models render a non-uniform near-white background around `254`, not exact `255`, even with a perfect prompt. This is a model rendering limit, not a compression issue, and switching to PNG/TIFF doesn't fix it. Reaching exact-255 compliance needs a deterministic downstream normalization pass that clamps the background field to 255. The audit flags when that step is needed and tells you to sample the corners rather than judge by eye. - **One provider per session.** A request uses Gemini or OpenAI based on its key — not both in the same call. - **Synthetic images must be honest.** AI-generated product images are acceptable only when they realistically represent the actual product and never hide defects, change identity, color, scale, or contents, or add prohibited text or claims. ## Related - [Amazon Agent Iris feature overview](/features/amazon-agent-iris/) — the product surface at a higher level. - [Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/) — publish generated images straight onto listings and verify ingestion. - [Amazon Ads MCP](/features/amazon-ads-mcp/) — pull live ad performance to seed creative. - [MCP client configuration](/docs/mcp-client-configuration/) — connect Claude, ChatGPT, Cursor, and other clients. ### Using a Knowledge Library With Your Agent URL: https://www.kuudo.com/docs/agent-knowledge-usage/ This page is for people who work in ChatGPT, Claude, or similar assistants that can **search a curated library** (for example product rules, playbooks, or internal guides) instead of relying only on what the model remembers from training. You do not need to know how the library is stored. If your workspace or project already connects the assistant to that library, treat this as **how to ask** so answers stay grounded, specific, and useful. On Kuudo, **Amazon Agent Atlas** is one way that library is connected; the habits below apply to any similar setup. ## What Changes When a Library Is Connected A connected library is **searchable text your agent can pull in during the conversation**. It is not magic: the assistant finds passages that match your question, then reads them to answer. Clear questions and explicit goals produce better retrieval than vague ones. **You should expect** - Answers that quote or follow your organization’s material when it is relevant. - Less invention on topics where your library is the source of truth. - The assistant to say when it cannot find a match, instead of guessing. ## How to Ask Use the same habits you would use with a sharp colleague who has access to your file share. - **Name the domain** in plain language (Amazon listings, sponsored ads, compliance, style guides). - **Say the output shape** you want: checklist, table, rewrite, pros and cons, email draft, bullet talking points. - **Add constraints**: audience (seller, executive, new hire), region, tone, or “only use our library; say if something is missing.” - **One main task per message** when possible. Long laundry lists get partial answers. ## Use Case: Category or Channel Rules Use this when you need **how we title, bullet, or structure listings** for a specific category or channel. **You might write** > Pull our style guidance for Amazon **Grocery** listings. Summarize title patterns and bullet order in a short checklist I can hand to a copywriter. **You might write** > We are launching a **pet food** SKU. What does our library say about species, life stage, and parent/child titles? Give me a do/don’t list. **What you should get** - A compact checklist or bullets tied to your guides, not generic e-commerce advice. - Explicit callouts when your library distinguishes sub-categories (for example food vs toys). ## Use Case: Rewrite or Strengthen Copy Use this when you have **draft listing text** and want it aligned to your stored rules. **You might write** > Here is our draft title and five bullets for a **chromebook**. Rewrite them to match our Computers style guide. Keep the same facts; flag anything we should verify on Seller Central. **You might write** > Rewrite these bullets for a **baby car seat** listing in a calmer, compliance-first tone. Cite which rules from our library you applied. **What you should get** - Revised copy plus a short “why” tied to your library (title formula, claim limits, required attributes). - Flags where the library says to verify with compliance or live templates. ## Use Case: Compare Two Approaches Use this when you are **choosing between strategies** and want the assistant to ground the tradeoffs in your material. **You might write** > Compare “keyword-stuffed titles” vs “spec-first titles” for **consumer electronics** accessories using only our guidance. End with a recommendation for a three-SKU cable line. **What you should get** - A side-by-side or short table grounded in your docs, plus a clear recommendation and assumptions stated explicitly. ## Use Case: Onboarding and Training Use this when someone **new needs the shape of a domain** without reading hundreds of pages. **You might write** > New hire starts Monday on **Amazon Ads reporting**. Give a 10-minute spoken overview outline: what to read first, three concepts that confuse people, and five questions they should ask the account lead. **You might write** > What topics does our library cover under **vendor operational compliance**? List them as a syllabus with one sentence each on why it matters. **What you should get** - A syllabus, outline, or FAQ-style map that reflects what is actually in the library. ## Use Case: Pre-Flight Before a Launch or Audit Use this when you want a **last pass against stored rules** before publishing or before a client call. **You might write** > We are about to publish a **supplements** detail page. Scan against our Health & Personal Care guidance: structure/function vs disease claims, disclaimer placement, and title formula. Output pass / fix / escalate. **You might write** > Tomorrow’s meeting: **sponsored ads bidding**. List the top five risks or misconceptions our library warns about, with one example question to ask the client for each. **What you should get** - A prioritized review list with “fix” vs “escalate to legal/compliance” style buckets when your material supports that split. ## Use Case: “What Do We Actually Say About X?” Use this for **pointed fact finding** when rumors or forum advice conflict with your standards. **You might write** > What does our library say about **refurbished** computer listings and disclosure wording? Quote short phrases if helpful. **You might write** > Find anything we have on **live plants** or **hardiness zones** in listing copy. If we have nothing, say so clearly. **What you should get** - Direct excerpts or faithful paraphrases with scope (“this is from the Garden guide, not legal advice”). - A clear “not found in library” when there is no match. ## Limits and Expectations - **Staleness:** Your library reflects the documents that were indexed. Amazon templates, policies, and UI change; always confirm critical details in Seller Central or official sources when stakes are high. - **Not legal advice:** Guides summarize patterns and internal standards. Compliance decisions stay with your counsel and account owners. - **Retrieval is not perfect:** Unusual wording or missing tags in source files can make matches weaker. Rephrase or add a keyword from your domain if the first answer feels thin. - **Privacy:** Do not paste secrets into chats unless your organization approves that workflow. Ask about **sanitized examples** when demonstrating issues. ## Related Material - [Amazon Agent Atlas](/docs/amazon-agent-atlas/) — Kuudo’s curated Amazon operating library and how it fits agents. - [Claude quick start](/docs/quick-start/claude-ai/) and [ChatGPT quick start](/docs/quick-start/chatgpt/) — connect a client, then use the prompts above. For the open-source **Chroma MCP** knowledge pipeline (developers), see the **chroma-mcp** repository README and agent instructions at the repository root. ### Amazon Listing Optimizer URL: https://www.kuudo.com/docs/amazon-listing-optimizer/ Amazon Listing Optimizer audits, rewrites, and fixes your Amazon listings from the AI client you already use. It reads the live catalog and your submitted listing, finds what's wrong or thin — suppressions, contradictions, weak bullets, broken variations, empty search terms, missing A+ Content — rewrites it grounded in your product's real attributes and Amazon's current rules, and publishes the approved changes straight to the listing. You talk to it in plain language. Name an ASIN (Amazon Standard Identification Number) or SKU and say "review it," "clean up the bullets," "why is this suppressed," or "fix the whole catalog," and it takes it from there. It runs on Kuudo's hosted infrastructure as a Skill on the [Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/). There is nothing to deploy or operate, and nothing it writes goes live without your sign-off. This page covers what it does, what to say, what it checks, how changes get published safely, and how it pairs with [Amazon Agent Iris](/features/amazon-agent-iris/) for images. ## What it does - **Audit** — review one listing or scan the whole catalog: surface suppressions, policy warnings, contradictions, thin copy, broken variations, and missing A+ Content. - **Optimize** — rewrite titles, bullets, descriptions, and search terms grounded in the product's real attributes and the category's Amazon style guide. Fix variation scope and fill gaps. - **Publish** — write approved changes straight to the live listing, then confirm Amazon accepted and ingested them. Audit and optimize are one conversation: review a listing, pick the fixes, preview the change, approve, publish — without leaving chat. ## Example prompts You drive it in plain language from your AI client — no tool names, fields, or APIs to remember. Replace bracketed values like `[ASIN]`, `[SKU]`, or `[brand]` with your own. > **Nothing goes live without your sign-off** > Every change that writes to a live listing is previewed first and waits for your approval. You see the exact before/after before anything is submitted. ### Find problems across the catalog Surface what needs attention before you decide where to spend effort. - "Scan my US listings and show me which ones have problems." - "Which of my listings are suppressed, and why?" - "Find my thin listings — a single image, one weak bullet, or no description." - "Give me a health check on [parent ASIN] and all its variations." - "Which of my brand-registered listings are missing A+ Content?" ### Diagnose one listing Zoom in on a specific SKU to understand its current state. - "Pull up [SKU] and tell me what's wrong with it." - "Review the listing for [ASIN] — title, bullets, description, search terms, and images." - "Why isn't [SKU] showing in search? What does it need to come back online?" - "Is there anything in [SKU]'s copy that looks tampered with or hijacked?" ### Fix the copy Rewrite text grounded in the product's real attributes — never invented features. - "Rewrite the bullets for [SKU] — it only has one and it's weak. Use only what's true from the listing." - "The description for [SKU] has copy-pasted text from another product. Clean it up." - "My title is over the limit and stuffed with keywords — tighten it to the category formula." - "Make the bullets answer who it's for and why to buy, not just list features." - "There's a contradiction — the bullet says 'cast iron' but the attributes say metal. Fix it the right way." ### Fix variations and the family - "This is a variation parent but the bullets name a specific color — fix the scope so it describes the family." - "Compare the parent's child ASINs to its child SKUs and find the orphan." - "Each child should show its own color in the main image — which ones don't?" ### Search terms and SEO - "My backend search terms are empty — fill them from the listing and customer reviews." - "Audit [SKU]'s search terms: strip out brand names, duplicates, and anything over the limit." ### A+ Content - "Does [ASIN] have A+ Content? If not, what would it add?" - "Audit the A+ Content on [ASIN] against Amazon's policy." - "Draft A+ modules for [ASIN] — lifestyle, feature callouts, and a same-brand comparison." ### Check compliance before you change anything - "Check [SKU] against Amazon's listing rules before I touch it." - "Is my responsible-party address DSA-compliant?" - "What would suppress this listing if I submitted it as-is?" ### Preview and publish - "Draft the cleaned bullets and show me the exact before and after." - "Apply the rewritten bullets and description to [SKU]." *(it previews; you confirm)* - "Patch [SKU]'s title with the tightened version." ### Confirm it actually went live - "Did my last change to [SKU] go through, or were there errors?" - "Re-check [SKU] in a bit and confirm the detail page updated." ### Work at scale - "List every suppressed listing so I can prioritize them." - "Rank my listings by how much a copy cleanup would help." - "Walk me through fixing the thinnest listings one at a time." Most real sessions chain these together. A typical one runs: *"Scan my catalog for problems"* → *"Start with [SKU]"* → *"Why is it suppressed?"* → *"Rewrite the bullets and fix the contradiction"* → *"Preview the patch"* → *"Confirm"* → *"Re-check it went live."* Treat it as a conversation, not a set of one-off commands. ## What it checks When it audits a listing, it looks for the problems that actually cost you visibility and conversions, and reports them ranked by priority: - **Active warnings and suppressions** — policy errors, missing required fields, and category-specific gaps that hide the listing from search. - **Hijacked or tampered copy** — adult terms, slurs, or sabotage phrases ("do not buy," "counterfeit") injected by a compromised account or a hijacker. Flagged as a security issue to investigate, not a typo to quietly rewrite. - **Self-contradictions** — title versus bullets versus description versus structured attributes: a size mismatch, "machine washable" with a hand-wash attribute, "cast iron" on a part that can't be. - **Thin or feature-dump copy** — bullets that list specs but never say who the product is for or why to buy it. - **Wrong variation scope** — color- or size-specific copy on a parent that spans the family, or an orphaned child SKU. - **Weak SEO** — empty or keyword-stuffed backend search terms, and titles that ignore the category formula. - **Missing A+ Content** — brand-registered ASINs leaving conversion lift on the table. - **Compliance gaps** — brand-name policy, the EU DSA responsible-party address, and the rest of Amazon's hard rules. It leads with the warning that's hiding your listing, groups the cosmetic fixes, and offers concrete next actions rather than dumping a thirty-item list. ## Nothing goes live without your sign-off Listings are public content, so every change that writes to a live listing runs the same three steps: > **Preview → Confirm → Submit** > It shows you the exact change — which field, from what, to what — and waits. Nothing is submitted until you reply with your approval. Then it submits and reports the result. "Accepted" means Amazon validated the change; the detail page itself updates a few minutes to a few hours later. It won't run back-to-back edits without your say-so, and it won't "fix" a field you didn't ask about. If you request a change that contradicts the product's reality — a spec the attributes say isn't true — it surfaces the conflict and offers the correct fix instead of silently shipping something that drives returns. ## Grounded in Amazon's rules The optimizer applies Amazon's hard policy — title and bullet limits, prohibited content, suppression triggers, brand-name rules, per-category required attributes — and grounds category-specific decisions like title formulas and bullet conventions in [Amazon Agent Atlas](/features/agent-atlas/), Kuudo's indexed Amazon knowledge base. When Atlas doesn't have a rule for a category, it says so rather than inventing one. ## Images: pair it with Amazon Agent Iris The optimizer handles everything text and structure — copy, variations, search terms, A+ Content. For the image side of a listing it pairs with **[Amazon Agent Iris](/features/amazon-agent-iris/)**, and that pairing matters more than it looks. Amazon's image fields don't take bytes — they take a **URL Amazon fetches** and copies into its CDN, so a listing image has to be generated *and* hosted somewhere publicly reachable. Iris does both: it generates compliant images from your real product and hosts each one at a fetchable URL the instant it's created. You skip the part that usually breaks image work — standing up a storage bucket, credentials, public-read policies, and staging — and the optimizer publishes the resulting URL straight onto the listing through the same preview-and-confirm flow. The full motion across both reads: *audit the listing → rewrite the copy → generate the missing images with Iris → check everything against Amazon's rules → publish → confirm it went live.* See the [Amazon Agent Iris docs](/docs/amazon-agent-iris/) for the image side, and the [Rebuild Your Listing Images From Your Own Photos](/guides/seller-listing-image-regeneration-seeded/) guide for the seeded-image workflow. ## Limits and honest framing - **You own the call.** It rewrites and previews; you approve every live change. It will push back on edits that contradict the product, but the final decision is yours. - **"Accepted" isn't "live."** Amazon validates the change immediately; the detail page propagates over minutes to hours. Re-check shortly after to confirm. - **Some fixes need you at Seller Central.** Brand-approval errors and A+ rejections require a support case or a resubmission you own — it tells you exactly what to file. - **A+ Content goes through review.** Amazon reviews new A+ Content (about seven business days); rejections usually trace to competitor comparisons or promotional claims. - **It only touches listings your account owns.** Edits are scoped to the connected seller identity and marketplace. ## Related - [Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/) — the product surface this runs on. - [Amazon Agent Iris](/features/amazon-agent-iris/) — generate and host compliant listing images; the perfect companion for the image side of optimization. - [Amazon Agent Iris docs](/docs/amazon-agent-iris/) — the image generation, audit, and hosting workflow. - [Amazon Agent Atlas](/features/agent-atlas/) — the indexed Amazon knowledge the optimizer grounds its category decisions in. - [Rebuild Your Listing Images From Your Own Photos](/guides/seller-listing-image-regeneration-seeded/) — a worked listing-image workflow. - [MCP client configuration](/docs/mcp-client-configuration/) — connect Claude, ChatGPT, Cursor, and other clients. ### Amazon Returns Monitor URL: https://www.kuudo.com/docs/amazon-returns-monitor/ Amazon Returns Monitor turns your returns data into a report that tells you which products are coming back, why, and which ones you can actually do something about. You ask for it in plain language from the AI client you already use — name a window, say "run my returns report," and it pulls the data, breaks it down, and hands you the result. It reads your FBA (Fulfillment by Amazon) and MFN returns, ranks the ASINs driving the volume, sorts every return reason into what you can fix versus what you can't, and flags the products that need attention now — with the recurring complaint pulled straight from customer comments. It runs on Kuudo's hosted infrastructure as a Skill on the [Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/). There is nothing to deploy or operate, and it never changes your account — it analyzes returns and produces a deliverable you control. This page covers what it does, what to say, what it surfaces, how it keeps the numbers honest, and how it pairs with [Amazon Listing Optimizer](/docs/amazon-listing-optimizer/) and [Amazon Agent Iris](/docs/amazon-agent-iris/) to fix the returns you can fix. ## What it does - **Break it down** — returns by ASIN (Amazon Standard Identification Number), SKU, reason, and disposition: which products drive the volume, and the dominant reason for each. - **Separate what you can fix from what you can't** — every return reason sorted into controllable, remorse, ops, and other, so you spend effort where a fix would actually move the number. - **Flag the ones that need action now** — red-flag ASINs with a high return rate and a fixable cause, each with two or three representative customer comments and a grounded hypothesis for what's wrong. - **Trend it and hand it off** — this period versus the one before, delivered as a chat summary, a Word document, an Excel workbook, or an interactive dashboard. ## Example prompts You drive it in plain language from your AI client — no report types, columns, or APIs to remember. Replace bracketed values like `[ASIN]`, `[SKU]`, or `[brand]` with your own. > **This one reads; it never writes** > The monitor pulls your returns data and analyzes it. It doesn't change a listing, issue a refund, or touch your account — so there's nothing to approve. Acting on what it finds is a separate, deliberate step. ### Run the report - "Run my returns report for the last 30 days." - "Pull FBA returns for last month and compare them to the month before." - "Give me a returns report for my US account I can send to the team." ### See what's coming back - "Which of my ASINs have the most returns?" - "Break my returns down by product and reason." - "What's my most-returned SKU, and what's the top reason for it?" ### Understand the reasons - "Group my return reasons into what I can fix versus buyer's remorse." - "How much of my return volume is 'not as described' versus 'changed their mind'?" - "Which returns are defects or damage, and which are just preference?" ### Find the problem ASINs - "Flag any ASIN with a return rate high enough to worry about." - "Show me the products where the returns are something I could actually fix." - "Which ASINs come back as 'customer damaged' more than half the time?" ### Get the return rate right - "What's my return rate for [ASIN] — and tell me how you measured it." - "I only have the returns file, no sales data. What can you still tell me?" - "Compare [ASIN]'s return rate to my portfolio median." ### Read the customer comments - "What are customers actually saying when they return [ASIN]?" - "Pull the recurring complaint from the comments on my worst-returning products." - "Are buyers complaining about sizing, the photos, or quality?" ### Disposition and reimbursement - "How many of my returns came back unsellable?" - "Where's the gap between units returned and units I can resell — am I owed reimbursements?" - "Break down returns by disposition for [ASIN]." ### Trend it over time - "Is my return rate going up or down versus last period?" - "Which reasons grew the most this month?" - "Did my red-flag ASIN list change from last month?" ### Pick the format - "Give me the workbook so my BI team can slice it." - "Make it a one-page exec summary." - "Build me a dashboard I can explore and filter by reason." ### Turn the findings into fixes - "Which of these returns trace back to a bad listing or a misleading photo?" - "Take my top 'not as described' ASINs and tell me what to fix." - "List the controllable-return ASINs so I can hand them to the listing optimizer." Most real sessions chain these together. A typical one runs: *"Run my returns report for last month"* → *"Which ASINs are red-flagged?"* → *"Why is [ASIN] coming back?"* → *"What are customers saying?"* → *"Which of these are listing or image problems?"* Treat it as a conversation, not a set of one-off commands. ## What it surfaces When it runs a full report, it leads with the urgent and works down, so you read the things that need action first: - **Red-flag ASINs, up top** — the products to deal with now: a high return rate, enough shipped volume to be real, and a top reason you can fix. These lead the report; they're never buried in an appendix. - **Reason breakdown** — every return reason, grouped into controllable, remorse, ops, and other, so you can see at a glance what a fix would move and what it wouldn't. - **Return concentration** — which ASINs drive the volume, with the dominant reason and per-ASIN rate for each. - **Customer-comment themes** — the recurring complaint behind your worst returns, mined from real buyer comments, not guessed. - **Disposition and reimbursement** — what came back sellable versus unsellable, with a callout when the gap suggests you're owed a reimbursement. - **Fulfillment-center concentration** — when returns cluster at one FC, a packaging or handling signal worth a look. - **Time trend** — daily and weekly movement, with partial weeks flagged so a refresh lag doesn't read as a real dip. - **Prior-period deltas** — this window against the one before, on volume, rate, reason mix, and which ASINs joined or left the red-flag list. A product gets red-flagged when more than 40% of its shipped units come back, it shipped enough to clear the noise, and the top reason is something a listing, catalog, or quality fix would address. It also flags any ASIN coming back as "customer damaged" more than half the time, regardless of rate — that pattern usually means a packaging failure or return abuse. ## Straight talk on the return rate A return rate is one of the easiest numbers on Amazon to quote wrong, because returns and sales are dated and counted differently. The monitor won't hand you a bare percentage and let you misread it: > Every rate carries a label for how it was measured. A *share of returns* — what slice of your returns a reason or ASIN accounts for — is never dressed up as a *return rate* against units sold. When the data lets it tie returns back to the orders that caused them, it says so and states the follow window. And it keeps facts separate from policy. What the data shows — counts, reasons, concentration — it states plainly. Account-health thresholds, which Amazon changes by program and region, it flags as *verify in Seller Central* rather than quoting a number as if it were the rule. When a recommendation leans on an actual Amazon rule, it grounds that in [Amazon Agent Atlas](/features/agent-atlas/), Kuudo's indexed Amazon knowledge base, instead of inventing one. ## From diagnosis to fix The monitor is a diagnosis. It tells you which products are bleeding returns and the reason behind each — but it doesn't change anything. The controllable bucket it surfaces is exactly what two companion tools repair. - **"Not as described" and image-driven returns** usually mean the photos oversell or under-show the product. [Amazon Agent Iris](/features/amazon-agent-iris/) regenerates compliant, accurate images from your real product and hosts them where Amazon can fetch them, so the picture matches what shows up at the door. See the [Iris docs](/docs/amazon-agent-iris/). - **Sizing, fit, contradictions, and thin or wrong copy** live in the listing text. [Amazon Listing Optimizer](/docs/amazon-listing-optimizer/) rewrites titles, bullets, and size guidance grounded in the product's real attributes and Amazon's rules, then publishes the fix once you approve it. The full loop runs in one place: *run the returns report → read the controllable ASINs and their modal reason → hand the copy and sizing problems to the Optimizer and the image problems to Iris → re-list → re-run the report next period and watch the controllable rate fall.* Diagnosis, fix, proof — without leaving your AI client. ## Limits and honest framing - **It reads; it doesn't change anything.** No writes to your account. It analyzes returns and produces a report; fixing the listings behind them is a separate, opt-in step. - **A real return rate needs shipment data.** Without a units-sold denominator it gives you rankings and reason shares, not a validated rate — and labels them as exactly that. - **Account-health thresholds aren't hard-coded.** Policies shift by program and region; it flags risk and points you to your own Seller Central numbers rather than stating a threshold as fact. - **Returns data lags and uses its own dates.** Amazon's daily refresh trails real time, and returns and sales are indexed by different events; it states the exact UTC window it pulled so a time-zone or refresh gap doesn't fool you. - **It only sees the account you connect.** Every pull is scoped to the selected seller identity and marketplace. ## Related - [Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/) — the product surface this runs on. - [Amazon Listing Optimizer](/docs/amazon-listing-optimizer/) — fix the copy, sizing, and contradictions behind controllable returns. - [Amazon Agent Iris](/features/amazon-agent-iris/) — regenerate the misleading or thin images behind "not as described" returns. - [Amazon Agent Iris docs](/docs/amazon-agent-iris/) — the image generation, audit, and hosting workflow. - [Amazon Agent Atlas](/features/agent-atlas/) — the indexed Amazon knowledge that grounds rule-dependent recommendations. - [MCP client configuration](/docs/mcp-client-configuration/) — connect Claude, ChatGPT, Cursor, and other clients. ### Amazon Search Query Analyzer URL: https://www.kuudo.com/docs/amazon-search-query-analyzer/ Amazon Search Query Analyzer reads your Search Query Performance (SQP) data and tells you, for each ASIN (Amazon Standard Identification Number) and each search term, exactly where you're losing — showing up, getting clicked, or closing the sale — and what to change to win it back. You ask for it in plain language from the AI client you already use. It walks the funnel one search term at a time. For a query like "large dog bed," it compares your share of impressions, clicks, and purchases against the whole market and your peers, finds the stage that's leaking, and names the fix — a title, a hero image, a price test, a faster delivery promise, or a variant cleanup. It runs on Kuudo's hosted infrastructure as a Skill on the [Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/). There is nothing to deploy or operate, and it never changes your account — it diagnoses, ranks, and recommends; making the changes is your call. This page covers what it does, what to say, what it surfaces, how it keeps the calls honest, and how it pairs with [Amazon Agent Iris](/docs/amazon-agent-iris/) and [Amazon Listing Optimizer](/docs/amazon-listing-optimizer/) to fix what it finds. ## What it does - **Diagnose the funnel** — for every search-term-and-ASIN pair, where you stand on impression share, click share, and purchase share against the market and your peers, and which stage is the bottleneck. - **Name the fix for each gap** — invisible for a term, weak click-through, conversion friction, slow delivery, price, or variant cannibalization, each mapped to a concrete change. - **Rank by upside, not volume** — opportunities scored by how much recoverable sales sit behind the gap, so the top of the list is the highest-leverage work, not just the biggest keyword. - **Tag who owns each fix** — every recommendation marked as a listing change, an ops change, or an ad play, so the right person picks it up. ## Example prompts You drive it in plain language from your AI client — no report types, columns, or metrics to remember. Replace bracketed values like `[ASIN]`, `[SKU]`, or `[search term]` with your own. > **This one reads; it never writes** > The analyzer pulls your search data and diagnoses it. It doesn't edit a listing, change a price, or touch a campaign — so there's nothing to approve. Acting on what it finds is a separate, deliberate step. ### Run the analysis - "Analyze my Search Query Performance for [ASIN]." - "Run an SQP diagnostic on my top sellers for the last month." - "Pull search query performance for [parent ASIN] and all its children." ### Find where you're losing - "For [ASIN], am I losing on visibility, clicks, or conversion?" - "Where in the funnel is [ASIN] leaking — show me the biggest gap." - "Which search terms drive impressions for [ASIN] but no sales?" ### Visibility and SEO - "Which high-volume searches is [ASIN] barely showing up for?" - "What terms should [ASIN] rank for but doesn't?" - "My impression share is low on '[search term]' — what would help?" ### Click-through - "People see [ASIN] but don't click — is it the image or the title?" - "Which queries have strong impressions but a weak click-through rate?" - "Why is my CTR below the benchmark on '[search term]'?" ### Conversion - "People click [ASIN] but don't buy — what's the friction?" - "Where is my click share beating my purchase share?" - "Is it price or shipping that's killing conversion on '[search term]'?" ### Price and shipping - "Am I priced above the market on the terms where I'm losing sales?" - "Which ASINs lose purchases to slow delivery?" - "Show me queries where a faster shipping promise would move the needle." ### Variants and cannibalization - "Are my own variants competing for the same search?" - "Which child ASIN should own '[search term]'?" - "Find where my products eat into each other in search." ### Rank the opportunities - "Rank my search-term opportunities by upside, not just volume." - "What are the ten fixes that would recover the most sales?" - "Give me a prioritized to-do list from this report." ### Sort by who owns the fix - "Split the recommendations into listing fixes, ops fixes, and ad plays." - "Show me only the changes I can make on the listing itself." - "Which of these are shipping or inventory problems, not listing ones?" ### Turn the findings into fixes - "Take my low-CTR ASINs and tell me which images to redo." - "Hand the SEO and copy fixes to the listing optimizer." - "Which of these need a new hero image versus a title rewrite?" Most real sessions chain these together: *"Run SQP for [ASIN]"* → *"Where am I losing?"* → *"It's clicks — is it the image?"* → *"Which terms is this worst on?"* → *"Send those to Iris."* Treat it as a conversation, not a set of one-off commands. ## What it surfaces The analyzer reads each search term as a funnel and tells you where it breaks: - **The funnel, stage by stage** — your impression share, click share, and purchase share for the term, against the market total and your peer set, so the leaking stage is obvious. - **A named cause for every gap**, each pointing at a specific fix: - High-volume term, low impression share → an **SEO and PDP update** toward the intent behind the query. You're invisible for something people search. - Clicks beat impressions but purchases don't keep up → a **conversion fix** on price versus the market median, ratings, or the delivery promise. - CTR below the query benchmark while you hold impression share → a **hero image and title** fix. You show up; you just don't win the click. - Purchases trail clicks with a high slow-shipping share → a **delivery-speed fix** and a clearer delivery promise. - Priced above the market median with weak purchase share → a **bounded price test**. - Underperforming your own brand peers on a term → a **variant fix** or a re-balance of on-page emphasis, so your products stop competing with each other. - **Lift-aware ranking** — every opportunity scored by the size of the gap times the volume behind it, so the list leads with recoverable sales rather than raw search volume. - **Owner tags** — each recommendation marked listing, ops, or ads, so a copy change, a fulfillment change, and a campaign change never get confused for one another. - **Confidence badges** — each finding carries whether it had enough data, which peer benchmarks it used, and its attribution scope, so you can tell a real signal from noise at a glance. ## Straight talk on the numbers Search Query Performance is powerful and easy to over-read. The analyzer holds a few lines so it doesn't send you chasing noise: > It won't make a strong call on thin data. Below a floor of impressions and clicks for a term, it flags the row as thin and softens the recommendation instead of telling you to rebuild a listing over a handful of events. - **The scope is the search results page, over a recent window** — not lifetime, and not every path to a sale. Every finding says so, so you weigh it accordingly. - **It keeps organic and paid apart.** SQP is organic search; it won't compute ACoS or ROAS (return on ad spend) by bolting ad spend onto these totals. Sponsored tactics are tagged separately and routed to your ads workflow. - **It paces changes.** After it recommends a test on a term, it waits out a cooldown before recommending another on the same term, so you measure the result instead of stacking edits you can't tell apart. ## From diagnosis to fix The analyzer tells you where each product loses in search and what to change. It doesn't change anything itself — and the fixes it names are exactly what its companion tools execute. - **"You show up but nobody clicks"** is almost always the main image or the title. [Amazon Agent Iris](/features/amazon-agent-iris/) regenerates a compliant, click-winning hero image from your real product and hosts it where Amazon can fetch it. See the [Iris docs](/docs/amazon-agent-iris/). - **"You're invisible for a term," or "people click but the copy doesn't close"** lives in the listing text. [Amazon Listing Optimizer](/docs/amazon-listing-optimizer/) rewrites titles, bullets, and search terms toward the intent the analyzer found, grounded in the product's real attributes and Amazon's rules, and publishes once you approve. - **The ad-tagged plays** — bids, budget, and placement on the terms where you're strong and want more — belong on the [Amazon Ads MCP](/features/amazon-ads-mcp/). The loop runs in one place: *run the SQP diagnostic → read the ranked gaps → send image gaps to Iris, copy and SEO gaps to the Optimizer, bid gaps to Ads → re-pull next window and watch the share gaps close.* From "where am I losing" to "fixed," without leaving your AI client. ## Limits and honest framing - **It reads; it doesn't change anything.** It diagnoses and ranks; making the changes is a separate, opt-in step. - **Thin data gets soft calls.** Low-traffic terms are flagged, not force-ranked. Give it a window with real volume for confident recommendations. - **Short window, search-page scope.** SQP captures recent search-results behavior, not lifetime performance or every route to purchase. - **Organic only.** It won't blend ad spend into these numbers; ad tactics route to your ads workflow with their own tags. - **It only sees the account you connect.** Every pull is scoped to the selected seller identity and marketplace. ## Related - [Amazon Selling Partner MCP](/features/amazon-selling-partner-mcp/) — the product surface this runs on. - [Amazon Listing Optimizer](/docs/amazon-listing-optimizer/) — execute the SEO, copy, and PDP fixes the analyzer recommends. - [Amazon Agent Iris](/features/amazon-agent-iris/) — regenerate the hero image behind a low click-through rate. - [Amazon Agent Iris docs](/docs/amazon-agent-iris/) — the image generation, audit, and hosting workflow. - [Amazon Ads MCP](/features/amazon-ads-mcp/) — run the bid, budget, and placement plays on terms where you're strong. - [Amazon Agent Atlas](/features/agent-atlas/) — the indexed Amazon knowledge that grounds rule-dependent recommendations. - [MCP client configuration](/docs/mcp-client-configuration/) — connect Claude, ChatGPT, Cursor, and other clients. ### Cloud Deployment Destinations URL: https://www.kuudo.com/docs/cloud/ Use these guides to prepare one or more cloud accounts before creating a deployment environment in the app. Each guide focuses on the provider-side setup: credentials, project or subscription selection, required APIs or resource providers, and a verification step that separates cloud-account problems from product provisioning problems. ## Pick a destination | Provider | Best fit | What you prepare | | --- | --- | --- | | [AWS ECS Express](/docs/cloud/aws-ecs-express-activation-guide/) | AWS accounts that standardize on ECS, ECR, CloudFormation, and IAM roles. | IAM access key, region, CloudFormation permissions, ECR, ECS, logs, and ECS load balancer role permissions. | | [Google Cloud](/docs/cloud/gcp-activation-guide/) | Teams that want Cloud Run with Artifact Registry. | Project ID, Cloud Run region, enabled APIs, service account roles, and a service account JSON key. | | [Azure](/docs/cloud/azure-activation-guide/) | Azure subscriptions using service principals and resource provider registration. | Subscription ID, Tenant ID, Client ID, Client Secret, region, RBAC, and required resource providers. | | [Cloudflare](/docs/cloud/cloudflare-activation-guide/) | Cloudflare Workers, Containers, and R2-backed deployments. | Scoped API token, target account access, Workers permissions, Containers permission, and optional Account ID for troubleshooting. | ## What to have ready Before you open the environment wizard, decide: - Which cloud account, project, or subscription should own the deployment. - Which region or global runtime should host the deployment. - Whether your organization allows long-lived keys, service account keys, API tokens, or client secrets. - Who can create IAM/RBAC bindings and provider registrations. - Where generated credentials will be stored after you paste them into the wizard. ## Security baseline Use dedicated credentials for the deployment workflow. Avoid root keys, personal admin credentials, broad tenant-wide grants, and credentials shared between unrelated systems. Rotate credentials periodically, and rotate immediately when someone leaves the team or a token may have been exposed. Prefer cloud-native temporary credential or managed identity flows when the product supports them; use the documented key, token, or service principal flows when the wizard requires those values directly. ## Verify before provisioning Each provider guide includes a CLI or API verification step. Run it before opening the wizard: - AWS: `sts get-caller-identity`, CloudFormation, ECR, and ECS read checks. - Google Cloud: project metadata, Cloud Run, and Artifact Registry read checks. - Azure: service-principal login and subscription read check. - Cloudflare: accounts API and account read checks. If verification fails locally, fix the cloud setup first. The wizard cannot provision resources with credentials that fail the provider's own read checks. ## Continue Start with the provider you plan to deploy first: - [AWS ECS Express Activation Guide](/docs/cloud/aws-ecs-express-activation-guide/) - [Google Cloud Activation Guide](/docs/cloud/gcp-activation-guide/) - [Azure Activation Guide](/docs/cloud/azure-activation-guide/) - [Cloudflare Activation Guide](/docs/cloud/cloudflare-activation-guide/) ### AWS ECS Express Activation Guide URL: https://www.kuudo.com/docs/cloud/aws-ecs-express-activation-guide/ This guide explains how to prepare AWS so the in-app **environment wizard** (Choose Deployment Pattern → Credentials → Configuration → Review & create) can create infrastructure for the **ECS Express** deployment pattern successfully. **Core idea:** prepare AWS first (usually with the AWS CLI), then paste the access key, secret, and region into the product. The app validates credentials via STS at create time, then provisioning creates a small CloudFormation stack (ECR repository + IAM roles) that ECS Express uses on subsequent deploys. > **About ECS Express** > ECS Express is the lightweight ECS deployment pattern (replacing App Runner). The platform creates only an ECR repository plus two IAM roles up front; ECS Express manages the load balancer, security group, target group, and auto-scaling for each service at deploy time. No VPC, ALB, or cluster pre-provisioning is required. --- ## Quick path 1. Sign in with an AWS user that has IAM admin rights and select the correct account ([§ Sign in and select the account](#sign-in-and-select-the-account)). 2. Pick a region where ECS Express is supported and you want to deploy ([§ Region](#choose-a-region)). 3. Create or reuse a dedicated IAM user for the access-key flow and attach a policy with the required permissions ([§ IAM user](#create-or-reuse-an-iam-user)). 4. Create an access key for that user and save the **Access Key ID** and **Secret Access Key** ([§ Access key](#create-an-access-key)). 5. Verify the credentials can call STS and CloudFormation in your region ([§ Verify the credentials](#verify-the-credentials)). 6. Open the wizard: **Choose Deployment Pattern** → **Credentials** → **Configuration** → **Review & create** ([§ Complete the wizard](#complete-the-wizard-in-the-app)). 7. If something fails, use [§ Common issues](#common-issues). --- ## Prerequisites - Access to the target AWS account. - Permission to create IAM users / policies (for example **AdministratorAccess**, or an equivalent IAM admin). - The **ECS Express** deployment pattern selected when creating the environment in the wizard (the `aws-ecs` pattern uses a different, larger CloudFormation stack). - [AWS CLI v2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) installed locally, or [CloudShell](https://docs.aws.amazon.com/cloudshell/latest/userguide/welcome.html) from the AWS console. The CLI is recommended because console labels and layout change more often than command-line flows. --- ## Field reference The wizard matches AWS outputs like this: | What you do in AWS | Output to copy | Wizard field | | ------------------------------------------------------ | ------------------------------ | ----------------------- | | IAM → Users → Security credentials → Create access key | Access key ID (e.g. `AKIA...`) | **Access Key ID** | | Same dialog | Secret access key (shown once) | **Secret Access Key** | | Your choice of deploy location | Region code, e.g. `us-east-1` | **Region** | | (your label only) | Any name | **Environment Name** | | Account console / `aws sts get-caller-identity` | 12-digit Account ID | _(auto-derived by app)_ | **Account ID vs other IDs:** AWS account ID is still important for verification and troubleshooting, but the current wizard derives it from credentials (STS) instead of asking you to type it. **Region:** lowercase region code with hyphens (e.g. `us-east-1`, `eu-west-1`). List regions enabled on your account: ```bash aws ec2 describe-regions --query "Regions[].RegionName" --output text ``` ECS Express must be available in the region you choose. If you are unsure, start with a major region like `us-east-1` or `us-west-2`. **Access keys are long-lived:** rotate them periodically. AWS recommends temporary credentials where possible; use this IAM-user key flow only when the deployment wizard requires an access key and secret. Create a new key, update the wizard, then deactivate and delete the old one. --- ## Prepare AWS with the CLI Run the steps below as an **AWS admin user** unless noted. Replace placeholders such as ``, ``, and `` with your values. ### Sign in and select the account ```bash aws configure # set admin profile aws sts get-caller-identity --output json ``` From the JSON output, record: - `Account` → **AWS Account ID** ### Choose a region ```bash export AWS_REGION= # e.g. us-east-1 aws ec2 describe-regions \ --query "Regions[?RegionName=='$AWS_REGION'].RegionName" --output text ``` A non-empty result confirms the region is enabled on your account. ### Create or reuse an IAM user Reuse an existing IAM user if it is dedicated to this deployment workflow and already has the right permissions. Avoid root access keys. If your organization prefers IAM roles or AWS IAM Identity Center, use that path only if the deployment wizard supports temporary credentials or role assumption. **Option A — new IAM user:** ```bash aws iam create-user --user-name ``` **Option B — console:** **IAM** → **Users** → **Create user**. ### Attach a permissions policy ECS Express provisioning needs to create a CloudFormation stack containing an ECR repository and two IAM roles, and to manage ECS services, log groups, and (via the ECS Express infrastructure role) elastic load balancing. The simplest path is **PowerUserAccess + IAMFullAccess** (CloudFormation needs IAM to create the execution and infrastructure roles). ```bash aws iam attach-user-policy \ --user-name \ --policy-arn arn:aws:iam::aws:policy/PowerUserAccess aws iam attach-user-policy \ --user-name \ --policy-arn arn:aws:iam::aws:policy/IAMFullAccess ``` For tighter least privilege, use a custom policy with at least these actions, scoped to your account/region as appropriate: | Service / namespace | Why | | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `cloudformation:*` | Create / update / delete the ECS Express infrastructure stack | | `ecr:*` | Manage the ECR repository created by the stack and push images during deploys | | `ecs:*` | Create and update ECS Express services | | `iam:CreateRole`, `iam:GetRole`, `iam:PassRole`, `iam:AttachRolePolicy`, `iam:PutRolePolicy`, `iam:DeleteRole`, `iam:DetachRolePolicy`, `iam:DeleteRolePolicy` | Stack creates the execution and infrastructure roles using `CAPABILITY_NAMED_IAM`; deploys `PassRole` them to ECS | | `logs:*` | Create CloudWatch log groups for ECS tasks | | `elasticloadbalancing:*` | Allow the ECS Express infrastructure role to attach services to managed ALBs | | `sts:GetCallerIdentity` | Discover the AWS account ID at deploy time | > **Why CAPABILITY_NAMED_IAM?** > The stack creates **named** IAM roles (e.g. `mcp--execution-role`, `mcp--infra-role`) so ECS Express can find them by name. CloudFormation requires explicit acknowledgement when a template names IAM resources, which is why the user must have `iam:*` on those role names. Verify: ```bash aws iam list-attached-user-policies --user-name --output table ``` ### Create an access key ```bash aws iam create-access-key --user-name ``` Record `AccessKey.AccessKeyId` (**Access Key ID**) and `AccessKey.SecretAccessKey` (**Secret Access Key**) immediately. The secret is only shown once. Treat it like a password — anyone with these two values can act as the user. > **Rotation** > to rotate, create a second access key, update the wizard, then `aws iam update-access-key --status Inactive` and `aws iam delete-access-key` for the old one. ### Verify the credentials This separates AWS misconfiguration from product issues. Configure a temporary profile that uses the new key, then run a few read calls. ```bash aws configure --profile mcp-deployer # AWS Access Key ID: # AWS Secret Access Key: # Default region name: # Default output format: json # 1. STS works (matches the wizard's identity check) aws sts get-caller-identity --profile mcp-deployer # 2. CloudFormation is reachable in the chosen region aws cloudformation list-stacks --profile mcp-deployer --region \ --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE # 3. ECR is reachable aws ecr describe-repositories --profile mcp-deployer --region \ --max-items 1 || true # 4. ECS is reachable aws ecs list-clusters --profile mcp-deployer --region --max-items 1 ``` If `sts get-caller-identity` returns the expected account ID and the other calls return JSON (even an empty list), authentication and the most-used APIs are working. --- ## Complete the wizard in the app Use the [Field reference](#field-reference) for definitions. ### Choose Deployment Pattern - **Deployment Pattern** — choose **ECS Express** (not the full ECS pattern). ### Credentials - **Environment Name** — label in your app (for example `aws-ecs-express`). - **Access Key ID**, **Secret Access Key**, **Region** — from [§ Access key](#create-an-access-key). ### Configuration - Optional settings page (for ECS Express, no additional required fields). ### Review & create After submit, the platform creates a CloudFormation stack (name pattern `mcp--`) containing: - An **ECR repository** for your container images - An **ECS task execution role** (ECR pull + CloudWatch logs) - An **ECS Express infrastructure role** (manages ALB, security groups, auto-scaling) You can watch progress in the AWS console under **CloudFormation → Stacks**. --- ## Common issues | Symptom or error | Likely cause | What to do | | -------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `InvalidClientTokenId` / `The security token included in the request is invalid` | Wrong access key ID, deactivated key, or typo in secret | Re-create the access key, update the wizard. | | `SignatureDoesNotMatch` | Secret access key copied with extra whitespace or partial value | Re-paste the exact secret from `aws iam create-access-key` output. | | Account ID mismatch / "Account ID does not match credentials" | Pasted the wrong account, or used an alias | Run `aws sts get-caller-identity` and copy the **12-digit `Account` field**. | | Environment creation fails with `AccessDenied` during credential checks | IAM user lacks `sts:GetCallerIdentity` | Attach `PowerUserAccess` (or at least include STS read + required deploy actions in [§ Permissions](#attach-a-permissions-policy)). | | `User: ... is not authorized to perform: iam:CreateRole` | IAM user is missing IAM permissions | Attach `IAMFullAccess` or grant the IAM actions listed in [§ Permissions](#attach-a-permissions-policy). | | `User ... is not authorized to perform: iam:PassRole` during deploy | Deploy step cannot pass the execution role to ECS | Add `iam:PassRole` for the role ARNs created by the stack (or use `*` while developing). | | `Stack mcp- already exists` on retry | Previous provisioning partially completed | The platform will reuse the existing stack on retry. If it is in `ROLLBACK_COMPLETE`, delete it manually with `aws cloudformation delete-stack` and retry. | | Region rejected or `OptInRequired` | Region not enabled on the account, or ECS Express unavailable there | Enable the region in **Account → AWS Regions**, or pick a major region such as `us-east-1` / `us-west-2`. | | Environment created, but deploy fails creating an ALB | ECS Express infrastructure role is missing `elasticloadbalancing:*` | Re-attach `PowerUserAccess`, or add `elasticloadbalancing:*` to your custom policy. | | Pasted **root account access keys** | Root access keys are blocked by AWS best practice | Create a dedicated IAM user, attach the policies, and use that user's access keys. | ## Official references - [AWS IAM: Secure access keys](https://docs.aws.amazon.com/IAM/latest/UserGuide/securing_access-keys.html) - [AWS CloudFormation: Control access with IAM](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/control-access-with-iam.html) - [Amazon ECS infrastructure IAM role for load balancers](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/AmazonECSInfrastructureRolePolicyForLoadBalancers.html) - [Install or update the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) --- ## Appendix: Copy-paste activation script The block below repeats [Prepare AWS with the CLI](#prepare-aws-with-the-cli) in one place for convenience. Replace placeholders before running. ```bash # --- As your AWS admin --- ACCOUNT_ID= REGION= # e.g. us-east-1 USER_NAME= # e.g. mcp-deployer aws configure # admin profile aws sts get-caller-identity --output json # Create dedicated IAM user aws iam create-user --user-name "$USER_NAME" # Attach permissions (broad — see guide for least-privilege alternative) aws iam attach-user-policy \ --user-name "$USER_NAME" \ --policy-arn arn:aws:iam::aws:policy/PowerUserAccess aws iam attach-user-policy \ --user-name "$USER_NAME" \ --policy-arn arn:aws:iam::aws:policy/IAMFullAccess aws iam list-attached-user-policies --user-name "$USER_NAME" --output table # Create access key (capture both fields immediately) aws iam create-access-key --user-name "$USER_NAME" # --- Test as the new user --- aws configure --profile mcp-deployer # paste the new key, secret, region aws sts get-caller-identity --profile mcp-deployer aws cloudformation list-stacks --profile mcp-deployer --region "$REGION" \ --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE aws ecr describe-repositories --profile mcp-deployer --region "$REGION" \ --max-items 1 || true aws ecs list-clusters --profile mcp-deployer --region "$REGION" --max-items 1 ``` After this succeeds, fill the wizard using the [Field reference](#field-reference) and complete [§ Complete the wizard](#complete-the-wizard-in-the-app). ### Google Cloud Activation Guide URL: https://www.kuudo.com/docs/cloud/gcp-activation-guide/ This guide explains how to prepare Google Cloud so the in-app **environment wizard** (Configuration → Credentials → Validation → Review & create) can create infrastructure successfully. **Core idea:** prepare GCP first (usually with the `gcloud` CLI), then copy the project ID, region, and service account key into the product. Validation checks credential and project access, then provisioning verifies Cloud Run access and prepares Artifact Registry. --- ## Quick path 1. Sign in with your Google account and select the correct project ([§ Sign in and select the project](#sign-in-and-select-the-project)). 2. Enable the required APIs: **Cloud Run**, **Artifact Registry**, **Cloud Resource Manager** ([§ Enable APIs](#enable-required-apis)). 3. Create or reuse a service account and grant it the right roles ([§ Service account](#create-or-reuse-a-service-account)). 4. Create a JSON key for the service account and save the file ([§ Service account key](#create-a-service-account-key)). 5. Verify the key works against your project ([§ Verify the service account](#verify-the-service-account)). 6. Open the wizard: **Configuration** → **Credentials** → run **Validation** → **Review & create** ([§ Complete the wizard](#complete-the-wizard-in-the-app)). 7. If something fails, use [§ Common issues](#common-issues). --- ## Prerequisites - Access to the target Google Cloud project. - Permission to grant IAM roles (for example **Owner** or **IAM Admin**) when binding roles to the service account. - Billing **enabled** on the project (Cloud Run and Artifact Registry require it, even at $0 usage). - [`gcloud` CLI](https://cloud.google.com/sdk/docs/install) installed locally, or [Cloud Shell](https://cloud.google.com/shell) from the GCP console. The CLI is recommended because console labels and layout change more often than command-line flows. --- ## Field reference The wizard matches GCP outputs like this: | What you do in GCP | Output to copy | Wizard field | | -------------------------------------------------- | ---------------------------------------- | ------------------------------ | | Project picker / `gcloud config get-value project` | Project ID (not the project number/name) | **Project ID** | | Your choice of deploy location | Cloud Run region, e.g. `us-central1` | **Region** (Credentials step) | | IAM & Admin → Service Accounts → Keys → Add Key | Downloaded **JSON file contents** | **Service Account Key (JSON)** | | (your label only) | Any name | **Environment Name** | **Project ID vs project number vs project name:** the wizard wants the **Project ID** (e.g. `my-mcp-project-481923`), which is a lowercase string with optional digits/dashes — not the numeric project number and not the human-readable display name. **Region:** use a valid Cloud Run region identifier (lowercase with hyphens). List supported regions: ```bash gcloud run regions list ``` **Service Account Key (JSON):** paste the **entire contents** of the downloaded JSON file, including the `{ ... }` braces. The wizard validates that it has `type: "service_account"`, a PEM-formatted `private_key`, and a `client_email` ending in `.iam.gserviceaccount.com`. Google recommends avoiding user-managed service account keys when a safer alternative is available; use this key flow only when the deployment wizard requires a JSON key. --- ## Prepare GCP with the CLI Run the steps below as **your GCP user/admin** unless noted. Replace placeholders such as `` and `` with your values. ### Sign in and select the project ```bash gcloud auth login gcloud projects list gcloud config set project gcloud config get-value project ``` Record the value of `gcloud config get-value project` — this becomes the wizard's **Project ID**. ### Enable required APIs These APIs are required for the MCP deployment path described here: - `run.googleapis.com` — Cloud Run (runtime) - `artifactregistry.googleapis.com` — Artifact Registry (private image storage) - `cloudresourcemanager.googleapis.com` — Resource Manager (used by validation to fetch project metadata) ```bash gcloud services enable \ run.googleapis.com \ artifactregistry.googleapis.com \ cloudresourcemanager.googleapis.com \ --project ``` Verify (each should appear in the list): ```bash gcloud services list --enabled --project \ --filter="config.name:(run.googleapis.com OR artifactregistry.googleapis.com OR cloudresourcemanager.googleapis.com)" \ --format="value(config.name)" ``` API enablement can take a minute or two to propagate. If validation fails immediately after enabling, wait and retry. ### Create or reuse a service account Reuse an existing service account if you already have one with the right roles. **Option A — new service account (quick setup):** ```bash gcloud iam service-accounts create \ --display-name "MCP Deployment Service Account" \ --project ``` The full email becomes `@.iam.gserviceaccount.com`. **Option B — console:** **IAM & Admin** → **Service Accounts** → **Create service account**. ### Grant IAM roles Validation needs the service account to read project metadata; provisioning needs permission to manage Cloud Run services and Artifact Registry repositories. Grant these roles at **project scope**: | Role | Why | | ------------------------------------------ | --------------------------------------------------------------- | | `roles/run.developer` | Create, update, and delete Cloud Run services | | `roles/artifactregistry.admin` | First-run repository creation + image push in Artifact Registry | | `roles/iam.serviceAccountUser` | Allow Cloud Run to act as the runtime service account | | `roles/serviceusage.serviceUsageConsumer` | Commonly required in org policies for service usage checks | | `roles/viewer` (or equivalent read access) | Read project metadata (`cloudresourcemanager.projects.get`) | ```bash SA_EMAIL=@.iam.gserviceaccount.com for ROLE in \ roles/run.developer \ roles/artifactregistry.admin \ roles/iam.serviceAccountUser \ roles/serviceusage.serviceUsageConsumer \ roles/viewer do gcloud projects add-iam-policy-binding \ --member "serviceAccount:$SA_EMAIL" \ --role "$ROLE" done ``` Verify: ```bash gcloud projects get-iam-policy \ --flatten="bindings[].members" \ --filter="bindings.members:$SA_EMAIL" \ --format="value(bindings.role)" ``` You should see these roles listed for that service account. > **Least privilege note** > For tighter scoping, replace `roles/artifactregistry.admin` with `roles/artifactregistry.writer` **after** the repository has been created the first time. Initial provisioning may need repository-create permissions. > **Public endpoint note** > If deployments succeed but your endpoint still requires authentication, add `roles/run.admin` so the deploy flow can set the Cloud Run service IAM policy and grant `roles/run.invoker` to `allUsers`. ### Create a service account key ```bash gcloud iam service-accounts keys create ./mcp-sa-key.json \ --iam-account "$SA_EMAIL" \ --project ``` This writes a JSON file. Open it and copy the **entire contents** when filling out the wizard. Treat this file as secret — anyone with it can act as the service account. > **Key rotation** > GCP service account keys do not expire by default but should be rotated periodically. List existing keys with `gcloud iam service-accounts keys list --iam-account "$SA_EMAIL"`, create a new one, update the wizard, then delete the old key with `gcloud iam service-accounts keys delete --iam-account "$SA_EMAIL"`. ### Verify the service account This separates GCP misconfiguration from product issues. Activate the key and run a few read-only calls. ```bash gcloud auth activate-service-account --key-file ./mcp-sa-key.json gcloud config set project # 1. Project is readable (matches the wizard's validation call) gcloud projects describe # 2. Cloud Run API is enabled and listable gcloud run services list --region # 3. Artifact Registry is accessible gcloud artifacts repositories list --location ``` If all three calls succeed, authentication, project access, and the required APIs are working. Switch back to your user account when done: ```bash gcloud auth login gcloud config set account ``` --- ## Complete the wizard in the app Use the [Field reference](#field-reference) for definitions. ### Configuration - **Environment Name** — label in your app (for example `gcp`). - **Project ID** — GCP project ID from [§ Sign in](#sign-in-and-select-the-project). - **Region** — Cloud Run region, e.g. `us-central1`. ### Credentials - **Service Account Key (JSON)** — paste the full contents of the JSON file from [§ Service account key](#create-a-service-account-key). ### Validation Run validation in the UI. It should succeed when the key parses cleanly and the service account can read the project via Resource Manager. Cloud Run API access checks and Artifact Registry repository preparation happen during provisioning right after **Review & create**. ### Review & create After validation succeeds, finish creating the environment. --- ## Common issues | Symptom or error | Likely cause | What to do | | ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `Missing required field: ` from validation | Pasted only part of the JSON, or pasted a non-key file | Re-paste the **entire** JSON file contents, including `{` and `}`. | | `Invalid private key format. Expected PEM format.` | Newlines mangled when copy/pasting (e.g. `\n` literals replaced) | Re-download or re-open the original JSON file and paste it exactly — do not edit. | | `Invalid service account email format` | Pasted a user OAuth credential, not a service account key | Create a key under **IAM & Admin → Service Accounts**, not **APIs & Services → Credentials**. | | Validation succeeds, but provisioning fails with `Cloud Run API is not enabled` | `run.googleapis.com` is disabled on the project | `gcloud services enable run.googleapis.com` ([§ Enable APIs](#enable-required-apis)). Wait 1–2 minutes and retry. | | Validation succeeds, but provisioning fails with `PERMISSION_DENIED` listing Cloud Run services | Service account is missing **Cloud Run Developer** | Add `roles/run.developer` ([§ IAM roles](#grant-iam-roles)). | | Validation succeeds, but provisioning fails creating Artifact Registry repository | Service account is missing repository-create permission | Add `roles/artifactregistry.admin` for first run, then consider downgrading to `roles/artifactregistry.writer`. | | Deployment works but service URL requires auth | Service account cannot set IAM policy for unauthenticated invoker | Add `roles/run.admin` and redeploy so `roles/run.invoker` can be granted to `allUsers`. | | `Permission 'resourcemanager.projects.get' denied` | Project ID is wrong, or the SA can't read the project | Confirm `gcloud config get-value project` matches **Project ID**; ensure the SA has any role on the project (e.g. `roles/viewer`). | | `Billing has not been enabled` | Project has no billing account attached | Link a billing account in the GCP console (**Billing → Link a billing account**), then retry. | | Pasted the **project number** (e.g. `483921047215`) instead of the Project ID | Wrong identifier | Use the lowercase string from `gcloud config get-value project`, not the numeric project number. | | Region rejected or `Cloud Run not available in ` | Region typo or unsupported region | Pick a value from `gcloud run regions list`. | | Key recently created but validation still fails with auth errors | IAM/key propagation delay | Wait ~60 seconds and retry; GCP IAM is eventually consistent. | ## Official references - [Cloud Run IAM roles](https://cloud.google.com/run/docs/reference/iam/roles) - [Cloud Run regions](https://cloud.google.com/run/docs/locations) - [Artifact Registry roles and permissions](https://cloud.google.com/artifact-registry/docs/access-control) - [Best practices for managing service account keys](https://cloud.google.com/iam/docs/best-practices-for-managing-service-account-keys) - [Install the Google Cloud CLI](https://cloud.google.com/sdk/docs/install) --- ## Appendix: Copy-paste activation script The block below repeats [Prepare GCP with the CLI](#prepare-gcp-with-the-cli) in one place for convenience. Replace placeholders before running. ```bash # --- As your GCP user --- PROJECT_ID= REGION= # e.g. us-central1 SA_NAME= # e.g. mcp-deployer SA_EMAIL="$SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" gcloud auth login gcloud config set project "$PROJECT_ID" # Enable APIs gcloud services enable \ run.googleapis.com \ artifactregistry.googleapis.com \ cloudresourcemanager.googleapis.com \ --project "$PROJECT_ID" # Create service account gcloud iam service-accounts create "$SA_NAME" \ --display-name "MCP Deployment Service Account" \ --project "$PROJECT_ID" # Grant roles for ROLE in \ roles/run.developer \ roles/artifactregistry.admin \ roles/iam.serviceAccountUser \ roles/serviceusage.serviceUsageConsumer \ roles/viewer do gcloud projects add-iam-policy-binding "$PROJECT_ID" \ --member "serviceAccount:$SA_EMAIL" \ --role "$ROLE" done # Create JSON key (treat as secret) gcloud iam service-accounts keys create ./mcp-sa-key.json \ --iam-account "$SA_EMAIL" \ --project "$PROJECT_ID" # --- Test as the service account --- gcloud auth activate-service-account --key-file ./mcp-sa-key.json gcloud config set project "$PROJECT_ID" gcloud projects describe "$PROJECT_ID" gcloud run services list --region "$REGION" gcloud artifacts repositories list --location "$REGION" ``` After this succeeds, fill the wizard using the [Field reference](#field-reference) and complete [§ Complete the wizard](#complete-the-wizard-in-the-app). ### Azure Activation Guide URL: https://www.kuudo.com/docs/cloud/azure-activation-guide/ This guide explains how to prepare Azure so the in-app **environment wizard** (Configuration → Credentials → Validation → Review & create) can create infrastructure successfully. **Core idea:** every value you paste into the wizard is an **output of Azure setup**. Prepare Azure first (usually with the Azure CLI), then copy IDs and secrets into the product. --- ## Quick path 1. Sign in with your user account and select the correct subscription ([§ Sign in and select the subscription](#sign-in-and-select-the-subscription)). 2. Create or reuse an app registration / service principal and save **Client ID**, **Client Secret** (value), and **Tenant ID** ([§ Service principal](#create-or-reuse-a-service-principal)). 3. Grant the service principal **Contributor** on that subscription ([§ RBAC](#grant-rbac-on-the-subscription)). 4. Register **Microsoft.ContainerRegistry** and **Microsoft.App** ([§ Resource providers](#register-resource-providers)). 5. Log in as the service principal and confirm subscription access ([§ Verify the service principal](#verify-the-service-principal)). 6. Open the wizard: **Configuration** → **Credentials** → run **Validation** → **Review & create** ([§ Complete the wizard](#complete-the-wizard-in-the-app)). 7. If something fails, use [§ Common issues](#common-issues). --- ## Prerequisites - Access to the target Azure subscription. - Permission to assign RBAC (for example **Owner** or **User Access Administrator**) when granting the service principal access. - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) installed locally, or [Azure Cloud Shell](https://learn.microsoft.com/en-us/azure/cloud-shell/overview). The CLI is recommended because portal labels and layout change more often than command-line flows. --- ## Field reference The wizard matches Azure outputs like this: | What you do in Azure | Output to copy | Wizard field | | ------------------------------------ | ------------------------------------ | ---------------------------------------- | | Microsoft Entra ID (tenant) | Tenant ID | **Tenant ID (Directory ID)** | | Subscription | Subscription ID | **Subscription ID** (Configuration step) | | App registration / service principal | Application (client) ID | **Client ID (Application ID)** | | Certificates & secrets | **Secret value** (not the secret ID) | **Client Secret** | | Your choice of deploy location | Region name, e.g. `eastus` | **Region** | | (your label only) | Any name | **Environment Name** | **Subscription ID vs Tenant ID:** both look like GUIDs (for example `eb620971-347b-41f1-bb45-e9c8b4f5020d`), but they are different. **Subscription ID** belongs in **Configuration**; **Tenant ID** belongs in **Credentials**. **Region:** use a valid Azure region identifier (lowercase, no spaces). List names for your subscription: ```bash az account list-locations --query "[].name" -o tsv ``` --- ## Prepare Azure with the CLI Run the steps below as **your Azure user/admin** unless noted. Replace placeholders such as `` and `` with your values. ### Sign in and select the subscription ```bash az login az account list --output table az account set --subscription az account show --output json ``` From the JSON output, record: - `subscription.id` → **Subscription ID** - `tenantId` → **Tenant ID** ### Create or reuse a service principal Reuse an existing app registration if you already have one. **Option A — new service principal (quick setup):** ```bash az ad sp create-for-rbac --name ``` Note `appId` (**Client ID**), `password` (**Client Secret**), and `tenant` (**Tenant ID**). Save the secret immediately; it is not shown again. **Option B — portal:** create an app registration in Microsoft Entra ID, add a **client secret** under **Certificates & secrets**, and copy the **Value** column (not the Secret ID). **Option C — new secret for an existing app:** ```bash az ad app credential reset --id --append ``` Use `--append` when rotating so Azure adds a second credential instead of replacing existing credentials. In production, prefer adding a second secret, updating the wizard, verifying deployment, then removing the old secret. Entra secrets **expire**. When one expires, create a new secret and update **Client Secret** in the wizard. ### Grant RBAC on the subscription Validation needs the service principal to read the subscription; provisioning needs permissions to create resources (resource groups, Container Apps, registries, etc.). **Contributor** at subscription scope is the usual choice. ```bash az login az account set --subscription az role assignment create \ --assignee \ --role Contributor \ --scope /subscriptions/ ``` Verify: ```bash az role assignment list \ --assignee \ --scope /subscriptions/ \ --output table ``` You should see **Contributor** for that service principal on the subscription. For tighter least privilege, some organizations scope **Contributor** to a **resource group** instead of the whole subscription. That only works if all resources the worker creates stay inside that group. ### Register resource providers Provisioning fails if the subscription is not registered for the services in use. These namespaces are required for the MCP deployment path described here: - `Microsoft.ContainerRegistry` - `Microsoft.App` ```bash az account set --subscription az provider register --namespace Microsoft.ContainerRegistry --wait az provider register --namespace Microsoft.App --wait ``` Verify (each should print `Registered`): ```bash az provider show --namespace Microsoft.ContainerRegistry --query registrationState -o tsv az provider show --namespace Microsoft.App --query registrationState -o tsv ``` Depending on what the worker provisions, you may also need: ```bash az provider register --namespace Microsoft.OperationalInsights --wait az provider register --namespace Microsoft.ManagedIdentity --wait az provider register --namespace Microsoft.Network --wait ``` ### Verify the service principal This separates Azure misconfiguration from product issues. ```bash az logout az login --service-principal \ --username \ --password \ --tenant az account set --subscription az rest \ --method get \ --url "https://management.azure.com/subscriptions/?api-version=2020-01-01" ``` If this returns subscription JSON, authentication and subscription access are working. --- ## Complete the wizard in the app Use the [Field reference](#field-reference) for definitions. ### Configuration - **Environment Name** — label in your app (for example `azure`). - **Subscription ID** — Azure subscription GUID from [§ Sign in](#sign-in-and-select-the-subscription). ### Credentials - **Tenant ID**, **Client ID**, **Client Secret** (secret **value**), **Region** — from Entra and the service principal ([§ Service principal](#create-or-reuse-a-service-principal), [§ Sign in](#sign-in-and-select-the-subscription)). ### Validation Run validation in the UI. It should succeed when the secret is valid, tenant and subscription IDs are correct, and the service principal can read the subscription. ### Review & create After validation succeeds, finish creating the environment. --- ## Common issues | Symptom or error | Likely cause | What to do | | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | | Tenant ID pasted into **Subscription ID** (or the reverse) | Same GUID shape, wrong meaning | Put subscription GUID in **Configuration**; tenant GUID in **Credentials** ([Field reference](#field-reference)). | | `AADSTS7000215 Invalid client secret provided` | Wrong secret, expired secret, or **Secret ID** used instead of **Value** | Create a new client secret; copy the **value**; update the wizard. | | Validation OK but provisioning fails with insufficient access | **Reader** only, or wrong scope | Use **Contributor** (or equivalent) on the subscription or target resource group ([§ RBAC](#grant-rbac-on-the-subscription)). | | `Microsoft.Resources/subscriptions/read` (or similar read denial) | SP cannot read the subscription | Assign **Reader** or **Contributor** on the correct subscription; confirm **Subscription ID**. | | `roleAssignments/write` when running CLI | Current user cannot assign RBAC | Sign in as an admin or a user with **Owner** / **User Access Administrator** on the subscription. | | Role assignment commands do nothing useful while logged in as the SP | SP cannot grant itself roles | Use your **user** account for `az role assignment create`. | | `The subscription is not registered to use namespace 'Microsoft.App'` or `'Microsoft.ContainerRegistry'` | Resource provider not registered | `az provider register --namespace --wait` ([§ Resource providers](#register-resource-providers)). | | `The subscription is not registered to use namespace 'Microsoft.X'` | Other provider missing | `az provider register --namespace Microsoft.X --wait` | ## Official references - [Create an Azure service principal with Azure CLI](https://learn.microsoft.com/en-us/cli/azure/azure-cli-sp-tutorial-1) - [Azure resource providers and types](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-providers-and-types) - [Azure built-in roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles) - [Install the Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) --- ## Appendix: Copy-paste activation script The block below repeats [Prepare Azure with the CLI](#prepare-azure-with-the-cli) in one place for convenience. Replace placeholders before running. ```bash # --- As your Azure user --- az login az account list --output table az account set --subscription # RBAC (Contributor on subscription) az role assignment create \ --assignee \ --role Contributor \ --scope /subscriptions/ az role assignment list \ --assignee \ --scope /subscriptions/ \ --output table # Required providers az provider register --namespace Microsoft.ContainerRegistry --wait az provider register --namespace Microsoft.App --wait az provider show --namespace Microsoft.ContainerRegistry --query registrationState -o tsv az provider show --namespace Microsoft.App --query registrationState -o tsv # --- Test as the service principal --- az logout az login --service-principal \ --username \ --password \ --tenant az account set --subscription az rest \ --method get \ --url "https://management.azure.com/subscriptions/?api-version=2020-01-01" ``` After this succeeds, fill the wizard using the [Field reference](#field-reference) and complete [§ Complete the wizard](#complete-the-wizard-in-the-app). ### Cloudflare Activation Guide URL: https://www.kuudo.com/docs/cloud/cloudflare-activation-guide/ This guide explains how to prepare Cloudflare so the in-app **environment wizard** (Configuration → Credentials with inline Validate → Review & create) can create infrastructure successfully. **Core idea:** prepare Cloudflare first (in the dashboard, optionally verified with `curl` or `wrangler`), then paste your API token into the product. The app derives account details from that token during validation. --- ## Quick path 1. Sign in to the [Cloudflare dashboard](https://dash.cloudflare.com) and select the correct account ([§ Sign in and select the account](#sign-in-and-select-the-account)). 2. (Optional) Copy the **Account ID** from account home for troubleshooting ([§ Account ID](#copy-the-account-id-optional)). 3. Create an **API token** with the required Cloudflare permissions and save the **token value** ([§ API token](#create-an-api-token)). 4. Confirm the token can read your account ([§ Verify the token](#verify-the-api-token)). 5. Open the wizard: **Configuration** → **Credentials** (click **Validate**) → **Review & create** ([§ Complete the wizard](#complete-the-wizard-in-the-app)). 6. If something fails, use [§ Common issues](#common-issues). --- ## Prerequisites - Access to the target Cloudflare account. - Permission to create API tokens for that account (Super Administrator, or a role that includes "Account API Tokens: Edit"). - Optional: [`wrangler`](https://developers.cloudflare.com/workers/wrangler/install-and-update/) installed locally, or any tool that can call `https://api.cloudflare.com`. The dashboard is recommended for token creation because tokens can only be created from the UI. CLI tools are useful for verification. --- ## Field reference The wizard matches Cloudflare outputs like this: | What you do in Cloudflare | Output to copy | Wizard field | | -------------------------------------- | ------------------------------- | -------------------------------- | | My Profile → API Tokens → Create Token | **Token value** (shown once) | **Cloudflare API Token** | | (your label only) | Any name | **Environment Name** | | Account home → right sidebar | Account ID (optional reference) | _(auto-derived during validate)_ | **Account ID vs Token:** the Account ID is a 32-character hex string (for example `a1b2c3d4e5f67890abcdef1234567890`). The API token is a longer secret string starting with letters and numbers — **not** a Global API Key. Never use the Global API Key with this wizard; it grants too much access and is not scoped to the resources we provision. **Workers subdomain** (`.workers.dev`) is discovered automatically during provisioning/deployment flows; you do not need to enter it. **Region:** Cloudflare runs on a global anycast network, so there is no region field. Containers and Workers are placed automatically near end-users. --- ## Prepare Cloudflare with the dashboard Run the steps below as **a Cloudflare account admin**. ### Sign in and select the account 1. Open . 2. If you belong to multiple accounts, pick the correct one from the account switcher (top-left). ### Copy the Account ID (optional) 1. Click the account name to land on the **account home** page. 2. In the right sidebar, find **Account ID** and click the copy icon. 3. Save it as a troubleshooting reference (the wizard does not ask for Account ID directly). You can also retrieve it with `wrangler`: ```bash wrangler whoami ``` The output lists the accounts your current `wrangler` login can see along with their IDs. ### Create an API token 1. Top-right avatar → **My Profile** → **API Tokens** → **Create Token**. 2. Choose **Create Custom Token** (the templates do not include Containers). 3. Name it something memorable, e.g. `mcp-deployment-token`. 4. Add the following **permissions** (all Account-scoped): | Resource | Permission | | ------------------------------- | ---------- | | Account → Account Settings | Read | | Account → Workers Scripts | Edit | | Account → Workers Scripts | Read | | Account → Workers R2 Storage | Edit | | Account → Containers | Edit | 5. Under **Account Resources**, select **Include → Specific account → \**. 6. Leave **Client IP Address Filtering** blank unless you have a fixed egress IP. 7. **TTL:** leave open-ended unless your security policy requires expiry. If you set a TTL, you will need to rotate the token in the wizard before it expires. 8. Click **Continue to summary** → **Create Token**. 9. Copy the **token value immediately**. Cloudflare only shows it once. > **Why these permissions?** > Account Settings: Read enables account discovery during token validation. Workers Scripts permissions support worker deployment and reads. Containers is required for container-based MCP runtime. Workers R2 Storage is needed when attaching R2-backed storage. If you need to rotate later: return to **My Profile → API Tokens**, click the existing token → **Roll**, then update **API Token** in the wizard. ### Verify the API token This separates Cloudflare misconfiguration from product issues. Replace `` and `` with your values. ```bash # 1. Token can read accounts (matches the wizard's validation call) curl -sS https://api.cloudflare.com/client/v4/accounts \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" # 2. Token can read the specific account you intend to deploy to curl -sS https://api.cloudflare.com/client/v4/accounts/ \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" # 3. Optional: token self-verification endpoint # Note: some account-scoped tokens may not return useful results here. curl -sS https://api.cloudflare.com/client/v4/user/tokens/verify \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" ``` `/accounts` and `/accounts/` should return JSON with `"success": true`. If `accounts` returns an empty `result` array, the token is missing **Account Settings: Read** or is scoped to the wrong account. You can also verify with `wrangler` by exporting the token: ```bash export CLOUDFLARE_API_TOKEN= export CLOUDFLARE_ACCOUNT_ID= wrangler whoami ``` --- ## Complete the wizard in the app Use the [Field reference](#field-reference) for definitions. ### Configuration - **Environment Name** — label in your app (for example `cloudflare`). ### Credentials - **API Token** — token **value** from [§ API token](#create-an-api-token). ### Validation Run validation in the UI (Credentials step → **Validate**). It should succeed when the token is valid and can list at least one account. The app derives account details from that result. ### Review & create After validation succeeds, finish creating the environment. --- ## Common issues | Symptom or error | Likely cause | What to do | | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `Invalid API token` / HTTP 401 from `tokens/verify` | Wrong token, expired token, or Global API Key pasted instead | Create a new API token (not a Global API Key); copy the value; update the wizard ([§ API token](#create-an-api-token)). | | `No Cloudflare accounts found. Your API token may not have 'Account Settings: Read' permission.` | Token missing **Account Settings: Read** | Edit the token and add **Account → Account Settings: Read**, then re-run validation. | | Validation OK but provisioning fails with `Authentication error` on Workers/Containers/R2 | Token missing **Edit** on one of the required resources | Edit the token and add **Workers Scripts: Edit**, **Containers: Edit**, **Workers R2 Storage: Edit** ([§ API token](#create-an-api-token)). | | Validation says no account found | Token cannot list accounts or is scoped to a different account | Confirm **Account Settings: Read** and that token **Account Resources** include the target account. | | `workers.dev subdomain not configured` during deployment | The account has never enabled a Workers subdomain | Visit **Workers & Pages → Overview** in the dashboard once to provision the subdomain, then retry provisioning/deployment. | | Token expires unexpectedly | TTL was set when the token was created | **My Profile → API Tokens → Roll** the token, paste the new value into the wizard, and consider removing the TTL. | | `Containers` permission not visible when creating the token | Account is not enrolled in Cloudflare Containers | Enable Cloudflare Containers from **Workers & Pages → Containers**, then create the token. | | Pasted the **Global API Key** instead of an API token | Wrong credential type | Create an API token via **My Profile → API Tokens → Create Token**; never use the Global API Key here. | ## Official references - [Cloudflare API token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/) - [Wrangler commands](https://developers.cloudflare.com/workers/wrangler/commands/) - [Wrangler configuration](https://developers.cloudflare.com/workers/wrangler/configuration/) - [Cloudflare API reference](https://developers.cloudflare.com/api/) --- ## Appendix: Copy-paste verification script The block below repeats [§ Verify the token](#verify-the-api-token) in one place for convenience. Replace placeholders before running. ```bash export CLOUDFLARE_API_TOKEN= export CLOUDFLARE_ACCOUNT_ID= # Token can list accounts (matches wizard validation) curl -sS https://api.cloudflare.com/client/v4/accounts \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" # Token can read the specific account curl -sS "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" # Optional: token self-verification endpoint curl -sS https://api.cloudflare.com/client/v4/user/tokens/verify \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" # Optional: confirm with wrangler wrangler whoami ``` After this succeeds, fill the wizard using the [Field reference](#field-reference) and complete [§ Complete the wizard](#complete-the-wizard-in-the-app).