{"id":"cd2233f1-7e1e-473e-8c69-da43f8f1ea8c","entityType":"agent","slug":"clawhub-apiclaw-zoodata","name":"zoodata","canonicalUrl":"https://www.xpersona.co/agent/clawhub-apiclaw-zoodata","canonicalPath":"/agent/clawhub-apiclaw-zoodata","generatedAt":"2026-10-10T06:44:29.196Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T04:38:56.225Z","emptyReason":null},"description":"API endpoint reference for the ZooData data platform: the 12 commerce endpoints plus 10 keyword-intelligence endpoints (categories, markets, products, competitors, realtime ASIN, AI review analysis, raw reviews, price band, brand, history, and the keyword detail/trend/extends/search/ market-profile/product-traffic/competitor-keywords/traffic-timeline family) — their inputs/outputs, parameter quirks, Quick Start (auth, base URL), how credits are tracked (meta.creditsConsumed), and the Local Review Toolkit (Map/Reduce for raw reviews). Use when the user asks about the API itself: which endpoints exist, how to call them (e.g. /products/search), field schemas returned by an endpoint, parameter quirks, how to authenticate, how credit consumption is reported, how to get started, or how the Local Review Toolkit works. Requires ZOODATA_API_KEY.","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.7K downloads reported by the source. Last updated 10/10/2026.","installCommand":"clawhub skill install s17081rahwfg1emrhs1pmfhmq984gan3:zoodata","sourceUrl":"https://clawhub.ai/apiclaw/zoodata","homepage":"https://clawhub.ai/apiclaw/skills/zoodata","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/apiclaw/zoodata","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/apiclaw/skills/zoodata","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":65,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"zoodata 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-10T04:38:56.225Z","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-10T04:38:56.225Z","emptyReason":null},"stars":null,"forks":null,"downloads":1678,"packageName":null,"latestVersion":"1.1.9","tractionLabel":"1.7K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T04:38:56.225Z","emptyReason":null},"lastUpdatedAt":"2026-10-10T04:38:56.225Z","lastCrawledAt":"2026-10-10T04:38:56.225Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-11T04:38:56.225Z","lastVerifiedAt":null,"highlights":[{"version":"1.1.9","createdAt":"2026-08-07T02:15:00.697Z","changelog":"Composite resolved_category_path metadata + ABA out-of-window date guidance; per-skill CLI command allowlists (COMMAND_NOT_ALLOWED enforcement); credential-source hardening; SKILL.md description trims. See CHANGELOG.","fileCount":9,"zipByteSize":121182},{"version":"1.1.8","createdAt":"2026-08-04T01:30:31.635Z","changelog":"Release v1.3.0: composite robustness (empty-target guard, category self-heal, terminal fail-fast, realtime retry + offline fallback), keyword workflow + shared CLI hardening, security declarations, release-notify CI","fileCount":8,"zipByteSize":71079},{"version":"1.1.7","createdAt":"2026-07-29T08:36:15.239Z","changelog":"Reference cleanup: stop 7 references mislabelling themselves as Market Entry Analyzer; per-skill endpoint scoping for narrow skills (#94)","fileCount":7,"zipByteSize":63329},{"version":"1.1.6","createdAt":"2026-07-28T14:02:23.277Z","changelog":"Security: remove leaked bundled key + credential/base-url hardening; clear LLM-review content flags; accurate credit reporting for composite + crawl-wait (#93)","fileCount":7,"zipByteSize":63244},{"version":"1.1.5","createdAt":"2026-07-28T07:12:37.482Z","changelog":"Capabilities & Data Flow declarations + CLI hardening (SkillSpector audit response, #91)","fileCount":8,"zipByteSize":61896},{"version":"1.1.4","createdAt":"2026-07-24T09:28:43.641Z","changelog":"ZooData rebrand + backend-contract release: correct 13 selection modes (fixes hard-422 on listingAge/badges preset values), mode documented as CLI-local (not an API param), category parser hardening (comma-safe, JSON array input), credential env renamed to ZOODATA_API_KEY (legacy APICLAW_API_KEY still works), realtime cold-start retry guidance, refreshed docs and API reference.","fileCount":8,"zipByteSize":60922},{"version":"1.1.1","createdAt":"2026-04-13T12:36:16.801Z","changelog":"- Added author and homepage fields to SKILL metadata for improved attribution and discoverability. - Bumped version to 1.1.1. - No changes to functionality or API endpoints.","fileCount":7,"zipByteSize":34642},{"version":"1.1.0","createdAt":"2026-04-09T05:16:33.440Z","changelog":"Initial release","fileCount":6,"zipByteSize":33202}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17081rahwfg1emrhs1pmfhmq984gan3:zoodata","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s17081rahwfg1emrhs1pmfhmq984gan3:zoodata` 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/apiclaw/zoodata 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-apiclaw-zoodata/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-apiclaw-zoodata/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-apiclaw-zoodata/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-apiclaw-zoodata/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-apiclaw-zoodata/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-apiclaw-zoodata/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-10T06:44:29.191Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-apiclaw-zoodata/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-apiclaw-zoodata/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-apiclaw-zoodata/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-apiclaw-zoodata/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-10T04:38:56.225Z","emptyReason":null},"readme":"Skill: zoodata\n\nOwner: apiclaw\n\nSummary: API endpoint reference for the ZooData data platform: the 12 commerce endpoints plus 10 keyword-intelligence endpoints (categories, markets, products, competitors, realtime ASIN, AI review analysis, raw reviews, price band, brand, history, and the keyword detail/trend/extends/search/ market-profile/product-traffic/competitor-keywords/traffic-timeline family) — their inputs/outputs, parameter quirks, Quick Start (auth, base URL), how credits are tracked (meta.creditsConsumed), and the Local Review Toolkit (Map/Reduce for raw reviews). Use when the user asks about the API itself: which endpoints exist, how to call them (e.g. /products/search), field schemas returned by an endpoint, parameter quirks, how to authenticate, how credit consumption is reported, how to get started, or how the Local Review Toolkit works. Requires ZOODATA_API_KEY.\n\nTags: latest:1.1.9\n\nVersion history:\n\nv1.1.9 | 2026-08-07T02:15:00.697Z | user\n\nComposite resolved_category_path metadata + ABA out-of-window date guidance; per-skill CLI command allowlists (COMMAND_NOT_ALLOWED enforcement); credential-source hardening; SKILL.md description trims. See CHANGELOG.\n\nv1.1.8 | 2026-08-04T01:30:31.635Z | user\n\nRelease v1.3.0: composite robustness (empty-target guard, category self-heal, terminal fail-fast, realtime retry + offline fallback), keyword workflow + shared CLI hardening, security declarations, release-notify CI\n\nv1.1.7 | 2026-07-29T08:36:15.239Z | user\n\nReference cleanup: stop 7 references mislabelling themselves as Market Entry Analyzer; per-skill endpoint scoping for narrow skills (#94)\n\nv1.1.6 | 2026-07-28T14:02:23.277Z | user\n\nSecurity: remove leaked bundled key + credential/base-url hardening; clear LLM-review content flags; accurate credit reporting for composite + crawl-wait (#93)\n\nv1.1.5 | 2026-07-28T07:12:37.482Z | user\n\nCapabilities & Data Flow declarations + CLI hardening (SkillSpector audit response, #91)\n\nv1.1.4 | 2026-07-24T09:28:43.641Z | user\n\nZooData rebrand + backend-contract release: correct 13 selection modes (fixes hard-422 on listingAge/badges preset values), mode documented as CLI-local (not an API param), category parser hardening (comma-safe, JSON array input), credential env renamed to ZOODATA_API_KEY (legacy APICLAW_API_KEY still works), realtime cold-start retry guidance, refreshed docs and API reference.\n\nv1.1.1 | 2026-04-13T12:36:16.801Z | auto\n\n- Added author and homepage fields to SKILL metadata for improved attribution and discoverability.\n- Bumped version to 1.1.1.\n- No changes to functionality or API endpoints.\n\nv1.1.0 | 2026-04-09T05:16:33.440Z | user\n\nInitial release\n\nArchive index:\n\nArchive v1.1.9: 9 files, 121182 bytes\n\nFiles: README.md (4462b), references/cli-contract.md (9156b), references/openapi-reference.md (32537b), references/reference.md (12264b), scripts/__pycache__/zoodata.cpython-310.pyc (104994b), scripts/zoodata.py (179106b), skill-card.md (2830b), SKILL.md (35144b), _meta.json (126b)\n\nFile v1.1.9:SKILL.md\n\n---\nname: zoodata\ndescription: >\n  API endpoint reference for the ZooData data platform: the 12 commerce\n  endpoints plus 10 keyword-intelligence endpoints (categories, markets,\n  products, competitors, realtime ASIN, AI review analysis, raw reviews,\n  price band, brand, history, and the keyword detail/trend/extends/search/\n  market-profile/product-traffic/competitor-keywords/traffic-timeline\n  family) — their inputs/outputs, parameter quirks, Quick Start (auth,\n  base URL), how credits are tracked (meta.creditsConsumed), and the Local\n  Review Toolkit (Map/Reduce for raw reviews).\n  Use when the user asks about the API itself: which endpoints exist, how\n  to call them (e.g. /products/search), field schemas returned by an\n  endpoint, parameter quirks, how to authenticate, how credit consumption\n  is reported, how to get started, or how the Local Review Toolkit works.\n  Requires ZOODATA_API_KEY.\nmetadata:\n  version: \"1.1.9\"\n  author: SerendipityOneInc\n  homepage: https://github.com/SerendipityOneInc/ZooData-Skills\n  openclaw: {\"requires\": {\"env\": [\"ZOODATA_API_KEY\"]}, \"primaryEnv\": \"ZOODATA_API_KEY\"}\n---\n\n> **📋 Live API Reference**: Field names and parameters may change. If you encounter field errors,\n> check the latest OpenAPI spec at https://zoodata.ai/api/v1/openapi-spec for current field definitions.\n> Keyword exception: the observation endpoints currently support `granularity=week` only. Do not\n> reintroduce `day`, `month`, `lately_day`, or `lookbackDays` from a stale generated schema.\n\n# ZooData — Commerce Data Infrastructure for AI Agents\n\n200M+ Amazon products. 22 endpoints. One API key.\n\n## Quick Start\n1. Get key: [zoodata.ai/api-keys](https://zoodata.ai/en/api-keys) (1,000 free credits)\n2. `export ZOODATA_API_KEY='hms_live_xxx'`\n3. Base URL: `https://api.zoodata.ai/openapi/v2` — all POST with JSON body\n4. Auth: `Authorization: Bearer YOUR_API_KEY`\n5. New keys need 3-5s to activate. If 403, wait and retry.\n\n## Capabilities & Data Flow\n\n- **Network**: only `https://api.zoodata.ai` (Bearer `ZOODATA_API_KEY`). Setting `ZOODATA_BASE_URL` to an untrusted host (anything other than `api.zoodata.ai` / `*.zoodata.ai` / localhost) makes the CLI **refuse the request and withhold the key** — the Bearer token is never sent to an untrusted host.\n- **Execution**: bundled shared ZooData CLI `{skill_base_dir}/scripts/zoodata.py` (Python 3, stdlib-only). This data-layer reference skill allows the complete literal subcommand surface exposed by the bundled client's current top-level help.\n- **Local files**: none by default; reads the optional credential store `~/.zoodata/config.json`; the Local Review Toolkit uses a private temporary working dir (created with `mktemp -d`, removed when the fallback completes) during the review fallback.\n- **Sent to the API**: keywords, category paths, ASINs, marketplace/date and numeric filter values only. **Never sent**: budget, experience level, risk tolerance, or any other user-profile text — profile inputs map client-side to numeric filters.\n- **Credits**: every API call consumes account credits. For broad or ambiguous requests, state the estimated credit cost and confirm with the user before running multi-call scans.\n\n## Shared CLI contract\n\nBefore selecting or invoking a bundled CLI command, read and apply `references/cli-contract.md`; reapply it after every result. It is the local source of truth for invocation, command identity, execution-environment permission handling, composite reuse, exit-status handling, authoritative transport status, retries, terminal interface failures, and partial results.\n\n### Local Interface Failure Output\n\nFor this API-reference skill, a terminal interface failure must produce one concise localized notice stating that the ZooData API lookup could not be completed, followed by the succeeded and failed endpoint identifiers. Do not continue into endpoint guidance, schema interpretation, or another API call. Do not expose control tokens or internal retry logs unless the user requests diagnostics.\n\n## ⚠️ Critical API Pitfalls (ALL skills must follow)\n1. **Commerce product/market search using a broad query** → resolve and lock `categoryPath` before interpreting category-sensitive product, market, competitor, brand, or price-band results. An explicitly labeled `products/search` category probe may run without a locked category only to resolve that category. Do **not** apply this rule to `/openapi/v2/keywords/*` Keyword Intelligence endpoints: their `keyword` / `query` inputs are Amazon search queries and do not require `categoryPath`.\n2. **Brand/price-band queries MUST include --category** to avoid cross-category contamination\n3. **Revenue** = `sampleAvgMonthlyRevenue` directly. **NEVER** calculate avgPrice × totalSales (overestimates 30-70%)\n4. **Sales** = `monthlySalesFloor` (lower bound). Fallback: 300,000 / BSR^0.65, tag as 🔍\n5. **Use API fields directly**: `sampleOpportunityIndex`, `sampleTop10BrandSalesRate` — never reinvent\n6. **reviews/analysis** needs 50+ reviews. Fallback chain when sample is insufficient:\n   1. Lightweight: `realtime/product` → `ratingBreakdown` (star distribution only, no themes)\n   2. Full 11-dim insights: `realtime/reviews` (raw text, up to 100) + local Map/Reduce via the\n      Local Review Toolkit below — see \"Local Review Toolkit\" section\n7. **Aggregation endpoints** (price-band, brand) without categoryPath produce severely distorted data\n8. **Price-band and brand endpoints only accept `keyword`** (not categoryPath) — cross-validate returned products\n9. **`mode` is CLI-local, NOT an API parameter** → `zoodata.py` expands `--mode` client-side into the filter sets in `PRODUCT_MODES` (`{skill_base_dir}/scripts/zoodata.py`, 13 presets) before the request; sending `mode` raw → 422\n10. **CLI filter flags ≠ API field names** → `--sales-min` → `monthlySalesMin`; `--ratings-max` (review count) → `ratingCountMax`, **not** `ratingMax` (a different valid field — max star rating — that returns wrong results silently, no 422). Pass `categoryPath` as a JSON array (`[\"Electronics\"]`), never a string. Unknown fields (`salesMin`, `ratingsMax`, …) → 422\n\n## On Missing Key (no credentials configured)\n\n**BEFORE calling any endpoint**, verify credentials are configured. The reliable check is `python {skill_base_dir}/scripts/zoodata.py check` — credentials-only by default, no endpoint calls and no credit usage; exits non-zero if no key is found in env vars OR config files. A `[ -z \"$ZOODATA_API_KEY\" ]` test alone is NOT sufficient — a user may have only `~/.zoodata/config.json` set.\n\nWhen no key is found through any mechanism:\n\n1. **STOP.** Do not run the workflow. Do not call `zoodata.py` (you'll just get the same credential error and burn tokens).\n2. **Do NOT fall back to a \"partial analysis from training data\" / \"industry common-sense headlines\" / \"for reference only\" preview.** Your training data is stale, has no per-ASIN granularity, and presenting it as analysis — even disclaimed — misrepresents what this skill produces. The deliverable is data-backed; without data, there is no deliverable.\n3. **Tell the user, in their language**, all three of:\n   - \"`ZOODATA_API_KEY` is not set — I need this to run the analysis.\"\n   - **Get a free key** (1,000 credits, no credit card): https://zoodata.ai/en/api-keys\n   - **Configure** via one of:\n     - `export ZOODATA_API_KEY='hms_live_xxx'` (session only)\n     - `mkdir -p ~/.zoodata && chmod 700 ~/.zoodata && (umask 077; echo '{\"api_key\":\"hms_live_xxx\"}' > ~/.zoodata/config.json)` (persistent; keep the file private — 0600)\n4. **Optionally** state in **one sentence** what the workflow will produce once the key is configured (deliverable shape only — no numbers, no market color, no \"common sense\" preview).\n\n## On 401 Invalid Key\n\nWhen `zoodata.py` returns a structured error with `_transport.status=401`,\n`error.status=401`, and `error.message=\"API Key invalid or expired\"`:\n\n1. **STOP further endpoint calls immediately.** Do not retry — a rejected key won't be accepted on a second try; every subsequent call will return 401 too.\n2. **Keep the selected credential authoritative.** Do not inspect, compare, export, or switch to a lower-priority legacy credential after rejection. A legacy credential may be selected only when neither new source is configured; trying another endpoint or asking to continue does not change this precedence.\n3. **Report to the user**:\n   - The selected ZooData credential was rejected (likely invalid, revoked, or expired)\n   - If any partial findings were collected before the failure, show them and mark as partial\n   - Fix at https://zoodata.ai/en/api-keys (verify the key, regenerate if needed)\n4. **Do not fabricate or guess** the data the failed calls would have returned. This includes \"training-data fallback\" / \"industry common-sense\" headlines disguised as preview — those are fabrications.\n\n## On 402 Credit Exhausted\n\nWhen `zoodata.py` returns a structured error with `_transport.status=402`,\n`error.status=402`, and `error.message=\"API quota exhausted or subscription expired\"`:\n\n1. **STOP further endpoint calls immediately.** Do not retry. Do not switch endpoints as a workaround — 402 is account-level (key/subscription), not endpoint-level.\n2. **Report to the user** with all four of:\n   - Which step in the workflow was reached (e.g. \"Completed step 3/5: brand analysis\")\n   - Partial findings already collected (show the actual data, not just a list of completed steps)\n   - Returned credit metadata when available; if it is absent, say it was not returned rather than estimating it\n   - Top-up link: https://zoodata.ai/en/pricing\n3. **Do not fabricate or guess** the missing data to \"complete\" the report. Mark partial findings explicitly as partial. **No \"training-data fallback\" / \"industry common-sense\" filler** — substituting public-knowledge prose for missing endpoint data is still fabrication.\n\n## On 422 Validation Error\n\nFor every parsed HTTP response from `zoodata.py`, treat `_transport.status` as the authoritative outer status; response-body and nested status-like fields do not override it. When the CLI returns HTTP 422 / `VALIDATION_ERROR`, read the preserved structured server error on stdout, including its message/details and `_query.params`. Do not retry the unchanged request. Correct the named fields first; the CLI exits non-zero while preserving the server error fields for the calling agent. Keyword endpoints that expose granularity currently accept `week` only; do not send `day`, `month`, `lately_day`, or `lookbackDays`.\n\n## 22 Endpoints\n\n| # | Endpoint | Purpose | Key Output |\n|---|----------|---------|------------|\n| 1 | `categories` | Browse/search category tree | categoryPath, productCount |\n| 2 | `markets/search` | Market-level metrics | sampleAvgMonthlySales, sampleAvgPrice, topSalesRate, sampleNewSkuRate |\n| 3 | `products/search` | Product search (20+ filter fields) | asin, price, monthlySalesFloor, rating, ratingCount, fbaFee |\n| 4 | `products/competitors` | Competitor discovery | same fields as products/search |\n| 5 | `realtime/product` | Live ASIN detail | rating, features, bestsellersRank[], buyboxWinner.price, variants |\n| 6 | `reviews/analysis` | AI review insights (11 dims) | sentimentDistribution, consumerInsights, topKeywords |\n| 7 | `realtime/reviews` | Live raw review text (cursor paginated, max 100) | reviews[], nextCursor — feeds Local Review Toolkit |\n| 8 | `products/price-band-overview` | Price band summary | hottestBand, bestOpportunityBand, sampleOpportunityIndex |\n| 9 | `products/price-band-detail` | Full 5-band distribution | priceBands[] with sales, brands, ratings per band |\n| 10 | `products/brand-overview` | Brand concentration | sampleTop10BrandSalesRate (CR10), sampleBrandCount |\n| 11 | `products/brand-detail` | Per-brand breakdown | brands[] with sales, revenue, sampleProducts |\n| 12 | `products/history` | Time series (single ASIN per call) | timestamps[], price[], bsr[], monthlySalesFloor[], rating[], ratingCount[], sellerCount[], title/imageUrl/bestSeller/newRelease/aPlus/inventoryStatus changelogs |\n| 13 | `/openapi/v2/keywords/detail` | Keyword summary from the nearest available weekly snapshot | `data.context + data.items[].snapshotData` with `estimateSearchCount`, `abaRank`, market/SKU/ad fields |\n| 14 | `/openapi/v2/keywords/market-profile` | Multidimensional weekly keyword profile | demand scale, Top3 concentration, ad activity, organic-entry difficulty, saturation, brand structure, organic benchmark, coverage |\n| 15 | `/openapi/v2/keywords/trend` | Weekly keyword time series | `data.context + data.items[].series[]` with search count, ABA rank, Top3 shares, period bounds |\n| 15b | `/openapi/v2/keywords/trend-profile` | Server-calculated trend profile over fixed weekly windows | trend shape, volatility, normalized slope, direction consistency, ABA-rank evidence |\n| 16 | `/openapi/v2/keywords/extends` | Keyword expansion / long-tail discovery | `data.context + data.rows[].{matchData,keywordSnapshot}`; may return empty `rows[]` |\n| 17 | `/openapi/v2/keywords/search-results` | Weekly keyword SERP snapshot | `data.context + data.identity + data.rows[]` with placement, product, and impression fields |\n| 18 | `/openapi/v2/keywords/competitor-product-keywords` | Keyword set where an ASIN appears as a competitor | `data.context + data.identity + data.rows[]` with keyword, position, demand, and traffic share |\n| 19 | `/openapi/v2/keywords/product-traffic-terms` | Traffic-driving keywords for an ASIN | same response shape as competitor-product-keywords |\n| 20 | `/openapi/v2/keywords/product-traffic-terms-overview` | Weekly ASIN all-keyword traffic-change overview | current vs previous-period placement-level impression points, ORG first-3-page keyword entries/exits |\n| 21 | `/openapi/v2/keywords/product-traffic-terms-timeline` | ASIN + keyword weekly timeline | `data.context + data.items[].series[]` with nested ASIN, traffic, placement, keyword, and ad groups |\n\n## Known Quirks\n- `topN`, `listingAge`, `newProductPeriod` are **strings** (`\"10\"` not `10`)\n- Many search/list endpoints return `.data` as an **array** — use `.data[0]` for the first record. But some commands may return non-array payloads inside `data`, so inspect the actual response shape before indexing.\n- `ratingCount` not `reviewCount` everywhere\n- `bsr` (int) in products vs `bestsellersRank` (array) in realtime\n- `buyboxWinner.price` — NOT top-level `price` in realtime\n- `realtime/product` does NOT return: monthlySalesFloor, fbaFee, sellerCount\n- `realtime/product` cold-start: first call for an uncached ASIN may return `success: true` with an EMPTY `data` (`asin: \"\"`) while the live fetch warms up — retry once after a few seconds before concluding \"no data\" (still billed 1 credit per call)\n- `reviewCountMin/Max` filters currently broken (API-56)\n- `reviews/analysis` may 500 for certain ASINs (API-58) — retry different ASIN\n- Rate limit: 100 req/min, 10 req/sec burst\n- `categories` uses `categoryKeyword` (not `keyword`) and `parentCategoryPath` (not `parentCategoryName`)\n- `reviews/analysis`: `mode` required (\"asin\"/\"category\"), use `asins` (plural array) not `asin`\n- `realtime/reviews`: returns 10 reviews/page fixed (no `pageSize` param); 1 credit/page; cursor-paginated; hard cap = 100 reviews (10 pages); supports `marketplace` US/UK only\n- `keywords/detail` accepts exactly one of `keyword` / `keywords[]` (max 20), resolves `date` to the nearest available weekly snapshot, and returns input-ordered `data.items[]`; an unmatched item has `status=empty`, not top-level `data: null`\n- `keywords/market-profile` accepts one of `keyword` / `keywords[]` (max 20), requires `date`, supports weekly granularity only, and returns input-ordered `data.items[]` with `status=ok|empty`. `emptyReason` is descriptive no-result text, not an enum. A subject-specific calculation failure can return HTTP 500 for the whole batch.\n- `keywords/trend-profile` accepts one of `keyword` / `keywords[]` (max 20), requires `date` and 1–4 unique `windowPeriods` selected from 4/8/12/26, and supports weekly granularity only.\n- `keywords/extends` requires `query` (not `keyword`), uses the latest available weekly snapshot, supports `queryType` = `phrase` or `fuzzy`, and may legitimately return empty `data.rows[]`; legacy `date` is optional and ignored\n- All keyword endpoints that expose `granularity` currently support `week` only. `day`, `month`, `lately_day`, and `lookbackDays` are unsupported. Use returned period boundaries instead of inferring a rolling window.\n- Keyword endpoints are keyword-query workflows; for inputs named `keyword` or `query`, use the Amazon search query / keyword phrase being analyzed\n- For keyword endpoints that require `date` or `dateTo`, prefer T-1 or earlier and avoid the current date unless the user explicitly asks for today's lookup\n- `keywords/search-results` requires `date` + `keyword`; `exploreTypes` values are `ORG`, `SP`, `SB`, `SBV`, `SPR`\n- `keywords/competitor-product-keywords` and `keywords/product-traffic-terms` require `date` + `asin`; both currently return the same live item shape, including `trafficShare`\n- `keywords/product-traffic-terms-overview` requires `date` + `asin`; it returns the latest weekly overview of all keyword impression traffic changes under that ASIN at or before the date, compared with the previous period\n- `keywords/product-traffic-terms-timeline` requires `asin` + exactly one of `keyword` / `keywords[]` + `dateFrom` + `dateTo`; the date range cannot exceed 61 days and the series request has no pagination or sort parameters\n- `keywords/search-results` is the default source for explaining what products currently appear on a keyword SERP because it already returns listing-level product fields\n- `products/search` is a broader ZooData product-database query and must not be presented as Amazon live keyword SERP ordering\n\n## Keyword Intelligence Endpoints\n\nThese ten endpoints fill the gap between raw\ncatalog data and search-demand/search-visibility intelligence.\n\nKeyword value boundary:\n- Keyword endpoints provide estimated search, visibility, rank, traffic-share, and impression-point signals\n- They do not provide a seller's first-party ABA Search Query Performance funnel by themselves\n- Treat keyword value, profitability, and conversion potential as directional unless the user supplies ABA-SQP impressions, clicks, cart adds, purchases, click share, purchase share, and conversion rate\n- Seller-artifact acquisition, stage selection, field interpretation, and user-facing output policy belong to the `amazon-keyword-traffic-analysis` skill. This API reference does not prescribe a blanket caveat or one seller view for every subject.\n\n### `/openapi/v2/keywords/detail`\n- Input: exactly one of `keyword` / `keywords[]` (1–20), required `date`, optional `marketplace`, `granularity=week` only\n- Data window: resolves the requested `date` to the nearest available weekly snapshot at or before that date\n- Date rule: prefer T-1 or earlier for `date`; avoid current-date lookup unless explicitly requested\n- Response shape: `data.context + data.items[]`, preserving request order\n- Item fields: `identity`, `status=ok|empty`, `snapshotData`, `emptyReason`, nullable `errorCode`, nullable `errorMessage`\n- `snapshotData` fields include `estimateSearchCount`, `abaRank`, Top3 click/conversion shares,\n  `marketCharacteristics`, `totalSkuCount`, SKU/brand/title coverage, organic/ad counts, and Top48 benchmarks\n- Do not read legacy `estimateSearchCountWeekly`, `totalSkuCnt`, or top-level `data:null`\n\n### `/openapi/v2/keywords/market-profile` (metric layer)\n- Availability: standard production endpoint under the documented base URL\n- Input: exactly one of `keyword` or `keywords[]` (1–20), required `date`, optional `marketplace`, `granularity=week` only\n- Response shape: `data.context + data.items[]`, preserving request order\n- Context fields: `requestedDate`, `resolvedDate`, `dataWindow.currentPeriod`, `scoringSpec`, marketplace/site/granularity\n- Item fields: `identity`, `status=ok|empty`, `marketProfile`, `emptyReason`\n- `marketProfile` dimensions: `marketCharacteristics`, `demandScale`, `top3Concentration`, `adActivity`, `top20OrganicEntryDifficulty`, `supplySaturation`, `brandStructure`, `organicProductBenchmark`\n- Interpret scores only with `context.scoringSpec` (`id`, `version`, `scoreType`, `scoreRange`, `referenceScope`). Scored dimensions expose `supported`, `calculationStatus`, `unsupportedReason`, `level`, `interpretation`, and `levelEvidence.score.{value,direction}`. There is no aggregate coverage object.\n- `marketCharacteristics.volatility` and `marketCharacteristics.annualSeasonality` are independent evidence objects. Do not collapse their classifications, let one override the other, or invent peak periods from an empty list.\n- Unmatched keywords return `status=empty`, `marketProfile=null`, and a descriptive `emptyReason`; resolved context and `scoringSpec` may be null\n- A subject-specific calculation failure can currently produce HTTP 500 for the whole batch. Treat it as a service failure, not an item-level `empty` result; do not automatically fan out all subjects into single calls.\n- Three-layer boundary: use data-layer `keywords/detail` for source snapshot fields, metric-layer `keywords/market-profile` for stable deterministic profile objects, and the Agent + skill layer for evidence composition, confidence, explanations, limitations, and actions\n- Metric-first access: call the matching metric before its source data endpoint. Descend only when the Agent needs an indicator or evidence grain omitted by the metric contract, the metric endpoint is unavailable and transparent data-based calculation is valid, no metric exists, or raw evidence is explicitly requested. Incomplete metric calculation coverage is a conclusion limit—not by itself a reason to call same-source data.\n- Batch-first execution: after selecting the endpoint, collect all subjects with identical non-subject context and prefer its batch contract over repeated single calls. Deduplicate case-insensitively, preserve order, chunk compatible sets at the endpoint limit (20 for current keyword batches), and merge results back into global input order. Batch support never justifies an extra cross-layer call.\n\n### `/openapi/v2/keywords/trend`\n- Input: exactly one of `keyword` / `keywords[]` (1–20), required `dateFrom` / `dateTo`, optional `marketplace`, `granularity=week` only; maximum 93-day range\n- Data window: weekly-granularity points across the requested date range\n- Date rule: prefer T-1 or earlier for `dateTo`; avoid current-date lookup unless explicitly requested\n- Response shape: `data.context + data.items[].series[]`, preserving request order\n- Item fields: `identity`, `status=ok|empty`, `series[]`, `emptyReason`, nullable `errorCode`, nullable `errorMessage`\n- Series fields: `periodStartDate`, `periodEndDate`, `estimateSearchCount`, `abaRank`,\n  `abaTop3ClickShareRate`, `abaTop3ConversionShareRate`\n\n### `/openapi/v2/keywords/trend-profile` (metric layer)\n- Input: exactly one of `keyword` / `keywords[]` (1–20), required `date`, required unique `windowPeriods[]` selected from 4/8/12/26, optional `marketplace`, `granularity=week` only\n- Response: `data.context + data.items[].rows[]`; every requested window returns one row with `rowContext`, `status=ok|empty`, `emptyReason`, and `trendProfile`\n- Available profiles contain independently guarded `searchDemand` and `abaRank` dimensions with `trend`, `trendPattern`, and `{value,direction}` entries under `trendEvidence`\n- Evidence includes first/last/change values, normalized slope, direction consistency, aligned/eligible period counts, plus demand volatility/window position or ABA best/worst rank\n- Use this metric endpoint before raw `keywords/trend` for trend-shape and volatility judgments. Descend only for required weekly points or fields omitted from the profile.\n- Preserve null empty reasons rather than inventing one. Billing is per keyword with at least one `status=ok` window; use returned credit metadata.\n\n### `/openapi/v2/keywords/extends`\n- Input: required `query`; optional `marketplace`, `page`, `pageSize`, `queryType`, `sortBy`, `sortOrder`; no date is required\n- Important quirk: seed field is `query`, not `keyword`; `queryType` supports `phrase` and `fuzzy`\n- Data window: latest available weekly snapshot; a legacy `date` may be sent but is ignored\n- Response shape: `data.context + data.query + data.queryType + data.rows[]`\n- Row fields: `matchData.{query,keyword,site,relevanceScore}` and `keywordSnapshot`, whose\n  `dataWindow.currentPeriod` and snapshot metrics use the same current field families as `keywords/detail`\n- Do not flatten rows to legacy `term`, `seedKeyword`, or `estimateSearchCountWeekly`; empty `rows[]` is normal\n\n### `/openapi/v2/keywords/search-results`\n- Input: required `keyword` / `date`, `granularity=week` only; optional `marketplace`, `page`, `pageSize`, `exploreTypes`, `sortBy`, `sortOrder`\n- Do not send `lookbackDays`; `day`, `month`, and `lately_day` are unsupported\n- Data window: latest available weekly period at or before the requested date; use the returned period boundaries\n- Date rule: prefer T-1 or earlier for `date`; avoid current-date lookup unless explicitly requested\n- Response shape: `data.context + data.identity + data.rows[]`\n- Row fields include `latestObservedAt`, `exploreType`, `absolutePosition`, `pageIndex`,\n  `pagePosition`, `asin`, `title`, `brand`, `price`, `currency`, `link`, `imageLink`, `rating`,\n  `ratingCount`, `recentSales`, `hasVideo`, `estimateImpressionPoint`,\n  `keywordTotalEstimateImpressionPoint`\n- Interpretation rule: use this endpoint first for \"what is on page 1 / what products dominate this keyword / what does the SERP look like\"\n- Do not substitute `products/search` when the question is about observed keyword SERP composition or ordering\n\n### `/openapi/v2/keywords/competitor-product-keywords`\n- Input: required `asin` / `date`, `granularity=week` only; optional `marketplace`, `page`, `pageSize`, `exploreTypes`,\n  `keywordContains`, `sortBy`, `sortOrder`\n- Do not send `lookbackDays`; `day`, `month`, and `lately_day` are unsupported; use returned weekly period boundaries\n- Date rule: prefer T-1 or earlier for `date`; avoid current-date lookup unless explicitly requested\n- Response shape: `data.context + data.identity + data.rows[]`\n- Row fields include `latestObservedAt`, `exploreType`, `absolutePosition`, `pageIndex`,\n  `pagePosition`, `asin`, `keyword`, `estimateImpressionPoint`, `asinTotalEstimateImpressionPoint`,\n  `avgPosition`, `daysCoverageRate`, `observationCount`, `keywordEstimateSearchCount`,\n  `keywordEstimateSearchChangeCount`, `keywordEstimateSearchCountChangeRate`, `keywordAbaRank`,\n  `keywordAbaRankChangeCount`, `trafficShare`\n\n### `/openapi/v2/keywords/product-traffic-terms`\n- Input: same request shape as `keywords/competitor-product-keywords`\n- Data window: weekly period selected by `date` + `granularity=week`; use returned period boundaries\n- Date rule: prefer T-1 or earlier for `date`; avoid current-date lookup unless explicitly requested\n- Response shape: `data.context + data.identity + data.rows[]`\n- Row fields include `latestObservedAt`, `exploreType`, `absolutePosition`, `pageIndex`,\n  `pagePosition`, `asin`, `keyword`, `estimateImpressionPoint`, `asinTotalEstimateImpressionPoint`,\n  `avgPosition`, `daysCoverageRate`, `observationCount`, `keywordEstimateSearchCount`,\n  `keywordEstimateSearchChangeCount`, `keywordEstimateSearchCountChangeRate`, `keywordAbaRank`,\n  `keywordAbaRankChangeCount`, `trafficShare`\n- Live validation note: current live response item shape matches `keywords/competitor-product-keywords`\n  field-for-field; keep the semantic distinction in output wording rather than assuming a unique schema\n\n### `/openapi/v2/keywords/product-traffic-terms-overview`\n- Input: `asin`, `date`, optional `marketplace`\n- Data window: latest weekly overview snapshot at or before the requested date; compares all keyword impression traffic under the ASIN with the previous period\n- Date rule: prefer T-1 or earlier for `date`; avoid current-date lookup unless explicitly requested\n- Response shape: `data` is an object or `null`\n- Key fields from live MCP response: `periodStartDate`, `periodEndDate`, `asin`, `site`,\n  `organicImpressionPoint`, `sponsoredProductImpressionPoint`, `sponsoredBrandImpressionPoint`,\n  `sponsoredBrandVideoImpressionPoint`, `sponsoredRecommendImpressionPoint`,\n  `organicImpressionPointPrev`, `sponsoredProductImpressionPointPrev`,\n  `sponsoredBrandImpressionPointPrev`, `sponsoredBrandVideoImpressionPointPrev`,\n  `sponsoredRecommendImpressionPointPrev`, `first3PagesNewOrganicKeywords`,\n  `first3PagesLostOrganicKeywords`\n- `*Prev` fields are previous-period baselines for the matching current impression-point fields\n- The legacy response returns only the current `periodStartDate` / `periodEndDate`; it does not return separate previous-period boundaries. A `*Prev` field may be null or absent when no previous-period value is available.\n- `first3PagesNewOrganicKeywords` and `first3PagesLostOrganicKeywords` are arrays of objects with\n  `keyword`, `pageIndex`, and `pagePosition`\n- `first3PagesNewOrganicKeywords` lists keywords newly entering ORG first three pages; `first3PagesLostOrganicKeywords`\n  lists keywords that dropped out of ORG first three pages\n- Live validation request: MCP tool `openapi_v2_product_traffic_terms_overview`,\n  `asin=\"B01CGLCGRA\"`, `date=\"2026-06-29\"`, `marketplace=\"US\"`\n\n### `/openapi/v2/keywords/product-traffic-terms-timeline`\n- Input: required `asin`, exactly one of `keyword` / `keywords[]` (1–20), `dateFrom`, `dateTo`, `granularity=week` only; optional `marketplace`\n- Do not send `lookbackDays`, `page`, `pageSize`, `sortBy`, or `sortOrder`; `day`, `month`, and `lately_day` are unsupported\n- Data window: ASIN + keyword timeline across the requested date range; date range cannot exceed 61 days\n- Date rule: prefer T-1 or earlier for `dateTo`; avoid current-date lookup unless explicitly requested\n- Response shape: `data.context + data.items[].series[]`, preserving keyword request order\n- Item fields: `identity`, `status=ok|empty`, `series[]`, `emptyReason`, nullable `errorCode`, nullable `errorMessage`\n- Each series point groups fields under `asinSnapshot`, `traffic`, `placement`, `keywordMetrics`, and `adActivity`; keep their returned period boundaries separate\n- Diagnosis curves/events: price (`asinSnapshot.latestPrice`), BSR (`asinSnapshot.latestBsr`,\n  `asinSnapshot.latestSubBsr`), sales (`asinSnapshot.latestMonthlySaleCount`), rating\n  (`asinSnapshot.latestRating`, `asinSnapshot.latestRatingCount`), traffic estimate (`traffic.*`\n  plus placement averages), and listing events (`asinSnapshot.latestTitle`, `asinSnapshot.latestMainImageLink`)\n- Key groups: listing/product/rank fields in `asinSnapshot`; ORG/SP/SB/SBV/SPR impression points\n  in `traffic`; positions/pages/observation times in `placement`; weekly search/ABA fields and\n  `metricWindow` in `keywordMetrics`; observation/campaign/ad counts in `adActivity`\n\n## Local Review Toolkit\n\nWhen `/reviews/analysis` lacks aggregation (ASIN has <50 reviews or no daily snapshot),\nfall back to live raw reviews + your own LLM. The toolkit does NOT call any external\nLLM — you (the calling skill's LLM) perform the Map/Reduce steps.\n\n**Workflow:**\n\n```bash\n# 1. Fetch raw reviews (up to 100, cursor-paginated, ~60s, 10 credits at full)\nzoodata.py reviews-raw --asin B0XXXXXXXX [--marketplace US] [--max-pages 10]\n\n# 2. For EACH review, render the per-review Map prompt\nzoodata.py review-tag-prompt --review '<single review JSON>' \\\n    [--product-title \"...\"] [--product-category \"...\"]\n# → Your LLM produces a JSON object with sentiment + 11 dimension arrays\n#   (mentioned_scenarios, mentioned_issues, mentioned_positives, mentioned_improvements,\n#    mentioned_buying_factors, mentioned_pain_points, user_profiles, mentioned_usage_times,\n#    mentioned_usage_locations, mentioned_behaviors, keywords)\n# Suggested map parallelism: ~20 concurrent if your LLM supports it\n\n# 3. Collect candidate phrases per dimension. For EACH dimension render the Reduce prompt\nzoodata.py review-reduce-prompt --label-type positives \\\n    --candidates '[\"comfortable\",\"comfy\",\"very comfortable\",...]'\n# → Your LLM produces {clusters: [{canonical, members}, ...]}\n# Suggested chunk size for `keywords` dim when >150 candidates: 150 per call\n\n# 4. Aggregate into reviews/analysis-compatible consumerInsights\nzoodata.py review-aggregate --reviews raw.json --tagged tags.json --clusters clusters.json\n# → Output shape matches /reviews/analysis: reviewCount, avgRating,\n#   sentimentDistribution, consumerInsights[], topKeywords[]\n```\n\n**When to use the toolkit instead of `reviews/analysis`:**\n- ASIN has fewer than 50 reviews\n- `reviews/analysis` returns sparse `consumerInsights` (missing dimensions)\n- Need the freshest possible data (Spider scrape vs. T+1 BigQuery snapshot)\n- Need to analyze a brand-new product that has no daily snapshot yet\n\n## Field Differences Across Endpoints\n\n| Data | markets | products/competitors | realtime/product | reviews/analysis | realtime/reviews | price-band | brand | history |\n|------|---------|---------------------|----------|---------|---------|------------|-------|---------|\n| Sales | sampleAvgMonthlySales | monthlySalesFloor | ❌ | ❌ | ❌ | sampleSalesRate | sampleGroupMonthlySales | monthlySalesFloor[] |\n| Price | sampleAvgPrice | price | buyboxWinner.price | ❌ | ❌ | bandMin/MaxPrice | sampleAvgPrice | price[] |\n| BSR | sampleAvgBsr | bsr (int) | bestsellersRank[] | ❌ | ❌ | ❌ | ❌ | bsr[] |\n| Rating | sampleAvgRating | rating | rating | avgRating | rating (per review) | sampleAvgRating | sampleAvgRating | rating[] |\n| Reviews | sampleAvgReviewCount | ratingCount | ratingCount | reviewCount | reviews[] (raw text, max 100) | ❌ | sampleAvgRatingCount | ratingCount[] |\n| Insights | ❌ | ❌ | ❌ | ✅ consumerInsights | ❌ (raw only — feeds Local Review Toolkit) | ❌ | ❌ | ❌ |\n| Concentration | topSalesRate | ❌ | ❌ | ❌ | ❌ | sampleTop3BrandSalesRate | CR10 | ❌ |\n| Opportunity | ❌ | ❌ | ❌ | ❌ | ❌ | sampleOpportunityIndex | ❌ | ❌ |\n\n## Confidence Labels (all skills)\n- 📊 **Data-backed** — direct API data\n- 🔍 **Inferred** — logical reasoning from data\n- 💡 **Directional** — suggestions, predictions\n\nStrategy recommendations and subjective conclusions are NEVER 📊. Extreme growth (>200%) = 💡 only.\n\n## Data Notes\n- Sales (`monthlySalesFloor`) = lower-bound estimate\n- Realtime = live; products/competitors = ~T+1 delay\n- Marketplace coverage varies by endpoint; follow each endpoint schema\n- Each call consumes credits; check `meta.creditsConsumed`\n\n## Links\n- [zoodata.ai](https://zoodata.ai) · [API Docs](https://api.zoodata.ai/api-docs) · [GitHub](https://github.com/SerendipityOneInc/ZooData-Skills) · support@zoodata.ai\n\nFile v1.1.9:README.md\n\n# ZooData — Commerce Data Infrastructure for AI Agents\n\n> 200M+ Amazon products. 22 endpoints. One API key.\n\n## What This Skill Does\n\nThe foundational data layer for all ZooData agent skills. Provides direct access to 22 API endpoints covering category browsing, market metrics, product search (20+ filter fields), competitor lookup, real-time ASIN detail, AI review analysis, price band analysis, brand intelligence, product history, and keyword intelligence. Use this skill when you need raw API access or want to understand what data is available.\n\n### What Makes This Different\n\n- **22 endpoints in one skill**: Complete API reference with field mappings and known quirks\n- **Critical pitfalls documented**: Category-first workflow, field naming differences across endpoints, aggregation gotchas\n- **Cross-endpoint field guide**: Know exactly which field to use from which endpoint\n- **Foundation for all skills**: Every ZooData skill builds on this data layer\n\n## Install\n\n```bash\nnpx skills add SerendipityOneInc/ZooData-Skills\n```\n\nSelect **ZooData** when prompted.\n\n## API Key Setup\n\n1. Get a free key at [zoodata.ai/api-keys](https://zoodata.ai/en/api-keys) — 1,000 free credits, no credit card\n2. Set the environment variable:\n   ```bash\n   export ZOODATA_API_KEY='hms_live_xxxxxx'\n   ```\n\n## Example Prompts\n\n- *\"What ZooData endpoints are available?\"*\n- *\"What ZooData endpoints are available and how do I use them?\"*\n- *\"Look up real-time data for ASIN B0XXXXXXXX\"*\n- *\"Search for products in the 'yoga mat' category sorted by sales\"*\n- *\"Pull the market data for this product category\"*\n\n## What You Get\n\n| Section | Description |\n|---------|-------------|\n| 📚 22 Endpoint Reference | Purpose, key parameters, output fields |\n| ⚠️ API Pitfalls | Critical rules all skills must follow |\n| 📊 Field Difference Table | Which field comes from which endpoint |\n| 🏷️ Confidence Labels | Data-backed / Inferred / Directional tagging system |\n| 📝 Known Quirks | String types, array handling, rate limits |\n\n## API Endpoints\n\n| # | Endpoint | Purpose |\n|---|----------|---------|\n| 1 | `categories` | Browse/search category tree |\n| 2 | `markets/search` | Market-level metrics (sales, price, concentration) |\n| 3 | `products/search` | Product search with 20+ filter fields (13 CLI presets) |\n| 4 | `products/competitors` | Competitor discovery |\n| 5 | `realtime/product` | Live ASIN detail (rating, BSR, Buy Box, variants) |\n| 6 | `reviews/analysis` | AI review insights (sentiment, pain points, keywords) |\n| 7 | `realtime/reviews` | Live raw review text |\n| 8 | `products/price-band-overview` | Price band summary (hottest, best opportunity) |\n| 9 | `products/price-band-detail` | Full 5-band distribution |\n| 10 | `products/brand-overview` | Brand concentration (CR10) |\n| 11 | `products/brand-detail` | Per-brand breakdown |\n| 12 | `products/history` | Daily price/BSR/sales snapshots |\n| 13 | `keywords/detail` | Keyword weekly snapshot |\n| 14 | `keywords/market-profile` | Multidimensional weekly keyword market profile |\n| 15 | `keywords/trend` | Keyword weekly trend |\n| 16 | `keywords/trend-profile` | Keyword trend profile for fixed weekly windows |\n| 17 | `keywords/extends` | Keyword expansion |\n| 18 | `keywords/search-results` | Keyword SERP snapshot |\n| 19 | `keywords/competitor-product-keywords` | Competitor ASIN keyword coverage |\n| 20 | `keywords/product-traffic-terms` | ASIN traffic-driving keywords |\n| 21 | `keywords/product-traffic-terms-overview` | Weekly ASIN traffic-term overview |\n| 22 | `keywords/product-traffic-terms-timeline` | ASIN + keyword timeline |\n\nKeyword endpoint note: ZooData keyword data is estimated search, exposure, visibility, rank, placement, and impression evidence; it is not seller ABA-SQP or Amazon Ads performance. Analysis-stage routing, seller-artifact acquisition, and output policy are owned by [`amazon-keyword-traffic-analysis`](../amazon-keyword-traffic-analysis/).\n\nKeyword date rule: keyword workflows are keyword-query lookups. When a keyword endpoint requires `date` or `dateTo`, prefer T-1 or earlier and avoid current-date lookup unless the user explicitly asks for today's data.\n\n## Credit Cost\n\nVaries per endpoint. Each call consumes credits — check `meta.creditsConsumed` in response. 1,000 free credits on signup.\n\n## Powered By\n\n[ZooData](https://zoodata.ai) — The data infrastructure built for agents. 200M+ Amazon products, 1B+ reviews, real-time signals.\n\nFile v1.1.9:_meta.json\n\n{\n  \"ownerId\": \"kn78k155f6rbh2j8r8yjx8r2e18304q9\",\n  \"slug\": \"zoodata\",\n  \"version\": \"1.1.9\",\n  \"publishedAt\": 1786068900697\n}\n\nFile v1.1.9:references/cli-contract.md\n\n<!-- Canonical source - do not edit copies under amazon-* skill directories directly -->\n\n# ZooData CLI Contract\n\n## Ownership and application\n\nThis file owns the project-wide caller contract before and after every bundled `{skill_base_dir}/scripts/zoodata.py` invocation. Read it before selecting the first command, then apply it after each granular or composite result and before any additional API/tool call, fallback, state write, interpretation, or user-facing report.\n\nIt owns the shared invocation form, command-identity validation, execution-environment permission handling, caller/CLI responsibilities, composite-result reuse, result acquisition, transport-status precedence, terminal-interface classification, retry ownership, and partial-result handling. It does not own skill-specific command allowlists, endpoint request/response fields, business interpretation, scenario selection, conclusion authority, or any user-facing failure/report rendering.\n\n## Invocation interface\n\n1. Invoke the bundled client as `python {skill_base_dir}/scripts/zoodata.py [global options] <subcommand> [subcommand options]` using the active skill's local copy.\n2. Place global options before the subcommand. Treat top-level and subcommand `--help` as the live invocation contract; help inspection makes no API request and consumes no credits.\n3. Use the active skill to select the allowed workflow and command scope. Use this contract to validate and execute that selection; do not let this shared file select a business workflow.\n4. Distinguish API/evidence commands from local-only diagnostic, prompt-rendering, and aggregation commands according to the selected subcommand's help. Do not attribute an API call or credit use to a local-only command.\n5. Credential resolution is owned by the bundled CLI. Invoke it directly; do not inspect local credential stores or pre-resolve, compare, export, or override credential values in the caller.\n\n## Command identity and composite reuse\n\n1. Inspect the bundled CLI's top-level `--help` and the selected subcommand's `--help` before invocation. Execute only an exact literal subcommand exposed by the current client and allowed by the active skill.\n2. Treat API endpoint identifiers and composite result keys as data identities, not CLI command names. Never derive a subcommand from either identity or invent an alias.\n3. Treat a successful composite command's structured output as the evidence bundle for that run. Perform selection, narrowing, transformation, extraction, and formatting locally.\n4. Do not make an additional API call solely to reread, reshape, or narrow evidence already present in the composite bundle.\n5. A granular call after a composite is allowed only for evidence absent from the bundle when the active skill's workflow or an explicit non-terminal fallback requires it.\n6. A keyword-driven composite resolves the working category through a fallback chain and records the outcome in `meta`: `meta.category_source` states how it resolved and `meta.resolved_category_path` carries the path used. An empty top-level `categories` section together with a non-null `meta.resolved_category_path` is successful fallback resolution (a multi-word product phrase not matching a category name), not missing data; read the resolved path and `category_source` before treating category evidence as absent.\n\n## Execution-environment permission gate\n\nApply this gate before classifying a connection or network failure as a CLI/API interface failure.\n\n1. Inspect the execution tool's permission profile and diagnostics. When they indicate, or strongly suggest, that a host sandbox or network policy blocked the request, treat the result as unresolved execution permission rather than endpoint failure.\n2. Use the execution tool's permission or escalation mechanism to request access and rerun the exact unchanged CLI command. Do not first emit the skill's interface-failure notice or a succeeded/failed endpoint ledger.\n3. A permission-approved rerun is environment recovery, not an external transport retry. Do not mutate the command, parameters, endpoint, or acquisition surface while requesting access.\n4. If access is declined or no permission mechanism is available, state only that the required network access was not granted and the task could not continue. Do not label endpoints as failed or imply that API requests consumed credits when no request reached the service.\n5. After the permission issue is resolved, classify the rerun normally through the sections below. Do not use this gate to bypass a returned HTTP status, credential failure, credit failure, validation failure, rate limit, or confirmed service outage.\n\n## Result acquisition\n\n1. Always inspect stdout, even when the process exits non-zero. Exit `1` with valid structured JSON means at least one API call failed; it does not make the JSON unreadable.\n2. Treat `_transport.status` as the authoritative outer HTTP status. Response-body or nested status-like fields never override it.\n3. For a composite payload, inspect nested endpoint results before classifying the whole workflow. Preserve returned `_query`, credit metadata, successful sections, and failure details internally.\n\n## Classification order\n\nAfter the execution-environment permission gate is resolved or found inapplicable, apply these routes in order:\n\n1. Missing credentials before an evidence call follow the local skill's missing-key procedure.\n2. `_transport.status=401` and `_transport.status=402` follow the local skill's credential and credit procedures. Do not retry, switch endpoints, or change credential sources.\n3. `_transport.status=422` is validation failure. Preserve the structured server error and `_query.params`; do not retry the unchanged request. Correct only fields identified by the server contract.\n4. A terminal interface failure is present when the result carries `error.action=\"STOP_CURRENT_TURN. APPLY_SKILL_INTERFACE_FAILURE_TEMPLATE. DO_NOT_SELECT_ANOTHER_COMMAND.\"`, or represents exhausted HTTP 5xx, exhausted 429, exhausted non-HTTP transport failure after host permission restrictions have been ruled out or resolved, endpoint unavailability, `MALFORMED_RESPONSE`, or non-zero execution without valid structured JSON.\n5. A valid `status=empty` or a documented business/coverage error is not automatically terminal. A local skill fallback is allowed only when its contract explicitly supports that result and no terminal interface-failure signal is present.\n\n## Retry and terminal behavior\n\nThe shared CLI owns transport retries. Once the execution-environment permission gate is resolved or found inapplicable, a terminal interface failure requires:\n\n1. Stop the current workflow turn. Do not retry externally, mutate parameters, switch endpoints or acquisition surfaces, start another tool command, or continue to a later workflow step.\n2. Do not reinterpret an HTTP 5xx body as validation, credential, credit, empty coverage, or permission to try another date, subject, marketplace, filter, or page.\n3. Retain earlier successful data for compatible later reuse, but do not produce the normal analysis, update monitoring/baseline state, or request the next workflow input.\n4. Keep detailed messages, request parameters, retry logs, and control tokens internal unless the user explicitly requests diagnostics.\n5. Hand off rendering to the active skill's local interface-failure template. This shared contract intentionally defines no user-facing wording.\n\n## Composite and partial results\n\n- A non-zero composite result may still contain successful sections. If any nested result is a terminal interface failure, stop after inventorying succeeded and failed interfaces; do not turn the surviving sections into the normal conclusion.\n- If all failures are documented non-terminal business/coverage failures, a local skill may use its explicit fallback and the compatible successful sections. Label coverage precisely and never present the composite as fully successful.\n- Process exit status and JSON status must agree for a single-result command. A partial pagination failure must return `success=false` while preserving already collected rows under `data`.\n\n## Realtime unavailable — offline fallback\n\n`realtime/product` is a live scrape endpoint that can return a transient 200-success with an empty payload. Composites retry it a few times; if it is still empty, that item's result carries `_realtimeStatus=\"empty_after_retries\"`, and the composite `meta` carries `realtimeUnavailable` (count) plus `realtimeFallbackHint`. When `realtimeFallbackHint` is present, tell the user realtime lookup is temporarily unavailable for those items, then continue the analysis using the offline snapshot data already gathered (products/search fields, history, price/BSR/rating). Do not stall, silently re-run, or fabricate the missing realtime detail.\n\n## Partial review pagination\n\nWhen `reviews-raw` fails after one or more successful pages, it returns `success=false`, preserves collected reviews and page count under `data`, and exposes the failed page request through `_failedQuery`. Never treat that payload as a complete review sample.\n\nFile v1.1.9:references/openapi-reference.md\n\n# ZooData API Quick Reference\n\n> Concise field reference for the currently documented Amazon commerce and keyword-intelligence endpoints. Load when you need exact parameter/field names.\n>\n> **OpenAPI Spec (live)**: https://zoodata.ai/api/v1/openapi-spec\n\nBase URL: `https://api.zoodata.ai/openapi/v2`\nAuth: `Bearer $ZOODATA_API_KEY`\nMethod: All POST with JSON body\n\n---\n\n## 1. categories\n\n| Parameter | Type | Note |\n|-----------|------|------|\n| categoryKeyword | String | Search by keyword |\n| categoryPath | List\\<String\\> | Exact path lookup, e.g. `[\"Electronics\", \"Computers\"]` |\n| parentCategoryPath | List\\<String\\> | Browse children |\n| _(no params)_ | — | Returns root categories |\n\nResponse: `categoryId`, `categoryName`, `categoryPath`, `hasChildren`, `isRoot`, `level`, `productCount`, `link`\n\n---\n\n## 2. markets/search\n\n| Parameter | Type | Note |\n|-----------|------|------|\n| categoryPath | List\\<String\\> | e.g. `[\"Pet Supplies\", \"Dogs\"]` |\n| categoryKeyword | String | Keyword match across levels |\n| topN | **String** | `\"3\"` / `\"5\"` / `\"10\"` / `\"20\"` ⚠️ must be string |\n| newProductPeriod | **String** | `\"1\"` / `\"3\"` / `\"6\"` / `\"12\"` ⚠️ must be string |\n| sampleType | String | `bySale100` / `byBsr100` / `avg` |\n| dateRange | String | default `30d` |\n| pageSize | Integer | default 20 |\n| sortBy | String | default `sampleAvgMonthlySales` |\n| sortOrder | String | `asc` / `desc` |\n\nKey response fields: `sampleAvgMonthlySales`, `sampleAvgPrice`, `sampleAvgMonthlyRevenue`, `sampleBrandCount`, `sampleSellerCount`, `sampleFbaRate`, `sampleNewSkuRate`, `topSalesRate`, `topBrandSalesRate`, `topSellerSalesRate`, `totalSkuCount`\n\n---\n\n## 3. products/competitors\n\n| Parameter | Type | Note |\n|-----------|------|------|\n| keyword | String | Search keyword |\n| brand | String | Brand filter |\n| seller | String | Seller filter |\n| asin | String | ASIN filter |\n| categoryPath | List\\<String\\> | Category filter |\n| sortBy | String | `monthlySalesFloor` / `monthlyRevenueFloor` / `bsr` / `price` / `rating` / `ratingCount` / `listingDate` |\n| sortOrder | String | `asc` / `desc` |\n| pageSize | Integer | default 20 |\n\n---\n\n## 4. products/search\n\nSame as competitors, plus:\n\n| Parameter | Type | Note |\n|-----------|------|------|\n| keywordMatchType | String | `fuzzy` / `phrase` / `exact` |\n| listingAge | **Enum String** | One of `30d` / `90d` / `180d` / `1y` / `2y` (⚠️ bare numbers like `180` → 422) |\n\nFilter pairs (all optional, Min/Max): `monthlySales`, `revenue`, `salesGrowthRate`, `bsr`, `subBsr`, `bsrGrowthRate`, `price`, `rating`, `ratingCount`, `fbaShipping`, `variantCount`, `grossMargin`, `sellerCount`\n\n> `mode` is **NOT** an API parameter. The 13 CLI presets in `zoodata.py` expand client-side into the filter pairs above before the request is sent; passing `mode` in a raw request returns 422.\n\nAdditional: `includeBrands`, `excludeBrands`, `fulfillment` (`[\"FBA\"]`/`[\"FBM\"]`/`[\"AMZ\"]`), `badges` — enum values `[\"bestSeller\"]` / `[\"amazonChoice\"]` / `[\"newRelease\"]` / `[\"aPlus\"]` / `[\"video\"]` (⚠️ `\"New Release\"` with a space → 422)\n\n---\n\n## 5. realtime/product\n\n| Parameter | Required | Note |\n|-----------|----------|------|\n| asin | **Yes** | Product ASIN |\n| marketplace | No | `US`/`UK`/`DE`/`FR`/`IT`/`ES`/`JP`/`CA`/`AU`/`IN`/`MX`/`BR` (default: US) |\n\nResponse fields: `asin`, `title`, `brand`, `rating`, `ratingCount`, `ratingBreakdown`, `features`, `description`, `specifications`, `categories`, `variants`, `bestsellersRank` (array), `buyboxWinner` (object with price), `images`, `dimensions`, `weight`\n\n⚠️ Does NOT have: `monthlySalesFloor`, `fbaFee`, `sellerCount`\n\n---\n\n## 6. reviews/analysis\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| mode | String | **Yes** | `asin` or `category` |\n| asins | List\\<String\\> | When mode=asin | ⚠️ plural, array format |\n| categoryPath | String | When mode=category | Category path |\n| period | String | No | e.g. `6m` |\n\n⚠️ `labelType` is **not** an API request parameter. The API returns all 11 dimensions in one call. Filter by `labelType` client-side from the `consumerInsights` array.\n\nResponse: `reviewCount`, `avgRating`, `verifiedRate`, `ratingDistribution`, `sentimentDistribution`, `consumerInsights` (list of InsightItem), `topKeywords`\n\nInsightItem: `element`, `labelType`, `count`, `reviewRate`, `avgRating`\n\nlabelType values (in response): `scenarios`, `issues`, `positives`, `improvements`, `buyingFactors`, `painPoints`, `keywords`, `userProfiles`, `usageTimes`, `usageLocations`, `behaviors`\n\n---\n\n## 6b. realtime/reviews\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| asin | String | **Yes** | Product ASIN (10 chars) |\n| marketplace | String | No | `US`/`UK` only (default: US) |\n| cursor | String | No | Pagination token from previous response's `nextCursor`. Omit for first page. |\n\n⚠️ No `pageSize` parameter — server returns 10 reviews/page fixed. Hard cap = **100 reviews / 10 pages**. Cost = **1 credit/page**.\n\nResponse: `asin`, `reviews` (array of RealtimeReview), `nextCursor` (null = no more pages).\n\nRealtimeReview: `reviewId`, `title`, `body`, `bodyHtml`, `rating`, `author`, `date` (ISO 8601), `verifiedPurchase`, `vineProgram`, `helpfulVoteCount`, `unhelpfulVoteCount`, `reviewCountry`, `images`, `link`, `isGlobalReview`\n\nUse cases:\n- ASIN has <50 reviews so `/reviews/analysis` aggregation is empty\n- Brand-new product with no daily snapshot\n- Need fresh raw text for local LLM analysis (Map/Reduce → consumerInsights)\n\nSee `zoodata.py reviews-raw / review-tag-prompt / review-reduce-prompt / review-aggregate` for the local toolkit that consumes this endpoint.\n\n---\n\n## 6c. reviews/search\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| asin | String | **Yes** | Product ASIN |\n| ratingMin / ratingMax | Number | No | 1-5 inclusive |\n| verifiedOnly | Boolean | No | Default false |\n| vineOnly | Boolean | No | Default false |\n| helpfulVoteCountMin | Integer | No | Filter low-engagement reviews |\n| dateStart / dateEnd | Date (YYYY-MM-DD) | No | Inclusive range |\n| sortBy | String | No | `recent` (default) / `rating` / `helpfulVoteCount` |\n| sortOrder | String | No | `desc` (default) / `asc` |\n| page | Integer | No | 1-indexed, default 1 |\n| pageSize | Integer | No | 1-20, default 10 |\n\nResponse: array of TaggedReview with AI-generated `tags[{labelType, element}]` derived from the offline analysis pipeline (BigQuery daily snapshot).\n\nTaggedReview vs RealtimeReview: `reviews/search` uses snapshot data with AI tags (T+1 delay); `realtime/reviews` is live raw text (no tags). Use `reviews/search` when daily snapshot exists and you want pre-tagged data; use `realtime/reviews` for fresh data or new products.\n\n---\n\n## 7. products/price-band-overview\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| keyword | String | **Yes** | Search keyword |\n\n⚠️ Only accepts `keyword` — does NOT support `categoryPath`.\n\n**Response (top-level):**\n\n| Field | Type | Note |\n|-------|------|------|\n| sampleMedianPrice | Float | Median price across sampled products |\n| hottestBand | BandObject | Band with highest sales rate |\n| bestOpportunityBand | BandObject | Band with highest opportunity index |\n\n**BandObject:**\n\n| Field | Type | Note |\n|-------|------|------|\n| bandIdx | Integer | Band index (0-4) |\n| bandLabel | String | e.g. \"$10-$20\" |\n| sampleBandMinPrice | Float | Band minimum price |\n| sampleBandMaxPrice | Float | Band maximum price |\n| sampleSkuCount | Integer | Number of SKUs in this band |\n| sampleSalesRate | Float | Share of total sales in this band |\n| sampleBrandCount | Integer | Number of brands in this band |\n| sampleTop3BrandSalesRate | Float | Top 3 brands' share within this band |\n| sampleAvgRating | Float | Average rating in this band |\n| sampleOpportunityIndex | Float | Composite opportunity score |\n\n---\n\n## 8. products/price-band-detail\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| keyword | String | **Yes** | Search keyword |\n\n⚠️ Only accepts `keyword` — does NOT support `categoryPath`.\n\n**Response:**\n\n| Field | Type | Note |\n|-------|------|------|\n| sampleSkuCount | Integer | Total sampled SKUs |\n| sampleTotalMonthlySales | Integer | Total monthly sales across all bands |\n| priceBands | Array\\<BandObject\\> | Array of 5 band objects (same structure as §7) |\n\n---\n\n## 9. products/brand-overview\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| keyword | String | **Yes** | Search keyword |\n\n⚠️ Only accepts `keyword` — does NOT support `categoryPath`.\n\n**Response:**\n\n| Field | Type | Note |\n|-------|------|------|\n| sampleBrandCount | Integer | Total number of brands found |\n| sampleTop10BrandSalesRate | Float | CR10 — top 10 brands' share of total sales |\n| sampleTop10AvgRating | Float | Average rating of top 10 brands |\n| sampleTop10AvgPrice | Float | Average price of top 10 brands |\n\n---\n\n## 10. products/brand-detail\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| keyword | String | **Yes** | Search keyword |\n\n⚠️ Only accepts `keyword` — does NOT support `categoryPath`.\n\n**Response (top-level):**\n\n| Field | Type | Note |\n|-------|------|------|\n| sampleSkuCount | Integer | Total sampled SKUs |\n| sampleTotalMonthlySales | Integer | Total monthly sales |\n| sampleBrandCount | Integer | Total brands found |\n| brands | Array\\<BrandObject\\> | Per-brand breakdown |\n\n**BrandObject:**\n\n| Field | Type | Note |\n|-------|------|------|\n| brandName | String | Brand name |\n| sampleSkuCount | Integer | SKUs for this brand |\n| sampleGroupMonthlySales | Integer | Monthly unit sales |\n| sampleGroupMonthlyRevenue | Float | Monthly revenue |\n| sampleSalesRate | Float | Share of total sales |\n| sampleAvgPrice | Float | Average price |\n| minPrice | Float | Lowest price product |\n| maxPrice | Float | Highest price product |\n| sampleAvgRating | Float | Average rating |\n| sampleAvgRatingCount | Integer | Average review count |\n| sampleProducts | Array\\<ProductObject\\> | Sample products from this brand |\n\n**ProductObject** (within sampleProducts): Same fields as Shared Product Object below.\n\n---\n\n## 11. products/history\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| asin | String | **Yes** | Single ASIN (one per call) |\n| startDate | String | **Yes** | Start date `YYYY-MM-DD` |\n| endDate | String | **Yes** | End date `YYYY-MM-DD` |\n| marketplace | String | No | Marketplace code, default `US` |\n\n⚠️ `asin` is a **single string** — NOT an array. For multiple ASINs, make separate calls.\n⚠️ Does NOT support `page`/`pageSize` — returns full date range in one response.\n⚠️ Uses `startDate`/`endDate` — NOT `dateRange`.\n\n**Response:** Single time series object (NOT an array of snapshots).\n\n| Field | Type | Note |\n|-------|------|------|\n| asin | String | Product ASIN |\n| timestamps | List\\<String\\> | Dates (YYYY-MM-DD) |\n| price | List\\<Float\\> | Price on each date |\n| bsr | List\\<Integer\\> | BSR on each date |\n| subBsr | List\\<Integer\\> | Sub-category BSR |\n| monthlySalesFloor | List\\<Integer\\> | Monthly sales lower bound |\n| rating | List\\<Float\\> | Rating on each date |\n| ratingCount | List\\<Integer\\> | Review count on each date |\n| sellerCount | List\\<Integer\\> | Seller count |\n| title | List\\<ChangeLog\\> | Title changes `{date, value}` |\n| imageUrl | List\\<ChangeLog\\> | Main image changes `{date, value}` |\n| bestSeller | List\\<ChangeLog\\> | Best Seller badge `{date, value}` |\n| amazonChoice | List\\<ChangeLog\\> | Amazon's Choice badge `{date, value}` |\n| newRelease | List\\<ChangeLog\\> | New Release badge `{date, value}` |\n| aPlus | List\\<ChangeLog\\> | A+ content status `{date, value}` |\n| inventoryStatus | List\\<ChangeLog\\> | Stock status `{date, value}` |\n| currency | String | e.g. `USD` |\n\n---\n\n## Keyword Intelligence Endpoints\n\nThis reference is a production endpoint whitelist; every listed endpoint must be deployed and callable through the standard production base URL.\n\nTool-surface note:\n- API documentation and live endpoint availability do not guarantee that the current agent session exposes matching callable tools\n- For skill execution, verify the live tool surface first; use this file for parameter and field confirmation after that\n\n## 12. /openapi/v2/keywords/detail\n\nKeyword value boundary for all keyword endpoints:\n- The keyword endpoints expose estimated search, SERP visibility, rank, traffic-share, and impression-point signals.\n- Keyword endpoints are keyword-query workflows; parameters named `keyword` or `query` expect Amazon search query / keyword phrases.\n- For keyword endpoints that require `date` or `dateTo`, prefer T-1 or earlier and avoid the current date unless the user explicitly asks for today's lookup.\n- These signals support directional screening and testing priority, but do not 100% prove a keyword's value for a specific ASIN.\n- Seller-artifact acquisition, stage selection, field interpretation, and output policy are outside this endpoint contract and belong to the `amazon-keyword-traffic-analysis` skill.\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| keyword | String | Conditional | One keyword; exactly one of `keyword` / `keywords` |\n| keywords | List\\<String\\> | Conditional | Batch of 1–20 keywords; preserves request order |\n| date | String | **Yes** | Lookup date `YYYY-MM-DD`; prefer T-1 or earlier; resolves to the nearest available weekly snapshot at or before that date |\n| marketplace | String | No | `US` / `UK`, default `US` |\n| granularity | String | No | `week` only |\n\n**Response:** `data.context + data.items[]` for both single and batch requests.\n\nContext fields include marketplace/site, requested/resolved date, weekly granularity, and `dataWindow.currentPeriod`.\n\nEach item has `identity`, `status=ok|empty`, `snapshotData`, `emptyReason`, and nullable `errorCode` /\n`errorMessage`. The latter are auxiliary fields, not status enums. `snapshotData` includes\n`estimateSearchCount`, `abaRank`, Top3 click/conversion shares,\n`marketCharacteristics`, `totalSkuCount`, SKU/brand/title coverage, organic/ad counts, and Top48 benchmarks.\n\nDo not expect legacy `estimateSearchCountWeekly`, `totalSkuCnt`, or top-level `data:null`. An unmatched\nkeyword is an item with `status=empty` and an `emptyReason`.\n\n---\n\n## 12b. /openapi/v2/keywords/market-profile (metric layer)\n\nAvailability: standard production endpoint under the documented base URL. A subject-specific calculation failure can return HTTP 500 for the whole batch; treat that as runtime behavior, not an empty item.\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| keyword | String | Conditional | One keyword; exactly one of `keyword` / `keywords` |\n| keywords | List\\<String\\> | Conditional | Batch of 1–20 keywords; preserves request order |\n| date | String | **Yes** | Lookup date `YYYY-MM-DD`; resolves to the latest weekly snapshot on or before this date |\n| marketplace | String | No | `US` / `UK`, default `US` |\n| granularity | String | No | `week` only |\n\n**Response:** `data.context + data.items[]` for both single and batch requests.\n\nContext fields: `marketplace`, `site`, `requestedDate`, `resolvedDate`, `granularity`, `dataWindow.currentPeriod`, and `scoringSpec` (`id`, `version`, `scoreType`, `scoreRange`, `referenceScope`).\n\nEach item has `identity`, `status=ok|empty`, `marketProfile`, and `emptyReason`. `marketProfile` contains `marketCharacteristics`, `demandScale`, `top3Concentration`, `adActivity`, `top20OrganicEntryDifficulty`, `supplySaturation`, `brandStructure`, and `organicProductBenchmark`.\n\nUse returned scores only with `context.scoringSpec`. Each scored dimension exposes `supported`, `level`, `interpretation`, `calculationStatus`, `unsupportedReason`, and `levelEvidence.score.{value,direction}`; evaluate it independently and treat any explicit unavailable signal as a conclusion boundary. `marketCharacteristics.volatility` exposes type and mapping-confidence evidence. `marketCharacteristics.annualSeasonality` separately exposes classification, year-over-year correlation, eligible-pair count, peak-pattern detection, and peak periods. Do not merge the two classifications or invent peak periods. This endpoint returns deterministic weekly snapshot evidence, not trend, root cause, recommendations, or seller-private ABA-SQP conversion data.\n\nAn unmatched keyword returns `status=empty`, `marketProfile=null`, descriptive `emptyReason` text, zero consumed credits, and may return null resolved context / scoring spec. A subject-specific calculation error can currently return HTTP 500 for the entire batch; treat that as a service failure rather than an empty item, and do not automatically fan out the batch. Use returned `meta.creditsConsumed` / `meta.creditsConsumedExact`.\n\nThree-layer boundary: `keywords/detail` is the traceable data layer; `keywords/market-profile` is the stable deterministic metric layer; the Agent + skill layer combines evidence and produces confidence, explanations, limitations, and recommendations.\n\nMetric-first rule: use `market-profile` before `detail` for supported market judgments. Do not descend merely because a metric dimension has incomplete calculation coverage; both are source-related, so the missing metric input will usually remain missing. Descend only when a named Agent inference requires raw fields omitted by the metric contract, the metric endpoint is unavailable, or the user requests source evidence.\n\nBatch-first rule: once an endpoint is selected, prefer its batch form for all subjects sharing marketplace, date/range, granularity, window, filters, and sort context. Deduplicate while preserving order, chunk at 20, and use single calls only for one subject or incompatible contexts.\n\nCLI: `zoodata.py keyword-market-profile --keywords \"yoga mat,pilates mat\" --date 2026-06-29 --marketplace US`\n\n---\n\n## 13. /openapi/v2/keywords/trend\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| keyword | String | Conditional | One keyword; exactly one of `keyword` / `keywords` |\n| keywords | List\\<String\\> | Conditional | Batch of 1–20 keywords; preserves request order |\n| dateFrom | String | **Yes** | Start date `YYYY-MM-DD` |\n| dateTo | String | **Yes** | End date `YYYY-MM-DD`; prefer T-1 or earlier; maximum 93-day range |\n| marketplace | String | No | `US` / `UK`, default `US` |\n| granularity | String | No | `week` only |\n\n**Response:** `data.context + data.items[].series[]` for both single and batch requests.\n\nInterpretation note:\n- `keywords/trend` is a weekly time series. Align returned period boundaries before comparing it with SERP or ASIN observation endpoints; those interfaces are not interchangeable evidence even when all use `week`.\n\nEach item has `identity`, `status=ok|empty`, `series[]`, `emptyReason`, and nullable `errorCode` /\n`errorMessage`. The latter are auxiliary fields, not status enums. Series fields are\n`periodStartDate`, `periodEndDate`, `estimateSearchCount`, `abaRank`,\n`abaTop3ClickShareRate`, and `abaTop3ConversionShareRate`.\n\n---\n\n## 13b. /openapi/v2/keywords/trend-profile (metric layer)\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| keyword | String | Conditional | Exactly one of `keyword` / `keywords` |\n| keywords | String[] | Conditional | 1–20, mutually exclusive with `keyword` |\n| date | String | **Yes** | As-of date `YYYY-MM-DD` |\n| windowPeriods | Integer[] | **Yes** | 1–4 unique values from `4`, `8`, `12`, `26` |\n| marketplace | String | No | `US` / `UK`, default `US` |\n| granularity | String | No | `week` only |\n\n**Response:** `data.context + data.items[].rows[]`. Each keyword has one row per requested window. Rows return `status=ok|empty`, `rowContext`, `emptyReason`, and `trendProfile`. `status=ok` profiles expose guarded `searchDemand` and `abaRank` dimensions. Their `trendEvidence` values include an explicit direction plus slope and consistency evidence, so do not infer the server label from endpoint movement alone. Preserve null empty reasons without inventing one.\n\nUse this metric endpoint first for trend shape and volatility; call raw `keywords/trend` only when weekly points or omitted fields are required.\n\n---\n\n## 14. /openapi/v2/keywords/extends\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| query | String | **Yes** | Seed keyword |\n| marketplace | String | No | Marketplace code, default `US` |\n| page | Integer | No | default 1 |\n| pageSize | Integer | No | default 20, max 100 |\n| queryType | String | No | `phrase` / `fuzzy` (default `phrase`) |\n| sortBy | String | No | `relevanceScore` / `estimateSearchCount` / `abaRank` / `keyword` |\n| sortOrder | String | No | `asc` / `desc` |\n\n⚠️ Uses `query`, NOT `keyword`.\n⚠️ No date is required; the service uses the latest available weekly snapshot. A legacy `date` may be sent but is ignored.\n⚠️ Empty `data.rows[]` is a normal success case.\n\n**Response:** `data.context + data.query + data.queryType + data.rows[]`.\n\nEach row contains `matchData.{query,keyword,site,relevanceScore}` and `keywordSnapshot`.\n`keywordSnapshot.dataWindow.currentPeriod` provides the resolved weekly period; its metric families match\nthe current `keywords/detail` snapshot contract.\n\nDo not flatten the response back to legacy `term`, `seedKeyword`, or `estimateSearchCountWeekly` fields.\n\n---\n\n## 15. /openapi/v2/keywords/search-results\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| keyword | String | **Yes** | Keyword to inspect |\n| date | String | **Yes** | Snapshot lookup date `YYYY-MM-DD`; prefer T-1 or earlier |\n| granularity | String | No | `week` only |\n| marketplace | String | No | Marketplace code, default `US` |\n| page | Integer | No | default 1 |\n| pageSize | Integer | No | default 20, max 100 |\n| exploreTypes | Array\\<String\\> | No | `ORG` / `SP` / `SB` / `SBV` / `SPR` |\n| sortBy | String | No | `absolutePosition` / `estimateImpressionPoint` / `latestObservedAt` / `price` / `rating` / `ratingCount` / `recentSales` / `asin` / `title` |\n| sortOrder | String | No | `asc` / `desc` |\n\n⚠️ `day`, `month`, `lately_day`, and `lookbackDays` are unsupported. Use the returned weekly period boundaries instead of inferring a rolling window.\n⚠️ Use this endpoint as the primary source for \"what products are currently showing on the keyword SERP/page 1\" because it already returns listing-level product fields.\n⚠️ Do not replace it with `products/search` when the question is about observed Amazon keyword SERP composition or ordering.\n⚠️ When analyzing this endpoint, separate `exploreType` at least into `ORG` and sponsored placements instead of collapsing all rows together.\n\n**Response:** `data.context + data.identity + data.rows[]`.\n\nKey row fields: `latestObservedAt`, `exploreType`, `absolutePosition`, `pageIndex`, `pagePosition`, `asin`,\n`title`, `brand`, `price`, `currency`, `link`, `imageLink`, `rating`, `ratingCount`, `recentSales`,\n`hasVideo`, `estimateImpressionPoint`, `keywordTotalEstimateImpressionPoint`\n\nInterpretation rule:\n- `keywords/search-results` = observed keyword SERP snapshot\n- It can answer page-1 product mix, brand mix, ad vs organic composition, and visible price band questions\n- If you also use `products/search`, present it as a broader catalog supplement, not as the same thing\n\n---\n\n## 16. /openapi/v2/keywords/competitor-product-keywords\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| asin | String | **Yes** | Target ASIN |\n| date | String | **Yes** | Snapshot lookup date `YYYY-MM-DD`; prefer T-1 or earlier |\n| granularity | String | No | `week` only |\n| marketplace | String | No | Marketplace code, default `US` |\n| page | Integer | No | default 1 |\n| pageSize | Integer | No | default 20, max 100 |\n| exploreTypes | Array\\<String\\> | No | `ORG` / `SP` / `SB` / `SBV` / `SPR` |\n| keywordContains | String | No | Optional substring filter on returned keywords |\n| sortBy | String | No | `trafficShare` / `estimateImpressionPoint` / `absolutePosition` / `avgPosition` / `keywordEstimateSearchCount` / `keywordAbaRank` / `latestObservedAt` / `keyword` |\n| sortOrder | String | No | `asc` / `desc` |\n\n**Response:** `data.context + data.identity + data.rows[]`.\n\nKey row fields: `latestObservedAt`, `exploreType`, `absolutePosition`, `pageIndex`, `pagePosition`, `asin`,\n`keyword`, `estimateImpressionPoint`, `asinTotalEstimateImpressionPoint`, `avgPosition`,\n`daysCoverageRate`, `observationCount`, `keywordEstimateSearchCount`,\n`keywordEstimateSearchChangeCount`, `keywordEstimateSearchCountChangeRate`, `keywordAbaRank`,\n`keywordAbaRankChangeCount`, `trafficShare`\n\n⚠️ `day`, `month`, `lately_day`, and `lookbackDays` are unsupported; use the returned weekly period boundaries.\n⚠️ In skill workflows, this endpoint is a reverse-ASIN source endpoint, not a substitute for `keywords/search-results` when the question is about visible page-1 product composition.\n\n---\n\n## 17. /openapi/v2/keywords/product-traffic-terms\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| asin | String | **Yes** | Target ASIN |\n| date | String | **Yes** | Snapshot lookup date `YYYY-MM-DD`; prefer T-1 or earlier |\n| granularity | String | No | `week` only |\n| marketplace | String | No | Marketplace code, default `US` |\n| page | Integer | No | default 1 |\n| pageSize | Integer | No | default 20, max 100 |\n| exploreTypes | Array\\<String\\> | No | `ORG` / `SP` / `SB` / `SBV` / `SPR` |\n| keywordContains | String | No | Optional substring filter on returned keywords |\n| sortBy | String | No | `trafficShare` / `estimateImpressionPoint` / `absolutePosition` / `avgPosition` / `keywordEstimateSearchCount` / `keywordAbaRank` / `latestObservedAt` / `keyword` |\n| sortOrder | String | No | `asc` / `desc` |\n\n⚠️ Live validation showed the same item shape as `keywords/competitor-product-keywords`; do not assume\nthe semantic label implies a different wire schema.\n⚠️ `day`, `month`, `lately_day`, and `lookbackDays` are unsupported; use the returned weekly period boundaries.\n⚠️ In skill workflows, this endpoint is a reverse-ASIN source endpoint, not a substitute for `keywords/search-results` when the question is about visible page-1 product composition.\n\n**Response:** `data.context + data.identity + data.rows[]`.\n\nKey row fields: `latestObservedAt`, `exploreType`, `absolutePosition`, `pageIndex`, `pagePosition`, `asin`,\n`keyword`, `estimateImpressionPoint`, `asinTotalEstimateImpressionPoint`, `avgPosition`,\n`daysCoverageRate`, `observationCount`, `keywordEstimateSearchCount`,\n`keywordEstimateSearchChangeCount`, `keywordEstimateSearchCountChangeRate`, `keywordAbaRank`,\n`keywordAbaRankChangeCount`, `trafficShare`\n\n---\n\n## 18. /openapi/v2/keywords/product-traffic-terms-overview\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| asin | String | **Yes** | Target ASIN |\n| date | String | **Yes** | Lookup date `YYYY-MM-DD`; prefer T-1 or earlier; returns the latest weekly all-keyword impression traffic-change overview on or before this date |\n| marketplace | String | No | Marketplace code, default `US` |\n\n**Response:** Single overview object **or `null`**.\n\nPurpose:\n- Shows estimated impression traffic changes across all keywords under the ASIN versus the previous period\n- Current placement-level impression-point fields are paired with matching `*Prev` previous-period fields\n- Lists keywords newly entering ORG first three pages and keywords dropping out of ORG first three pages\n\nKey fields from live MCP response:\n`periodStartDate`, `periodEndDate`, `asin`, `site`, `organicImpressionPoint`,\n`sponsoredProductImpressionPoint`, `sponsoredBrandImpressionPoint`,\n`sponsoredBrandVideoImpressionPoint`, `sponsoredRecommendImpressionPoint`,\n`organicImpressionPointPrev`, `sponsoredProductImpressionPointPrev`,\n`sponsoredBrandImpressionPointPrev`, `sponsoredBrandVideoImpressionPointPrev`,\n`sponsoredRecommendImpressionPointPrev`, `first3PagesNewOrganicKeywords`,\n`first3PagesLostOrganicKeywords`.\n\n`*Prev` fields are previous-period baselines for the matching current impression-point fields. The legacy response returns only the current `periodStartDate` / `periodEndDate`; it does not return separate previous-period date boundaries. A `*Prev` field may be null or absent when no previous-period value is available.\n\n`first3PagesNewOrganicKeywords` and `first3PagesLostOrganicKeywords` items contain\n`keyword`, `pageIndex`, and `pagePosition`.\n\n`first3PagesNewOrganicKeywords` lists keywords newly entering ORG first three pages;\n`first3PagesLostOrganicKeywords` lists keywords that dropped out of ORG first three pages.\n\nLive validation source: MCP tool surface\n`openapi_v2_product_traffic_terms_overview`, request\n`{\"asin\":\"B01CGLCGRA\",\"date\":\"2026-06-29\",\"marketplace\":\"US\"}`.\n\n---\n\n## 19. /openapi/v2/keywords/product-traffic-terms-timeline\n\n| Parameter | Type | Required | Note |\n|-----------|------|----------|------|\n| asin | String | **Yes** | Target ASIN |\n| keyword | String | Conditional | One exact keyword; exactly one of `keyword` / `keywords` |\n| keywords | List\\<String\\> | Conditional | Batch of 1–20 exact keywords for the same ASIN |\n| dateFrom | String | **Yes** | Start date `YYYY-MM-DD` |\n| dateTo | String | **Yes** | End date `YYYY-MM-DD`; prefer T-1 or earlier; maximum 61-day range |\n| marketplace | String | No | Marketplace code, default `US` |\n| granularity | String | No | `week` only |\n\n**Response:** `data.context + data.items[].series[]` for both single and batch requests.\n\nEach item has `identity`, `status=ok|empty`, `series[]`, `emptyReason`, and nullable `errorCode` /\n`errorMessage`. The latter are auxiliary fields, not status enums. Each series point contains\n`date` plus nested `asinSnapshot`, `traffic`, `placement`,\n`keywordMetrics`, and `adActivity` groups.\n\n⚠️ Do not send `page`, `pageSize`, `sortBy`, or `sortOrder`. `day`, `month`, `lately_day`, and\n`lookbackDays` are unsupported.\n\nDiagnosis curves and events:\n- Price curve: `asinSnapshot.latestPrice`\n- BSR curve: `asinSnapshot.latestBsr`, `asinSnapshot.latestSubBsr`\n- Sales curve: `asinSnapshot.latestMonthlySaleCount`\n- Rating curve: `asinSnapshot.latestRating`, `asinSnapshot.latestRatingCount`\n- Traffic-estimate curve: `traffic.*` plus `placement.avgOrganicObservation` / `placement.avgAdObservation`\n- Keyword fields: use `keywordMetrics` only as supporting context for traffic-estimate changes\n- Listing events: changes in `asinSnapshot.latestTitle` / `asinSnapshot.latestMainImageLink`\n\nKey groups: product/listing/rank fields in `asinSnapshot`; ORG/SP/SB/SBV/SPR impression points in\n`traffic`; positions/pages/observation timestamps in `placement`; weekly search/ABA fields and\n`metricWindow` in `keywordMetrics`; observation/campaign/ad counts in `adActivity`.\n\n---\n\n## Shared Product Object (products/search, competitors & brand-detail sampleProducts)\n\nBoundary note:\n- `products/search` is a query against ZooData's product-database snapshot\n- It is useful for broader catalog analysis such as market winners, sales distribution, price bands, and variant concentration\n- It does NOT represent Amazon live keyword SERP ordering\n- Do not describe `products/search` output as \"Amazon search results\" or \"Amazon首页结果\" unless you are explicitly talking about the ZooData product database rather than the observed Amazon keyword SERP\n\n| Field | Type | Note |\n|-------|------|------|\n| asin | String | |\n| title | String | |\n| brand | String | |\n| price | Float | Top-level (unlike realtime) |\n| bsr | Integer | BSR rank (NOT `bsr` or `bestsellersRank`) |\n| monthlySalesFloor | Integer | Lower-bound monthly sales |\n| monthlyRevenueFloor | Float | Monthly revenue lower bound |\n| salesGrowthRate | Float | Growth rate |\n| rating | Float | 0-5 |\n| ratingCount | Integer | NOT `reviewCount` |\n| fbaFee | Float | |\n| sellerCount | Integer | |\n| variantCount | Integer | |\n| fulfillment | String | FBA/FBM/AMZ |\n| listingDate | String | |\n| buyBoxSellerName | String | |\n| categoryPath | List | Full category path root→leaf; always present — lets a keyword→category lookup resolve from the search row without a realtime call |\n| bsrCategory | String | BSR category name (root); fallback when `categoryPath` is absent |\n\nFile v1.1.9:references/reference.md\n\n# ZooData API Field Reference\n\n> Load this file only when you need exact field names or response structure.\n\n## ZooData Endpoint Field Reference\n\n> Shared field reference. This skill's workflows use ONLY the subcommands\n> listed in its SKILL.md; the endpoints below are documented for field-name /\n> response-structure lookup, not as a claim that this skill invokes all of them.\n\n| # | Endpoint | Purpose |\n|---|----------|---------|\n| 1 | `categories` | Category path lookup |\n| 2 | `markets/search` | Market size, competition metrics, new-product rate |\n| 3 | `products/search` | Product supply (100+ via pagination), brand/price drill |\n| 4 | `products/competitors` | Top competitor list |\n| 5 | `realtime/product` | Live product detail |\n| 6 | `reviews/analysis` | Consumer pain points, buying factors |\n| 7 | `products/price-band-overview` | Price-band opportunity overview |\n| 8 | `products/price-band-detail` | Per-band SKU/sales/brand/rating breakdown |\n| 9 | `products/brand-overview` | Brand count, CR10, top-brand avg price/rating |\n| 10 | `products/brand-detail` | Per-brand SKU/sales/revenue/share ranking |\n| 11 | `products/history` | 30-day price/BSR/sales trend |\n\nBase URL: `https://api.zoodata.ai/openapi/v2`\nAuth: `Bearer $ZOODATA_API_KEY`\nMethod: All POST with JSON body\nAll endpoints return: `{success, data, error, meta}` with `meta.creditsRemaining`\n\n---\n\n## 1. categories\n\n**Request:** (mutually exclusive modes)\n- No params → root categories\n- `categoryKeyword`: String → search by keyword\n- `categoryPath`: List<String> → exact path\n- `parentCategoryPath`: List<String> → child categories\n\n**Response:**\n| Field | Type | Used For |\n|-------|------|----------|\n| `categoryId` | string | Category ID |\n| `categoryName` | string | Category name |\n| `categoryPath` | list | Full path from root |\n| `hasChildren` | bool | Has subcategories |\n| `level` | int | Depth (1=root) |\n| `productCount` | int | Products in category |\n\n---\n\n## 2. markets/search\n\n**Key Request Params:**\n- `categoryPath`: List<String> (e.g. `[\"Pet Supplies\", \"Dogs\"]`)\n- `categoryKeyword`: String\n- `topN`: **String** (`\"10\"` not `10`)\n- `sampleType`: `by_sale_100` / `by_bsr_100` / `avg`\n- `pageSize`: Integer (max 20)\n\n**Key Response Fields:**\n| Field | Type | Used For |\n|-------|------|----------|\n| `totalSkuCount` | int | Market size |\n| `sampleAvgMonthlySales` | float | Demand level |\n| `sampleAvgMonthlyRevenue` | float | Market value |\n| `sampleAvgPrice` | float | Price benchmark |\n| `sampleAvgRating` | float | Quality benchmark |\n| `sampleBrandCount` | int | Brand diversity |\n| `sampleSellerCount` | int | Seller diversity |\n| `sampleFbaRate` | float | FBA adoption (decimal) |\n| `sampleNewSkuRate` | float | New entrant rate (decimal) |\n| `topSalesRate` | float | Product concentration (CR_topN) |\n| `topBrandSalesRate` | float | Brand concentration |\n| `topSellerSalesRate` | float | Seller concentration |\n| `sampleAPlusRate` | float | Margin benchmark |\n\n---\n\n## 3. products/search — Shared Product Object\n\n**Key Request Params:**\n- `keyword`, `categoryPath`, `keywordMatchType` (`mode` is a CLI-only preset — `zoodata.py` expands it into the filter pairs below client-side; it is NOT an API field and returns 422 if sent raw)\n- Filter pairs: `monthlySalesMin/Max`, `priceMin/Max`, `ratingMin/Max`, etc.\n- `pageSize` (max 20), `page`, `sortBy`, `sortOrder`\n- `includeBrands`, `excludeBrands`\n\n**Key Response Fields (per product):**\n| Field | Type | Used For |\n|-------|------|----------|\n| `asin` | string | Product ID |\n| `title` | string | Product name |\n| `brandName` | string | Brand |\n| `price` | float | Price |\n| `monthlySalesFloor` | int | Monthly sales (lower bound) |\n| `monthlyRevenueFloor` | float | Monthly revenue lower bound |\n| `rating` | float | Rating (0-5) |\n| `ratingCount` | int | Review count |\n| `bsr` | int | BSR (NOT `bestsellersRank`) |\n| `fbaFee` | float | FBA cost |\n| `sellerCount` | int | Sellers on listing |\n| `fulfillment` | string | FBA/FBM/AMZ |\n| `listingDate` | string | When listed |\n| `salesGrowthRate` | float | Growth rate |\n| `variantCount` | int | Variants |\n| `categoryPath` | list | Full category path (root→leaf); always present — used to self-heal a keyword→category lookup without a realtime call |\n| `bsrCategory` | string | BSR category name (root); fallback when `categoryPath` is unexpectedly absent |\n\n---\n\n## 4. products/competitors\n\nSame response as products/search. Different use: discovery by keyword/brand/asin.\nRequest params: `keyword`, `brand`, `asin`, `categoryPath`, `sortBy`, `pageSize`\n\n---\n\n## 5. realtime/product\n\n**Request:**\n- `asin`: String (required)\n- `marketplace`: String (US/UK/DE/FR/IT/ES/JP/CA/AU/IN/MX/BR, default US)\n\n**Response:**\n| Field | Type | Used For |\n|-------|------|----------|\n| `asin` | string | Product ID |\n| `title` | string | Full title |\n| `brandName` | string | Brand |\n| `rating` | float | Current rating |\n| `ratingCount` | int | Current review count |\n| `ratingBreakdown` | object | Star distribution {five_star: {percentage, count}, ...} |\n| `features` | list | Bullet points |\n| `description` | string | Product description |\n| `specifications` | object | Tech specs |\n| `variants` | list | All variants with dimensions |\n| `bestsellersRank` | list | BSR info [{category, rank}, ...] |\n| `buyboxWinner` | object | Buy Box: {price, fulfillment, seller} |\n| `images` | list | All image URLs |\n\n⚠️ Does NOT have: monthlySalesFloor, fbaFee, sellerCount\n\n---\n\n## 6. reviews/analysis\n\n**Request:**\n- `mode`: `\"asin\"` or `\"category\"`\n- `asins`: List<String> (when mode=asin)\n- `categoryPath`: String (when mode=category)\n- `period`: e.g. `\"1m\"` / `\"3m\"` / `\"6m\"` / `\"1y\"` / `\"2y\"`\n\n⚠️ `labelType` is **not** an API request parameter. The API returns all 11 dimensions in a single call. Filter by `labelType` client-side from the `consumerInsights` array.\n\n**labelType values (in response):** `scenarios`, `issues`, `positives`, `improvements`, `buyingFactors`, `painPoints`, `keywords`, `userProfiles`, `usageTimes`, `usageLocations`, `behaviors`\n\n**Response:**\n| Field | Type | Used For |\n|-------|------|----------|\n| `reviewCount` | int | Sample size |\n| `avgRating` | float | Overall satisfaction |\n| `sentimentDistribution` | object | Positive/neutral/negative ratio |\n| `consumerInsights` | list | Structured insights by dimension |\n| `topKeywords` | list | Trending terms |\n\n**InsightItem:** `{element, labelType, count, reviewRate, avgRating}`\n\n---\n\n## 6b. realtime/reviews\n\n**Request:**\n- `asin`: String (10 chars, required)\n- `marketplace`: String (US/UK only, default US)\n- `cursor`: String (pagination token; omit for first page)\n\n⚠️ Fixed 10 reviews/page; max 10 pages = **100 reviews** hard cap. 1 credit/page. Cursor-based pagination.\n\n**Response:**\n| Field | Type | Used For |\n|-------|------|----------|\n| `asin` | string | Product ID |\n| `reviews` | list | Array of RealtimeReview |\n| `nextCursor` | string\\|null | Next page token (null = end) |\n\n**RealtimeReview:** `reviewId`, `title`, `body`, `bodyHtml`, `rating`, `author`, `date` (ISO 8601 UTC), `verifiedPurchase`, `vineProgram`, `helpfulVoteCount`, `unhelpfulVoteCount`, `reviewCountry`, `images`, `link`, `isGlobalReview`\n\n**Use cases:** ASIN <50 reviews (fallback for `/reviews/analysis`), brand-new product without snapshot, freshest possible raw text. Feeds the local Map/Reduce toolkit (`zoodata.py reviews-raw / review-tag-prompt / review-reduce-prompt / review-aggregate`).\n\n---\n\n## 6c. reviews/search\n\n**Request:**\n- `asin`: String (required)\n- Optional filters: `ratingMin`/`ratingMax` (1-5), `verifiedOnly`, `vineOnly`, `helpfulVoteCountMin`, `dateStart`/`dateEnd` (YYYY-MM-DD)\n- `sortBy`: `recent` (default) / `rating` / `helpfulVoteCount`\n- `sortOrder`: `desc` (default) / `asc`\n- `page`: 1-indexed (default 1)\n- `pageSize`: 1-20 (default 10)\n\n**Response:** Array of `TaggedReview` — same fields as `RealtimeReview` + `tags[{labelType, element}]` (AI tags from offline pipeline).\n\n**Differs from realtime/reviews:** uses BigQuery daily snapshot (T+1 delay) but already has AI tags applied. Prefer `reviews/search` when snapshot exists; prefer `realtime/reviews` for live data or new products.\n\n---\n\n## 7. products/price-band-overview\n\n**Request:** Same params as products/search (keyword, category, filters)\n\n**Response:**\n| Field | Type | Used For |\n|-------|------|----------|\n| `sampleSkuCount` | int | Total products analyzed |\n| `sampleMedianPrice` | float | Median price point |\n| `hottestBand` | object | Highest sales share band |\n| `bestOpportunityBand` | object | Highest opportunity index band |\n\n**Band object:** `{bandIdx, bandLabel, sampleBandMinPrice, sampleBandMaxPrice, sampleSkuCount, sampleSalesRate, sampleBrandCount, sampleTop3BrandSalesRate, sampleAvgRating, sampleOpportunityIndex}`\n\n---\n\n## 8. products/price-band-detail\n\n**Response:**\n- `sampleSkuCount`, `sampleTotalMonthlySales`\n- `priceBands`: array of 5 band objects (same structure as above)\n\n---\n\n## 9. products/brand-overview\n\n**Response:**\n| Field | Type | Used For |\n|-------|------|----------|\n| `sampleBrandCount` | int | Total brands |\n| `sampleTop10BrandSalesRate` | float | CR10 concentration (top 10 brands) |\n| `sampleTop10AvgRating` | float | Top 10 brand avg rating |\n| `sampleTop10AvgPrice` | float | Top 10 brand avg price |\n\n---\n\n## 10. products/brand-detail\n\n**Response:**\n- `sampleSkuCount`, `sampleTotalMonthlySales`, `sampleBrandCount`\n- `brands`: array of brand objects\n\n**BrandStats:** `{brandName, sampleSkuCount, sampleGroupMonthlySales, sampleGroupMonthlyRevenue, sampleSalesRate, sampleAvgPrice, minPrice, maxPrice, sampleAvgRating, sampleAvgRatingCount, sampleProducts}`\n\n**sampleProducts:** List of Product objects for this brand within the sample. Each product contains the full Shared Product Object fields (asin, title, price, bsr, monthlySalesFloor, rating, ratingCount, fulfillment, etc). This enables brand-level product matrix analysis without a separate products/search call.\n\n---\n\n## 11. products/history\n\n**Request:**\n- `asin`: String (required) — Single ASIN (one per call, NOT an array)\n- `startDate`: String \"YYYY-MM-DD\" (required)\n- `endDate`: String \"YYYY-MM-DD\" (required)\n- `marketplace`: String (optional, default \"US\")\n⚠️ `asin` is a **single string** — NOT an array. For multiple ASINs, make separate calls.\n⚠️ Does NOT support `page`/`pageSize` — returns full date range in one response.\n⚠️ Does NOT accept `dateRange` — must use startDate + endDate.\n\n**Response (single time series object, NOT an array of snapshots):**\n| Field | Type | Used For |\n|-------|------|----------|\n| `asin` | string | Product ASIN |\n| `timestamps` | List\\<string\\> | Dates (YYYY-MM-DD) |\n| `price` | List\\<float\\> | Price on each date |\n| `bsr` | List\\<int\\> | BSR on each date |\n| `subBsr` | List\\<int\\> | Sub-category BSR |\n| `monthlySalesFloor` | List\\<int\\> | Monthly sales lower bound |\n| `rating` | List\\<float\\> | Rating on each date |\n| `ratingCount` | List\\<int\\> | Review count on each date |\n| `sellerCount` | List\\<int\\> | Seller count |\n| `title` | List\\<ChangeLog\\> | Title changes `{date, value}` |\n| `imageUrl` | List\\<ChangeLog\\> | Main image changes `{date, value}` |\n| `bestSeller` | List\\<ChangeLog\\> | Best Seller badge `{date, value}` |\n| `amazonChoice` | List\\<ChangeLog\\> | Amazon's Choice badge `{date, value}` |\n| `newRelease` | List\\<ChangeLog\\> | New Release badge `{date, value}` |\n| `aPlus` | List\\<ChangeLog\\> | A+ content status `{date, value}` |\n| `inventoryStatus` | List\\<ChangeLog\\> | Stock status `{date, value}` |\n| `currency` | string | e.g. \"USD\" |\n\n---\n\n## Cross-Validation Matrix\n\n| Data Point | Primary Source | Validation Source |\n|-----------|---------------|-------------------|\n| Market size | markets/search | products/search (total count) |\n| Brand concentration | brand-overview (sampleTop10BrandSalesRate) | markets/search (topBrandSalesRate) |\n| Price distribution | price-band-detail | products/search (price field) |\n| Competition level | markets (topSalesRate) | brand-detail (top brand shares) |\n| Consumer demand | reviews/analysis | products (sales + growth) |\n| Avg rating quality | markets (sampleAvgRating) | brand-overview (sampleTop10AvgRating) |\n\nFile v1.1.9:skill-card.md\n\n## Description:\n\nZooData is an API endpoint reference and bundled client for agent access to ZooData commerce and keyword-intelligence data, including endpoint inputs, response fields, authentication, credit tracking, and local review-toolkit behavior.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[apiclaw](https://clawhub.ai/user/apiclaw)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to understand and call ZooData endpoints for Amazon product, market, competitor, review, price-band, brand, history, and keyword-intelligence lookups. It is suited for data-backed commerce analysis workflows that require endpoint selection, parameter guidance, API-key authentication, and credit-aware execution.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Live API calls use a user-provided ZooData API key and may spend account credits.\n\nMitigation: Configure credentials intentionally, prefer ZOODATA_API_KEY for short sessions, and ask the agent to estimate and confirm cost before broad or ambiguous multi-call scans.\n\nRisk: Persisted credentials in ~/.zoodata/config.json could be exposed if local file permissions are too broad.\n\nMitigation: Keep the local credential file private and use restrictive directory and file permissions when persistent storage is needed.\n\nRisk: Endpoint parameters and live API field names may change, causing failed calls or misleading analysis if stale schemas are used.\n\nMitigation: Use the bundled references and current ZooData OpenAPI specification for endpoint selection, supported parameters, and response-field interpretation.\n\n## Reference(s):\n\n- [ZooData skill page](https://clawhub.ai/apiclaw/skills/zoodata)\n- [ZooData API keys](https://zoodata.ai/en/api-keys)\n- [ZooData OpenAPI specification](https://zoodata.ai/api/v1/openapi-spec)\n- [ZooData Skills homepage](https://github.com/SerendipityOneInc/ZooData-Skills)\n- [CLI contract](references/cli-contract.md)\n- [OpenAPI reference](references/openapi-reference.md)\n- [ZooData API field reference](references/reference.md)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Code, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown guidance with inline shell commands and JSON API examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires ZOODATA_API_KEY for live API calls; each API call may consume ZooData account credits.]\n\n## Skill Version(s):\n\n1.1.9 (source: server release metadata and SKILL.md frontmatter)\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.8: 8 files, 71079 bytes\n\nFiles: README.md (4462b), references/cli-contract.md (8636b), references/openapi-reference.md (32537b), references/reference.md (12264b), scripts/zoodata.py (175180b), skill-card.md (2541b), SKILL.md (35269b), _meta.json (126b)\n\nFile v1.1.8:SKILL.md\n\n---\nname: zoodata\ndescription: >\n  API endpoint reference for the ZooData data platform. Provides the 12\n  commerce endpoints plus 10 keyword intelligence endpoints (categories,\n  markets, products, competitors, realtime ASIN, AI review analysis, raw\n  reviews, price band, brand, history, keyword detail/trend/extends/search\n  results/market profile/product traffic/competitor keywords, traffic overview/timeline),\n  their inputs/outputs,\n  parameter quirks, Quick Start (auth, base URL), how credits are tracked\n  (meta.creditsConsumed field), and the Local Review Toolkit (Map/Reduce\n  for raw reviews).\n  Use when the user asks about the API itself — which endpoints exist,\n  how to call them, field schemas, parameter quirks, how to authenticate,\n  how credit consumption is reported, or how the Local Review Toolkit works.\n  Use when user asks: what endpoints does ZooData have, how do I call\n  /products/search, fields returned by reviews/analysis, how to check\n  credit usage, how the Local Review Toolkit works, how to get started.\n  Requires ZOODATA_API_KEY.\nmetadata:\n  version: \"1.1.8\"\n  author: SerendipityOneInc\n  homepage: https://github.com/SerendipityOneInc/ZooData-Skills\n  openclaw: {\"requires\": {\"env\": [\"ZOODATA_API_KEY\"]}, \"primaryEnv\": \"ZOODATA_API_KEY\"}\n---\n\n> **📋 Live API Reference**: Field names and parameters may change. If you encounter field errors,\n> check the latest OpenAPI spec at https://zoodata.ai/api/v1/openapi-spec for current field definitions.\n> Keyword exception: the observation endpoints currently support `granularity=week` only. Do not\n> reintroduce `day`, `month`, `lately_day`, or `lookbackDays` from a stale generated schema.\n\n# ZooData — Commerce Data Infrastructure for AI Agents\n\n200M+ Amazon products. 22 endpoints. One API key.\n\n## Quick Start\n1. Get key: [zoodata.ai/api-keys](https://zoodata.ai/en/api-keys) (1,000 free credits)\n2. `export ZOODATA_API_KEY='hms_live_xxx'`\n3. Base URL: `https://api.zoodata.ai/openapi/v2` — all POST with JSON body\n4. Auth: `Authorization: Bearer YOUR_API_KEY`\n5. New keys need 3-5s to activate. If 403, wait and retry.\n\n## Capabilities & Data Flow\n\n- **Network**: only `https://api.zoodata.ai` (Bearer `ZOODATA_API_KEY`). Setting `ZOODATA_BASE_URL` to an untrusted host (anything other than `api.zoodata.ai` / `*.zoodata.ai` / localhost) makes the CLI **refuse the request and withhold the key** — the Bearer token is never sent to an untrusted host.\n- **Execution**: bundled shared ZooData CLI `{skill_base_dir}/scripts/zoodata.py` (Python 3, stdlib-only). This data-layer reference skill allows the complete literal subcommand surface exposed by the bundled client's current top-level help.\n- **Local files**: none by default; reads `~/.zoodata/config.json` and, only when no new credential is configured, the legacy `~/.apiclaw/config.json` credential store; the Local Review Toolkit uses a temporary `/tmp/review_<ASIN>_<timestamp>/` working dir during the review fallback.\n- **Sent to the API**: keywords, category paths, ASINs, marketplace/date and numeric filter values only. **Never sent**: budget, experience level, risk tolerance, or any other user-profile text — profile inputs map client-side to numeric filters.\n- **Credits**: every API call consumes account credits. For broad or ambiguous requests, state the estimated credit cost and confirm with the user before running multi-call scans.\n\n## Shared CLI contract\n\nBefore selecting or invoking a bundled CLI command, read and apply `references/cli-contract.md`; reapply it after every result. It is the local source of truth for invocation, command identity, execution-environment permission handling, composite reuse, exit-status handling, authoritative transport status, retries, terminal interface failures, and partial results.\n\n### Local Interface Failure Output\n\nFor this API-reference skill, a terminal interface failure must produce one concise localized notice stating that the ZooData API lookup could not be completed, followed by the succeeded and failed endpoint identifiers. Do not continue into endpoint guidance, schema interpretation, or another API call. Do not expose control tokens or internal retry logs unless the user requests diagnostics.\n\n## ⚠️ Critical API Pitfalls (ALL skills must follow)\n1. **Commerce product/market search using a broad query** → resolve and lock `categoryPath` before interpreting category-sensitive product, market, competitor, brand, or price-band results. An explicitly labeled `products/search` category probe may run without a locked category only to resolve that category. Do **not** apply this rule to `/openapi/v2/keywords/*` Keyword Intelligence endpoints: their `keyword` / `query` inputs are Amazon search queries and do not require `categoryPath`.\n2. **Brand/price-band queries MUST include --category** to avoid cross-category contamination\n3. **Revenue** = `sampleAvgMonthlyRevenue` directly. **NEVER** calculate avgPrice × totalSales (overestimates 30-70%)\n4. **Sales** = `monthlySalesFloor` (lower bound). Fallback: 300,000 / BSR^0.65, tag as 🔍\n5. **Use API fields directly**: `sampleOpportunityIndex`, `sampleTop10BrandSalesRate` — never reinvent\n6. **reviews/analysis** needs 50+ reviews. Fallback chain when sample is insufficient:\n   1. Lightweight: `realtime/product` → `ratingBreakdown` (star distribution only, no themes)\n   2. Full 11-dim insights: `realtime/reviews` (raw text, up to 100) + local Map/Reduce via the\n      Local Review Toolkit below — see \"Local Review Toolkit\" section\n7. **Aggregation endpoints** (price-band, brand) without categoryPath produce severely distorted data\n8. **Price-band and brand endpoints only accept `keyword`** (not categoryPath) — cross-validate returned products\n9. **`mode` is CLI-local, NOT an API parameter** → `zoodata.py` expands `--mode` client-side into the filter sets in `PRODUCT_MODES` (`{skill_base_dir}/scripts/zoodata.py`, 13 presets) before the request; sending `mode` raw → 422\n10. **CLI filter flags ≠ API field names** → `--sales-min` → `monthlySalesMin`; `--ratings-max` (review count) → `ratingCountMax`, **not** `ratingMax` (a different valid field — max star rating — that returns wrong results silently, no 422). Pass `categoryPath` as a JSON array (`[\"Electronics\"]`), never a string. Unknown fields (`salesMin`, `ratingsMax`, …) → 422\n\n## On Missing Key (no credentials configured)\n\n**BEFORE calling any endpoint**, verify credentials are configured. The reliable check is `python {skill_base_dir}/scripts/zoodata.py check` — credentials-only by default, no endpoint calls and no credit usage; exits non-zero if no key is found in env vars OR config files. A `[ -z \"$ZOODATA_API_KEY\" ]` test alone is NOT sufficient — a user may have only `~/.zoodata/config.json` set.\n\nWhen no key is found through any mechanism:\n\n1. **STOP.** Do not run the workflow. Do not call `zoodata.py` (you'll just get the same credential error and burn tokens).\n2. **Do NOT fall back to a \"partial analysis from training data\" / \"industry common-sense headlines\" / \"for reference only\" preview.** Your training data is stale, has no per-ASIN granularity, and presenting it as analysis — even disclaimed — misrepresents what this skill produces. The deliverable is data-backed; without data, there is no deliverable.\n3. **Tell the user, in their language**, all three of:\n   - \"`ZOODATA_API_KEY` is not set — I need this to run the analysis.\"\n   - **Get a free key** (1,000 credits, no credit card): https://zoodata.ai/en/api-keys\n   - **Configure** via one of:\n     - `export ZOODATA_API_KEY='hms_live_xxx'` (session only)\n     - `mkdir -p ~/.zoodata && echo '{\"api_key\":\"hms_live_xxx\"}' > ~/.zoodata/config.json` (persistent)\n4. **Optionally** state in **one sentence** what the workflow will produce once the key is configured (deliverable shape only — no numbers, no market color, no \"common sense\" preview).\n\n## On 401 Invalid Key\n\nWhen `zoodata.py` returns a structured error with `_transport.status=401`,\n`error.status=401`, and `error.message=\"API Key invalid or expired\"`:\n\n1. **STOP further endpoint calls immediately.** Do not retry — a rejected key won't be accepted on a second try; every subsequent call will return 401 too.\n2. **Keep the selected credential authoritative.** Do not inspect, compare, export, or switch to a lower-priority legacy credential after rejection. A legacy credential may be selected only when neither new source is configured; trying another endpoint or asking to continue does not change this precedence.\n3. **Report to the user**:\n   - The selected ZooData credential was rejected (likely invalid, revoked, or expired)\n   - If any partial findings were collected before the failure, show them and mark as partial\n   - Fix at https://zoodata.ai/en/api-keys (verify the key, regenerate if needed)\n4. **Do not fabricate or guess** the data the failed calls would have returned. This includes \"training-data fallback\" / \"industry common-sense\" headlines disguised as preview — those are fabrications.\n\n## On 402 Credit Exhausted\n\nWhen `zoodata.py` returns a structured error with `_transport.status=402`,\n`error.status=402`, and `error.message=\"API quota exhausted or subscription expired\"`:\n\n1. **STOP further endpoint calls immediately.** Do not retry. Do not switch endpoints as a workaround — 402 is account-level (key/subscription), not endpoint-level.\n2. **Report to the user** with all four of:\n   - Which step in the workflow was reached (e.g. \"Completed step 3/5: brand analysis\")\n   - Partial findings already collected (show the actual data, not just a list of completed steps)\n   - Returned credit metadata when available; if it is absent, say it was not returned rather than estimating it\n   - Top-up link: https://zoodata.ai/en/pricing\n3. **Do not fabricate or guess** the missing data to \"complete\" the report. Mark partial findings explicitly as partial. **No \"training-data fallback\" / \"industry common-sense\" filler** — substituting public-knowledge prose for missing endpoint data is still fabrication.\n\n## On 422 Validation Error\n\nFor every parsed HTTP response from `zoodata.py`, treat `_transport.status` as the authoritative outer status; response-body and nested status-like fields do not override it. When the CLI returns HTTP 422 / `VALIDATION_ERROR`, read the preserved structured server error on stdout, including its message/details and `_query.params`. Do not retry the unchanged request. Correct the named fields first; the CLI exits non-zero while preserving the server error fields for the calling agent. Keyword endpoints that expose granularity currently accept `week` only; do not send `day`, `month`, `lately_day`, or `lookbackDays`.\n\n## 22 Endpoints\n\n| # | Endpoint | Purpose | Key Output |\n|---|----------|---------|------------|\n| 1 | `categories` | Browse/search category tree | categoryPath, productCount |\n| 2 | `markets/search` | Market-level metrics | sampleAvgMonthlySales, sampleAvgPrice, topSalesRate, sampleNewSkuRate |\n| 3 | `products/search` | Product search (20+ filter fields) | asin, price, monthlySalesFloor, rating, ratingCount, fbaFee |\n| 4 | `products/competitors` | Competitor discovery | same fields as products/search |\n| 5 | `realtime/product` | Live ASIN detail | rating, features, bestsellersRank[], buyboxWinner.price, variants |\n| 6 | `reviews/analysis` | AI review insights (11 dims) | sentimentDistribution, consumerInsights, topKeywords |\n| 7 | `realtime/reviews` | Live raw review text (cursor paginated, max 100) | reviews[], nextCursor — feeds Local Review Toolkit |\n| 8 | `products/price-band-overview` | Price band summary | hottestBand, bestOpportunityBand, sampleOpportunityIndex |\n| 9 | `products/price-band-detail` | Full 5-band distribution | priceBands[] with sales, brands, ratings per band |\n| 10 | `products/brand-overview` | Brand concentration | sampleTop10BrandSalesRate (CR10), sampleBrandCount |\n| 11 | `products/brand-detail` | Per-brand breakdown | brands[] with sales, revenue, sampleProducts |\n| 12 | `products/history` | Time series (single ASIN per call) | timestamps[], price[], bsr[], monthlySalesFloor[], rating[], ratingCount[], sellerCount[], title/imageUrl/bestSeller/newRelease/aPlus/inventoryStatus changelogs |\n| 13 | `/openapi/v2/keywords/detail` | Keyword summary from the nearest available weekly snapshot | `data.context + data.items[].snapshotData` with `estimateSearchCount`, `abaRank`, market/SKU/ad fields |\n| 14 | `/openapi/v2/keywords/market-profile` | Multidimensional weekly keyword profile | demand scale, Top3 concentration, ad activity, organic-entry difficulty, saturation, brand structure, organic benchmark, coverage |\n| 15 | `/openapi/v2/keywords/trend` | Weekly keyword time series | `data.context + data.items[].series[]` with search count, ABA rank, Top3 shares, period bounds |\n| 15b | `/openapi/v2/keywords/trend-profile` | Server-calculated trend profile over fixed weekly windows | trend shape, volatility, normalized slope, direction consistency, ABA-rank evidence |\n| 16 | `/openapi/v2/keywords/extends` | Keyword expansion / long-tail discovery | `data.context + data.rows[].{matchData,keywordSnapshot}`; may return empty `rows[]` |\n| 17 | `/openapi/v2/keywords/search-results` | Weekly keyword SERP snapshot | `data.context + data.identity + data.rows[]` with placement, product, and impression fields |\n| 18 | `/openapi/v2/keywords/competitor-product-keywords` | Keyword set where an ASIN appears as a competitor | `data.context + data.identity + data.rows[]` with keyword, position, demand, and traffic share |\n| 19 | `/openapi/v2/keywords/product-traffic-terms` | Traffic-driving keywords for an ASIN | same response shape as competitor-product-keywords |\n| 20 | `/openapi/v2/keywords/product-traffic-terms-overview` | Weekly ASIN all-keyword traffic-change overview | current vs previous-period placement-level impression points, ORG first-3-page keyword entries/exits |\n| 21 | `/openapi/v2/keywords/product-traffic-terms-timeline` | ASIN + keyword weekly timeline | `data.context + data.items[].series[]` with nested ASIN, traffic, placement, keyword, and ad groups |\n\n## Known Quirks\n- `topN`, `listingAge`, `newProductPeriod` are **strings** (`\"10\"` not `10`)\n- Many search/list endpoints return `.data` as an **array** — use `.data[0]` for the first record. But some commands may return non-array payloads inside `data`, so inspect the actual response shape before indexing.\n- `ratingCount` not `reviewCount` everywhere\n- `bsr` (int) in products vs `bestsellersRank` (array) in realtime\n- `buyboxWinner.price` — NOT top-level `price` in realtime\n- `realtime/product` does NOT return: monthlySalesFloor, fbaFee, sellerCount\n- `realtime/product` cold-start: first call for an uncached ASIN may return `success: true` with an EMPTY `data` (`asin: \"\"`) while the live fetch warms up — retry once after a few seconds before concluding \"no data\" (still billed 1 credit per call)\n- `reviewCountMin/Max` filters currently broken (API-56)\n- `reviews/analysis` may 500 for certain ASINs (API-58) — retry different ASIN\n- Rate limit: 100 req/min, 10 req/sec burst\n- `categories` uses `categoryKeyword` (not `keyword`) and `parentCategoryPath` (not `parentCategoryName`)\n- `reviews/analysis`: `mode` required (\"asin\"/\"category\"), use `asins` (plural array) not `asin`\n- `realtime/reviews`: returns 10 reviews/page fixed (no `pageSize` param); 1 credit/page; cursor-paginated; hard cap = 100 reviews (10 pages); supports `marketplace` US/UK only\n- `keywords/detail` accepts exactly one of `keyword` / `keywords[]` (max 20), resolves `date` to the nearest available weekly snapshot, and returns input-ordered `data.items[]`; an unmatched item has `status=empty`, not top-level `data: null`\n- `keywords/market-profile` accepts one of `keyword` / `keywords[]` (max 20), requires `date`, supports weekly granularity only, and returns input-ordered `data.items[]` with `status=ok|empty`. `emptyReason` is descriptive no-result text, not an enum. A subject-specific calculation failure can return HTTP 500 for the whole batch.\n- `keywords/trend-profile` accepts one of `keyword` / `keywords[]` (max 20), requires `date` and 1–4 unique `windowPeriods` selected from 4/8/12/26, and supports weekly granularity only.\n- `keywords/extends` requires `query` (not `keyword`), uses the latest available weekly snapshot, supports `queryType` = `phrase` or `fuzzy`, and may legitimately return empty `data.rows[]`; legacy `date` is optional and ignored\n- All keyword endpoints that expose `granularity` currently support `week` only. `day`, `month`, `lately_day`, and `lookbackDays` are unsupported. Use returned period boundaries instead of inferring a rolling window.\n- Keyword endpoints are keyword-query workflows; for inputs named `keyword` or `query`, use the Amazon search query / keyword phrase being analyzed\n- For keyword endpoints that require `date` or `dateTo`, prefer T-1 or earlier and avoid the current date unless the user explicitly asks for today's lookup\n- `keywords/search-results` requires `date` + `keyword`; `exploreTypes` values are `ORG`, `SP`, `SB`, `SBV`, `SPR`\n- `keywords/competitor-product-keywords` and `keywords/product-traffic-terms` require `date` + `asin`; both currently return the same live item shape, including `trafficShare`\n- `keywords/product-traffic-terms-overview` requires `date` + `asin`; it returns the latest weekly overview of all keyword impression traffic changes under that ASIN at or before the date, compared with the previous period\n- `keywords/product-traffic-terms-timeline` requires `asin` + exactly one of `keyword` / `keywords[]` + `dateFrom` + `dateTo`; the date range cannot exceed 61 days and the series request has no pagination or sort parameters\n- `keywords/search-results` is the default source for explaining what products currently appear on a keyword SERP because it already returns listing-level product fields\n- `products/search` is a broader ZooData product-database query and must not be presented as Amazon live keyword SERP ordering\n\n## Keyword Intelligence Endpoints\n\nThese ten endpoints fill the gap between raw\ncatalog data and search-demand/search-visibility intelligence.\n\nKeyword value boundary:\n- Keyword endpoints provide estimated search, visibility, rank, traffic-share, and impression-point signals\n- They do not provide a seller's first-party ABA Search Query Performance funnel by themselves\n- Treat keyword value, profitability, and conversion potential as directional unless the user supplies ABA-SQP impressions, clicks, cart adds, purchases, click share, purchase share, and conversion rate\n- Seller-artifact acquisition, stage selection, field interpretation, and user-facing output policy belong to the `amazon-keyword-traffic-analysis` skill. This API reference does not prescribe a blanket caveat or one seller view for every subject.\n\n### `/openapi/v2/keywords/detail`\n- Input: exactly one of `keyword` / `keywords[]` (1–20), required `date`, optional `marketplace`, `granularity=week` only\n- Data window: resolves the requested `date` to the nearest available weekly snapshot at or before that date\n- Date rule: prefer T-1 or earlier for `date`; avoid current-date lookup unless explicitly requested\n- Response shape: `data.context + data.items[]`, preserving request order\n- Item fields: `identity`, `status=ok|empty`, `snapshotData`, `emptyReason`, nullable `errorCode`, nullable `errorMessage`\n- `snapshotData` fields include `estimateSearchCount`, `abaRank`, Top3 click/conversion shares,\n  `marketCharacteristics`, `totalSkuCount`, SKU/brand/title coverage, organic/ad counts, and Top48 benchmarks\n- Do not read legacy `estimateSearchCountWeekly`, `totalSkuCnt`, or top-level `data:null`\n\n### `/openapi/v2/keywords/market-profile` (metric layer)\n- Availability: standard production endpoint under the documented base URL\n- Input: exactly one of `keyword` or `keywords[]` (1–20), required `date`, optional `marketplace`, `granularity=week` only\n- Response shape: `data.context + data.items[]`, preserving request order\n- Context fields: `requestedDate`, `resolvedDate`, `dataWindow.currentPeriod`, `scoringSpec`, marketplace/site/granularity\n- Item fields: `identity`, `status=ok|empty`, `marketProfile`, `emptyReason`\n- `marketProfile` dimensions: `marketCharacteristics`, `demandScale`, `top3Concentration`, `adActivity`, `top20OrganicEntryDifficulty`, `supplySaturation`, `brandStructure`, `organicProductBenchmark`\n- Interpret scores only with `context.scoringSpec` (`id`, `version`, `scoreType`, `scoreRange`, `referenceScope`). Scored dimensions expose `supported`, `calculationStatus`, `unsupportedReason`, `level`, `interpretation`, and `levelEvidence.score.{value,direction}`. There is no aggregate coverage object.\n- `marketCharacteristics.volatility` and `marketCharacteristics.annualSeasonality` are independent evidence objects. Do not collapse their classifications, let one override the other, or invent peak periods from an empty list.\n- Unmatched keywords return `status=empty`, `marketProfile=null`, and a descriptive `emptyReason`; resolved context and `scoringSpec` may be null\n- A subject-specific calculation failure can currently produce HTTP 500 for the whole batch. Treat it as a service failure, not an item-level `empty` result; do not automatically fan out all subjects into single calls.\n- Three-layer boundary: use data-layer `keywords/detail` for source snapshot fields, metric-layer `keywords/market-profile` for stable deterministic profile objects, and the Agent + skill layer for evidence composition, confidence, explanations, limitations, and actions\n- Metric-first access: call the matching metric before its source data endpoint. Descend only when the Agent needs an indicator or evidence grain omitted by the metric contract, the metric endpoint is unavailable and transparent data-based calculation is valid, no metric exists, or raw evidence is explicitly requested. Incomplete metric calculation coverage is a conclusion limit—not by itself a reason to call same-source data.\n- Batch-first execution: after selecting the endpoint, collect all subjects with identical non-subject context and prefer its batch contract over repeated single calls. Deduplicate case-insensitively, preserve order, chunk compatible sets at the endpoint limit (20 for current keyword batches), and merge results back into global input order. Batch support never justifies an extra cross-layer call.\n\n### `/openapi/v2/keywords/trend`\n- Input: exactly one of `keyword` / `keywords[]` (1–20), required `dateFrom` / `dateTo`, optional `marketplace`, `granularity=week` only; maximum 93-day range\n- Data window: weekly-granularity points across the requested date range\n- Date rule: prefer T-1 or earlier for `dateTo`; avoid current-date lookup unless explicitly requested\n- Response shape: `data.context + data.items[].series[]`, preserving request order\n- Item fields: `identity`, `status=ok|empty`, `series[]`, `emptyReason`, nullable `errorCode`, nullable `errorMessage`\n- Series fields: `periodStartDate`, `periodEndDate`, `estimateSearchCount`, `abaRank`,\n  `abaTop3ClickShareRate`, `abaTop3ConversionShareRate`\n\n### `/openapi/v2/keywords/trend-profile` (metric layer)\n- Input: exactly one of `keyword` / `keywords[]` (1–20), required `date`, required unique `windowPeriods[]` selected from 4/8/12/26, optional `marketplace`, `granularity=week` only\n- Response: `data.context + data.items[].rows[]`; every requested window returns one row with `rowContext`, `status=ok|empty`, `emptyReason`, and `trendProfile`\n- Available profiles contain independently guarded `searchDemand` and `abaRank` dimensions with `trend`, `trendPattern`, and `{value,direction}` entries under `trendEvidence`\n- Evidence includes first/last/change values, normalized slope, direction consistency, aligned/eligible period counts, plus demand volatility/window position or ABA best/worst rank\n- Use this metric endpoint before raw `keywords/trend` for trend-shape and volatility judgments. Descend only for required weekly points or fields omitted from the profile.\n- Preserve null empty reasons rather than inventing one. Billing is per keyword with at least one `status=ok` window; use returned credit metadata.\n\n### `/openapi/v2/keywords/extends`\n- Input: required `query`; optional `marketplace`, `page`, `pageSize`, `queryType`, `sortBy`, `sortOrder`; no date is required\n- Important quirk: seed field is `query`, not `keyword`; `queryType` supports `phrase` and `fuzzy`\n- Data window: latest available weekly snapshot; a legacy `date` may be sent but is ignored\n- Response shape: `data.context + data.query + data.queryType + data.rows[]`\n- Row fields: `matchData.{query,keyword,site,relevanceScore}` and `keywordSnapshot`, whose\n  `dataWindow.currentPeriod` and snapshot metrics use the same current field families as `keywords/detail`\n- Do not flatten rows to legacy `term`, `seedKeyword`, or `estimateSearchCountWeekly`; empty `rows[]` is normal\n\n### `/openapi/v2/keywords/search-results`\n- Input: required `keyword` / `date`, `granularity=week` only; optional `marketplace`, `page`, `pageSize`, `exploreTypes`, `sortBy`, `sortOrder`\n- Do not send `lookbackDays`; `day`, `month`, and `lately_day` are unsupported\n- Data window: latest available weekly period at or before the requested date; use the returned period boundaries\n- Date rule: prefer T-1 or earlier for `date`; avoid current-date lookup unless explicitly requested\n- Response shape: `data.context + data.identity + data.rows[]`\n- Row fields include `latestObservedAt`, `exploreType`, `absolutePosition`, `pageIndex`,\n  `pagePosition`, `asin`, `title`, `brand`, `price`, `currency`, `link`, `imageLink`, `rating`,\n  `ratingCount`, `recentSales`, `hasVideo`, `estimateImpressionPoint`,\n  `keywordTotalEstimateImpressionPoint`\n- Interpretation rule: use this endpoint first for \"what is on page 1 / what products dominate this keyword / what does the SERP look like\"\n- Do not substitute `products/search` when the question is about observed keyword SERP composition or ordering\n\n### `/openapi/v2/keywords/competitor-product-keywords`\n- Input: required `asin` / `date`, `granularity=week` only; optional `marketplace`, `page`, `pageSize`, `exploreTypes`,\n  `keywordContains`, `sortBy`, `sortOrder`\n- Do not send `lookbackDays`; `day`, `month`, and `lately_day` are unsupported; use returned weekly period boundaries\n- Date rule: prefer T-1 or earlier for `date`; avoid current-date lookup unless explicitly requested\n- Response shape: `data.context + data.identity + data.rows[]`\n- Row fields include `latestObservedAt`, `exploreType`, `absolutePosition`, `pageIndex`,\n  `pagePosition`, `asin`, `keyword`, `estimateImpressionPoint`, `asinTotalEstimateImpressionPoint`,\n  `avgPosition`, `daysCoverageRate`, `observationCount`, `keywordEstimateSearchCount`,\n  `keywordEstimateSearchChangeCount`, `keywordEstimateSearchCountChangeRate`, `keywordAbaRank`,\n  `keywordAbaRankChangeCount`, `trafficShare`\n\n### `/openapi/v2/keywords/product-traffic-terms`\n- Input: same request shape as `keywords/competitor-product-keywords`\n- Data window: weekly period selected by `date` + `granularity=week`; use returned period boundaries\n- Date rule: prefer T-1 or earlier for `date`; avoid current-date lookup unless explicitly requested\n- Response shape: `data.context + data.identity + data.rows[]`\n- Row fields include `latestObservedAt`, `exploreType`, `absolutePosition`, `pageIndex`,\n  `pagePosition`, `asin`, `keyword`, `estimateImpressionPoint`, `asinTotalEstimateImpressionPoint`,\n  `avgPosition`, `daysCoverageRate`, `observationCount`, `keywordEstimateSearchCount`,\n  `keywordEstimateSearchChangeCount`, `keywordEstimateSearchCountChangeRate`, `keywordAbaRank`,\n  `keywordAbaRankChangeCount`, `trafficShare`\n- Live validation note: current live response item shape matches `keywords/competitor-product-keywords`\n  field-for-field; keep the semantic distinction in output wording rather than assuming a unique schema\n\n### `/openapi/v2/keywords/product-traffic-terms-overview`\n- Input: `asin`, `date`, optional `marketplace`\n- Data window: latest weekly overview snapshot at or before the requested date; compares all keyword impression traffic under the ASIN with the previous period\n- Date rule: prefer T-1 or earlier for `date`; avoid current-date lookup unless explicitly requested\n- Response shape: `data` is an object or `null`\n- Key fields from live MCP response: `periodStartDate`, `periodEndDate`, `asin`, `site`,\n  `organicImpressionPoint`, `sponsoredProductImpressionPoint`, `sponsoredBrandImpressionPoint`,\n  `sponsoredBrandVideoImpressionPoint`, `sponsoredRecommendImpressionPoint`,\n  `organicImpressionPointPrev`, `sponsoredProductImpressionPointPrev`,\n  `sponsoredBrandImpressionPointPrev`, `sponsoredBrandVideoImpressionPointPrev`,\n  `sponsoredRecommendImpressionPointPrev`, `first3PagesNewOrganicKeywords`,\n  `first3PagesLostOrganicKeywords`\n- `*Prev` fields are previous-period baselines for the matching current impression-point fields\n- The legacy response returns only the current `periodStartDate` / `periodEndDate`; it does not return separate previous-period boundaries. A `*Prev` field may be null or absent when no previous-period value is available.\n- `first3PagesNewOrganicKeywords` and `first3PagesLostOrganicKeywords` are arrays of objects with\n  `keyword`, `pageIndex`, and `pagePosition`\n- `first3PagesNewOrganicKeywords` lists keywords newly entering ORG first three pages; `first3PagesLostOrganicKeywords`\n  lists keywords that dropped out of ORG first three pages\n- Live validation request: MCP tool `openapi_v2_product_traffic_terms_overview`,\n  `asin=\"B01CGLCGRA\"`, `date=\"2026-06-29\"`, `marketplace=\"US\"`\n\n### `/openapi/v2/keywords/product-traffic-terms-timeline`\n- Input: required `asin`, exactly one of `keyword` / `keywords[]` (1–20), `dateFrom`, `dateTo`, `granularity=week` only; optional `marketplace`\n- Do not send `lookbackDays`, `page`, `pageSize`, `sortBy`, or `sortOrder`; `day`, `month`, and `lately_day` are unsupported\n- Data window: ASIN + keyword timeline across the requested date range; date range cannot exceed 61 days\n- Date rule: prefer T-1 or earlier for `dateTo`; avoid current-date lookup unless explicitly requested\n- Response shape: `data.context + data.items[].series[]`, preserving keyword request order\n- Item fields: `identity`, `status=ok|empty`, `series[]`, `emptyReason`, nullable `errorCode`, nullable `errorMessage`\n- Each series point groups fields under `asinSnapshot`, `traffic`, `placement`, `keywordMetrics`, and `adActivity`; keep their returned period boundaries separate\n- Diagnosis curves/events: price (`asinSnapshot.latestPrice`), BSR (`asinSnapshot.latestBsr`,\n  `asinSnapshot.latestSubBsr`), sales (`asinSnapshot.latestMonthlySaleCount`), rating\n  (`asinSnapshot.latestRating`, `asinSnapshot.latestRatingCount`), traffic estimate (`traffic.*`\n  plus placement averages), and listing events (`asinSnapshot.latestTitle`, `asinSnapshot.latestMainImageLink`)\n- Key groups: listing/product/rank fields in `asinSnapshot`; ORG/SP/SB/SBV/SPR impression points\n  in `traffic`; positions/pages/observation times in `placement`; weekly search/ABA fields and\n  `metricWindow` in `keywordMetrics`; observation/campaign/ad counts in `adActivity`\n\n## Local Review Toolkit\n\nWhen `/reviews/analysis` lacks aggregation (ASIN has <50 reviews or no daily snapshot),\nfall back to live raw reviews + your own LLM. The toolkit does NOT call any external\nLLM — you (the calling skill's LLM) perform the Map/Reduce steps.\n\n**Workflow:**\n\n```bash\n# 1. Fetch raw reviews (up to 100, cursor-paginated, ~60s, 10 credits at full)\nzoodata.py reviews-raw --asin B0XXXXXXXX [--marketplace US] [--max-pages 10]\n\n# 2. For EACH review, render the per-review Map prompt\nzoodata.py review-tag-prompt --review '<single review JSON>' \\\n    [--product-title \"...\"] [--product-category \"...\"]\n# → Your LLM produces a JSON object with sentiment + 11 dimension arrays\n#   (mentioned_scenarios, mentioned_issues, mentioned_positives, mentioned_improvements,\n#    mentioned_buying_factors, mentioned_pain_points, user_profiles, mentioned_usage_times,\n#    mentioned_usage_locations, mentioned_behaviors, keywords)\n# Suggested map parallelism: ~20 concurrent if your LLM supports it\n\n# 3. Collect candidate phrases per dimension. For EACH dimension render the Reduce prompt\nzoodata.py review-reduce-prompt --label-type positives \\\n    --candidates '[\"comfortable\",\"comfy\",\"very comfortable\",...]'\n# → Your LLM produces {clusters: [{canonical, members}, ...]}\n# Suggested chunk size for `keywords` dim when >150 candidates: 150 per call\n\n# 4. Aggregate into reviews/analysis-compatible consumerInsights\nzoodata.py review-aggregate --reviews raw.json --tagged tags.json --clusters clusters.json\n# → Output shape matches /reviews/analysis: reviewCount, avgRating,\n#   sentimentDistribution, consumerInsights[], topKeywords[]\n```\n\n**When to use the toolkit instead of `reviews/analysis`:**\n- ASIN has fewer than 50 reviews\n- `reviews/analysis` returns sparse `consumerInsights` (missing dimensions)\n- Need the freshest possible data (Spider scrape vs. T+1 BigQuery snapshot)\n- Need to analyze a brand-new product that has no daily snapshot yet\n\n## Field Differences Across Endpoints\n\n| Data | markets | products/competitors | realtime/product | reviews/analysis | realtime/reviews | price-band | brand | history |\n|------|---------|---------------------|----------|---------|---------|------------|-------|---------|\n| Sales | sampleAvgMonthlySales | monthlySalesFloor | ❌ | ❌ | ❌ | sampleSalesRate | sampleGroupMonthlySales | monthlySalesFloor[] |\n| Price | sampleAvgPrice | price | buyboxWinner.price | ❌ | ❌ | bandMin/MaxPrice | sampleAvgPrice | price[] |\n| BSR | sampleAvgBsr | bsr (int) | bestsellersRank[] | ❌ | ❌ | ❌ | ❌ | bsr[] |\n| Rating | sampleAvgRating | rating | rating | avgRating | rating (per review) | sampleAvgRating | sampleAvgRating | rating[] |\n| Reviews | sampleAvgReviewCount | ratingCount | ratingCount | reviewCount | reviews[] (raw text, max 100) | ❌ | sampleAvgRatingCount | ratingCount[] |\n| Insights | ❌ | ❌ | ❌ | ✅ consumerInsights | ❌ (raw only — feeds Local Review Toolkit) | ❌ | ❌ | ❌ |\n| Concentration | topSalesRate | ❌ | ❌ | ❌ | ❌ | sampleTop3BrandSalesRate | CR10 | ❌ |\n| Opportunity | ❌ | ❌ | ❌ | ❌ | ❌ | sampleOpportunityIndex | ❌ | ❌ |\n\n## Confidence Labels (all skills)\n- 📊 **Data-backed** — direct API data\n- 🔍 **Inferred** — logical reasoning from data\n- 💡 **Directional** — suggestions, predictions\n\nStrategy recommendations and subjective conclusions are NEVER 📊. Extreme growth (>200%) = 💡 only.\n\n## Data Notes\n- Sales (`monthlySalesFloor`) = lower-bound estimate\n- Realtime = live; products/competitors = ~T+1 delay\n- Marketplace coverage varies by endpoint; follow each endpoint schema\n- Each call consumes credits; check `meta.creditsConsumed`\n\n## Links\n- [zoodata.ai](https://zoodata.ai) · [API Docs](https://api.zoodata.ai/api-docs) · [GitHub](https://github.com/SerendipityOneInc/ZooData-Skills) · support@zoodata.ai\n\nFile v1.1.8:README.md\n\n# ZooData — Commerce Data Infrastructure for AI Agents\n\n> 200M+ Amazon products. 22 endpoints. One API key.\n\n## What This Skill Does\n\nThe foundational data layer for all ZooData agent skills. Provides direct access to 22 API endpoints covering category browsing, market metrics, product search (20+ filter fields), competitor lookup, real-time ASIN detail, AI review analysis, price band analysis, brand intelligence, product history, and keyword intelligence. Use this skill when you need raw API access or want to understand what data is available.\n\n### What Makes This Different\n\n- **22 endpoints in one skill**: Complete API reference with field mappings and known quirks\n- **Critical pitfalls documented**: Category-first workflow, field naming differences across endpoints, aggregation gotchas\n- **Cross-endpoint field guide**: Know exactly which field to use from which endpoint\n- **Foundation for all skills**: Every ZooData skill builds on this data layer\n\n## Install\n\n```bash\nnpx skills add SerendipityOneInc/ZooData-Skills\n```\n\nSelect **ZooData** when prompted.\n\n## API Key Setup\n\n1. Get a free key at [zoodata.ai/api-keys](https://zoodata.ai/en/api-keys) — 1,000 free credits, no credit card\n2. Set the environment variable:\n   ```bash\n   export ZOODATA_API_KEY='hms_live_xxxxxx'\n   ```\n\n## Example Prompts\n\n- *\"What ZooData endpoints are available?\"*\n- *\"What ZooData endpoints are available and how do I use them?\"*\n- *\"Look up real-time data for ASIN B0XXXXXXXX\"*\n- *\"Search for products in the 'yoga mat' category sorted by sales\"*\n- *\"Pull the market data for this product category\"*\n\n## What You Get\n\n| Section | Description |\n|---------|-------------|\n| 📚 22 Endpoint Reference | Purpose, key parameters, output fields |\n| ⚠️ API Pitfalls | Critical rules all skills must follow |\n| 📊 Field Difference Table | Which field comes from which endpoint |\n| 🏷️ Confidence Labels | Data-backed / Inferred / Directional tagging system |\n| 📝 Known Quirks | String types, array handling, rate limits |\n\n## API Endpoints\n\n| # | Endpoint | Purpose |\n|---|----------|---------|\n| 1 | `categories` | Browse/search category tree |\n| 2 | `markets/search` | Market-level metrics (sales, price, concentration) |\n| 3 | `products/search` | Product search with 20+ filter fields (13 CLI presets) |\n| 4 | `products/competitors` | Competitor discovery |\n| 5 | `realtime/product` | Live ASIN detail (rating, BSR, Buy Box, variants) |\n| 6 | `reviews/analysis` | AI review insights (sentiment, pain points, keywords) |\n| 7 | `realtime/reviews` | Live raw review text |\n| 8 | `products/price-band-overview` | Price band summary (hottest, best opportunity) |\n| 9 | `products/price-band-detail` | Full 5-band distribution |\n| 10 | `products/brand-overview` | Brand concentration (CR10) |\n| 11 | `products/brand-detail` | Per-brand breakdown |\n| 12 | `products/history` | Daily price/BSR/sales snapshots |\n| 13 | `keywords/detail` | Keyword weekly snapshot |\n| 14 | `keywords/market-profile` | Multidimensional weekly keyword market profile |\n| 15 | `keywords/trend` | Keyword weekly trend |\n| 16 | `keywords/trend-profile` | Keyword trend profile for fixed weekly windows |\n| 17 | `keywords/extends` | Keyword expansion |\n| 18 | `keywords/search-results` | Keyword SERP snapshot |\n| 19 | `keywords/competitor-product-keywords` | Competitor ASIN keyword coverage |\n| 20 | `keywords/product-traffic-terms` | ASIN traffic-driving keywords |\n| 21 | `keywords/product-traffic-terms-overview` | Weekly ASIN traffic-term overview |\n| 22 | `keywords/product-traffic-terms-timeline` | ASIN + keyword timeline |\n\nKeyword endpoint note: ZooData keyword data is estimated search, exposure, visibility, rank, placement, and impression evidence; it is not seller ABA-SQP or Amazon Ads performance. Analysis-stage routing, seller-artifact acquisition, and output policy are owned by [`amazon-keyword-traffic-analysis`](../amazon-keyword-traffic-analysis/).\n\nKeyword date rule: keyword workflows are keyword-query lookups. When a keyword endpoint requires `date` or `dateTo`, prefer T-1 or earlier and avoid current-date lookup unless the user explicitly asks for today's data.\n\n## Credit Cost\n\nVaries per endpoint. Each call consumes credits — check `meta.creditsConsumed` in response. 1,000 free credits on signup.\n\n## Powered By\n\n[ZooData](https://zoodata.ai) — The data infrastructure built for agents. 200M+ Amazon products, 1B+ reviews, real-time signals.\n\nFile v1.1.8:_meta.json\n\n{\n  \"ownerId\": \"kn78k155f6rbh2j8r8yjx8r2e18304q9\",\n  \"slug\": \"zoodata\",\n  \"version\": \"1.1.8\",\n  \"publishedAt\": 1785807031635\n}\n\nFile v1.1.8:references/cli-contract.md\n\n<!-- Canonical source - do not edit copies under amazon-* skill directories directly -->\n\n# ZooData CLI Contract\n\n## Ownership and application\n\nThis file owns the project-wide caller contract before and after every bundled `{skill_base_dir}/scripts/zoodata.py` invocation. Read it before selecting the first command, then apply it after each granular or composite result and before any additional API/tool call, fallback, state write, interpretation, or user-facing report.\n\nIt owns the shared invocation form, command-identity validation, execution-environment permission handling, caller/CLI responsibilities, composite-result reuse, result acquisition, transport-status precedence, terminal-interface classification, retry ownership, and partial-result handling. It does not own skill-specific command allowlists, endpoint request/response fields, business interpretation, scenario selection, conclusion authority, or any user-facing failure/report rendering.\n\n## Invocation interface\n\n1. Invoke the bundled client as `python {skill_base_dir}/scripts/zoodata.py [global options] <subcommand> [subcommand options]` using the active skill's local copy.\n2. Place global options before the subcommand. Treat top-level and subcommand `--help` as the live invocation contract; help inspection makes no API request and consumes no credits.\n3. Use the active skill to select the allowed workflow and command scope. Use this contract to validate and execute that selection; do not let this shared file select a business workflow.\n4. Distinguish API/evidence commands from local-only diagnostic, prompt-rendering, and aggregation commands according to the selected subcommand's help. Do not attribute an API call or credit use to a local-only command.\n5. Credential resolution is owned by the bundled CLI. Invoke it directly; do not inspect local credential stores or pre-resolve, compare, export, or override credential values in the caller.\n\n## Command identity and composite reuse\n\n1. Inspect the bundled CLI's top-level `--help` and the selected subcommand's `--help` before invocation. Execute only an exact literal subcommand exposed by the current client and allowed by the active skill.\n2. Treat API endpoint identifiers and composite result keys as data identities, not CLI command names. Never derive a subcommand from either identity or invent an alias.\n3. Treat a successful composite command's structured output as the evidence bundle for that run. Perform selection, narrowing, transformation, extraction, and formatting locally.\n4. Do not make an additional API call solely to reread, reshape, or narrow evidence already present in the composite bundle.\n5. A granular call after a composite is allowed only for evidence absent from the bundle when the active skill's workflow or an explicit non-terminal fallback requires it.\n\n## Execution-environment permission gate\n\nApply this gate before classifying a connection or network failure as a CLI/API interface failure.\n\n1. Inspect the execution tool's permission profile and diagnostics. When they indicate, or strongly suggest, that a host sandbox or network policy blocked the request, treat the result as unresolved execution permission rather than endpoint failure.\n2. Use the execution tool's permission or escalation mechanism to request access and rerun the exact unchanged CLI command. Do not first emit the skill's interface-failure notice or a succeeded/failed endpoint ledger.\n3. A permission-approved rerun is environment recovery, not an external transport retry. Do not mutate the command, parameters, endpoint, or acquisition surface while requesting access.\n4. If access is declined or no permission mechanism is available, state only that the required network access was not granted and the task could not continue. Do not label endpoints as failed or imply that API requests consumed credits when no request reached the service.\n5. After the permission issue is resolved, classify the rerun normally through the sections below. Do not use this gate to bypass a returned HTTP status, credential failure, credit failure, validation failure, rate limit, or confirmed service outage.\n\n## Result acquisition\n\n1. Always inspect stdout, even when the process exits non-zero. Exit `1` with valid \n\nArchive v1.1.7: 7 files, 63329 bytes\n\nFiles: README.md (5136b), references/openapi-reference.md (34586b), references/reference.md (12006b), scripts/zoodata.py (153321b), skill-card.md (2729b), SKILL.md (34274b), _meta.json (126b)\n\nArchive v1.1.6: 7 files, 63244 bytes\n\nFiles: README.md (5136b), references/openapi-reference.md (34586b), references/reference.md (12001b), scripts/zoodata.py (153321b), skill-card.md (2611b), SKILL.md (34274b), _meta.json (126b)\n\nArchive v1.1.5: 8 files, 61896 bytes\n\nFiles: config.json (67b), README.md (5136b), references/openapi-reference.md (34586b), references/reference.md (12001b), scripts/zoodata.py (149089b), skill-card.md (2524b), SKILL.md (34157b), _meta.json (126b)\n\nArchive v1.1.4: 8 files, 60922 bytes\n\nFiles: config.json (67b), README.md (5136b), references/openapi-reference.md (34586b), references/reference.md (12001b), scripts/zoodata.py (147843b), skill-card.md (2439b), SKILL.md (32932b), _meta.json (126b)\n\nArchive v1.1.1: 7 files, 34642 bytes\n\nFiles: README.md (3107b), references/openapi-reference.md (10038b), references/reference.md (10138b), scripts/apiclaw.py (105922b), skill-card.md (2889b), SKILL.md (6311b), _meta.json (126b)\n\nArchive v1.1.0: 6 files, 33202 bytes\n\nFiles: README.md (3107b), references/openapi-reference.md (10038b), references/reference.md (10138b), scripts/apiclaw.py (105921b), SKILL.md (6223b), _meta.json (126b)","readmeExcerpt":"Skill: zoodata Owner: apiclaw Summary: API endpoint reference for the ZooData data platform: the 12 commerce endpoints plus 10 keyword-intelligence endpoints (categories, markets, products, competitors, realtime ASIN, AI review analysis, raw reviews, price band, brand, history, and the keyword detail/trend/extends/search/ market-profile/product-traffic/competitor-keywords/traffic-timeline family) — their inputs/outpu","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"# 1. Fetch raw reviews (up to 100, cursor-paginated, ~60s, 10 credits at full)\nzoodata.py reviews-raw --asin B0XXXXXXXX [--marketplace US] [--max-pages 10]\n\n# 2. For EACH review, render the per-review Map prompt\nzoodata.py review-tag-prompt --review '<single review JSON>' \\\n    [--product-title \"...\"] [--product-category \"...\"]\n# → Your LLM produces a JSON object with sentiment + 11 dimension arrays\n#   (mentioned_scenarios, mentioned_issues, mentioned_positives, mentioned_improvements,\n#    mentioned_buying_factors, mentioned_pain_points, user_profiles, mentioned_usage_times,\n#    mentioned_usage_locations, mentioned_behaviors, keywords)\n# Suggested map parallelism: ~20 concurrent if your LLM supports it\n\n# 3. Collect candidate phrases per dimension. For EACH dimension render the Reduce prompt\nzoodata.py review-reduce-prompt --label-type positives \\\n    --candidates '[\"comfortable\",\"comfy\",\"very comfortable\",...]'\n# → Your LLM produces {clusters: [{canonical, members}, ...]}\n# Suggested chunk size for `keywords` dim when >150 candidates: 150 per call\n\n# 4. Aggregate into reviews/analysis-compatible consumerInsights\nzoodata.py review-aggregate --reviews raw.json --tagged tags.json --clusters clusters.json\n# → Output shape matches /reviews/analysis: reviewCount, avgRating,\n#   sentimentDistribution, consumerInsights[], topKeywords[]"},{"language":"bash","snippet":"npx skills add SerendipityOneInc/ZooData-Skills"},{"language":"bash","snippet":"export ZOODATA_API_KEY='hms_live_xxxxxx'"},{"language":"bash","snippet":"# 1. Fetch raw reviews (up to 100, cursor-paginated, ~60s, 10 credits at full)\nzoodata.py reviews-raw --asin B0XXXXXXXX [--marketplace US] [--max-pages 10]\n\n# 2. For EACH review, render the per-review Map prompt\nzoodata.py review-tag-prompt --review '<single review JSON>' \\\n    [--product-title \"...\"] [--product-category \"...\"]\n# → Your LLM produces a JSON object with sentiment + 11 dimension arrays\n#   (mentioned_scenarios, mentioned_issues, mentioned_positives, mentioned_improvements,\n#    mentioned_buying_factors, mentioned_pain_points, user_profiles, mentioned_usage_times,\n#    mentioned_usage_locations, mentioned_behaviors, keywords)\n# Suggested map parallelism: ~20 concurrent if your LLM supports it\n\n# 3. Collect candidate phrases per dimension. For EACH dimension render the Reduce prompt\nzoodata.py review-reduce-prompt --label-type positives \\\n    --candidates '[\"comfortable\",\"comfy\",\"very comfortable\",...]'\n# → Your LLM produces {clusters: [{canonical, members}, ...]}\n# Suggested chunk size for `keywords` dim when >150 candidates: 150 per call\n\n# 4. Aggregate into reviews/analysis-compatible consumerInsights\nzoodata.py review-aggregate --reviews raw.json --tagged tags.json --clusters clusters.json\n# → Output shape matches /reviews/analysis: reviewCount, avgRating,\n#   sentimentDistribution, consumerInsights[], topKeywords[]"},{"language":"bash","snippet":"npx skills add SerendipityOneInc/ZooData-Skills"},{"language":"bash","snippet":"export ZOODATA_API_KEY='hms_live_xxxxxx'"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: zoodata\ndescription: >\n  API endpoint reference for the ZooData data platform: the 12 commerce\n  endpoints plus 10 keyword-intelligence endpoints (categories, markets,\n  products, competitors, realtime ASIN, AI review analysis, raw reviews,\n  price band, brand, history, and the keyword detail/trend/extends/search/\n  market-profile/product-traffic/competitor-keywords/traffic-timeline\n  family) — their inputs/outputs, parameter quirks, Quick Start (auth,\n  base URL), how credits are tracked (meta.creditsConsumed), and the Local\n  Review Toolkit (Map/Reduce for raw reviews).\n  Use when the user asks about the API itself: which endpoints exist, how\n  to call them (e.g. /products/search), field schemas returned by an\n  endpoint, parameter quirks, how to authenticate, how credit consumption\n  is reported, how to get started, or how the Local Review Toolkit works.\n  Requires ZOODATA_API_KEY.\nmetadata:\n  version: \"1.1.9\"\n  author: SerendipityOneInc\n  homepage: https://github.com/SerendipityOneInc/ZooData-Skills\n  openclaw: {\"requires\": {\"env\": [\"ZOODATA_API_KEY\"]}, \"primaryEnv\": \"ZOODATA_API_KEY\"}\n---\n\n> **📋 Live API Reference**: Field names and parameters may change. If you encounter field errors,\n> check the latest OpenAPI spec at https://zoodata.ai/api/v1/openapi-spec for current field definitions.\n> Keyword exception: the observation endpoints currently support `granularity=week` only. Do not\n> reintroduce `day`, `month`, `lately_day`, or `lookbackDays` from a stale generated schema.\n\n# ZooData — Commerce Data Infrastructure for AI Agents\n\n200M+ Amazon products. 22 endpoints. One API key.\n\n## Quick Start\n1. Get key: [zoodata.ai/api-keys](https://zoodata.ai/en/api-keys) (1,000 free credits)\n2. `export ZOODATA_API_KEY='hms_live_xxx'`\n3. Base URL: `https://api.zoodata.ai/openapi/v2` — all POST with JSON body\n4. Auth: `Authorization: Bearer YOUR_API_KEY`\n5. New keys need 3-5s to activate. If 403, wait and retry.\n\n## Capabilities & Data Flow\n\n- **Network**: only `https://api.zoodata.ai` (Bearer `ZOODATA_API_KEY`). Setting `ZOODATA_BASE_URL` to an untrusted host (anything other than `api.zoodata.ai` / `*.zoodata.ai` / localhost) makes the CLI **refuse the request and withhold the key** — the Bearer token is never sent to an untrusted host.\n- **Execution**: bundled shared ZooData CLI `{skill_base_dir}/scripts/zoodata.py` (Python 3, stdlib-only). This data-layer reference skill allows the complete literal subcommand surface exposed by the bundled client's current top-level help.\n- **Local files**: none by default; reads the optional credential store `~/.zoodata/config.json`; the Local Review Toolkit uses a private temporary working dir (created with `mktemp -d`, removed when the fallback completes) during the review fallback.\n- **Sent to the API**: keywords, category paths, ASINs, marketplace/date and numeric filter values only. **Never sent**: budget, experience level, risk tolerance, or any other user-profile text — profile inputs map client-sid"},{"path":"README.md","content":"# ZooData — Commerce Data Infrastructure for AI Agents\n\n> 200M+ Amazon products. 22 endpoints. One API key.\n\n## What This Skill Does\n\nThe foundational data layer for all ZooData agent skills. Provides direct access to 22 API endpoints covering category browsing, market metrics, product search (20+ filter fields), competitor lookup, real-time ASIN detail, AI review analysis, price band analysis, brand intelligence, product history, and keyword intelligence. Use this skill when you need raw API access or want to understand what data is available.\n\n### What Makes This Different\n\n- **22 endpoints in one skill**: Complete API reference with field mappings and known quirks\n- **Critical pitfalls documented**: Category-first workflow, field naming differences across endpoints, aggregation gotchas\n- **Cross-endpoint field guide**: Know exactly which field to use from which endpoint\n- **Foundation for all skills**: Every ZooData skill builds on this data layer\n\n## Install\n\n```bash\nnpx skills add SerendipityOneInc/ZooData-Skills\n```\n\nSelect **ZooData** when prompted.\n\n## API Key Setup\n\n1. Get a free key at [zoodata.ai/api-keys](https://zoodata.ai/en/api-keys) — 1,000 free credits, no credit card\n2. Set the environment variable:\n   ```bash\n   export ZOODATA_API_KEY='hms_live_xxxxxx'\n   ```\n\n## Example Prompts\n\n- *\"What ZooData endpoints are available?\"*\n- *\"What ZooData endpoints are available and how do I use them?\"*\n- *\"Look up real-time data for ASIN B0XXXXXXXX\"*\n- *\"Search for products in the 'yoga mat' category sorted by sales\"*\n- *\"Pull the market data for this product category\"*\n\n## What You Get\n\n| Section | Description |\n|---------|-------------|\n| 📚 22 Endpoint Reference | Purpose, key parameters, output fields |\n| ⚠️ API Pitfalls | Critical rules all skills must follow |\n| 📊 Field Difference Table | Which field comes from which endpoint |\n| 🏷️ Confidence Labels | Data-backed / Inferred / Directional tagging system |\n| 📝 Known Quirks | String types, array handling, rate limits |\n\n## API Endpoints\n\n| # | Endpoint | Purpose |\n|---|----------|---------|\n| 1 | `categories` | Browse/search category tree |\n| 2 | `markets/search` | Market-level metrics (sales, price, concentration) |\n| 3 | `products/search` | Product search with 20+ filter fields (13 CLI presets) |\n| 4 | `products/competitors` | Competitor discovery |\n| 5 | `realtime/product` | Live ASIN detail (rating, BSR, Buy Box, variants) |\n| 6 | `reviews/analysis` | AI review insights (sentiment, pain points, keywords) |\n| 7 | `realtime/reviews` | Live raw review text |\n| 8 | `products/price-band-overview` | Price band summary (hottest, best opportunity) |\n| 9 | `products/price-band-detail` | Full 5-band distribution |\n| 10 | `products/brand-overview` | Brand concentration (CR10) |\n| 11 | `products/brand-detail` | Per-brand breakdown |\n| 12 | `products/history` | Daily price/BSR/sales snapshots |\n| 13 | `keywords/detail` | Keyword weekly snapshot |\n| 14 | `keywords/market-profile` | Multidimensio"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn78k155f6rbh2j8r8yjx8r2e18304q9\",\n  \"slug\": \"zoodata\",\n  \"version\": \"1.1.9\",\n  \"publishedAt\": 1786068900697\n}"},{"path":"references/cli-contract.md","content":"<!-- Canonical source - do not edit copies under amazon-* skill directories directly -->\n\n# ZooData CLI Contract\n\n## Ownership and application\n\nThis file owns the project-wide caller contract before and after every bundled `{skill_base_dir}/scripts/zoodata.py` invocation. Read it before selecting the first command, then apply it after each granular or composite result and before any additional API/tool call, fallback, state write, interpretation, or user-facing report.\n\nIt owns the shared invocation form, command-identity validation, execution-environment permission handling, caller/CLI responsibilities, composite-result reuse, result acquisition, transport-status precedence, terminal-interface classification, retry ownership, and partial-result handling. It does not own skill-specific command allowlists, endpoint request/response fields, business interpretation, scenario selection, conclusion authority, or any user-facing failure/report rendering.\n\n## Invocation interface\n\n1. Invoke the bundled client as `python {skill_base_dir}/scripts/zoodata.py [global options] <subcommand> [subcommand options]` using the active skill's local copy.\n2. Place global options before the subcommand. Treat top-level and subcommand `--help` as the live invocation contract; help inspection makes no API request and consumes no credits.\n3. Use the active skill to select the allowed workflow and command scope. Use this contract to validate and execute that selection; do not let this shared file select a business workflow.\n4. Distinguish API/evidence commands from local-only diagnostic, prompt-rendering, and aggregation commands according to the selected subcommand's help. Do not attribute an API call or credit use to a local-only command.\n5. Credential resolution is owned by the bundled CLI. Invoke it directly; do not inspect local credential stores or pre-resolve, compare, export, or override credential values in the caller.\n\n## Command identity and composite reuse\n\n1. Inspect the bundled CLI's top-level `--help` and the selected subcommand's `--help` before invocation. Execute only an exact literal subcommand exposed by the current client and allowed by the active skill.\n2. Treat API endpoint identifiers and composite result keys as data identities, not CLI command names. Never derive a subcommand from either identity or invent an alias.\n3. Treat a successful composite command's structured output as the evidence bundle for that run. Perform selection, narrowing, transformation, extraction, and formatting locally.\n4. Do not make an additional API call solely to reread, reshape, or narrow evidence already present in the composite bundle.\n5. A granular call after a composite is allowed only for evidence absent from the bundle when the active skill's workflow or an explicit non-terminal fallback requires it.\n6. A keyword-driven composite resolves the working category through a fallback chain and records the outcome in `meta`: `meta.category_source` states how it resolved "},{"path":"references/openapi-reference.md","content":"# ZooData API Quick Reference\n\n> Concise field reference for the currently documented Amazon commerce and keyword-intelligence endpoints. Load when you need exact parameter/field names.\n>\n> **OpenAPI Spec (live)**: https://zoodata.ai/api/v1/openapi-spec\n\nBase URL: `https://api.zoodata.ai/openapi/v2`\nAuth: `Bearer $ZOODATA_API_KEY`\nMethod: All POST with JSON body\n\n---\n\n## 1. categories\n\n| Parameter | Type | Note |\n|-----------|------|------|\n| categoryKeyword | String | Search by keyword |\n| categoryPath | List\\<String\\> | Exact path lookup, e.g. `[\"Electronics\", \"Computers\"]` |\n| parentCategoryPath | List\\<String\\> | Browse children |\n| _(no params)_ | — | Returns root categories |\n\nResponse: `categoryId`, `categoryName`, `categoryPath`, `hasChildren`, `isRoot`, `level`, `productCount`, `link`\n\n---\n\n## 2. markets/search\n\n| Parameter | Type | Note |\n|-----------|------|------|\n| categoryPath | List\\<String\\> | e.g. `[\"Pet Supplies\", \"Dogs\"]` |\n| categoryKeyword | String | Keyword match across levels |\n| topN | **String** | `\"3\"` / `\"5\"` / `\"10\"` / `\"20\"` ⚠️ must be string |\n| newProductPeriod | **String** | `\"1\"` / `\"3\"` / `\"6\"` / `\"12\"` ⚠️ must be string |\n| sampleType | String | `bySale100` / `byBsr100` / `avg` |\n| dateRange | String | default `30d` |\n| pageSize | Integer | default 20 |\n| sortBy | String | default `sampleAvgMonthlySales` |\n| sortOrder | String | `asc` / `desc` |\n\nKey response fields: `sampleAvgMonthlySales`, `sampleAvgPrice`, `sampleAvgMonthlyRevenue`, `sampleBrandCount`, `sampleSellerCount`, `sampleFbaRate`, `sampleNewSkuRate`, `topSalesRate`, `topBrandSalesRate`, `topSellerSalesRate`, `totalSkuCount`\n\n---\n\n## 3. products/competitors\n\n| Parameter | Type | Note |\n|-----------|------|------|\n| keyword | String | Search keyword |\n| brand | String | Brand filter |\n| seller | String | Seller filter |\n| asin | String | ASIN filter |\n| categoryPath | List\\<String\\> | Category filter |\n| sortBy | String | `monthlySalesFloor` / `monthlyRevenueFloor` / `bsr` / `price` / `rating` / `ratingCount` / `listingDate` |\n| sortOrder | String | `asc` / `desc` |\n| pageSize | Integer | default 20 |\n\n---\n\n## 4. products/search\n\nSame as competitors, plus:\n\n| Parameter | Type | Note |\n|-----------|------|------|\n| keywordMatchType | String | `fuzzy` / `phrase` / `exact` |\n| listingAge | **Enum String** | One of `30d` / `90d` / `180d` / `1y` / `2y` (⚠️ bare numbers like `180` → 422) |\n\nFilter pairs (all optional, Min/Max): `monthlySales`, `revenue`, `salesGrowthRate`, `bsr`, `subBsr`, `bsrGrowthRate`, `price`, `rating`, `ratingCount`, `fbaShipping`, `variantCount`, `grossMargin`, `sellerCount`\n\n> `mode` is **NOT** an API parameter. The 13 CLI presets in `zoodata.py` expand client-side into the filter pairs above before the request is sent; passing `mode` in a raw request returns 422.\n\nAdditional: `includeBrands`, `excludeBrands`, `fulfillment` (`[\"FBA\"]`/`[\"FBM\"]`/`[\"AMZ\"]`), `badges` — enum values `[\"bestSeller\"]` / `[\"amazonChoice\"]` / `[\"newRelease\"]"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":2162,"uniquenessScore":42,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-10T04:38:56.225Z","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-10T04:38:56.225Z","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-10T06:44:29.196Z","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"}]}}}