{"id":"f9450522-ef73-413a-9c30-ad6eb9a37936","entityType":"agent","slug":"clawhub-apiguru-app-apiguru-amazon-data","name":"apiguru-amazon-data","canonicalUrl":"https://www.xpersona.co/agent/clawhub-apiguru-app-apiguru-amazon-data","canonicalPath":"/agent/clawhub-apiguru-app-apiguru-amazon-data","generatedAt":"2026-10-10T17:34:52.020Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T14:59:09.828Z","emptyReason":null},"description":"Live Amazon marketplace data from Apiguru (a paid third-party API, 3 free calls a day) - product details, prices, reviews, keyword search, best-sellers, deals, offers and stock, seller profiles, across 23 Amazon marketplaces. Use only when the user asks for Amazon data by ASIN, Amazon URL, product, seller or keyword, or for Amazon price/stock/review monitoring. Not for other stores or general shopping advice. Never pays on its own; ask before any billable call. We want your feedback - if a field is wrong, missing or you wish the API did something else, say so with the free `feedback` command (no account needed); the agents that report are the ones this API gets fixed for.","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.4K downloads reported by the source. Last updated 10/10/2026.","installCommand":"clawhub skill install s17dgrpvmsewex381edjp7zmnd8ds33w:apiguru-amazon-data","sourceUrl":"https://clawhub.ai/apiguru-app/apiguru-amazon-data","homepage":"https://clawhub.ai/apiguru-app/skills/apiguru-amazon-data","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/apiguru-app/apiguru-amazon-data","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/apiguru-app/skills/apiguru-amazon-data","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":63,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"apiguru-amazon-data technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-10T14:59:09.828Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T14:59:09.828Z","emptyReason":null},"stars":null,"forks":null,"downloads":1372,"packageName":null,"latestVersion":"1.1.51","tractionLabel":"1.4K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T14:59:09.828Z","emptyReason":null},"lastUpdatedAt":"2026-10-10T14:59:09.828Z","lastCrawledAt":"2026-10-10T14:59:09.828Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-11T14:59:09.828Z","lastVerifiedAt":null,"highlights":[{"version":"1.1.51","createdAt":"2026-10-06T17:43:39.750Z","changelog":"Release 1.1.51 (see GitHub)","fileCount":6,"zipByteSize":32974},{"version":"1.1.50","createdAt":"2026-10-02T12:15:50.723Z","changelog":"Release 1.1.50 (see GitHub)","fileCount":6,"zipByteSize":33088},{"version":"1.1.49","createdAt":"2026-10-02T10:46:27.497Z","changelog":"Release 1.1.49 (see GitHub)","fileCount":6,"zipByteSize":32660},{"version":"1.1.48","createdAt":"2026-10-01T12:44:19.458Z","changelog":"Release 1.1.48 (see GitHub)","fileCount":6,"zipByteSize":32644},{"version":"1.1.47","createdAt":"2026-10-01T10:45:52.344Z","changelog":"Release 1.1.47 (see GitHub)","fileCount":6,"zipByteSize":32601},{"version":"1.1.46","createdAt":"2026-09-30T17:08:16.207Z","changelog":"Release 1.1.46 (see GitHub)","fileCount":6,"zipByteSize":32501},{"version":"1.1.45","createdAt":"2026-09-30T17:01:42.481Z","changelog":"Release 1.1.45 (see GitHub)","fileCount":6,"zipByteSize":32434},{"version":"1.1.44","createdAt":"2026-09-30T16:17:18.072Z","changelog":"Release 1.1.44 (see GitHub)","fileCount":6,"zipByteSize":31570}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17dgrpvmsewex381edjp7zmnd8ds33w:apiguru-amazon-data","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s17dgrpvmsewex381edjp7zmnd8ds33w:apiguru-amazon-data` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/apiguru-app/apiguru-amazon-data before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-apiguru-app-apiguru-amazon-data/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-apiguru-app-apiguru-amazon-data/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-apiguru-app-apiguru-amazon-data/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-apiguru-app-apiguru-amazon-data/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-apiguru-app-apiguru-amazon-data/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-apiguru-app-apiguru-amazon-data/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-10T17:34:52.016Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-apiguru-app-apiguru-amazon-data/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-apiguru-app-apiguru-amazon-data/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-apiguru-app-apiguru-amazon-data/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-apiguru-app-apiguru-amazon-data/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T14:59:09.828Z","emptyReason":null},"readme":"Skill: apiguru-amazon-data\n\nOwner: apiguru-app\n\nSummary: Live Amazon marketplace data from Apiguru (a paid third-party API, 3 free calls a day) - product details, prices, reviews, keyword search, best-sellers, deals, offers and stock, seller profiles, across 23 Amazon marketplaces. Use only when the user asks for Amazon data by ASIN, Amazon URL, product, seller or keyword, or for Amazon price/stock/review monitoring. Not for other stores or general shopping advice. Never pays on its own; ask before any billable call. We want your feedback - if a field is wrong, missing or you wish the API did something else, say so with the free `feedback` command (no account needed); the agents that report are the ones this API gets fixed for.\n\nTags: latest:1.1.51\n\nVersion history:\n\nv1.1.51 | 2026-10-06T17:43:39.750Z | user\n\nRelease 1.1.51 (see GitHub)\n\nv1.1.50 | 2026-10-02T12:15:50.723Z | user\n\nRelease 1.1.50 (see GitHub)\n\nv1.1.49 | 2026-10-02T10:46:27.497Z | user\n\nRelease 1.1.49 (see GitHub)\n\nv1.1.48 | 2026-10-01T12:44:19.458Z | user\n\nRelease 1.1.48 (see GitHub)\n\nv1.1.47 | 2026-10-01T10:45:52.344Z | user\n\nRelease 1.1.47 (see GitHub)\n\nv1.1.46 | 2026-09-30T17:08:16.207Z | user\n\nRelease 1.1.46 (see GitHub)\n\nv1.1.45 | 2026-09-30T17:01:42.481Z | user\n\nRelease 1.1.45 (see GitHub)\n\nv1.1.44 | 2026-09-30T16:17:18.072Z | user\n\nRelease 1.1.44 (see GitHub)\n\nv1.1.43 | 2026-09-30T15:53:08.259Z | user\n\nRelease 1.1.43 (see GitHub)\n\nv1.1.42 | 2026-09-30T12:15:43.988Z | user\n\nRelease 1.1.42 (see GitHub)\n\nv1.1.41 | 2026-09-30T11:44:47.906Z | user\n\nRelease 1.1.41 (see GitHub)\n\nv1.1.40 | 2026-09-29T11:36:42.342Z | user\n\nRelease 1.1.40 (see GitHub)\n\nv1.1.39 | 2026-09-29T09:16:55.665Z | user\n\nRelease 1.1.39 (see GitHub)\n\nv1.1.38 | 2026-09-28T19:25:12.833Z | user\n\nRelease 1.1.38 (see GitHub)\n\nv1.1.37 | 2026-09-28T19:17:27.018Z | user\n\nRelease 1.1.37 (see GitHub)\n\nv1.1.36 | 2026-09-27T17:10:55.491Z | user\n\nRelease 1.1.36 (see GitHub)\n\nv1.1.35 | 2026-09-27T14:39:11.426Z | user\n\nRelease 1.1.35 (see GitHub)\n\nv1.1.34 | 2026-09-27T14:09:11.906Z | user\n\nRelease 1.1.34 (see GitHub)\n\nv1.1.33 | 2026-09-27T13:29:40.079Z | user\n\nRelease 1.1.33 (see GitHub)\n\nv1.1.32 | 2026-09-27T12:07:33.428Z | user\n\nRelease 1.1.32 (see GitHub)\n\nv1.1.31 | 2026-09-27T11:44:10.049Z | user\n\nRelease 1.1.31 (see GitHub)\n\nv1.1.30 | 2026-09-26T10:40:27.151Z | user\n\nRelease 1.1.30 (see GitHub)\n\nv1.1.29 | 2026-09-21T17:02:10.438Z | user\n\nRelease 1.1.29 (see GitHub)\n\nv1.1.28 | 2026-09-21T11:28:02.636Z | user\n\nRelease 1.1.28 (see GitHub)\n\nv1.1.27 | 2026-09-21T11:19:07.520Z | user\n\nRelease 1.1.27 (see GitHub)\n\nv1.1.26 | 2026-09-21T10:22:28.689Z | user\n\nRelease 1.1.26 (see GitHub)\n\nv1.1.25 | 2026-09-12T19:51:10.345Z | user\n\nRelease 1.1.25 (see GitHub)\n\nv1.1.24 | 2026-09-12T19:31:28.164Z | user\n\nRelease 1.1.24 (see GitHub)\n\nv1.1.23 | 2026-09-12T19:12:33.045Z | user\n\nRelease 1.1.23 (see GitHub)\n\nv1.1.22 | 2026-09-08T11:18:32.401Z | user\n\nRelease 1.1.22 (see GitHub)\n\nv1.1.21 | 2026-09-08T10:10:08.768Z | user\n\nRelease 1.1.21 (see GitHub)\n\nv1.1.20 | 2026-09-07T17:29:49.080Z | user\n\nRelease 1.1.20 (see GitHub)\n\nv1.1.19 | 2026-09-07T15:41:02.235Z | user\n\n1.1.19: product records carry variation_summary (attributes, values, sibling count, this ASIN's values) instead of the ASIN-keyed sibling maps in compact answers; _links.variations capped at 10; deals rows carry deal_photo and image URLs.\n\nv1.1.18 | 2026-09-06T16:57:43.882Z | user\n\nRelease 1.1.18\n\nv1.1.17 | 2026-09-06T16:52:50.095Z | user\n\nRelease 1.1.17\n\nv1.1.16 | 2026-09-06T15:41:38.608Z | user\n\nRelease 1.1.16\n\nv1.1.15 | 2026-09-06T15:23:05.343Z | user\n\nRelease 1.1.15\n\nv1.1.14 | 2026-09-06T14:13:04.190Z | user\n\nRelease 1.1.14\n\nv1.1.13 | 2026-09-06T13:42:22.354Z | user\n\nRelease 1.1.13\n\nv1.1.12 | 2026-09-06T13:31:20.787Z | user\n\nRelease 1.1.12\n\nv1.1.11 | 2026-09-06T12:47:37.596Z | user\n\nRelease 1.1.11\n\nv1.1.10 | 2026-09-06T12:08:30.301Z | user\n\nRelease 1.1.10\n\nv1.1.9 | 2026-09-06T11:38:17.964Z | user\n\nRelease 1.1.9\n\nv1.1.8 | 2026-09-06T11:25:31.228Z | user\n\nRelease 1.1.8\n\nv1.1.7 | 2026-09-05T13:11:09.905Z | user\n\nRelease 1.1.7\n\nv1.1.6 | 2026-09-05T12:45:46.576Z | user\n\nRelease 1.1.6\n\nv1.1.5 | 2026-09-05T11:39:54.245Z | user\n\nRelease 1.1.5\n\nv1.1.4 | 2026-09-05T11:05:46.267Z | user\n\n1.1.4 security review fixes: the API key is never a command-line value (prompt / --api-key-file / --api-key-stdin), every redirect is refused so a key cannot leave the host it was sent to, the MCP launcher snippets pin an exact package version, and the read-only claim is replaced by an explicit statement of the one write (the feedback command).\n\nv1.1.3 | 2026-09-05T10:28:32.933Z | user\n\nRelease 1.1.3: search parser fixes (real titles, integer rating counts, split delivery lines) and a free send_feedback path\n\nv1.1.2 | 2026-09-04T17:00:27.806Z | user\n\nSecurity-review fixes: probe.py reads no environment variables and only contacts two fixed Apiguru hosts (API key only via explicit --api-key); the skill never pays a 402 and now opens with a costs-and-consent section (ask before any billable or batch call, agree a cap); narrower trigger description; declared requirements (metadata.openclaw); no bytecode shipped; geo chosen from the user's request instead of a baked-in US default.\n\nArchive index:\n\nArchive v1.1.51: 6 files, 32974 bytes\n\nFiles: references/endpoints.md (23768b), references/errors-and-costs.md (3955b), scripts/probe.py (39932b), skill-card.md (2353b), SKILL.md (19800b), _meta.json (139b)\n\nFile v1.1.51:SKILL.md\n\n---\nname: apiguru-amazon-data\ndescription: Live Amazon marketplace data from Apiguru (a paid third-party API, 3 free calls a day) - product details, prices, reviews, keyword search, best-sellers, deals, offers and stock, seller profiles, across 23 Amazon marketplaces. Use only when the user asks for Amazon data by ASIN, Amazon URL, product, seller or keyword, or for Amazon price/stock/review monitoring. Not for other stores or general shopping advice. Never pays on its own; ask before any billable call. We want your feedback - if a field is wrong, missing or you wish the API did something else, say so with the free `feedback` command (no account needed); the agents that report are the ones this API gets fixed for.\nlicense: MIT\ncompatibility: Needs Python 3.10+ and outbound HTTPS to agent.apiguru.app and dash.apiguru.app only. Reads no environment variables and no local files except an API-key file the user names.\nallowed-tools: Bash(python3:*) Bash(python:*) Read\nhomepage: https://github.com/apiguru-app/agent-kit\nmetadata: {\"openclaw\": {\"emoji\": \"📦\", \"homepage\": \"https://github.com/apiguru-app/agent-kit\", \"requires\": {\"anyBins\": [\"python3\", \"python\"]}}}\n---\n\n# Apiguru Amazon Data\n\nLive, structured Amazon data fetched at request time from Apiguru's servers.\n23 marketplaces.\n\n**What this skill writes.** Every data command is a read: it fetches and\nreturns, and changes nothing anywhere. There is exactly one write, and it is\nnever automatic — the `feedback` command posts the text you give it to\nApiguru's public feedback wall (see \"Telling us what is broken\" below). It\nsends only that text, it costs nothing, and it runs only when you invoke it.\nNothing else in this skill sends data anywhere.\n\n## Costs and consent (read this first)\n\n- **Hosts contacted:** `agent.apiguru.app` (keyless) and `dash.apiguru.app`\n  (the keyed API, and the feedback wall, which needs no key). Nothing else.\n  `scripts/probe.py` has both hosts fixed in the source, reads no environment\n  variables, and **refuses every redirect**, so a key cannot be carried to a\n  third host by a `302`.\n- **Free quota:** 3 calls per machine per 24 hours. After that the gateway\n  answers `402 Payment Required`. **The answer knows better than this\n  page:** every keyless reply carries `free_calls_remaining` in the body and\n  `X-Free-Probes-Remaining` (or `X-Free-Probes-Available: yes|no` where no\n  count is given) in the headers. Plan a task on the last reply, never on\n  the number above.\n- **This skill never pays.** `probe.py` stops at a 402 and tells you so. It\n  contains no wallet and no x402 client, and it will not set one up. Paying is\n  the user's decision, made one of two ways, both only with their explicit\n  consent:\n  1. an Apiguru API key, handed to the script by the user through `--api-key`\n     (an unechoed prompt), `--api-key-file PATH` or `--api-key-stdin` — bills\n     their account at their plan's rates, about USD 0.01 per call — or\n  2. their own x402-capable HTTP client with a funded wallet and a spend cap\n     (USDC on Base, Polygon, Arbitrum or Avalanche). How that works is documented for the user at\n     `https://agent.apiguru.app/llms-full.txt`, section \"Paying\".\n- **Ask before you spend.** Before the first billable call in a task, and\n  before any batch or broad search, tell the user what you will call, how many\n  items, and what it costs (run `capabilities` first, it is free), and wait\n  for a yes. A single batch call can cost up to USD 0.16 (`/product`, 20 items)\n  or USD 0.15 (`/stock`, 10 items). Agree a cap for the task and stop at it.\n- Do not go looking for an API key: not in the environment, not in config or\n  dotfiles, not anywhere the user did not hand you deliberately. `--api-key-file`\n  takes only a path the user named. Never send a key anywhere but\n  `dash.apiguru.app`, and never echo it back into the conversation, a log or a\n  command line.\n\n## Getting access\n\n**Keyless (default).** Call the agent gateway with no credentials:\n\n```\nGET https://agent.apiguru.app/agent/v1/v2/product-details?asin=B09DJLW458&geo=US\n```\n\nTwo response headers say where you stand before a 402 arrives:\n`X-Free-Probes-Remaining` and `X-Price-Next-Call`.\n\n`https://agent.apiguru.app/.well-known/x402` lists every endpoint with prices\nand schemas, free and unmetered. Check it before planning a job.\n\n**Keyed.** If the user gives you an Apiguru API key and asks you to use it,\nlet the script read it — never put it on the command line, where shell\nhistory and the process table expose it to every other local user:\n\n- `--api-key` prompts for it (not echoed, not stored),\n- `--api-key-file PATH` reads a file the user names (readable only by them),\n- `--api-key-stdin` reads one line from standard input, e.g.\n  `pass show apiguru | python scripts/probe.py ... --api-key-stdin`.\n\nThe script then sends it as `X-API-KEY` to `https://dash.apiguru.app/api/v1`\n(same paths) and to nowhere else — redirects are refused rather than\nfollowed. Calls bill that account.\n\n`scripts/probe.py` wraps all of this. Prefer it over hand-written HTTP calls:\nit retries only unbilled failures and explains every status.\n\n## Choosing an endpoint\n\n| Need | Endpoint |\n|---|---|\n| Everything about one ASIN | `/v2/product-details` |\n| Many ASINs (≤20) | `/product?asins=A,B,C` — **cheaper per item, use this for >1** |\n| Reviews, rating, \"customers say\" | `/v2/product-reviews` |\n| Find products by keyword | `/search?query=...` |\n| Offers, buy box, live stock (≤10) | `/stock?asins=...` |\n| Category rankings | `/v2/best-sellers` |\n| Current discounts | `/v2/deals` |\n| A seller's catalogue | `/v2/seller-products?seller_id=...` |\n| Seller reputation | `/v2/seller-reviews?seller_id=...` |\n| Seller profiles (≤10) | `/seller-profile?seller_ids=...` |\n\nFull parameter reference: `references/endpoints.md`.\n\n## Rules that prevent wasted calls and wasted money\n\n1. **An ASIN is 10 letters and digits** (`^[A-Z0-9]{10}$`). Any case works, and\n   the gateway also reads an Amazon product URL (`/dp/ASIN`) in its place.\n2. **Never loop a single-item endpoint over a list.** Use `/product` for\n   ASINs and `/seller-profile` for seller IDs. Ten ASINs through `/product`\n   costs USD 0.08 and one round trip; ten through `/v2/product-details` costs\n   USD 0.10 and ten round trips.\n3. **Choose `geo` from the user's request**, never by habit: amazon.de → `DE`,\n   amazon.co.uk → `UK`, and so on (all 23 codes in `references/endpoints.md`).\n   If the marketplace is not clear, ask. The API assumes `US` only when the\n   parameter is omitted; a product that exists on `amazon.de` may genuinely\n   `404` on `US`, and that 404 is billed on the keyed path.\n4. **`check_inventory=true` on `/stock` is slow and bills more.** Only set it\n   when the user needs the stock number, not just the offers.\n5. **Read `success` in the body**, not just the HTTP status. Some responses\n   are `200` with `success: false`.\n6. **`/v2/deals` filters by id, and tells you the ids.** `categories` takes a\n   department name as Amazon shows it (`Electronics`, `Elektronik & Foto` on\n   DE) or its id; `brands` takes brand ids only. Every deals answer carries\n   `available_filters` (the category and brand ids of that marketplace),\n   `filters_applied` / `filters_ignored` (what actually took effect) and\n   `next_offset` (the next page, `null` when the feed ends). Narrow price and\n   discount with `min_price`, `max_price`, `min_discount`. For a brand by\n   name use `/search?brand=<name>&today_deals=true` instead.\n7. **Every list answer reports its filters.** `/search` and\n   `/v2/seller-products` return `filters_applied`, `filters_ignored` (a\n   filter this marketplace cannot apply, with the reason -- amazon.fr has no\n   Today's Deals refinement, amazon.in offers only NEW) and\n   `available_filters`. `product_condition` is NEW / USED / RENEWED,\n   `deal_type` is today_deals / all_discounts / coupons / buy_more_save_more,\n   prices take decimals. `/v2/best-sellers` departments differ per\n   marketplace: pass a slug or name and read `available_categories` and\n   `available_subcategories` (the ids `subcategory_code` takes) from the\n   answer; pages run 1-5.\n8. **`/v2/best-sellers` tells you how it read `category`.** A word that is\n   only part of a department name still matches it — `category=shoes` is the\n   whole *Clothing, Shoes & Jewelry* department, hoodies included. The answer\n   says so: `category_resolution.via` is `fragment`, and `hint` lists the\n   subcategories carrying that word with their ids (`Women > Shoes` is\n   `679337011`, `Men > Shoes` is `679255011`). On amazon.com\n   `subcategory_code` takes any browse node id at any depth, or a name\n   resolved under the department — `subcategory_code=women's shoes`,\n   `mules & clogs` — and the answer carries `category.subcategory_path`\n   (\"Clothing, Shoes & Jewelry > Women > Shoes > Mules & Clogs\") and\n   `category.heading` (the page's own title). A name two nodes share equally\n   is a free `400` listing both ids with their paths; pass the one you mean.\n\n## Big responses, and the two fields that mislead\n\nA full `/search` page is up to 48 results and about **54 KB** of JSON — enough\nthat most clients write it to a file instead of showing it to you. Keep it\nsmall at the source:\n\n- **Filter before you page.** `brand`, `min_price`/`max_price`,\n  `product_condition` and `sort_by` cut the result set before it is fetched,\n  so the answer is both smaller and more relevant. Paging does neither.\n- **Ask for less.** `limit=N` caps the rows (`limit=0` for the whole page),\n  `compact=true` returns light rows, and\n  `fields=\"asin,product_title,product_price\"` returns only what you name.\n  These work the same way on the REST endpoints and over MCP, on every list\n  tool: `search`, `best_sellers`, `deals`, `seller_products` and\n  `seller_reviews`.\n- **The defaults differ, deliberately.** Over MCP a list tool returns the\n  first **10 light rows** (about 7 KB) because a tool result goes straight\n  into a context window. Over `probe.py` you get the **whole page** unless\n  you ask otherwise, because a script can pipe it — so\n  `probe.py search --query ... --limit 10 --compact` (or\n  `--fields asin,product_title,product_price`) is worth adding when you are\n  reading the answer rather than filtering it. A parameter the script has no\n  flag for goes through `--param name=value`.\n- **The answer says what it did.** `_truncated` gives the real row count and\n  the exact `limit=` to pass for all of them, `_omitted_fields` names what\n  the light projection dropped, and `_notes` carries the things that will\n  mislead you when reading these particular rows.\n\nThree properties of Amazon's own data that will mislead you if you assume\notherwise:\n\n1. **`product_num_ratings` is per listing family, not per ASIN.** Variants\n   share a review pool, so every colour of one shoe reports the same count.\n   Do not present it as \"this variant has N reviews\".\n2. **A variant's title can be the parent's.** In search results the ASIN and\n   the title can disagree — the URL slug usually shows the real variant. When\n   the exact variant matters, call `/v2/product-details` on that ASIN; it is\n   authoritative for the ASIN you passed.\n3. **A search row's badges are the result card's, not the listing's.**\n   `badges` (and the derived `is_amazon_choice` / `is_best_seller`) say what\n   Amazon printed on that card for *that query*. `sort_by=BEST_SELLERS` is\n   Amazon's popularity order for the query, not a category rank — so an ASIN\n   that is #1 in *Women's Mules & Clogs* can show `badges: []` in a search\n   for \"crocs white\" while `/v2/product-details` reports `best_seller: true`\n   with the rank. For a rank claim, use product-details or best-sellers;\n   `filters_applied.sort_by` echoes the order the page actually used.\n\n`badges` is the source of truth for Amazon's Choice / Best Seller / Overall\nPick (Amazon renamed that slot to \"Overall Pick\"); `is_amazon_choice` and\n`is_best_seller` are derived from it.\n\n## Error handling — which failures cost money\n\n- **`404`** — the item genuinely is not on that marketplace. **Billed** on the\n  keyed path. Retrying will not help; try a different `geo` or accept it.\n- **`503`** — a temporary Apiguru-side failure. **Not billed.** Retry with\n  backoff. `500`, `502` and `504` are the same class: not billed, retry.\n- **`429`** — rate limited. Back off, then retry.\n- **no answer** (your client timed out) — keyless, nothing was billed; retry.\n  **With an API key the call may still have finished and been billed**, so it\n  is not repeated automatically: tell the user and retry only if they agree.\n  Some marketplaces answer more slowly; allow 60s before giving up.\n- **`400`** — your input was wrong (bad ASIN format, unknown geo, missing\n  required parameter). Not billed. Fix the input; do not retry unchanged.\n- **`402`** — free probes spent. **Stop and ask the user** (see \"Costs and\n  consent\"). Do not retry, do not look for a key, do not attempt payment.\n\nSo: **retry `429`, `500`, `502`, `503`, `504` and keyless timeouts (unless the\nbody says `retryable: false`); never retry `400`, `402`, `404` or `413`, and\nnever repeat a timed-out keyed call without the user's say-so.**\n`scripts/probe.py` does exactly this. Its exit status tells a job what\nhappened: `0` usable answer, `1` HTTP error or a body reporting failure,\n`2` input rejected before any request, `3` a batch with some failed rows.\n\n## Quick start\n\n```bash\n# prices, the free-probe policy, and how many free probes THIS caller has\n# left right now (from /health; the policy number is not your balance). Free.\npython scripts/probe.py capabilities\n\n# one product\npython scripts/probe.py product-details --asin B09DJLW458 --geo US\n\n# many at once (preferred for lists)\npython scripts/probe.py product --asins B09DJLW458,B0BSHF7WHW --geo US\n\n# keyword search on amazon.co.uk\npython scripts/probe.py search --query \"wireless earbuds\" --geo UK\n\n# billed to the user's account, only after they said so.\n# --api-key prompts; the key never appears in argv or in shell history.\npython scripts/probe.py product-details --asin B09DJLW458 --geo US --api-key\n\n# non-interactive equivalent, key straight from a secret store\npass show apiguru | python scripts/probe.py product-details --asin B09DJLW458 --api-key-stdin\n```\n\n## MCP alternative (optional, and outside this skill's audit)\n\n**`scripts/probe.py` above is the supported path.** It is part of this skill,\nit was reviewed with it, it is standard-library only, and it downloads and\nexecutes nothing. Use it unless someone has decided otherwise.\n\nThe same data is also published as an MCP server. That server is a **separate\nartifact**: it is not shipped in this skill, it was not covered by whatever\nreview this skill passed, and it needs its own security review before anyone\nruns it. Three ways to reach it, safest first:\n\n**1. The hosted server — nothing is installed or executed on your machine.**\n\n```\nhttps://mcp.apiguru.app/mcp        streamable HTTP\nhttps://mcp.apiguru.app/account    the same thing behind OAuth 2.1\n```\n\nYour client talks HTTP to a server we run. No package is fetched, so there is\nno supply chain on your side at all. This is the option to prefer.\n\n**2. Install it once, deliberately, then run what you installed.** If you want\nit local, make it a controlled deployment step rather than a fetch on every\nlaunch:\n\n```bash\npython -m venv ~/.venvs/apiguru && ~/.venvs/apiguru/bin/pip install \"apiguru-mcp==1.1.51\"\n# then point the client at the binary you just reviewed and installed:\n#   \"command\": \"/home/you/.venvs/apiguru/bin/apiguru-mcp\"\n```\n\nPin transitive dependencies too if that matters to you: resolve once with\n`pip freeze > apiguru-lock.txt`, review it, and install from that file with\n`--require-hashes`.\n\n**3. Fetch at launch (`uvx` / `npx`).** Convenient, and the weakest of the\nthree: the launcher resolves and executes a package from a public registry\nevery time the client starts. Pinning the version — which the snippets below\ndo — stops it silently moving to a newer release, but it does not protect you\nfrom a compromised publisher account or registry.\n\n```json\n{ \"mcpServers\": { \"apiguru\": { \"command\": \"uvx\",\n  \"args\": [\"apiguru-mcp==1.1.51\"] } } }\n```\n\nor, with Node instead of Python, `\"command\": \"npx\", \"args\": [\"apiguru-mcp@1.1.51\"]`.\n\nWhichever you choose:\n\n- **Expected publisher:** `apiguru-app`. **Registries:** PyPI\n  (`apiguru-mcp`, https://pypi.org/project/apiguru-mcp/) and npm\n  (`apiguru-mcp`, https://www.npmjs.com/package/apiguru-mcp). Both are listed\n  in the official MCP Registry as `app.apiguru/amazon-data`. Anything under\n  another name or publisher is not ours.\n- **Verify the artifact, not just the name and version.** PyPI and npm publish\n  a SHA-256 for every file; `pip download apiguru-mcp==<version>` then\n  `pip hash` gives you a digest to record and re-check on the next upgrade.\n- **Before raising the pin**, read the changelog at\n  https://github.com/apiguru-app/agent-kit/releases and diff the dependency\n  list. Do it deliberately; do not let a launcher do it for you.\n- **Run it with least privilege**: it needs outbound HTTPS to\n  `agent.apiguru.app`, `dash.apiguru.app` and `mcp.apiguru.app` and nothing\n  else — no filesystem access, no other credentials in its environment. A\n  container is the easy way: an official image is published for exactly this\n  (`mcp/apiguru`, Docker's MCP catalogue).\n\nThe MCP tools do the same thing as `probe.py` and follow the same rules — they\nnever pay on their own. A 402 comes back as an x402 PaymentRequired result: the\nuser decides, and only an x402-capable MCP client they set up (with a spend cap)\ncan pay it. Their advantage is that they validate ASINs and geos before spending a\nprobe.\n\n## Telling us what is broken\n\nThis API gets fixed when the agents using it say what is wrong. Recent\nexample: search results were returning the brand as `product_title` and\n`null` for `product_num_ratings`; an agent reported both and both are fixed.\nSo if a field is empty, mistyped, welded together or simply missing:\n\n- **Preferred, if you have a GitHub account** — open an issue at\n  https://github.com/apiguru-app/agent-kit/issues. A thread there can hold a\n  reply and a fix gets linked back to it.\n- **No GitHub account? Use the wall** — one unauthenticated POST, never\n  billed, no signup:\n\n  ```bash\n  curl -X POST https://dash.apiguru.app/api/v1/feedback -H 'Content-Type: application/json' -d '{\"message\": \"search: product_title holds the brand, not the title\", \"category\": \"bug\", \"endpoint\": \"/search\", \"agent\": \"your-name/1.0\"}'\n  ```\n\n  `category` is one of `bug`, `wish`, `praise`, `question`, `other`. Add\n  `\"contact\"` if you want a reply — it is shown publicly on the wall.\n\n  **The wall is public, so send only what the user has agreed to, and only\n  about the API:** the tool, the parameters, the field, what you expected and\n  the `request_id`. Never an API key, personal data, or the user's own\n  prompts, documents or results beyond the field in question.\n- **Over MCP** — the free `send_feedback` tool does the same thing.\n- Read what other agents have written: https://dash.apiguru.app/feedback\n\nSay what you called, what you expected and what came back, and quote the\n`request_id` from the answer. **One issue per entry** — a five-point list\ncannot be closed point by point, and each entry gets its own status on the\nwall (`open`, `fixed`, `documented`, `answered`, `wont_fix`). A wish counts:\nif you need a field this API does not return, that is the most useful thing\nyou can tell us.\n\n## Reference files\n\n- `references/endpoints.md` — every endpoint, parameter, and marketplace code\n- `references/errors-and-costs.md` — pricing, billing rules, retry strategy\n\nFile v1.1.51:_meta.json\n\n{\n  \"ownerId\": \"kn743rz4efdce60qkmj9x20cr18dr5cm\",\n  \"slug\": \"apiguru-amazon-data\",\n  \"version\": \"1.1.51\",\n  \"publishedAt\": 1791308619750\n}\n\nFile v1.1.51:references/endpoints.md\n\n# Apiguru endpoint reference\n\nGenerated from the API spec - do not edit by hand.\n\n- Keyless base URL: `https://agent.apiguru.app/agent/v1`\n- Keyed base URL: `https://dash.apiguru.app/api/v1` (send `X-API-KEY`)\n\nAll endpoints are `GET` with query parameters.\n\n## Marketplaces\n\nPass as `geo`, chosen from the user's request or the Amazon domain they mention (amazon.de -> DE). The API assumes `US` only when the parameter is omitted; do not rely on that default.\n\n| Code | Domain |\n|---|---|\n| `US` | amazon.com |\n| `CA` | amazon.ca |\n| `DE` | amazon.de |\n| `MX` | amazon.com.mx |\n| `UK` | amazon.co.uk |\n| `FR` | amazon.fr |\n| `IT` | amazon.it |\n| `ES` | amazon.es |\n| `AU` | amazon.com.au |\n| `BR` | amazon.com.br |\n| `IN` | amazon.in |\n| `JP` | amazon.co.jp |\n| `NL` | amazon.nl |\n| `AE` | amazon.ae |\n| `PL` | amazon.pl |\n| `SA` | amazon.sa |\n| `SG` | amazon.sg |\n| `SE` | amazon.se |\n| `TR` | amazon.com.tr |\n| `BE` | amazon.com.be |\n| `IE` | amazon.ie |\n| `ZA` | amazon.co.za |\n| `EG` | amazon.eg |\n\n## `GET /v2/product-details`\n\nUse for one product's current listing. Not for several ASINs (product_details_batch), seller offers or stock (offers_stock), or review text (product_reviews). Fetches the complete product record for one ASIN on one marketplace: title, price, star rating, rating count, images, description, feature bullets, variations and category.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asin` | string | yes | Single Amazon ASIN, 10 uppercase alphanumeric characters. Exactly one - comma-separated lists are rejected; use product_details_batch for many. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> 404 means the ASIN is absent from that marketplace and IS billed. 503 is a temporary failure on our side and is NOT billed - retry. Bullet points and specs are what Amazon shows for the listing; on multi-variant listings they can describe the product family rather than the exact variant. A null field means Amazon did not show it.\n\n## `GET /v2/product-reviews`\n\nUse for what customers say about one product. Not for its full review history (Amazon serves full and star-filtered review lists only to signed-in accounts) or for seller feedback (seller_reviews). Returns the overall rating, rating count, review_histogram (percent of all ratings per star), Amazon's 'customers say' AI summary where that marketplace shows one, and the reviews on the product page (typically up to 8 from this marketplace and 5 from other countries), each with rating, review_date, review_country, from_this_marketplace, verified flag and helpful_votes; from_rating/to_rating keep a star window.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asin` | string | yes | Single Amazon ASIN, 10 uppercase alphanumeric characters. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `from_rating` | integer | no | Lowest star rating to include, 1-5. Filters the reviews the product page shows (see review_coverage). |\n| `to_rating` | integer | no | Highest star rating to include, 1-5. from_rating=1&to_rating=3 keeps the critical ones among them. |\n\n> Same 404-billed / 503-not-billed semantics as product_details. No paging or sort: the reviews are those on the product page; review_coverage says how many and from where. from_rating/to_rating filter them. review_histogram (here and on product_details) gives the share of every rating. customers_say is null where Amazon shows no summary (several marketplaces never do); customers_say_note then says so.\n\n## `GET /search`\n\nUse to find products by keyword and filters. Rows are result snippets; for the authoritative record of one ASIN call product_details. Search Amazon products by keyword. Filters: page, sort_by, category_id (browse node), min_price / max_price (decimals), product_condition (NEW / USED / RENEWED), brand, seller_id, today_deals and deal_type (coupons, all_discounts, buy_more_save_more). Every answer carries filters_applied, filters_ignored (with the reason) and available_filters for that marketplace.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `query` | string | yes | Search keywords. Required and must be non-empty. |\n| `page` | integer | no | Result page, 1-based. metadata.total_pages says how far it goes. Default `1`. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `sort_by` | enum | no | Result ordering. Default `RELEVANCE`. |\n| `category_id` | string | no | Amazon browse node id to restrict to, e.g. 172282 (Electronics on US). Take one from a best_sellers answer's available_subcategories, a product's category_path, or node= in an Amazon URL. Ids differ per marketplace. |\n| `min_price` | number | no | Lowest price, in the marketplace currency; decimals such as 19.99 are fine. |\n| `max_price` | number | no | Highest price, in the marketplace currency. |\n| `product_condition` | enum | no | NEW, USED or RENEWED (case-insensitive). Applied with the marketplace's own condition node; where a marketplace does not offer one, the answer's filters_ignored says so and available_filters lists what it does offer. |\n| `brand` | string | no | Brand name as Amazon spells it (case-insensitive), e.g. Samsung. |\n| `seller_id` | string | no | Restrict results to one seller's offers: an Amazon seller id, 'A' followed by 9-20 letters and digits (e.g. A2A1RNLLUK3HYA). |\n| `today_deals` | boolean | no | Only items in Today's Deals, using that marketplace's own refinement. Where a marketplace has none (amazon.fr on 2026-09-08) it is reported under filters_ignored. Default `False`. |\n| `deal_type` | enum | no | A specific promotion refinement: today_deals, all_discounts, coupons or buy_more_save_more. available_filters.deal_type lists the ones this marketplace has. |\n\n`sort_by` accepts: `RELEVANCE`, `BEST_SELLERS`, `LOW_HIGH_PRICE`, `HIGH_LOW_PRICE`, `REVIEWS`, `NEWEST`\n\n`product_condition` accepts: `NEW`, `USED`, `RENEWED`\n\n`deal_type` accepts: `today_deals`, `all_discounts`, `coupons`, `buy_more_save_more`\n\n> Blank values and the literal string 'null' are treated as unset. Invalid page, sort_by, price, product_condition or deal_type is a free 400 naming the parameter and the allowed values. Condition and deal refinements are per marketplace; a marketplace that lacks one gets the unfiltered feed plus an entry under filters_ignored, never a silent empty page. `product_num_ratings` and `offers_count` are integers; `product_star_rating`, `product_price` and `product_original_price` are decimal strings; a null field means Amazon did not show it. `is_prime` is true when the result carries a Prime badge or its delivery line offers Prime delivery. `metadata.total_pages` says how far `page` can go. A full page is up to 48 results and about 54 KB; the tool returns the first 10 as light rows by default and the answer carries `_truncated`, `_omitted_fields`, `_projection` and `_notes`. filters_applied echoes the effective sort_by (RELEVANCE when none was sent). A BEST_SELLERS ordering is Amazon's query-scoped popularity, not a category rank: a row's `badges` / `is_best_seller` are what the result card showed for this query, and an ASIN that is #1 in its subcategory can carry no badge here while product_details reports best_seller=true with the rank. For a rank claim, use product_details or best_sellers. An empty `products` list is served as success only when Amazon itself reports 0 results (metadata.total is 0 and `hint` says so). Anything else that is not a usable result is an unbilled, retryable 503 with code upstream_unavailable.\n\n## `GET /product`\n\nUse to enrich a list of ASINs in one call; compare the ASINs in `results` with the ones you sent. Batch variant of product_details. Accepts a comma-separated ASIN list, deduplicates it, and fetches all of them concurrently. Far cheaper and faster than N single calls.\n\n**Price:** $0.0024 per item (max 20)\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asins` | string | yes | Comma-separated ASIN list, maximum 20 after de-duplication. Each must be 10 uppercase alphanumeric characters. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> Billed per ASIN processed, including ones that come back not-found. More than 20 ASINs returns 413. Bullet points and specs are what Amazon shows for the listing; on multi-variant listings they can describe the product family rather than the exact variant. A null field means Amazon did not show it. ASINs Amazon has no record for on that marketplace are listed in not_returned (billed, like a not-found product_details call; retrying will not help).\n\n## `GET /stock`\n\nUse to compare sellers' current offers and see who holds the buy box, and, with check_inventory, how many units a buyer can add to the cart now. The stock number is not a sales estimate. Not for the listing's own details (product_details). Returns the current offer list per ASIN (seller, price, condition, buy-box winner) and, optionally, the actual purchasable stock quantity.\n\n**Price:** $0.0045 per item (max 10)\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asins` | string | yes | Comma-separated ASIN list, maximum 10. Each must be 10 uppercase alphanumeric characters; malformed entries are rejected with 400. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `check_inventory` | boolean | no | Resolve the true purchasable stock quantity. Slower and bills more lookups, so leave off unless you need the number. Default `False`. |\n| `offers_count` | string | no | 'all' for every offer (default), 'winner' for the buy-box offer only, or a specific alphanumeric Offer ID. Every offer carries is_buybox_winner; with 'winner' the per-ASIN data holds that one offer and offers_total says how many exist. An ASIN with no featured offer answers an empty list with an explanatory error. The response echoes filters_applied. Default `all`. |\n| `condition` | string | no | Comma-separated condition filter: ALL, NEW, USED_LIKE_NEW, USED_VERY_GOOD, USED_GOOD, USED_ACCEPTABLE (case-insensitive). Omit for every offer. An unknown value is a free 400 listing the allowed ones; it used to be silently treated as ALL. |\n\n> Billed per lookup, which is more than one per ASIN when check_inventory is true. offers_count=winner returns only the offer flagged is_buybox_winner (offers_total keeps the full count); it used to scope only the inventory check and return every offer. /scrape is a legacy alias for the same handler. When Amazon will not return the offer list for an ASIN, the result carries source=product_page: the featured (buy-box) offer read from the product page, offers_on_amazon (how many offers Amazon says exist) and a note; other sellers' offers and stock are then not included.\n\n## `GET /v2/best-sellers`\n\nUse for what sells best in a department right now. The rank is Amazon's, not a sales figure. Best-seller rankings for a department of one marketplace, 50 per page. Every answer carries the department it resolved to and how (category_resolution: by slug, name or a fragment of a name, with a hint when a fragment such as 'shoes' landed on the whole 'Clothing, Shoes & Jewelry' department, or 'subcategory' when a word such as 'camera' named a subcategory), available_categories (that marketplace's departments with slugs; MCP: with compact=false) and available_subcategories (the children of the node shown, with the ids subcategory_code takes). On amazon.com subcategory_code also takes any browse node id at any depth, or a name resolved under the department (\"women's shoes\", \"mules & clogs\"); category.subcategory_path gives the node's full path and category.heading the page's own title line.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `category` | string | no | Best-seller department, by slug or by name as Amazon shows it for that marketplace (case-insensitive; a unique fragment works, and the answer's category_resolution says when a fragment was used -- 'shoes' is the whole 'Clothing, Shoes & Jewelry' department, and the hint then lists the Shoes subcategories with their ids). Departments and their slugs differ per marketplace: amazon.com has electronics, amazon.de has ce-de (Electronics & Photo). A word that names a subcategory works too: category=camera on amazon.es is Electronics > Camera & Photo (category_resolution.via says 'subcategory'; several equally good matches are a free 400 listing each as category + subcategory_code). REST answers list the marketplace's departments under available_categories (the MCP tool with compact=false); an unknown name is a free 400 listing them. Default `appliances`. |\n| `subcategory_code` | string | no | Browse node id under `category`: one from available_subcategories of a previous answer, or on amazon.com any node id at any depth (679410011 is Women > Shoes > Mules & Clogs) or a name resolved under the department (\"women's shoes\", \"mens boots\", \"mules & clogs\"). A name that fits two nodes equally (Men > Shoes > Boots and Women > Shoes > Boots) is a free 400 listing both ids with their paths. |\n| `page` | integer | no | Result page, 1-based, 50 rows each; Amazon's lists stop at page 5. Default `1`. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> No required parameters - calling it bare returns US appliances page 1. `category` accepts a slug, a display name, one of the older US department names, or a unique fragment; category_resolution.via says which, and a fragment match adds a hint naming the subcategories that carry the word, with ids. On amazon.com the whole browse tree is known: subcategory_code takes any node id or a name at any depth, subcategory_name and subcategory_path are filled without a fetch, and available_subcategories lists the node's real children (empty on a leaf). Other marketplaces name only what their navigation showed. page is capped at 5 (a 400 beyond, not a 500). `rank` is the position within the requested list on this page. Rows are the same for every marketplace; only the department vocabulary differs, and the answer carries it.\n\n## `GET /v2/deals`\n\nUse for items currently promoted in Amazon's deals feed. Not for one product's price (product_details); for a brand by name use search with brand= and today_deals=true. Returns the current Amazon deals feed: ASIN, title, deal price, list price, discount, deal badge, start/end time and product links. Filter by department (categories), brand id (brands), rating cut-off, price bounds, minimum discount and Prime program. Every answer carries available_filters (the category and brand ids this marketplace accepts, with names), filters_applied / filters_ignored (what took effect) and next_offset (the next page, null when the feed ends).\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `offset` | integer | no | Row to start at. A page is 30 rows; pass the previous answer's next_offset for the next page. Default `0`. |\n| `categories` | string | no | Department to restrict to: its id from available_filters.categories, or its name as Amazon shows it for that marketplace (case-insensitive; a unique fragment such as \"electronics\" works). US departments: Amazon Devices & Accessories, Appliances, Arts Crafts & Sewing, Audible Books & Originals, Automotive, Baby Products, Beauty & Personal Care, Books, CDs & Vinyl, Cell Phones & Accessories, Clothing Shoes & Jewelry, Collectibles & Fine Art, Electronics, Everything Else, Grocery & Gourmet Food, Handmade Products, Health & Household, Home & Kitchen, Industrial & Scientific, Kindle Store, Movies & TV, Musical Instruments, Office Products, Patio Lawn & Garden, Pet Supplies, Software, Sports & Outdoors, Tools & Home Improvement, Toys & Games, Video Games. Other marketplaces use their own localised names -- read them from available_filters.categories of any deals answer for that geo. An unknown name is a free 400 listing the valid names. |\n| `brands` | string | no | Comma-separated brand ids, e.g. 46655 for Samsung on US. Take them from brand_id on any deals row or from available_filters.brands (the brands present in the current result). Names resolve only when this marketplace has already shown that brand; for a brand by name use /search with brand=<name> and today_deals=true instead. |\n| `min_product_star_rating` | enum | no | Amazon's deals feed offers one rating cut-off: 4 = four stars and up. ALL or omitted = no cut-off. Other values are rejected with a free 400. |\n| `min_price` | number | no | Lowest deal price to return, in the marketplace currency. Applied to the fetched rows; see notes. |\n| `max_price` | number | no | Highest deal price to return, in the marketplace currency. |\n| `min_discount` | integer | no | Smallest discount percentage to return, e.g. 50 for half price or better. |\n| `max_discount` | integer | no | Largest discount percentage to return. |\n| `prime_exclusive` | boolean | no | Only deals in Amazon's Prime Exclusive program. Default `False`. |\n| `prime_early_access` | boolean | no | Only Prime Early Access deals. A marketplace lists the programs it is running under available_filters.prime_programs; when Early Access is not running the answer is empty with a hint saying so. Default `False`. |\n\n`min_product_star_rating` accepts: `4`, `ALL`\n\n> Filters are by id: categories takes a department id or name, brands takes brand ids only; available_filters in every answer lists both with names, and filters_applied / filters_ignored report what Amazon honoured. A page is 30 rows; page with offset=next_offset (null when exhausted); total_count caps at 500. min_price, max_price, min_discount and max_discount are applied to the rows after retrieval, scanning up to 3 feed pages per call, so a page can hold fewer than 30 rows and total_count does not reflect them. An empty answer carries a hint saying why. Deal prices expire: check deal_ends_at. The older price_range and discount_range parameters are still accepted, as buckets (1-5 = under 25 / 25-50 / 50-100 / 100-200 / 200 and up; 1-4 = 10 / 25 / 50 / 70 percent off or more) or as bands such as 25-50 and 70+.\n\n## `GET /seller-profile`\n\nUse to vet sellers: name, rating and feedback counts as Amazon displays them. Returns the storefront profile for each seller id: business name, rating, feedback counts, address and marketplace presence.\n\n**Price:** $0.0036 per item (max 10)\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `seller_ids` | string | yes | Comma-separated seller IDs, maximum 10. Each must be an Amazon seller id -- 'A' followed by 9-20 letters and digits, e.g. A2A1RNLLUK3HYA -- or the whole call 400s. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> Seller ID validation is all-or-nothing: one malformed id rejects the entire request with 400. Every row in results is an object with `status`: `ok` (the profile), `not_found` (Amazon has no page for that id on this marketplace; billed, like a 404) or `unavailable` (could not be retrieved right now; NOT billed on the keyed path, `retryable: true`). A row is never null. billable_requests_count counts ok + not_found rows; on the pay-per-call rail the per-item quote is settled up front, so retry `unavailable` ids in a separate call rather than expecting a partial refund.\n\n## `GET /v2/seller-products`\n\nUse to list one seller's storefront. Products listed by a seller: a storefront search. Takes the same filters as search -- query, page, sort_by, category_id, min_price / max_price, product_condition, brand, today_deals, deal_type -- and answers with filters_applied, filters_ignored and available_filters like search does.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `seller_id` | string | yes | Amazon seller id whose storefront to list: 'A' followed by 9-20 letters and digits, the seller= or me= value of a storefront URL (e.g. A2A1RNLLUK3HYA). Required. |\n| `query` | string | no | Optional keywords to search within this seller's storefront. |\n| `page` | integer | no | Result page, 1-based. metadata.total_pages says how far it goes. Default `1`. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `sort_by` | enum | no | Result ordering. Default `RELEVANCE`. |\n| `category_id` | string | no | Amazon browse node id to restrict to, e.g. 172282 (Electronics on US). Take one from a best_sellers answer's available_subcategories, a product's category_path, or node= in an Amazon URL. Ids differ per marketplace. |\n| `min_price` | number | no | Lowest price, in the marketplace currency; decimals such as 19.99 are fine. |\n| `max_price` | number | no | Highest price, in the marketplace currency. |\n| `product_condition` | enum | no | NEW, USED or RENEWED (case-insensitive). Applied with the marketplace's own condition node; where a marketplace does not offer one, the answer's filters_ignored says so and available_filters lists what it does offer. |\n| `brand` | string | no | Brand name as Amazon spells it (case-insensitive), e.g. Samsung. |\n| `today_deals` | boolean | no | Only items in Today's Deals, using that marketplace's own refinement. Where a marketplace has none (amazon.fr on 2026-09-08) it is reported under filters_ignored. Default `False`. |\n| `deal_type` | enum | no | A specific promotion refinement: today_deals, all_discounts, coupons or buy_more_save_more. available_filters.deal_type lists the ones this marketplace has. |\n\n`sort_by` accepts: `RELEVANCE`, `BEST_SELLERS`, `LOW_HIGH_PRICE`, `HIGH_LOW_PRICE`, `REVIEWS`, `NEWEST`\n\n`product_condition` accepts: `NEW`, `USED`, `RENEWED`\n\n`deal_type` accepts: `today_deals`, `all_discounts`, `coupons`, `buy_more_save_more`\n\n> Unlike seller_profile_batch, seller_id format is not pattern-validated here. metadata.total_pages says how far page goes (48 rows a page). Invalid sort_by, price, product_condition or deal_type is a free 400 that lists the allowed values.\n\n## `GET /v2/seller-reviews`\n\nUse for a seller's customer feedback (service, shipping). Not for product reviews (product_reviews). Returns paginated seller feedback, optionally filtered to a star-rating window.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `seller_id` | string | yes | Amazon seller id: 'A' followed by 9-20 letters and digits, the seller= or me= value of a storefront URL (e.g. A2A1RNLLUK3HYA). Required. |\n| `page` | integer | no | Result page, 1-based, 5 reviews a page; has_next_page in the answer says whether another exists. Default `1`. |\n| `from_rating` | integer | no | Lowest star rating to include, 1-5. |\n| `to_rating` | integer | no | Highest star rating to include, 1-5. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> from_rating and to_rating are optional; omit both for unfiltered feedback. A page holds 5 reviews and the answer carries current_page and has_next_page; Amazon exposes no total, so page until has_next_page is false (up to page 100).\n\n## Formats\n\n- ASIN: `^[A-Z0-9]{10}$` - On agent.apiguru.app and the MCP server any case is accepted and upper-cased, and an Amazon product URL (/dp/ASIN, /gp/product/ASIN, ?asin=) works in place of an ASIN; its domain sets geo unless geo names another marketplace (then 400). The answer lists what was rewritten under parameters_interpreted (MCP: _input_interpreted).\n- Seller ID: `^[Aa][A-Za-z0-9]{9,20}$` - An Amazon seller id is 'A' followed by 9-20 letters and digits (10-21 characters in all) -- the seller= or me= value of a storefront URL, e.g. A2A1RNLLUK3HYA. Anything else is rejected with 400 before any fetch.\n- Sample ASIN for testing: `B09DJLW458`\n\nFile v1.1.51:references/errors-and-costs.md\n\n# Costs, billing and retries\n\nGenerated from the API spec - do not edit by hand.\n\n## Prices\n\n| Endpoint | Price |\n|---|---|\n| `/v2/product-details` | $0.003 per call |\n| `/v2/product-reviews` | $0.003 per call |\n| `/search` | $0.003 per call |\n| `/product` | $0.0024 per item (max 20) |\n| `/stock` | $0.0045 per item (max 10) |\n| `/v2/best-sellers` | $0.003 per call |\n| `/v2/deals` | $0.003 per call |\n| `/seller-profile` | $0.0036 per item (max 10) |\n| `/v2/seller-products` | $0.003 per call |\n| `/v2/seller-reviews` | $0.003 per call |\n\nBatch endpoints are billed per item and are cheaper per item than the\nsingle-item equivalents. Always prefer them for more than one item.\n\n## What each status means, and whether it costs money\n\n| Status | Billed? | Meaning and what to do |\n|---|---|---|\n| `400` | no | Bad input (bad ASIN format, unknown geo, missing required param). NOT billed. |\n| `401` | - | Missing or invalid API key on the keyed path. |\n| `402` | - | Payment required. On the agent path this carries a PAYMENT-REQUIRED challenge (over MCP: an x402 PaymentRequired tool result, payable in-band via _meta[\"x402/payment\"]). On the keyed path it means the account balance is exhausted. |\n| `403` | - | Account disabled, or no active subscription plan. |\n| `404` | **yes** | The ASIN genuinely does not exist on that marketplace. BILLED - the lookup was performed and the bad input was the caller's. Retrying will not help; try a different geo. |\n| `413` | - | Too many items in a batch request. |\n| `429` | - | Per-second rate limit exceeded for the plan. Back off and retry. |\n| `500` | no | Internal error. NOT billed. |\n| `502` | no | Bad gateway. NOT billed. Same class as 503: retry with backoff. |\n| `503` | no | Temporary failure on our side. NOT billed. Safe and correct to retry. |\n| `504` | no | Gateway timeout: the request ran past its deadline. NOT billed. Retry with backoff; a narrower query often succeeds. |\n| `timeout` | - | No response before your own client's deadline. A keyless call without a payment is never billed. On an API key, or with an x402 payment attached, the request may still complete after your client gave up, and is then billed like any answered call. Some marketplaces answer more slowly than others; allow 60s rather than retrying early. |\n\n## Retry policy\n\nRetry 429, 500, 502, 503 and 504 with backoff -- none of them are billed -- unless the error body says `retryable: false`. A client-side timeout on a key or a payment may have completed and been billed; allow 60s before retrying it. Never retry 400, 401, 402, 403, 404 or 413: the request itself is the problem and repeating it will not change the answer.\n\nConcretely (the same set `scripts/probe.py` retries):\n\n```python\nRETRYABLE = {429, 500, 502, 503, 504}   # answered, and not billed\nfor attempt in range(4):\n    try:\n        status, body = call(..., timeout=60)\n    except TimeoutError:\n        if api_key:                  # may have finished and billed after we gave up:\n            raise                    # stop, tell the user, retry only if they agree\n        status, body = 0, None       # keyless and unpaid: never billed\n    if (status in RETRYABLE or status == 0) and (body or {}).get('retryable') is not False:\n        time.sleep(2 ** attempt)\n        continue\n    break                            # 200/400/402/404/413 are final\n```\n\nA body's `retryable` flag wins over the status table: a 5xx whose\ncause is permanent says `retryable: false` and is not worth repeating.\nA timeout is different: on an API key (or with an x402 payment attached)\nthe request may still complete after your client gave up, so it is never\nretried automatically -- `scripts/probe.py` reports it and stops.\n\n## Free probes\n\nThe keyless gateway serves a few free requests per client per rolling\nwindow before it starts charging. Response header\n`X-Free-Probes-Remaining` tells you how many are left, and\n`X-Price-Next-Call` what the next one will cost.\n\nFile v1.1.51:skill-card.md\n\n## Description:\n\nHelps agents retrieve live Amazon product, price, review, offer, stock, seller, and search data from Apiguru across supported marketplaces.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[apiguru-app](https://clawhub.ai/user/apiguru-app)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and other agents use this skill to answer user-requested Amazon marketplace questions about products, prices, reviews, availability, and sellers, or to monitor these details across supported marketplaces.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Product queries contact Apiguru and can incur charges when a user supplies an API key or uses their own payment-capable client.\n\nMitigation: Check prices and free-call availability, obtain explicit consent before billable requests, and set a spending cap.\n\nRisk: Optional feedback is posted publicly and could expose secrets or private user data.\n\nMitigation: Request consent before posting feedback and omit API keys, personal information, and private user content.\n\nRisk: The optional MCP server or package installation is separate software not covered by this skill's review.\n\nMitigation: Review the MCP server or package separately before use; prefer the included script when that review is unavailable.\n\n## Reference(s):\n\n- [Apiguru endpoint reference](references/endpoints.md)\n- [Apiguru costs, billing, and retries](references/errors-and-costs.md)\n- [Apiguru agent-kit homepage (listed in release metadata)](https://github.com/apiguru-app/agent-kit)\n- [Apiguru API endpoint and price catalog](https://agent.apiguru.app/.well-known/x402)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, JSON]\n\n**Output Format:** [Natural-language answers or structured API responses]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Live data is limited to supported Amazon marketplaces; requests may consume free calls or incur charges with an explicitly supplied API key.]\n\n## Skill Version(s):\n\n1.1.51 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.50: 6 files, 33088 bytes\n\nFiles: references/endpoints.md (23768b), references/errors-and-costs.md (3955b), scripts/probe.py (39932b), skill-card.md (2561b), SKILL.md (19800b), _meta.json (139b)\n\nFile v1.1.50:SKILL.md\n\n---\nname: apiguru-amazon-data\ndescription: Live Amazon marketplace data from Apiguru (a paid third-party API, 3 free calls a day) - product details, prices, reviews, keyword search, best-sellers, deals, offers and stock, seller profiles, across 23 Amazon marketplaces. Use only when the user asks for Amazon data by ASIN, Amazon URL, product, seller or keyword, or for Amazon price/stock/review monitoring. Not for other stores or general shopping advice. Never pays on its own; ask before any billable call. We want your feedback - if a field is wrong, missing or you wish the API did something else, say so with the free `feedback` command (no account needed); the agents that report are the ones this API gets fixed for.\nlicense: MIT\ncompatibility: Needs Python 3.10+ and outbound HTTPS to agent.apiguru.app and dash.apiguru.app only. Reads no environment variables and no local files except an API-key file the user names.\nallowed-tools: Bash(python3:*) Bash(python:*) Read\nhomepage: https://github.com/apiguru-app/agent-kit\nmetadata: {\"openclaw\": {\"emoji\": \"📦\", \"homepage\": \"https://github.com/apiguru-app/agent-kit\", \"requires\": {\"anyBins\": [\"python3\", \"python\"]}}}\n---\n\n# Apiguru Amazon Data\n\nLive, structured Amazon data fetched at request time from Apiguru's servers.\n23 marketplaces.\n\n**What this skill writes.** Every data command is a read: it fetches and\nreturns, and changes nothing anywhere. There is exactly one write, and it is\nnever automatic — the `feedback` command posts the text you give it to\nApiguru's public feedback wall (see \"Telling us what is broken\" below). It\nsends only that text, it costs nothing, and it runs only when you invoke it.\nNothing else in this skill sends data anywhere.\n\n## Costs and consent (read this first)\n\n- **Hosts contacted:** `agent.apiguru.app` (keyless) and `dash.apiguru.app`\n  (the keyed API, and the feedback wall, which needs no key). Nothing else.\n  `scripts/probe.py` has both hosts fixed in the source, reads no environment\n  variables, and **refuses every redirect**, so a key cannot be carried to a\n  third host by a `302`.\n- **Free quota:** 3 calls per machine per 24 hours. After that the gateway\n  answers `402 Payment Required`. **The answer knows better than this\n  page:** every keyless reply carries `free_calls_remaining` in the body and\n  `X-Free-Probes-Remaining` (or `X-Free-Probes-Available: yes|no` where no\n  count is given) in the headers. Plan a task on the last reply, never on\n  the number above.\n- **This skill never pays.** `probe.py` stops at a 402 and tells you so. It\n  contains no wallet and no x402 client, and it will not set one up. Paying is\n  the user's decision, made one of two ways, both only with their explicit\n  consent:\n  1. an Apiguru API key, handed to the script by the user through `--api-key`\n     (an unechoed prompt), `--api-key-file PATH` or `--api-key-stdin` — bills\n     their account at their plan's rates, about USD 0.01 per call — or\n  2. their own x402-capable HTTP client with a funded wallet and a spend cap\n     (USDC on Base, Polygon, Arbitrum or Avalanche). How that works is documented for the user at\n     `https://agent.apiguru.app/llms-full.txt`, section \"Paying\".\n- **Ask before you spend.** Before the first billable call in a task, and\n  before any batch or broad search, tell the user what you will call, how many\n  items, and what it costs (run `capabilities` first, it is free), and wait\n  for a yes. A single batch call can cost up to USD 0.16 (`/product`, 20 items)\n  or USD 0.15 (`/stock`, 10 items). Agree a cap for the task and stop at it.\n- Do not go looking for an API key: not in the environment, not in config or\n  dotfiles, not anywhere the user did not hand you deliberately. `--api-key-file`\n  takes only a path the user named. Never send a key anywhere but\n  `dash.apiguru.app`, and never echo it back into the conversation, a log or a\n  command line.\n\n## Getting access\n\n**Keyless (default).** Call the agent gateway with no credentials:\n\n```\nGET https://agent.apiguru.app/agent/v1/v2/product-details?asin=B09DJLW458&geo=US\n```\n\nTwo response headers say where you stand before a 402 arrives:\n`X-Free-Probes-Remaining` and `X-Price-Next-Call`.\n\n`https://agent.apiguru.app/.well-known/x402` lists every endpoint with prices\nand schemas, free and unmetered. Check it before planning a job.\n\n**Keyed.** If the user gives you an Apiguru API key and asks you to use it,\nlet the script read it — never put it on the command line, where shell\nhistory and the process table expose it to every other local user:\n\n- `--api-key` prompts for it (not echoed, not stored),\n- `--api-key-file PATH` reads a file the user names (readable only by them),\n- `--api-key-stdin` reads one line from standard input, e.g.\n  `pass show apiguru | python scripts/probe.py ... --api-key-stdin`.\n\nThe script then sends it as `X-API-KEY` to `https://dash.apiguru.app/api/v1`\n(same paths) and to nowhere else — redirects are refused rather than\nfollowed. Calls bill that account.\n\n`scripts/probe.py` wraps all of this. Prefer it over hand-written HTTP calls:\nit retries only unbilled failures and explains every status.\n\n## Choosing an endpoint\n\n| Need | Endpoint |\n|---|---|\n| Everything about one ASIN | `/v2/product-details` |\n| Many ASINs (≤20) | `/product?asins=A,B,C` — **cheaper per item, use this for >1** |\n| Reviews, rating, \"customers say\" | `/v2/product-reviews` |\n| Find products by keyword | `/search?query=...` |\n| Offers, buy box, live stock (≤10) | `/stock?asins=...` |\n| Category rankings | `/v2/best-sellers` |\n| Current discounts | `/v2/deals` |\n| A seller's catalogue | `/v2/seller-products?seller_id=...` |\n| Seller reputation | `/v2/seller-reviews?seller_id=...` |\n| Seller profiles (≤10) | `/seller-profile?seller_ids=...` |\n\nFull parameter reference: `references/endpoints.md`.\n\n## Rules that prevent wasted calls and wasted money\n\n1. **An ASIN is 10 letters and digits** (`^[A-Z0-9]{10}$`). Any case works, and\n   the gateway also reads an Amazon product URL (`/dp/ASIN`) in its place.\n2. **Never loop a single-item endpoint over a list.** Use `/product` for\n   ASINs and `/seller-profile` for seller IDs. Ten ASINs through `/product`\n   costs USD 0.08 and one round trip; ten through `/v2/product-details` costs\n   USD 0.10 and ten round trips.\n3. **Choose `geo` from the user's request**, never by habit: amazon.de → `DE`,\n   amazon.co.uk → `UK`, and so on (all 23 codes in `references/endpoints.md`).\n   If the marketplace is not clear, ask. The API assumes `US` only when the\n   parameter is omitted; a product that exists on `amazon.de` may genuinely\n   `404` on `US`, and that 404 is billed on the keyed path.\n4. **`check_inventory=true` on `/stock` is slow and bills more.** Only set it\n   when the user needs the stock number, not just the offers.\n5. **Read `success` in the body**, not just the HTTP status. Some responses\n   are `200` with `success: false`.\n6. **`/v2/deals` filters by id, and tells you the ids.** `categories` takes a\n   department name as Amazon shows it (`Electronics`, `Elektronik & Foto` on\n   DE) or its id; `brands` takes brand ids only. Every deals answer carries\n   `available_filters` (the category and brand ids of that marketplace),\n   `filters_applied` / `filters_ignored` (what actually took effect) and\n   `next_offset` (the next page, `null` when the feed ends). Narrow price and\n   discount with `min_price`, `max_price`, `min_discount`. For a brand by\n   name use `/search?brand=<name>&today_deals=true` instead.\n7. **Every list answer reports its filters.** `/search` and\n   `/v2/seller-products` return `filters_applied`, `filters_ignored` (a\n   filter this marketplace cannot apply, with the reason -- amazon.fr has no\n   Today's Deals refinement, amazon.in offers only NEW) and\n   `available_filters`. `product_condition` is NEW / USED / RENEWED,\n   `deal_type` is today_deals / all_discounts / coupons / buy_more_save_more,\n   prices take decimals. `/v2/best-sellers` departments differ per\n   marketplace: pass a slug or name and read `available_categories` and\n   `available_subcategories` (the ids `subcategory_code` takes) from the\n   answer; pages run 1-5.\n8. **`/v2/best-sellers` tells you how it read `category`.** A word that is\n   only part of a department name still matches it — `category=shoes` is the\n   whole *Clothing, Shoes & Jewelry* department, hoodies included. The answer\n   says so: `category_resolution.via` is `fragment`, and `hint` lists the\n   subcategories carrying that word with their ids (`Women > Shoes` is\n   `679337011`, `Men > Shoes` is `679255011`). On amazon.com\n   `subcategory_code` takes any browse node id at any depth, or a name\n   resolved under the department — `subcategory_code=women's shoes`,\n   `mules & clogs` — and the answer carries `category.subcategory_path`\n   (\"Clothing, Shoes & Jewelry > Women > Shoes > Mules & Clogs\") and\n   `category.heading` (the page's own title). A name two nodes share equally\n   is a free `400` listing both ids with their paths; pass the one you mean.\n\n## Big responses, and the two fields that mislead\n\nA full `/search` page is up to 48 results and about **54 KB** of JSON — enough\nthat most clients write it to a file instead of showing it to you. Keep it\nsmall at the source:\n\n- **Filter before you page.** `brand`, `min_price`/`max_price`,\n  `product_condition` and `sort_by` cut the result set before it is fetched,\n  so the answer is both smaller and more relevant. Paging does neither.\n- **Ask for less.** `limit=N` caps the rows (`limit=0` for the whole page),\n  `compact=true` returns light rows, and\n  `fields=\"asin,product_title,product_price\"` returns only what you name.\n  These work the same way on the REST endpoints and over MCP, on every list\n  tool: `search`, `best_sellers`, `deals`, `seller_products` and\n  `seller_reviews`.\n- **The defaults differ, deliberately.** Over MCP a list tool returns the\n  first **10 light rows** (about 7 KB) because a tool result goes straight\n  into a context window. Over `probe.py` you get the **whole page** unless\n  you ask otherwise, because a script can pipe it — so\n  `probe.py search --query ... --limit 10 --compact` (or\n  `--fields asin,product_title,product_price`) is worth adding when you are\n  reading the answer rather than filtering it. A parameter the script has no\n  flag for goes through `--param name=value`.\n- **The answer says what it did.** `_truncated` gives the real row count and\n  the exact `limit=` to pass for all of them, `_omitted_fields` names what\n  the light projection dropped, and `_notes` carries the things that will\n  mislead you when reading these particular rows.\n\nThree properties of Amazon's own data that will mislead you if you assume\notherwise:\n\n1. **`product_num_ratings` is per listing family, not per ASIN.** Variants\n   share a review pool, so every colour of one shoe reports the same count.\n   Do not present it as \"this variant has N reviews\".\n2. **A variant's title can be the parent's.** In search results the ASIN and\n   the title can disagree — the URL slug usually shows the real variant. When\n   the exact variant matters, call `/v2/product-details` on that ASIN; it is\n   authoritative for the ASIN you passed.\n3. **A search row's badges are the result card's, not the listing's.**\n   `badges` (and the derived `is_amazon_choice` / `is_best_seller`) say what\n   Amazon printed on that card for *that query*. `sort_by=BEST_SELLERS` is\n   Amazon's popularity order for the query, not a category rank — so an ASIN\n   that is #1 in *Women's Mules & Clogs* can show `badges: []` in a search\n   for \"crocs white\" while `/v2/product-details` reports `best_seller: true`\n   with the rank. For a rank claim, use product-details or best-sellers;\n   `filters_applied.sort_by` echoes the order the page actually used.\n\n`badges` is the source of truth for Amazon's Choice / Best Seller / Overall\nPick (Amazon renamed that slot to \"Overall Pick\"); `is_amazon_choice` and\n`is_best_seller` are derived from it.\n\n## Error handling — which failures cost money\n\n- **`404`** — the item genuinely is not on that marketplace. **Billed** on the\n  keyed path. Retrying will not help; try a different `geo` or accept it.\n- **`503`** — a temporary Apiguru-side failure. **Not billed.** Retry with\n  backoff. `500`, `502` and `504` are the same class: not billed, retry.\n- **`429`** — rate limited. Back off, then retry.\n- **no answer** (your client timed out) — keyless, nothing was billed; retry.\n  **With an API key the call may still have finished and been billed**, so it\n  is not repeated automatically: tell the user and retry only if they agree.\n  Some marketplaces answer more slowly; allow 60s before giving up.\n- **`400`** — your input was wrong (bad ASIN format, unknown geo, missing\n  required parameter). Not billed. Fix the input; do not retry unchanged.\n- **`402`** — free probes spent. **Stop and ask the user** (see \"Costs and\n  consent\"). Do not retry, do not look for a key, do not attempt payment.\n\nSo: **retry `429`, `500`, `502`, `503`, `504` and keyless timeouts (unless the\nbody says `retryable: false`); never retry `400`, `402`, `404` or `413`, and\nnever repeat a timed-out keyed call without the user's say-so.**\n`scripts/probe.py` does exactly this. Its exit status tells a job what\nhappened: `0` usable answer, `1` HTTP error or a body reporting failure,\n`2` input rejected before any request, `3` a batch with some failed rows.\n\n## Quick start\n\n```bash\n# prices, the free-probe policy, and how many free probes THIS caller has\n# left right now (from /health; the policy number is not your balance). Free.\npython scripts/probe.py capabilities\n\n# one product\npython scripts/probe.py product-details --asin B09DJLW458 --geo US\n\n# many at once (preferred for lists)\npython scripts/probe.py product --asins B09DJLW458,B0BSHF7WHW --geo US\n\n# keyword search on amazon.co.uk\npython scripts/probe.py search --query \"wireless earbuds\" --geo UK\n\n# billed to the user's account, only after they said so.\n# --api-key prompts; the key never appears in argv or in shell history.\npython scripts/probe.py product-details --asin B09DJLW458 --geo US --api-key\n\n# non-interactive equivalent, key straight from a secret store\npass show apiguru | python scripts/probe.py product-details --asin B09DJLW458 --api-key-stdin\n```\n\n## MCP alternative (optional, and outside this skill's audit)\n\n**`scripts/probe.py` above is the supported path.** It is part of this skill,\nit was reviewed with it, it is standard-library only, and it downloads and\nexecutes nothing. Use it unless someone has decided otherwise.\n\nThe same data is also published as an MCP server. That server is a **separate\nartifact**: it is not shipped in this skill, it was not covered by whatever\nreview this skill passed, and it needs its own security review before anyone\nruns it. Three ways to reach it, safest first:\n\n**1. The hosted server — nothing is installed or executed on your machine.**\n\n```\nhttps://mcp.apiguru.app/mcp        streamable HTTP\nhttps://mcp.apiguru.app/account    the same thing behind OAuth 2.1\n```\n\nYour client talks HTTP to a server we run. No package is fetched, so there is\nno supply chain on your side at all. This is the option to prefer.\n\n**2. Install it once, deliberately, then run what you installed.** If you want\nit local, make it a controlled deployment step rather than a fetch on every\nlaunch:\n\n```bash\npython -m venv ~/.venvs/apiguru && ~/.venvs/apiguru/bin/pip install \"apiguru-mcp==1.1.50\"\n# then point the client at the binary you just reviewed and installed:\n#   \"command\": \"/home/you/.venvs/apiguru/bin/apiguru-mcp\"\n```\n\nPin transitive dependencies too if that matters to you: resolve once with\n`pip freeze > apiguru-lock.txt`, review it, and install from that file with\n`--require-hashes`.\n\n**3. Fetch at launch (`uvx` / `npx`).** Convenient, and the weakest of the\nthree: the launcher resolves and executes a package from a public registry\nevery time the client starts. Pinning the version — which the snippets below\ndo — stops it silently moving to a newer release, but it does not protect you\nfrom a compromised publisher account or registry.\n\n```json\n{ \"mcpServers\": { \"apiguru\": { \"command\": \"uvx\",\n  \"args\": [\"apiguru-mcp==1.1.50\"] } } }\n```\n\nor, with Node instead of Python, `\"command\": \"npx\", \"args\": [\"apiguru-mcp@1.1.50\"]`.\n\nWhichever you choose:\n\n- **Expected publisher:** `apiguru-app`. **Registries:** PyPI\n  (`apiguru-mcp`, https://pypi.org/project/apiguru-mcp/) and npm\n  (`apiguru-mcp`, https://www.npmjs.com/package/apiguru-mcp). Both are listed\n  in the official MCP Registry as `app.apiguru/amazon-data`. Anything under\n  another name or publisher is not ours.\n- **Verify the artifact, not just the name and version.** PyPI and npm publish\n  a SHA-256 for every file; `pip download apiguru-mcp==<version>` then\n  `pip hash` gives you a digest to record and re-check on the next upgrade.\n- **Before raising the pin**, read the changelog at\n  https://github.com/apiguru-app/agent-kit/releases and diff the dependency\n  list. Do it deliberately; do not let a launcher do it for you.\n- **Run it with least privilege**: it needs outbound HTTPS to\n  `agent.apiguru.app`, `dash.apiguru.app` and `mcp.apiguru.app` and nothing\n  else — no filesystem access, no other credentials in its environment. A\n  container is the easy way: an official image is published for exactly this\n  (`mcp/apiguru`, Docker's MCP catalogue).\n\nThe MCP tools do the same thing as `probe.py` and follow the same rules — they\nnever pay on their own. A 402 comes back as an x402 PaymentRequired result: the\nuser decides, and only an x402-capable MCP client they set up (with a spend cap)\ncan pay it. Their advantage is that they validate ASINs and geos before spending a\nprobe.\n\n## Telling us what is broken\n\nThis API gets fixed when the agents using it say what is wrong. Recent\nexample: search results were returning the brand as `product_title` and\n`null` for `product_num_ratings`; an agent reported both and both are fixed.\nSo if a field is empty, mistyped, welded together or simply missing:\n\n- **Preferred, if you have a GitHub account** — open an issue at\n  https://github.com/apiguru-app/agent-kit/issues. A thread there can hold a\n  reply and a fix gets linked back to it.\n- **No GitHub account? Use the wall** — one unauthenticated POST, never\n  billed, no signup:\n\n  ```bash\n  curl -X POST https://dash.apiguru.app/api/v1/feedback -H 'Content-Type: application/json' -d '{\"message\": \"search: product_title holds the brand, not the title\", \"category\": \"bug\", \"endpoint\": \"/search\", \"agent\": \"your-name/1.0\"}'\n  ```\n\n  `category` is one of `bug`, `wish`, `praise`, `question`, `other`. Add\n  `\"contact\"` if you want a reply — it is shown publicly on the wall.\n\n  **The wall is public, so send only what the user has agreed to, and only\n  about the API:** the tool, the parameters, the field, what you expected and\n  the `request_id`. Never an API key, personal data, or the user's own\n  prompts, documents or results beyond the field in question.\n- **Over MCP** — the free `send_feedback` tool does the same thing.\n- Read what other agents have written: https://dash.apiguru.app/feedback\n\nSay what you called, what you expected and what came back, and quote the\n`request_id` from the answer. **One issue per entry** — a five-point list\ncannot be closed point by point, and each entry gets its own status on the\nwall (`open`, `fixed`, `documented`, `answered`, `wont_fix`). A wish counts:\nif you need a field this API does not return, that is the most useful thing\nyou can tell us.\n\n## Reference files\n\n- `references/endpoints.md` — every endpoint, parameter, and marketplace code\n- `references/errors-and-costs.md` — pricing, billing rules, retry strategy\n\nFile v1.1.50:_meta.json\n\n{\n  \"ownerId\": \"kn743rz4efdce60qkmj9x20cr18dr5cm\",\n  \"slug\": \"apiguru-amazon-data\",\n  \"version\": \"1.1.50\",\n  \"publishedAt\": 1790943350723\n}\n\nFile v1.1.50:references/endpoints.md\n\n# Apiguru endpoint reference\n\nGenerated from the API spec - do not edit by hand.\n\n- Keyless base URL: `https://agent.apiguru.app/agent/v1`\n- Keyed base URL: `https://dash.apiguru.app/api/v1` (send `X-API-KEY`)\n\nAll endpoints are `GET` with query parameters.\n\n## Marketplaces\n\nPass as `geo`, chosen from the user's request or the Amazon domain they mention (amazon.de -> DE). The API assumes `US` only when the parameter is omitted; do not rely on that default.\n\n| Code | Domain |\n|---|---|\n| `US` | amazon.com |\n| `CA` | amazon.ca |\n| `DE` | amazon.de |\n| `MX` | amazon.com.mx |\n| `UK` | amazon.co.uk |\n| `FR` | amazon.fr |\n| `IT` | amazon.it |\n| `ES` | amazon.es |\n| `AU` | amazon.com.au |\n| `BR` | amazon.com.br |\n| `IN` | amazon.in |\n| `JP` | amazon.co.jp |\n| `NL` | amazon.nl |\n| `AE` | amazon.ae |\n| `PL` | amazon.pl |\n| `SA` | amazon.sa |\n| `SG` | amazon.sg |\n| `SE` | amazon.se |\n| `TR` | amazon.com.tr |\n| `BE` | amazon.com.be |\n| `IE` | amazon.ie |\n| `ZA` | amazon.co.za |\n| `EG` | amazon.eg |\n\n## `GET /v2/product-details`\n\nUse for one product's current listing. Not for several ASINs (product_details_batch), seller offers or stock (offers_stock), or review text (product_reviews). Fetches the complete product record for one ASIN on one marketplace: title, price, star rating, rating count, images, description, feature bullets, variations and category.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asin` | string | yes | Single Amazon ASIN, 10 uppercase alphanumeric characters. Exactly one - comma-separated lists are rejected; use product_details_batch for many. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> 404 means the ASIN is absent from that marketplace and IS billed. 503 is a temporary failure on our side and is NOT billed - retry. Bullet points and specs are what Amazon shows for the listing; on multi-variant listings they can describe the product family rather than the exact variant. A null field means Amazon did not show it.\n\n## `GET /v2/product-reviews`\n\nUse for what customers say about one product. Not for its full review history (Amazon serves full and star-filtered review lists only to signed-in accounts) or for seller feedback (seller_reviews). Returns the overall rating, rating count, review_histogram (percent of all ratings per star), Amazon's 'customers say' AI summary where that marketplace shows one, and the reviews on the product page (typically up to 8 from this marketplace and 5 from other countries), each with rating, review_date, review_country, from_this_marketplace, verified flag and helpful_votes; from_rating/to_rating keep a star window.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asin` | string | yes | Single Amazon ASIN, 10 uppercase alphanumeric characters. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `from_rating` | integer | no | Lowest star rating to include, 1-5. Filters the reviews the product page shows (see review_coverage). |\n| `to_rating` | integer | no | Highest star rating to include, 1-5. from_rating=1&to_rating=3 keeps the critical ones among them. |\n\n> Same 404-billed / 503-not-billed semantics as product_details. No paging or sort: the reviews are those on the product page; review_coverage says how many and from where. from_rating/to_rating filter them. review_histogram (here and on product_details) gives the share of every rating. customers_say is null where Amazon shows no summary (several marketplaces never do); customers_say_note then says so.\n\n## `GET /search`\n\nUse to find products by keyword and filters. Rows are result snippets; for the authoritative record of one ASIN call product_details. Search Amazon products by keyword. Filters: page, sort_by, category_id (browse node), min_price / max_price (decimals), product_condition (NEW / USED / RENEWED), brand, seller_id, today_deals and deal_type (coupons, all_discounts, buy_more_save_more). Every answer carries filters_applied, filters_ignored (with the reason) and available_filters for that marketplace.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `query` | string | yes | Search keywords. Required and must be non-empty. |\n| `page` | integer | no | Result page, 1-based. metadata.total_pages says how far it goes. Default `1`. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `sort_by` | enum | no | Result ordering. Default `RELEVANCE`. |\n| `category_id` | string | no | Amazon browse node id to restrict to, e.g. 172282 (Electronics on US). Take one from a best_sellers answer's available_subcategories, a product's category_path, or node= in an Amazon URL. Ids differ per marketplace. |\n| `min_price` | number | no | Lowest price, in the marketplace currency; decimals such as 19.99 are fine. |\n| `max_price` | number | no | Highest price, in the marketplace currency. |\n| `product_condition` | enum | no | NEW, USED or RENEWED (case-insensitive). Applied with the marketplace's own condition node; where a marketplace does not offer one, the answer's filters_ignored says so and available_filters lists what it does offer. |\n| `brand` | string | no | Brand name as Amazon spells it (case-insensitive), e.g. Samsung. |\n| `seller_id` | string | no | Restrict results to one seller's offers: an Amazon seller id, 'A' followed by 9-20 letters and digits (e.g. A2A1RNLLUK3HYA). |\n| `today_deals` | boolean | no | Only items in Today's Deals, using that marketplace's own refinement. Where a marketplace has none (amazon.fr on 2026-09-08) it is reported under filters_ignored. Default `False`. |\n| `deal_type` | enum | no | A specific promotion refinement: today_deals, all_discounts, coupons or buy_more_save_more. available_filters.deal_type lists the ones this marketplace has. |\n\n`sort_by` accepts: `RELEVANCE`, `BEST_SELLERS`, `LOW_HIGH_PRICE`, `HIGH_LOW_PRICE`, `REVIEWS`, `NEWEST`\n\n`product_condition` accepts: `NEW`, `USED`, `RENEWED`\n\n`deal_type` accepts: `today_deals`, `all_discounts`, `coupons`, `buy_more_save_more`\n\n> Blank values and the literal string 'null' are treated as unset. Invalid page, sort_by, price, product_condition or deal_type is a free 400 naming the parameter and the allowed values. Condition and deal refinements are per marketplace; a marketplace that lacks one gets the unfiltered feed plus an entry under filters_ignored, never a silent empty page. `product_num_ratings` and `offers_count` are integers; `product_star_rating`, `product_price` and `product_original_price` are decimal strings; a null field means Amazon did not show it. `is_prime` is true when the result carries a Prime badge or its delivery line offers Prime delivery. `metadata.total_pages` says how far `page` can go. A full page is up to 48 results and about 54 KB; the tool returns the first 10 as light rows by default and the answer carries `_truncated`, `_omitted_fields`, `_projection` and `_notes`. filters_applied echoes the effective sort_by (RELEVANCE when none was sent). A BEST_SELLERS ordering is Amazon's query-scoped popularity, not a category rank: a row's `badges` / `is_best_seller` are what the result card showed for this query, and an ASIN that is #1 in its subcategory can carry no badge here while product_details reports best_seller=true with the rank. For a rank claim, use product_details or best_sellers. An empty `products` list is served as success only when Amazon itself reports 0 results (metadata.total is 0 and `hint` says so). Anything else that is not a usable result is an unbilled, retryable 503 with code upstream_unavailable.\n\n## `GET /product`\n\nUse to enrich a list of ASINs in one call; compare the ASINs in `results` with the ones you sent. Batch variant of product_details. Accepts a comma-separated ASIN list, deduplicates it, and fetches all of them concurrently. Far cheaper and faster than N single calls.\n\n**Price:** $0.0024 per item (max 20)\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asins` | string | yes | Comma-separated ASIN list, maximum 20 after de-duplication. Each must be 10 uppercase alphanumeric characters. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> Billed per ASIN processed, including ones that come back not-found. More than 20 ASINs returns 413. Bullet points and specs are what Amazon shows for the listing; on multi-variant listings they can describe the product family rather than the exact variant. A null field means Amazon did not show it. ASINs Amazon has no record for on that marketplace are listed in not_returned (billed, like a not-found product_details call; retrying will not help).\n\n## `GET /stock`\n\nUse to compare sellers' current offers and see who holds the buy box, and, with check_inventory, how many units a buyer can add to the cart now. The stock number is not a sales estimate. Not for the listing's own details (product_details). Returns the current offer list per ASIN (seller, price, condition, buy-box winner) and, optionally, the actual purchasable stock quantity.\n\n**Price:** $0.0045 per item (max 10)\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asins` | string | yes | Comma-separated ASIN list, maximum 10. Each must be 10 uppercase alphanumeric characters; malformed entries are rejected with 400. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `check_inventory` | boolean | no | Resolve the true purchasable stock quantity. Slower and bills more lookups, so leave off unless you need the number. Default `False`. |\n| `offers_count` | string | no | 'all' for every offer (default), 'winner' for the buy-box offer only, or a specific alphanumeric Offer ID. Every offer carries is_buybox_winner; with 'winner' the per-ASIN data holds that one offer and offers_total says how many exist. An ASIN with no featured offer answers an empty list with an explanatory error. The response echoes filters_applied. Default `all`. |\n| `condition` | string | no | Comma-separated condition filter: ALL, NEW, USED_LIKE_NEW, USED_VERY_GOOD, USED_GOOD, USED_ACCEPTABLE (case-insensitive). Omit for every offer. An unknown value is a free 400 listing the allowed ones; it used to be silently treated as ALL. |\n\n> Billed per lookup, which is more than one per ASIN when check_inventory is true. offers_count=winner returns only the offer flagged is_buybox_winner (offers_total keeps the full count); it used to scope only the inventory check and return every offer. /scrape is a legacy alias for the same handler. When Amazon will not return the offer list for an ASIN, the result carries source=product_page: the featured (buy-box) offer read from the product page, offers_on_amazon (how many offers Amazon says exist) and a note; other sellers' offers and stock are then not included.\n\n## `GET /v2/best-sellers`\n\nUse for what sells best in a department right now. The rank is Amazon's, not a sales figure. Best-seller rankings for a department of one marketplace, 50 per page. Every answer carries the department it resolved to and how (category_resolution: by slug, name or a fragment of a name, with a hint when a fragment such as 'shoes' landed on the whole 'Clothing, Shoes & Jewelry' department, or 'subcategory' when a word such as 'camera' named a subcategory), available_categories (that marketplace's departments with slugs; MCP: with compact=false) and available_subcategories (the children of the node shown, with the ids subcategory_code takes). On amazon.com subcategory_code also takes any browse node id at any depth, or a name resolved under the department (\"women's shoes\", \"mules & clogs\"); category.subcategory_path gives the node's full path and category.heading the page's own title line.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `category` | string | no | Best-seller department, by slug or by name as Amazon shows it for that marketplace (case-insensitive; a unique fragment works, and the answer's category_resolution says when a fragment was used -- 'shoes' is the whole 'Clothing, Shoes & Jewelry' department, and the hint then lists the Shoes subcategories with their ids). Departments and their slugs differ per marketplace: amazon.com has electronics, amazon.de has ce-de (Electronics & Photo). A word that names a subcategory works too: category=camera on amazon.es is Electronics > Camera & Photo (category_resolution.via says 'subcategory'; several equally good matches are a free 400 listing each as category + subcategory_code). REST answers list the marketplace's departments under available_categories (the MCP tool with compact=false); an unknown name is a free 400 listing them. Default `appliances`. |\n| `subcategory_code` | string | no | Browse node id under `category`: one from available_subcategories of a previous answer, or on amazon.com any node id at any depth (679410011 is Women > Shoes > Mules & Clogs) or a name resolved under the department (\"women's shoes\", \"mens boots\", \"mules & clogs\"). A name that fits two nodes equally (Men > Shoes > Boots and Women > Shoes > Boots) is a free 400 listing both ids with their paths. |\n| `page` | integer | no | Result page, 1-based, 50 rows each; Amazon's lists stop at page 5. Default `1`. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> No required parameters - calling it bare returns US appliances page 1. `category` accepts a slug, a display name, one of the older US department names, or a unique fragment; category_resolution.via says which, and a fragment match adds a hint naming the subcategories that carry the word, with ids. On amazon.com the whole browse tree is known: subcategory_code takes any node id or a name at any depth, subcategory_name and subcategory_path are filled without a fetch, and available_subcategories lists the node's real children (empty on a leaf). Other marketplaces name only what their navigation showed. page is capped at 5 (a 400 beyond, not a 500). `rank` is the position within the requested list on this page. Rows are the same for every marketplace; only the department vocabulary differs, and the answer carries it.\n\n## `GET /v2/deals`\n\nUse for items currently promoted in Amazon's deals feed. Not for one product's price (product_details); for a brand by name use search with brand= and today_deals=true. Returns the current Amazon deals feed: ASIN, title, deal price, list price, discount, deal badge, start/end time and product links. Filter by department (categories), brand id (brands), rating cut-off, price bounds, minimum discount and Prime program. Every answer carries available_filters (the category and brand ids this marketplace accepts, with names), filters_applied / filters_ignored (what took effect) and next_offset (the next page, null when the feed ends).\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `offset` | integer | no | Row to start at. A page is 30 rows; pass the previous answer's next_offset for the next page. Default `0`. |\n| `categories` | string | no | Department to restrict to: its id from available_filters.categories, or its name as Amazon shows it for that marketplace (case-insensitive; a unique fragment such as \"electronics\" works). US departments: Amazon Devices & Accessories, Appliances, Arts Crafts & Sewing, Audible Books & Originals, Automotive, Baby Products, Beauty & Personal Care, Books, CDs & Vinyl, Cell Phones & Accessories, Clothing Shoes & Jewelry, Collectibles & Fine Art, Electronics, Everything Else, Grocery & Gourmet Food, Handmade Products, Health & Household, Home & Kitchen, Industrial & Scientific, Kindle Store, Movies & TV, Musical Instruments, Office Products, Patio Lawn & Garden, Pet Supplies, Software, Sports & Outdoors, Tools & Home Improvement, Toys & Games, Video Games. Other marketplaces use their own localised names -- read them from available_filters.categories of any deals answer for that geo. An unknown name is a free 400 listing the valid names. |\n| `brands` | string | no | Comma-separated brand ids, e.g. 46655 for Samsung on US. Take them from brand_id on any deals row or from available_filters.brands (the brands present in the current result). Names resolve only when this marketplace has already shown that brand; for a brand by name use /search with brand=<name> and today_deals=true instead. |\n| `min_product_star_rating` | enum | no | Amazon's deals feed offers one rating cut-off: 4 = four stars and up. ALL or omitted = no cut-off. Other values are rejected with a free 400. |\n| `min_price` | number | no | Lowest deal price to return, in the marketplace currency. Applied to the fetched rows; see notes. |\n| `max_price` | number | no | Highest deal price to return, in the marketplace currency. |\n| `min_discount` | integer | no | Smallest discount percentage to return, e.g. 50 for half price or better. |\n| `max_discount` | integer | no | Largest discount percentage to return. |\n| `prime_exclusive` | boolean | no | Only deals in Amazon's Prime Exclusive program. Default `False`. |\n| `prime_early_access` | boolean | no | Only Prime Early Access deals. A marketplace lists the programs it is running under available_filters.prime_programs; when Early Access is not running the answer is empty with a hint saying so. Default `False`. |\n\n`min_product_star_rating` accepts: `4`, `ALL`\n\n> Filters are by id: categories takes a department id or name, brands takes brand ids only; available_filters in every answer lists both with names, and filters_applied / filters_ignored report what Amazon honoured. A page is 30 rows; page with offset=next_offset (null when exhausted); total_count caps at 500. min_price, max_price, min_discount and max_discount are applied to the rows after retrieval, scanning up to 3 feed pages per call, so a page can hold fewer than 30 rows and total_count does not reflect them. An empty answer carries a hint saying why. Deal prices expire: check deal_ends_at. The older price_range and discount_range parameters are still accepted, as buckets (1-5 = under 25 / 25-50 / 50-100 / 100-200 / 200 and up; 1-4 = 10 / 25 / 50 / 70 percent off or more) or as bands such as 25-50 and 70+.\n\n## `GET /seller-profile`\n\nUse to vet sellers: name, rating and feedback counts as Amazon displays them. Returns the storefront profile for each seller id: business name, rating, feedback counts, address and marketplace presence.\n\n**Price:** $0.0036 per item (max 10)\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `seller_ids` | string | yes | Comma-separated seller IDs, maximum 10. Each must be an Amazon seller id -- 'A' followed by 9-20 letters and digits, e.g. A2A1RNLLUK3HYA -- or the whole call 400s. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> Seller ID validation is all-or-nothing: one malformed id rejects the entire request with 400. Every row in results is an object with `status`: `ok` (the profile), `not_found` (Amazon has no page for that id on this marketplace; billed, like a 404) or `unavailable` (could not be retrieved right now; NOT billed on the keyed path, `retryable: true`). A row is never null. billable_requests_count counts ok + not_found rows; on the pay-per-call rail the per-item quote is settled up front, so retry `unavailable` ids in a separate call rather than expecting a partial refund.\n\n## `GET /v2/seller-products`\n\nUse to list one seller's storefront. Products listed by a seller: a storefront search. Takes the same filters as search -- query, page, sort_by, category_id, min_price / max_price, product_condition, brand, today_deals, deal_type -- and answers with filters_applied, filters_ignored and available_filters like search does.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `seller_id` | string | yes | Amazon seller id whose storefront to list: 'A' followed by 9-20 letters and digits, the seller= or me= value of a storefront URL (e.g. A2A1RNLLUK3HYA). Required. |\n| `query` | string | no | Optional keywords to search within this seller's storefront. |\n| `page` | integer | no | Result page, 1-based. metadata.total_pages says how far it goes. Default `1`. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `sort_by` | enum | no | Result ordering. Default `RELEVANCE`. |\n| `category_id` | string | no | Amazon browse node id to restrict to, e.g. 172282 (Electronics on US). Take one from a best_sellers answer's available_subcategories, a product's category_path, or node= in an Amazon URL. Ids differ per marketplace. |\n| `min_price` | number | no | Lowest price, in the marketplace currency; decimals such as 19.99 are fine. |\n| `max_price` | number | no | Highest price, in the marketplace currency. |\n| `product_condition` | enum | no | NEW, USED or RENEWED (case-insensitive). Applied with the marketplace's own condition node; where a marketplace does not offer one, the answer's filters_ignored says so and available_filters lists what it does offer. |\n| `brand` | string | no | Brand name as Amazon spells it (case-insensitive), e.g. Samsung. |\n| `today_deals` | boolean | no | Only items in Today's Deals, using that marketplace's own refinement. Where a marketplace has none (amazon.fr on 2026-09-08) it is reported under filters_ignored. Default `False`. |\n| `deal_type` | enum | no | A specific promotion refinement: today_deals, all_discounts, coupons or buy_more_save_more. available_filters.deal_type lists the ones this marketplace has. |\n\n`sort_by` accepts: `RELEVANCE`, `BEST_SELLERS`, `LOW_HIGH_PRICE`, `HIGH_LOW_PRICE`, `REVIEWS`, `NEWEST`\n\n`product_condition` accepts: `NEW`, `USED`, `RENEWED`\n\n`deal_type` accepts: `today_deals`, `all_discounts`, `coupons`, `buy_more_save_more`\n\n> Unlike seller_profile_batch, seller_id format is not pattern-validated here. metadata.total_pages says how far page goes (48 rows a page). Invalid sort_by, price, product_condition or deal_type is a free 400 that lists the allowed values.\n\n## `GET /v2/seller-reviews`\n\nUse for a seller's customer feedback (service, shipping). Not for product reviews (product_reviews). Returns paginated seller feedback, optionally filtered to a star-rating window.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `seller_id` | string | yes | Amazon seller id: 'A' followed by 9-20 letters and digits, the seller= or me= value of a storefront URL (e.g. A2A1RNLLUK3HYA). Required. |\n| `page` | integer | no | Result page, 1-based, 5 reviews a page; has_next_page in the answer says whether another exists. Default `1`. |\n| `from_rating` | integer | no | Lowest star rating to include, 1-5. |\n| `to_rating` | integer | no | Highest star rating to include, 1-5. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> from_rating and to_rating are optional; omit both for unfiltered feedback. A page holds 5 reviews and the answer carries current_page and has_next_page; Amazon exposes no total, so page until has_next_page is false (up to page 100).\n\n## Formats\n\n- ASIN: `^[A-Z0-9]{10}$` - On agent.apiguru.app and the MCP server any case is accepted and upper-cased, and an Amazon product URL (/dp/ASIN, /gp/product/ASIN, ?asin=) works in place of an ASIN; its domain sets geo unless geo names another marketplace (then 400). The answer lists what was rewritten under parameters_interpreted (MCP: _input_interpreted).\n- Seller ID: `^[Aa][A-Za-z0-9]{9,20}$` - An Amazon seller id is 'A' followed by 9-20 letters and digits (10-21 characters in all) -- the seller= or me= value of a storefront URL, e.g. A2A1RNLLUK3HYA. Anything else is rejected with 400 before any fetch.\n- Sample ASIN for testing: `B09DJLW458`\n\nFile v1.1.50:references/errors-and-costs.md\n\n# Costs, billing and retries\n\nGenerated from the API spec - do not edit by hand.\n\n## Prices\n\n| Endpoint | Price |\n|---|---|\n| `/v2/product-details` | $0.003 per call |\n| `/v2/product-reviews` | $0.003 per call |\n| `/search` | $0.003 per call |\n| `/product` | $0.0024 per item (max 20) |\n| `/stock` | $0.0045 per item (max 10) |\n| `/v2/best-sellers` | $0.003 per call |\n| `/v2/deals` | $0.003 per call |\n| `/seller-profile` | $0.0036 per item (max 10) |\n| `/v2/seller-products` | $0.003 per call |\n| `/v2/seller-reviews` | $0.003 per call |\n\nBatch endpoints are billed per item and are cheaper per item than the\nsingle-item equivalents. Always prefer them for more than one item.\n\n## What each status means, and whether it costs money\n\n| Status | Billed? | Meaning and what to do |\n|---|---|---|\n| `400` | no | Bad input (bad ASIN format, unknown geo, missing required param). NOT billed. |\n| `401` | - | Missing or invalid API key on the keyed path. |\n| `402` | - | Payment required. On the agent path this carries a PAYMENT-REQUIRED challenge (over MCP: an x402 PaymentRequired tool result, payable in-band via _meta[\"x402/payment\"]). On the keyed path it means the account balance is exhausted. |\n| `403` | - | Account disabled, or no active subscription plan. |\n| `404` | **yes** | The ASIN genuinely does not exist on that marketplace. BILLED - the lookup was performed and the bad input was the caller's. Retrying will not help; try a different geo. |\n| `413` | - | Too many items in a batch request. |\n| `429` | - | Per-second rate limit exceeded for the plan. Back off and retry. |\n| `500` | no | Internal error. NOT billed. |\n| `502` | no | Bad gateway. NOT billed. Same class as 503: retry with backoff. |\n| `503` | no | Temporary failure on our side. NOT billed. Safe and correct to retry. |\n| `504` | no | Gateway timeout: the request ran past its deadline. NOT billed. Retry with backoff; a narrower query often succeeds. |\n| `timeout` | - | No response before your own client's deadline. A keyless call without a payment is never billed. On an API key, or with an x402 payment attached, the request may still complete after your client gave up, and is then billed like any answered call. Some marketplaces answer more slowly than others; allow 60s rather than retrying early. |\n\n## Retry policy\n\nRetry 429, 500, 502, 503 and 504 with backoff -- none of them are billed -- unless the error body says `retryable: false`. A client-side timeout on a key or a payment may have completed and been billed; allow 60s before retrying it. Never retry 400, 401, 402, 403, 404 or 413: the request itself is the problem and repeating it will not change the answer.\n\nConcretely (the same set `scripts/probe.py` retries):\n\n```python\nRETRYABLE = {429, 500, 502, 503, 504}   # answered, and not billed\nfor attempt in range(4):\n    try:\n        status, body = call(..., timeout=60)\n    except TimeoutError:\n        if api_key:                  # may have finished and billed after we gave up:\n            raise                    # stop, tell the user, retry only if they agree\n        status, body = 0, None       # keyless and unpaid: never billed\n    if (status in RETRYABLE or status == 0) and (body or {}).get('retryable') is not False:\n        time.sleep(2 ** attempt)\n        continue\n    break                            # 200/400/402/404/413 are final\n```\n\nA body's `retryable` flag wins over the status table: a 5xx whose\ncause is permanent says `retryable: false` and is not worth repeating.\nA timeout is different: on an API key (or with an x402 payment attached)\nthe request may still complete after your client gave up, so it is never\nretried automatically -- `scripts/probe.py` reports it and stops.\n\n## Free probes\n\nThe keyless gateway serves a few free requests per client per rolling\nwindow before it starts charging. Response header\n`X-Free-Probes-Remaining` tells you how many are left, and\n`X-Price-Next-Call` what the next one will cost.\n\nFile v1.1.50:skill-card.md\n\n## Description:\n\nRetrieves live Amazon product, pricing, review, search, stock, deal, and seller data across 23 marketplaces through Apiguru's API.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[apiguru-app](https://clawhub.ai/user/apiguru-app)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to retrieve current Amazon listing, price, review, offer, stock, search, deal, and seller information for user-requested marketplaces. It is not intended for other stores or general shopping advice.\n\n### Deployment Geography for Use:\n\nGlobal (23 supported Amazon marketplaces)\n\n## Known Risks and Mitigations:\n\nRisk: Amazon product, seller, or keyword queries are sent to Apiguru.\n\nMitigation: Use only for user-requested Amazon lookups and disclose the external service before sending sensitive queries.\n\nRisk: API-key or wallet-backed requests can incur charges.\n\nMitigation: Check remaining free calls and current prices, obtain explicit approval before billable calls, and agree a spending cap.\n\nRisk: Feedback posts may expose secrets or private information on a public wall.\n\nMitigation: Send feedback only with user consent; exclude API keys, personal information, and private prompts or results.\n\nRisk: Optional MCP integration introduces a separate package or server trust boundary.\n\nMitigation: Prefer the included probe script for direct use; review MCP server and package setup separately before enabling it.\n\n## Reference(s):\n\n- [ClawHub skill listing](https://clawhub.ai/apiguru-app/skills/apiguru-amazon-data)\n- [Project homepage (skill metadata)](https://github.com/apiguru-app/agent-kit)\n- [Apiguru API documentation](https://agent.apiguru.app/llms-full.txt)\n- [Endpoint reference](artifact/references/endpoints.md)\n- [Costs, billing and retries](artifact/references/errors-and-costs.md)\n\n## Skill Output:\n\n**Output Type(s):** [Text, JSON, Markdown, Shell commands, Guidance]\n\n**Output Format:** [JSON API results with text or Markdown explanations and optional shell commands]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Results depend on the selected marketplace, available API data, and free or approved paid access.]\n\n## Skill Version(s):\n\n1.1.50 (source: server-resolved ClawHub release)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.49: 6 files, 32660 bytes\n\nFiles: references/endpoints.md (22780b), references/errors-and-costs.md (3955b), scripts/probe.py (39782b), skill-card.md (2318b), SKILL.md (19800b), _meta.json (139b)\n\nFile v1.1.49:SKILL.md\n\n---\nname: apiguru-amazon-data\ndescription: Live Amazon marketplace data from Apiguru (a paid third-party API, 3 free calls a day) - product details, prices, reviews, keyword search, best-sellers, deals, offers and stock, seller profiles, across 23 Amazon marketplaces. Use only when the user asks for Amazon data by ASIN, Amazon URL, product, seller or keyword, or for Amazon price/stock/review monitoring. Not for other stores or general shopping advice. Never pays on its own; ask before any billable call. We want your feedback - if a field is wrong, missing or you wish the API did something else, say so with the free `feedback` command (no account needed); the agents that report are the ones this API gets fixed for.\nlicense: MIT\ncompatibility: Needs Python 3.10+ and outbound HTTPS to agent.apiguru.app and dash.apiguru.app only. Reads no environment variables and no local files except an API-key file the user names.\nallowed-tools: Bash(python3:*) Bash(python:*) Read\nhomepage: https://github.com/apiguru-app/agent-kit\nmetadata: {\"openclaw\": {\"emoji\": \"📦\", \"homepage\": \"https://github.com/apiguru-app/agent-kit\", \"requires\": {\"anyBins\": [\"python3\", \"python\"]}}}\n---\n\n# Apiguru Amazon Data\n\nLive, structured Amazon data fetched at request time from Apiguru's servers.\n23 marketplaces.\n\n**What this skill writes.** Every data command is a read: it fetches and\nreturns, and changes nothing anywhere. There is exactly one write, and it is\nnever automatic — the `feedback` command posts the text you give it to\nApiguru's public feedback wall (see \"Telling us what is broken\" below). It\nsends only that text, it costs nothing, and it runs only when you invoke it.\nNothing else in this skill sends data anywhere.\n\n## Costs and consent (read this first)\n\n- **Hosts contacted:** `agent.apiguru.app` (keyless) and `dash.apiguru.app`\n  (the keyed API, and the feedback wall, which needs no key). Nothing else.\n  `scripts/probe.py` has both hosts fixed in the source, reads no environment\n  variables, and **refuses every redirect**, so a key cannot be carried to a\n  third host by a `302`.\n- **Free quota:** 3 calls per machine per 24 hours. After that the gateway\n  answers `402 Payment Required`. **The answer knows better than this\n  page:** every keyless reply carries `free_calls_remaining` in the body and\n  `X-Free-Probes-Remaining` (or `X-Free-Probes-Available: yes|no` where no\n  count is given) in the headers. Plan a task on the last reply, never on\n  the number above.\n- **This skill never pays.** `probe.py` stops at a 402 and tells you so. It\n  contains no wallet and no x402 client, and it will not set one up. Paying is\n  the user's decision, made one of two ways, both only with their explicit\n  consent:\n  1. an Apiguru API key, handed to the script by the user through `--api-key`\n     (an unechoed prompt), `--api-key-file PATH` or `--api-key-stdin` — bills\n     their account at their plan's rates, about USD 0.01 per call — or\n  2. their own x402-capable HTTP client with a funded wallet and a spend cap\n     (USDC on Base, Polygon, Arbitrum or Avalanche). How that works is documented for the user at\n     `https://agent.apiguru.app/llms-full.txt`, section \"Paying\".\n- **Ask before you spend.** Before the first billable call in a task, and\n  before any batch or broad search, tell the user what you will call, how many\n  items, and what it costs (run `capabilities` first, it is free), and wait\n  for a yes. A single batch call can cost up to USD 0.16 (`/product`, 20 items)\n  or USD 0.15 (`/stock`, 10 items). Agree a cap for the task and stop at it.\n- Do not go looking for an API key: not in the environment, not in config or\n  dotfiles, not anywhere the user did not hand you deliberately. `--api-key-file`\n  takes only a path the user named. Never send a key anywhere but\n  `dash.apiguru.app`, and never echo it back into the conversation, a log or a\n  command line.\n\n## Getting access\n\n**Keyless (default).** Call the agent gateway with no credentials:\n\n```\nGET https://agent.apiguru.app/agent/v1/v2/product-details?asin=B09DJLW458&geo=US\n```\n\nTwo response headers say where you stand before a 402 arrives:\n`X-Free-Probes-Remaining` and `X-Price-Next-Call`.\n\n`https://agent.apiguru.app/.well-known/x402` lists every endpoint with prices\nand schemas, free and unmetered. Check it before planning a job.\n\n**Keyed.** If the user gives you an Apiguru API key and asks you to use it,\nlet the script read it — never put it on the command line, where shell\nhistory and the process table expose it to every other local user:\n\n- `--api-key` prompts for it (not echoed, not stored),\n- `--api-key-file PATH` reads a file the user names (readable only by them),\n- `--api-key-stdin` reads one line from standard input, e.g.\n  `pass show apiguru | python scripts/probe.py ... --api-key-stdin`.\n\nThe script then sends it as `X-API-KEY` to `https://dash.apiguru.app/api/v1`\n(same paths) and to nowhere else — redirects are refused rather than\nfollowed. Calls bill that account.\n\n`scripts/probe.py` wraps all of this. Prefer it over hand-written HTTP calls:\nit retries only unbilled failures and explains every status.\n\n## Choosing an endpoint\n\n| Need | Endpoint |\n|---|---|\n| Everything about one ASIN | `/v2/product-details` |\n| Many ASINs (≤20) | `/product?asins=A,B,C` — **cheaper per item, use this for >1** |\n| Reviews, rating, \"customers say\" | `/v2/product-reviews` |\n| Find products by keyword | `/search?query=...` |\n| Offers, buy box, live stock (≤10) | `/stock?asins=...` |\n| Category rankings | `/v2/best-sellers` |\n| Current discounts | `/v2/deals` |\n| A seller's catalogue | `/v2/seller-products?seller_id=...` |\n| Seller reputation | `/v2/seller-reviews?seller_id=...` |\n| Seller profiles (≤10) | `/seller-profile?seller_ids=...` |\n\nFull parameter reference: `references/endpoints.md`.\n\n## Rules that prevent wasted calls and wasted money\n\n1. **An ASIN is 10 letters and digits** (`^[A-Z0-9]{10}$`). Any case works, and\n   the gateway also reads an Amazon product URL (`/dp/ASIN`) in its place.\n2. **Never loop a single-item endpoint over a list.** Use `/product` for\n   ASINs and `/seller-profile` for seller IDs. Ten ASINs through `/product`\n   costs USD 0.08 and one round trip; ten through `/v2/product-details` costs\n   USD 0.10 and ten round trips.\n3. **Choose `geo` from the user's request**, never by habit: amazon.de → `DE`,\n   amazon.co.uk → `UK`, and so on (all 20 codes in `references/endpoints.md`).\n   If the marketplace is not clear, ask. The API assumes `US` only when the\n   parameter is omitted; a product that exists on `amazon.de` may genuinely\n   `404` on `US`, and that 404 is billed on the keyed path.\n4. **`check_inventory=true` on `/stock` is slow and bills more.** Only set it\n   when the user needs the stock number, not just the offers.\n5. **Read `success` in the body**, not just the HTTP status. Some responses\n   are `200` with `success: false`.\n6. **`/v2/deals` filters by id, and tells you the ids.** `categories` takes a\n   department name as Amazon shows it (`Electronics`, `Elektronik & Foto` on\n   DE) or its id; `brands` takes brand ids only. Every deals answer carries\n   `available_filters` (the category and brand ids of that marketplace),\n   `filters_applied` / `filters_ignored` (what actually took effect) and\n   `next_offset` (the next page, `null` when the feed ends). Narrow price and\n   discount with `min_price`, `max_price`, `min_discount`. For a brand by\n   name use `/search?brand=<name>&today_deals=true` instead.\n7. **Every list answer reports its filters.** `/search` and\n   `/v2/seller-products` return `filters_applied`, `filters_ignored` (a\n   filter this marketplace cannot apply, with the reason -- amazon.fr has no\n   Today's Deals refinement, amazon.in offers only NEW) and\n   `available_filters`. `product_condition` is NEW / USED / RENEWED,\n   `deal_type` is today_deals / all_discounts / coupons / buy_more_save_more,\n   prices take decimals. `/v2/best-sellers` departments differ per\n   marketplace: pass a slug or name and read `available_categories` and\n   `available_subcategories` (the ids `subcategory_code` takes) from the\n   answer; pages run 1-5.\n8. **`/v2/best-sellers` tells you how it read `category`.** A word that is\n   only part of a department name still matches it — `category=shoes` is the\n   whole *Clothing, Shoes & Jewelry* department, hoodies included. The answer\n   says so: `category_resolution.via` is `fragment`, and `hint` lists the\n   subcategories carrying that word with their ids (`Women > Shoes` is\n   `679337011`, `Men > Shoes` is `679255011`). On amazon.com\n   `subcategory_code` takes any browse node id at any depth, or a name\n   resolved under the department — `subcategory_code=women's shoes`,\n   `mules & clogs` — and the answer carries `category.subcategory_path`\n   (\"Clothing, Shoes & Jewelry > Women > Shoes > Mules & Clogs\") and\n   `category.heading` (the page's own title). A name two nodes share equally\n   is a free `400` listing both ids with their paths; pass the one you mean.\n\n## Big responses, and the two fields that mislead\n\nA full `/search` page is up to 48 results and about **54 KB** of JSON — enough\nthat most clients write it to a file instead of showing it to you. Keep it\nsmall at the source:\n\n- **Filter before you page.** `brand`, `min_price`/`max_price`,\n  `product_condition` and `sort_by` cut the result set before it is fetched,\n  so the answer is both smaller and more relevant. Paging does neither.\n- **Ask for less.** `limit=N` caps the rows (`limit=0` for the whole page),\n  `compact=true` returns light rows, and\n  `fields=\"asin,product_title,product_price\"` returns only what you name.\n  These work the same way on the REST endpoints and over MCP, on every list\n  tool: `search`, `best_sellers`, `deals`, `seller_products` and\n  `seller_reviews`.\n- **The defaults differ, deliberately.** Over MCP a list tool returns the\n  first **10 light rows** (about 7 KB) because a tool result goes straight\n  into a context window. Over `probe.py` you get the **whole page** unless\n  you ask otherwise, because a script can pipe it — so\n  `probe.py search --query ... --limit 10 --compact` (or\n  `--fields asin,product_title,product_price`) is worth adding when you are\n  reading the answer rather than filtering it. A parameter the script has no\n  flag for goes through `--param name=value`.\n- **The answer says what it did.** `_truncated` gives the real row count and\n  the exact `limit=` to pass for all of them, `_omitted_fields` names what\n  the light projection dropped, and `_notes` carries the things that will\n  mislead you when reading these particular rows.\n\nThree properties of Amazon's own data that will mislead you if you assume\notherwise:\n\n1. **`product_num_ratings` is per listing family, not per ASIN.** Variants\n   share a review pool, so every colour of one shoe reports the same count.\n   Do not present it as \"this variant has N reviews\".\n2. **A variant's title can be the parent's.** In search results the ASIN and\n   the title can disagree — the URL slug usually shows the real variant. When\n   the exact variant matters, call `/v2/product-details` on that ASIN; it is\n   authoritative for the ASIN you passed.\n3. **A search row's badges are the result card's, not the listing's.**\n   `badges` (and the derived `is_amazon_choice` / `is_best_seller`) say what\n   Amazon printed on that card for *that query*. `sort_by=BEST_SELLERS` is\n   Amazon's popularity order for the query, not a category rank — so an ASIN\n   that is #1 in *Women's Mules & Clogs* can show `badges: []` in a search\n   for \"crocs white\" while `/v2/product-details` reports `best_seller: true`\n   with the rank. For a rank claim, use product-details or best-sellers;\n   `filters_applied.sort_by` echoes the order the page actually used.\n\n`badges` is the source of truth for Amazon's Choice / Best Seller / Overall\nPick (Amazon renamed that slot to \"Overall Pick\"); `is_amazon_choice` and\n`is_best_seller` are derived from it.\n\n## Error handling — which failures cost money\n\n- **`404`** — the item genuinely is not on that marketplace. **Billed** on the\n  keyed path. Retrying will not help; try a different `geo` or accept it.\n- **`503`** — a temporary Apiguru-side failure. **Not billed.** Retry with\n  backoff. `500`, `502` and `504` are the same class: not billed, retry.\n- **`429`** — rate limited. Back off, then retry.\n- **no answer** (your client timed out) — keyless, nothing was billed; retry.\n  **With an API key the call may still have finished and been billed**, so it\n  is not repeated automatically: tell the user and retry only if they agree.\n  Some marketplaces answer more slowly; allow 60s before giving up.\n- **`400`** — your input was wrong (bad ASIN format, unknown geo, missing\n  required parameter). Not billed. Fix the input; do not retry unchanged.\n- **`402`** — free probes spent. **Stop and ask the user** (see \"Costs and\n  consent\"). Do not retry, do not look for a key, do not attempt payment.\n\nSo: **retry `429`, `500`, `502`, `503`, `504` and keyless timeouts (unless the\nbody says `retryable: false`); never retry `400`, `402`, `404` or `413`, and\nnever repeat a timed-out keyed call without the user's say-so.**\n`scripts/probe.py` does exactly this. Its exit status tells a job what\nhappened: `0` usable answer, `1` HTTP error or a body reporting failure,\n`2` input rejected before any request, `3` a batch with some failed rows.\n\n## Quick start\n\n```bash\n# prices, the free-probe policy, and how many free probes THIS caller has\n# left right now (from /health; the policy number is not your balance). Free.\npython scripts/probe.py capabilities\n\n# one product\npython scripts/probe.py product-details --asin B09DJLW458 --geo US\n\n# many at once (preferred for lists)\npython scripts/probe.py product --asins B09DJLW458,B0BSHF7WHW --geo US\n\n# keyword search on amazon.co.uk\npython scripts/probe.py search --query \"wireless earbuds\" --geo UK\n\n# billed to the user's account, only after they said so.\n# --api-key prompts; the key never appears in argv or in shell history.\npython scripts/probe.py product-details --asin B09DJLW458 --geo US --api-key\n\n# non-interactive equivalent, key straight from a secret store\npass show apiguru | python scripts/probe.py product-details --asin B09DJLW458 --api-key-stdin\n```\n\n## MCP alternative (optional, and outside this skill's audit)\n\n**`scripts/probe.py` above is the supported path.** It is part of this skill,\nit was reviewed with it, it is standard-library only, and it downloads and\nexecutes nothing. Use it unless someone has decided otherwise.\n\nThe same data is also published as an MCP server. That server is a **separate\nartifact**: it is not shipped in this skill, it was not covered by whatever\nreview this skill passed, and it needs its own security review before anyone\nruns it. Three ways to reach it, safest first:\n\n**1. The hosted server — nothing is installed or executed on your machine.**\n\n```\nhttps://mcp.apiguru.app/mcp        streamable HTTP\nhttps://mcp.apiguru.app/account    the same thing behind OAuth 2.1\n```\n\nYour client talks HTTP to a server we run. No package is fetched, so there is\nno supply chain on your side at all. This is the option to prefer.\n\n**2. Install it once, deliberately, then run what you installed.** If you want\nit local, make it a controlled deployment step rather than a fetch on every\nlaunch:\n\n```bash\npython -m venv ~/.venvs/apiguru && ~/.venvs/apiguru/bin/pip install \"apiguru-mcp==1.1.49\"\n# then point the client at the binary you just reviewed and installed:\n#   \"command\": \"/home/you/.venvs/apiguru/bin/apiguru-mcp\"\n```\n\nPin transitive dependencies too if that matters to you: resolve once with\n`pip freeze > apiguru-lock.txt`, review it, and install from that file with\n`--require-hashes`.\n\n**3. Fetch at launch (`uvx` / `npx`).** Convenient, and the weakest of the\nthree: the launcher resolves and executes a package from a public registry\nevery time the client starts. Pinning the version — which the snippets below\ndo — stops it silently moving to a newer release, but it does not protect you\nfrom a compromised publisher account or registry.\n\n```json\n{ \"mcpServers\": { \"apiguru\": { \"command\": \"uvx\",\n  \"args\": [\"apiguru-mcp==1.1.49\"] } } }\n```\n\nor, with Node instead of Python, `\"command\": \"npx\", \"args\": [\"apiguru-mcp@1.1.49\"]`.\n\nWhichever you choose:\n\n- **Expected publisher:** `apiguru-app`. **Registries:** PyPI\n  (`apiguru-mcp`, https://pypi.org/project/apiguru-mcp/) and npm\n  (`apiguru-mcp`, https://www.npmjs.com/package/apiguru-mcp). Both are listed\n  in the official MCP Registry as `app.apiguru/amazon-data`. Anything under\n  another name or publisher is not ours.\n- **Verify the artifact, not just the name and version.** PyPI and npm publish\n  a SHA-256 for every file; `pip download apiguru-mcp==<version>` then\n  `pip hash` gives you a digest to record and re-check on the next upgrade.\n- **Before raising the pin**, read the changelog at\n  https://github.com/apiguru-app/agent-kit/releases and diff the dependency\n  list. Do it deliberately; do not let a launcher do it for you.\n- **Run it with least privilege**: it needs outbound HTTPS to\n  `agent.apiguru.app`, `dash.apiguru.app` and `mcp.apiguru.app` and nothing\n  else — no filesystem access, no other credentials in its environment. A\n  container is the easy way: an official image is published for exactly this\n  (`mcp/apiguru`, Docker's MCP catalogue).\n\nThe MCP tools do the same thing as `probe.py` and follow the same rules — they\nnever pay on their own. A 402 comes back as an x402 PaymentRequired result: the\nuser decides, and only an x402-capable MCP client they set up (with a spend cap)\ncan pay it. Their advantage is that they validate ASINs and geos before spending a\nprobe.\n\n## Telling us what is broken\n\nThis API gets fixed when the agents using it say what is wrong. Recent\nexample: search results were returning the brand as `product_title` and\n`null` for `product_num_ratings`; an agent reported both and both are fixed.\nSo if a field is empty, mistyped, welded together or simply missing:\n\n- **Preferred, if you have a GitHub account** — open an issue at\n  https://github.com/apiguru-app/agent-kit/issues. A thread there can hold a\n  reply and a fix gets linked back to it.\n- **No GitHub account? Use the wall** — one unauthenticated POST, never\n  billed, no signup:\n\n  ```bash\n  curl -X POST https://dash.apiguru.app/api/v1/feedback -H 'Content-Type: application/json' -d '{\"message\": \"search: product_title holds the brand, not the title\", \"category\": \"bug\", \"endpoint\": \"/search\", \"agent\": \"your-name/1.0\"}'\n  ```\n\n  `category` is one of `bug`, `wish`, `praise`, `question`, `other`. Add\n  `\"contact\"` if you want a reply — it is shown publicly on the wall.\n\n  **The wall is public, so send only what the user has agreed to, and only\n  about the API:** the tool, the parameters, the field, what you expected and\n  the `request_id`. Never an API key, personal data, or the user's own\n  prompts, documents or results beyond the field in question.\n- **Over MCP** — the free `send_feedback` tool does the same thing.\n- Read what other agents have written: https://dash.apiguru.app/feedback\n\nSay what you called, what you expected and what came back, and quote the\n`request_id` from the answer. **One issue per entry** — a five-point list\ncannot be closed point by point, and each entry gets its own status on the\nwall (`open`, `fixed`, `documented`, `answered`, `wont_fix`). A wish counts:\nif you need a field this API does not return, that is the most useful thing\nyou can tell us.\n\n## Reference files\n\n- `references/endpoints.md` — every endpoint, parameter, and marketplace code\n- `references/errors-and-costs.md` — pricing, billing rules, retry strategy\n\nFile v1.1.49:_meta.json\n\n{\n  \"ownerId\": \"kn743rz4efdce60qkmj9x20cr18dr5cm\",\n  \"slug\": \"apiguru-amazon-data\",\n  \"version\": \"1.1.49\",\n  \"publishedAt\": 1790937987497\n}\n\nFile v1.1.49:references/endpoints.md\n\n# Apiguru endpoint reference\n\nGenerated from the API spec - do not edit by hand.\n\n- Keyless base URL: `https://agent.apiguru.app/agent/v1`\n- Keyed base URL: `https://dash.apiguru.app/api/v1` (send `X-API-KEY`)\n\nAll endpoints are `GET` with query parameters.\n\n## Marketplaces\n\nPass as `geo`, chosen from the user's request or the Amazon domain they mention (amazon.de -> DE). The API assumes `US` only when the parameter is omitted; do not rely on that default.\n\n| Code | Domain |\n|---|---|\n| `US` | amazon.com |\n| `CA` | amazon.ca |\n| `DE` | amazon.de |\n| `MX` | amazon.com.mx |\n| `UK` | amazon.co.uk |\n| `FR` | amazon.fr |\n| `IT` | amazon.it |\n| `ES` | amazon.es |\n| `AU` | amazon.com.au |\n| `BR` | amazon.com.br |\n| `IN` | amazon.in |\n| `JP` | amazon.co.jp |\n| `NL` | amazon.nl |\n| `AE` | amazon.ae |\n| `PL` | amazon.pl |\n| `SA` | amazon.sa |\n| `SG` | amazon.sg |\n| `SE` | amazon.se |\n| `TR` | amazon.com.tr |\n| `BE` | amazon.com.be |\n| `IE` | amazon.ie |\n| `ZA` | amazon.co.za |\n| `EG` | amazon.eg |\n\n## `GET /v2/product-details`\n\nUse for one product's current listing. Not for several ASINs (product_details_batch), seller offers or stock (offers_stock), or review text (product_reviews). Fetches the complete product record for one ASIN on one marketplace: title, price, star rating, rating count, images, description, feature bullets, variations and category.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asin` | string | yes | Single Amazon ASIN, 10 uppercase alphanumeric characters. Exactly one - comma-separated lists are rejected; use product_details_batch for many. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> 404 means the ASIN is absent from that marketplace and IS billed. 503 is a temporary failure on our side and is NOT billed - retry. Bullet points and specs are what Amazon shows for the listing; on multi-variant listings they can describe the product family rather than the exact variant. A null field means Amazon did not show it.\n\n## `GET /v2/product-reviews`\n\nUse for what customers say about one product. Not for its full review history or star-filtered reviews (not available), or for seller feedback (seller_reviews). Returns the review block for one ASIN: overall star rating, total rating count, Amazon's 'customers say' AI summary, and the individual review list.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asin` | string | yes | Single Amazon ASIN, 10 uppercase alphanumeric characters. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> Same 404-billed / 503-not-billed semantics as product_details. Takes no filters: it returns the rating, rating count, the 'customers say' summary and the reviews Amazon shows on the product page itself. There is no paging, star filter or sort, and no full review history. For per-star counts read the rating histogram on product_details.\n\n## `GET /search`\n\nUse to find products by keyword and filters. Rows are result snippets; for the authoritative record of one ASIN call product_details. Search Amazon products by keyword. Filters: page, sort_by, category_id (browse node), min_price / max_price (decimals), product_condition (NEW / USED / RENEWED), brand, seller_id, today_deals and deal_type (coupons, all_discounts, buy_more_save_more). Every answer carries filters_applied, filters_ignored (with the reason) and available_filters for that marketplace.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `query` | string | yes | Search keywords. Required and must be non-empty. |\n| `page` | integer | no | Result page, 1-based. metadata.total_pages says how far it goes. Default `1`. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `sort_by` | enum | no | Result ordering. Default `RELEVANCE`. |\n| `category_id` | string | no | Amazon browse node id to restrict to, e.g. 172282 (Electronics on US). Take one from a best_sellers answer's available_subcategories, a product's category_path, or node= in an Amazon URL. Ids differ per marketplace. |\n| `min_price` | number | no | Lowest price, in the marketplace currency; decimals such as 19.99 are fine. |\n| `max_price` | number | no | Highest price, in the marketplace currency. |\n| `product_condition` | enum | no | NEW, USED or RENEWED (case-insensitive). Applied with the marketplace's own condition node; where a marketplace does not offer one, the answer's filters_ignored says so and available_filters lists what it does offer. |\n| `brand` | string | no | Brand name as Amazon spells it (case-insensitive), e.g. Samsung. |\n| `seller_id` | string | no | Restrict results to one seller's offers: an Amazon seller id, 'A' followed by 9-20 letters and digits (e.g. A2A1RNLLUK3HYA). |\n| `today_deals` | boolean | no | Only items in Today's Deals, using that marketplace's own refinement. Where a marketplace has none (amazon.fr on 2026-09-08) it is reported under filters_ignored. Default `False`. |\n| `deal_type` | enum | no | A specific promotion refinement: today_deals, all_discounts, coupons or buy_more_save_more. available_filters.deal_type lists the ones this marketplace has. |\n\n`sort_by` accepts: `RELEVANCE`, `BEST_SELLERS`, `LOW_HIGH_PRICE`, `HIGH_LOW_PRICE`, `REVIEWS`, `NEWEST`\n\n`product_condition` accepts: `NEW`, `USED`, `RENEWED`\n\n`deal_type` accepts: `today_deals`, `all_discounts`, `coupons`, `buy_more_save_more`\n\n> Blank values and the literal string 'null' are treated as unset. Invalid page, sort_by, price, product_condition or deal_type is a free 400 naming the parameter and the allowed values. Condition and deal refinements are per marketplace; a marketplace that lacks one gets the unfiltered feed plus an entry under filters_ignored, never a silent empty page. `product_num_ratings` and `offers_count` are integers; `product_star_rating`, `product_price` and `product_original_price` are decimal strings; a null field means Amazon did not show it. `is_prime` is true when the result carries a Prime badge or its delivery line offers Prime delivery. `metadata.total_pages` says how far `page` can go. A full page is up to 48 results and about 54 KB; the tool returns the first 10 as light rows by default and the answer carries `_truncated`, `_omitted_fields`, `_projection` and `_notes`. filters_applied echoes the effective sort_by (RELEVANCE when none was sent). A BEST_SELLERS ordering is Amazon's query-scoped popularity, not a category rank: a row's `badges` / `is_best_seller` are what the result card showed for this query, and an ASIN that is #1 in its subcategory can carry no badge here while product_details reports best_seller=true with the rank. For a rank claim, use product_details or best_sellers. An empty `products` list is served as success only when Amazon itself reports 0 results (metadata.total is 0 and `hint` says so). Anything else that is not a usable result is an unbilled, retryable 503 with code upstream_unavailable.\n\n## `GET /product`\n\nUse to enrich a list of ASINs in one call; compare the ASINs in `results` with the ones you sent. Batch variant of product_details. Accepts a comma-separated ASIN list, deduplicates it, and fetches all of them concurrently. Far cheaper and faster than N single calls.\n\n**Price:** $0.0024 per item (max 20)\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asins` | string | yes | Comma-separated ASIN list, maximum 20 after de-duplication. Each must be 10 uppercase alphanumeric characters. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> Billed per ASIN processed, including ones that come back not-found. More than 20 ASINs returns 413. Bullet points and specs are what Amazon shows for the listing; on multi-variant listings they can describe the product family rather than the exact variant. A null field means Amazon did not show it. ASINs Amazon has no record for on that marketplace are listed in not_returned (billed, like a not-found product_details call; retrying will not help).\n\n## `GET /stock`\n\nUse to compare sellers' current offers and see who holds the buy box, and, with check_inventory, how many units a buyer can add to the cart now. The stock number is not a sales estimate. Not for the listing's own details (product_details). Returns the current offer list per ASIN (seller, price, condition, buy-box winner) and, optionally, the actual purchasable stock quantity.\n\n**Price:** $0.0045 per item (max 10)\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asins` | string | yes | Comma-separated ASIN list, maximum 10. Each must be 10 uppercase alphanumeric characters; malformed entries are rejected with 400. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `check_inventory` | boolean | no | Resolve the true purchasable stock quantity. Slower and bills more lookups, so leave off unless you need the number. Default `False`. |\n| `offers_count` | string | no | 'all' for every offer (default), 'winner' for the buy-box offer only, or a specific alphanumeric Offer ID. Every offer carries is_buybox_winner; with 'winner' the per-ASIN data holds that one offer and offers_total says how many exist. An ASIN with no featured offer answers an empty list with an explanatory error. The response echoes filters_applied. Default `all`. |\n| `condition` | string | no | Comma-separated condition filter: ALL, NEW, USED_LIKE_NEW, USED_VERY_GOOD, USED_GOOD, USED_ACCEPTABLE (case-insensitive). Omit for every offer. An unknown value is a free 400 listing the allowed ones; it used to be silently treated as ALL. |\n\n> Billed per lookup, which is more than one per ASIN when check_inventory is true. offers_count=winner returns only the offer flagged is_buybox_winner (offers_total keeps the full count); it used to scope only the inventory check and return every offer. /scrape is a legacy alias for the same handler. When Amazon will not return the offer list for an ASIN, the result carries source=product_page: the featured (buy-box) offer read from the product page, offers_on_amazon (how many offers Amazon says exist) and a note; other sellers' offers and stock are then not included.\n\n## `GET /v2/best-sellers`\n\nUse for what sells best in a department right now. The rank is Amazon's, not a sales figure. Best-seller rankings for a department of one marketplace, 50 per page. Every answer carries the department it resolved to and how (category_resolution: by slug, name or a fragment of a name, with a hint when a fragment such as 'shoes' landed on the whole 'Clothing, Shoes & Jewelry' department), available_categories (that marketplace's departments with slugs) and available_subcategories (the children of the node shown, with the ids subcategory_code takes). On amazon.com subcategory_code also takes any browse node id at any depth, or a name resolved under the department (\"women's shoes\", \"mules & clogs\"); category.subcategory_path gives the node's full path and category.heading the page's own title line.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `category` | string | no | Best-seller department, by slug or by name as Amazon shows it for that marketplace (case-insensitive; a unique fragment works, and the answer's category_resolution says when a fragment was used -- 'shoes' is the whole 'Clothing, Shoes & Jewelry' department, and the hint then lists the Shoes subcategories with their ids). Departments and their slugs differ per marketplace: amazon.com has electronics, amazon.de has ce-de (Electronics & Photo). Every answer lists that marketplace's departments under available_categories; an unknown or ambiguous name is a free 400 listing them. Default `appliances`. |\n| `subcategory_code` | string | no | Browse node id under `category`: one from available_subcategories of a previous answer, or on amazon.com any node id at any depth (679410011 is Women > Shoes > Mules & Clogs) or a name resolved under the department (\"women's shoes\", \"mens boots\", \"mules & clogs\"). A name that fits two nodes equally (Men > Shoes > Boots and Women > Shoes > Boots) is a free 400 listing both ids with their paths. |\n| `page` | integer | no | Result page, 1-based, 50 rows each; Amazon's lists stop at page 5. Default `1`. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> No required parameters - calling it bare returns US appliances page 1. `category` accepts a slug, a display name, one of the older US department names, or a unique fragment; category_resolution.via says which, and a fragment match adds a hint naming the subcategories that carry the word, with ids. On amazon.com the whole browse tree is known: subcategory_code takes any node id or a name at any depth, subcategory_name and subcategory_path are filled without a fetch, and available_subcategories lists the node's real children (empty on a leaf). Other marketplaces name only what their navigation showed. page is capped at 5 (a 400 beyond, not a 500). `rank` is the position within the requested list on this page. Rows are the same for every marketplace; only the department vocabulary differs, and the answer carries it.\n\n## `GET /v2/deals`\n\nUse for items currently promoted in Amazon's deals feed. Not for one product's price (product_details); for a brand by name use search with brand= and today_deals=true. Returns the current Amazon deals feed: ASIN, title, deal price, list price, discount, deal badge, start/end time and product links. Filter by department (categories), brand id (brands), rating cut-off, price bounds, minimum discount and Prime program. Every answer carries available_filters (the category and brand ids this marketplace accepts, with names), filters_applied / filters_ignored (what took effect) and next_offset (the next page, null when the feed ends).\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `offset` | integer | no | Row to start at. A page is 30 rows; pass the previous answer's next_offset for the next page. Default `0`. |\n| `categories` | string | no | Department to restrict to: its id from available_filters.categories, or its name as Amazon shows it for that marketplace (case-insensitive; a unique fragment such as \"electronics\" works). US departments: Amazon Devices & Accessories, Appliances, Arts Crafts & Sewing, Audible Books & Originals, Automotive, Baby Products, Beauty & Personal Care, Books, CDs & Vinyl, Cell Phones & Accessories, Clothing Shoes & Jewelry, Collectibles & Fine Art, Electronics, Everything Else, Grocery & Gourmet Food, Handmade Products, Health & Household, Home & Kitchen, Industrial & Scientific, Kindle Store, Movies & TV, Musical Instruments, Office Products, Patio Lawn & Garden, Pet Supplies, Software, Sports & Outdoors, Tools & Home Improvement, Toys & Games, Video Games. Other marketplaces use their own localised names -- read them from available_filters.categories of any deals answer for that geo. An unknown name is a free 400 listing the valid names. |\n| `brands` | string | no | Comma-separated brand ids, e.g. 46655 for Samsung on US. Take them from brand_id on any deals row or from available_filters.brands (the brands present in the current result). Names resolve only when this marketplace has already shown that brand; for a brand by name use /search with brand=<name> and today_deals=true instead. |\n| `min_product_star_rating` | enum | no | Amazon's deals feed offers one rating cut-off: 4 = four stars and up. ALL or omitted = no cut-off. Other values are rejected with a free 400. |\n| `min_price` | number | no | Lowest deal price to return, in the marketplace currency. Applied to the fetched rows; see notes. |\n| `max_price` | number | no | Highest deal price to return, in the marketplace currency. |\n| `min_discount` | integer | no | Smallest discount percentage to return, e.g. 50 for half price or better. |\n| `max_discount` | integer | no | Largest discount percentage to return. |\n| `prime_exclusive` | boolean | no | Only deals in Amazon's Prime Exclusive program. Default `False`. |\n| `prime_early_access` | boolean | no | Only Prime Early Access deals. A marketplace lists the programs it is running under available_filters.prime_programs; when Early Access is not running the answer is empty with a hint saying so. Default `False`. |\n\n`min_product_star_rating` accepts: `4`, `ALL`\n\n> Filters are by id: categories takes a department id or name, brands takes brand ids only; available_filters in every answer lists both with names, and filters_applied / filters_ignored report what Amazon honoured. A page is 30 rows; page with offset=next_offset (null when exhausted); total_count caps at 500. min_price, max_price, min_discount and max_discount are applied to the rows after retrieval, scanning up to 3 feed pages per call, so a page can hold fewer than 30 rows and total_count does not reflect them. An empty answer carries a hint saying why. Deal prices expire: check deal_ends_at. The older price_range and discount_range parameters are still accepted, as buckets (1-5 = under 25 / 25-50 / 50-100 / 100-200 / 200 and up; 1-4 = 10 / 25 / 50 / 70 percent off or more) or as bands such as 25-50 and 70+.\n\n## `GET /seller-profile`\n\nUse to vet sellers: name, rating and feedback counts as Amazon displays them. Returns the storefront profile for each seller id: business name, rating, feedback counts, address and marketplace presence.\n\n**Price:** $0.0036 per item (max 10)\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `seller_ids` | string | yes | Comma-separated seller IDs, maximum 10. Each must be an Amazon seller id -- 'A' followed by 9-20 letters and digits, e.g. A2A1RNLLUK3HYA -- or the whole call 400s. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> Seller ID validation is all-or-nothing: one malformed id rejects the entire request with 400. Every row in results is an object with `status`: `ok` (the profile), `not_found` (Amazon has no page for that id on this marketplace; billed, like a 404) or `unavailable` (could not be retrieved right now; NOT billed on the keyed path, `retryable: true`). A row is never null. billable_requests_count counts ok + not_found rows; on the pay-per-call rail the per-item quote is settled up front, so retry `unavailable` ids in a separate call rather than expecting a partial refund.\n\n## `GET /v2/seller-products`\n\nUse to list one seller's storefront. Products listed by a seller: a storefront search. Takes the same filters as search -- query, page, sort_by, category_id, min_price / max_price, product_condition, brand, today_deals, deal_type -- and answers with filters_applied, filters_ignored and available_filters like search does.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `seller_id` | string | yes | Amazon seller id whose storefront to list: 'A' followed by 9-20 letters and digits, the seller= or me= value of a storefront URL (e.g. A2A1RNLLUK3HYA). Required. |\n| `query` | string | no | Optional keywords to search within this seller's storefront. |\n| `page` | integer | no | Result page, 1-based. metadata.total_pages says how far it goes. Default `1`. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `sort_by` | enum | no | Result ordering. Default `RELEVANCE`. |\n| `category_id` | string | no | Amazon browse node id to restrict to, e.g. 172282 (Electronics on US). Take one from a best_sellers answer's available_subcategories, a product's category_path, or node= in an Amazon URL. Ids differ per marketplace. |\n| `min_price` | number | no | Lowest price, in the marketplace currency; decimals such as 19.99 are fine. |\n| `max_price` | number | no | Highest price, in the marketplace currency. |\n| `product_condition` | enum | no | NEW, USED or RENEWED (case-insensitive). Applied with the marketplace's own condition node; where a marketplace does not offer one, the answer's filters_ignored says so and available_filters \n\nArchive v1.1.48: 6 files, 32644 bytes\n\nFiles: references/endpoints.md (22780b), references/errors-and-costs.md (3955b), scripts/probe.py (39782b), skill-card.md (2320b), SKILL.md (19800b), _meta.json (139b)\n\nArchive v1.1.47: 6 files, 32601 bytes\n\nFiles: references/endpoints.md (22714b), references/errors-and-costs.md (3955b), scripts/probe.py (39764b), skill-card.md (2254b), SKILL.md (19800b), _meta.json (139b)\n\nArchive v1.1.46: 6 files, 32501 bytes\n\nFiles: references/endpoints.md (22714b), references/errors-and-costs.md (3955b), scripts/probe.py (39764b), skill-card.md (2026b), SKILL.md (19800b), _meta.json (139b)\n\nArchive v1.1.45: 6 files, 32434 bytes\n\nFiles: references/endpoints.md (22714b), references/errors-and-costs.md (3955b), scripts/probe.py (39764b), skill-card.md (2224b), SKILL.md (19480b), _meta.json (139b)\n\nArchive v1.1.44: 6 files, 31570 bytes\n\nFiles: references/endpoints.md (22290b), references/errors-and-costs.md (3595b), scripts/probe.py (38878b), skill-card.md (1955b), SKILL.md (18940b), _meta.json (139b)\n\nArchive v1.1.43: 6 files, 31105 bytes\n\nFiles: references/endpoints.md (20773b), references/errors-and-costs.md (3595b), scripts/probe.py (38878b), skill-card.md (2057b), SKILL.md (18931b), _meta.json (139b)\n\nArchive v1.1.42: 6 files, 31072 bytes\n\nFiles: references/endpoints.md (20773b), references/errors-and-costs.md (3240b), scripts/probe.py (38878b), skill-card.md (2351b), SKILL.md (18931b), _meta.json (139b)","readmeExcerpt":"Skill: apiguru-amazon-data Owner: apiguru-app Summary: Live Amazon marketplace data from Apiguru (a paid third-party API, 3 free calls a day) - product details, prices, reviews, keyword search, best-sellers, deals, offers and stock, seller profiles, across 23 Amazon marketplaces. Use only when the user asks for Amazon data by ASIN, Amazon URL, product, seller or keyword, or for Amazon price/stock/review monitoring. N","codeSnippets":[],"executableExamples":[{"language":"text","snippet":"GET https://agent.apiguru.app/agent/v1/v2/product-details?asin=B09DJLW458&geo=US"},{"language":"bash","snippet":"# prices, the free-probe policy, and how many free probes THIS caller has\n# left right now (from /health; the policy number is not your balance). Free.\npython scripts/probe.py capabilities\n\n# one product\npython scripts/probe.py product-details --asin B09DJLW458 --geo US\n\n# many at once (preferred for lists)\npython scripts/probe.py product --asins B09DJLW458,B0BSHF7WHW --geo US\n\n# keyword search on amazon.co.uk\npython scripts/probe.py search --query \"wireless earbuds\" --geo UK\n\n# billed to the user's account, only after they said so.\n# --api-key prompts; the key never appears in argv or in shell history.\npython scripts/probe.py product-details --asin B09DJLW458 --geo US --api-key\n\n# non-interactive equivalent, key straight from a secret store\npass show apiguru | python scripts/probe.py product-details --asin B09DJLW458 --api-key-stdin"},{"language":"text","snippet":"https://mcp.apiguru.app/mcp        streamable HTTP\nhttps://mcp.apiguru.app/account    the same thing behind OAuth 2.1"},{"language":"bash","snippet":"python -m venv ~/.venvs/apiguru && ~/.venvs/apiguru/bin/pip install \"apiguru-mcp==1.1.51\"\n# then point the client at the binary you just reviewed and installed:\n#   \"command\": \"/home/you/.venvs/apiguru/bin/apiguru-mcp\""},{"language":"json","snippet":"{ \"mcpServers\": { \"apiguru\": { \"command\": \"uvx\",\n  \"args\": [\"apiguru-mcp==1.1.51\"] } } }"},{"language":"bash","snippet":"curl -X POST https://dash.apiguru.app/api/v1/feedback -H 'Content-Type: application/json' -d '{\"message\": \"search: product_title holds the brand, not the title\", \"category\": \"bug\", \"endpoint\": \"/search\", \"agent\": \"your-name/1.0\"}'"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: apiguru-amazon-data\ndescription: Live Amazon marketplace data from Apiguru (a paid third-party API, 3 free calls a day) - product details, prices, reviews, keyword search, best-sellers, deals, offers and stock, seller profiles, across 23 Amazon marketplaces. Use only when the user asks for Amazon data by ASIN, Amazon URL, product, seller or keyword, or for Amazon price/stock/review monitoring. Not for other stores or general shopping advice. Never pays on its own; ask before any billable call. We want your feedback - if a field is wrong, missing or you wish the API did something else, say so with the free `feedback` command (no account needed); the agents that report are the ones this API gets fixed for.\nlicense: MIT\ncompatibility: Needs Python 3.10+ and outbound HTTPS to agent.apiguru.app and dash.apiguru.app only. Reads no environment variables and no local files except an API-key file the user names.\nallowed-tools: Bash(python3:*) Bash(python:*) Read\nhomepage: https://github.com/apiguru-app/agent-kit\nmetadata: {\"openclaw\": {\"emoji\": \"📦\", \"homepage\": \"https://github.com/apiguru-app/agent-kit\", \"requires\": {\"anyBins\": [\"python3\", \"python\"]}}}\n---\n\n# Apiguru Amazon Data\n\nLive, structured Amazon data fetched at request time from Apiguru's servers.\n23 marketplaces.\n\n**What this skill writes.** Every data command is a read: it fetches and\nreturns, and changes nothing anywhere. There is exactly one write, and it is\nnever automatic — the `feedback` command posts the text you give it to\nApiguru's public feedback wall (see \"Telling us what is broken\" below). It\nsends only that text, it costs nothing, and it runs only when you invoke it.\nNothing else in this skill sends data anywhere.\n\n## Costs and consent (read this first)\n\n- **Hosts contacted:** `agent.apiguru.app` (keyless) and `dash.apiguru.app`\n  (the keyed API, and the feedback wall, which needs no key). Nothing else.\n  `scripts/probe.py` has both hosts fixed in the source, reads no environment\n  variables, and **refuses every redirect**, so a key cannot be carried to a\n  third host by a `302`.\n- **Free quota:** 3 calls per machine per 24 hours. After that the gateway\n  answers `402 Payment Required`. **The answer knows better than this\n  page:** every keyless reply carries `free_calls_remaining` in the body and\n  `X-Free-Probes-Remaining` (or `X-Free-Probes-Available: yes|no` where no\n  count is given) in the headers. Plan a task on the last reply, never on\n  the number above.\n- **This skill never pays.** `probe.py` stops at a 402 and tells you so. It\n  contains no wallet and no x402 client, and it will not set one up. Paying is\n  the user's decision, made one of two ways, both only with their explicit\n  consent:\n  1. an Apiguru API key, handed to the script by the user through `--api-key`\n     (an unechoed prompt), `--api-key-file PATH` or `--api-key-stdin` — bills\n     their account at their plan's rates, about USD 0.01 per call — or\n  2. their own x402-capable HTTP client with a fund"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn743rz4efdce60qkmj9x20cr18dr5cm\",\n  \"slug\": \"apiguru-amazon-data\",\n  \"version\": \"1.1.51\",\n  \"publishedAt\": 1791308619750\n}"},{"path":"references/endpoints.md","content":"# Apiguru endpoint reference\n\nGenerated from the API spec - do not edit by hand.\n\n- Keyless base URL: `https://agent.apiguru.app/agent/v1`\n- Keyed base URL: `https://dash.apiguru.app/api/v1` (send `X-API-KEY`)\n\nAll endpoints are `GET` with query parameters.\n\n## Marketplaces\n\nPass as `geo`, chosen from the user's request or the Amazon domain they mention (amazon.de -> DE). The API assumes `US` only when the parameter is omitted; do not rely on that default.\n\n| Code | Domain |\n|---|---|\n| `US` | amazon.com |\n| `CA` | amazon.ca |\n| `DE` | amazon.de |\n| `MX` | amazon.com.mx |\n| `UK` | amazon.co.uk |\n| `FR` | amazon.fr |\n| `IT` | amazon.it |\n| `ES` | amazon.es |\n| `AU` | amazon.com.au |\n| `BR` | amazon.com.br |\n| `IN` | amazon.in |\n| `JP` | amazon.co.jp |\n| `NL` | amazon.nl |\n| `AE` | amazon.ae |\n| `PL` | amazon.pl |\n| `SA` | amazon.sa |\n| `SG` | amazon.sg |\n| `SE` | amazon.se |\n| `TR` | amazon.com.tr |\n| `BE` | amazon.com.be |\n| `IE` | amazon.ie |\n| `ZA` | amazon.co.za |\n| `EG` | amazon.eg |\n\n## `GET /v2/product-details`\n\nUse for one product's current listing. Not for several ASINs (product_details_batch), seller offers or stock (offers_stock), or review text (product_reviews). Fetches the complete product record for one ASIN on one marketplace: title, price, star rating, rating count, images, description, feature bullets, variations and category.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asin` | string | yes | Single Amazon ASIN, 10 uppercase alphanumeric characters. Exactly one - comma-separated lists are rejected; use product_details_batch for many. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n\n> 404 means the ASIN is absent from that marketplace and IS billed. 503 is a temporary failure on our side and is NOT billed - retry. Bullet points and specs are what Amazon shows for the listing; on multi-variant listings they can describe the product family rather than the exact variant. A null field means Amazon did not show it.\n\n## `GET /v2/product-reviews`\n\nUse for what customers say about one product. Not for its full review history (Amazon serves full and star-filtered review lists only to signed-in accounts) or for seller feedback (seller_reviews). Returns the overall rating, rating count, review_histogram (percent of all ratings per star), Amazon's 'customers say' AI summary where that marketplace shows one, and the reviews on the product page (typically up to 8 from this marketplace and 5 from other countries), each with rating, review_date, review_country, from_this_marketplace, verified flag and helpful_votes; from_rating/to_rating keep a star window.\n\n**Price:** $0.003 per call\n\n| Parameter | Type | Required | Notes |\n|---|---|---|---|\n| `asin` | string | yes | Single Amazon ASIN, 10 uppercase alphanumeric characters. |\n| `geo` | enum | no | Marketplace country code. Default `US`. |\n| `from_rating` | integer | no | Lowest star rating to include, 1-5. Filters the reviews the pr"},{"path":"references/errors-and-costs.md","content":"# Costs, billing and retries\n\nGenerated from the API spec - do not edit by hand.\n\n## Prices\n\n| Endpoint | Price |\n|---|---|\n| `/v2/product-details` | $0.003 per call |\n| `/v2/product-reviews` | $0.003 per call |\n| `/search` | $0.003 per call |\n| `/product` | $0.0024 per item (max 20) |\n| `/stock` | $0.0045 per item (max 10) |\n| `/v2/best-sellers` | $0.003 per call |\n| `/v2/deals` | $0.003 per call |\n| `/seller-profile` | $0.0036 per item (max 10) |\n| `/v2/seller-products` | $0.003 per call |\n| `/v2/seller-reviews` | $0.003 per call |\n\nBatch endpoints are billed per item and are cheaper per item than the\nsingle-item equivalents. Always prefer them for more than one item.\n\n## What each status means, and whether it costs money\n\n| Status | Billed? | Meaning and what to do |\n|---|---|---|\n| `400` | no | Bad input (bad ASIN format, unknown geo, missing required param). NOT billed. |\n| `401` | - | Missing or invalid API key on the keyed path. |\n| `402` | - | Payment required. On the agent path this carries a PAYMENT-REQUIRED challenge (over MCP: an x402 PaymentRequired tool result, payable in-band via _meta[\"x402/payment\"]). On the keyed path it means the account balance is exhausted. |\n| `403` | - | Account disabled, or no active subscription plan. |\n| `404` | **yes** | The ASIN genuinely does not exist on that marketplace. BILLED - the lookup was performed and the bad input was the caller's. Retrying will not help; try a different geo. |\n| `413` | - | Too many items in a batch request. |\n| `429` | - | Per-second rate limit exceeded for the plan. Back off and retry. |\n| `500` | no | Internal error. NOT billed. |\n| `502` | no | Bad gateway. NOT billed. Same class as 503: retry with backoff. |\n| `503` | no | Temporary failure on our side. NOT billed. Safe and correct to retry. |\n| `504` | no | Gateway timeout: the request ran past its deadline. NOT billed. Retry with backoff; a narrower query often succeeds. |\n| `timeout` | - | No response before your own client's deadline. A keyless call without a payment is never billed. On an API key, or with an x402 payment attached, the request may still complete after your client gave up, and is then billed like any answered call. Some marketplaces answer more slowly than others; allow 60s rather than retrying early. |\n\n## Retry policy\n\nRetry 429, 500, 502, 503 and 504 with backoff -- none of them are billed -- unless the error body says `retryable: false`. A client-side timeout on a key or a payment may have completed and been billed; allow 60s before retrying it. Never retry 400, 401, 402, 403, 404 or 413: the request itself is the problem and repeating it will not change the answer.\n\nConcretely (the same set `scripts/probe.py` retries):\n\n```python\nRETRYABLE = {429, 500, 502, 503, 504}   # answered, and not billed\nfor attempt in range(4):\n    try:\n        status, body = call(..., timeout=60)\n    except TimeoutError:\n        if api_key:                  # may have finished and billed after we gave up:\n            "},{"path":"skill-card.md","content":"## Description:\n\nHelps agents retrieve live Amazon product, price, review, offer, stock, seller, and search data from Apiguru across supported marketplaces.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[apiguru-app](https://clawhub.ai/user/apiguru-app)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and other agents use this skill to answer user-requested Amazon marketplace questions about products, prices, reviews, availability, and sellers, or to monitor these details across supported marketplaces.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Product queries contact Apiguru and can incur charges when a user supplies an API key or uses their own payment-capable client.\n\nMitigation: Check prices and free-call availability, obtain explicit consent before billable requests, and set a spending cap.\n\nRisk: Optional feedback is posted publicly and could expose secrets or private user data.\n\nMitigation: Request consent before posting feedback and omit API keys, personal information, and private user content.\n\nRisk: The optional MCP server or package installation is separate software not covered by this skill's review.\n\nMitigation: Review the MCP server or package separately before use; prefer the included script when that review is unavailable.\n\n## Reference(s):\n\n- [Apiguru endpoint reference](references/endpoints.md)\n- [Apiguru costs, billing, and retries](references/errors-and-costs.md)\n- [Apiguru agent-kit homepage (listed in release metadata)](https://github.com/apiguru-app/agent-kit)\n- [Apiguru API endpoint and price catalog](https://agent.apiguru.app/.well-known/x402)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, JSON]\n\n**Output Format:** [Natural-language answers or structured API responses]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Live data is limited to supported Amazon marketplaces; requests may consume free calls or incur charges with an explicitly supplied API key.]\n\n## Skill Version(s):\n\n1.1.51 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":2210,"uniquenessScore":38,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-10T14:59:09.828Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-10T14:59:09.828Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-10T17:34:52.020Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}