{"openapi":"3.1.0","info":{"title":"Brand Intelligence API","version":"1.0.0","description":"Brand intelligence, audience conversations, category trends, and creative deltas in a single API. Track brand activity, monitor what audiences are saying, and get ready-to-use briefs, digests, and alerts.\n\nThe Brand Intelligence API provides programmatic access to brand intelligence across three data domains. Data is collected and scanned daily, normalized, and served through a consistent REST interface.\n\n## Three Data Domains\n\n- **Brand Data** — Owned media, paid media/ads, and brand mentions sourced from all the major social platforms and news organizations. All data scanned daily.\n- **Category Data** — Industry news and trending topics sourced from X, Google, TikTok, Reddit, and more. Scanned daily.\n- **Audience Data** — Top-level audience segments with subreddit activity, influencer accounts, and podcast monitoring. Audiences are derived from analysis of tracked brand followings and can be linked to one or many brands. Scanned daily.\n\n## Authentication\n\nAll requests require a Bearer token in the `Authorization` header:\n\n```\nAuthorization: Bearer waldo_your_key_here\n```\n\nAPI keys are scoped to a specific user and team. Manage them with the [API Keys endpoints](#tag/api-keys) (`POST /v1/api-keys`, `GET /v1/api-keys`, `DELETE /v1/api-keys/{keyId}`), from the Waldo app under Settings → API Keys, or with the `api_key_*` tools on the Waldo MCP server.\n\n## Access\n\nDiscover, Enrichment, Account and API Keys work on every workspace. Brands, Categories, Audiences, Topics, Trends, Brand Search and Evidence Search require **Brand Intelligence** on your workspace, and the beta sections (Brand Overview, Competitive Analysis) additionally require beta access; without them those routes return 403. Contact support@waldo.fyi to enable either.\n\nThis reference always lists the full public surface. Fetched with a valid key or a signed-in session, it also lists any further routes your workspace can call.\n\n## MCP Server\n\nEverything in this API is also available over the [Model Context Protocol](https://modelcontextprotocol.io) — use it from Claude Desktop, Claude Code, Cursor, VS Code, ChatGPT, or any MCP-compatible client. Add the server URL to your client:\n\n```\nhttps://mcp.waldo.fyi\n```\n\n**Authentication** — most MCP clients (Claude Desktop, Cursor, etc.) handle OAuth automatically: add the server URL and authorize when prompted. For clients without OAuth support, pass an API key as a Bearer token instead — the same keys this API uses.\n\n**Tools** — the REST surface maps to MCP tools one-to-one: `brand_search`, `brand_get`, `brand_mentions_list`, `brand_mentions_summary`, `brand_owned_media_summary`, `brand_paid_media_ads_list`, `audience_insights`, `category_landscape`, `api_key_create`, and so on. Anything you can do here, your AI assistant can do over MCP.\n\n**Troubleshooting** — authentication failures usually mean an expired or revoked key: list yours with `GET /v1/api-keys` and mint a fresh one. For OAuth, disconnect and re-authorize.\n\n## Rate Limits\n\nRate limits are applied per team — all keys and users on the same team share a single quota of **1,000 requests/minute**. A small number of **live data** endpoints — those that fetch fresh, on-demand results — have a tighter per-team cap: **60 requests/minute** on the free tier and **600 requests/minute** for paid teams.\n\nRate limit status is returned in response headers:\n- `X-RateLimit-Limit` — Maximum requests per window\n- `X-RateLimit-Remaining` — Requests remaining in current window\n- `X-RateLimit-Reset` — Unix timestamp when the window resets\n\n## Pagination\n\nList endpoints use cursor-based pagination:\n\n```\nGET /v1/brands/{brand_id}/mentions?limit=20&cursor=eyJpZCI6Ij...\n```\n\nList responses carry a `meta` envelope with `total`, `total_pages`, and `next_cursor` (pass as `cursor` for the next page; `null` on the last page).\n\n## Errors\n\nErrors return JSON with an `error` object:\n\n```json\n{ \"error\": { \"code\": \"not_found\", \"message\": \"Brand not found\" } }\n```\n\nStandard HTTP status codes: 400 (bad request), 401 (unauthorized), 404 (not found), 429 (rate limited), 502 (upstream platform error), 500 (internal error).","contact":{"name":"Waldo Support","url":"https://waldo.fyi","email":"support@waldo.fyi"}},"servers":[{"url":"https://data.waldo.fyi"}],"tags":[{"name":"Trends","description":"Cross-platform trend intelligence"},{"name":"Brands","description":"Search brand profiles with metadata and linked audiences"},{"name":"Platforms","description":"Per-platform handles and follower data for a brand"},{"name":"Owned Media","description":"Brand-owned social posts and their performance"},{"name":"Executives","description":"A brand's tracked leadership members and their personal profiles"},{"name":"Executive Media","description":"Posts published by a brand's executives on their personal profiles — reported separately from the brand's own owned media"},{"name":"Paid Media","description":"Paid-media ads, creative and spend summaries"},{"name":"Mentions","description":"Third-party mentions of the brand across social media, news, forums, review sites, and podcasts"},{"name":"Competitive","description":"Side-by-side brand comparison (compare)"},{"name":"Brand Search","description":"Full-text search across data Waldo has already indexed"},{"name":"Evidence Search","description":"Semantic search by meaning across every indexed corpus at once — audience posts, brand mentions, owned media and unaffiliated news"},{"name":"Audiences","description":"Consumer segments — who they are, where they spend time, and what they're saying"},{"name":"Categories","description":"Waldo's industry taxonomy — categories and subcategories with metadata and brand populations"},{"name":"Topics","description":"Search the shared topic-tag vocabulary to discover tags available to filter mentions and audience posts by"},{"name":"Brand Overview","description":"Cross-dataset brand overview (beta)"},{"name":"Competitive Analysis","description":"Competitive set + benchmark (beta)"},{"name":"Discover","description":"Query-first discovery search across live platforms — posts, ads, trends, creators, companies, jobs, and communities"},{"name":"Enrichment","description":"Platform passthrough — look up posts, profiles, comments, and companies in real time"},{"name":"Account","description":"Account info, credit balance, spend controls, and usage tracking"},{"name":"API Keys","description":"Create, list, and revoke API keys"}],"components":{"securitySchemes":{"API-Key":{"type":"http","scheme":"bearer","bearerFormat":"API Key","description":"Your Waldo API key. Generate one with the **Generate key** button above."}},"schemas":{"AccountUsage":{"type":"object","properties":{"period":{"type":"object","properties":{"start":{"type":"string","example":"2026-04-01"},"end":{"type":"string","example":"2026-04-30"}},"required":["start","end"]},"total_calls":{"type":"integer","example":0},"by_domain":{"type":"array","items":{"type":"object","properties":{"domain":{"type":"string","example":"brands"},"calls":{"type":"integer","example":0}},"required":["domain","calls"]}}},"required":["period","total_calls","by_domain"]},"AccountBalance":{"type":"object","properties":{"balance":{"type":"number","example":4200,"description":"Credits remaining in the current period."},"used":{"type":"number","example":800},"limit":{"type":"number","example":5000},"plan":{"type":["string","null"],"example":"pro"},"status":{"type":["string","null"],"example":"active"},"period":{"type":"object","properties":{"start":{"type":["string","null"],"example":"2026-06-01T00:00:00Z"},"end":{"type":["string","null"],"example":"2026-06-30T23:59:59Z"},"days_remaining":{"type":["number","null"],"example":21}},"required":["start","end","days_remaining"]}},"required":["balance","used","limit","plan","status","period"]},"AccountProfile":{"type":"object","properties":{"account_id":{"type":"string","example":"1080"},"email":{"type":["string","null"],"example":"team@example.com"},"entities":{"type":"object","properties":{"brands":{"type":"integer","example":12},"categories":{"type":"integer","example":5},"audiences":{"type":"integer","example":3}},"required":["brands","categories","audiences"]},"requests_this_month":{"type":"integer","example":0}},"required":["account_id","email","entities","requests_this_month"]},"EvidenceSearchMeta":{"allOf":[{"$ref":"#/components/schemas/Meta"},{"type":"object","properties":{"model":{"type":"string","description":"The embedding model this response's similarity scores were computed with. Disclosed so you can tell whether two result sets are comparable.","example":"openai/text-embedding-3-large"}},"required":["model"]}]},"Meta":{"type":"object","properties":{"request_id":{"type":"string","example":"req_abc123"},"total":{"type":"integer","description":"Total number of items matching the request, across all pages. Omitted when no total is available for the endpoint — absence means unknown, not zero.","example":142},"total_pages":{"type":"integer","description":"ceil(total / limit). Present exactly when total is; paginate via next_cursor regardless.","example":6},"next_cursor":{"type":["string","null"],"example":"eyJpZCI6Ij..."}},"required":["request_id"]},"EvidenceResult":{"type":"object","properties":{"post_id":{"type":"string","format":"uuid","example":"p1a2c3d4-e5f6-7890-abcd-ef1234567890"},"similarity":{"type":"number","description":"Cosine similarity to the query, 0–1, computed against the full-precision embedding (higher is closer). Comparable only within one response and one `meta.model` — similarity values from different embedding models are not on the same scale.","example":0.938},"corpus":{"type":"array","items":{"type":"string","enum":["mentions","owned_media","audience","unlinked"]},"description":"Which corpora this post belongs to, as visible to you. A post can appear in more than one — the same conversation reached as an audience post and as a brand mention reports both. `unlinked` means it is associated with no brand or audience at all. Never empty.","example":["audience","mentions"]},"brand_id":{"type":["string","null"],"format":"uuid","description":"The OWNING brand, or null when the post is unowned (a third-party mention, an audience-collected post, news). Null does not mean the post is unrelated to a brand — check `corpus`.","example":null},"brand_name":{"type":["string","null"],"example":null},"platform":{"type":"string","example":"reddit"},"source_type":{"type":["string","null"],"enum":["SOCIAL","NEWS","FORUM","REVIEW","PODCAST","BLOG",null],"description":"Source category as stored on the post. Null on rows collected before source-type stamping.","example":"SOCIAL"},"text":{"type":["string","null"],"example":"Example post: six months in and the battery is toast."},"url":{"type":["string","null"],"example":"https://www.reddit.com/r/example/comments/example1/"},"posted_at":{"type":["string","null"],"format":"date-time","example":"2026-03-15T10:30:00Z"},"fetched_at":{"type":"string","format":"date-time","example":"2026-04-01T12:00:00Z"},"author":{"type":"object","properties":{"handle":{"type":["string","null"],"example":"@example_fan"},"name":{"type":["string","null"],"example":"Sam Example"}},"required":["handle","name"],"description":"Same shape as owned-media and mention authors"},"sentiment_polarity":{"type":["string","null"],"enum":["POSITIVE","NEGATIVE","NEUTRAL","MIXED",null],"description":"Analyzer polarity label; null on rows not yet analyzed.","example":"NEGATIVE"},"sentiment_aspect":{"type":["string","null"],"description":"What the sentiment is about (e.g. pricing, battery); null until analyzed.","example":"battery"},"topic_tags":{"type":"array","items":{"type":"string"},"description":"Analyzer topic tags. Empty on rows not yet analyzed.","example":["battery-life","durability"]}},"required":["post_id","similarity","corpus","brand_id","brand_name","platform","source_type","text","url","posted_at","fetched_at","author","sentiment_polarity","sentiment_aspect","topic_tags"]},"SearchResult":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"p1a2c3d4-e5f6-7890-abcd-ef1234567890"},"brand_id":{"type":["string","null"],"format":"uuid","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"brand_name":{"type":["string","null"],"example":"Acme Corp"},"platform":{"type":"string","example":"instagram"},"ownership":{"type":"string","example":"owned"},"text":{"type":["string","null"],"example":"Example post: check out our new product launch!"},"url":{"type":["string","null"],"example":"https://www.instagram.com/p/EXAMPLE1/"},"posted_at":{"type":["string","null"],"format":"date-time","example":"2026-03-15T10:30:00Z"},"fetched_at":{"type":"string","format":"date-time","example":"2026-04-01T12:00:00Z"},"source_type":{"type":["string","null"],"example":"social"},"sentiment_polarity":{"type":["string","null"],"example":"positive"},"rank":{"type":"number","example":0.85}},"required":["id","brand_id","brand_name","platform","ownership","text","url","posted_at","fetched_at","source_type","sentiment_polarity","rank"]},"LinkedInCompanyPerson":{"type":"object","properties":{"name":{"type":"string"},"position":{"type":"string"},"location":{"type":"string"},"publicIdentifier":{"type":["string","null"]},"urn":{"type":["string","null"]},"url":{"type":["string","null"]},"image":{"type":"string"}}},"CompanyProfile":{"type":"object","properties":{"platform":{"type":"string","enum":["linkedin","facebook"]},"name":{"type":"string","example":"Example Company"},"publicIdentifier":{"type":"string","description":"URL-resolvable handle — LinkedIn `public_identifier` or Facebook `page_alias`.","example":"example-company"},"url":{"type":"string"},"logo":{"type":"string"},"followersCount":{"type":"number"},"universalName":{"type":"string"},"linkedinId":{"anyOf":[{"type":"string"},{"type":"number"}],"description":"LinkedIn's internal numeric company id. Served as a number despite the vendor documenting a string — accept either.","example":1000001},"urn":{"type":"string"},"backgroundImage":{"type":"string"},"headline":{"type":"string"},"employeeCountRange":{"type":"object","properties":{"start":{"type":["number","null"]},"end":{"type":["number","null"],"description":"Null when the published range is open-ended (e.g. 10001+)."}}},"industry":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"urn":{"type":"string"}}}},"pageId":{"type":"string"},"category":{"type":"string"},"verified":{"type":"boolean"},"igUsername":{"type":"string"},"igFollowers":{"type":"number"},"igVerified":{"type":"boolean"}},"required":["platform","name"]},"VideoTranscript":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string","example":"Example transcript: welcome back to the channel"},"startMs":{"type":"number","description":"Segment start offset in milliseconds.","example":2150},"durationMs":{"type":"number","description":"Segment duration in milliseconds.","example":3410}},"required":["text","startMs","durationMs"]},"description":"Transcript segments in playback order."}},"required":["data"],"additionalProperties":{}},"FollowedAccount":{"type":"object","properties":{"id":{"type":"string"},"username":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"profilePicture":{"type":"string"},"isVerified":{"type":"boolean"}},"additionalProperties":{}},"NormalizedProfile":{"type":"object","properties":{"type":{"type":"string","enum":["profile"]},"id":{"type":"string","description":"Stable content id derived from the platform + handle.","example":"3cd43482-1588-5272-b84a-5c52c695f93a"},"platform":{"type":"object","properties":{"source":{"type":"string","example":"reddit"},"name":{"type":"string","example":"Reddit"},"id":{"type":"string","example":"abc123"},"url":{"type":"string","example":"https://www.reddit.com/r/example/comments/abc123/"}},"required":["source","name","id"]},"publishedAt":{"type":"string"},"content":{"type":"object","properties":{"name":{"type":"string","example":"Example Brand"},"headline":{"type":"string"},"bio":{"type":"string","example":"Example bio: gear for every trail."},"location":{"type":"string"},"url":{"type":"string","example":"https://www.instagram.com/example_brand"},"profilePicture":{"type":"string"},"backgroundPicture":{"type":"string"}},"required":["name","url"]},"metrics":{"type":"object","properties":{"followers":{"type":"number","example":2513954},"connections":{"type":"number"}}},"professional":{"type":"object","properties":{"currentPosition":{"type":"string"},"currentCompany":{"type":"string"},"education":{"type":"string"}}},"metadata":{"type":"object","additionalProperties":{},"description":"Upstream annotation block. Keys vary by platform and are not part of the stable contract."}},"required":["type","id","platform","content"]},"PostReactor":{"type":"object","properties":{"author":{"type":"object","properties":{"type":{"type":"string","example":"Member"},"name":{"type":"string","example":"Pat Example"},"headline":{"type":"string"},"profileUrl":{"type":"string"},"publicIdentifier":{"type":"string"}},"additionalProperties":{}},"reactionType":{"type":"string","description":"Platform-native reaction name (LinkedIn: LIKE, EMPATHY, PRAISE, …). Absent where the platform reports only that a reaction happened.","example":"EMPATHY"}},"additionalProperties":{}},"PostComment":{"type":"object","properties":{"id":{"type":"string","example":"18000000000000001"},"text":{"type":"string","example":"Example comment: love this colorway."},"author":{"type":"object","properties":{"id":{"type":"string"},"username":{"type":"string","example":"example_commenter"},"name":{"type":"string"},"profileUrl":{"type":"string"},"profilePicture":{"type":"string"}},"additionalProperties":{},"description":"Comment author, as the platform reports them."},"createdAt":{"type":"string","example":"2026-06-09T14:17:59.000Z"},"likes":{"type":"number","example":7},"inReplyTo":{"type":"object","properties":{"tweetId":{"type":"string","example":"1000000000000000002"},"username":{"type":"string","example":"example_user"},"userId":{"type":"string","example":"1000000002"}},"required":["tweetId"],"description":"X only. The tweet this comment replies to — for a reply-to-reply that is the direct parent, not the thread root. Absent on a top-level tweet."}},"additionalProperties":{}},"RedditCommunityResult":{"type":"object","properties":{"name":{"type":"string","description":"Subreddit name, prefixed","example":"r/example"},"href":{"type":"string","description":"URL of the subreddit","example":"https://www.reddit.com/r/example/"},"description":{"type":"string","description":"Community public description"},"subscribers":{"type":"number","description":"Number of subscribers to the subreddit. 0 when the upstream result carries no count.","example":373899}},"required":["name","href","description","subscribers"]},"LinkedInJobResult":{"type":"object","properties":{"urn":{"type":"string","example":"urn:li:fs_normalized_jobPosting:1000000001"},"title":{"type":"string","example":"Overnight Merchant Support Advisor"},"company":{"type":["string","null"],"example":"Shopify"},"location":{"type":["string","null"],"example":"Canada (Remote)"},"url":{"type":["string","null"],"example":"https://www.linkedin.com/jobs/view/example-1000000001"},"listing_date":{"type":["string","null"],"example":"2026-06-29T17:37:34.000Z"},"subtitle":{"type":["string","null"]}},"required":["urn","title"],"additionalProperties":{}},"LinkedInCompanyResult":{"type":"object","properties":{"urn":{"type":"string","example":"urn:li:fsd_company:1000001"},"name":{"type":"string","example":"Example Company"},"url":{"type":["string","null"],"example":"https://www.linkedin.com/company/example-company/"},"public_identifier":{"type":["string","null"],"example":"example-company"},"description":{"type":["string","null"]},"specializes_in":{"type":["string","null"],"example":"Software Development"},"headquarters":{"type":["string","null"],"example":"Ottawa, ON"},"followers":{"type":["number","null"],"example":1000000},"company_logo":{"type":["string","null"]},"jobs":{"type":["number","null"],"description":"Open job listings on the company page at fetch time.","example":127},"page_by":{"type":["string","null"]}},"required":["urn","name"],"additionalProperties":{}},"CreatorProfile":{"type":"object","properties":{"platform":{"type":"string","enum":["instagram","x","tiktok","linkedin","facebook","youtube"]},"id":{"type":"string","description":"Platform-native id (instagram user_id, x rest_id, tiktok uid, linkedin urn, facebook id, youtube channelId).","example":"1000000001"},"handle":{"type":"string","description":"URL-resolvable handle (username / screen_name / public_identifier).","example":"example_creator"},"name":{"type":"string","example":"Example Creator"},"url":{"type":"string","example":"https://www.instagram.com/example_creator"},"bio":{"type":"string","description":"Descriptive line — bio/description, or the role headline on LinkedIn."},"location":{"type":"string"},"profilePicture":{"type":"string"},"followersCount":{"type":"number","example":3400000},"isVerified":{"type":"boolean","description":"Absent when the vendor didn't say — distinct from an explicit false."}},"required":["platform"]},"DiscoverTrend":{"type":"object","properties":{"type":{"type":"string","enum":["trend"]},"id":{"type":"string","example":"ce9430fa-38a3-5792-a2cd-3c391c8f8ab8"},"platform":{"type":"object","properties":{"source":{"type":"string","example":"reddit"},"name":{"type":"string","example":"Reddit"},"id":{"type":"string","example":"abc123"},"url":{"type":"string","example":"https://www.reddit.com/r/example/comments/abc123/"}},"required":["source","name","id"],"description":"Trend source block — `source` is google_trends, tiktok, or x."},"publishedAt":{"type":"string","example":"2026-06-14T15:58:12.841Z"},"content":{"type":"object","properties":{"title":{"type":"string","example":"shopify theme dev"},"query":{"type":"string","example":"shopify theme dev"},"value":{"anyOf":[{"type":"number"},{"type":"string"}]},"formattedValue":{"type":"string"},"description":{"type":"string"},"byline":{"type":"string"},"imageUrl":{"type":"string"},"newsToken":{"type":"string"}}},"metrics":{"type":"object","properties":{"searches":{"type":"number","example":600},"traffic":{"type":"number"},"views":{"type":"number"},"followers":{"type":"number"},"likes":{"type":"number"},"position":{"type":"number","example":1},"percentageIncrease":{"type":"number"},"posts":{"type":"number","description":"Publications behind the trend (TikTok hashtag volume)."},"rankChange":{"type":"number","description":"Vendor-published change in board position since the prior snapshot."}}},"metadata":{"type":"object","additionalProperties":{},"description":"Upstream annotation block. Keys vary by platform and are not part of the stable contract."}},"required":["type","id","platform","content"]},"DiscoverAd":{"type":"object","properties":{"type":{"type":"string","enum":["ad"]},"id":{"type":"string","description":"Stable content id derived from the platform + native ad id.","example":"f4a58cb0-adbc-52da-818d-05380973dd65"},"platform":{"type":"object","properties":{"source":{"type":"string","example":"reddit"},"name":{"type":"string","example":"Reddit"},"id":{"type":"string","example":"abc123"},"url":{"type":"string","example":"https://www.reddit.com/r/example/comments/abc123/"}},"required":["source","name","id"],"description":"Ad platform block — `source` is meta, google, or linkedin."},"publishedAt":{"type":"string","example":"2026-01-13T08:00:00.000Z"},"content":{"type":"object","properties":{"title":{"type":"string"},"text":{"type":"string"},"author":{"type":"object","properties":{"id":{"type":"string","example":""},"username":{"type":"string","example":"example_user"},"name":{"type":"string"},"profileUrl":{"type":"string","example":"https://www.reddit.com/user/example_user"},"profilePicture":{"type":"string"}},"required":["id","username"]},"media":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["image","video"]},"url":{"type":"string"},"thumbnail":{"type":"string"}},"required":["type","url"]}},"metrics":{"type":"object","properties":{"likes":{"type":"number","example":1240},"comments":{"type":"number","example":87},"shares":{"type":"number"},"views":{"type":"number"},"saves":{"type":"number"}}},"cta":{"type":"object","properties":{"text":{"type":"string"},"type":{"type":"string"},"url":{"type":"string"}},"required":["text"],"description":"Call-to-action button on the creative."},"adType":{"type":"string","example":"image"}},"required":["author"]},"targeting":{"type":"object","properties":{"platforms":{"type":"array","items":{"type":"string"},"example":["facebook","instagram"]},"region":{"type":"string"},"country":{"type":"string","example":"US"},"targetDomain":{"type":"string"}},"description":"Where the ad ran, as published by the platform's ad library."},"campaignDates":{"type":"object","properties":{"firstShown":{"type":"string","example":"2026-01-13T08:00:00.000Z"},"lastShown":{"type":"string"},"totalDaysShown":{"type":"number","example":42},"totalActiveTime":{"type":"number"}}},"metadata":{"type":"object","additionalProperties":{},"description":"Upstream annotation block. Keys vary by platform and are not part of the stable contract."}},"required":["type","id","platform","content"]},"NormalizedPost":{"type":"object","properties":{"type":{"type":"string","enum":["post"]},"post_id":{"type":"string","description":"Opaque post token — pass to /v1/posts/{post_id} to enrich.","example":"pid_eyJwIjoicmVkZGl0Iiwia..."},"platform":{"type":"object","properties":{"source":{"type":"string","example":"reddit"},"name":{"type":"string","example":"Reddit"},"id":{"type":"string","example":"abc123"},"url":{"type":"string","example":"https://www.reddit.com/r/example/comments/abc123/"}},"required":["source","name","id"]},"publishedAt":{"type":"string","example":"2026-06-30T12:00:00Z"},"content":{"type":"object","properties":{"title":{"type":"string"},"text":{"type":"string"},"author":{"type":"object","properties":{"id":{"type":"string","example":""},"username":{"type":"string","example":"example_user"},"name":{"type":"string"},"profileUrl":{"type":"string","example":"https://www.reddit.com/user/example_user"},"profilePicture":{"type":"string"}},"required":["id","username"]},"media":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["image","video"]},"url":{"type":"string"},"thumbnail":{"type":"string"}},"required":["type","url"]}},"metrics":{"type":"object","properties":{"likes":{"type":"number","example":1240},"comments":{"type":"number","example":87},"shares":{"type":"number"},"views":{"type":"number"},"saves":{"type":"number"}}}},"required":["author"]},"metadata":{"type":"object","additionalProperties":{},"description":"Upstream annotation block. Keys vary by platform and are not part of the stable contract."}},"required":["type","post_id","platform","content"]},"TrendDetail":{"allOf":[{"$ref":"#/components/schemas/Trend"},{"type":"object","properties":{"series":{"type":"array","items":{"$ref":"#/components/schemas/TrendSeriesPoint"},"description":"Google-interest series enriched for this trend (bounded, ascending by bucket_at)."}},"required":["series"]}]},"TrendSeriesPoint":{"type":"object","properties":{"query":{"type":"string","example":"tornado warning"},"comparison_set":{"type":"array","items":{"type":"string"},"description":"The set the 0-100 value was normalised against — 100 is the peak of the biggest term in the set, so a value is meaningless without it."},"geo":{"type":"string","example":"US"},"google_property":{"type":"string","example":"WEB"},"google_category":{"type":["integer","null"]},"granularity":{"type":"string","example":"DAILY"},"bucket_at":{"type":"string","example":"2026-08-27T00:00:00.000000Z"},"value":{"type":"integer","description":"0-100 relative index, NOT a volume.","example":100},"is_partial":{"type":"boolean","description":"The final bucket of a series is incomplete; true flags it so charts don't render a fake dip.","example":false}},"required":["query","comparison_set","geo","google_property","google_category","granularity","bucket_at","value","is_partial"]},"Trend":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"c1a2b3d4-e5f6-7890-abcd-ef1234567890"},"platform":{"type":"string","example":"google_trends"},"trend_type":{"type":"string","example":"SEARCH_QUERY"},"label":{"type":"string","example":"tornado warning"},"url":{"type":["string","null"]},"first_seen_at":{"type":"string","example":"2026-08-20T00:00:00.000Z","description":"When this trend was first observed, in ANY market. Not scoped by the `geo` filter."},"last_seen_at":{"type":"string","example":"2026-08-27T00:00:00.000Z","description":"When this trend was last observed, in ANY market. Not scoped by the `geo` filter — and it is the default sort key, so a geo-filtered list is ordered by each trend's most recent activity anywhere, which can differ from its most recent observation in the market you filtered to."},"days_observed":{"type":"integer","example":3,"description":"Distinct days this trend has been observed on, across ALL markets. Not scoped by the `geo` filter: a hashtag trending in two markets counts a day on which either was collected, so this can exceed the days it held a position in the market you filtered to."},"latest_observation":{"$ref":"#/components/schemas/TrendObservation"},"categories":{"type":"array","items":{"$ref":"#/components/schemas/TrendCategory"}}},"required":["id","platform","trend_type","label","url","first_seen_at","last_seen_at","days_observed","latest_observation","categories"]},"TrendCategory":{"type":"object","properties":{"taxonomy":{"type":"string","description":"GOOGLE_TRENDING | GOOGLE_TRENDS | TIKTOK_INDUSTRY | WALDO.","example":"WALDO"},"category_key":{"type":"string","example":"food_and_drink"},"brand_taxonomy_id":{"type":["string","null"],"description":"Set on derived WALDO rows that classify into the brand taxonomy; null for native and untethered rows.","example":"food-beverage"},"source":{"type":"string","description":"NATIVE (platform's own label) or DERIVED (from trend content).","example":"DERIVED"},"confidence":{"type":["number","null"],"description":"DERIVED rows only.","example":0.87}},"required":["taxonomy","category_key","brand_taxonomy_id","source","confidence"]},"TrendObservation":{"type":["object","null"],"properties":{"captured_on":{"type":["string","null"],"example":"2026-08-27"},"geo":{"type":["string","null"],"example":"US"},"board":{"type":["string","null"],"description":"The board/window the rank sits within — platform-specific (e.g. PAST_24_HOURS on Google, GENERAL or one of 18 industry boards on TikTok, LIVE on X). A rank is only comparable to another rank on the same board: rank 1 of PETS is not rank 1 of GENERAL.","example":"PAST_24_HOURS"},"rank":{"type":["integer","null"],"example":3},"rank_change":{"type":["integer","null"]},"prominence":{"type":["number","null"],"description":"0.0-1.0 percentile within (captured_on, geo, board) — the only cross-platform-comparable sort key.","example":0.92},"volume":{"type":["number","null"],"description":"Platform-specific and NOT comparable across platforms (TikTok views vs a Google 0-100 bucket vs X null). Read alongside volume_unit."},"volume_unit":{"type":["string","null"],"example":"VIEWS"},"captured_at":{"type":["string","null"],"example":"2026-08-27T16:24:46.000000Z"}},"required":["captured_on","geo","board","rank","rank_change","prominence","volume","volume_unit","captured_at"],"description":"A trend's most recent observation. A collector run stamps one capture instant across every board — and every market — it pulls, so a trend can hold several equally-recent observations. Among those, the one reported is the US market's where one of them is, then the GENERAL board's, then the strongest rank, then the lowest observation id. Passing `geo` on the list endpoint restricts the reading to that market, which can therefore be older than the trend's most recent observation overall."},"CategoryConversationsMeta":{"allOf":[{"$ref":"#/components/schemas/ConversationsMeta"},{"type":"object","properties":{"total":{"type":"integer","description":"Every distinct theme over the category's in-window posts, which is NOT the length of `data` once the count exceeds `theme_limit`.","example":60},"total_pages":{"type":"integer","description":"Always 1 for a non-empty response (0 for an empty one). This endpoint does not page, so this is not ceil(total / limit) — compare `total` against `theme_limit` to see whether themes were cut.","example":1},"set_version":{"type":["integer","null"],"description":"Always null: no cluster set backs this read. Not a 'not yet clustered' signal — nothing stores clusters for a category."},"other_share":{"type":["number","null"],"description":"Fraction of the category's in-window posts carrying no topic tag at all, over the same denominator as each theme's `share`. Null when the window holds no posts to take a fraction of."},"source":{"type":"string","enum":["TOPIC_TAGS_ONLY"],"description":"Always TOPIC_TAGS_ONLY — the only mode this endpoint has. Themes are the analyzer's topic tags over the category's posts, not embedded clusters: categories are never clustered at any size, so this is not the sub-floor fallback the audience endpoints report as TOPIC_TAGS but the permanent shape here. `type` and `intent` are null, and because a post carries up to three tags where clusters are disjoint, the shares overlap and do not sum to 1."},"theme_limit":{"type":"integer","description":"The most themes `data` holds. The first `conversation_themes` of them are the themes with the most conversation-backed posts (`stance_post_count`); the rest are the largest remaining themes by size. `total` counts every distinct theme over the scope, so `total > theme_limit` means themes were cut — the smallest by size among those not holding a conversation slot. The endpoint does not page — `total_pages` is 1 and `next_cursor` null — so the cut tail is not retrievable.","example":50},"conversation_themes":{"type":"integer","description":"How many leading items of `data` hold a reserved conversation slot — up to 15, each a theme with at least 3 conversation-backed posts, ordered by `stance_post_count`. Items after them are ordered by `size`. So `data` as a whole is not sorted by any one field: the first `conversation_themes` surface discussion that is outnumbered by brand-mention volume, and the rest carry the largest themes. Fewer than 15 when fewer themes qualify, the unused slots going to size; 0 when no theme has that many, which includes a category whose conversation lane is new or whose stances have not yet been recorded on its verdicts.","example":12}},"required":["source","theme_limit","conversation_themes"]}]},"ConversationsMeta":{"allOf":[{"$ref":"#/components/schemas/Meta"},{"type":"object","properties":{"set_version":{"type":["integer","null"],"description":"Version of the cluster set read. null when the audience has not been clustered yet."},"window_start":{"type":["string","null"],"description":"Start of the window the set was built over (ISO 8601)."},"window_end":{"type":["string","null"],"description":"End of the window (ISO 8601)."},"other_share":{"type":["number","null"],"description":"Fraction of scope posts in no theme (noise + sub-floor residual)."}},"required":["set_version","window_start","window_end","other_share"]}]},"CategoryConversationTheme":{"type":"object","properties":{"theme_id":{"type":"string","description":"Stable theme identity — under meta.source CLUSTERS the same theme keeps this id across weekly refreshes. Under TOPIC_TAGS it is derived from the tag instead, so it is stable for as long as the tag keeps appearing but is re-minted when the audience crosses the clustering floor and real themes take over. Under TOPIC_TAGS_ONLY it is likewise tag-derived and stable for as long as the tag keeps appearing, but there is no floor and no crossing: the scope is never clustered, so the id never churns into a cluster id. Do not treat an id as comparable across modes, or across scopes.","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"label":{"type":["string","null"],"description":"Human-readable name for the theme. Under meta.source CLUSTERS this is the labeler's 3-6 word English phrase. Under TOPIC_TAGS and TOPIC_TAGS_ONLY there is no labeler: it is the analyzer's topic tag, de-hyphenated and sentence-cased, so it reads as one or two words rather than a written phrase.","example":"Slow shipping complaints"},"type":{"type":["string","null"],"description":"Aspect × polarity, UPPERCASE_SNAKE. Under meta.source CLUSTERS this is the labeler's call over the whole theme. Always null under TOPIC_TAGS and TOPIC_TAGS_ONLY: no labeler runs in either, and the post analyzer writes topic tags but deliberately no sentiment, so there is no aspect or polarity to derive one from — a null here in those modes says nothing about the theme.","example":"SHIPPING_NEGATIVE"},"intent":{"type":["string","null"],"description":"Closed-taxonomy intent for the theme — TRIGGER, OBJECTION, NEED, PRAISE, COMPARISON or OTHER. null on cluster sets built before intent classification, and always null under meta.source TOPIC_TAGS and TOPIC_TAGS_ONLY, neither of which classifies anything.","example":"TRIGGER"},"awareness_stage":{"type":["string","null"],"description":"Closed-taxonomy funnel position for the theme — UNAWARE, PROBLEM_AWARE, SOLUTION_AWARE, PRODUCT_AWARE, MOST_AWARE or INDETERMINATE. Orthogonal to `intent`: intent is what kind of thing the theme is, this is where in the funnel the people in it stand. INDETERMINATE means no legible stance, not a sixth stage. null on cluster sets built before awareness classification, and always null under meta.source TOPIC_TAGS and TOPIC_TAGS_ONLY — the stage is classified from a cluster set's own members, and a tag is not a cluster.","example":"PROBLEM_AWARE"},"size":{"type":"integer","description":"Posts assigned to this theme."},"share":{"type":"number","description":"size / scope post count."},"confidence":{"type":"number","description":"Composite of size, content depth, author diversity and cross-refresh persistence (0–1). The persistence term only contributes under meta.source CLUSTERS, where a theme can carry over from the prior refresh; under TOPIC_TAGS and TOPIC_TAGS_ONLY the themes are computed per request and nothing carries, so that term scores zero and values read up to 0.2 lower — do not compare confidence across modes."},"top_author_share":{"type":"number","description":"Fraction of the theme's posts by its single most prolific author — a megaphone signal."},"first_observed":{"type":"string","description":"When this theme was first seen (ISO 8601). Under meta.source CLUSTERS this is stored at refresh time and does not move. Under TOPIC_TAGS and TOPIC_TAGS_ONLY it is the earliest in-window post carrying the tag, so it advances as older posts age out of the rolling window — theme age is not comparable across modes."},"verbatim_examples":{"type":"array","items":{"$ref":"#/components/schemas/Verbatim"}},"stance_post_count":{"type":"integer","description":"Posts in this theme that this category's conversation analyzer approved as discussion of the category and found a position in. The stance is the one written for this category — never one another category's analyzer wrote about the same post — and brand mentions the category never judged carry none, so this is the theme's conversation-backed volume. It decides which themes hold the up to 15 reserved slots at the head of `data` — at least 3 to qualify.","example":12},"stances":{"type":"array","items":{"type":"string"},"description":"Positions people take in this theme's posts toward this category, each a short claim this category's conversation analyzer wrote — e.g. \"speaker labels break down with multiple speakers\". Paraphrases, not quotes, so they carry no author or link; use `verbatim_examples` for people's own words. Drawn from the theme's posts, a post carrying up to three tags, so a stance may be about something beside the theme's label. Newest source post first, a repeated phrase listed once, at most 10. Empty when no post in the theme carries one.","example":["speaker labels break down with multiple speakers"]}},"required":["theme_id","label","type","intent","awareness_stage","size","share","confidence","top_author_share","first_observed","verbatim_examples","stance_post_count","stances"]},"Verbatim":{"type":"object","properties":{"text":{"type":["string","null"]},"author":{"type":"object","properties":{"handle":{"type":["string","null"]},"name":{"type":["string","null"]}},"required":["handle","name"]},"url":{"type":["string","null"]},"platform":{"type":"string"},"language":{"type":["string","null"],"description":"ISO 639-1 language code for this verbatim: the translator's own reading once the background cache has resolved the post, and a local detection before that. Null when neither can name it — local detection covers a fixed language table and returns null outside it.","example":"en"},"text_en":{"type":["string","null"],"description":"English translation of `text`. Read it together with `language`: null alongside `language: \"en\"` is final — the verbatim is already English and there is nothing to translate — while null alongside any other value means the background translation cache has not produced one yet, so poll rather than treat it as untranslatable. A null `language` does NOT mean null here; those verbatims are translated like any other. `text` is always the author's original and is never replaced.","example":"the delivery took three weeks"}},"required":["text","author","url","platform","language","text_en"]},"CreativePatterns":{"type":"object","properties":{"window":{"type":"string","enum":["7d","30d","90d"]},"period":{"type":"object","properties":{"start":{"type":"string"},"end":{"type":"string"}},"required":["start","end"]},"taxonomy_version":{"type":"integer","description":"Version of the frame taxonomy these rows were classified against.","example":1},"hooks":{"$ref":"#/components/schemas/CreativePatternAxis"},"angles":{"$ref":"#/components/schemas/CreativePatternAxis"}},"required":["window","period","taxonomy_version","hooks","angles"]},"CreativePatternAxis":{"type":"object","properties":{"creative_count":{"type":"integer","description":"Distinct creatives carrying any label on this axis — the denominator for this axis alone. The two axes have different coverage, so their counts differ.","example":214},"frames":{"type":"array","items":{"$ref":"#/components/schemas/CreativePatternFrame"}}},"required":["creative_count","frames"]},"CreativePatternFrame":{"type":"object","properties":{"frame":{"type":"string","enum":["analogy","better-way","command","endorsement","head-to-head","myth-vs-reality","paradox","personification","problem","problem-solution","proof","provocation","pun","question","reframe","relatable","sensory","superlative","surprise-pivot","tease","urgency","visual-reveal","access","adoption","advancement","affordability","appearance","authenticity","availability","barrier-removal","belonging","capability","cause","comfort","competitive-edge","consolidation","control","convenience","creation","credential","durability","early-detection","efficacy","efficiency","family-safety","flourishing","gifting","guidance","health","identity","indulgence","innovation","interpretation","leadership","lifestyle","mastery","memory","metrics","no-tradeoff","novelty","obligation","ownership","partnership","performance","personalisation","pleasure","prestige","protection","provenance","purity","quality","reframing","relief","returns","revenue","ritual","scalability","scarcity","seasonality","selection","self-knowledge","simplicity","superiority","transparency","urgency-of-change","visibility","other"],"example":"scarcity"},"label":{"type":"string","example":"Scarcity"},"family":{"type":["string","null"],"example":"urgency-and-timing"},"definition":{"type":["string","null"]},"frequency":{"type":"integer","description":"Distinct creatives carrying this frame. Duplicate ingests of one creative count once, and a creative whose labels both land on this frame counts once. A label mapping to two frames counts toward both, so these can sum above creative_count.","example":88},"used_by":{"type":"integer","description":"Distinct brands running this frame. 1 on every row at brand scope, by construction.","example":7},"top_labels":{"type":"array","items":{"type":"string"},"description":"The analyzer's own labels behind this frame, verbatim, most frequent first."},"example_ad_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Example ads carrying the frame. At category scope this lists only ads from brands in your scope, so it can be empty on a row whose frequency is not."}},"required":["frame","label","family","definition","frequency","used_by","top_labels","example_ad_ids"]},"CategoryWhitespace":{"type":"object","properties":{"category_id":{"type":"string","example":"technology-software-ai-machine-learning"},"themes":{"type":"array","items":{"type":"object","properties":{"theme":{"type":"string","example":"eu-ai-act"},"demand":{"type":"integer","example":54,"description":"Distinct category posts carrying this theme in the window — the theme's earned-conversation volume."},"ownership":{"type":"object","properties":{"total":{"type":"integer","example":3,"description":"Total brand-attributed mentions carrying this theme, counting only brands that belong to the category."},"owner_brand_count":{"type":"integer","example":2},"top_owner":{"type":["object","null"],"properties":{"brand":{"type":"string","example":"OpenAI"},"mentions":{"type":"integer","example":2}},"required":["brand","mentions"],"description":"The category brand with the most mentions on this theme, or null when no category brand has captured it."},"owners":{"type":"array","items":{"type":"object","properties":{"brand":{"type":"string","example":"OpenAI"},"mentions":{"type":"integer","example":2},"share":{"type":"number","example":66.7,"description":"This brand's share of the theme's owned mentions (0-100, one decimal)."}},"required":["brand","mentions","share"]}}},"required":["total","owner_brand_count","top_owner","owners"]},"open_lane":{"type":"boolean","example":true,"description":"True when no category brand owns the theme — zero owners, or the top owner holds under 10% of the theme's demand. High demand + open_lane is the whitespace signal."}},"required":["theme","demand","ownership","open_lane"]}}},"required":["category_id","themes"]},"CategoryLandscape":{"type":"object","properties":{"category_id":{"type":"string","example":"retail"},"total_mentions":{"type":"integer","example":15000},"category_sentiment":{"type":"object","properties":{"positive":{"type":"integer","example":6000},"neutral":{"type":"integer","example":7000},"negative":{"type":"integer","example":2000}},"required":["positive","neutral","negative"]},"top_brands_by_voice":{"type":"array","items":{"type":"object","properties":{"brand":{"type":"string","example":"Acme Corp"},"mentions":{"type":"integer","example":3400},"share_of_voice":{"type":"number","example":22.7}},"required":["brand","mentions","share_of_voice"]}}},"required":["category_id","total_mentions","category_sentiment","top_brands_by_voice"]},"CategoryTrend":{"type":"object","properties":{"trend":{"type":"string","example":"sustainability"},"trend_type":{"type":"string","example":"topic"},"volume_7d":{"type":"integer","example":342},"momentum":{"type":["integer","null"],"description":"Signed week-over-week volume delta for the tag: posts in the last 7 days minus posts in the 7 days before that. Positive means rising, negative means fading.","example":12},"sentiment":{"type":["string","null"],"example":"positive"}},"required":["trend","trend_type","volume_7d","momentum","sentiment"]},"CategoryNews":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"p1a2c3d4-e5f6-7890-abcd-ef1234567890"},"title":{"type":["string","null"],"example":"Brand X launches new product line"},"text":{"type":["string","null"],"example":"Example article: Brand X announced today..."},"source_name":{"type":["string","null"],"example":"Reuters"},"source_author":{"type":["string","null"],"example":"Jordan Example"},"source_primacy":{"type":["string","null"],"example":"PRIMARY"},"url":{"type":["string","null"],"example":"https://example.com/article"},"published_at":{"type":["string","null"],"example":"2026-04-01T12:00:00Z"},"region":{"type":["string","null"],"example":"us"}},"required":["id","title","text","source_name","source_author","source_primacy","url","published_at","region"]},"CategoryBrand":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","example":"Acme Corp"},"position":{"type":["string","null"],"enum":["LEADER","CHALLENGER","EMERGENT",null],"description":"Competitive position within the category.","example":"LEADER"}},"required":["id","name","position"]},"CategoryDetail":{"type":"object","properties":{"id":{"type":"string","example":"retail"},"name":{"type":"string","example":"Retail"},"parent_id":{"type":["string","null"],"example":null},"brand_count":{"type":"integer","example":42},"description":{"type":["string","null"],"description":"Human-readable category description. Null until populated.","example":null},"status":{"type":"string","enum":["ACTIVE","INACTIVE","RETIRED"],"description":"Lifecycle status. ACTIVE: launched. INACTIVE: not yet launched, or reversibly hidden; brands can still be linked to it. RETIRED: removed from the taxonomy for good; no brand can be linked to it, and superseded_by names its replacement, if any.","example":"ACTIVE"},"tier":{"type":["integer","null"],"description":"Priority tier (1 = highest). Null for parent categories.","example":1},"rollout_phase":{"type":["string","null"],"example":"V1 — Launch"},"est_addressable_brands":{"type":["integer","null"],"example":78},"recommended_brands_count":{"type":["integer","null"],"description":"Count of recommended (Leader/Challenger/Emergent) brands.","example":9},"priority_score":{"type":["number","null"],"description":"Launch priority score (0–100) ranking the subcategory within the rollout.","example":91.7},"superseded_by":{"type":["string","null"],"description":"For a RETIRED category, the subcategory that replaced it, if any.","example":null}},"required":["id","name","parent_id","brand_count","description","status","tier","rollout_phase","est_addressable_brands","recommended_brands_count","priority_score","superseded_by"]},"Category":{"type":"object","properties":{"id":{"type":"string","example":"retail"},"name":{"type":"string","example":"Retail"},"brand_count":{"type":"integer","example":42},"subcategories":{"type":"array","items":{"$ref":"#/components/schemas/CategorySubcategory"},"example":[]}},"required":["id","name","brand_count"]},"CategorySubcategory":{"type":"object","properties":{"id":{"type":"string","example":"apparel"},"name":{"type":"string","example":"Apparel"},"brand_count":{"type":"integer","example":12}},"required":["id","name","brand_count"]},"AudiencePost":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"p1a2c3d4-e5f6-7890-abcd-ef1234567890"},"brand_id":{"type":["string","null"],"format":"uuid","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"platform":{"type":"string","example":"instagram"},"posted_at":{"type":["string","null"],"format":"date-time","example":"2026-03-15T10:30:00Z"},"text":{"type":["string","null"],"example":"Example post: check out our new product launch!"},"media_urls":{"type":["array","null"],"items":{"type":"string"},"example":["https://data.waldo.fyi/v1/media/post/0e1a2b3c-0001-4a5b-8c6d-000000000101/0"],"description":"Images and videos collected with the post, in the platform's order. Fetch or render each as you would any image or video URL. They stay valid, so they are safe to store and embed; media that is no longer available resolves to a placeholder image."},"media_poster_urls":{"type":["array","null"],"items":{"type":["string","null"]},"example":["https://data.waldo.fyi/v1/media/post/0e1a2b3c-0001-4a5b-8c6d-000000000101/poster/0"],"description":"Poster still for each entry in media_urls, index-aligned with it. Null at an index whose media has no poster (every image entry, and video on platforms that send none), and null for the whole field when none do. Posters are kept out of media_urls so metadata.media_type still reads a video post as video."},"hashtags":{"type":"array","items":{"type":"string"},"example":["launch","newproduct"],"description":"Derived from post text when the collected column is empty; values are tag names without the # prefix"},"url":{"type":["string","null"],"example":"https://www.instagram.com/p/EXAMPLE1/"},"region":{"type":["string","null"],"example":"us","description":"Market region of the source profile that published the post (e.g. \"us\"). Null on rows collected before region stamping. Filter the list endpoint with ?region=."},"author":{"type":"object","properties":{"handle":{"type":["string","null"],"example":"@example_brand"},"name":{"type":["string","null"],"example":"Example Brand"}},"required":["handle","name"]},"likes":{"type":["integer","null"],"example":342,"description":"Like/reaction count. Populated on every platform except YouTube; null where unavailable."},"comments":{"type":["integer","null"],"example":12,"description":"Comment/reply count. Same platform coverage as likes."},"views":{"type":["integer","null"],"example":15000,"description":"Video view count. Populated on TikTok/YouTube/Twitter and most Instagram; null on platforms without a public view count (Facebook, Reddit, LinkedIn)."},"analysis":{"$ref":"#/components/schemas/PostAnalysis"},"fetched_at":{"type":"string","format":"date-time","example":"2026-04-01T12:00:00Z"}},"required":["id","brand_id","platform","posted_at","text","media_urls","media_poster_urls","hashtags","url","region","author","likes","comments","views","analysis","fetched_at"]},"PostAnalysis":{"type":["object","null"],"properties":{"tone":{"type":["string","null"],"enum":["aspirational","authoritative","celebratory","comedic","defensive","educational","informational","promotional","urgent",null],"example":"promotional"},"content_type":{"type":["string","null"],"description":"Content classification. Owned-media posts use: announcement, product, promo, educational, community, culture, recap, case_study, other.","example":"promo"},"hook":{"type":["string","null"],"example":"Ask yourself: is your skincare actually working?"},"angle":{"type":["string","null"],"example":"problem-solution"},"topic_tags":{"type":"array","items":{"type":"string"},"example":["womens-sneakers","new-collection","lifestyle"]},"entities":{"type":"array","items":{"$ref":"#/components/schemas/PostAnalysisEntity"},"example":[{"type":"product","value":"PUMA Cali Women's Sneakers"},{"type":"category","value":"Sneakers"}]},"brands":{"type":"array","items":{"type":"string"},"example":["PUMA"]},"audiences":{"type":"array","items":{"type":"string"},"example":["women","sneaker-enthusiasts","lifestyle-shoppers"]},"industries":{"type":"array","items":{"type":"string"},"example":["apparel","footwear","sportswear"]},"on_screen_text":{"type":["string","null"],"example":"EXAMPLE BRAND · NEW SEASON — 30% OFF · SHOP NOW"},"findable":{"$ref":"#/components/schemas/PostAnalysisFindable"},"analyzed_at":{"type":["string","null"],"example":"2026-06-02T16:04:00Z"}},"required":["tone","content_type","hook","angle","topic_tags","entities","brands","audiences","industries","on_screen_text","findable","analyzed_at"],"description":"Analyzer enrichment (tone, topic tags, entities, audiences, etc.). Null on rows that have not yet been analyzed."},"PostAnalysisFindable":{"type":["object","null"],"properties":{"answers_questions":{"type":"array","items":{"type":"string"},"description":"Brand-contextual questions the post answers, for AI-answer optimization. Present on roughly half of analyzed posts.","example":["What is PUMA giving away?"]}}},"PostAnalysisEntity":{"type":"object","properties":{"type":{"type":"string","example":"product"},"value":{"type":"string","example":"PUMA Cali Women's Sneakers"}},"required":["type","value"]},"AudienceInsights":{"type":"object","properties":{"audience_id":{"type":"string","example":"gen-z-foodies"},"brand_count":{"type":"integer","example":34},"top_brands":{"type":"array","items":{"$ref":"#/components/schemas/AudienceBrand"}},"top_content":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"p1a2c3d4-e5f6-7890-abcd-ef1234567890"},"brand_id":{"type":"string","format":"uuid","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"platform":{"type":"string","example":"instagram"},"text":{"type":["string","null"],"example":"Example post: check out our new menu!"},"posted_at":{"type":["string","null"],"example":"2026-03-15T10:30:00Z"}},"required":["id","brand_id","platform","text","posted_at"]}},"top_themes":{"type":"array","items":{"type":"object","properties":{"theme":{"type":"string","example":"product-launch"},"frequency":{"type":"integer","example":42}},"required":["theme","frequency"]},"description":"Top topic tags across the audience's posts, by frequency (max 10). Mirrors owned-media/summary top_themes."}},"required":["audience_id","brand_count","top_brands","top_content","top_themes"]},"AudienceBrand":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","example":"Acme Corp"},"relevance_score":{"type":["number","null"],"description":"Deprecated as a fit measure — see meta.linkage.score. Encodes rank_in_category mapped to 0.2 / 0.4 / 0.6 / 0.8, not a measured score. Null on a curated link that was never scored.","example":0.8},"link":{"$ref":"#/components/schemas/AudienceBrandLink"}},"required":["id","name","relevance_score","link"]},"AudienceBrandLink":{"type":"object","properties":{"basis":{"type":"string","enum":["CATEGORY_TEMPLATE","CURATED","LEARNED"],"description":"How the link was derived. `CATEGORY_TEMPLATE`: projected from the brand's category via the category→audience template (assigned, not measured). `CURATED`: hand-asserted by an admin. `LEARNED`: reserved for future learned linkage — nothing emits it yet.","example":"CATEGORY_TEMPLATE"},"measured":{"type":"boolean","description":"Whether the link reflects analysis of the brand's own data. Always false for CATEGORY_TEMPLATE and CURATED; true only for LEARNED once it exists.","example":false},"via_category":{"type":["object","null"],"properties":{"id":{"type":"string","example":"apparel-fashion-luxury-designer"},"name":{"type":"string","example":"Luxury & Designer"}},"required":["id","name"],"description":"The brand category that associated it with this audience. Present for CATEGORY_TEMPLATE links; null for CURATED links."},"rank_in_category":{"type":["integer","null"],"description":"Position of this audience within that category's template (1 = strongest … 4 = weakest), which is what relevance_score encodes. Null for CURATED links.","example":1}},"required":["basis","measured","via_category","rank_in_category"]},"AudienceSource":{"type":"object","properties":{"type":{"type":"string","enum":["subreddit","influencer","podcast","substack"],"example":"subreddit"},"kind":{"type":"string","description":"How the collector polls this source. `identify_only` means the source is listed but not collected (e.g. audio-only podcasts).","example":"reddit_subreddit"},"value":{"type":"string","description":"Pollable identifier (subreddit name, @handle, channel slug, RSS URL).","example":"programming"},"route":{"type":["string","null"],"description":"Discoverer route classification. Canonical values: `affiliator` (sources that orbit the audience — subreddits, creators they follow), `consumer` (sources the audience produces or subscribes to). The discoverer may emit other values as the taxonomy evolves.","example":"affiliator"},"confidence":{"type":["string","null"],"description":"Discoverer's qualitative confidence. Canonical values: `high`, `medium`, `low`.","example":"high"},"recurrence":{"type":["integer","null"],"description":"How many discovery passes surfaced this source.","example":5},"fit_score":{"type":["number","null"],"description":"Audience-overlap confidence (0-1). Null when not overlap-verified.","example":0.85},"cluster":{"type":["string","null"],"example":"general dev hub"},"receipts":{"type":"array","items":{"type":"string"},"description":"Provenance breadcrumbs the discoverer recorded for this source.","example":["reddit_search_communities top result","consistently ~7 posts/run"]},"notes":{"type":["string","null"],"example":"Core front-page dev community; broad signal across languages."},"members":{"type":["object","null"],"properties":{"value":{"type":"number","example":14200000},"collected_at":{"type":["string","null"],"example":"2026-07-20T14:03:00.000Z"}},"required":["value","collected_at"],"description":"Subscriber/member count with the timestamp it was collected. Null for non-subreddit sources and for subreddits whose count hasn't been captured yet. The figure is a point-in-time snapshot captured at discovery or a later backfill, not live."}},"required":["type","kind","value","route","confidence","recurrence","fit_score","cluster","receipts","notes","members"]},"LanguageMeta":{"allOf":[{"$ref":"#/components/schemas/ConversationsMeta"},{"type":"object","properties":{"clustered_post_count":{"type":["integer","null"],"description":"Distinct posts that landed in any theme of the set — the set-wide denominator every `lift` was computed against. NOT the scope's post count, which also counts posts left in no theme, and not the sum of the themes' sizes, since a post belonging to two themes is counted once here and once in each of them. null on a set refreshed before this was recorded, and null whenever `state` is not CLUSTERED, there being no set to have a denominator."},"state":{"type":"string","enum":["CLUSTERED","PENDING_FIRST_REFRESH","BELOW_FLOOR"],"description":"Why the response looks the way it does — read it before the data. CLUSTERED: a stored cluster set was read. Carrying no themes is then usually a real answer about the audience, meaning the set holds nothing matching this endpoint; where this meta also carries `intent_classified` or `awareness_classified`, read that too, because false there means the set predates that classification and the emptiness reflects the set's age rather than the audience. A set is served for as long as one exists, so an audience that has dropped below `min_scope_posts` since its last refresh still reports CLUSTERED, off a set that is no longer being refreshed — compare `window_end` against now. PENDING_FIRST_REFRESH: no set exists yet and the audience is above `min_scope_posts`, so the response carries nothing for a reason that has nothing to do with the audience, and real themes appear at its next weekly refresh. BELOW_FLOOR: no set exists and the audience is under `min_scope_posts`, so it is not clustered at all and this endpoint has no tag-derived mode to fall back on — nothing until the audience grows. /conversations serves that same audience tag-derived themes and reports TOPIC_TAGS instead, so the two endpoints disagree about the same audience by design."},"min_scope_posts":{"type":"integer","description":"Clusterable posts an audience must carry in the rolling window before it is clustered at all. A build-time constant, published so a BELOW_FLOOR or TOPIC_TAGS response carries its own threshold rather than leaving it to the docs. Not a measurement of this audience — its own post count is not returned.","example":200}},"required":["clustered_post_count","state","min_scope_posts"]}]},"LanguageTheme":{"type":"object","properties":{"theme_id":{"type":"string","description":"Stable theme identity — the same theme keeps this id across weekly refreshes.","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"label":{"type":["string","null"],"description":"English name for the theme, written by the labeler at refresh time. Always English, whatever language the members are in.","example":"Slow shipping complaints"},"type":{"type":["string","null"],"description":"Aspect × polarity, UPPERCASE_SNAKE.","example":"SHIPPING_NEGATIVE"},"intent":{"type":["string","null"],"description":"Closed-taxonomy intent for the theme — TRIGGER, OBJECTION, NEED, PRAISE, COMPARISON or OTHER. null on cluster sets built before intent classification.","example":"TRIGGER"},"awareness_stage":{"type":["string","null"],"description":"Closed-taxonomy funnel position for the theme — UNAWARE, PROBLEM_AWARE, SOLUTION_AWARE, PRODUCT_AWARE, MOST_AWARE or INDETERMINATE. Orthogonal to `intent`: intent is what kind of thing the theme is, this is where in the funnel the people in it stand. INDETERMINATE means no legible stance, not a sixth stage. null on cluster sets built before awareness classification.","example":"PROBLEM_AWARE"},"size":{"type":"integer","description":"Posts assigned to this theme."},"share":{"type":"number","description":"size / scope post count."},"confidence":{"type":"number","description":"Composite of size, content depth, author diversity, and cross-refresh persistence (0–1)."},"top_author_share":{"type":"number","description":"Fraction of the theme's posts by its single most prolific author — a megaphone signal."},"first_observed":{"type":"string","description":"When this theme was first seen (ISO 8601)."},"verbatim_examples":{"type":"array","items":{"$ref":"#/components/schemas/Verbatim"}},"terms":{"type":"array","items":{"$ref":"#/components/schemas/ThemeTerm"},"description":"The theme's distinctive vocabulary, mined from its members' text at the set's last weekly refresh and ordered by lift. Counted over the members approved at that moment, which is what makes it reconcile with the theme's `size`; a post approved or rejected since is reflected at the next refresh, not on this read. Empty when no term clears both floors (2 posts within the theme, 5 across the set), and on a set clustered before vocabulary was recorded. Function words are removed with an ENGLISH stopword list, so a predominantly non-English theme surfaces some of its own function words. Accented and non-Latin words are kept, but single-character tokens are not, which excludes one-character CJK words."}},"required":["theme_id","label","type","intent","awareness_stage","size","share","confidence","top_author_share","first_observed","verbatim_examples","terms"]},"ThemeTerm":{"type":"object","properties":{"term":{"type":"string","description":"The word or adjacent word pair, lowercased. Never stemmed — these are words the audience actually typed.","example":"next day"},"ngram":{"type":"integer","description":"1 for a single word, 2 for an adjacent pair. Pairs require strict adjacency in the source text, so a phrase separated by a function word (\"worth the money\") forms no pair.","example":2},"post_count":{"type":"integer","description":"Distinct posts of this theme containing the term — occurrences within one post count once, so a single repetitive poster cannot manufacture shared vocabulary. At least 2.","example":6},"set_post_count":{"type":"integer","description":"Distinct posts across the WHOLE cluster set containing the term — the raw count behind lift's denominator, and always at least 5. Never below `post_count`, since a theme's posts are a subset of the set's. A term whose set count barely exceeds its theme count is one this theme has almost to itself, which is what a high lift reports.","example":14},"lift":{"type":"number","description":"The theme's rate of this term divided by the whole cluster set's rate. Above 1 means the theme over-uses it relative to the audience overall; terms are ordered by this, not by raw frequency. Fully reproducible from the response: (post_count / the theme's `size`) ÷ (set_post_count / `meta.clustered_post_count`). All four inputs are counted over the same approved members at the same refresh, so they reconcile exactly.","example":3.4}},"required":["term","ngram","post_count","set_post_count","lift"]},"ObjectionsMeta":{"allOf":[{"$ref":"#/components/schemas/ConversationsMeta"},{"type":"object","properties":{"state":{"type":"string","enum":["CLUSTERED","PENDING_FIRST_REFRESH","BELOW_FLOOR"],"description":"Why the response looks the way it does — read it before the data. CLUSTERED: a stored cluster set was read. Carrying no themes is then usually a real answer about the audience, meaning the set holds nothing matching this endpoint; where this meta also carries `intent_classified` or `awareness_classified`, read that too, because false there means the set predates that classification and the emptiness reflects the set's age rather than the audience. A set is served for as long as one exists, so an audience that has dropped below `min_scope_posts` since its last refresh still reports CLUSTERED, off a set that is no longer being refreshed — compare `window_end` against now. PENDING_FIRST_REFRESH: no set exists yet and the audience is above `min_scope_posts`, so the response carries nothing for a reason that has nothing to do with the audience, and real themes appear at its next weekly refresh. BELOW_FLOOR: no set exists and the audience is under `min_scope_posts`, so it is not clustered at all and this endpoint has no tag-derived mode to fall back on — nothing until the audience grows. /conversations serves that same audience tag-derived themes and reports TOPIC_TAGS instead, so the two endpoints disagree about the same audience by design."},"min_scope_posts":{"type":"integer","description":"Clusterable posts an audience must carry in the rolling window before it is clustered at all. A build-time constant, published so a BELOW_FLOOR or TOPIC_TAGS response carries its own threshold rather than leaving it to the docs. Not a measurement of this audience — its own post count is not returned.","example":200}},"required":["state","min_scope_posts"]}]},"ObjectionTheme":{"allOf":[{"$ref":"#/components/schemas/ConversationCluster"},{"type":"object","properties":{"type":{"type":["string","null"],"description":"Aspect × polarity, UPPERCASE_SNAKE. The labeler's call over the WHOLE theme, so it can disagree with the objecting subset — a PRICING_POSITIVE theme carrying 3+ negative members is returned here, and that disagreement is signal, not an error.","example":"SHIPPING_NEGATIVE"},"objection_size":{"type":"integer","description":"Currently-approved members of this theme whose post carries NEGATIVE sentiment polarity — the objecting subset. At least 3, the floor a theme must clear to appear here at all.","example":7},"objection_share_of_theme":{"type":"number","description":"objection_size / the theme's currently-approved member count. Both sides are counted live at read time, so this is not `objection_size / size` — `size` is frozen at the last refresh.","example":0.35},"objection_top_author_share":{"type":"number","description":"Fraction of the objecting subset posted by its single most prolific author — the megaphone signal for the pushback specifically, where `top_author_share` measures the whole theme. Unattributed posts count toward the denominator but never toward the max, so an all-anonymous subset reads 0.","example":0.29},"objection_aspects":{"type":"array","items":{"$ref":"#/components/schemas/ObjectionAspect"},"description":"What the pushback is about, by `sentiment_aspect`, most frequent first (ties alphabetical). Empty when no negative member carries an aspect label."}},"required":["objection_size","objection_share_of_theme","objection_top_author_share","objection_aspects"]}]},"ObjectionAspect":{"type":"object","properties":{"aspect":{"type":"string","description":"What the pushback is about — the analyzer's `sentiment_aspect` label (e.g. price, quality, service, delivery, brand-image). Mostly a closed vocabulary; occasional off-list near-misses pass through unchanged. `other` is a real bucket, not an error. Members with no aspect are counted in `objection_size` but appear in no entry here.","example":"price"},"frequency":{"type":"integer","description":"Count of the theme's negative members carrying this aspect. Sums to at most `objection_size` — the shortfall is members with no aspect label.","example":7}},"required":["aspect","frequency"]},"ConversationCluster":{"type":"object","properties":{"theme_id":{"type":"string","description":"Stable theme identity — under meta.source CLUSTERS the same theme keeps this id across weekly refreshes. Under TOPIC_TAGS it is derived from the tag instead, so it is stable for as long as the tag keeps appearing but is re-minted when the audience crosses the clustering floor and real themes take over. Under TOPIC_TAGS_ONLY it is likewise tag-derived and stable for as long as the tag keeps appearing, but there is no floor and no crossing: the scope is never clustered, so the id never churns into a cluster id. Do not treat an id as comparable across modes, or across scopes.","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"label":{"type":["string","null"],"description":"Human-readable name for the theme. Under meta.source CLUSTERS this is the labeler's 3-6 word English phrase. Under TOPIC_TAGS and TOPIC_TAGS_ONLY there is no labeler: it is the analyzer's topic tag, de-hyphenated and sentence-cased, so it reads as one or two words rather than a written phrase.","example":"Slow shipping complaints"},"type":{"type":["string","null"],"description":"Aspect × polarity, UPPERCASE_SNAKE. Under meta.source CLUSTERS this is the labeler's call over the whole theme. Always null under TOPIC_TAGS and TOPIC_TAGS_ONLY: no labeler runs in either, and the post analyzer writes topic tags but deliberately no sentiment, so there is no aspect or polarity to derive one from — a null here in those modes says nothing about the theme.","example":"SHIPPING_NEGATIVE"},"intent":{"type":["string","null"],"description":"Closed-taxonomy intent for the theme — TRIGGER, OBJECTION, NEED, PRAISE, COMPARISON or OTHER. null on cluster sets built before intent classification, and always null under meta.source TOPIC_TAGS and TOPIC_TAGS_ONLY, neither of which classifies anything.","example":"TRIGGER"},"awareness_stage":{"type":["string","null"],"description":"Closed-taxonomy funnel position for the theme — UNAWARE, PROBLEM_AWARE, SOLUTION_AWARE, PRODUCT_AWARE, MOST_AWARE or INDETERMINATE. Orthogonal to `intent`: intent is what kind of thing the theme is, this is where in the funnel the people in it stand. INDETERMINATE means no legible stance, not a sixth stage. null on cluster sets built before awareness classification, and always null under meta.source TOPIC_TAGS and TOPIC_TAGS_ONLY — the stage is classified from a cluster set's own members, and a tag is not a cluster.","example":"PROBLEM_AWARE"},"size":{"type":"integer","description":"Posts assigned to this theme."},"share":{"type":"number","description":"size / scope post count."},"confidence":{"type":"number","description":"Composite of size, content depth, author diversity and cross-refresh persistence (0–1). The persistence term only contributes under meta.source CLUSTERS, where a theme can carry over from the prior refresh; under TOPIC_TAGS and TOPIC_TAGS_ONLY the themes are computed per request and nothing carries, so that term scores zero and values read up to 0.2 lower — do not compare confidence across modes."},"top_author_share":{"type":"number","description":"Fraction of the theme's posts by its single most prolific author — a megaphone signal."},"first_observed":{"type":"string","description":"When this theme was first seen (ISO 8601). Under meta.source CLUSTERS this is stored at refresh time and does not move. Under TOPIC_TAGS and TOPIC_TAGS_ONLY it is the earliest in-window post carrying the tag, so it advances as older posts age out of the rolling window — theme age is not comparable across modes."},"verbatim_examples":{"type":"array","items":{"$ref":"#/components/schemas/Verbatim"}}},"required":["theme_id","label","type","intent","awareness_stage","size","share","confidence","top_author_share","first_observed","verbatim_examples"]},"AwarenessMeta":{"allOf":[{"$ref":"#/components/schemas/ConversationsMeta"},{"type":"object","properties":{"other_share":{"type":["number","null"],"description":"Set-level residual — the fraction of scope posts in no theme at all, and so at no awareness stage. The levels' shares plus this sum to 1 only when every theme in the set carries a stage."},"awareness_classified":{"type":"boolean","description":"Whether the cluster set read has been awareness-classified. false means the set predates classification — every level being empty reflects that, not an audience whose themes sit at no stage. Resolves at the audience's next weekly refresh; a scope that stays below the clustering post floor keeps its old set and stays false indefinitely."},"state":{"type":"string","enum":["CLUSTERED","PENDING_FIRST_REFRESH","BELOW_FLOOR"],"description":"Why the response looks the way it does — read it before the data. CLUSTERED: a stored cluster set was read. Carrying no themes is then usually a real answer about the audience, meaning the set holds nothing matching this endpoint; where this meta also carries `intent_classified` or `awareness_classified`, read that too, because false there means the set predates that classification and the emptiness reflects the set's age rather than the audience. A set is served for as long as one exists, so an audience that has dropped below `min_scope_posts` since its last refresh still reports CLUSTERED, off a set that is no longer being refreshed — compare `window_end` against now. PENDING_FIRST_REFRESH: no set exists yet and the audience is above `min_scope_posts`, so the response carries nothing for a reason that has nothing to do with the audience, and real themes appear at its next weekly refresh. BELOW_FLOOR: no set exists and the audience is under `min_scope_posts`, so it is not clustered at all and this endpoint has no tag-derived mode to fall back on — nothing until the audience grows. /conversations serves that same audience tag-derived themes and reports TOPIC_TAGS instead, so the two endpoints disagree about the same audience by design."},"min_scope_posts":{"type":"integer","description":"Clusterable posts an audience must carry in the rolling window before it is clustered at all. A build-time constant, published so a BELOW_FLOOR or TOPIC_TAGS response carries its own threshold rather than leaving it to the docs. Not a measurement of this audience — its own post count is not returned.","example":200}},"required":["awareness_classified","state","min_scope_posts"]}]},"AwarenessLevel":{"type":"object","properties":{"level":{"type":"string","description":"Awareness stage — UNAWARE, PROBLEM_AWARE, SOLUTION_AWARE, PRODUCT_AWARE, MOST_AWARE or INDETERMINATE. All six are always present, in that funnel order, whether or not any theme sits at the stage.","example":"PROBLEM_AWARE"},"theme_count":{"type":"integer","description":"Themes classified at this stage."},"post_count":{"type":"integer","description":"Posts across those themes — the sum of their `size`."},"share":{"type":"number","description":"Sum of the stage's themes' shares of the scope post count. Levels do NOT sum to 1: `meta.other_share` covers posts in no theme at all, and themes on a set built before awareness classification carry no stage and are counted at no level."},"themes":{"type":"array","items":{"$ref":"#/components/schemas/ConversationCluster"},"description":"The stage's themes, largest first. `verbatim_examples` is empty unless `verbatim_limit` is passed."}},"required":["level","theme_count","post_count","share","themes"]},"TriggersMeta":{"allOf":[{"$ref":"#/components/schemas/ConversationsMeta"},{"type":"object","properties":{"other_share":{"type":["number","null"],"description":"Set-level residual — the fraction of scope posts in no theme at all. Not relative to the intent filter: on a filtered response the returned shares plus other_share sum to less than 1, the remainder being themes of other intents."},"intent_classified":{"type":"boolean","description":"Whether the cluster set read has been intent-classified. false means the set predates classification — the empty list reflects that, not an audience with no trigger themes. Resolves at the audience's next weekly refresh; a scope that stays below the clustering post floor keeps its old set and stays false indefinitely. Only meaningful under `state` CLUSTERED: with no set read there is nothing to have classified, and this reports false."},"state":{"type":"string","enum":["CLUSTERED","PENDING_FIRST_REFRESH","BELOW_FLOOR"],"description":"Why the response looks the way it does — read it before the data. CLUSTERED: a stored cluster set was read. Carrying no themes is then usually a real answer about the audience, meaning the set holds nothing matching this endpoint; where this meta also carries `intent_classified` or `awareness_classified`, read that too, because false there means the set predates that classification and the emptiness reflects the set's age rather than the audience. A set is served for as long as one exists, so an audience that has dropped below `min_scope_posts` since its last refresh still reports CLUSTERED, off a set that is no longer being refreshed — compare `window_end` against now. PENDING_FIRST_REFRESH: no set exists yet and the audience is above `min_scope_posts`, so the response carries nothing for a reason that has nothing to do with the audience, and real themes appear at its next weekly refresh. BELOW_FLOOR: no set exists and the audience is under `min_scope_posts`, so it is not clustered at all and this endpoint has no tag-derived mode to fall back on — nothing until the audience grows. /conversations serves that same audience tag-derived themes and reports TOPIC_TAGS instead, so the two endpoints disagree about the same audience by design."},"min_scope_posts":{"type":"integer","description":"Clusterable posts an audience must carry in the rolling window before it is clustered at all. A build-time constant, published so a BELOW_FLOOR or TOPIC_TAGS response carries its own threshold rather than leaving it to the docs. Not a measurement of this audience — its own post count is not returned.","example":200}},"required":["intent_classified","state","min_scope_posts"]}]},"ConversationThemesMeta":{"allOf":[{"$ref":"#/components/schemas/ConversationsMeta"},{"type":"object","properties":{"total":{"type":"integer","description":"Under CLUSTERS, the number of themes in the set, which is the length of `data`. Under TOPIC_TAGS, every distinct theme over the scope's in-window posts, which is NOT the length of `data` once the count exceeds `theme_limit`.","example":60},"total_pages":{"type":"integer","description":"Always 1 for a non-empty response (0 for an empty one). This endpoint does not page, so this is not ceil(total / limit) — under TOPIC_TAGS, compare `total` against `theme_limit` to see whether themes were cut.","example":1},"set_version":{"type":["integer","null"],"description":"Version of the cluster set read, or null when no stored set was read. Null does NOT mean 'no data' on its own — read it with meta.state, which names which of the two null cases this is: TOPIC_TAGS means the audience is below the clustering floor and these themes came from analyzer tags, PENDING_FIRST_REFRESH means it is above the floor but has not been clustered yet (and the list is empty)."},"other_share":{"type":["number","null"],"description":"Fraction of scope posts in no theme. Under CLUSTERS that is the noise plus sub-floor residual of the stored set. Under TOPIC_TAGS it is the fraction of in-window scope posts carrying no topic tag at all. Null in two cases: no stored set was read (the above-floor-not-yet-clustered response, where the list is empty), and — under TOPIC_TAGS — a window holding no scope posts to take a fraction of."},"source":{"type":"string","enum":["CLUSTERS","TOPIC_TAGS"],"description":"Which machine produced these themes. CLUSTERS is the stored clustering layer. TOPIC_TAGS is the sub-floor fallback used while the audience has too few posts to cluster: themes are analyzer topic tags rather than embedded clusters, so `type` and `intent` are null, `confidence` is lower, and — because a post carries up to three tags where clusters are disjoint — the shares overlap and do not sum to 1. This answers what built `data`; read `state` for why the response looks the way it does, since CLUSTERS covers both a real set and an audience that has none yet."},"state":{"type":"string","enum":["CLUSTERED","TOPIC_TAGS","PENDING_FIRST_REFRESH"],"description":"Why `data` looks the way it does — read it before the data. CLUSTERED: a stored cluster set was read. A set is served for as long as one exists, so an audience that has dropped below `min_scope_posts` since its last refresh still reports CLUSTERED rather than TOPIC_TAGS, off a set that is no longer being refreshed — compare `window_end` against now. TOPIC_TAGS: no set exists and the audience sits under `min_scope_posts`, so these themes are analyzer topic tags rather than clusters — the lower-fidelity mode `source` describes. PENDING_FIRST_REFRESH: no set exists yet and the audience is above the floor, so `data` is empty for a reason that has nothing to do with the audience and real themes appear at its next weekly refresh. An empty `data` is only an answer about the audience under CLUSTERED."},"min_scope_posts":{"type":"integer","description":"Clusterable posts an audience must carry in the rolling window before it is clustered at all. A build-time constant, published so a BELOW_FLOOR or TOPIC_TAGS response carries its own threshold rather than leaving it to the docs. Not a measurement of this audience — its own post count is not returned.","example":200},"theme_limit":{"type":["integer","null"],"description":"Under TOPIC_TAGS, the cap on how many themes `data` can hold: the list is the largest `theme_limit` themes by size, so `total > theme_limit` means the smaller themes were cut. The endpoint does not page — `total_pages` is 1 and `next_cursor` null — so the cut tail is not retrievable. Null under CLUSTERS, where the stored set bounds the theme count and no cap applies.","example":50}},"required":["source","state","min_scope_posts","theme_limit"]}]},"LinkageMeta":{"allOf":[{"$ref":"#/components/schemas/Meta"},{"type":"object","properties":{"linkage":{"$ref":"#/components/schemas/Linkage"}},"required":["linkage"]}]},"Linkage":{"type":"object","properties":{"method":{"type":"string","description":"How links in this response were derived: `category_template` (all from the category template), `curated` (all hand-asserted), or `mixed`.","example":"category_template"},"measured":{"type":"boolean","description":"Whether these links reflect analysis of each brand's own data. False for template and curated links; true only once learned linkage exists.","example":false},"summary":{"type":"string","description":"Plain-language explanation of the linkage, including how many links are assigned vs curated.","example":"Brands are linked to this audience because their category is associated with it — not because their own data was analysed. 9 of 9 links here are assigned; 0 are curated."},"score":{"type":"object","properties":{"field":{"type":"string","example":"relevance_score"},"deprecated":{"type":"boolean","description":"relevance_score is retained for compatibility but should not be read as a measured fit.","example":true},"replaced_by":{"type":"string","example":"link.rank_in_category"},"meaning":{"type":"string","example":"Position of this audience in the brand's category template, mapped to 0.2 / 0.4 / 0.6 / 0.8. Not a measured fit."},"distinct_values_in_response":{"type":"integer","description":"How many distinct relevance_score values this response contains.","example":1},"sortable":{"type":"boolean","description":"Whether relevance_score meaningfully orders this response (distinct_values_in_response > 1). Do not rank on it when false.","example":false}},"required":["field","deprecated","replaced_by","meaning","distinct_values_in_response","sortable"]}},"required":["method","measured","summary","score"]},"Audience":{"type":"object","properties":{"id":{"type":"string","example":"gen-z-foodies"},"name":{"type":"string","example":"Gen Z Foodies"},"description":{"type":["string","null"],"example":"Young food enthusiasts aged 18-25"},"top_interests":{"type":"array","items":{"type":"string"},"example":["cooking","restaurants","food photography"]},"brand_count":{"type":"integer","example":34},"family":{"type":["string","null"],"description":"Top-level launch taxonomy family. Null on rows predating the taxonomy.","example":"Consumer lifestyle"},"cluster":{"type":["string","null"],"description":"Mid-level launch taxonomy cluster.","example":"Digital-first professionals & tech enthusiasts"},"granularity":{"type":["string","null"],"description":"Audience breadth: Broad, Mid, or Niche.","example":"Broad"}},"required":["id","name","description","top_interests","brand_count","family","cluster","granularity"]},"AudienceLanguageGap":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"theme_id":{"type":"string","format":"uuid"},"label":{"type":["string","null"]},"size":{"type":"integer"},"share":{"type":"number"},"top_author_share":{"type":"number"},"audience_evidence":{"type":"array","items":{"type":"object","properties":{"post_id":{"type":"string","format":"uuid"},"text":{"type":["string","null"]},"transcript":{"type":["string","null"]},"on_screen_text":{"type":["string","null"]},"truncated":{"type":"boolean","description":"At least one content field is an original-language prefix, capped at 1200 characters."},"url":{"type":["string","null"]},"platform":{"type":"string"},"posted_at":{"type":"string","format":"date-time"}},"required":["post_id","text","transcript","on_screen_text","truncated","url","platform","posted_at"]}},"brand_evidence":{"type":"array","items":{"type":"object","properties":{"post_id":{"type":"string","format":"uuid"},"text":{"type":["string","null"]},"transcript":{"type":["string","null"]},"on_screen_text":{"type":["string","null"]},"truncated":{"type":"boolean","description":"At least one content field is an original-language prefix, capped at 1200 characters."},"url":{"type":["string","null"]},"platform":{"type":"string"},"posted_at":{"type":"string","format":"date-time"}},"required":["post_id","text","transcript","on_screen_text","truncated","url","platform","posted_at"]}},"judgment":{"type":"object","properties":{"status":{"type":"string","enum":["addressed","adjacent","not_observed","insufficient"],"description":"addressed means explicit topical presence, not resolution; adjacent means related messaging; not_observed applies only to the shown evidence excerpts, including when the corpus is partially embedded or posts are truncated; insufficient means the comparison cannot be supported."},"explanation":{"type":"string"},"audience_post_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"brand_post_ids":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["status","explanation","audience_post_ids","brand_post_ids"]}},"required":["theme_id","label","size","share","top_author_share","audience_evidence","brand_evidence","judgment"]}},"meta":{"type":"object","properties":{"request_id":{"type":"string"},"audience_id":{"type":"string"},"brand_id":{"type":"string","format":"uuid"},"total":{"type":"integer"},"next_cursor":{"type":["string","null"]},"set_version":{"type":["integer","null"]},"window_start":{"type":["string","null"],"format":"date-time"},"window_end":{"type":["string","null"],"format":"date-time"},"baseline_created_at":{"type":["string","null"],"format":"date-time"},"baseline_status":{"type":"string","enum":["available","unavailable","stale"]},"embedding_model":{"type":["string","null"]},"audience_posts":{"type":["integer","null"]},"other_share":{"type":["number","null"]},"owned_posts":{"type":["integer","null"]},"embedded_owned_posts":{"type":["integer","null"]},"newest_owned_post_at":{"type":["string","null"],"format":"date-time"},"judgment_model":{"type":"string"},"judgment_cached":{"type":"boolean"},"limitation":{"type":"string"}},"required":["request_id","audience_id","brand_id","total","next_cursor","set_version","window_start","window_end","baseline_created_at","baseline_status","embedding_model","audience_posts","other_share","owned_posts","embedded_owned_posts","newest_owned_post_at","judgment_model","judgment_cached","limitation"]}},"required":["data","meta"]},"EmergingNeedsMeta":{"allOf":[{"$ref":"#/components/schemas/ConversationsMeta"},{"type":"object","properties":{"comparison_status":{"type":"string","enum":["not_clustered","insufficient_history","incompatible_baseline","available"],"description":"available requires matching models, equal positive window lengths and strictly advancing window ends. Incompatible predecessors are not skipped because theme identities only carry across adjacent versions."},"baseline_set_version":{"type":["integer","null"]},"baseline_window_start":{"type":["string","null"],"format":"date-time"},"baseline_window_end":{"type":["string","null"],"format":"date-time"},"elapsed_days":{"type":["number","null"],"exclusiveMinimum":0,"description":"Days between window ends; null unless the comparison is available."},"current_post_count":{"type":["integer","null"]},"baseline_post_count":{"type":["integer","null"]},"embedding_model":{"type":["string","null"]},"baseline_embedding_model":{"type":["string","null"]}},"required":["comparison_status","baseline_set_version","baseline_window_start","baseline_window_end","elapsed_days","current_post_count","baseline_post_count","embedding_model","baseline_embedding_model"]}]},"EmergingNeed":{"allOf":[{"$ref":"#/components/schemas/ConversationCluster"},{"type":"object","properties":{"first_observed":{"type":"string","format":"date-time","description":"Refresh time at which this theme identity was minted; carried forward while it matches. Not the earliest post date or proof of when a need began."},"change_type":{"type":"string","enum":["NEW","RISING"]},"current_volume":{"type":"integer","minimum":0,"description":"Stored current-window theme size; identical to size."},"baseline_volume":{"type":"integer","minimum":0,"description":"Stored preceding-window theme size, or zero when this identity was absent from that set."},"baseline_share":{"type":"number","description":"Theme share of baseline scope posts, or zero for an absent identity."},"onset_velocity":{"type":"number","description":"(current_volume - baseline_volume) / elapsed_days. Change in rolling-window volume per elapsed day; windows overlap."}},"required":["change_type","current_volume","baseline_volume","baseline_share","onset_velocity"]}]},"AspectCluster":{"type":"object","properties":{"aspect":{"type":"string","description":"What the sentiment is about — the analyzer's `sentiment_aspect` label (e.g. price, quality, service, delivery, brand-image). Mostly a closed vocabulary; occasional off-list near-misses pass through unchanged. `other` is a real bucket, not an error.","example":"service"},"frequency":{"type":"integer","description":"Count of mentions carrying this aspect at the endpoint's polarity, over the whole match set (not just the examples/sources below, which are bounded samples).","example":42},"intensity":{"type":["string","null"],"enum":["LOW","MEDIUM","HIGH",null],"description":"Modal `sentiment_intensity` across the aspect's mentions — the most common bucket, ties broken toward the more severe. Null only if none are labeled.","example":"HIGH"},"verbatim_examples":{"type":"array","items":{"$ref":"#/components/schemas/AspectVerbatim"},"description":"Representative post texts for this aspect (max 3), most severe first then most recent. Very short throwaway posts are excluded; an aspect whose posts are all too short returns an empty array."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/AspectSource"},"description":"Per-mention link-backs behind the count (max 15), most recent first. A bounded sample for provenance, not the full set — see `frequency` for the total."}},"required":["aspect","frequency","intensity","verbatim_examples","sources"]},"AspectSource":{"type":"object","properties":{"url":{"type":["string","null"],"example":"https://www.reddit.com/r/example/comments/example1/"},"platform":{"type":"string","example":"reddit"},"author":{"type":"object","properties":{"handle":{"type":["string","null"],"example":"@example_fan"},"name":{"type":["string","null"],"example":"Sam Example"}},"required":["handle","name"]},"date":{"type":["string","null"],"format":"date-time","description":"Publication date of the mention (ISO 8601). Null on undated mentions.","example":"2026-03-15T10:30:00Z"}},"required":["url","platform","author","date"]},"AspectVerbatim":{"type":"object","properties":{"text":{"type":["string","null"],"example":"Example complaint: cancelling my membership took three calls and they still charged me."},"author":{"type":"object","properties":{"handle":{"type":["string","null"],"example":"@example_fan"},"name":{"type":["string","null"],"example":"Sam Example"}},"required":["handle","name"]},"url":{"type":["string","null"],"example":"https://www.reddit.com/r/example/comments/example1/"},"platform":{"type":"string","example":"reddit"}},"required":["text","author","url","platform"]},"MentionsAnalysisMeta":{"allOf":[{"$ref":"#/components/schemas/Meta"},{"type":"object","properties":{"set_version":{"type":["integer","null"],"description":"Version of the cluster set the themes came from. Null when the brand has not been clustered yet."},"window_start":{"type":"string","description":"Start of the period every figure in this response describes (ISO 8601). Taken from the cluster set, not from the request — this endpoint accepts no window, so themes and trend always agree on one period. Falls back to the last 30 days when the brand has no set."},"window_end":{"type":"string","description":"End of that period (ISO 8601). A set's window ends when its refresh ran, so it trails the present by up to one refresh interval."},"other_share":{"type":["number","null"],"description":"Fraction of the clustered population in no theme (noise plus sub-floor residual), as measured at refresh time. Themes therefore do not sum to 1. Null when the brand has no set."},"clustered_post_count":{"type":["integer","null"],"description":"Mentions the clustering read — the denominator behind every theme's share. Null when the brand has no set. Frozen at refresh time and measured under the verdict as it stood THEN, so a mention rejected since can still be counted here; total_mentions applies the current verdict. The two therefore answer slightly different questions, and the difference between them is not a clean subtraction."},"total_mentions":{"type":"integer","description":"Approved mentions in the window across all source types, under the CURRENT verdict. Ordinarily wider than clustered_post_count — news is never clustered, and a mention with no embedding when the refresh ran was invisible to it — but the two are measured at different times, so treat the difference as indicative of what the themes miss rather than as an exact uncovered count."},"undated_count":{"type":"integer","description":"Approved mentions carrying no publication date, counted all-time — absent from total_mentions, the trend series and every theme, since a date-bounded figure would exclude the very rows being counted."},"topic_tags_total":{"type":"integer","description":"Distinct analyzer topic tags in the window. This is the total behind topic_tag_counts — NOT behind top_themes, which is a different vocabulary and a different population. Typically runs to the low hundreds, against the ten tags this endpoint returns."}},"required":["set_version","window_start","window_end","other_share","clustered_post_count","total_mentions","undated_count","topic_tags_total"]}]},"MentionsAnalysis":{"type":"object","properties":{"brand_id":{"type":"string","format":"uuid"},"top_themes":{"type":"array","items":{"$ref":"#/components/schemas/MentionTheme"},"description":"Meaning-based themes across the brand's mentions, largest first. Empty with meta.set_version null until the brand has been clustered — which is distinct from a brand that genuinely has no themes. Built from platform-collected social conversation only: news mentions are excluded from clustering by design, so they appear in total_mentions and never in a theme."},"topic_tag_counts":{"type":"array","items":{"type":"object","properties":{"tag":{"type":"string","example":"product-launch"},"frequency":{"type":"integer"}},"required":["tag","frequency"]},"description":"The lexical view: the ten most frequent analyzer topic tags over the same window, most frequent first. This endpoint takes no paging parameters, so it is always the head of the list — meta.topic_tags_total reports how many distinct tags exist, and /mentions/summary is where the full vocabulary can be paged with themes_limit. Empty when the window's mentions carry no tags (unanalyzed rows contribute none). Each tag round-trips as the `topic` filter on GET /mentions, which a theme label does not — use this to drill into mentions, and top_themes to read what the conversation is about."},"sentiment_trend":{"type":"object","properties":{"direction":{"type":["string","null"],"enum":["IMPROVING","DECLINING","STABLE",null],"description":"Movement in positive share between the window's halves. Null when either half scored nothing."},"change_percentage":{"type":["number","null"],"description":"Second half's positive share minus the first half's, in percentage POINTS (not a relative change). Aggregated over each half's mentions rather than averaging daily percentages."},"data_points":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","example":"2026-06-15"},"scored":{"type":"integer","description":"Mentions that day carrying any sentiment polarity — the denominator behind positive_pct. Published so a day whose share rests on a handful of scored rows is distinguishable from one resting on hundreds; `direction` and `change_percentage` are aggregated over these counts, not over the daily percentages."},"mentions":{"type":"integer","description":"Mentions published that day, as COLLECTED — not reach. Collection favours recent content, so a window's older days are systematically thinner; read the shape of this line with that in mind rather than as a change in how much the brand is discussed."},"positive_pct":{"type":["number","null"],"description":"Share of that day's SCORED mentions reading POSITIVE, 0-100. Null when the day scored nothing — a day with no signal is not 0% positive."}},"required":["date","scored","mentions","positive_pct"]},"description":"One entry per day in the window, including days with no mentions."}},"required":["direction","change_percentage","data_points"]}},"required":["brand_id","top_themes","topic_tag_counts","sentiment_trend"]},"MentionTheme":{"type":"object","properties":{"theme_id":{"type":"string","format":"uuid","description":"Stable identity for the theme across refreshes — carried forward while the theme persists, so week-over-week comparisons track the same conversation."},"theme":{"type":["string","null"],"description":"Generated label for the theme. Prose, not a tag: it is NOT a valid value for the `topic` filter on GET /mentions (that filter matches analyzer topic_tags exactly). Regenerated on every refresh — a persisting theme keeps its theme_id but can be worded differently from one set_version to the next, so track a theme by theme_id and never by this string.","example":"Complaints about delivery delays"},"frequency":{"type":"integer","description":"Mentions assigned to this theme, as of the cluster set in meta.set_version."},"share":{"type":"number","description":"frequency / meta.clustered_post_count — the theme's share of the CLUSTERED population, not of total_mentions."},"positive_count":{"type":"integer"},"neutral_count":{"type":"integer"},"negative_count":{"type":"integer"},"mixed_count":{"type":"integer"},"scored_count":{"type":"integer","description":"Members carrying any sentiment polarity — exactly what the four counts sum to. Members the analyzer has not scored are in none of them, so a low scored_count means thin coverage rather than neutral sentiment. No single sentiment score is published: with roughly half of mentions NEUTRAL, an averaged score tracks neutral volume rather than how people feel."},"top_author_share":{"type":"number","description":"Largest single author's share of the theme's members. A high value marks one account's megaphone rather than a broad conversation. Computed over all members of the theme."},"confidence":{"type":"number","description":"Composite of size, text-length profile, author diversity and cross-refresh persistence — not a model probability."},"type":{"type":["string","null"],"description":"Sentiment aspect the theme is about, paired with a polarity. Regenerated per refresh alongside the label, so the polarity half is NOT a stable signal: a persisting theme can carry a different one at the next set_version without the underlying conversation changing. For how a theme's sentiment actually reads, and for anything tracking it over time, use the member counts above.","example":"PRODUCT_PERFORMANCE_NEGATIVE"},"first_observed":{"type":"string","format":"date-time","description":"When this theme first appeared for the brand, carried forward across refreshes."}},"required":["theme_id","theme","frequency","share","positive_count","neutral_count","negative_count","mixed_count","scored_count","top_author_share","confidence","type","first_observed"]},"MentionsSummary":{"type":"object","properties":{"brand_id":{"type":"string","format":"uuid"},"total_mentions":{"type":"integer","example":248},"undated_count":{"type":"integer","description":"Mentions matching these filters that carry no publication date, and are therefore absent from every windowed figure in this response — `total_mentions`, `mentions_per_day`, `by_source`, `by_platform`, `top_communities`, `top_themes`, `themes_total` and `sentiment_distribution` all exclude them. Counted all-time: the date window is dropped for this figure (a posted_at bound would exclude the very rows being counted), so it does not vary with `period`, `start_date`, or `end_date`. Comparable to the /mentions list only when that call passes no window of its own — an explicit start_date/end_date there excludes undated rows too, and this then counts rows on neither surface.","example":12},"mentions_per_day":{"type":"number","example":8.27},"by_source":{"type":"array","items":{"type":"object","properties":{"source_type":{"type":"string","enum":["SOCIAL","NEWS"],"example":"NEWS"},"count":{"type":"integer","example":142}},"required":["source_type","count"]}},"by_platform":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","example":"reddit"},"count":{"type":"integer","example":87}},"required":["platform","count"]},"description":"Mention volume by platform over the window, descending."},"top_communities":{"type":"array","items":{"type":"object","properties":{"community":{"type":"string","example":"r/running"},"count":{"type":"integer","example":34}},"required":["community","count"]},"description":"Top communities by mention volume over the window (max 10). The subreddit for reddit mentions, else the source domain — derived from the mention URL."},"top_themes":{"type":"array","items":{"type":"object","properties":{"theme":{"type":"string","example":"product-launch"},"frequency":{"type":"integer","example":42}},"required":["theme","frequency"]},"description":"Top topic tags across the brand's mentions in the window, by frequency. Capped by the themes_limit parameter (owned-media/summary returns a fixed top 10 and carries no total)."},"themes_total":{"type":"integer","description":"Distinct topic tags in the window — how many entries top_themes could return. When it exceeds top_themes.length, raise themes_limit to enumerate the rest; these are the values the /mentions topic filter accepts.","example":27},"sentiment_distribution":{"type":"object","properties":{"positive":{"type":"object","properties":{"count":{"type":"integer","example":120},"percentage":{"type":"number","example":48.4}},"required":["count","percentage"]},"neutral":{"type":"object","properties":{"count":{"type":"integer","example":80},"percentage":{"type":"number","example":32.3}},"required":["count","percentage"]},"negative":{"type":"object","properties":{"count":{"type":"integer","example":40},"percentage":{"type":"number","example":16.1}},"required":["count","percentage"]},"mixed":{"type":"object","properties":{"count":{"type":"integer","example":8},"percentage":{"type":"number","example":3.2}},"required":["count","percentage"]}},"required":["positive","neutral","negative","mixed"],"description":"Polarity buckets over the window. `count` is the row count per bucket; `percentage` is the share of labeled mentions in that bucket (0–100, one decimal). Rows with NULL sentiment (not yet analyzed) are excluded — bucket counts sum to the labeled total, not total_mentions. When no rows are labeled in the window, all percentages are 0."},"period":{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}},"required":["start","end"]}},"required":["brand_id","total_mentions","undated_count","mentions_per_day","by_source","by_platform","top_communities","top_themes","themes_total","sentiment_distribution","period"]},"Mention":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"p1a2c3d4-e5f6-7890-abcd-ef1234567890"},"brand_id":{"type":"string","format":"uuid","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"source_type":{"type":["string","null"],"enum":["SOCIAL","NEWS",null],"description":"Source category derived from the platform: SOCIAL for social platforms and review sites, NEWS for web articles.","example":"SOCIAL"},"source_platform":{"type":["string","null"],"example":"reddit"},"author":{"type":"object","properties":{"handle":{"type":["string","null"],"example":"@example_fan"},"name":{"type":["string","null"],"example":"Sam Example"}},"required":["handle","name"],"description":"Same shape as owned-media post authors"},"text":{"type":["string","null"],"example":"Example mention: love their new launch!"},"url":{"type":["string","null"],"example":"https://www.reddit.com/r/example/comments/example1/"},"sentiment_polarity":{"type":["string","null"],"enum":["POSITIVE","NEGATIVE","NEUTRAL","MIXED",null],"description":"Polarity label written by the brand-post analyzer. Null on rows not yet analyzed (existing mentions collected before sentiment classification was wired stay null until re-analyzed).","example":"POSITIVE"},"sentiment_intensity":{"type":["string","null"],"enum":["LOW","MEDIUM","HIGH",null],"description":"Intensity bucket paired with sentiment_polarity; null until analyzed.","example":"MEDIUM"},"sentiment_aspect":{"type":["string","null"],"description":"Free-text label for what the sentiment is about (e.g. pricing, product, leadership), written by the brand-post analyzer alongside polarity/intensity. Null until analyzed.","example":"pricing"},"topic_tags":{"type":"array","items":{"type":"string"},"description":"Topic tags from the brand-post analyzer — the same tags aggregated into /mentions/summary top_themes. Empty on rows not yet analyzed.","example":["product-launch","customer-experience"]},"speaker_type":{"type":["string","null"],"enum":["CUSTOMER","FAN","INFLUENCER","RANDOM","EMPLOYEE","COMPETITOR","PRESS",null],"description":"Who the analyzer judges the author to be relative to the brand: CUSTOMER, FAN, INFLUENCER, RANDOM, EMPLOYEE, COMPETITOR or PRESS. Null on rows not yet analyzed.","example":"CUSTOMER"},"content_type":{"type":["string","null"],"description":"Format the analyzer classified the mention as — product-review, haul, unboxing, comparison, tutorial, news or other. Open string rather than an enum: the vocabulary is per-analyzer and unconstrained in storage. Null on rows not yet analyzed.","example":"product-review"},"source_name":{"type":["string","null"],"description":"Publication or outlet behind the mention, as attributed by the analyzer — distinct from `author`, which is the account that posted it. Populated mainly on NEWS mentions; null on rows not yet analyzed.","example":"Defense News"},"source_author":{"type":["string","null"],"description":"Byline credited by the source, as attributed by the analyzer. Populated mainly on NEWS mentions; null on rows not yet analyzed.","example":"Jordan Example"},"source_primacy":{"type":["string","null"],"enum":["PRIMARY","COVERAGE","ANALYSIS","CURATORIAL",null],"description":"How close the source sits to the story: PRIMARY (the originating report), COVERAGE (a report of that report), ANALYSIS (commentary on it) or CURATORIAL (a roundup that links it). Null on rows not yet analyzed.","example":"PRIMARY"},"language":{"type":["string","null"],"description":"Language the analyzer detected in the post body — a lowercase ISO 639-1 code, or `und` for posts with no readable text. The value the `language` filter matches. Null on rows not yet analyzed.","example":"en"},"likes":{"type":["integer","null"],"example":342,"description":"Like/reaction/upvote count. Populated on most social & forum platforms; null on video-only sources and NEWS."},"comments":{"type":["integer","null"],"example":12,"description":"Comment/reply count. Same coverage as likes."},"shares":{"type":["integer","null"],"example":8,"description":"Share/repost count. Populated where the platform reports it (e.g. TikTok/Facebook/LinkedIn/Twitter); null on Reddit/forums, Instagram, YouTube, and NEWS."},"views":{"type":["integer","null"],"example":15000,"description":"Video/post view count. Populated on view-reporting platforms (e.g. TikTok/YouTube/Twitter and most Instagram); null on Reddit/forums, Facebook, LinkedIn, and NEWS."},"posted_at":{"type":["string","null"],"format":"date-time","example":"2026-03-15T10:30:00Z"},"fetched_at":{"type":"string","format":"date-time","example":"2026-04-01T12:00:00Z"},"discovered_at":{"type":"string","format":"date-time","description":"First-seen-in-Waldo timestamp (alias of fetched_at — the column the post was inserted with).","example":"2026-04-01T12:00:00Z"}},"required":["id","brand_id","source_type","source_platform","author","text","url","sentiment_polarity","sentiment_intensity","sentiment_aspect","topic_tags","speaker_type","content_type","source_name","source_author","source_primacy","language","likes","comments","shares","views","posted_at","fetched_at","discovered_at"]},"CrawlCoverage":{"type":"object","properties":{"brand_id":{"type":"string","format":"uuid"},"period":{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}},"required":["start","end"]},"platforms":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","example":"linkedin"},"coverage_since":{"type":["string","null"],"description":"First day this log holds a crawl-written attempt for the platform (YYYY-MM-DD). Days before it are reported UNKNOWN rather than NOT_CRAWLED — we cannot say whether they were crawled. Null means the log holds no crawl-written attempt yet, so every day in the window is UNKNOWN: either nothing has ever been attempted, or the only records are the backfilled rows reconstructed from an older watermark, which pin down one past crawl but say nothing about the days around it. `last_crawled_at` can therefore be non-null while this is null.","example":"2026-03-01"},"last_crawled_at":{"type":["string","null"],"format":"date-time","description":"Most recent attempt that was not a failure. Null when every attempt failed or none was made.","example":"2026-04-01T05:10:00Z"}},"required":["platform","coverage_since","last_crawled_at"]}},"days":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","example":"2026-04-01"},"platform":{"type":"string","example":"linkedin"},"status":{"type":"string","enum":["CRAWLED","PARTIAL","FAILED","NOT_CRAWLED","UNKNOWN"],"description":"Whether we looked on this day, and how well. CRAWLED — every attempt that day enumerated its whole window, so a zero new-ad count that day is trustworthy. PARTIAL — at least one attempt ran but the day was not fully enumerated: a crawl was cut short (page cap, time budget, incomplete coverage), or one of the platform's identities failed while another succeeded. A non-zero count is a floor and a zero is not trustworthy. FAILED — every attempt that day failed and returned nothing usable. NOT_CRAWLED — no attempt was made; a zero new-ad count that day says nothing about the advertiser. UNKNOWN — the date predates this log for the platform, so whether we crawled it is unknowable. Meta and Google days come from a lookback-windowed library query that floors on start_date: sound evidence for a NEW-ad series, but not a serving-liveness claim.","example":"CRAWLED"},"attempts":{"type":"integer","description":"Collection attempts logged that day across every identity and scope on the platform. 0 on a NOT_CRAWLED or UNKNOWN day.","example":1},"ads_seen":{"type":["integer","null"],"description":"Ads the day's crawls returned — the size of what we enumerated, NOT the count of newly-discovered ads. Null when nothing usable came back (and on days with no attempt); 0 on a successful crawl is a real observation.","example":24}},"required":["date","platform","status","attempts","ads_seen"]}}},"required":["brand_id","period","platforms","days"]},"PaidMediaSummary":{"type":"object","properties":{"brand_id":{"type":"string","format":"uuid"},"total_ads":{"type":"integer","description":"Distinct creatives whose flight overlaps the window — running or ended; `active_ads` is the live subset. Counted as CREATIVES, not ad rows: Meta publishes one ad-library row per creative variant, so an advertiser running Advantage+ or dynamic creative returns hundreds of rows for a handful of ads. Ads sharing a `collation_group_id` count once; an ad carrying none counts as itself. Meta is the only platform that publishes a variant key, so LinkedIn and Google ads each count individually even where an advertiser runs the same copy across several of them.","example":24},"variant_count":{"type":"integer","description":"Creative variants behind `total_ads` — the volume `total_ads` used to report. Heavy variant churn is a real creative-testing signal, it just is not a number of ads. This is Meta's OWN declared size for each variant set (its latest published count at or before the window's end), so it does NOT reconcile to the ad rows `GET /paid-media/ads` returns: Meta counts the variants active in one country at one moment, which runs both above and below what we have collected. Variant sets Meta never sized, and every ad with no variant key (all LinkedIn and Google ads), contribute the ads we hold — one each.","example":310},"active_ads":{"type":"integer","description":"Creatives in the window reading `status=ACTIVE` — a creative counts as active while any one of its variants is still serving. Mixed-platform, so the count is only as live as its weakest arm. On LinkedIn, ACTIVE means \"active in the last 30 days\" rather than \"serving right now\": the platform publishes no flight dates, so liveness comes from its rolling ~30-day activity view, and an ad that stopped serving keeps reading ACTIVE until it drops out of that window. Meta and Google ads carry real start/end dates, so their ACTIVE is a true liveness reading. Carry that caveat into any count you present; `by_platform[].active` splits it per platform.","example":18},"new_ads_in_period":{"type":"integer","description":"Creatives with at least one variant whose start_date falls inside the summary window — the creative appeared in the window, counted once however many of its variants started there. A long-running creative that gained a new variant in the window therefore counts. Reads 0 for a creative whose variants carry no start_date at all, which on LinkedIn is most of them; the `new_ads` time-series counts those by the day they were first seen, so its total exceeds this figure wherever dateless ads are in play.","example":12},"avg_new_ads_per_day":{"type":"number","description":"new_ads_in_period divided by days in the window.","example":0.4},"avg_days_running":{"type":["number","null"],"description":"Mean run length in days over ENDED creatives, measured across the variant set — the earliest start_date to the latest end_date among the variants the window selected. A creative with any still-running variant is open-ended and excluded, as is one missing either date; null when that leaves nothing. Two consequences worth carrying: the span is measured over the window's own variants, so a narrower window reports a shorter flight for the same creative; and measured per variant instead, an advertiser rotating variants daily reads a couple of days while its creatives have run for weeks.","example":17.5},"estimated_total_spend":{"type":["number","null"],"description":"Sum of estimated ad spend over the window. Null when no spend source is available (the absence of data, as distinct from a confirmed $0)."},"by_platform":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string"},"ads":{"type":"integer","description":"Distinct creatives on this platform. Counted as CREATIVES, not ad rows: Meta publishes one ad-library row per creative variant, so an advertiser running Advantage+ or dynamic creative returns hundreds of rows for a handful of ads. Ads sharing a `collation_group_id` count once; an ad carrying none counts as itself. Meta is the only platform that publishes a variant key, so LinkedIn and Google ads each count individually even where an advertiser runs the same copy across several of them."},"ad_count":{"type":"integer","description":"Alias of `ads` — prefer this name; `ads` is retained for backward compatibility."},"variants":{"type":"integer","description":"Creative variants behind this platform's `ads`, on the same basis as the top-level `variant_count`. The `meta` row is where the two diverge sharply; on every other platform it equals `ads`.","example":280},"active":{"type":"integer","description":"Creatives on this platform reading `status=ACTIVE`. On the `linkedin` row read this as \"active in the last 30 days\" rather than serving right now — see `active_ads`.","example":6},"estimated_spend":{"type":["number","null"],"description":"Estimated spend for this platform. Null when no spend source is available."}},"required":["platform","ads","ad_count","variants","active","estimated_spend"]}},"last_crawled_at":{"type":["string","null"],"format":"date-time","description":"When Waldo's ad collection last successfully ran for this brand (the most recent attempt that was not a failure), across every ad platform or the one named by `platform`. Null when no attempt has ever been made OR when every attempt failed — a brand whose vendor credentials have broken reads null, not stale. Deliberately NOT bounded by the summary window — it answers \"when did we last look\", not \"what happened in this window\". A zero or low count beside a stale or null value means we did not look, not that the brand ran nothing; GET /paid-media/crawl-coverage resolves that per day.","example":"2026-04-01T05:10:00Z"},"period":{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}},"required":["start","end"]}},"required":["brand_id","total_ads","variant_count","active_ads","new_ads_in_period","avg_new_ads_per_day","avg_days_running","estimated_total_spend","by_platform","last_crawled_at","period"]},"AdLandingPage":{"type":"object","properties":{"ad_id":{"type":"string","format":"uuid"},"url":{"type":["string","null"],"description":"Normalized destination URL the ad clicks through to (click-tracking params stripped). Null only when the ad carried no landing-page URL.","example":"https://example.com/clifton-9"},"screenshot_url":{"type":["string","null"],"description":"Public Waldo file URL for the full-page screenshot. Null when no capture was taken (see skip_reason).","example":"https://graphql.waldo.fyi/file/b8c4d1e2-f3a4-b5c6-d7e8-f9a0b1c2d3e4"},"captured_at":{"type":["string","null"],"format":"date-time","description":"When the screenshot was captured (ISO 8601). Null on skip.","example":"2026-04-28T14:00:00Z"},"skip_reason":{"type":["string","null"],"enum":["NO_URL","UNRESOLVED_MACRO","APP_STORE","HOMEPAGE",null],"description":"Why no screenshot was taken — NO_URL (ad had no destination), UNRESOLVED_MACRO (URL carried literal {{...}} macros), APP_STORE (app-install link), or HOMEPAGE (bare advertiser homepage, not a campaign LP). Null on a real capture.","example":null}},"required":["ad_id","url","screenshot_url","captured_at","skip_reason"]},"Ad":{"type":"object","properties":{"ad_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"brand_id":{"type":"string","format":"uuid","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"platform":{"type":"string","example":"meta"},"title":{"type":["string","null"],"example":"Spring Sale 2026"},"body":{"type":["string","null"],"example":"Example ad: don't miss our biggest sale of the year!"},"media_urls":{"type":["array","null"],"items":{"type":"string"},"example":["https://data.waldo.fyi/v1/media/ad/0a1b2c3d-0001-4e5f-8a6b-000000000201/0"],"description":"Creative assets for the ad, in the platform's order. Fetch or render each as you would any image or video URL. They stay valid, so they are safe to store and embed; media that is no longer available resolves to a placeholder image."},"targeting":{"type":"object","additionalProperties":{},"example":{"age":"18-34","interests":["fashion"]}},"source_cta":{"type":["object","null"],"properties":{"text":{"type":"string"},"type":{"type":"string"},"url":{"type":"string"}},"description":"CTA captured verbatim from the ad platform at ingest (the platform's own button text/type/URL), as opposed to the analyzer-derived `cta`/`cta_text`. Null when the platform provides none (Google ads, LinkedIn text/InMail ads).","example":{"text":"Example CTA: Learn more","type":"LEARN_MORE","url":"https://example.com/spring"}},"collation_group_id":{"type":["string","null"],"description":"Meta's variant-set grouping key: every creative variant of the same ad shares this id, so ads with a common value are variants of one test. Grouping only — it is not a variant count. The number of collected ads sharing the id is a running total of what we have collected, not the size of the variant set, and can both exceed and fall short of Meta's own count — for example, ads that have stopped running stay counted here after Meta drops them from its active count. Meta-only — null for Google and LinkedIn (no equivalent grouping) and for ads collected before it was captured.","example":"1234567890"},"native_ad_id":{"type":["string","null"],"description":"The advertising platform's own id for this creative, in that platform's namespace — Meta's ad_archive_id (the number the Ad Library prints as \"Library ID\"), LinkedIn's creative id (the same value LinkedIn Campaign Manager reports as creativeId), Google's `CR…` creative id. This is the join key for reconciling Waldo ads against a first-party ad-account export; `ad_id` is Waldo's own UUID and means nothing to the platform. Distinct from `collation_group_id`, which is Meta's variant-set key and is NOT the Library ID. Null on the small tail of rows whose source gave no id.","example":"EXAMPLE1000000001"},"ad_library_url":{"type":["string","null"],"description":"Public permalink to this exact creative in the platform's ad library, built from `native_ad_id` — Meta Ad Library, LinkedIn Ad Library, or Google Ads Transparency Center. Use it to cite a specific ad. Null is a real state, not a gap to retry: the row carries no `native_ad_id`, or (Google only) no captured advertiser id, which its URL also needs.","example":"https://www.facebook.com/ads/library/?id=EXAMPLE1000000001"},"cta":{"type":["string","null"],"enum":["shop_now","learn_more","sign_up","download","watch_more","contact","subscribe","book","install","other",null],"description":"Analyzer-derived CTA type. Null on rows not yet analyzed or with no CTA.","example":"shop_now"},"cta_text":{"type":["string","null"],"description":"Analyzer-derived literal CTA button/link label.","example":"Shop Now"},"on_screen_text":{"type":["string","null"],"description":"Text burned into the creative itself (overlays, end-cards, price/button labels), transcribed verbatim in reading order — distinct from `title`/`body` (the platform caption/headline). Null for text-only ads with no media pass, and on rows not yet analyzed.","example":"EXAMPLE BRAND\n50% OFF\nLimited time"},"promotion":{"$ref":"#/components/schemas/AdPromotion"},"currency":{"type":"string","example":"USD"},"status":{"type":"string","description":"Derived liveness. Dated ads: ACTIVE while end_date is within a short recency grace. Dateless ads (most LinkedIn — the platform exposes no flight dates): ACTIVE while Waldo's daily crawls keep re-encountering the ad (see last_seen_at). On LinkedIn, ACTIVE means \"active in the last 30 days\" rather than \"serving right now\": the platform publishes no flight dates, so liveness comes from its rolling ~30-day activity view, and an ad that stopped serving keeps reading ACTIVE until it drops out of that window. Meta and Google ads carry real start/end dates, so their ACTIVE is a true liveness reading.","example":"ACTIVE"},"start_date":{"type":["string","null"],"example":"2026-03-01"},"end_date":{"type":["string","null"],"example":"2026-03-31"},"landing_page_url":{"type":["string","null"],"description":"Ad destination URL. Sourced from the platform CTA URL (source_cta.url) — populated for Meta ads that carry one; null for Google/LinkedIn until the collector captures a dedicated landing-page URL.","example":"https://example.com/spring"},"days_running":{"type":["integer","null"],"description":"Days the ad has been running: today − start_date while live, frozen at end_date once it has passed. Null until start_date is populated.","example":14},"region":{"type":["string","null"],"example":null},"length_seconds":{"type":["number","null"],"description":"Video duration in seconds for video creatives, read at collection time via a container-level media probe. Null for image-only ads, when the probe failed, or on rows collected before the probe was wired.","example":16.5},"analysis":{"$ref":"#/components/schemas/AdAnalysis"},"first_seen_at":{"type":"string","format":"date-time","description":"When Waldo's crawls first surfaced this ad — our observation timeline, not a platform campaign date (see start_date/end_date for those, where the platform provides them). This is when Waldo first observed the ad, NOT when the advertiser launched it. Ads a brand was already running when we started tracking it all carry the onboarding/backfill date, so first_seen_at values cluster on the days we crawled. Before reading a gap as advertiser inactivity, check GET /paid-media/crawl-coverage: a zero-new-ad day is only trustworthy on a day that endpoint reports as CRAWLED.","example":"2026-03-02T05:10:00Z"},"last_seen_at":{"type":["string","null"],"format":"date-time","description":"Most recent serving-scoped Waldo crawl that observed this ad. Null = never observed serving — the ad was surfaced only via the ad library's historical listing (e.g. at brand activation) and was already outside the platform's activity window. For dateless ads this drives `status`: an ad the daily collection stops seeing (or never saw serving) reads ENDED.","example":"2026-04-01T05:10:00Z"},"fetched_at":{"type":"string","format":"date-time","example":"2026-04-01T12:00:00Z"}},"required":["ad_id","brand_id","platform","title","body","media_urls","targeting","source_cta","collation_group_id","native_ad_id","ad_library_url","cta","cta_text","on_screen_text","promotion","currency","status","start_date","end_date","landing_page_url","days_running","region","length_seconds","analysis","first_seen_at","last_seen_at","fetched_at"]},"AdAnalysis":{"type":["object","null"],"properties":{"tone":{"type":["string","null"],"enum":["aspirational","authoritative","celebratory","comedic","defensive","educational","informational","promotional","urgent",null],"example":"promotional"},"target_aspect":{"type":["string","null"],"example":"product","description":"What the ad promotes. Newly analyzed ads use a closed vocabulary (product, service, brand, category, recruitment, event, membership, course, resource, platform, report, guide, other); older rows may carry legacy free-text values."},"hook":{"type":["string","null"],"example":"Ask yourself: is your skincare actually working?"},"angle":{"type":["string","null"],"example":"problem-solution"},"offers":{"type":"array","items":{"$ref":"#/components/schemas/AdAnalysisOffer"},"example":[{"type":"discount","value":"30% off with code BLOOM (Mar 20–23)"}]},"topic_tags":{"type":"array","items":{"type":"string"},"example":["womens-sneakers","new-collection","lifestyle"]},"entities":{"type":"array","items":{"$ref":"#/components/schemas/AdAnalysisEntity"},"example":[{"type":"product","value":"PUMA Cali Women's Sneakers"},{"type":"category","value":"Sneakers"}]},"brands":{"type":"array","items":{"type":"string"},"example":["PUMA"]},"audiences":{"type":"array","items":{"type":"string"},"example":["women","sneaker-enthusiasts","lifestyle-shoppers"]},"industries":{"type":"array","items":{"type":"string"},"example":["apparel","footwear","sportswear"]},"analyzed_at":{"type":["string","null"],"example":"2026-06-02T16:04:00Z"}},"required":["tone","target_aspect","hook","angle","offers","topic_tags","entities","brands","audiences","industries","analyzed_at"],"description":"Analyzer enrichment (tone, target aspect, entities, audiences, etc.). Null on rows that have not yet been analyzed."},"AdAnalysisEntity":{"type":"object","properties":{"type":{"type":"string","example":"product"},"value":{"type":"string","example":"PUMA Cali Women's Sneakers"}},"required":["type","value"]},"AdAnalysisOffer":{"type":"object","properties":{"type":{"type":"string","example":"discount","description":"Kind of incentive. Newly analyzed ads use a closed vocabulary (discount, free_shipping, bogo, trial, gift, bundle, financing, sweepstakes, rewards, guarantee, fee_waiver, free_service, other); older rows may carry legacy free-text values."},"value":{"type":"string","example":"30% off with code BLOOM"}},"required":["type"]},"AdPromotion":{"type":["object","null"],"properties":{"is_promotional":{"type":"boolean","example":true},"discount_type":{"type":["string","null"],"description":"Open string (not an enum). Pricing mechanic of the primary offer. Newly analyzed ads use: percentage_off, dollar_off, free_trial, bogo, free_shipping, free_gift, bundle, clearance, sitewide_sale, cashback_rewards, financing_offer, other. May be null on older rows even when is_promotional is true.","example":"free_trial"},"discount_value":{"type":["string","null"],"example":"25"},"discount_unit":{"type":["string","null"],"example":"percent"},"discount_text":{"type":["string","null"],"example":"25% off select styles"},"promo_code":{"type":["string","null"],"example":"SPORT25"},"conditions":{"type":["string","null"],"example":"First order only"},"expires_at":{"type":["string","null"],"example":"2026-03-23"},"confidence":{"type":["number","null"],"example":0.9}},"required":["is_promotional","discount_type","discount_value","discount_unit","discount_text","promo_code","conditions","expires_at","confidence"],"description":"Structured offer extracted by the analyzer. Null when the ad carries no promotion or has not been analyzed yet."},"ExecutivePostDetail":{"allOf":[{"$ref":"#/components/schemas/PostDetail"},{"type":"object","properties":{"executive":{"$ref":"#/components/schemas/ExecutiveAttribution"}},"required":["executive"]}]},"ExecutiveAttribution":{"type":["object","null"],"properties":{"id":{"type":"string","format":"uuid","example":"x1a2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","example":"Jane Example"},"title":{"type":["string","null"],"example":"Global Chief Marketing Officer"},"is_top_executive":{"type":"boolean","example":true}},"required":["id","name","title","is_top_executive"]},"PostDetail":{"allOf":[{"$ref":"#/components/schemas/Post"},{"type":"object","properties":{"metadata":{"$ref":"#/components/schemas/PostMetadata"}},"required":["metadata"]}]},"PostMetadata":{"type":"object","properties":{"media_type":{"type":["string","null"],"enum":["image","video","mixed",null],"example":"image","description":"Bucket derived from media_urls extensions: image, video, mixed, or null when there are no URLs or none can be classified."},"language":{"type":["string","null"],"example":"en","description":"ISO 639-1 code detected from `text` via a deterministic library. Null for empty, too-short, or undetermined input."},"transcript":{"type":["string","null"],"example":"Welcome back to the channel — today we're unboxing...","description":"ASR/caption transcript of the post's video or audio. Null when the post has no transcribable media or transcription hasn't run."},"collaborators":{"type":"array","items":{"type":"object","properties":{"handle":{"type":["string","null"],"example":"example_partner"},"name":{"type":["string","null"],"example":"Example Partner"}},"required":["handle","name"]},"description":"Co-authors the brand co-published this post with (the `author` stays the brand); sourced from Instagram `coauthor_producers`. Present only on collaborative posts — its absence is the not-a-collab signal (no boolean is stored). An `invited_collaborators` sibling may be added later."}},"required":["media_type","language","transcript"]},"Post":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"p1a2c3d4-e5f6-7890-abcd-ef1234567890"},"brand_id":{"type":["string","null"],"format":"uuid","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"platform":{"type":"string","example":"instagram"},"posted_at":{"type":["string","null"],"format":"date-time","example":"2026-03-15T10:30:00Z"},"text":{"type":["string","null"],"example":"Example post: check out our new product launch!"},"media_urls":{"type":["array","null"],"items":{"type":"string"},"example":["https://data.waldo.fyi/v1/media/post/0e1a2b3c-0001-4a5b-8c6d-000000000101/0"],"description":"Images and videos collected with the post, in the platform's order. Fetch or render each as you would any image or video URL. They stay valid, so they are safe to store and embed; media that is no longer available resolves to a placeholder image."},"media_poster_urls":{"type":["array","null"],"items":{"type":["string","null"]},"example":["https://data.waldo.fyi/v1/media/post/0e1a2b3c-0001-4a5b-8c6d-000000000101/poster/0"],"description":"Poster still for each entry in media_urls, index-aligned with it. Null at an index whose media has no poster (every image entry, and video on platforms that send none), and null for the whole field when none do. Posters are kept out of media_urls so metadata.media_type still reads a video post as video."},"media_count":{"type":"integer","example":1},"hashtags":{"type":"array","items":{"type":"string"},"example":["launch","newproduct"],"description":"Derived from post text when the collected column is empty; values are tag names without the # prefix"},"url":{"type":["string","null"],"example":"https://www.instagram.com/p/EXAMPLE1/"},"region":{"type":["string","null"],"example":"us","description":"Market region of the source profile that published the post (e.g. \"us\"). Null on rows collected before region stamping. Filter the list endpoint with ?region=."},"author":{"type":"object","properties":{"handle":{"type":["string","null"],"example":"@example_brand"},"name":{"type":["string","null"],"example":"Example Brand"}},"required":["handle","name"]},"likes":{"type":["integer","null"],"example":342,"description":"Like/reaction count. Populated on every platform except YouTube; null where unavailable."},"comments":{"type":["integer","null"],"example":12,"description":"Comment/reply count. Same platform coverage as likes."},"shares":{"type":["integer","null"],"example":8,"description":"Share/repost count. Populated on TikTok/Facebook/LinkedIn/Twitter; null on Instagram and YouTube."},"views":{"type":["integer","null"],"example":15000,"description":"Video/post view count. Populated on TikTok/YouTube/Twitter and most Instagram; null on Facebook and LinkedIn."},"analysis":{"$ref":"#/components/schemas/PostAnalysis"},"is_quote":{"type":"boolean","example":false,"description":"The post quotes another post; `quoted_post` carries that original — author, text and media — and is non-null only when this is true. Populated on X today; false on every other platform (none of the collectors stamps a quote relationship yet)."},"is_retweet":{"type":"boolean","example":false,"description":"The post is a retweet; `retweeted_post` carries the original — author, text and media — and is non-null only when this is true AND the vendor sent the original's body (one level: the original's own quote is not nested). The row is the retweet itself: its own id, author and date, so a retweet of a third party's post never counts as that party's content. Engagement is what the vendor reports for a retweet — likes and comments are 0 and shares mirrors the original's retweet count — so sort or aggregate owned media with `is_retweet` in mind. Depends on the collecting route sending the marker: a post seen only through mention search, where the vendor sends none, reads `false`. A later capture through a route that does send it corrects the value while the post is still unowned; once the post is attributed to a brand or an executive the flag stops changing. Populated on X today; false on every other platform."},"is_reply":{"type":"boolean","example":false,"description":"The post is a reply to another post rather than a thread opener. Populated on X today; false on every other platform."},"quoted_post":{"$ref":"#/components/schemas/SharedPost"},"retweeted_post":{"$ref":"#/components/schemas/SharedPost"},"fetched_at":{"type":"string","format":"date-time","example":"2026-04-01T12:00:00Z","description":"When collection wrote the post record. It does not move when the engagement counts are refreshed — use `metrics_captured_at` for the age of `likes`, `comments`, `shares` and `views`."},"metrics_captured_at":{"type":"string","format":"date-time","example":"2026-04-03T08:15:00Z","description":"When `likes`, `comments`, `shares` and `views` were last observed on the platform. Counts are refreshed while the post is inside the daily collection window (its first few days) and whenever the post is re-read live, so an older post's counts can be well behind the platform; compare against this timestamp."}},"required":["id","brand_id","platform","posted_at","text","media_urls","media_poster_urls","media_count","hashtags","url","region","author","likes","comments","shares","views","analysis","is_quote","is_retweet","is_reply","quoted_post","retweeted_post","fetched_at","metrics_captured_at"]},"SharedPost":{"type":["object","null"],"properties":{"id":{"type":"string","example":"1000000000000000001"},"url":{"type":"string","example":"https://x.com/example_user/status/1000000000000000001"},"published_at":{"type":["string","null"],"format":"date-time","example":"2026-03-15T09:02:00Z"},"author":{"type":"object","properties":{"handle":{"type":["string","null"],"example":"example_user"},"name":{"type":["string","null"],"example":"Alex Example"}},"required":["handle","name"]},"text":{"type":"string","example":"Example post: the body of the nested post."},"media_urls":{"type":"array","items":{"type":"string"},"example":["https://media.example.com/posts/1.jpg"]}},"required":["id","url","published_at","author","text","media_urls"],"description":"A post nested inside another: the quoted post on a quote tweet, or the retweeted original on a retweet. Identity, author, text and media of the nested post itself."},"ExecutivePost":{"allOf":[{"$ref":"#/components/schemas/Post"},{"type":"object","properties":{"executive":{"$ref":"#/components/schemas/ExecutiveAttribution"}},"required":["executive"]}]},"Executive":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"x1a2c3d4-e5f6-7890-abcd-ef1234567890"},"brand_id":{"type":"string","format":"uuid","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","example":"Jane Example"},"title":{"type":["string","null"],"description":"The person's title verbatim as the brand publishes it — not normalized, not translated, not mapped to an enum. Use `is_top_executive` to filter priority voices programmatically.","example":"Global Chief Marketing Officer"},"is_top_executive":{"type":"boolean","description":"True when the person fills one of the brand's priority voices (the CEO or CMO slot, or its closest equivalent).","example":true},"status":{"type":"string","enum":["ACTIVE","DEPARTED"],"description":"ACTIVE = in role and collected daily. DEPARTED = no longer in role; collection stops, historic posts remain executive media.","example":"ACTIVE"},"profiles":{"type":"array","items":{"$ref":"#/components/schemas/ExecutiveProfile"}},"created_at":{"type":"string","format":"date-time","example":"2026-04-01T12:00:00Z"},"updated_at":{"type":"string","format":"date-time","example":"2026-04-01T12:00:00Z"}},"required":["id","brand_id","name","title","is_top_executive","status","profiles","created_at","updated_at"]},"ExecutiveProfile":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"e1a2c3d4-e5f6-7890-abcd-ef1234567890"},"platform":{"type":"string","example":"linkedin"},"handle":{"type":"string","example":"example-jane"},"url":{"type":["string","null"],"example":"https://www.linkedin.com/in/example-jane"},"region":{"type":"string","example":"us"},"collection_enabled":{"type":"boolean","description":"Whether the daily collector pulls this profile. Disabled profiles stay on record but are skipped during collection.","example":true}},"required":["id","platform","handle","url","region","collection_enabled"]},"OwnedMediaSummary":{"type":"object","properties":{"brand_id":{"type":"string","format":"uuid"},"total_posts":{"type":"integer"},"avg_posts_per_day":{"type":"number"},"by_platform":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string"},"posts":{"type":"integer"},"avg_posts_per_day":{"type":"number","example":0.4},"engagement":{"type":"object","properties":{"avg_likes":{"type":["number","null"]},"median_likes":{"type":["number","null"]},"likes_count":{"type":"integer"},"avg_comments":{"type":["number","null"]},"median_comments":{"type":["number","null"]},"comments_count":{"type":"integer"},"avg_views":{"type":["number","null"]},"median_views":{"type":["number","null"]},"views_count":{"type":"integer"},"top_post":{"type":["object","null"],"properties":{"post_id":{"type":"string","format":"uuid"},"posted_at":{"type":["string","null"],"format":"date-time"},"url":{"type":["string","null"]},"text":{"type":["string","null"]},"likes":{"type":["integer","null"]},"comments":{"type":["integer","null"]},"views":{"type":["integer","null"]}},"required":["post_id","posted_at","url","text","likes","comments","views"]}},"required":["avg_likes","median_likes","likes_count","avg_comments","median_comments","comments_count","avg_views","median_views","views_count","top_post"]}},"required":["platform","posts","avg_posts_per_day","engagement"]}},"top_themes":{"type":"array","items":{"type":"object","properties":{"theme":{"type":"string","example":"product-launch"},"frequency":{"type":"integer","example":42}},"required":["theme","frequency"]}},"sentiment_distribution":{"type":"object","properties":{"positive":{"type":"integer"},"neutral":{"type":"integer"},"negative":{"type":"integer"},"mixed":{"type":"integer"}},"required":["positive","neutral","negative","mixed"]},"period":{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}},"required":["start","end"]}},"required":["brand_id","total_posts","avg_posts_per_day","by_platform","top_themes","sentiment_distribution","period"]},"Platform":{"type":"object","properties":{"platform":{"type":"string","example":"instagram"},"handle":{"type":["string","null"],"example":"@example_brand"},"url":{"type":["string","null"],"example":"https://www.instagram.com/example_brand"},"followers":{"type":["number","null"],"example":125000},"follower_growth_30d":{"type":["number","null"],"example":2.5},"avg_engagement_rate":{"type":["number","null"],"example":3.2},"last_synced":{"type":["string","null"],"format":"date-time","example":"2026-04-01T12:00:00Z"},"collection_enabled":{"type":"boolean","description":"Whether the daily collectors pull ads/posts from this identity. Disabled identities stay registered for reference but are skipped during collection.","example":true}},"required":["platform","handle","url","followers","follower_growth_30d","avg_engagement_rate","last_synced","collection_enabled"]},"Timeseries":{"type":"object","properties":{"brand_id":{"type":"string","format":"uuid"},"metric":{"type":"string","example":"post_count"},"grain":{"type":"string","example":"week"},"series":{"type":"array","items":{"type":"object","properties":{"period_start":{"type":"string","example":"2026-03-01"},"value":{"type":"number","example":42}},"required":["period_start","value"]}},"deltas_vs_prior_window":{"type":"object","properties":{"total":{"type":["number","null"],"example":12.5},"avg_per_period":{"type":"number","example":6.3}},"required":["total","avg_per_period"]}},"required":["brand_id","metric","grain","series","deltas_vs_prior_window"]},"Benchmark":{"type":"object","properties":{"brand_id":{"type":"string","format":"uuid"},"dataset":{"type":"string","example":"owned-media"},"peer_set":{"type":"array","items":{"type":"string"},"example":["Nike","Adidas"]},"metrics":{"type":"array","items":{"$ref":"#/components/schemas/BenchmarkMetric"}}},"required":["brand_id","dataset","peer_set","metrics"]},"BenchmarkMetric":{"type":"object","properties":{"metric":{"type":"string","example":"owned_posts"},"value":{"type":"number","example":120},"rank":{"type":"integer","example":3},"percentile":{"type":"integer","example":75},"category_median":{"type":"number","example":80},"leader_value":{"type":"number","example":250}},"required":["metric","value","rank","percentile","category_median","leader_value"]},"CompetitiveSet":{"type":"object","properties":{"brand_id":{"type":"string","format":"uuid"},"category":{"type":["string","null"],"example":"Retail","description":"On fallback, the sole directly linked category, or null when there are zero or multiple categories. Curated sets retain a brand category label."},"competitors":{"type":"array","items":{"$ref":"#/components/schemas/BrandComparison"},"description":"Curated competitors, or up to 10 distinct fallback peers selected by brand ID across the category groups. Presented by name, then brand ID."},"category_groups":{"type":"array","items":{"type":"object","properties":{"category_id":{"type":"string"},"category":{"type":"string"},"competitors":{"type":"array","items":{"$ref":"#/components/schemas/BrandComparison"}},"has_more":{"type":"boolean","description":"More than 10 eligible peers exist in this category for this caller."}},"required":["category_id","category","competitors","has_more"]},"description":"Present only on fallback. Directly linked categories ordered by category ID, including empty categories. Each contains up to 10 live, visible peers selected by brand ID and presented by name, then brand ID. Shared peers appear in every applicable group."}},"required":["brand_id","category","competitors"]},"BrandComparison":{"type":"object","properties":{"brand_id":{"type":"string","format":"uuid","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","example":"Acme Corp"},"owned_posts_30d":{"type":"integer","example":120},"mention_volume_30d":{"type":"integer","example":3400},"avg_sentiment_30d":{"type":["number","null"],"example":0.65},"ad_count_30d":{"type":"integer","description":"Distinct creatives with content dated in the window. Counted as CREATIVES, not ad rows: Meta publishes one ad-library row per creative variant, so an advertiser running Advantage+ or dynamic creative returns hundreds of rows for a handful of ads. Ads sharing a `collation_group_id` count once; an ad carrying none counts as itself. Meta is the only platform that publishes a variant key, so LinkedIn and Google ads each count individually even where an advertiser runs the same copy across several of them.","example":45}},"required":["brand_id","name","owned_posts_30d","mention_volume_30d","avg_sentiment_30d","ad_count_30d"]},"BrandOverview":{"type":"object","properties":{"brand_id":{"type":"string","format":"uuid"},"window":{"type":"string","example":"30d"},"owned_media":{"type":"object","properties":{"post_count":{"type":"integer"},"top_theme":{"type":["string","null"]},"platform_mix":{"type":"object","additionalProperties":{"type":"number"}}},"required":["post_count","top_theme","platform_mix"]},"paid_media":{"type":"object","properties":{"active_ads":{"type":"integer","description":"Creatives reading `status=ACTIVE` in the window, across every ad platform the brand is tracked on — a creative counts as active while any one of its variants is still serving. Counted as CREATIVES, not ad rows: Meta publishes one ad-library row per creative variant, so an advertiser running Advantage+ or dynamic creative returns hundreds of rows for a handful of ads. Ads sharing a `collation_group_id` count once; an ad carrying none counts as itself. Meta is the only platform that publishes a variant key, so LinkedIn and Google ads each count individually even where an advertiser runs the same copy across several of them. On LinkedIn, ACTIVE means \"active in the last 30 days\" rather than \"serving right now\": the platform publishes no flight dates, so liveness comes from its rolling ~30-day activity view, and an ad that stopped serving keeps reading ACTIVE until it drops out of that window. Meta and Google ads carry real start/end dates, so their ACTIVE is a true liveness reading. Carry that caveat into any count you present; `/paid-media/summary` splits it per platform.","example":18},"new_creatives":{"type":"integer","description":"Distinct creatives whose flight overlaps the window — the same figure `/paid-media/summary` publishes as `total_ads`, read from the same aggregate. Counted as CREATIVES, not ad rows: Meta publishes one ad-library row per creative variant, so an advertiser running Advantage+ or dynamic creative returns hundreds of rows for a handful of ads. Ads sharing a `collation_group_id` count once; an ad carrying none counts as itself. Meta is the only platform that publishes a variant key, so LinkedIn and Google ads each count individually even where an advertiser runs the same copy across several of them.","example":24}},"required":["active_ads","new_creatives"]},"mentions":{"type":"object","properties":{"volume":{"type":"integer"},"net_sentiment":{"type":["number","null"]}},"required":["volume","net_sentiment"]}},"required":["brand_id","window","owned_media","paid_media","mentions"]},"BrandDetail":{"allOf":[{"$ref":"#/components/schemas/BrandSummary"},{"type":"object","properties":{"founded":{"type":["integer","null"],"example":2010},"headquarters":{"type":["string","null"],"example":"San Francisco, CA"},"logo_url":{"type":["string","null"],"format":"uri","description":"Stable, cacheable logo URL served from Waldo's own storage. The URL changes only when the image itself changes, so it is safe to cache indefinitely. Null when we hold no renderable logo — never a URL that fails to load for you.","example":"https://files.waldo.fyi/brand-logos/b1140000-0000-4000-8000-000000000001/9f2c1ab30d4e.png"},"colors":{"type":"array","items":{"type":"string"},"description":"Full detected brand palette as lowercase hex strings, most prominent first. Empty when we hold no palette. `primary_color` is the chosen accent and may not equal `colors[0]` — neutrals are skipped and staff can override it.","example":["#e4002b","#111820","#ffffff"]}},"required":["founded","headquarters","logo_url","colors"]}]},"BrandSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","example":"Acme Corp"},"aliases":{"type":"array","items":{"type":"string"},"description":"Other names this brand is known by — product lines, social handles, legal or former names. `/brands/search` matches these as well as `name`, so searching an alias finds this brand. Use them to confirm a name you were given refers to this brand rather than one that merely contains it.","example":["Samuel Adams","Sam Adams Beer"]},"categories":{"type":"array","items":{"$ref":"#/components/schemas/BrandCategory"},"description":"Flat list of taxonomy nodes this brand is associated with. Subcategories carry parent_id/parent_name; top-level categories have null parent refs."},"description":{"type":["string","null"],"example":"A leading tech company"},"audience_ids":{"type":"array","items":{"type":"string"},"example":[]},"platform_count":{"type":"integer","example":5},"primary_region":{"type":"string","example":"us"},"regions_tracked":{"type":"array","items":{"type":"string"},"example":["us","uk"]},"tracked_since":{"type":["string","null"],"format":"date-time","description":"When continuous collection began for this brand in Waldo's index (the first collection bootstrap run), ISO 8601. Anchor time-based charts to this date — Waldo has no continuous coverage before it, so any earlier data points are incidental historical backfill, not a monitored series. Null if the brand has not been launched yet.","example":"2026-06-19T14:30:00Z"},"primary_color":{"type":["string","null"],"description":"Primary brand accent as a lowercase hex string. Detected from the brand's logo (skipping near-black/near-white neutrals) and overridable by Waldo staff. Null when we hold no usable color.","example":"#e4002b"}},"required":["id","name","aliases","categories","description","audience_ids","platform_count","primary_region","regions_tracked","tracked_since","primary_color"]},"BrandCategory":{"type":"object","properties":{"id":{"type":"string","example":"apparel-fashion-activewear-athleisure"},"name":{"type":"string","example":"Activewear & Athleisure"},"parent_id":{"type":["string","null"],"example":"apparel-fashion"},"parent_name":{"type":["string","null"],"example":"Apparel & Fashion"}},"required":["id","name","parent_id","parent_name"]},"BrandsNotFoundError":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","example":"not_found"},"message":{"type":"string","example":"Brand not found: 550e8400-e29b-41d4-a716-446655440000"},"unresolved_brand_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The requested brand_ids that do not resolve to a brand","example":["550e8400-e29b-41d4-a716-446655440000"]}},"required":["code","message","unresolved_brand_ids"]}},"required":["error"]},"ApiKeyCreated":{"type":"object","properties":{"apiKey":{"type":"string","description":"The raw key. Returned in plaintext exactly once — store it securely; it cannot be retrieved later."},"keyId":{"type":"string","format":"uuid"},"expiresAt":{"type":["string","null"],"format":"date-time"}},"required":["apiKey","keyId","expiresAt"]},"Error":{"type":"object","properties":{"error":{"type":"string","example":"Resource not found"}},"required":["error"]},"ApiKeyMetadata":{"type":"object","properties":{"apiKeyId":{"type":"string","format":"uuid"},"userId":{"type":"integer","description":"User who minted the key (keys are team-scoped; this is provenance)","example":42},"name":{"type":"string","example":"CI pipeline key"},"type":{"type":"string","example":"REST","description":"Minting provenance (MCP, REST, or OAUTH) — all key types authenticate identically."},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":["string","null"],"format":"date-time"},"lastUsedAt":{"type":["string","null"],"format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"},"status":{"type":"string","enum":["ACTIVE","REVOKED","EXPIRED","DELETED"]}},"required":["apiKeyId","userId","name","type","createdAt","expiresAt","lastUsedAt","revokedAt","status"]}},"parameters":{}},"paths":{"/v1/api-keys":{"get":{"operationId":"api_key_list","tags":["API Keys"],"summary":"List API keys","description":"List the current workspace's API keys — metadata only with derived status. Raw key material is never returned; it is only shown once at creation. Paginated: pass the nextCursor from a response to fetch the next page.","parameters":[{"schema":{"type":"string","enum":["MCP","REST","OAUTH"],"description":"Filter by minting provenance"},"required":false,"description":"Filter by minting provenance","name":"type","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"Page size (1–100, default 25)"},"required":false,"description":"Page size (1–100, default 25)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Pagination cursor from a prior response's nextCursor"},"required":false,"description":"Pagination cursor from a prior response's nextCursor","name":"cursor","in":"query"}],"responses":{"200":{"description":"API keys for the current workspace","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyMetadata"}},"nextCursor":{"type":["string","null"],"description":"Cursor for the next page, or null on the last page"}},"required":["data","nextCursor"]}}}},"400":{"description":"No workspace selected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"api_key_create","tags":["API Keys"],"summary":"Create an API key","description":"Create an API key for the current workspace, usable against both the REST API and the MCP server. The raw key is returned ONCE in this response and cannot be retrieved later — store it securely.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Human-readable label for the key","example":"CI pipeline key"},"expiresInDays":{"type":"integer","exclusiveMinimum":0,"maximum":36500,"description":"Optional TTL in days (max 36500); omit for a non-expiring key","example":90}},"required":["name"]}}}},"responses":{"200":{"description":"Key created — the raw key appears only in this response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ApiKeyCreated"}},"required":["data"]}}}},"400":{"description":"No workspace selected or invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/api-keys/{keyId}":{"delete":{"operationId":"api_key_revoke","tags":["API Keys"],"summary":"Revoke an API key","description":"Revoke an API key in the current workspace. The key stops authenticating immediately and cannot be reactivated. Revoking an already-revoked key succeeds (idempotent); keys outside the current workspace report not-found.","parameters":[{"schema":{"type":"string","format":"uuid","description":"The apiKeyId to revoke (from the list endpoint)"},"required":true,"description":"The apiKeyId to revoke (from the list endpoint)","name":"keyId","in":"path"}],"responses":{"200":{"description":"Key revoked","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ApiKeyMetadata"}},"required":["data"]}}}},"400":{"description":"No workspace selected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Key not found in the current workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/api-keys/{keyId}/permanent":{"delete":{"operationId":"api_key_delete","tags":["API Keys"],"summary":"Permanently delete an API key","description":"Permanently delete an API key from the current workspace, removing it from all listings. The key stops authenticating immediately and cannot be recovered. Prefer revoking (DELETE /{keyId}) to disable a key while keeping it in the inventory; use this only to clear out long-dead keys. Keys outside the current workspace (or already deleted) report not-found.","parameters":[{"schema":{"type":"string","format":"uuid","description":"The apiKeyId to delete (from the list endpoint)"},"required":true,"description":"The apiKeyId to delete (from the list endpoint)","name":"keyId","in":"path"}],"responses":{"200":{"description":"Key deleted","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ApiKeyMetadata"}},"required":["data"]}}}},"400":{"description":"No workspace selected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Key not found in the current workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/search":{"get":{"operationId":"brand_search","tags":["Brands"],"summary":"Search brands","description":"Search brands by name or keyword. Optionally filter by category. Returns a paginated list of brand summaries.","parameters":[{"schema":{"type":"string","description":"Search query — matches against brand name","example":"Nike"},"required":false,"description":"Search query — matches against brand name","name":"q","in":"query"},{"schema":{"type":"string","description":"Filter to brands in this category or subcategory (brand_taxonomy id). Matches the category and its direct subcategories.","example":"apparel-fashion"},"required":false,"description":"Filter to brands in this category or subcategory (brand_taxonomy id). Matches the category and its direct subcategories.","name":"category_id","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Maximum number of results to return (1–100)","example":20},"required":false,"description":"Maximum number of results to return (1–100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response"},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response","name":"cursor","in":"query"}],"responses":{"200":{"description":"Paginated list of brands","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BrandSummary"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":[{"id":"121030cf-e18c-46c6-847a-03ce22ff88a3","name":"Nike","categories":[{"id":"apparel-fashion","name":"Apparel & Fashion","parent_id":null,"parent_name":null},{"id":"apparel-fashion-activewear-athleisure","name":"Activewear & Athleisure","parent_id":"apparel-fashion","parent_name":"Apparel & Fashion"},{"id":"sports-recreation","name":"Sports & Recreation","parent_id":null,"parent_name":null}],"description":"Inspiring the world's athletes, Nike delivers innovative products, experiences and services.","audience_ids":[],"platform_count":6,"primary_region":"us","regions_tracked":[],"tracked_since":"2026-06-19T14:30:00Z","primary_color":"#111820"},{"id":"267668e9-1ea8-4756-b8e0-772d9dba4461","name":"Waldo","categories":[],"description":"Waldo is an AI-powered strategy engine for agencies & brands. Get audience insights, industry trends, and competitive intelligence in one powerful platform. ","audience_ids":[],"platform_count":0,"primary_region":"us","regions_tracked":[],"tracked_since":null,"primary_color":"#5f2eea"},{"id":"3b575db9-aae0-448e-9455-97d8e836dbcb","name":"Canva","categories":[{"id":"entertainment-media","name":"Entertainment & Media","parent_id":null,"parent_name":null},{"id":"entertainment-media-social-media-creator-platforms","name":"Social Media & Creator Platforms","parent_id":"entertainment-media","parent_name":"Entertainment & Media"},{"id":"technology-software","name":"Technology & Software","parent_id":null,"parent_name":null}],"description":"Canva is a free-to-use online graphic design tool. Use it to create social media posts, presentations, posters, videos, logos and more.","audience_ids":[],"platform_count":6,"primary_region":"us","regions_tracked":[],"tracked_since":"2026-07-01T09:00:00Z","primary_color":"#00c4cc"}],"meta":{"request_id":"req_example","total":18,"total_pages":6,"next_cursor":"3b575db9-aae0-448e-9455-97d8e836dbcb"}}}}}}}}}},"/v1/brands/compare":{"get":{"operationId":"brand_compare","tags":["Competitive"],"summary":"Compare brands","description":"Compare up to 5 brands side-by-side on key metrics (owned posts, mention volume, sentiment, ad count). Every brand_id must resolve — if any is unknown the whole request returns 404 and lists the unresolved ids in `error.unresolved_brand_ids`, rather than returning a quietly shortened comparison.","parameters":[{"schema":{"type":"string","description":"Comma-separated brand UUIDs (max 5)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890,c2b3d4e5-f6a7-8901-bcde-f12345678901"},"required":true,"description":"Comma-separated brand UUIDs (max 5)","name":"brand_ids","in":"query"},{"schema":{"type":"string","enum":["7d","30d","90d"],"default":"30d","description":"Time window for comparison. Defaults to 30d.","example":"30d"},"required":false,"description":"Time window for comparison. Defaults to 30d.","name":"window","in":"query"}],"responses":{"200":{"description":"Brand comparison results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"comparison":{"type":"array","items":{"$ref":"#/components/schemas/BrandComparison"}},"period":{"type":"object","properties":{"start":{"type":"string","example":"2026-03-04"},"end":{"type":"string","example":"2026-04-03"}},"required":["start","end"]}},"required":["comparison","period"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"comparison":[{"brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","name":"Nike","owned_posts_30d":56,"mention_volume_30d":0,"avg_sentiment_30d":null,"ad_count_30d":1011}],"period":{"start":"2026-05-25","end":"2026-06-24"}},"meta":{"request_id":"req_example"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"One or more brand_ids were not found. `error.unresolved_brand_ids` lists them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandsNotFoundError"}}}}}}},"/v1/brands/{brand_id}":{"get":{"operationId":"brand_get","tags":["Brands"],"summary":"Get brand","description":"Get detailed information about a single brand, including founded year, headquarters, and logo.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"}],"responses":{"200":{"description":"Brand details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BrandDetail"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"id":"121030cf-e18c-46c6-847a-03ce22ff88a3","name":"Nike","categories":[{"id":"apparel-fashion","name":"Apparel & Fashion","parent_id":null,"parent_name":null},{"id":"apparel-fashion-activewear-athleisure","name":"Activewear & Athleisure","parent_id":"apparel-fashion","parent_name":"Apparel & Fashion"},{"id":"sports-recreation","name":"Sports & Recreation","parent_id":null,"parent_name":null}],"description":"Inspiring the world's athletes, Nike delivers innovative products, experiences and services.","audience_ids":[],"platform_count":6,"primary_region":"us","regions_tracked":["us"],"tracked_since":"2026-06-19T14:30:00Z","logo_url":"https://files.waldo.fyi/brand-logos/b1140000-0000-4000-8000-000000000001/9f2c1ab30d4e.png","primary_color":"#111820","founded":null,"headquarters":null,"colors":["#111820","#f5f5f5","#ffffff"]},"meta":{"request_id":"req_example"}}}}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/overview":{"get":{"operationId":"brand_overview","tags":["Brand Overview"],"summary":"Brand overview","description":"Cross-dataset snapshot for a brand. Returns owned media, paid media, and mention summaries in one call.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","enum":["7d","30d","90d"],"default":"30d","description":"Time window for the snapshot. Defaults to 30d.","example":"30d"},"required":false,"description":"Time window for the snapshot. Defaults to 30d.","name":"window","in":"query"}],"responses":{"200":{"description":"Brand overview snapshot","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BrandOverview"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","window":"30d","owned_media":{"post_count":56,"top_theme":"product-launch","platform_mix":{"instagram":0.39,"twitter":0.32,"linkedin":0.25,"tiktok":0.04}},"paid_media":{"active_ads":0,"new_creatives":1010},"mentions":{"volume":2718,"net_sentiment":0.23}},"meta":{"request_id":"req_example"}}}}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/competitive-set":{"get":{"operationId":"brand_competitive_set","tags":["Competitive Analysis"],"summary":"Brand competitive set","description":"Get a brand's competitive set with comparison metrics. Returns the brand's explicit, curated competitors when any exist; otherwise returns peers grouped by directly linked category (up to 10 per group, with has_more), plus a flat compatibility list of up to 10 distinct peers.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"}],"responses":{"200":{"description":"Competitive set with peer comparison metrics","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CompetitiveSet"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","category":"Activewear & Athleisure","competitors":[],"category_groups":[{"category_id":"activewear-athleisure","category":"Activewear & Athleisure","competitors":[],"has_more":false}]},"meta":{"request_id":"req_example"}}}}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/{dataset}/benchmark":{"get":{"operationId":"brand_benchmark","tags":["Competitive Analysis"],"summary":"Brand benchmark","description":"Rank a brand against category peers on key metrics. Returns percentile, rank, median, and leader values for each metric.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","enum":["owned-media","paid-media","mentions","all"],"description":"Dataset to benchmark against","example":"owned-media"},"required":true,"description":"Dataset to benchmark against","name":"dataset","in":"path"},{"schema":{"type":"string","enum":["7d","30d","90d"],"default":"30d","description":"Time window for benchmark. Defaults to 30d.","example":"30d"},"required":false,"description":"Time window for benchmark. Defaults to 30d.","name":"window","in":"query"}],"responses":{"200":{"description":"Benchmark results with percentile rankings","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Benchmark"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/{dataset}/timeseries":{"get":{"operationId":"brand_timeseries","tags":["Brands"],"summary":"Brand timeseries","description":"Get trend-line data for a brand metric over time. Supports multiple datasets (owned media, paid media, mentions, or all) with configurable grain and window.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","enum":["owned-media","paid-media","mentions","all"],"description":"Dataset to query: owned-media, paid-media, mentions, or all","example":"owned-media"},"required":true,"description":"Dataset to query: owned-media, paid-media, mentions, or all","name":"dataset","in":"path"},{"schema":{"type":"string","enum":["post_count","mention_volume","ad_count","avg_sentiment","net_sentiment","followers","follower_growth"],"description":"Metric to chart","example":"post_count"},"required":true,"description":"Metric to chart","name":"metric","in":"query"},{"schema":{"type":"string","enum":["day","week","month"],"description":"Time grain for bucketing","example":"week"},"required":true,"description":"Time grain for bucketing","name":"grain","in":"query"},{"schema":{"type":"string","enum":["30d","90d","26w","12m"],"description":"Lookback window: 30d, 90d, 26w, or 12m","example":"30d"},"required":true,"description":"Lookback window: 30d, 90d, 26w, or 12m","name":"window","in":"query"},{"schema":{"type":"string","description":"Filter/breakout by platform","example":"instagram"},"required":false,"description":"Filter/breakout by platform","name":"platform","in":"query"},{"schema":{"type":"string","description":"Filter/breakout by region","example":"us"},"required":false,"description":"Filter/breakout by region","name":"region","in":"query"}],"responses":{"200":{"description":"Timeseries data with deltas vs. prior window","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Timeseries"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/platforms":{"get":{"operationId":"brand_platforms_list","tags":["Platforms"],"summary":"List brand platforms","description":"List all social platform accounts tracked for a brand, including follower counts, engagement rates, and sync status.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","enum":["0","1","true","false"],"description":"Include ad-library identity rows (meta_ads, google_ads, linkedin_ads). Off by default — these drive ad collection and aren't social presence."},"required":false,"description":"Include ad-library identity rows (meta_ads, google_ads, linkedin_ads). Off by default — these drive ad collection and aren't social presence.","name":"include_ad_library","in":"query"}],"responses":{"200":{"description":"List of platform accounts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Platform"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":[{"platform":"facebook","handle":"example_brand","url":"https://www.facebook.com/example_brand","followers":39634463,"follower_growth_30d":null,"avg_engagement_rate":null,"last_synced":"2026-06-11T12:37:20.266Z"},{"platform":"instagram","handle":"example_brand","url":"https://www.instagram.com/example_brand","followers":292076716,"follower_growth_30d":null,"avg_engagement_rate":null,"last_synced":"2026-06-11T12:37:24.083Z"},{"platform":"linkedin","handle":"example-brand","url":"https://www.linkedin.com/company/example-brand/","followers":6271427,"follower_growth_30d":null,"avg_engagement_rate":null,"last_synced":"2026-06-11T12:37:04.973Z"},{"platform":"tiktok","handle":"example_brand","url":"https://www.tiktok.com/@example_brand","followers":8696363,"follower_growth_30d":null,"avg_engagement_rate":null,"last_synced":"2026-06-11T12:37:27.091Z"},{"platform":"twitter","handle":"ExampleBrand","url":"https://x.com/ExampleBrand","followers":9558911,"follower_growth_30d":null,"avg_engagement_rate":null,"last_synced":"2026-06-11T12:37:20.027Z"},{"platform":"youtube","handle":"example_brand","url":"https://www.youtube.com/@example_brand","followers":2260000,"follower_growth_30d":null,"avg_engagement_rate":null,"last_synced":"2026-06-11T12:37:25.267Z"}],"meta":{"request_id":"req_example","total":6,"next_cursor":null}}}}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/platforms/{platform}":{"get":{"operationId":"brand_platforms_get","tags":["Platforms"],"summary":"Get brand platform","description":"Get details for a specific social platform account tracked for a brand.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","description":"Platform name (e.g. instagram, tiktok, twitter)","example":"instagram"},"required":true,"description":"Platform name (e.g. instagram, tiktok, twitter)","name":"platform","in":"path"},{"schema":{"type":"string","enum":["0","1","true","false"],"description":"Allow resolving ad-library identity rows (meta_ads, google_ads, linkedin_ads). Off by default — these 404 unless opted in."},"required":false,"description":"Allow resolving ad-library identity rows (meta_ads, google_ads, linkedin_ads). Off by default — these 404 unless opted in.","name":"include_ad_library","in":"query"}],"responses":{"200":{"description":"Platform account details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Platform"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand or platform not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/owned-media/posts":{"get":{"operationId":"brand_owned_media_posts_list","tags":["Owned Media"],"summary":"List owned posts","description":"List owned social media posts for a brand with optional filters for platform, date range, and region. Results are paginated.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","description":"Filter to a single platform (e.g. instagram, tiktok, twitter). Mutually exclusive with exclude_platform.","example":"instagram"},"required":false,"description":"Filter to a single platform (e.g. instagram, tiktok, twitter). Mutually exclusive with exclude_platform.","name":"platform","in":"query"},{"schema":{"type":"string","description":"Exclude a single platform from the results (e.g. facebook). Mutually exclusive with platform.","example":"facebook"},"required":false,"description":"Exclude a single platform from the results (e.g. facebook). Mutually exclusive with platform.","name":"exclude_platform","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter posts on or after this date (ISO 8601)","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Filter posts on or after this date (ISO 8601)","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter posts on or before this date (ISO 8601)","example":"2026-03-31T23:59:59Z"},"required":false,"description":"Filter posts on or before this date (ISO 8601)","name":"end_date","in":"query"},{"schema":{"type":"string","description":"Filter by region","example":"us"},"required":false,"description":"Filter by region","name":"region","in":"query"},{"schema":{"type":"string","enum":["posted_at","likes","comments","shares","views","engagement"],"description":"Order results by posted_at (default, recency); a raw engagement metric (likes, comments, shares, views) compared as raw counts, meaningful within one platform; or `engagement` — a per-platform-normalized \"top recent posts\" rank balanced across platforms. `engagement` ignores `order` and defaults to the last 30 days when no date range is given. Posts missing the chosen metric sort last.","example":"engagement"},"required":false,"description":"Order results by posted_at (default, recency); a raw engagement metric (likes, comments, shares, views) compared as raw counts, meaningful within one platform; or `engagement` — a per-platform-normalized \"top recent posts\" rank balanced across platforms. `engagement` ignores `order` and defaults to the last 30 days when no date range is given. Posts missing the chosen metric sort last.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: desc (default) or asc. Ignored for sort=engagement.","example":"desc"},"required":false,"description":"Sort direction: desc (default) or asc. Ignored for sort=engagement.","name":"order","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Maximum number of results to return (1–100)","example":20},"required":false,"description":"Maximum number of results to return (1–100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response"},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response","name":"cursor","in":"query"}],"responses":{"200":{"description":"Paginated list of owned posts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Post"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":[{"id":"0e1a2b3c-0001-4a5b-8c6d-000000000101","brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","platform":"instagram","posted_at":"2026-06-23T17:07:03.000Z","text":"Example post: goals on the biggest stage, every four years. Which one was your favorite?","media_urls":["https://data.waldo.fyi/v1/media/post/0e1a2b3c-0001-4a5b-8c6d-000000000101/0","https://data.waldo.fyi/v1/media/post/0e1a2b3c-0001-4a5b-8c6d-000000000101/1","https://data.waldo.fyi/v1/media/post/0e1a2b3c-0001-4a5b-8c6d-000000000101/2"],"media_poster_urls":null,"media_count":3,"hashtags":[],"url":"https://www.instagram.com/p/EXAMPLE101/","region":"us","author":{"handle":"example_brand","name":"Example Brand"},"likes":485000,"comments":12000,"shares":null,"views":null,"analysis":{"tone":"celebratory","content_type":null,"hook":null,"angle":null,"on_screen_text":null,"topic_tags":["world-cup-2026","goal-celebration","athlete-spotlight"],"entities":[{"type":"person","value":"Example Athlete"},{"type":"event","value":"FIFA World Cup 2026"},{"type":"event","value":"FIFA World Cup"}],"brands":[],"audiences":["soccer-fans","sports-enthusiasts"],"industries":["apparel","sporting-goods"],"findable":null,"analyzed_at":"2026-06-23T17:12:49.968Z"},"is_quote":false,"is_retweet":false,"is_reply":false,"quoted_post":null,"retweeted_post":null,"fetched_at":"2026-06-23T17:12:22.691Z","metrics_captured_at":"2026-06-23T17:12:22.691Z"},{"id":"0e1a2b3c-0002-4a5b-8c6d-000000000102","brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","platform":"instagram","posted_at":"2026-06-23T14:09:28.000Z","text":"Example post: leading from the front, on and off the pitch. @example_captain @example_midfielder","media_urls":["https://data.waldo.fyi/v1/media/post/0e1a2b3c-0002-4a5b-8c6d-000000000102/0"],"media_poster_urls":null,"media_count":1,"hashtags":[],"url":"https://www.instagram.com/p/EXAMPLE102/","region":"us","author":{"handle":"example_brand","name":"Example Brand"},"likes":210000,"comments":3400,"shares":null,"views":5600000,"analysis":{"tone":"celebratory","content_type":null,"hook":null,"angle":null,"on_screen_text":null,"topic_tags":["football","athlete-endorsement","captaincy"],"entities":[{"type":"person","value":"Example Captain"},{"type":"person","value":"Example Midfielder"}],"brands":[],"audiences":["soccer-fans","sports-enthusiasts"],"industries":["apparel","sports"],"findable":null,"analyzed_at":"2026-06-23T17:12:52.848Z"},"is_quote":false,"is_retweet":false,"is_reply":false,"quoted_post":null,"retweeted_post":null,"fetched_at":"2026-06-23T17:12:22.729Z","metrics_captured_at":"2026-06-23T17:12:22.729Z"},{"id":"0e1a2b3c-0003-4a5b-8c6d-000000000103","brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","platform":"instagram","posted_at":"2026-06-22T14:01:05.000Z","text":"Example post: time for liftoff with @example_striker and @example_actor.","media_urls":["https://data.waldo.fyi/v1/media/post/0e1a2b3c-0003-4a5b-8c6d-000000000103/0"],"media_poster_urls":null,"media_count":1,"hashtags":[],"url":"https://www.instagram.com/p/EXAMPLE103/","region":"us","author":{"handle":"example_brand","name":"Example Brand"},"likes":178000,"comments":2100,"shares":null,"views":4200000,"analysis":{"tone":"aspirational","content_type":null,"hook":null,"angle":null,"on_screen_text":null,"topic_tags":["celebrity-collaboration","campaign-teaser","athlete-partnership"],"entities":[{"type":"person","value":"Example Striker"},{"type":"person","value":"Example Actor"}],"brands":[],"audiences":["soccer-fans","sports-fans","general-consumers"],"industries":["apparel","footwear"],"findable":null,"analyzed_at":"2026-06-22T17:13:54.209Z"},"is_quote":false,"is_retweet":false,"is_reply":false,"quoted_post":null,"retweeted_post":null,"fetched_at":"2026-06-22T17:13:21.467Z","metrics_captured_at":"2026-06-23T17:12:23.104Z"},{"id":"0e1a2b3c-0004-4a5b-8c6d-000000000104","brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","platform":"twitter","posted_at":"2026-06-22T15:41:18.000Z","text":"Example post: three years in the making. Congratulations to every athlete on this list.","media_urls":null,"media_poster_urls":null,"media_count":0,"hashtags":[],"url":"https://x.com/example_brand/status/1000000000000000104","region":"us","author":{"handle":"example_brand","name":"Example Brand"},"likes":1840,"comments":96,"shares":412,"views":210400,"analysis":null,"is_quote":true,"is_retweet":false,"is_reply":false,"quoted_post":{"id":"1000000000000000105","url":"https://x.com/example_league/status/1000000000000000105","published_at":"2026-06-22T14:02:07.000Z","author":{"handle":"example_league","name":"Example League"},"text":"Example post: the Golden Boot shortlist is here.","media_urls":["https://media.example.com/posts/example-post-105.jpg"]},"retweeted_post":null,"fetched_at":"2026-06-23T17:12:22.691Z","metrics_captured_at":"2026-06-23T17:12:22.691Z"}],"meta":{"request_id":"req_example","total":1153,"total_pages":385,"next_cursor":"ZXhhbXBsZS1jdXJzb3I.ZXhhbXBsZQ"}}}}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/owned-media/posts/{post_id}":{"get":{"operationId":"brand_owned_media_posts_get","tags":["Owned Media"],"summary":"Get owned post","description":"Get details for a single owned post by ID.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Post ID (UUID)","example":"p1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Post ID (UUID)","name":"post_id","in":"path"}],"responses":{"200":{"description":"Post details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PostDetail"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand or post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/owned-media/summary":{"get":{"operationId":"brand_owned_media_summary","tags":["Owned Media"],"summary":"Get owned media summary","description":"Get a summary of owned media activity for a brand, including posting cadence, platform breakdown, per-platform engagement (avg/median likes, comments, views plus each platform's top post), top themes, and sentiment distribution. Engagement is broken out per platform rather than blended - a single cross-platform engagement figure isn't definable, so consumers wanting a rate compute their own from these raw metrics. Accepts the same filters as GET /owned-media/posts; passing an identical filter set - including an explicit start_date/end_date, which this endpoint defaults to the last 30 days - yields aggregates over exactly the posts the list returns.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","description":"Filter to a single platform (e.g. instagram, tiktok, twitter). Mutually exclusive with exclude_platform.","example":"instagram"},"required":false,"description":"Filter to a single platform (e.g. instagram, tiktok, twitter). Mutually exclusive with exclude_platform.","name":"platform","in":"query"},{"schema":{"type":"string","description":"Exclude a single platform from the results (e.g. facebook). Mutually exclusive with platform.","example":"facebook"},"required":false,"description":"Exclude a single platform from the results (e.g. facebook). Mutually exclusive with platform.","name":"exclude_platform","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Start of date range (ISO 8601). Defaults to 30 days ago.","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Start of date range (ISO 8601). Defaults to 30 days ago.","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"End of date range (ISO 8601). Defaults to now.","example":"2026-03-31T23:59:59Z"},"required":false,"description":"End of date range (ISO 8601). Defaults to now.","name":"end_date","in":"query"},{"schema":{"type":"string","description":"Filter by region","example":"us"},"required":false,"description":"Filter by region","name":"region","in":"query"}],"responses":{"200":{"description":"Owned media summary","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OwnedMediaSummary"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","total_posts":56,"avg_posts_per_day":1.87,"by_platform":[{"platform":"instagram","posts":22,"avg_posts_per_day":0.73,"engagement":{"avg_likes":4210.5,"median_likes":2980,"likes_count":22,"avg_comments":118.3,"median_comments":74,"comments_count":22,"avg_views":51200.4,"median_views":38400,"views_count":10,"top_post":{"post_id":"0e1a2b3c-0011-4a5b-8c6d-000000000111","posted_at":"2026-06-18T16:02:11.000Z","url":"https://www.instagram.com/p/EXAMPLE111/","text":"Example post: our biggest launch yet is here.","likes":48200,"comments":910,"views":612000}}},{"platform":"twitter","posts":18,"avg_posts_per_day":0.6,"engagement":{"avg_likes":512.2,"median_likes":340,"likes_count":18,"avg_comments":22.1,"median_comments":15,"comments_count":18,"avg_views":18400.7,"median_views":12100,"views_count":18,"top_post":{"post_id":"0e1a2b3c-0012-4a5b-8c6d-000000000112","posted_at":"2026-06-20T13:45:00.000Z","url":"https://twitter.com/example_brand/status/1000000000000000112","text":"Example post: we heard you. Here's what's next.","likes":6300,"comments":410,"views":210000}}},{"platform":"linkedin","posts":14,"avg_posts_per_day":0.47,"engagement":{"avg_likes":288.6,"median_likes":205,"likes_count":14,"avg_comments":31.4,"median_comments":22,"comments_count":14,"avg_views":null,"median_views":null,"views_count":0,"top_post":{"post_id":"0e1a2b3c-0013-4a5b-8c6d-000000000113","posted_at":"2026-06-15T09:12:44.000Z","url":"https://www.linkedin.com/posts/example-brand_activity-7000000000000000113/","text":"Example post: a note from our founder on the year ahead.","likes":1820,"comments":240,"views":null}}}],"top_themes":[{"theme":"product-launch","frequency":10},{"theme":"football","frequency":9},{"theme":"collaboration","frequency":7}],"sentiment_distribution":{"positive":0,"neutral":0,"negative":0,"mixed":0},"period":{"start":"2026-05-25T14:21:53.757Z","end":"2026-06-24T14:21:53.757Z"}},"meta":{"request_id":"req_example"}}}}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/executives":{"get":{"operationId":"brand_executives_list","tags":["Executives"],"summary":"List tracked executives","description":"List the brand's tracked executives and their registered personal profiles. `title` is the person's title verbatim as the brand publishes it — filter priority voices with `top_only` rather than parsing titles.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","enum":["ACTIVE","DEPARTED"],"description":"Filter by status. ACTIVE = in role and collected daily; DEPARTED = collection stopped, historic posts retained.","example":"ACTIVE"},"required":false,"description":"Filter by status. ACTIVE = in role and collected daily; DEPARTED = collection stopped, historic posts retained.","name":"status","in":"query"},{"schema":{"type":"string","enum":["0","1","true","false"],"description":"Only executives filling a priority voice (the CEO/CMO slots)."},"required":false,"description":"Only executives filling a priority voice (the CEO/CMO slots).","name":"top_only","in":"query"}],"responses":{"200":{"description":"Tracked executives","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Executive"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/executive-media/posts":{"get":{"operationId":"brand_executive_media_posts_list","tags":["Executive Media"],"summary":"List executive posts","description":"List posts published by the brand's executives on their personal profiles. Separate from owned media by design: executive voice never enters the brand's own post counts, platform mix, or cross-brand comparisons.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","description":"Filter to a single platform (e.g. instagram, tiktok, twitter). Mutually exclusive with exclude_platform.","example":"instagram"},"required":false,"description":"Filter to a single platform (e.g. instagram, tiktok, twitter). Mutually exclusive with exclude_platform.","name":"platform","in":"query"},{"schema":{"type":"string","description":"Exclude a single platform from the results (e.g. facebook). Mutually exclusive with platform.","example":"facebook"},"required":false,"description":"Exclude a single platform from the results (e.g. facebook). Mutually exclusive with platform.","name":"exclude_platform","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter posts on or after this date (ISO 8601)","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Filter posts on or after this date (ISO 8601)","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter posts on or before this date (ISO 8601)","example":"2026-03-31T23:59:59Z"},"required":false,"description":"Filter posts on or before this date (ISO 8601)","name":"end_date","in":"query"},{"schema":{"type":"string","description":"Filter by region","example":"us"},"required":false,"description":"Filter by region","name":"region","in":"query"},{"schema":{"type":"string","enum":["posted_at","likes","comments","shares","views"],"description":"Order results by posted_at (default, recency) or a raw engagement metric: likes, comments, shares, or views.","example":"likes"},"required":false,"description":"Order results by posted_at (default, recency) or a raw engagement metric: likes, comments, shares, or views.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: desc (default) or asc.","example":"desc"},"required":false,"description":"Sort direction: desc (default) or asc.","name":"order","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"Maximum number of results to return (1–100)","example":25},"required":false,"description":"Maximum number of results to return (1–100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response"},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response","name":"cursor","in":"query"}],"responses":{"200":{"description":"Paginated list of executive posts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExecutivePost"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/executive-media/summary":{"get":{"operationId":"brand_executive_media_summary","tags":["Executive Media"],"summary":"Get executive media summary","description":"Aggregated summary of executive media activity: post volume, cadence, platform mix, and top themes. Same shape and filters as the owned-media summary, over the executive dataset. Sentiment is always empty — these analyzers tag tone, never sentiment.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","description":"Filter to a single platform (e.g. instagram, tiktok, twitter). Mutually exclusive with exclude_platform.","example":"instagram"},"required":false,"description":"Filter to a single platform (e.g. instagram, tiktok, twitter). Mutually exclusive with exclude_platform.","name":"platform","in":"query"},{"schema":{"type":"string","description":"Exclude a single platform from the results (e.g. facebook). Mutually exclusive with platform.","example":"facebook"},"required":false,"description":"Exclude a single platform from the results (e.g. facebook). Mutually exclusive with platform.","name":"exclude_platform","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter posts on or after this date (ISO 8601)","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Filter posts on or after this date (ISO 8601)","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter posts on or before this date (ISO 8601)","example":"2026-03-31T23:59:59Z"},"required":false,"description":"Filter posts on or before this date (ISO 8601)","name":"end_date","in":"query"},{"schema":{"type":"string","description":"Filter by region","example":"us"},"required":false,"description":"Filter by region","name":"region","in":"query"}],"responses":{"200":{"description":"Executive media summary","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OwnedMediaSummary"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/executive-media/posts/{post_id}":{"get":{"operationId":"brand_executive_media_posts_get","tags":["Executive Media"],"summary":"Get executive post","description":"Get details for a single executive-media post by ID.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Post ID (UUID)","example":"p1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Post ID (UUID)","name":"post_id","in":"path"}],"responses":{"200":{"description":"Post details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ExecutivePostDetail"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand or post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/executives/{executive_id}":{"get":{"operationId":"brand_executives_get","tags":["Executives"],"summary":"Get tracked executive","description":"Get a single tracked executive and their registered profiles.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Brand executive ID (UUID)","example":"x1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand executive ID (UUID)","name":"executive_id","in":"path"}],"responses":{"200":{"description":"Executive details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Executive"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand or executive not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/paid-media/ads":{"get":{"operationId":"brand_paid_media_ads_list","tags":["Paid Media"],"summary":"List ads","description":"List paid advertising creatives for a brand with optional filters for platform, status and date range, and optional sorting — including by how long an ad has been running. Returns analyzer-approved ads only. Results are paginated.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","description":"Filter by ad platform (e.g. meta, google, tiktok)","example":"meta"},"required":false,"description":"Filter by ad platform (e.g. meta, google, tiktok)","name":"platform","in":"query"},{"schema":{"type":"string","enum":["ACTIVE","ENDED"],"description":"Filter by ad status (ACTIVE or ENDED). LinkedIn ads read ACTIVE as \"active in the last 30 days\" (its activity window), not serving right now; Meta/Google ACTIVE is true liveness from real flight dates.","example":"ACTIVE"},"required":false,"description":"Filter by ad status (ACTIVE or ENDED). LinkedIn ads read ACTIVE as \"active in the last 30 days\" (its activity window), not serving right now; Meta/Google ACTIVE is true liveness from real flight dates.","name":"status","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter to ads running on or after this date (ISO 8601). Overlap semantics — an ad matches if it ran at any point inside the range. Most ads carry no end_date, so the run end falls back to crawl evidence: on LinkedIn, the last serving crawl that saw the ad, so one we stopped seeing drops out of recent windows; on Meta and Google, whose daily runs skip evergreen ads, the run stays open-ended and the ad matches every later window. The summary defaults this to 30 days ago; the list applies no default.","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Filter to ads running on or after this date (ISO 8601). Overlap semantics — an ad matches if it ran at any point inside the range. Most ads carry no end_date, so the run end falls back to crawl evidence: on LinkedIn, the last serving crawl that saw the ad, so one we stopped seeing drops out of recent windows; on Meta and Google, whose daily runs skip evergreen ads, the run stays open-ended and the ad matches every later window. The summary defaults this to 30 days ago; the list applies no default.","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter to ads running on or before this date (ISO 8601). An ad the platform gave no start_date runs from the day Waldo first saw it — a crawl date, not a launch date, so a brand's backfilled history carries the day it was onboarded and this bound cannot separate ads that ran before it. The summary defaults this to now; the list applies no default.","example":"2026-03-31T23:59:59Z"},"required":false,"description":"Filter to ads running on or before this date (ISO 8601). An ad the platform gave no start_date runs from the day Waldo first saw it — a crawl date, not a launch date, so a brand's backfilled history carries the day it was onboarded and this bound cannot separate ads that ran before it. The summary defaults this to now; the list applies no default.","name":"end_date","in":"query"},{"schema":{"type":"string","enum":["start_date","end_date","days_running"],"description":"Order results by start_date (default, recency), end_date, or days_running (how long the ad has been running — frozen at its run length once ended). Ads missing the chosen date sort last.","example":"days_running"},"required":false,"description":"Order results by start_date (default, recency), end_date, or days_running (how long the ad has been running — frozen at its run length once ended). Ads missing the chosen date sort last.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: desc (default) or asc.","example":"desc"},"required":false,"description":"Sort direction: desc (default) or asc.","name":"order","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Maximum number of results to return (1–100)","example":20},"required":false,"description":"Maximum number of results to return (1–100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response"},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response","name":"cursor","in":"query"}],"responses":{"200":{"description":"Paginated list of ads","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Ad"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":[{"ad_id":"0a1b2c3d-0001-4e5f-8a6b-000000000201","brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","platform":"meta","title":null,"body":"Example ad: make it here, take it anywhere.\n\nThe city's best street players head to the Example City Finals on June 25th for a chance to go all the way.\n\nTap the link for details.","media_urls":["https://data.waldo.fyi/v1/media/ad/0a1b2c3d-0001-4e5f-8a6b-000000000201/0"],"targeting":{"platforms":["FACEBOOK","INSTAGRAM"]},"source_cta":{"url":"https://www.example.com/events/example-city-finals","text":"Example CTA: Learn more","type":"LEARN_MORE"},"cta":"learn_more","cta_text":"Learn more","on_screen_text":"Example on-screen text:\nMAKE IT HERE\nEXAMPLE CITY FINALS\n6.25","promotion":{"is_promotional":false,"discount_type":null,"discount_value":null,"discount_unit":null,"discount_text":null,"promo_code":null,"conditions":null,"expires_at":null,"confidence":null},"currency":"USD","status":"ENDED","start_date":"2026-06-22T00:00:00.000Z","end_date":"2026-06-23T00:00:00.000Z","landing_page_url":"https://www.example.com/events/example-city-finals","days_running":1,"region":null,"length_seconds":21.77177177177177,"analysis":{"tone":"aspirational","target_aspect":"event","offers":[],"topic_tags":["street-basketball","city-finals","community-event"],"entities":[{"type":"event","value":"Example City Finals"},{"type":"place","value":"New York"},{"type":"brand","value":"Example Street League"}],"brands":["Example Street League"],"audiences":["street-basketball-players","sports-fans","new-york-city-residents"],"industries":["apparel","sports"],"analyzed_at":"2026-06-23T17:07:08.231Z"},"first_seen_at":"2026-06-22T17:06:04.566Z","last_seen_at":"2026-06-23T17:06:04.566Z","fetched_at":"2026-06-23T17:06:04.566Z"},{"ad_id":"0a1b2c3d-0002-4e5f-8a6b-000000000202","brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","platform":"meta","title":null,"body":"Example ad: different city. Same mentality.","media_urls":["https://data.waldo.fyi/v1/media/ad/0a1b2c3d-0002-4e5f-8a6b-000000000202/0","https://data.waldo.fyi/v1/media/ad/0a1b2c3d-0002-4e5f-8a6b-000000000202/1"],"targeting":{"platforms":["INSTAGRAM"]},"source_cta":{"url":"https://www.example.com/soccer","text":"Example CTA: Learn more","type":"LEARN_MORE"},"cta":"learn_more","cta_text":"Learn more","on_screen_text":"Example on-screen text:\nNO DAYS OFF.\nUSA","promotion":{"is_promotional":false,"discount_type":null,"discount_value":null,"discount_unit":null,"discount_text":null,"promo_code":null,"conditions":null,"expires_at":null,"confidence":null},"currency":"USD","status":"ENDED","start_date":"2026-06-20T00:00:00.000Z","end_date":"2026-06-21T00:00:00.000Z","landing_page_url":"https://www.example.com/soccer","days_running":1,"region":null,"length_seconds":null,"analysis":{"tone":"aspirational","target_aspect":"brand","offers":[],"topic_tags":["soccer","usa-sports","brand-campaign"],"entities":[{"type":"brand","value":"Example Soccer Club"},{"type":"category","value":"soccer"},{"type":"event","value":"Example national team"}],"brands":[],"audiences":["soccer-fans","athletes","sports-enthusiasts"],"industries":["apparel","sportswear"],"analyzed_at":"2026-06-20T17:07:25.987Z"},"first_seen_at":"2026-06-20T17:06:05.370Z","last_seen_at":"2026-06-21T17:06:05.370Z","fetched_at":"2026-06-21T17:06:05.370Z"},{"ad_id":"0a1b2c3d-0003-4e5f-8a6b-000000000203","brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","platform":"meta","title":"Example Community Experiences.","body":"Example ad: all roads lead to the national finals.\n\nFrom coast to coast, the best young players earned their place. Now there's only one thing left to do.\n\nWho wins it all? Come see for yourself.","media_urls":["https://data.waldo.fyi/v1/media/ad/0a1b2c3d-0003-4e5f-8a6b-000000000203/0"],"targeting":{"platforms":["FACEBOOK","INSTAGRAM"]},"source_cta":{"url":"https://www.example.com/events/example-national-finals","text":"Example CTA: Learn more","type":"LEARN_MORE"},"cta":"learn_more","cta_text":"Learn more","on_screen_text":"Example on-screen text:\nNATIONAL FINALS\nJune\n25-27\nStreet soccer. Live music. Local merch.","promotion":{"is_promotional":false,"discount_type":null,"discount_value":null,"discount_unit":null,"discount_text":null,"promo_code":null,"conditions":null,"expires_at":null,"confidence":null},"currency":"USD","status":"ENDED","start_date":"2026-06-17T00:00:00.000Z","end_date":"2026-06-19T00:00:00.000Z","landing_page_url":"https://www.example.com/events/example-national-finals","days_running":2,"region":null,"length_seconds":null,"analysis":{"tone":"celebratory","target_aspect":"event","offers":[],"topic_tags":["basketball","community-event","youth-sports"],"entities":[{"type":"event","value":"Example National Finals"},{"type":"place","value":"Bryant Park"},{"type":"place","value":"New York"}],"brands":["Example Street League"],"audiences":["youth-athletes","basketball-fans","local-community"],"industries":["sportswear","sports-events"],"analyzed_at":"2026-06-18T17:07:28.909Z"},"first_seen_at":"2026-06-17T17:06:15.976Z","last_seen_at":"2026-06-19T17:06:15.976Z","fetched_at":"2026-06-19T17:06:15.976Z"}],"meta":{"request_id":"req_example","total":1011,"total_pages":337,"next_cursor":"ZXhhbXBsZS1jdXJzb3I.ZXhhbXBsZQ"}}}}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/paid-media/ads/{ad_id}":{"get":{"operationId":"brand_paid_media_ads_get","tags":["Paid Media"],"summary":"Get ad","description":"Get details for a single paid media ad by ID. Returns the row regardless of analyzer stage (the list endpoint defaults to analyzer-approved only).","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Ad ID (UUID)","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Ad ID (UUID)","name":"ad_id","in":"path"}],"responses":{"200":{"description":"Ad details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Ad"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand or ad not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/paid-media/ads/{ad_id}/landing-page":{"get":{"operationId":"brand_paid_media_ads_landing_page_get","tags":["Paid Media"],"summary":"Capture ad landing page","description":"Capture a snapshot of the landing page an ad clicks through to — full-page screenshot, normalized destination URL, and capture timestamp. Capture-on-request: each call to a real landing page takes a fresh screenshot. Snapshots are retained 90 days for change detection. Destinations that aren't capturable landing pages (no URL, unresolved tracking macro, app-store link, or bare homepage) return 200 with a skip_reason and no screenshot.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Ad ID (UUID)","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Ad ID (UUID)","name":"ad_id","in":"path"}],"responses":{"200":{"description":"Landing-page snapshot (captured or skipped)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AdLandingPage"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand or ad not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/paid-media/summary":{"get":{"operationId":"brand_paid_media_summary","tags":["Paid Media"],"summary":"Get paid media summary","description":"Get a summary of paid media activity for a brand, including total spend, active campaigns, and platform breakdown. Accepts the same platform, status and date-range filters as GET /paid-media/ads, and aggregates over exactly the ads that list returns for an identical filter set. This endpoint defaults the window to the last 30 days while the list leaves it open, so pass the same explicit start_date/end_date to both when comparing. The two count different things over that one population: total_ads counts CREATIVES (Meta variants of one creative collapse to one) while the list paginates the variant ROWS, so the list can return far more rows than total_ads. variant_count is not the reconciling figure either — it is Meta's declared set size, not the rows we hold.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","description":"Filter by ad platform (e.g. meta, google, tiktok)","example":"meta"},"required":false,"description":"Filter by ad platform (e.g. meta, google, tiktok)","name":"platform","in":"query"},{"schema":{"type":"string","enum":["ACTIVE","ENDED"],"description":"Filter by ad status (ACTIVE or ENDED). LinkedIn ads read ACTIVE as \"active in the last 30 days\" (its activity window), not serving right now; Meta/Google ACTIVE is true liveness from real flight dates.","example":"ACTIVE"},"required":false,"description":"Filter by ad status (ACTIVE or ENDED). LinkedIn ads read ACTIVE as \"active in the last 30 days\" (its activity window), not serving right now; Meta/Google ACTIVE is true liveness from real flight dates.","name":"status","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter to ads running on or after this date (ISO 8601). Overlap semantics — an ad matches if it ran at any point inside the range. Most ads carry no end_date, so the run end falls back to crawl evidence: on LinkedIn, the last serving crawl that saw the ad, so one we stopped seeing drops out of recent windows; on Meta and Google, whose daily runs skip evergreen ads, the run stays open-ended and the ad matches every later window. The summary defaults this to 30 days ago; the list applies no default.","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Filter to ads running on or after this date (ISO 8601). Overlap semantics — an ad matches if it ran at any point inside the range. Most ads carry no end_date, so the run end falls back to crawl evidence: on LinkedIn, the last serving crawl that saw the ad, so one we stopped seeing drops out of recent windows; on Meta and Google, whose daily runs skip evergreen ads, the run stays open-ended and the ad matches every later window. The summary defaults this to 30 days ago; the list applies no default.","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter to ads running on or before this date (ISO 8601). An ad the platform gave no start_date runs from the day Waldo first saw it — a crawl date, not a launch date, so a brand's backfilled history carries the day it was onboarded and this bound cannot separate ads that ran before it. The summary defaults this to now; the list applies no default.","example":"2026-03-31T23:59:59Z"},"required":false,"description":"Filter to ads running on or before this date (ISO 8601). An ad the platform gave no start_date runs from the day Waldo first saw it — a crawl date, not a launch date, so a brand's backfilled history carries the day it was onboarded and this bound cannot separate ads that ran before it. The summary defaults this to now; the list applies no default.","name":"end_date","in":"query"}],"responses":{"200":{"description":"Paid media summary","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaidMediaSummary"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","total_ads":1010,"active_ads":0,"new_ads_in_period":40,"avg_new_ads_per_day":1.33,"avg_days_running":989.08,"estimated_total_spend":null,"by_platform":[{"platform":"google","ads":931,"ad_count":931,"active":0,"estimated_spend":null},{"platform":"meta","ads":79,"ad_count":79,"active":0,"estimated_spend":null}],"period":{"start":"2026-05-25T14:21:54.315Z","end":"2026-06-24T14:21:54.315Z"}},"meta":{"request_id":"req_example"}}}}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/paid-media/crawl-coverage":{"get":{"operationId":"brand_paid_media_crawl_coverage","tags":["Paid Media"],"summary":"Get ad crawl coverage","description":"Report, per day and per ad platform, whether Waldo attempted to collect this brand's ads — one row for every day in the window, including days with no attempt, so the series needs no gap-filling. This is what makes the ads list interpretable over time: `first_seen_at` records when Waldo first saw an ad, so a day with no new ads is ambiguous between \"the brand launched nothing\" and \"we didn't look\" until this endpoint resolves it. Days before the log holds anything for a platform report UNKNOWN rather than NOT_CRAWLED. Defaults to the last 30 days; windows wider than 366 days are rejected.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","description":"Filter by ad platform (e.g. meta, google, tiktok)","example":"meta"},"required":false,"description":"Filter by ad platform (e.g. meta, google, tiktok)","name":"platform","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"First day of the coverage window (ISO 8601 date or timestamp). Defaults to 30 days ago. Days are bucketed on the UTC calendar; days before the platform's first logged attempt report UNKNOWN rather than NOT_CRAWLED.","example":"2026-03-01"},"required":false,"description":"First day of the coverage window (ISO 8601 date or timestamp). Defaults to 30 days ago. Days are bucketed on the UTC calendar; days before the platform's first logged attempt report UNKNOWN rather than NOT_CRAWLED.","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Last day of the coverage window (ISO 8601 date or timestamp), inclusive. Defaults to today.","example":"2026-03-31"},"required":false,"description":"Last day of the coverage window (ISO 8601 date or timestamp), inclusive. Defaults to today.","name":"end_date","in":"query"}],"responses":{"200":{"description":"Daily crawl coverage","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CrawlCoverage"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"400":{"description":"Invalid date bound or a window wider than the maximum","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/mentions":{"get":{"operationId":"brand_mentions_list","tags":["Mentions"],"summary":"List brand mentions","description":"List third-party mentions of a brand (posts from accounts the brand does not own that reference it). Results are paginated.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","enum":["SOCIAL","NEWS"],"description":"Filter by source category: SOCIAL (social platforms and customer review sites) or NEWS (web articles)","example":"NEWS"},"required":false,"description":"Filter by source category: SOCIAL (social platforms and customer review sites) or NEWS (web articles)","name":"source_type","in":"query"},{"schema":{"type":"string","description":"Filter by platform (e.g. instagram, twitter, reddit)","example":"reddit"},"required":false,"description":"Filter by platform (e.g. instagram, twitter, reddit)","name":"platform","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter mentions on or after this date (ISO 8601)","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Filter mentions on or after this date (ISO 8601)","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter mentions on or before this date (ISO 8601)","example":"2026-03-31T23:59:59Z"},"required":false,"description":"Filter mentions on or before this date (ISO 8601)","name":"end_date","in":"query"},{"schema":{"type":"string","pattern":"^(?:[a-z]{2}|und)$","description":"Filter by the language the analyzer detected in the post body (matches the `language` field): a lowercase ISO 639-1 code such as `en`, `es` or `pt`, or `und` for posts with no readable text. Mentions not yet analyzed carry no language and are excluded by any value of this filter.","example":"en"},"required":false,"description":"Filter by the language the analyzer detected in the post body (matches the `language` field): a lowercase ISO 639-1 code such as `en`, `es` or `pt`, or `und` for posts with no readable text. Mentions not yet analyzed carry no language and are excluded by any value of this filter.","name":"language","in":"query"},{"schema":{"type":"string","enum":["POSITIVE","NEGATIVE","NEUTRAL","MIXED"],"description":"Filter by analyzer sentiment polarity (matches the `sentiment_polarity` field). Mentions not yet analyzed carry no polarity and are excluded by any value of this filter.","example":"NEGATIVE"},"required":false,"description":"Filter by analyzer sentiment polarity (matches the `sentiment_polarity` field). Mentions not yet analyzed carry no polarity and are excluded by any value of this filter.","name":"sentiment","in":"query"},{"schema":{"type":"string","enum":["CUSTOMER","FAN","INFLUENCER","RANDOM","EMPLOYEE","COMPETITOR","PRESS"],"description":"Filter by the analyzer's speaker classification (matches the `speaker_type` field). Mentions not yet analyzed carry no speaker type and are excluded by any value of this filter.","example":"PRESS"},"required":false,"description":"Filter by the analyzer's speaker classification (matches the `speaker_type` field). Mentions not yet analyzed carry no speaker type and are excluded by any value of this filter.","name":"speaker_type","in":"query"},{"schema":{"type":"string","maxLength":100,"description":"Filter by the analyzer's content-format label (matches the `content_type` field), compared exactly and case-sensitively. Not an enum — the vocabulary is per-analyzer; typical mention values are product-review, haul, unboxing, comparison, tutorial, news and other.","example":"product-review"},"required":false,"description":"Filter by the analyzer's content-format label (matches the `content_type` field), compared exactly and case-sensitively. Not an enum — the vocabulary is per-analyzer; typical mention values are product-review, haul, unboxing, comparison, tutorial, news and other.","name":"content_type","in":"query"},{"schema":{"type":"string","enum":["PRIMARY","COVERAGE","ANALYSIS","CURATORIAL"],"description":"Filter by how close the source sits to the story (matches the `source_primacy` field): PRIMARY, COVERAGE, ANALYSIS or CURATORIAL. Mentions not yet analyzed are excluded by any value of this filter.","example":"PRIMARY"},"required":false,"description":"Filter by how close the source sits to the story (matches the `source_primacy` field): PRIMARY, COVERAGE, ANALYSIS or CURATORIAL. Mentions not yet analyzed are excluded by any value of this filter.","name":"source_primacy","in":"query"},{"schema":{"type":"string","maxLength":100,"description":"Filter to mentions carrying this analyzer topic tag. Matched exactly (and case-sensitively) against `topic_tags` — pass a tag as returned by /mentions/summary top_themes.","example":"product-launch"},"required":false,"description":"Filter to mentions carrying this analyzer topic tag. Matched exactly (and case-sensitively) against `topic_tags` — pass a tag as returned by /mentions/summary top_themes.","name":"topic","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Full-text filter over mention text. Supports quoted phrases and or/- operators; terms are stemmed, so `launch` matches `launched`.","example":"\"battery life\" or charging"},"required":false,"description":"Full-text filter over mention text. Supports quoted phrases and or/- operators; terms are stemmed, so `launch` matches `launched`.","name":"q","in":"query"},{"schema":{"type":"string","enum":["posted_at","likes","comments","shares","views"],"description":"Order results by posted_at (default, recency) or a raw engagement metric: likes, comments, shares, or views. Engagement is compared as raw counts, so a metric sort is only directly meaningful within one platform — pair it with `platform`. NEWS mentions carry no engagement and sort last.","example":"likes"},"required":false,"description":"Order results by posted_at (default, recency) or a raw engagement metric: likes, comments, shares, or views. Engagement is compared as raw counts, so a metric sort is only directly meaningful within one platform — pair it with `platform`. NEWS mentions carry no engagement and sort last.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: desc (default) or asc.","example":"desc"},"required":false,"description":"Sort direction: desc (default) or asc.","name":"order","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Maximum number of results to return (1–100)","example":20},"required":false,"description":"Maximum number of results to return (1–100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response"},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response","name":"cursor","in":"query"}],"responses":{"200":{"description":"Paginated list of mentions","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Mention"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":[{"id":"0c1d2e3f-0001-4a2b-9c3d-000000000301","brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","source_type":"SOCIAL","source_platform":"twitter","author":{"handle":null,"name":null},"text":"Example mention: picked up my new running shoes from the brand today and took them straight to the track.","url":"https://x.com/example_fan/status/1000000000000000301","sentiment_polarity":"POSITIVE","sentiment_intensity":"MEDIUM","sentiment_aspect":"sponsorship","topic_tags":["basketball-camp","throwback","nike-events"],"speaker_type":"FAN","content_type":"other","source_name":null,"source_author":null,"source_primacy":null,"language":"en","posted_at":"2026-06-28T21:07:02.968Z","fetched_at":"2026-06-28T21:07:03.041Z","discovered_at":"2026-06-28T21:07:03.041Z"},{"id":"0c1d2e3f-0002-4a2b-9c3d-000000000302","brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","source_type":"SOCIAL","source_platform":"facebook","author":{"handle":null,"name":null},"text":"Example news post: the brand names a new chief executive as it works through a slower turnaround. The pay package includes a base salary, long-term incentives and a signing bonus ...","url":"https://www.facebook.com/example_news_page/posts/1000000000000000302/","sentiment_polarity":"MIXED","sentiment_intensity":"MEDIUM","sentiment_aspect":"leadership","topic_tags":["executive-hire","leadership","compensation"],"speaker_type":"PRESS","content_type":"news","source_name":"Example Retail News","source_author":null,"source_primacy":"COVERAGE","language":"en","posted_at":"2026-06-28T21:06:52.535Z","fetched_at":"2026-06-28T21:06:52.712Z","discovered_at":"2026-06-28T21:06:52.712Z"},{"id":"0c1d2e3f-0003-4a2b-9c3d-000000000303","brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","source_type":"SOCIAL","source_platform":"twitter","author":{"handle":null,"name":null},"text":"Example news post: the brand reports quarterly results and outlines plans for new store openings next year.","url":"https://x.com/example_markets/status/1000000000000000303","sentiment_polarity":"NEUTRAL","sentiment_intensity":"LOW","sentiment_aspect":"financial-performance","topic_tags":["q4-earnings","cfo-change","tariffs"],"speaker_type":"PRESS","content_type":"news","source_name":"Example Markets Daily","source_author":null,"source_primacy":"ANALYSIS","language":"en","posted_at":"2026-06-28T21:06:52.534Z","fetched_at":"2026-06-28T21:06:52.652Z","discovered_at":"2026-06-28T21:06:52.652Z"}],"meta":{"request_id":"req_example","total":1547,"total_pages":516,"next_cursor":"ZXhhbXBsZS1jdXJzb3I.ZXhhbXBsZQ"}}}}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/mentions/summary":{"get":{"operationId":"brand_mentions_summary","tags":["Mentions"],"summary":"Get mentions summary","description":"Aggregate mention volume for a brand over a window: total count, average per day, breakdowns by source type and by platform, top communities, top themes, and sentiment distribution. Accepts the same filters as GET /mentions; passing an identical filter set - including an explicit start_date/end_date, which this endpoint defaults to the last 30 days - yields aggregates over exactly the mentions the list returns.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","enum":["SOCIAL","NEWS"],"description":"Filter by source category: SOCIAL (social platforms and customer review sites) or NEWS (web articles)","example":"NEWS"},"required":false,"description":"Filter by source category: SOCIAL (social platforms and customer review sites) or NEWS (web articles)","name":"source_type","in":"query"},{"schema":{"type":"string","description":"Filter by platform (e.g. instagram, twitter, reddit)","example":"reddit"},"required":false,"description":"Filter by platform (e.g. instagram, twitter, reddit)","name":"platform","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Start of date range (ISO 8601). Defaults to 30 days ago.","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Start of date range (ISO 8601). Defaults to 30 days ago.","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"End of date range (ISO 8601). Defaults to now.","example":"2026-03-31T23:59:59Z"},"required":false,"description":"End of date range (ISO 8601). Defaults to now.","name":"end_date","in":"query"},{"schema":{"type":"string","pattern":"^(?:[a-z]{2}|und)$","description":"Filter by the language the analyzer detected in the post body (matches the `language` field): a lowercase ISO 639-1 code such as `en`, `es` or `pt`, or `und` for posts with no readable text. Mentions not yet analyzed carry no language and are excluded by any value of this filter.","example":"en"},"required":false,"description":"Filter by the language the analyzer detected in the post body (matches the `language` field): a lowercase ISO 639-1 code such as `en`, `es` or `pt`, or `und` for posts with no readable text. Mentions not yet analyzed carry no language and are excluded by any value of this filter.","name":"language","in":"query"},{"schema":{"type":"string","enum":["POSITIVE","NEGATIVE","NEUTRAL","MIXED"],"description":"Filter by analyzer sentiment polarity (matches the `sentiment_polarity` field). Mentions not yet analyzed carry no polarity and are excluded by any value of this filter.","example":"NEGATIVE"},"required":false,"description":"Filter by analyzer sentiment polarity (matches the `sentiment_polarity` field). Mentions not yet analyzed carry no polarity and are excluded by any value of this filter.","name":"sentiment","in":"query"},{"schema":{"type":"string","enum":["CUSTOMER","FAN","INFLUENCER","RANDOM","EMPLOYEE","COMPETITOR","PRESS"],"description":"Filter by the analyzer's speaker classification (matches the `speaker_type` field). Mentions not yet analyzed carry no speaker type and are excluded by any value of this filter.","example":"PRESS"},"required":false,"description":"Filter by the analyzer's speaker classification (matches the `speaker_type` field). Mentions not yet analyzed carry no speaker type and are excluded by any value of this filter.","name":"speaker_type","in":"query"},{"schema":{"type":"string","maxLength":100,"description":"Filter by the analyzer's content-format label (matches the `content_type` field), compared exactly and case-sensitively. Not an enum — the vocabulary is per-analyzer; typical mention values are product-review, haul, unboxing, comparison, tutorial, news and other.","example":"product-review"},"required":false,"description":"Filter by the analyzer's content-format label (matches the `content_type` field), compared exactly and case-sensitively. Not an enum — the vocabulary is per-analyzer; typical mention values are product-review, haul, unboxing, comparison, tutorial, news and other.","name":"content_type","in":"query"},{"schema":{"type":"string","enum":["PRIMARY","COVERAGE","ANALYSIS","CURATORIAL"],"description":"Filter by how close the source sits to the story (matches the `source_primacy` field): PRIMARY, COVERAGE, ANALYSIS or CURATORIAL. Mentions not yet analyzed are excluded by any value of this filter.","example":"PRIMARY"},"required":false,"description":"Filter by how close the source sits to the story (matches the `source_primacy` field): PRIMARY, COVERAGE, ANALYSIS or CURATORIAL. Mentions not yet analyzed are excluded by any value of this filter.","name":"source_primacy","in":"query"},{"schema":{"type":"string","maxLength":100,"description":"Filter to mentions carrying this analyzer topic tag. Matched exactly (and case-sensitively) against `topic_tags` — pass a tag as returned by /mentions/summary top_themes.","example":"product-launch"},"required":false,"description":"Filter to mentions carrying this analyzer topic tag. Matched exactly (and case-sensitively) against `topic_tags` — pass a tag as returned by /mentions/summary top_themes.","name":"topic","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Full-text filter over mention text. Supports quoted phrases and or/- operators; terms are stemmed, so `launch` matches `launched`.","example":"\"battery life\" or charging"},"required":false,"description":"Full-text filter over mention text. Supports quoted phrases and or/- operators; terms are stemmed, so `launch` matches `launched`.","name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":10,"description":"How many entries top_themes returns, most frequent first (1–200, default 10). Compare against themes_total to see how much of the brand's topic vocabulary this covers — a themes_total above 200 cannot be fully enumerated here.","example":10},"required":false,"description":"How many entries top_themes returns, most frequent first (1–200, default 10). Compare against themes_total to see how much of the brand's topic vocabulary this covers — a themes_total above 200 cannot be fully enumerated here.","name":"themes_limit","in":"query"}],"responses":{"200":{"description":"Mentions summary","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MentionsSummary"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"brand_id":"121030cf-e18c-46c6-847a-03ce22ff88a3","total_mentions":14,"undated_count":2,"mentions_per_day":0.47,"by_source":[{"source_type":"SOCIAL","count":11},{"source_type":"NEWS","count":3}],"by_platform":[{"platform":"reddit","count":7},{"platform":"web","count":3},{"platform":"twitter","count":2}],"top_communities":[{"community":"r/Nike","count":3},{"community":"r/Sneakers","count":3},{"community":"x.com","count":2}],"top_themes":[{"theme":"sneakers","frequency":3},{"theme":"comfort","frequency":3},{"theme":"community-question","frequency":2}],"sentiment_distribution":{"positive":{"count":7,"percentage":50},"neutral":{"count":4,"percentage":28.6},"negative":{"count":1,"percentage":7.1},"mixed":{"count":2,"percentage":14.3}},"period":{"start":"2026-06-28T14:24:27.205Z","end":"2026-07-28T14:24:27.205Z"}},"meta":{"request_id":"req_example"}}}}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/mentions/analysis":{"get":{"operationId":"brand_mentions_analysis","tags":["Mentions"],"summary":"Mention themes and sentiment trend","description":"What a brand's mentions are about and how the mood is moving. Returns meaning-based themes from the stored conversation-cluster set — each with a stable theme_id, a generated label, size/share, per-polarity counts, top-author share and confidence — alongside the analyzer's topic-tag counts and a daily sentiment trend. Takes no window: every figure describes the period in meta.window_start/window_end, which comes from the cluster set (built weekly, so it trails the present by up to a refresh interval). top_themes is empty with meta.set_version null until the brand has been clustered, which is not the same as having no themes. News mentions are excluded from clustering by design — counted in meta.total_mentions, never inside a theme.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"}],"responses":{"200":{"description":"Mention themes, topic-tag counts and sentiment trend","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MentionsAnalysis"},"meta":{"$ref":"#/components/schemas/MentionsAnalysisMeta"}},"required":["data","meta"]}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/mentions/{mention_id}":{"get":{"operationId":"brand_mentions_get","tags":["Mentions"],"summary":"Get mention","description":"Get a single mention by ID.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Mention ID (UUID — corresponds to the underlying post_id)","example":"p1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Mention ID (UUID — corresponds to the underlying post_id)","name":"mention_id","in":"path"}],"responses":{"200":{"description":"Mention details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Mention"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand or mention not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/customer-complaints":{"get":{"operationId":"brand_customer_complaints","tags":["Mentions"],"summary":"Customer complaints","description":"What customers complain about: negative mentions grouped by aspect (what the sentiment is about), each with a frequency, dominant intensity, representative verbatim examples, and source link-backs. Ordered by frequency, descending. Accepts the same filters as GET /mentions except sentiment, which is fixed to negative. Aggregates all-time by default; pass start_date/end_date to narrow the window.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","enum":["SOCIAL","NEWS"],"description":"Filter by source category: SOCIAL (social platforms and customer review sites) or NEWS (web articles)","example":"NEWS"},"required":false,"description":"Filter by source category: SOCIAL (social platforms and customer review sites) or NEWS (web articles)","name":"source_type","in":"query"},{"schema":{"type":"string","description":"Filter by platform (e.g. instagram, twitter, reddit)","example":"reddit"},"required":false,"description":"Filter by platform (e.g. instagram, twitter, reddit)","name":"platform","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter mentions on or after this date (ISO 8601)","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Filter mentions on or after this date (ISO 8601)","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter mentions on or before this date (ISO 8601)","example":"2026-03-31T23:59:59Z"},"required":false,"description":"Filter mentions on or before this date (ISO 8601)","name":"end_date","in":"query"},{"schema":{"type":"string","pattern":"^(?:[a-z]{2}|und)$","description":"Filter by the language the analyzer detected in the post body (matches the `language` field): a lowercase ISO 639-1 code such as `en`, `es` or `pt`, or `und` for posts with no readable text. Mentions not yet analyzed carry no language and are excluded by any value of this filter.","example":"en"},"required":false,"description":"Filter by the language the analyzer detected in the post body (matches the `language` field): a lowercase ISO 639-1 code such as `en`, `es` or `pt`, or `und` for posts with no readable text. Mentions not yet analyzed carry no language and are excluded by any value of this filter.","name":"language","in":"query"},{"schema":{"type":"string","enum":["CUSTOMER","FAN","INFLUENCER","RANDOM","EMPLOYEE","COMPETITOR","PRESS"],"description":"Filter by the analyzer's speaker classification (matches the `speaker_type` field). Mentions not yet analyzed carry no speaker type and are excluded by any value of this filter.","example":"PRESS"},"required":false,"description":"Filter by the analyzer's speaker classification (matches the `speaker_type` field). Mentions not yet analyzed carry no speaker type and are excluded by any value of this filter.","name":"speaker_type","in":"query"},{"schema":{"type":"string","maxLength":100,"description":"Filter by the analyzer's content-format label (matches the `content_type` field), compared exactly and case-sensitively. Not an enum — the vocabulary is per-analyzer; typical mention values are product-review, haul, unboxing, comparison, tutorial, news and other.","example":"product-review"},"required":false,"description":"Filter by the analyzer's content-format label (matches the `content_type` field), compared exactly and case-sensitively. Not an enum — the vocabulary is per-analyzer; typical mention values are product-review, haul, unboxing, comparison, tutorial, news and other.","name":"content_type","in":"query"},{"schema":{"type":"string","enum":["PRIMARY","COVERAGE","ANALYSIS","CURATORIAL"],"description":"Filter by how close the source sits to the story (matches the `source_primacy` field): PRIMARY, COVERAGE, ANALYSIS or CURATORIAL. Mentions not yet analyzed are excluded by any value of this filter.","example":"PRIMARY"},"required":false,"description":"Filter by how close the source sits to the story (matches the `source_primacy` field): PRIMARY, COVERAGE, ANALYSIS or CURATORIAL. Mentions not yet analyzed are excluded by any value of this filter.","name":"source_primacy","in":"query"},{"schema":{"type":"string","maxLength":100,"description":"Filter to mentions carrying this analyzer topic tag. Matched exactly (and case-sensitively) against `topic_tags` — pass a tag as returned by /mentions/summary top_themes.","example":"product-launch"},"required":false,"description":"Filter to mentions carrying this analyzer topic tag. Matched exactly (and case-sensitively) against `topic_tags` — pass a tag as returned by /mentions/summary top_themes.","name":"topic","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Full-text filter over mention text. Supports quoted phrases and or/- operators; terms are stemmed, so `launch` matches `launched`.","example":"\"battery life\" or charging"},"required":false,"description":"Full-text filter over mention text. Supports quoted phrases and or/- operators; terms are stemmed, so `launch` matches `launched`.","name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"Maximum number of aspects to return (1–100)","example":25},"required":false,"description":"Maximum number of aspects to return (1–100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response"},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response","name":"cursor","in":"query"}],"responses":{"200":{"description":"Paginated list of aspects","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AspectCluster"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/love-letters":{"get":{"operationId":"brand_love_letters","tags":["Mentions"],"summary":"Love letters","description":"What customers love: positive mentions grouped by aspect (what the sentiment is about), each with a frequency, dominant intensity, representative verbatim examples, and source link-backs. Ordered by frequency, descending. Accepts the same filters as GET /mentions except sentiment, which is fixed to positive. Aggregates all-time by default; pass start_date/end_date to narrow the window.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID (UUID)","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID (UUID)","name":"brand_id","in":"path"},{"schema":{"type":"string","enum":["SOCIAL","NEWS"],"description":"Filter by source category: SOCIAL (social platforms and customer review sites) or NEWS (web articles)","example":"NEWS"},"required":false,"description":"Filter by source category: SOCIAL (social platforms and customer review sites) or NEWS (web articles)","name":"source_type","in":"query"},{"schema":{"type":"string","description":"Filter by platform (e.g. instagram, twitter, reddit)","example":"reddit"},"required":false,"description":"Filter by platform (e.g. instagram, twitter, reddit)","name":"platform","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter mentions on or after this date (ISO 8601)","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Filter mentions on or after this date (ISO 8601)","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter mentions on or before this date (ISO 8601)","example":"2026-03-31T23:59:59Z"},"required":false,"description":"Filter mentions on or before this date (ISO 8601)","name":"end_date","in":"query"},{"schema":{"type":"string","pattern":"^(?:[a-z]{2}|und)$","description":"Filter by the language the analyzer detected in the post body (matches the `language` field): a lowercase ISO 639-1 code such as `en`, `es` or `pt`, or `und` for posts with no readable text. Mentions not yet analyzed carry no language and are excluded by any value of this filter.","example":"en"},"required":false,"description":"Filter by the language the analyzer detected in the post body (matches the `language` field): a lowercase ISO 639-1 code such as `en`, `es` or `pt`, or `und` for posts with no readable text. Mentions not yet analyzed carry no language and are excluded by any value of this filter.","name":"language","in":"query"},{"schema":{"type":"string","enum":["CUSTOMER","FAN","INFLUENCER","RANDOM","EMPLOYEE","COMPETITOR","PRESS"],"description":"Filter by the analyzer's speaker classification (matches the `speaker_type` field). Mentions not yet analyzed carry no speaker type and are excluded by any value of this filter.","example":"PRESS"},"required":false,"description":"Filter by the analyzer's speaker classification (matches the `speaker_type` field). Mentions not yet analyzed carry no speaker type and are excluded by any value of this filter.","name":"speaker_type","in":"query"},{"schema":{"type":"string","maxLength":100,"description":"Filter by the analyzer's content-format label (matches the `content_type` field), compared exactly and case-sensitively. Not an enum — the vocabulary is per-analyzer; typical mention values are product-review, haul, unboxing, comparison, tutorial, news and other.","example":"product-review"},"required":false,"description":"Filter by the analyzer's content-format label (matches the `content_type` field), compared exactly and case-sensitively. Not an enum — the vocabulary is per-analyzer; typical mention values are product-review, haul, unboxing, comparison, tutorial, news and other.","name":"content_type","in":"query"},{"schema":{"type":"string","enum":["PRIMARY","COVERAGE","ANALYSIS","CURATORIAL"],"description":"Filter by how close the source sits to the story (matches the `source_primacy` field): PRIMARY, COVERAGE, ANALYSIS or CURATORIAL. Mentions not yet analyzed are excluded by any value of this filter.","example":"PRIMARY"},"required":false,"description":"Filter by how close the source sits to the story (matches the `source_primacy` field): PRIMARY, COVERAGE, ANALYSIS or CURATORIAL. Mentions not yet analyzed are excluded by any value of this filter.","name":"source_primacy","in":"query"},{"schema":{"type":"string","maxLength":100,"description":"Filter to mentions carrying this analyzer topic tag. Matched exactly (and case-sensitively) against `topic_tags` — pass a tag as returned by /mentions/summary top_themes.","example":"product-launch"},"required":false,"description":"Filter to mentions carrying this analyzer topic tag. Matched exactly (and case-sensitively) against `topic_tags` — pass a tag as returned by /mentions/summary top_themes.","name":"topic","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Full-text filter over mention text. Supports quoted phrases and or/- operators; terms are stemmed, so `launch` matches `launched`.","example":"\"battery life\" or charging"},"required":false,"description":"Full-text filter over mention text. Supports quoted phrases and or/- operators; terms are stemmed, so `launch` matches `launched`.","name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"Maximum number of aspects to return (1–100)","example":25},"required":false,"description":"Maximum number of aspects to return (1–100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response"},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response","name":"cursor","in":"query"}],"responses":{"200":{"description":"Paginated list of aspects","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AspectCluster"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/emerging-needs":{"get":{"operationId":"audience_emerging_needs","tags":["Audiences"],"summary":"List newly identified and rising audience themes","description":"Newly identified and rising conversation themes across the audience's two latest stored cluster sets, without filtering by intent. NEW means a theme identity absent from the preceding set, not proof of a newly arising or unmet need: cluster splits and failed identity matches can mint new IDs. RISING requires at least 5 additional posts, at least 20% volume growth, and an increased share of scope posts. These are tunable heuristics, not statistical significance thresholds. Volumes are frozen counts in overlapping rolling windows; onset_velocity is their difference divided by elapsed days between window ends, not a count of newly published posts per day. Ordered by onset_velocity descending, then theme_id. No topic-tag fallback. Empty data with comparison_status distinguishes missing clustering, insufficient history and incompatible baselines from an available comparison with no emerging themes.","parameters":[{"schema":{"type":"string"},"required":true,"name":"audience_id","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":10,"default":3},"required":false,"name":"verbatim_limit","in":"query"}],"responses":{"200":{"description":"Emerging themes and their stored baseline","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmergingNeed"}},"meta":{"$ref":"#/components/schemas/EmergingNeedsMeta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/language-gap":{"get":{"operationId":"audience_language_gap","tags":["Audiences"],"summary":"Compare audience themes with owned messaging","description":"Evidence-first, exploratory comparison against an explicitly selected brand. Reads approved social/forum owned posts in the stored audience window. A not_observed judgment is limited to retrieved evidence, not proof of a gap in all brand communications. Requires access to both subjects. Returns at most three themes per page; cursor pins the audience baseline.","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"audience_id","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"brand_id","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":3,"default":3},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Evidence and scoped judgments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudienceLanguageGap"}}}},"404":{"description":"Audience or brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences":{"get":{"operationId":"audience_list","tags":["Audiences"],"summary":"List audiences","description":"List all audiences. Optionally filter by brand to see only audiences linked to that brand.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Filter audiences linked to a specific brand","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":false,"description":"Filter audiences linked to a specific brand","name":"brand_id","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Maximum number of results to return (1-100)","example":50},"required":false,"description":"Maximum number of results to return (1-100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response"},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response","name":"cursor","in":"query"}],"responses":{"200":{"description":"List of audiences","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Audience"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":[{"id":"AUD143","name":"Active traders","description":"Active traders. Example brands: Betterment, Charles Schwab, Fidelity, Public, Robinhood","top_interests":["Wealth","Brokerage & Asset Management"],"brand_count":0,"family":"Professional / B2B","cluster":"Investors, traders & wealth builders","granularity":"Mid"},{"id":"AUD053","name":"Adult nicotine users","description":"Adult nicotine users. Example brands: Cann, Grizzly, Juul, Marlboro, STIIIZY","top_interests":["Tobacco","Nicotine & Cannabis"],"brand_count":0,"family":"Consumer lifestyle","cluster":"Nicotine & cannabis consumers","granularity":"Niche"},{"id":"AUD127","name":"Advertisers and social marketers","description":"Advertisers and social marketers. Example brands: Discord, Instagram, Reddit, Snapchat, TikTok","top_interests":["Social Platforms","Messaging & Creator Ecosystems"],"brand_count":1,"family":"Professional / B2B","cluster":"Marketers & agency teams","granularity":"Mid"}],"meta":{"request_id":"req_example","total":150,"total_pages":50,"next_cursor":"ZXhhbXBsZS1jdXJzb3I.ZXhhbXBsZQ"}}}}}}}}}},"/v1/audiences/search":{"get":{"operationId":"audience_search","tags":["Audiences"],"summary":"Search audiences","description":"Search audiences by name. Returns a paginated list of matching audiences. Omit `q` to page the full catalog.","parameters":[{"schema":{"type":"string","description":"Search query — matches against audience name","example":"foodies"},"required":false,"description":"Search query — matches against audience name","name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Maximum number of results to return (1-100)","example":50},"required":false,"description":"Maximum number of results to return (1-100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response"},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response","name":"cursor","in":"query"}],"responses":{"200":{"description":"List of matching audiences","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Audience"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}}}}},"/v1/audiences/{audience_id}":{"get":{"operationId":"audience_get","tags":["Audiences"],"summary":"Get audience","description":"Get details for a single audience, including its description, top interests, and brand count.","parameters":[{"schema":{"type":"string","description":"Audience ID","example":"gen-z-foodies"},"required":true,"description":"Audience ID","name":"audience_id","in":"path"}],"responses":{"200":{"description":"Audience details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Audience"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/brands":{"get":{"operationId":"audience_brands","tags":["Audiences"],"summary":"List brands in audience","description":"Get a paginated list of brands linked to this audience, with relevance scores.","parameters":[{"schema":{"type":"string","description":"Audience ID","example":"gen-z-foodies"},"required":true,"description":"Audience ID","name":"audience_id","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"Maximum number of results to return (1-100)","example":25},"required":false,"description":"Maximum number of results to return (1-100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response"},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response","name":"cursor","in":"query"}],"responses":{"200":{"description":"Paginated list of brands in the audience","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AudienceBrand"}},"meta":{"$ref":"#/components/schemas/LinkageMeta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/conversations":{"get":{"operationId":"audience_conversations","tags":["Audiences"],"summary":"List conversation themes in audience","description":"The conversation themes in this audience's posts — each with a stable theme_id, an English label, size/share/confidence, and top verbatim examples pulled live from the posts behind it. Read meta.state before the data — it names which of three situations produced the response. CLUSTERED: the stored clustering layer, where a theme is an embedded cluster with a sentiment aspect in `type` and an intent, and meta.set_version names the set. TOPIC_TAGS: the audience has fewer than meta.min_scope_posts posts to cluster and the themes are analyzer topic tags instead — lower-fidelity, with null `type` and `intent`, a null set_version, and overlapping shares that do not sum to 1, because a post carries up to three tags where clusters are disjoint. PENDING_FIRST_REFRESH: above the floor but not yet clustered, so the list is empty and real themes arrive at the next weekly refresh. meta.source answers the narrower question of which machine built the themes. Under TOPIC_TAGS, `data` holds the largest `meta.theme_limit` themes by size while `meta.total` counts every distinct theme, so `total > theme_limit` means the smaller themes were cut and the endpoint does not page to them; `theme_limit` is null in every other state, where no cap applies.","parameters":[{"schema":{"type":"string","description":"Audience ID","example":"gen-z-foodies"},"required":true,"description":"Audience ID","name":"audience_id","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":10,"default":3,"description":"Verbatim examples to return per theme (1-10).","example":3},"required":false,"description":"Verbatim examples to return per theme (1-10).","name":"verbatim_limit","in":"query"}],"responses":{"200":{"description":"Conversation-theme clusters for the audience","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ConversationCluster"}},"meta":{"$ref":"#/components/schemas/ConversationThemesMeta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/triggers":{"get":{"operationId":"audience_triggers","tags":["Audiences"],"summary":"List consideration and purchase triggers in audience","description":"The conversation themes that move this audience toward consideration, purchase or action — the stored theme clusters classified TRIGGER, each with a stable theme_id, an English label, size/share/confidence and top verbatim examples pulled live from the members nearest the theme. Membership of this filtered set is re-decided at every refresh: intent is classified from that refresh's own member posts, so a theme can keep its theme_id and still drop out when it is reclassified away from TRIGGER — a theme's absence means it is not a trigger this week, not that it ended. Read meta.state before the data: BELOW_FLOOR means the audience carries fewer than meta.min_scope_posts clusterable posts, so it is never clustered and this endpoint has no tag-derived mode to fall back on; PENDING_FIRST_REFRESH means it is above that floor but not yet clustered, so the list fills at its next weekly refresh; CLUSTERED means a set was read, and meta.intent_classified = false then says the set predates intent classification rather than the audience having no triggers.","parameters":[{"schema":{"type":"string","description":"Audience ID","example":"gen-z-foodies"},"required":true,"description":"Audience ID","name":"audience_id","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":10,"default":3,"description":"Verbatim examples to return per theme (1-10).","example":3},"required":false,"description":"Verbatim examples to return per theme (1-10).","name":"verbatim_limit","in":"query"}],"responses":{"200":{"description":"Trigger themes for the audience","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ConversationCluster"}},"meta":{"$ref":"#/components/schemas/TriggersMeta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/awareness-map":{"get":{"operationId":"audience_awareness_map","tags":["Audiences"],"summary":"Map audience themes onto awareness stages","description":"This audience's conversation themes grouped by how aware the people in them are of their problem and of the solutions to it — Schwartz's five stages plus INDETERMINATE, always all six in funnel order, each with its theme count, post count, share of scope posts and themes. Stage is classified from each refresh's own member posts and never carried forward, so a theme whose audience moves down the funnel moves between levels while keeping its theme_id. The levels do not sum to 1: `meta.other_share` is the fraction of posts in no theme at all, and themes on a set built before awareness classification carry no stage and appear at no level. Verbatims are omitted by default — pass `verbatim_limit` to quote each theme. Read meta.state before the data: BELOW_FLOOR means the audience carries fewer than meta.min_scope_posts clusterable posts and is never clustered; PENDING_FIRST_REFRESH means it is above that floor but not yet clustered, so the levels fill at its next weekly refresh; CLUSTERED means a set was read, and meta.awareness_classified = false then says the set predates awareness classification rather than its themes sitting at no stage.","parameters":[{"schema":{"type":"string","description":"Audience ID","example":"gen-z-foodies"},"required":true,"description":"Audience ID","name":"audience_id","in":"path"},{"schema":{"type":"integer","minimum":0,"maximum":10,"default":0,"description":"Verbatim examples to return per theme (0-10). Defaults to 0: the map reads every theme in the set, so quoting them all costs one nearest-centroid query per theme.","example":0},"required":false,"description":"Verbatim examples to return per theme (0-10). Defaults to 0: the map reads every theme in the set, so quoting them all costs one nearest-centroid query per theme.","name":"verbatim_limit","in":"query"}],"responses":{"200":{"description":"Awareness-stage map for the audience","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AwarenessLevel"}},"meta":{"$ref":"#/components/schemas/AwarenessMeta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/objections":{"get":{"operationId":"audience_objections","tags":["Audiences"],"summary":"List objection themes in audience","description":"Why this audience pushes back: the stored conversation themes whose currently-approved members include at least 3 carrying NEGATIVE sentiment polarity, with verbatim examples drawn live from those members nearest the theme centroid. Theme-level fields (size, share, confidence, top_author_share, type, first_observed) are the same stored values /conversations reports for the same theme; everything prefixed objection_ is measured over the objecting subset instead. `type` is the labeler's call over the whole theme, so it can disagree with that subset. Ordered by objection_size, largest first. Read meta.state before the data: BELOW_FLOOR means the audience carries fewer than meta.min_scope_posts clusterable posts, so it is never clustered and this endpoint has no tag-derived mode to fall back on; PENDING_FIRST_REFRESH means it is above that floor but not yet clustered, so the list fills at its next weekly refresh; CLUSTERED means a set was read and an empty list is an answer about the audience.","parameters":[{"schema":{"type":"string","description":"Audience ID","example":"gen-z-foodies"},"required":true,"description":"Audience ID","name":"audience_id","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":10,"default":3,"description":"Verbatim examples to return per theme (1-10).","example":3},"required":false,"description":"Verbatim examples to return per theme (1-10).","name":"verbatim_limit","in":"query"}],"responses":{"200":{"description":"Objection themes for the audience","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ObjectionTheme"}},"meta":{"$ref":"#/components/schemas/ObjectionsMeta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/language":{"get":{"operationId":"audience_language","tags":["Audiences"],"summary":"List how an audience talks, by theme","description":"The vocabulary and phrasing this audience actually uses — every stored conversation theme with the words that distinguish it, and verbatim examples in the audience's own language. `terms` is mined from the theme's member posts at each weekly refresh and ordered by LIFT (the theme's rate of a term over the whole set's rate) rather than raw frequency, so it surfaces what this theme says more than its neighbours instead of the corpus's common words; `post_count` counts distinct posts, so a single repetitive poster cannot manufacture shared vocabulary. `lift` is reproducible from the response — see its field description. Terms are never stemmed, and word pairs require strict adjacency in the source text — a phrase spanning a function word forms no pair rather than being bridged into a string nobody wrote. Verbatims are the theme's members nearest its centroid, quoted in whatever language they were written in and carrying the detected `language` code. Theme-level fields (size, share, confidence, top_author_share, type, first_observed) are the same stored values /conversations reports for the same theme. Unfiltered by intent, unlike /triggers. Read meta.state before the data: BELOW_FLOOR means the audience carries fewer than meta.min_scope_posts clusterable posts, so it is never clustered and this endpoint has no tag-derived mode to fall back on; PENDING_FIRST_REFRESH means it is above that floor but not yet clustered, so the list fills at its next weekly refresh; CLUSTERED means a set was read and an empty list is an answer about the audience.","parameters":[{"schema":{"type":"string","description":"Audience ID","example":"gen-z-foodies"},"required":true,"description":"Audience ID","name":"audience_id","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":10,"default":3,"description":"Verbatim examples to return per theme (1-10).","example":3},"required":false,"description":"Verbatim examples to return per theme (1-10).","name":"verbatim_limit","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":25,"default":10,"description":"Distinctive terms to return per theme (1-25).","example":10},"required":false,"description":"Distinctive terms to return per theme (1-25).","name":"term_limit","in":"query"}],"responses":{"200":{"description":"Language themes for the audience","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LanguageTheme"}},"meta":{"$ref":"#/components/schemas/LanguageMeta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/subreddits":{"get":{"operationId":"audience_subreddits","tags":["Audiences"],"summary":"List audience subreddits","description":"Returns the curated list of sources for this audience as written by the audience-discoverer agent into `space.properties.sources`. Audiences are global reference data — the curated source lists are surfaced to any caller, not scoped to your team. Each item carries `type`, `kind`, `value`, optional `route`/`confidence`/`recurrence`/`fit_score`/`cluster`/`receipts`/`notes`. `kind: \"identify_only\"` means the source is listed for reference but not actively polled.\n\nFiltered to `type: subreddit`.","parameters":[{"schema":{"type":"string","description":"Audience ID","example":"gen-z-foodies"},"required":true,"description":"Audience ID","name":"audience_id","in":"path"}],"responses":{"200":{"description":"Subreddits curated for this audience","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AudienceSource"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/influencers":{"get":{"operationId":"audience_influencers","tags":["Audiences"],"summary":"List audience influencers","description":"Returns the curated list of sources for this audience as written by the audience-discoverer agent into `space.properties.sources`. Audiences are global reference data — the curated source lists are surfaced to any caller, not scoped to your team. Each item carries `type`, `kind`, `value`, optional `route`/`confidence`/`recurrence`/`fit_score`/`cluster`/`receipts`/`notes`. `kind: \"identify_only\"` means the source is listed for reference but not actively polled.\n\nFiltered to `type: influencer`.","parameters":[{"schema":{"type":"string","description":"Audience ID","example":"gen-z-foodies"},"required":true,"description":"Audience ID","name":"audience_id","in":"path"}],"responses":{"200":{"description":"Influencers curated for this audience","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AudienceSource"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/podcasts":{"get":{"operationId":"audience_podcasts","tags":["Audiences"],"summary":"List audience podcasts","description":"Returns the curated list of sources for this audience as written by the audience-discoverer agent into `space.properties.sources`. Audiences are global reference data — the curated source lists are surfaced to any caller, not scoped to your team. Each item carries `type`, `kind`, `value`, optional `route`/`confidence`/`recurrence`/`fit_score`/`cluster`/`receipts`/`notes`. `kind: \"identify_only\"` means the source is listed for reference but not actively polled.\n\nFiltered to `type: podcast`. Audio-only podcasts surface as `kind: identify_only` — listed for reference, not polled by the collector.","parameters":[{"schema":{"type":"string","description":"Audience ID","example":"gen-z-foodies"},"required":true,"description":"Audience ID","name":"audience_id","in":"path"}],"responses":{"200":{"description":"Podcasts curated for this audience","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AudienceSource"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/substacks":{"get":{"operationId":"audience_substacks","tags":["Audiences"],"summary":"List audience Substacks","description":"Returns the curated list of sources for this audience as written by the audience-discoverer agent into `space.properties.sources`. Audiences are global reference data — the curated source lists are surfaced to any caller, not scoped to your team. Each item carries `type`, `kind`, `value`, optional `route`/`confidence`/`recurrence`/`fit_score`/`cluster`/`receipts`/`notes`. `kind: \"identify_only\"` means the source is listed for reference but not actively polled.\n\nFiltered to `type: substack`. `value` is the newsletter's RSS or canonical URL.","parameters":[{"schema":{"type":"string","description":"Audience ID","example":"gen-z-foodies"},"required":true,"description":"Audience ID","name":"audience_id","in":"path"}],"responses":{"200":{"description":"Substack newsletters curated for this audience","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AudienceSource"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/insights":{"get":{"operationId":"audience_insights","tags":["Audiences"],"summary":"Get audience insights","description":"Get aggregate insights for an audience, including brand count, top brands by relevance, and top content from audience-tagged posts.","parameters":[{"schema":{"type":"string","description":"Audience ID","example":"gen-z-foodies"},"required":true,"description":"Audience ID","name":"audience_id","in":"path"}],"responses":{"200":{"description":"Audience insights with top brands and content","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AudienceInsights"},"meta":{"$ref":"#/components/schemas/LinkageMeta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audiences/{audience_id}/posts":{"get":{"operationId":"audience_posts","tags":["Audiences"],"summary":"List audience posts","description":"Get paginated posts from brands tagged with this audience. Order with `sort`: `recent` (default, newest-first) or `engagement` for the top recent posts ranked per-platform-normalized (so strong posts from every platform surface, not just the highest-volume ones); engagement sort defaults to the last 14 days when no date range is given. Filter by platform (include/exclude), date range, region, sentiment, topic, or free-text keyword (q); all filters compose.","parameters":[{"schema":{"type":"string","description":"Audience ID","example":"gen-z-foodies"},"required":true,"description":"Audience ID","name":"audience_id","in":"path"},{"schema":{"type":"string","description":"Filter to a single platform (e.g. reddit, instagram, tiktok, youtube, twitter, facebook, linkedin). Mutually exclusive with exclude_platform.","example":"reddit"},"required":false,"description":"Filter to a single platform (e.g. reddit, instagram, tiktok, youtube, twitter, facebook, linkedin). Mutually exclusive with exclude_platform.","name":"platform","in":"query"},{"schema":{"type":"string","description":"Exclude a single platform from the results (e.g. facebook). Mutually exclusive with platform.","example":"facebook"},"required":false,"description":"Exclude a single platform from the results (e.g. facebook). Mutually exclusive with platform.","name":"exclude_platform","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter posts on or after this date (ISO 8601)","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Filter posts on or after this date (ISO 8601)","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter posts on or before this date (ISO 8601)","example":"2026-03-31T23:59:59Z"},"required":false,"description":"Filter posts on or before this date (ISO 8601)","name":"end_date","in":"query"},{"schema":{"type":"string","description":"Filter by region","example":"us"},"required":false,"description":"Filter by region","name":"region","in":"query"},{"schema":{"type":"string","enum":["POSITIVE","NEGATIVE","NEUTRAL","MIXED"],"description":"Filter by analyzer sentiment polarity (matches the `sentiment_polarity` field). Posts not yet analyzed carry no polarity and are excluded by any value of this filter.","example":"NEGATIVE"},"required":false,"description":"Filter by analyzer sentiment polarity (matches the `sentiment_polarity` field). Posts not yet analyzed carry no polarity and are excluded by any value of this filter.","name":"sentiment","in":"query"},{"schema":{"type":"string","maxLength":100,"description":"Filter to posts carrying this analyzer topic tag. Matched exactly (and case-sensitively) against `topic_tags` — pass a tag as returned by audience insights top_themes.","example":"product-launch"},"required":false,"description":"Filter to posts carrying this analyzer topic tag. Matched exactly (and case-sensitively) against `topic_tags` — pass a tag as returned by audience insights top_themes.","name":"topic","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Full-text filter over post text. Supports quoted phrases and or/- operators; terms are stemmed, so `launch` matches `launched`.","example":"\"battery life\" or charging"},"required":false,"description":"Full-text filter over post text. Supports quoted phrases and or/- operators; terms are stemmed, so `launch` matches `launched`.","name":"q","in":"query"},{"schema":{"type":"string","enum":["recent","engagement"],"default":"recent","description":"Result ordering. `recent` (default) returns newest posts first. `engagement` returns the top *recent* posts ranked by likes+comments+views normalized *within each platform* (so a strong LinkedIn or YouTube post surfaces alongside a viral TikTok instead of being buried by raw-count scale). When `engagement` is requested without a date range, results are bounded to the last 14 days.","example":"engagement"},"required":false,"description":"Result ordering. `recent` (default) returns newest posts first. `engagement` returns the top *recent* posts ranked by likes+comments+views normalized *within each platform* (so a strong LinkedIn or YouTube post surfaces alongside a viral TikTok instead of being buried by raw-count scale). When `engagement` is requested without a date range, results are bounded to the last 14 days.","name":"sort","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Maximum number of results to return (1-100)","example":50},"required":false,"description":"Maximum number of results to return (1-100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response"},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response","name":"cursor","in":"query"}],"responses":{"200":{"description":"Paginated list of posts tagged with this audience","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AudiencePost"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/categories":{"get":{"operationId":"category_list","tags":["Categories"],"summary":"List categories","description":"List all brand taxonomy categories. Top-level categories include nested subcategories.","responses":{"200":{"description":"List of categories with subcategories","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Category"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":[{"id":"advertising-marketing-pr","name":"Advertising, Marketing & PR","brand_count":0,"subcategories":[{"id":"advertising-marketing-pr-ad-tech-martech","name":"Ad Tech & Martech","brand_count":2},{"id":"advertising-marketing-pr-agencies-services","name":"Agencies & Services","brand_count":0}]},{"id":"agriculture-agribusiness","name":"Agriculture & Agribusiness","brand_count":0,"subcategories":[{"id":"agriculture-agribusiness-farm-equipment-agtech","name":"Farm Equipment & Agtech","brand_count":0}]},{"id":"alcohol-spirits","name":"Alcohol & Spirits","brand_count":0,"subcategories":[{"id":"alcohol-spirits-beer","name":"Beer","brand_count":0},{"id":"alcohol-spirits-spirits-liquor","name":"Spirits & Liquor","brand_count":0},{"id":"alcohol-spirits-wine-hard-seltzer","name":"Wine & Hard Seltzer","brand_count":0}]},{"id":"apparel-fashion","name":"Apparel & Fashion","brand_count":0,"subcategories":[{"id":"apparel-fashion-activewear-athleisure","name":"Activewear & Athleisure","brand_count":1},{"id":"apparel-fashion-fast-fashion-mass-market","name":"Fast Fashion & Mass Market","brand_count":0},{"id":"apparel-fashion-luxury-designer","name":"Luxury & Designer","brand_count":0}]},{"id":"automotive-mobility","name":"Automotive & Mobility","brand_count":0,"subcategories":[{"id":"automotive-mobility-electric-vehicles","name":"Electric Vehicles","brand_count":0},{"id":"automotive-mobility-mobility-services","name":"Mobility Services","brand_count":0},{"id":"automotive-mobility-traditional-auto","name":"Traditional Auto","brand_count":0}]},{"id":"beauty-personal-care","name":"Beauty & Personal Care","brand_count":0,"subcategories":[{"id":"beauty-personal-care-color-cosmetics","name":"Color Cosmetics","brand_count":1},{"id":"beauty-personal-care-fragrance","name":"Fragrance","brand_count":0},{"id":"beauty-personal-care-hair-care","name":"Hair Care","brand_count":0}]},{"id":"cannabis-cbd","name":"Cannabis & CBD","brand_count":0,"subcategories":[{"id":"cannabis-cbd-cannabis-brands-retail","name":"Cannabis Brands & Retail","brand_count":0}]},{"id":"childcare-baby-toys","name":"Childcare, Baby & Toys","brand_count":0,"subcategories":[{"id":"childcare-baby-toys-baby-parenting","name":"Baby & Parenting","brand_count":0},{"id":"childcare-baby-toys-toys-games","name":"Toys & Games","brand_count":0}]},{"id":"construction-building","name":"Construction & Building","brand_count":1,"subcategories":[{"id":"construction-building-building-materials-equipment","name":"Building Materials & Equipment","brand_count":0}]},{"id":"consulting-professional-services","name":"Consulting & Professional Services","brand_count":0,"subcategories":[{"id":"consulting-professional-services-management-consulting-advisory","name":"Management Consulting & Advisory","brand_count":0}]},{"id":"consumer-electronics","name":"Consumer Electronics","brand_count":0,"subcategories":[{"id":"consumer-electronics-audio-home-devices","name":"Audio & Home Devices","brand_count":0},{"id":"consumer-electronics-smartphones-computers","name":"Smartphones & Computers","brand_count":0}]},{"id":"crypto-web3","name":"Crypto & Web3","brand_count":0,"subcategories":[{"id":"crypto-web3-crypto-platforms-services","name":"Crypto Platforms & Services","brand_count":0}]},{"id":"education-edtech","name":"Education & EdTech","brand_count":0,"subcategories":[{"id":"education-edtech-k-12-higher-ed","name":"K-12 & Higher Ed","brand_count":0},{"id":"education-edtech-online-learning-platforms","name":"Online Learning Platforms","brand_count":1}]},{"id":"energy-utilities","name":"Energy & Utilities","brand_count":0,"subcategories":[{"id":"energy-utilities-oil-gas-traditional-energy","name":"Oil, Gas & Traditional Energy","brand_count":0},{"id":"energy-utilities-renewable-clean-energy","name":"Renewable & Clean Energy","brand_count":0}]},{"id":"entertainment-media","name":"Entertainment & Media","brand_count":0,"subcategories":[{"id":"entertainment-media-gaming","name":"Gaming","brand_count":0},{"id":"entertainment-media-music-audio","name":"Music & Audio","brand_count":0},{"id":"entertainment-media-social-media-creator-platforms","name":"Social Media & Creator Platforms","brand_count":1}]},{"id":"environmental-waste","name":"Environmental & Waste","brand_count":0,"subcategories":[{"id":"environmental-waste-waste-management-recycling","name":"Waste Management & Recycling","brand_count":0}]},{"id":"financial-services","name":"Financial Services","brand_count":0,"subcategories":[{"id":"financial-services-consumer-banking","name":"Consumer Banking","brand_count":0},{"id":"financial-services-investing-wealth","name":"Investing & Wealth","brand_count":0},{"id":"financial-services-lending-mortgage","name":"Lending & Mortgage","brand_count":0}]},{"id":"fitness-wellness","name":"Fitness & Wellness","brand_count":0,"subcategories":[{"id":"fitness-wellness-connected-fitness-wearables","name":"Connected Fitness & Wearables","brand_count":0},{"id":"fitness-wellness-gyms-studios","name":"Gyms & Studios","brand_count":0},{"id":"fitness-wellness-supplements-nutrition","name":"Supplements & Nutrition","brand_count":0}]},{"id":"food-beverage","name":"Food & Beverage","brand_count":0,"subcategories":[{"id":"food-beverage-beverages-non-alcohol","name":"Beverages (Non-Alcohol)","brand_count":0},{"id":"food-beverage-coffee-tea","name":"Coffee & Tea","brand_count":0},{"id":"food-beverage-condiments-sauces-pantry","name":"Condiments, Sauces & Pantry","brand_count":0}]},{"id":"government-defense","name":"Government & Defense","brand_count":0,"subcategories":[{"id":"government-defense-defense-aerospace-contractors","name":"Defense & Aerospace Contractors","brand_count":0}]},{"id":"healthcare-pharmaceuticals","name":"Healthcare & Pharmaceuticals","brand_count":0,"subcategories":[{"id":"healthcare-pharmaceuticals-health-insurance","name":"Health Insurance","brand_count":0},{"id":"healthcare-pharmaceuticals-medical-devices-diagnostics","name":"Medical Devices & Diagnostics","brand_count":0},{"id":"healthcare-pharmaceuticals-otc-consumer-health","name":"OTC & Consumer Health","brand_count":0}]},{"id":"home-garden","name":"Home & Garden","brand_count":0,"subcategories":[{"id":"home-garden-cleaning-household","name":"Cleaning & Household","brand_count":0},{"id":"home-garden-furniture-home-d-cor","name":"Furniture & Home Décor","brand_count":0},{"id":"home-garden-home-improvement-hardware","name":"Home Improvement & Hardware","brand_count":0}]},{"id":"insurance","name":"Insurance","brand_count":0,"subcategories":[{"id":"insurance-auto-home-insurance","name":"Auto & Home Insurance","brand_count":0},{"id":"insurance-life-specialty-insurance","name":"Life & Specialty Insurance","brand_count":0}]},{"id":"jewelry-watches","name":"Jewelry & Watches","brand_count":0,"subcategories":[{"id":"jewelry-watches-fine-jewelry-watches","name":"Fine Jewelry & Watches","brand_count":0}]},{"id":"legal-services","name":"Legal Services","brand_count":0,"subcategories":[{"id":"legal-services-legal-tech-services","name":"Legal Tech & Services","brand_count":0}]},{"id":"logistics-transportation","name":"Logistics & Transportation","brand_count":0,"subcategories":[{"id":"logistics-transportation-shipping-delivery","name":"Shipping & Delivery","brand_count":0}]},{"id":"manufacturing-industrial","name":"Manufacturing & Industrial","brand_count":0,"subcategories":[{"id":"manufacturing-industrial-industrial-products-automation","name":"Industrial Products & Automation","brand_count":0}]},{"id":"marine-watercraft","name":"Marine & Watercraft","brand_count":0,"subcategories":[{"id":"marine-watercraft-boats-marine-equipment","name":"Boats & Marine Equipment","brand_count":0}]},{"id":"nicotine-tobacco","name":"Nicotine & Tobacco","brand_count":0,"subcategories":[{"id":"nicotine-tobacco-tobacco-vaping-nicotine","name":"Tobacco, Vaping & Nicotine","brand_count":0}]},{"id":"nonprofit-social-impact","name":"Nonprofit & Social Impact","brand_count":0,"subcategories":[{"id":"nonprofit-social-impact-charitable-organizations","name":"Charitable Organizations","brand_count":0}]},{"id":"pet-care","name":"Pet Care","brand_count":0,"subcategories":[{"id":"pet-care-pet-food-treats","name":"Pet Food & Treats","brand_count":0},{"id":"pet-care-pet-services-tech","name":"Pet Services & Tech","brand_count":0}]},{"id":"real-estate-property","name":"Real Estate & Property","brand_count":0,"subcategories":[{"id":"real-estate-property-commercial-proptech","name":"Commercial & Proptech","brand_count":0},{"id":"real-estate-property-residential-real-estate","name":"Residential Real Estate","brand_count":0}]},{"id":"restaurants-food-service","name":"Restaurants & Food Service","brand_count":0,"subcategories":[{"id":"restaurants-food-service-delivery-food-platforms","name":"Delivery & Food Platforms","brand_count":1},{"id":"restaurants-food-service-fast-casual","name":"Fast Casual","brand_count":0},{"id":"restaurants-food-service-quick-service-qsr","name":"Quick Service (QSR)","brand_count":0}]},{"id":"retail-e-commerce","name":"Retail & E-Commerce","brand_count":0,"subcategories":[{"id":"retail-e-commerce-e-commerce-marketplace","name":"E-Commerce & Marketplace","brand_count":1},{"id":"retail-e-commerce-mass-retail-grocery","name":"Mass Retail & Grocery","brand_count":0}]},{"id":"semiconductor-hardware","name":"Semiconductor & Hardware","brand_count":0,"subcategories":[{"id":"semiconductor-hardware-chips-components","name":"Chips & Components","brand_count":0}]},{"id":"sports-recreation","name":"Sports & Recreation","brand_count":0,"subcategories":[{"id":"sports-recreation-athletic-footwear-apparel","name":"Athletic Footwear & Apparel","brand_count":1},{"id":"sports-recreation-golf-tennis-racquet","name":"Golf, Tennis & Racquet","brand_count":0},{"id":"sports-recreation-outdoor-adventure","name":"Outdoor & Adventure","brand_count":0}]},{"id":"technology-software","name":"Technology & Software","brand_count":0,"subcategories":[{"id":"technology-software-ai-machine-learning","name":"AI & Machine Learning","brand_count":3},{"id":"technology-software-cloud-enterprise-software","name":"Cloud & Enterprise Software","brand_count":6},{"id":"technology-software-cybersecurity","name":"Cybersecurity","brand_count":0}]},{"id":"telecommunications","name":"Telecommunications","brand_count":0,"subcategories":[{"id":"telecommunications-internet-cable","name":"Internet & Cable","brand_count":0},{"id":"telecommunications-mobile-carriers","name":"Mobile Carriers","brand_count":0}]},{"id":"travel-hospitality","name":"Travel & Hospitality","brand_count":0,"subcategories":[{"id":"travel-hospitality-airlines-air-travel","name":"Airlines & Air Travel","brand_count":0},{"id":"travel-hospitality-cruise-tour","name":"Cruise & Tour","brand_count":0},{"id":"travel-hospitality-hotels-lodging","name":"Hotels & Lodging","brand_count":0}]}],"meta":{"request_id":"req_example","total":39}}}}}}}}}},"/v1/categories/{category_id}":{"get":{"operationId":"category_get","tags":["Categories"],"summary":"Get category","description":"Get details for a single category, including its ID, name, parent, brand count, and description.","parameters":[{"schema":{"type":"string","description":"Category ID (brand_taxonomy_id)","example":"retail"},"required":true,"description":"Category ID (brand_taxonomy_id)","name":"category_id","in":"path"}],"responses":{"200":{"description":"Category details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CategoryDetail"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/categories/{category_id}/brands":{"get":{"operationId":"category_brands","tags":["Categories"],"summary":"List brands in category","description":"Get a paginated list of brands belonging to a specific category.","parameters":[{"schema":{"type":"string","description":"Category ID (brand_taxonomy_id)","example":"retail"},"required":true,"description":"Category ID (brand_taxonomy_id)","name":"category_id","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"Maximum number of results to return (1-100)","example":25},"required":false,"description":"Maximum number of results to return (1-100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response"},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response","name":"cursor","in":"query"}],"responses":{"200":{"description":"Paginated list of brands in the category","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CategoryBrand"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/categories/{category_id}/news":{"get":{"operationId":"category_news","tags":["Categories"],"summary":"Get category news","description":"Get recent news articles related to brands in this category.","parameters":[{"schema":{"type":"string","description":"Category ID (brand_taxonomy_id)","example":"retail"},"required":true,"description":"Category ID (brand_taxonomy_id)","name":"category_id","in":"path"},{"schema":{"type":"string","description":"Filter by region code","example":"us"},"required":false,"description":"Filter by region code","name":"region","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"Maximum number of results to return (1-100)","example":25},"required":false,"description":"Maximum number of results to return (1-100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass the published_at value of the last item"},"required":false,"description":"Cursor for pagination — pass the published_at value of the last item","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":365,"description":"Only return articles published within this many days. Defaults to 30 — a recency backstop so stale items don't surface in the feed.","example":30},"required":false,"description":"Only return articles published within this many days. Defaults to 30 — a recency backstop so stale items don't surface in the feed.","name":"max_age_days","in":"query"}],"responses":{"200":{"description":"List of news articles for the category","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CategoryNews"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/categories/{category_id}/topics":{"get":{"operationId":"category_trends","tags":["Categories"],"summary":"Get category topics","description":"Topic tags attached to this category over the last 7 days, with per-topic occurrence counts. (Platform-level trending — Google/TikTok/X — lives under `/v1/trends` and `/v1/discover/trends`.)","parameters":[{"schema":{"type":"string","description":"Category ID (brand_taxonomy_id)","example":"retail"},"required":true,"description":"Category ID (brand_taxonomy_id)","name":"category_id","in":"path"},{"schema":{"type":"string","description":"Filter by region code","example":"us"},"required":false,"description":"Filter by region code","name":"region","in":"query"}],"responses":{"200":{"description":"List of topic tags for the category","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CategoryTrend"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/categories/{category_id}/landscape":{"get":{"operationId":"category_landscape","tags":["Categories"],"summary":"Get category landscape","description":"Get category-level share of voice and sentiment distribution across brands.","parameters":[{"schema":{"type":"string","description":"Category ID (brand_taxonomy_id)","example":"retail"},"required":true,"description":"Category ID (brand_taxonomy_id)","name":"category_id","in":"path"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Start date (ISO 8601). Defaults to 30 days ago.","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Start date (ISO 8601). Defaults to 30 days ago.","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"End date (ISO 8601). Defaults to now.","example":"2026-04-01T00:00:00Z"},"required":false,"description":"End date (ISO 8601). Defaults to now.","name":"end_date","in":"query"},{"schema":{"type":"string","description":"Filter by region code","example":"us"},"required":false,"description":"Filter by region code","name":"region","in":"query"}],"responses":{"200":{"description":"Category landscape with SOV and sentiment","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CategoryLandscape"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/categories/{category_id}/whitespace":{"get":{"operationId":"category_whitespace","tags":["Categories"],"summary":"Get category theme whitespace","description":"Get category themes with a demand signal and per-theme brand ownership. Surfaces open lanes — high-demand themes no category brand has captured.","parameters":[{"schema":{"type":"string","description":"Category ID (brand_taxonomy_id)","example":"technology-software-ai-machine-learning"},"required":true,"description":"Category ID (brand_taxonomy_id)","name":"category_id","in":"path"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Start date (ISO 8601). Defaults to 30 days ago.","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Start date (ISO 8601). Defaults to 30 days ago.","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"End date (ISO 8601). Defaults to now.","example":"2026-04-01T00:00:00Z"},"required":false,"description":"End date (ISO 8601). Defaults to now.","name":"end_date","in":"query"},{"schema":{"type":"string","description":"Filter by region code","example":"us"},"required":false,"description":"Filter by region code","name":"region","in":"query"}],"responses":{"200":{"description":"Category themes with demand, ownership, and open-lane flags","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CategoryWhitespace"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/categories/{category_id}/creative-patterns":{"get":{"operationId":"category_creative_patterns","tags":["Categories"],"summary":"Get category creative patterns","description":"Get the creative hook and angle frames working across a category — each frame with how many distinct creatives carry it, how many brands run it, the analyzer labels behind it, and example ads.","parameters":[{"schema":{"type":"string","description":"Category ID (brand_taxonomy_id)","example":"technology-software-ai-machine-learning"},"required":true,"description":"Category ID (brand_taxonomy_id)","name":"category_id","in":"path"},{"schema":{"type":"string","enum":["7d","30d","90d"],"default":"30d","description":"Time window for the read. Defaults to 30d.","example":"30d"},"required":false,"description":"Time window for the read. Defaults to 30d.","name":"window","in":"query"}],"responses":{"200":{"description":"Hook and angle frames running across the category","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CreativePatterns"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/categories/{category_id}/conversations":{"get":{"operationId":"category_conversations","tags":["Categories"],"summary":"List conversation themes in category","description":"The conversation themes in this category's social posts — each with a stable theme_id, a label, size/share/confidence, and top verbatim examples pulled live from the posts behind it. The post set is both the earned mentions of the brands linked to this category and the posts collected for the category itself, so it reaches discussion that names no tracked brand as well as discussion that does. Themes are tag-derived — meta.source is always TOPIC_TAGS_ONLY and meta.set_version always null, because a category is never clustered — so `type` and `intent` are null and the shares overlap rather than summing to 1, a post carrying up to three tags where clusters are disjoint. Theme labels are analyzer topic tags, which name categories of talk (voice dictation, productivity tools) rather than positions; the positions are in each theme's `stances` — short claims the category's conversation analyzer wrote about the theme's posts — with `stance_post_count` saying how many of its posts carry one. Most of the post set is brand mentions, which carry no stance, so ranking purely by size would bury the themes where the category's own discussion is. `data` therefore holds up to `meta.theme_limit` themes in two runs: first the `meta.conversation_themes` themes with the most conversation-backed posts, ordered by `stance_post_count`; then the largest remaining themes, ordered by `size`. `meta.total` counts every distinct theme, so `total > theme_limit` means themes were cut and the endpoint does not page to them. Each verbatim carries the detected `language`, and `text_en` ONLY where an English translation is already cached for that post; a null `text_en` on a non-English quote means the translation has not landed yet, so poll again.","parameters":[{"schema":{"type":"string","description":"Category ID (brand_taxonomy_id)","example":"technology-software-ai-dictation-voice-input"},"required":true,"description":"Category ID (brand_taxonomy_id)","name":"category_id","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":10,"default":3,"description":"Verbatim examples to return per theme (1-10).","example":3},"required":false,"description":"Verbatim examples to return per theme (1-10).","name":"verbatim_limit","in":"query"}],"responses":{"200":{"description":"Conversation themes for the category","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CategoryConversationTheme"}},"meta":{"$ref":"#/components/schemas/CategoryConversationsMeta"}},"required":["data","meta"]}}}},"404":{"description":"Category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trends":{"get":{"operationId":"trend_list","tags":["Trends"],"summary":"List platform trends","description":"List trends from the collected Google/TikTok/X corpus. Default order groups by platform then recency; `blended` interleaves all platforms by recency. Each item carries its latest cross-platform observation and category set. Paginate via `meta.next_cursor`.","parameters":[{"schema":{"type":"string","description":"Filter to one platform.","example":"tiktok"},"required":false,"description":"Filter to one platform.","name":"platform","in":"query"},{"schema":{"type":"string","description":"Filter to trends observed in this geo (e.g. US), which also restricts which observation is reported for each of them. X uses numeric market codes, not comparable across platforms.","example":"US"},"required":false,"description":"Filter to trends observed in this geo (e.g. US), which also restricts which observation is reported for each of them. X uses numeric market codes, not comparable across platforms.","name":"geo","in":"query"},{"schema":{"type":"string","description":"Filter to trends carrying this category — a native category_key or a derived WALDO brand_taxonomy_id.","example":"food_and_drink"},"required":false,"description":"Filter to trends carrying this category — a native category_key or a derived WALDO brand_taxonomy_id.","name":"category","in":"query"},{"schema":{"type":"string","enum":["0","1","true","false"],"description":"Interleave all platforms by recency instead of grouping by platform.","example":true},"required":false,"description":"Interleave all platforms by recency instead of grouping by platform.","name":"blended","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response. Bound to the sort it was issued for; flipping `blended` mid-pagination returns 400."},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response. Bound to the sort it was issued for; flipping `blended` mid-pagination returns 400.","name":"cursor","in":"query"}],"responses":{"200":{"description":"Paginated list of trends","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Trend"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"400":{"description":"Invalid pagination cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trends/{trend_id}":{"get":{"operationId":"trend_get","tags":["Trends"],"summary":"Get trend","description":"Get a single trend by ID, with its latest observation, category set, and the Google-interest series enriched for it.","parameters":[{"schema":{"type":"string","description":"Trend ID (uuid).","example":"c1a2b3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Trend ID (uuid).","name":"trend_id","in":"path"}],"responses":{"200":{"description":"Trend detail","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrendDetail"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"404":{"description":"Trend not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/topics":{"get":{"operationId":"topic_list","tags":["Topics"],"summary":"Search topics","description":"Search the shared topic vocabulary for tags available to filter by — search-as-you-type autocomplete. Ranks by closeness to the query then popularity; only established tags are returned. Omit `q` for the most-used tags. Use a returned tag verbatim as a `topic` filter value on the mentions and audience-post endpoints.","parameters":[{"schema":{"type":"string","maxLength":100,"description":"Search text, matched fuzzily against the tag. Omit for the most-used tags.","example":"5g"},"required":false,"description":"Search text, matched fuzzily against the tag. Omit for the most-used tags.","name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":25,"default":20,"description":"Maximum number of tags to return (1–25).","example":20},"required":false,"description":"Maximum number of tags to return (1–25).","name":"limit","in":"query"}],"responses":{"200":{"description":"Matching topics, most relevant first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"tag":{"type":"string"},"description":{"type":["string","null"]},"occurrence_count":{"type":"number"}},"required":["tag","description","occurrence_count"]}}},"required":["data"]}}}}}}},"/v1/discover/posts":{"get":{"operationId":"discover_posts","tags":["Discover"],"summary":"Search posts","deprecated":true,"description":"Search social media posts across a specified platform. **Deprecated** — use `GET /v1/discover/{platform}/posts`, which exposes each platform's sort and time-window filters. This generic form only accepts q/cursor.","parameters":[{"schema":{"type":"string","enum":["x","instagram","tiktok","linkedin","facebook","youtube","reddit"],"description":"Social platform to search"},"required":true,"description":"Social platform to search","name":"platform","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Search query"},"required":true,"description":"Search query","name":"q","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NormalizedPost"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"type":"post","platform":{"source":"instagram","name":"Instagram","id":"1000000000000000001","url":"https://www.instagram.com/reel/EXAMPLE1/"},"publishedAt":"2025-07-21T09:00:00.000Z","content":{"text":"Example caption: restock day, and the shelves are full again #smallbusiness #shoplocal","author":{"id":"1000000001","username":"example_creator","name":"Dana Example","profileUrl":"https://instagram.com/example_creator"},"media":[{"type":"video","url":"https://instagram.fna.fbcdn.net/o1/v/t2/f2/m367/example_reel_1.mp4"}],"metrics":{"likes":663,"comments":53,"shares":40}},"post_id":"pid_eyJwIjoiaW5zdGFncmFtIiwiayI6Imh0dHBzOi8vd3d3Lmluc3RhZ3JhbS5jb20vcmVlbC9FWEFNUExFMS8iLCJpIjoiMTAwMDAwMDAwMDAwMDAwMDAwMSJ9"},{"type":"post","platform":{"source":"instagram","name":"Instagram","id":"1000000000000000002","url":"https://www.instagram.com/reel/EXAMPLE2/"},"publishedAt":"2025-10-09T10:21:15.000Z","content":{"text":"Example caption: behind the scenes at our studio this week ✨ New colorways drop Friday.\n\n#smallbusiness #handmade #newcollection","author":{"id":"1000000002","username":"example_mentor","name":"Jordan Example | Ecom Business Mentor","profileUrl":"https://instagram.com/example_mentor"},"media":[{"type":"video","url":"https://instagram.fna.fbcdn.net/o1/v/t2/f2/m367/example_reel_2.mp4"}],"metrics":{"likes":988,"comments":190,"shares":27}},"post_id":"pid_eyJwIjoiaW5zdGFncmFtIiwiayI6Imh0dHBzOi8vd3d3Lmluc3RhZ3JhbS5jb20vcmVlbC9FWEFNUExFMi8iLCJpIjoiMTAwMDAwMDAwMDAwMDAwMDAwMiJ9"},{"type":"post","platform":{"source":"instagram","name":"Instagram","id":"1000000000000000003","url":"https://www.instagram.com/reel/EXAMPLE3/"},"publishedAt":"2026-02-04T18:39:36.000Z","content":{"text":"Example caption: packing day 📦\n#smallbusiness #shoplocal","author":{"id":"1000000003","username":"example_hustle","name":"Quinn Example","profileUrl":"https://instagram.com/example_hustle"},"media":[{"type":"video","url":"https://instagram.fna.fbcdn.net/o1/v/t2/f2/m367/example_reel_3.mp4"}],"metrics":{"likes":19824,"comments":495,"shares":702}},"post_id":"pid_eyJwIjoiaW5zdGFncmFtIiwiayI6Imh0dHBzOi8vd3d3Lmluc3RhZ3JhbS5jb20vcmVlbC9FWEFNUExFMy8iLCJpIjoiMTAwMDAwMDAwMDAwMDAwMDAwMyJ9"}]},"meta":{"request_id":"req_example","next_cursor":"eyJleGFtcGxlIjoiY3Vyc29yIn0=::sid::00000000-0000-4000-8000-000000000002"}}}}}}}}}},"/v1/discover/x/posts":{"get":{"operationId":"discover_x_posts","tags":["Discover"],"summary":"Search X/Twitter posts","description":"Search X (Twitter) posts. Supports `sort` (top/latest). No time-window filter upstream.","parameters":[{"schema":{"type":"string","minLength":1,"description":"Search query"},"required":true,"description":"Search query","name":"q","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"},{"schema":{"type":"string","enum":["top","latest"],"description":"Sort order: `top` (most relevant) or `latest` (most recent)."},"required":false,"description":"Sort order: `top` (most relevant) or `latest` (most recent).","name":"sort","in":"query"}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NormalizedPost"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"type":"post","platform":{"source":"twitter","name":"X (Twitter)","id":"1000000000000000001","url":"https://x.com/example_user/status/1000000000000000001"},"publishedAt":"2026-08-19T14:09:54.000Z","content":{"text":"Example post: we tested three checkout layouts this month. The one with the fewest fields won by a wide margin.","author":{"id":"1000000000000000101","username":"example_user","name":"Lee Example","profileUrl":"https://x.com/example_user"},"media":[{"type":"image","url":"https://pbs.twimg.com/media/example_media_1.jpg","thumbnail":"https://pbs.twimg.com/media/example_media_1.jpg"}],"metrics":{"likes":57,"shares":1,"comments":29,"views":2174}},"post_id":"pid_eyJwIjoieCIsImsiOiJodHRwczovL3guY29tL2V4YW1wbGVfdXNlci9zdGF0dXMvMTAwMDAwMDAwMDAwMDAwMDAwMSIsImkiOiIxMDAwMDAwMDAwMDAwMDAwMDAxIn0"},{"type":"post","platform":{"source":"twitter","name":"X (Twitter)","id":"1000000000000000002","url":"https://x.com/example_dropship/status/1000000000000000002"},"publishedAt":"2026-08-18T02:55:21.000Z","content":{"text":"Example post: small batch, big week. Thanks to everyone who ordered the autumn restock 🍂","author":{"id":"1000000000000000102","username":"example_dropship","name":"Example Dropship | Fulfillment","profileUrl":"https://x.com/example_dropship"},"media":[{"type":"video","url":"https://video.twimg.com/amplify_video/example_1000000000000000201/vid/avc1/886x1920/example.mp4","thumbnail":"https://pbs.twimg.com/amplify_video_thumb/example_1000000000000000201/img/example.jpg"}],"metrics":{"likes":34,"shares":4,"comments":0,"views":503}},"post_id":"pid_eyJwIjoieCIsImsiOiJodHRwczovL3guY29tL2V4YW1wbGVfZHJvcHNoaXAvc3RhdHVzLzEwMDAwMDAwMDAwMDAwMDAwMDIiLCJpIjoiMTAwMDAwMDAwMDAwMDAwMDAwMiJ9"},{"type":"post","platform":{"source":"twitter","name":"X (Twitter)","id":"1000000000000000003","url":"https://x.com/example_brand/status/1000000000000000003"},"publishedAt":"2026-08-19T17:37:58.000Z","content":{"text":"Example post: packing orders all afternoon with a very supervisory cat","author":{"id":"1000000000000000103","username":"example_brand","name":"Example Brand","profileUrl":"https://x.com/example_brand"},"metrics":{"likes":22,"shares":0,"comments":7,"views":4048}},"post_id":"pid_eyJwIjoieCIsImsiOiJodHRwczovL3guY29tL2V4YW1wbGVfYnJhbmQvc3RhdHVzLzEwMDAwMDAwMDAwMDAwMDAwMDMiLCJpIjoiMTAwMDAwMDAwMDAwMDAwMDAwMyJ9"}]},"meta":{"request_id":"req_example","next_cursor":null}}}}}}}}}},"/v1/discover/tiktok/posts":{"get":{"operationId":"discover_tiktok_posts","tags":["Discover"],"summary":"Search TikTok posts","description":"Search TikTok posts. Supports `sort` (relevance/likes/date), `since` (day/week/month/year), and `country` (ISO-2 region).","parameters":[{"schema":{"type":"string","minLength":1,"description":"Search query"},"required":true,"description":"Search query","name":"q","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"},{"schema":{"type":"string","enum":["relevance","likes","date"],"description":"Sort order: `relevance`, `likes` (most liked), or `date` (most recent)."},"required":false,"description":"Sort order: `relevance`, `likes` (most liked), or `date` (most recent).","name":"sort","in":"query"},{"schema":{"type":"string","enum":["day","week","month","year"],"description":"Time window — posts from the last day, week, month, or year."},"required":false,"description":"Time window — posts from the last day, week, month, or year.","name":"since","in":"query"},{"schema":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO-2 country code to adjust results by region (e.g. `US`)."},"required":false,"description":"ISO-2 country code to adjust results by region (e.g. `US`).","name":"country","in":"query"}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NormalizedPost"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"type":"post","platform":{"source":"tiktok","name":"TikTok","id":"7000000000000000001","url":"https://tiktok.com/@example_creator/video/7000000000000000001"},"publishedAt":"2026-08-13T23:04:01.000Z","content":{"text":"Example caption: a day in the life of a two-person candle shop #smallbusiness #candles","author":{"id":"7000000000000000101","username":"example_creator","name":"Avery Example","profileUrl":"https://tiktok.com/@example_creator"},"media":[{"type":"video","url":"https://v19.tiktokcdn-eu.com/example_video_1/?mime_type=video_mp4","thumbnail":"https://p16-common-sign.tiktokcdn-eu.com/example_cover_1.image?x-expires=1800000000&x-signature=example"}],"metrics":{"likes":2935,"shares":1195,"comments":341,"views":44013,"saves":3729}},"post_id":"pid_eyJwIjoidGlrdG9rIiwiayI6Imh0dHBzOi8vdGlrdG9rLmNvbS9AZXhhbXBsZV9jcmVhdG9yL3ZpZGVvLzcwMDAwMDAwMDAwMDAwMDAwMDEiLCJpIjoiNzAwMDAwMDAwMDAwMDAwMDAwMSJ9"},{"type":"post","platform":{"source":"tiktok","name":"TikTok","id":"7000000000000000002","url":"https://tiktok.com/@example_ecom/video/7000000000000000002"},"publishedAt":"2026-08-11T02:26:30.000Z","content":{"text":"Example caption: unboxing our new packaging samples #packaging #smallbusiness","author":{"id":"7000000000000000102","username":"example_ecom","name":"Casey Example","profileUrl":"https://tiktok.com/@example_ecom"},"media":[{"type":"video","url":"https://v19.tiktokcdn-eu.com/example_video_2/?mime_type=video_mp4","thumbnail":"https://p19-common-sign.tiktokcdn-eu.com/example_cover_2.image?x-expires=1800000000&x-signature=example"}],"metrics":{"likes":4479,"shares":1855,"comments":759,"views":126591,"saves":3433}},"post_id":"pid_eyJwIjoidGlrdG9rIiwiayI6Imh0dHBzOi8vdGlrdG9rLmNvbS9AZXhhbXBsZV9lY29tL3ZpZGVvLzcwMDAwMDAwMDAwMDAwMDAwMDIiLCJpIjoiNzAwMDAwMDAwMDAwMDAwMDAwMiJ9"},{"type":"post","platform":{"source":"tiktok","name":"TikTok","id":"7000000000000000003","url":"https://tiktok.com/@example.ecom/video/7000000000000000003"},"publishedAt":"2026-08-19T16:31:40.000Z","content":{"text":"Example caption: how we photograph products on a kitchen table #productphotography #tips","author":{"id":"7000000000000000103","username":"example.ecom","name":"Rowan Example","profileUrl":"https://tiktok.com/@example.ecom"},"media":[{"type":"video","url":"https://v19.tiktokcdn-eu.com/example_video_3/?mime_type=video_mp4","thumbnail":"https://p16-common-sign.tiktokcdn-eu.com/example_cover_3.image?x-expires=1800000000&x-signature=example"}],"metrics":{"likes":42,"shares":1,"comments":6,"views":792,"saves":31}},"post_id":"pid_eyJwIjoidGlrdG9rIiwiayI6Imh0dHBzOi8vdGlrdG9rLmNvbS9AZXhhbXBsZS5lY29tL3ZpZGVvLzcwMDAwMDAwMDAwMDAwMDAwMDMiLCJpIjoiNzAwMDAwMDAwMDAwMDAwMDAwMyJ9"}]},"meta":{"request_id":"req_example","next_cursor":null}}}}}}}}}},"/v1/discover/reddit/posts":{"get":{"operationId":"discover_reddit_posts","tags":["Discover"],"summary":"Search Reddit posts","description":"Search Reddit posts. Supports `sort` (relevance/hot/top/new/comments) and `since` (hour/today/week/month/year/all).","parameters":[{"schema":{"type":"string","minLength":1,"description":"Search query"},"required":true,"description":"Search query","name":"q","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"},{"schema":{"type":"string","enum":["relevance","hot","top","new","comments"],"description":"Sort order: relevance, hot, top, new, or comments."},"required":false,"description":"Sort order: relevance, hot, top, new, or comments.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["hour","today","week","month","year","all"],"description":"Time window: hour, today, week, month, year, or all. Reddit requires it when `sort` is top, comments, or relevance."},"required":false,"description":"Time window: hour, today, week, month, year, or all. Reddit requires it when `sort` is top, comments, or relevance.","name":"since","in":"query"}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NormalizedPost"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"type":"post","platform":{"source":"reddit","name":"Reddit","id":"1exmp01","url":"https://www.reddit.com/r/example_community/comments/1exmp01/example_most_useful_store_change/"},"publishedAt":"2026-08-19T20:26:18.877Z","content":{"title":"Example thread: what's the most useful thing you changed in your store this year?","text":"Example post: I finally added a size guide to every product page and returns dropped. What small change made the biggest difference for you?","author":{"id":"t2_example001","username":"example_user_1","profileUrl":"https://reddit.com/u/example_user_1"},"metrics":{"comments":0,"likes":1}},"metadata":{"subreddit":"r/example_community"},"post_id":"pid_eyJwIjoicmVkZGl0IiwiayI6Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9leGFtcGxlX2NvbW11bml0eS9jb21tZW50cy8xZXhtcDAxL2V4YW1wbGVfd2hhdF9tb3ZlZF9pbnN0YWxscy8iLCJpIjoiMWV4bXAwMSJ9"},{"type":"post","platform":{"source":"reddit","name":"Reddit","id":"1exmp02","url":"https://www.reddit.com/r/example_forhire/comments/1exmp02/example_for_hire_storefront_developer/"},"publishedAt":"2026-08-19T20:15:16.121Z","content":{"title":"Example thread: [For Hire] storefront themes and landing pages","text":"Example post: I build storefront themes and landing pages. Portfolio: https://portfolio.example.com\n\nAvailable for part-time projects.","author":{"id":"t2_example002","username":"example_user_2","profileUrl":"https://reddit.com/u/example_user_2"},"metrics":{"comments":1,"likes":1}},"metadata":{"subreddit":"r/example_forhire"},"post_id":"pid_eyJwIjoicmVkZGl0IiwiayI6Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9leGFtcGxlX2ZvcmhpcmUvY29tbWVudHMvMWV4bXAwMi9leGFtcGxlX2Zvcl9oaXJlX2Zyb250ZW5kX2RldmVsb3Blci8iLCJpIjoiMWV4bXAwMiJ9"},{"type":"post","platform":{"source":"reddit","name":"Reddit","id":"1exmp03","url":"https://www.reddit.com/r/example_photos/comments/1exmp03/example_photo_share/"},"publishedAt":"2026-08-19T20:08:52.833Z","content":{"title":"Example thread: photo share !","author":{"id":"t2_example003","username":"example_user_3","profileUrl":"https://reddit.com/u/example_user_3"},"media":[{"type":"image","url":"https://preview.redd.it/example_image_1.png?auto=webp&s=example"},{"type":"image","url":"https://i.redd.it/example_image_1.png"}],"metrics":{"comments":0,"likes":1}},"metadata":{"subreddit":"r/example_photos"},"post_id":"pid_eyJwIjoicmVkZGl0IiwiayI6Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9leGFtcGxlX3Bob3Rvcy9jb21tZW50cy8xZXhtcDAzL2V4YW1wbGVfcGhvdG9fc2hhcmUvIiwiaSI6IjFleG1wMDMifQ"}]},"meta":{"request_id":"req_example","next_cursor":"eJyexample_cursor_page_2"}}}}}}}}}},"/v1/discover/linkedin/posts":{"get":{"operationId":"discover_linkedin_posts","tags":["Discover"],"summary":"Search LinkedIn posts","description":"Search LinkedIn posts. Supports `sort` (top/latest, defaults to top — LinkedIn requires a sort) and `since` (day/week/month).","parameters":[{"schema":{"type":"string","minLength":1,"description":"Search query"},"required":true,"description":"Search query","name":"q","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"},{"schema":{"type":"string","enum":["top","latest"],"default":"top","description":"Sort order: `top` (most relevant, default) or `latest` (most recent)."},"required":false,"description":"Sort order: `top` (most relevant, default) or `latest` (most recent).","name":"sort","in":"query"},{"schema":{"type":"string","enum":["day","week","month"],"description":"Time window: day, week, or month."},"required":false,"description":"Time window: day, week, or month.","name":"since","in":"query"}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NormalizedPost"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"type":"post","platform":{"source":"linkedin","name":"LinkedIn","id":"7000000000000000001","url":"https://www.linkedin.com/posts/example_hiring-manager_were-growing-share-7000000000000000001-Exmp"},"publishedAt":"2026-08-17T11:33:00.892Z","content":{"text":"Example post: we're hiring a backend engineer to help build our order and inventory services.\n\nRemote within the US. Details and the application link are on our careers page.","author":{"id":"ACoAAExample0000000000000000000000000001","username":"example_hiring-manager","name":"Morgan Example"},"media":[],"metrics":{"likes":46,"shares":3,"comments":5}},"post_id":"pid_eyJwIjoibGlua2VkaW4iLCJrIjoiaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL3Bvc3RzL2V4YW1wbGVfaGlyaW5nLW1hbmFnZXJfd2VyZS1ncm93aW5nLXNoYXJlLTcwMDAwMDAwMDAwMDAwMDAwMDEtRXhtcCIsImkiOiI3MDAwMDAwMDAwMDAwMDAwMDAxIn0"},{"type":"post","platform":{"source":"linkedin","name":"LinkedIn","id":"7000000000000000002","url":"https://www.linkedin.com/posts/example-recruiter_storefront-developer-share-7000000000000000002-Exmp"},"publishedAt":"2026-08-18T23:59:27.530Z","content":{"text":"Example post: Example Co is hiring a part-time support specialist for our storefront team.\n\nRemote, flexible hours. Apply through the link on our careers page.","author":{"id":"ACoAAExample0000000000000000000000000002","username":"example-recruiter","name":"Riley Example"},"media":[],"metrics":{"likes":6,"shares":0,"comments":7}},"post_id":"pid_eyJwIjoibGlua2VkaW4iLCJrIjoiaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL3Bvc3RzL2V4YW1wbGUtcmVjcnVpdGVyX3N0b3JlZnJvbnQtZGV2ZWxvcGVyLXNoYXJlLTcwMDAwMDAwMDAwMDAwMDAwMDItRXhtcCIsImkiOiI3MDAwMDAwMDAwMDAwMDAwMDAyIn0"},{"type":"post","platform":{"source":"linkedin","name":"LinkedIn","id":"7000000000000000003","url":"https://www.linkedin.com/posts/example-studio_hiring-freelance-developer-share-7000000000000000003-Exmp"},"publishedAt":"2026-08-19T07:55:19.102Z","content":{"text":"Example post: three lessons from our first year selling online:\n• Ship fast, then refine\n• Answer every support email the same day\n• Photograph products in daylight","author":{"id":"1000000003","username":"example-studio","name":"Example Studio"},"media":[],"metrics":{"likes":17,"shares":1,"comments":26}},"post_id":"pid_eyJwIjoibGlua2VkaW4iLCJrIjoiaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL3Bvc3RzL2V4YW1wbGUtc3R1ZGlvX2hpcmluZy1mcmVlbGFuY2UtZGV2ZWxvcGVyLXNoYXJlLTcwMDAwMDAwMDAwMDAwMDAwMDMtRXhtcCIsImkiOiI3MDAwMDAwMDAwMDAwMDAwMDAzIn0"}]},"meta":{"request_id":"req_example","next_cursor":"eyJleGFtcGxlIjoiY3Vyc29yIn0="}}}}}}}}}},"/v1/discover/youtube/posts":{"get":{"operationId":"discover_youtube_posts","tags":["Discover"],"summary":"Search YouTube videos","description":"Search YouTube videos. Supports `sort` (relevance/popularity) and `since` (day/week/month/year; omit for all-time).","parameters":[{"schema":{"type":"string","minLength":1,"description":"Search query"},"required":true,"description":"Search query","name":"q","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"},{"schema":{"type":"string","enum":["relevance","popularity"],"description":"Sort order: `relevance` or `popularity` (by view count)."},"required":false,"description":"Sort order: `relevance` or `popularity` (by view count).","name":"sort","in":"query"},{"schema":{"type":"string","enum":["day","week","month","year"],"description":"Time window — videos from the last day, week, month, or year. Omit for all-time."},"required":false,"description":"Time window — videos from the last day, week, month, or year. Omit for all-time.","name":"since","in":"query"}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NormalizedPost"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"type":"post","platform":{"source":"youtube","name":"YouTube","id":"exampleVid1","url":"https://www.youtube.com/watch?v=exampleVid1"},"publishedAt":"2023-01-01T00:00:00.000Z","content":{"text":"Example description: a walkthrough of how we set up shipping zones for our shop. Links and notes: https://www.example.com/notes","title":"Example video: setting up shipping zones for a small shop","author":{"id":"UCexample0000000000000001","username":"example_media","name":"Example Media","profileUrl":"https://youtube.com/@example_media"},"media":[{"type":"video","url":"https://www.youtube.com/watch?v=exampleVid1","thumbnail":"https://i.ytimg.com/vi/exampleVid1/hq720.jpg"},{"type":"image","url":"https://i.ytimg.com/vi/exampleVid1/hq720.jpg","thumbnail":"https://i.ytimg.com/vi/exampleVid1/hq720.jpg"}],"metrics":{"views":1717213}},"metadata":{"videoType":"video"},"post_id":"pid_eyJwIjoieW91dHViZSIsImsiOiJleGFtcGxlVmlkMSIsImkiOiJleGFtcGxlVmlkMSJ9"},{"type":"post","platform":{"source":"youtube","name":"YouTube","id":"exampleVid2","url":"https://www.youtube.com/watch?v=exampleVid2"},"publishedAt":"2026-03-01T00:00:00.000Z","content":{"text":"Example Beschreibung: wir zeigen, wie wir Produktfotos für unseren kleinen Laden aufnehmen. Notizen: https://www.example.com/fotos","title":"Example Video: Produktfotos für kleine Läden","author":{"id":"UCexample0000000000000002","username":"example_ecom_de","name":"Example E-Com DE","profileUrl":"https://youtube.com/@example-ecom-de"},"media":[{"type":"video","url":"https://www.youtube.com/watch?v=exampleVid2","thumbnail":"https://i.ytimg.com/vi/exampleVid2/hq720.jpg"},{"type":"image","url":"https://i.ytimg.com/vi/exampleVid2/hq720.jpg","thumbnail":"https://i.ytimg.com/vi/exampleVid2/hq720.jpg"}],"metrics":{"views":15230}},"metadata":{"videoType":"video"},"post_id":"pid_eyJwIjoieW91dHViZSIsImsiOiJleGFtcGxlVmlkMiIsImkiOiJleGFtcGxlVmlkMiJ9"},{"type":"post","platform":{"source":"youtube","name":"YouTube","id":"exampleVid3","url":"https://www.youtube.com/watch?v=exampleVid3"},"publishedAt":"2025-01-01T00:00:00.000Z","content":{"text":"Example description: our first year of running a small online shop, month by month. Notes: https://www.example.com/year-one","title":"Example video: our first year running a small online shop","author":{"id":"UCexample0000000000000003","username":"example_creator_de","name":"Alex Example","profileUrl":"https://youtube.com/@example_creator_de"},"media":[{"type":"video","url":"https://www.youtube.com/watch?v=exampleVid3","thumbnail":"https://i.ytimg.com/vi/exampleVid3/hq720.jpg"},{"type":"image","url":"https://i.ytimg.com/vi/exampleVid3/hq720.jpg","thumbnail":"https://i.ytimg.com/vi/exampleVid3/hq720.jpg"}],"metrics":{"views":122569}},"metadata":{"videoType":"video"},"post_id":"pid_eyJwIjoieW91dHViZSIsImsiOiJleGFtcGxlVmlkMyIsImkiOiJleGFtcGxlVmlkMyJ9"}]},"meta":{"request_id":"req_example","next_cursor":"Et8FEgdleGFtcGxlGgdleGFtcGxl"}}}}}}}}}},"/v1/discover/instagram/posts":{"get":{"operationId":"discover_instagram_posts","tags":["Discover"],"summary":"Search Instagram posts","description":"Search Instagram posts. No sort or time-window filter is available upstream.","parameters":[{"schema":{"type":"string","minLength":1,"description":"Search query"},"required":true,"description":"Search query","name":"q","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NormalizedPost"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"type":"post","platform":{"source":"instagram","name":"Instagram","id":"1000000000000000001","url":"https://www.instagram.com/reel/EXAMPLE1/"},"publishedAt":"2025-07-21T09:00:00.000Z","content":{"text":"Example caption: restock day, and the shelves are full again #smallbusiness #shoplocal","author":{"id":"1000000001","username":"example_creator","name":"Dana Example","profileUrl":"https://instagram.com/example_creator"},"media":[{"type":"video","url":"https://instagram.fna.fbcdn.net/o1/v/t2/f2/m367/example_reel_1.mp4"}],"metrics":{"likes":663,"comments":53,"shares":40}},"post_id":"pid_eyJwIjoiaW5zdGFncmFtIiwiayI6Imh0dHBzOi8vd3d3Lmluc3RhZ3JhbS5jb20vcmVlbC9FWEFNUExFMS8iLCJpIjoiMTAwMDAwMDAwMDAwMDAwMDAwMSJ9"},{"type":"post","platform":{"source":"instagram","name":"Instagram","id":"1000000000000000002","url":"https://www.instagram.com/reel/EXAMPLE2/"},"publishedAt":"2025-10-09T10:21:15.000Z","content":{"text":"Example caption: behind the scenes at our studio this week ✨ New colorways drop Friday.\n\n#smallbusiness #handmade #newcollection","author":{"id":"1000000002","username":"example_mentor","name":"Jordan Example | Ecom Business Mentor","profileUrl":"https://instagram.com/example_mentor"},"media":[{"type":"video","url":"https://instagram.fna.fbcdn.net/o1/v/t2/f2/m367/example_reel_2.mp4"}],"metrics":{"likes":988,"comments":190,"shares":27}},"post_id":"pid_eyJwIjoiaW5zdGFncmFtIiwiayI6Imh0dHBzOi8vd3d3Lmluc3RhZ3JhbS5jb20vcmVlbC9FWEFNUExFMi8iLCJpIjoiMTAwMDAwMDAwMDAwMDAwMDAwMiJ9"},{"type":"post","platform":{"source":"instagram","name":"Instagram","id":"1000000000000000003","url":"https://www.instagram.com/reel/EXAMPLE3/"},"publishedAt":"2026-02-04T18:39:36.000Z","content":{"text":"Example caption: packing day 📦\n#smallbusiness #shoplocal","author":{"id":"1000000003","username":"example_hustle","name":"Quinn Example","profileUrl":"https://instagram.com/example_hustle"},"media":[{"type":"video","url":"https://instagram.fna.fbcdn.net/o1/v/t2/f2/m367/example_reel_3.mp4"}],"metrics":{"likes":19824,"comments":495,"shares":702}},"post_id":"pid_eyJwIjoiaW5zdGFncmFtIiwiayI6Imh0dHBzOi8vd3d3Lmluc3RhZ3JhbS5jb20vcmVlbC9FWEFNUExFMy8iLCJpIjoiMTAwMDAwMDAwMDAwMDAwMDAwMyJ9"}]},"meta":{"request_id":"req_example","next_cursor":"eyJleGFtcGxlIjoiY3Vyc29yIn0=::sid::00000000-0000-4000-8000-000000000002"}}}}}}}}}},"/v1/discover/facebook/posts":{"get":{"operationId":"discover_facebook_posts","tags":["Discover"],"summary":"Search Facebook posts","description":"Search Facebook posts. No sort or time-window filter is available upstream.","parameters":[{"schema":{"type":"string","minLength":1,"description":"Search query"},"required":true,"description":"Search query","name":"q","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NormalizedPost"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"type":"post","platform":{"source":"facebook","name":"Facebook","id":"1000000000000001_2000000000000001","url":"https://www.facebook.com/groups/example_group/permalink/2000000000000001/"},"publishedAt":"2026-08-19T10:02:28.000Z","content":{"text":"Example post: need a storefront expert for our local market","author":{"id":"1000000000000101","username":"example.merchant.1001","name":"Sam Example","profileUrl":"https://m.facebook.com/example.merchant.1001/","profilePicture":"https://media.example.com/avatars/example_merchant_1001.jpg"},"metrics":{"likes":50,"comments":96,"shares":0}},"post_id":"pid_eyJwIjoiZmFjZWJvb2siLCJrIjoiaHR0cHM6Ly93d3cuZmFjZWJvb2suY29tL2dyb3Vwcy9leGFtcGxlX2dyb3VwL3Blcm1hbGluay8yMDAwMDAwMDAwMDAwMDAxLyIsImkiOiIxMDAwMDAwMDAwMDAwMDAxXzIwMDAwMDAwMDAwMDAwMDEifQ"},{"type":"post","platform":{"source":"facebook","name":"Facebook","id":"1000000000000001_2000000000000002","url":"https://www.facebook.com/groups/example_group/permalink/2000000000000002/"},"publishedAt":"2026-08-03T09:32:03.000Z","content":{"text":"Example post: our weekend market stall is moving online. New hours and pickup details are on the shop page 🛍️","author":{"id":"1000000000000102","username":"example.seller.1002","name":"Priya Example","profileUrl":"https://m.facebook.com/example.seller.1002/","profilePicture":"https://media.example.com/avatars/example_seller_1002.jpg"},"media":[{"type":"image","url":"https://external.fna.fbcdn.net/emg1/v/t13/example_1002?url=https%3A%2F%2Fshop.example.com%2Fimage.png","thumbnail":"https://external.fna.fbcdn.net/emg1/v/t13/example_1002?url=https%3A%2F%2Fshop.example.com%2Fimage.png"}],"metrics":{"likes":47,"comments":44,"shares":0}},"post_id":"pid_eyJwIjoiZmFjZWJvb2siLCJrIjoiaHR0cHM6Ly93d3cuZmFjZWJvb2suY29tL2dyb3Vwcy9leGFtcGxlX2dyb3VwL3Blcm1hbGluay8yMDAwMDAwMDAwMDAwMDAyLyIsImkiOiIxMDAwMDAwMDAwMDAwMDAxXzIwMDAwMDAwMDAwMDAwMDIifQ"},{"type":"post","platform":{"source":"facebook","name":"Facebook","id":"1000000000000001_2000000000000003","url":"https://www.facebook.com/groups/example_group/permalink/2000000000000003/"},"publishedAt":"2026-08-17T02:09:16.000Z","content":{"text":"Example post: looking for a storefront expert","author":{"id":"1000000000000103","username":"example.seller.1003","name":"Luna Example","profileUrl":"https://m.facebook.com/example.seller.1003/","profilePicture":"https://media.example.com/avatars/example_seller_1003.jpg"},"metrics":{"likes":80,"comments":142,"shares":0}},"post_id":"pid_eyJwIjoiZmFjZWJvb2siLCJrIjoiaHR0cHM6Ly93d3cuZmFjZWJvb2suY29tL2dyb3Vwcy9leGFtcGxlX2dyb3VwL3Blcm1hbGluay8yMDAwMDAwMDAwMDAwMDAzLyIsImkiOiIxMDAwMDAwMDAwMDAwMDAxXzIwMDAwMDAwMDAwMDAwMDMifQ"}]},"meta":{"request_id":"req_example","next_cursor":"eyJleGFtcGxlIjoiY3Vyc29yIn0::sid::00000000-0000-4000-8000-000000000001"}}}}}}}}}},"/v1/discover/ads":{"get":{"operationId":"discover_ads","tags":["Discover"],"summary":"Search ads","description":"Search ad libraries across Meta, Google, or LinkedIn.","parameters":[{"schema":{"type":"string","enum":["meta","google","linkedin"],"description":"Ad platform to search (meta, google, or linkedin)"},"required":true,"description":"Ad platform to search (meta, google, or linkedin)","name":"platform","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Free-text term matched against the library's CREATIVE TEXT on meta and linkedin — it returns ads mentioning the term, not one advertiser's ads (use `advertiser` for that), and it composes with `advertiser` to narrow that advertiser's own ads. For platform=google this is an advertiser domain (e.g. 'shopify.com') — the Google Ads Transparency Center has no free-text search — so there it names the advertiser too and cannot be combined with `advertiser`; pass one. Optional only when `advertiser` is supplied."},"required":false,"description":"Free-text term matched against the library's CREATIVE TEXT on meta and linkedin — it returns ads mentioning the term, not one advertiser's ads (use `advertiser` for that), and it composes with `advertiser` to narrow that advertiser's own ads. For platform=google this is an advertiser domain (e.g. 'shopify.com') — the Google Ads Transparency Center has no free-text search — so there it names the advertiser too and cannot be combined with `advertiser`; pass one. Optional only when `advertiser` is supplied.","name":"q","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":512,"description":"Return one advertiser's OWN ads. Supported by platform — meta: the advertiser's numeric page id; google: the advertiser's transparency-center id (AR + 20 digits); linkedin: the advertiser's name. On meta, resolve a name to its page id with GET /v1/companies/facebook/search first — the library answers a name with nothing. On google every row of a domain search carries the advertiser's id, so a domain search resolves one without a second lookup."},"required":false,"description":"Return one advertiser's OWN ads. Supported by platform — meta: the advertiser's numeric page id; google: the advertiser's transparency-center id (AR + 20 digits); linkedin: the advertiser's name. On meta, resolve a name to its page id with GET /v1/companies/facebook/search first — the library answers a name with nothing. On google every row of a domain search carries the advertiser's id, so a domain search resolves one without a second lookup.","name":"advertiser","in":"query"},{"schema":{"type":"string","enum":["ALL","ACTIVE","INACTIVE"],"description":"Whether to answer live ads, ended ones, or both. Supported by platform — meta: ALL|ACTIVE|INACTIVE. Omitted, meta answers currently-running ads, which is what this endpoint has always returned. Refused on any other platform."},"required":false,"description":"Whether to answer live ads, ended ones, or both. Supported by platform — meta: ALL|ACTIVE|INACTIVE. Omitted, meta answers currently-running ads, which is what this endpoint has always returned. Refused on any other platform.","name":"activity_status","in":"query"},{"schema":{"type":"string","description":"ISO-2 country code (e.g. US). Supported by platform — meta: ISO-2; google: ISO-2; linkedin: ISO-2. The meta library has no every-market value, so omitting it there searches the US rather than worldwide."},"required":false,"description":"ISO-2 country code (e.g. US). Supported by platform — meta: ISO-2; google: ISO-2; linkedin: ISO-2. The meta library has no every-market value, so omitting it there searches the US rather than worldwide.","name":"country","in":"query"},{"schema":{"type":"string","description":"Recency window, NOT a date. Supported values by platform — google: 7d|30d; linkedin: 30d. meta takes no window on this endpoint — its library has date bounds, but they are not wired here yet. `activity_status` is not a substitute: it selects live vs ended creative, not a date range."},"required":false,"description":"Recency window, NOT a date. Supported values by platform — google: 7d|30d; linkedin: 30d. meta takes no window on this endpoint — its library has date bounds, but they are not wired here yet. `activity_status` is not a substitute: it selects live vs ended creative, not a date range.","name":"since","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"}],"responses":{"200":{"description":"Ad search results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DiscoverAd"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"type":"ad","id":"00000000-0000-5000-8000-000000000001","platform":{"source":"meta","name":"Meta Ads","id":"1000000000000001","url":"https://www.facebook.com/ads/library/?id=example1000000000000001"},"publishedAt":"2026-01-13T08:00:00.000Z","content":{"text":"Example ad: when it’s time to start your business, it’s time for Example Brand.","title":"Example headline: get going and keep growing","author":{"id":"1000000001","username":"example_brand","name":"Example Brand","profileUrl":"https://facebook.com/example_brand"},"media":[{"type":"image","url":"https://scontent.fna.fbcdn.net/v/t39.35426-6/example_ad_1_a.jpg","thumbnail":"https://scontent.fna.fbcdn.net/v/t39.35426-6/example_ad_1_a_thumb.jpg"},{"type":"image","url":"https://scontent.fna.fbcdn.net/v/t39.35426-6/example_ad_1_b.jpg","thumbnail":"https://scontent.fna.fbcdn.net/v/t39.35426-6/example_ad_1_b_thumb.jpg"}],"cta":{"text":"Example CTA: Sign up","type":"SIGN_UP","url":"https://www.example.com/free-trial"},"adType":"DCO"},"targeting":{"platforms":["FACEBOOK","INSTAGRAM","MESSENGER"]},"campaignDates":{"firstShown":"2026-01-13T08:00:00.000Z","lastShown":"2026-07-02T07:00:00.000Z"},"metadata":{"collationId":"1000000000000101","collationCount":null,"isActive":true,"pageCategories":["Software"],"pageLikes":4533317,"profilePictureUrl":"https://media.example.com/avatars/example_brand.jpg"}},{"type":"ad","id":"00000000-0000-5000-8000-000000000002","platform":{"source":"meta","name":"Meta Ads","id":"1000000000000002","url":"https://www.facebook.com/ads/library/?id=example1000000000000002"},"publishedAt":"2026-03-25T07:00:00.000Z","content":{"text":"Example anuncio: vende en todas partes, online, en redes sociales y en persona","title":"Example titular: vende en todas partes","author":{"id":"1000000001","username":"example_brand","name":"Example Brand","profileUrl":"https://facebook.com/example_brand"},"media":[{"type":"image","url":"https://scontent.fna.fbcdn.net/v/t39.35426-6/example_ad_2_a.jpg","thumbnail":"https://scontent.fna.fbcdn.net/v/t39.35426-6/example_ad_2_a_thumb.jpg"},{"type":"image","url":"https://scontent.fna.fbcdn.net/v/t39.35426-6/example_ad_2_b.jpg","thumbnail":"https://scontent.fna.fbcdn.net/v/t39.35426-6/example_ad_2_b_thumb.jpg"}],"cta":{"text":"Example CTA: Sign up","type":"SIGN_UP","url":"https://www.example.com/es?country=es&lang=es"},"adType":"DCO"},"targeting":{"platforms":["FACEBOOK","INSTAGRAM","MESSENGER"]},"campaignDates":{"firstShown":"2026-03-25T07:00:00.000Z","lastShown":"2026-07-02T07:00:00.000Z"},"metadata":{"collationId":"1000000000000102","collationCount":null,"isActive":true,"pageCategories":["Software"],"pageLikes":4533317,"profilePictureUrl":"https://media.example.com/avatars/example_brand.jpg"}},{"type":"ad","id":"00000000-0000-5000-8000-000000000003","platform":{"source":"meta","name":"Meta Ads","id":"1000000000000003","url":"https://www.facebook.com/ads/library/?id=example1000000000000003"},"publishedAt":"2026-04-15T07:00:00.000Z","content":{"text":"Example ad: when it’s time to start your business, it’s time for Example Brand.","title":"Example headline: go from launch to legendary","author":{"id":"1000000001","username":"example_brand","name":"Example Brand","profileUrl":"https://facebook.com/example_brand"},"media":[{"type":"image","url":"https://scontent.fna.fbcdn.net/v/t39.35426-6/example_ad_3_a.jpg","thumbnail":"https://scontent.fna.fbcdn.net/v/t39.35426-6/example_ad_3_a_thumb.jpg"},{"type":"image","url":"https://scontent.fna.fbcdn.net/v/t39.35426-6/example_ad_3_b.jpg","thumbnail":"https://scontent.fna.fbcdn.net/v/t39.35426-6/example_ad_3_b_thumb.jpg"}],"cta":{"text":"Example CTA: Sign up","type":"SIGN_UP","url":"https://www.example.com/?country=us&lang=en"},"adType":"DCO"},"targeting":{"platforms":["FACEBOOK","INSTAGRAM","MESSENGER"]},"campaignDates":{"firstShown":"2026-04-15T07:00:00.000Z","lastShown":"2026-07-02T07:00:00.000Z"},"metadata":{"collationId":"1000000000000103","collationCount":null,"isActive":true,"pageCategories":["Software"],"pageLikes":4533317,"profilePictureUrl":"https://media.example.com/avatars/example_brand.jpg"}}]},"meta":{"request_id":"req_example","total":11333,"next_cursor":"AQHSexample_cursor_page_2"}}}}}}}}}},"/v1/discover/trends":{"get":{"operationId":"discover_trends","tags":["Discover"],"summary":"Get trending topics","description":"Retrieve trending topics from X, TikTok, or Google Trends.","parameters":[{"schema":{"type":"string","enum":["x","google_trends","tiktok"],"description":"Trends platform (x | tiktok | google_trends)"},"required":true,"description":"Trends platform (x | tiktok | google_trends)","name":"platform","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Search query (required for google_trends; ignored for x and tiktok, which list current trends rather than searching them)"},"required":false,"description":"Search query (required for google_trends; ignored for x and tiktok, which list current trends rather than searching them)","name":"q","in":"query"},{"schema":{"type":"string","description":"Country filter (ISO 2-letter code)"},"required":false,"description":"Country filter (ISO 2-letter code)","name":"country","in":"query"}],"responses":{"200":{"description":"Trending topics","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DiscoverTrend"}}},"required":["items"],"additionalProperties":{},"description":"Normalized `items` plus the upstream platform's own response fields (e.g. Google Trends returns `query`, `timeframe`, `results`, `count`). Only `items` is stable across platforms."},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"success":true,"query":"shopify","location":"US","timeframe":"today 1-m","platform":"web","dataType":"related_queries","search_metadata":{"id":"search_example0000000000000001","status":"Success","created_at":"2026-06-14T15:58:07Z","request_time_taken":5.03,"parsing_time_taken":0,"total_time_taken":5.04,"request_url":"https://trends.google.com/trends/explore?q=shopify&geo=&tz=420&date=today 1-m&cat=0","html_url":"https://www.searchapi.io/api/v1/searches/search_example0000000000000001.html","json_url":"https://www.searchapi.io/api/v1/searches/search_example0000000000000001"},"results":{"rising":[{"position":1,"query":"shopify theme dev","values":"+600%","extracted_value":600,"link":"https://trends.google.com/trends/explore?q=shopify+theme+dev&date=today+1-m"},{"position":2,"query":"shopify down?","values":"+170%","extracted_value":170,"link":"https://trends.google.com/trends/explore?q=shopify+down?&date=today+1-m"},{"position":3,"query":"shopify rebellion r6","values":"+130%","extracted_value":130,"link":"https://trends.google.com/trends/explore?q=shopify+rebellion+r6&date=today+1-m"}],"top":[{"position":1,"query":"shopify app","values":"100","extracted_value":100,"link":"https://trends.google.com/trends/explore?q=shopify+app&date=today+1-m"},{"position":2,"query":"shopify store","values":"88","extracted_value":88,"link":"https://trends.google.com/trends/explore?q=shopify+store&date=today+1-m"},{"position":3,"query":"shopify price","values":"76","extracted_value":76,"link":"https://trends.google.com/trends/explore?q=shopify+price&date=today+1-m"}]},"count":18,"numResults":20,"items":[{"type":"trend","id":"00000000-0000-5000-8000-0000000000a1","platform":{"source":"google_trends","name":"Google Trends","id":"shopify theme dev","url":"https://trends.google.com/trends/explore?q=shopify+theme+dev&date=today+1-m"},"publishedAt":"2026-06-14T15:58:12.841Z","content":{"title":"shopify theme dev","query":"shopify theme dev"},"metrics":{"searches":600,"position":1},"metadata":{"type":"related_query"}},{"type":"trend","id":"00000000-0000-5000-8000-0000000000a2","platform":{"source":"google_trends","name":"Google Trends","id":"shopify down?","url":"https://trends.google.com/trends/explore?q=shopify+down?&date=today+1-m"},"publishedAt":"2026-06-14T15:58:12.841Z","content":{"title":"shopify down?","query":"shopify down?"},"metrics":{"searches":170,"position":2},"metadata":{"type":"related_query"}},{"type":"trend","id":"00000000-0000-5000-8000-0000000000a3","platform":{"source":"google_trends","name":"Google Trends","id":"shopify rebellion r6","url":"https://trends.google.com/trends/explore?q=shopify+rebellion+r6&date=today+1-m"},"publishedAt":"2026-06-14T15:58:12.841Z","content":{"title":"shopify rebellion r6","query":"shopify rebellion r6"},"metrics":{"searches":130,"position":3},"metadata":{"type":"related_query"}}]},"meta":{"request_id":"req_example"}}}}}}}}}},"/v1/discover/users":{"get":{"operationId":"discover_users","tags":["Discover"],"summary":"Find creators","description":"Search for creators or users across a specified social platform.","parameters":[{"schema":{"type":"string","enum":["x","instagram","tiktok","linkedin","facebook","youtube"],"description":"Social platform to search"},"required":true,"description":"Social platform to search","name":"platform","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Search query"},"required":true,"description":"Search query","name":"q","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"}],"responses":{"200":{"description":"Creator search results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/CreatorProfile"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"platform":"instagram","id":"1000000001","handle":"example_brand","name":"Example Brand","url":"https://www.instagram.com/example_brand","profilePicture":"https://media.example.com/avatars/example_brand.jpg","isVerified":true},{"platform":"instagram","id":"1000000002","handle":"example_esports","name":"Example Esports Team","url":"https://www.instagram.com/example_esports","profilePicture":"https://media.example.com/avatars/example_esports.jpg","isVerified":false},{"platform":"instagram","id":"1000000003","handle":"example_merchant","name":"Example Merchant | Storefront Tips","url":"https://www.instagram.com/example_merchant","profilePicture":"https://media.example.com/avatars/example_merchant.jpg","isVerified":false}]},"meta":{"request_id":"req_example","next_cursor":null}}}}}}}}}},"/v1/discover/companies":{"get":{"operationId":"discover_companies","tags":["Discover"],"summary":"Search companies","description":"Search for companies on LinkedIn.","parameters":[{"schema":{"type":"string","minLength":1,"description":"Company name or keyword"},"required":true,"description":"Company name or keyword","name":"q","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"}],"responses":{"200":{"description":"Company search results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LinkedInCompanyResult"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"urn":"urn:li:fsd_company:1000001","name":"Example Commerce Co","specializes_in":"Software Development","description":"Example Commerce Co is a global commerce company providing tools to start, grow, market and manage a retail business of any size...","headquarters":"Ottawa, ON","followers":1000000,"company_logo":"https://media.licdn.com/dms/image/example_logo_1/company-logo_400_400/0/1700000000000/example_commerce_logo?e=1800000000&v=beta&t=example_token_1","jobs":127,"page_by":null,"public_identifier":"example_commerce","url":"https://www.linkedin.com/company/example_commerce/"},{"urn":"urn:li:fsd_company:1000002","name":"Example Agency (Commerce Partner)","specializes_in":"Software Development","description":"Example Agency is a full-service eCommerce agency delivering end-to-end solutions that connect brand strategy...","headquarters":"Tampa, Florida","followers":28000,"company_logo":"https://media.licdn.com/dms/image/example_logo_2/company-logo_400_400/0/1700000000001/example_agency_logo?e=1800000000&v=beta&t=example_token_2","jobs":null,"page_by":null,"public_identifier":"example_agency","url":"https://www.linkedin.com/company/example_agency/"},{"urn":"urn:li:fsd_company:1000003","name":"Example Studio - Platinum Partner","specializes_in":"Software Development","description":"Example Studio builds precision-engineered commerce solutions for enterprise","headquarters":"Charleston, South Carolina","followers":26000,"company_logo":"https://media.licdn.com/dms/image/example_logo_3/company-logo_400_400/0/1700000000002/example_studio_logo?e=1800000000&v=beta&t=example_token_3","jobs":8,"page_by":null,"public_identifier":"example_studio","url":"https://www.linkedin.com/company/example_studio/"}]},"meta":{"request_id":"req_example","next_cursor":"eyJleGFtcGxlIjoiY3Vyc29yIn0="}}}}}}}}}},"/v1/discover/jobs":{"get":{"operationId":"discover_jobs","tags":["Discover"],"summary":"Search jobs","description":"Search for job listings on LinkedIn.","parameters":[{"schema":{"type":"string","minLength":1,"description":"Job title or keyword"},"required":true,"description":"Job title or keyword","name":"q","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"}],"responses":{"200":{"description":"Job search results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LinkedInJobResult"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"title":"Overnight Merchant Support Advisor, Canada (Canada )","subtitle":null,"urn":"urn:li:fs_normalized_jobPosting:1000000001","company":"Example Commerce Co","location":"Canada (Remote)","url":"https://www.linkedin.com/jobs/view/example-1000000001","listing_date":"2026-06-29T17:37:34.000Z"},{"title":"Freelance Storefront Developer – Remote","subtitle":null,"urn":"urn:li:fs_normalized_jobPosting:1000000002","company":"Example Talent Network","location":"New Zealand (Remote)","url":"https://www.linkedin.com/jobs/view/example-1000000002","listing_date":"2026-07-02T11:10:09.000Z"},{"title":"Ecommerce Consultant - Fully Remote | Up to $70/hr","subtitle":null,"urn":"urn:li:fs_normalized_jobPosting:1000000003","company":"Example Staffing","location":"Toronto, ON (Remote)","url":"https://www.linkedin.com/jobs/view/example-1000000003","listing_date":"2026-06-30T11:56:05.000Z"}]},"meta":{"request_id":"req_example","next_cursor":"eyJleGFtcGxlIjoiY3Vyc29yIn0="}}}}}}}}}},"/v1/discover/communities":{"get":{"operationId":"discover_communities","tags":["Discover"],"summary":"Search communities","description":"Search for subreddits and communities on Reddit.","parameters":[{"schema":{"type":"string","minLength":1,"description":"Community name or topic"},"required":true,"description":"Community name or topic","name":"q","in":"query"}],"responses":{"200":{"description":"Community search results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/RedditCommunityResult"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"name":"r/example_community","href":"https://reddit.com/r/example_community/","description":"Example community: a forum for store owners to ask questions and discuss platform-specific issues. Promotion-free; posts must be specific to the platform.","subscribers":373899},{"name":"r/example_devs","href":"https://reddit.com/r/example_devs/","description":"Example community for app and storefront developers. Surveys are not allowed.","subscribers":27288},{"name":"r/example_growth","href":"https://reddit.com/r/example_growth/","description":"Example community for founders, marketers and operators focused on scaling ecommerce brands: conversion, retention, personalization and paid performance.","subscribers":7592}]},"meta":{"request_id":"req_example"}}}}}}}}}},"/v1/posts/lookup":{"get":{"operationId":"enrichment_post_lookup","tags":["Enrichment"],"summary":"Look up a post by URL","description":"Resolve a raw post URL to its enriched data. The response carries a minted opaque `post_id` (`pid_…` token) downstream `/v1/posts/{post_id}` and `/comments` lookups consume directly — this is the entry point into the post-id system for URLs sourced outside our API. Platform is sniffed from the URL host; pass `platform` explicitly when the host is ambiguous (e.g. a shortened link).","parameters":[{"schema":{"type":"string","format":"uri","description":"Full post URL (LinkedIn, Twitter/X, Instagram, TikTok, Facebook, YouTube, Reddit)"},"required":true,"description":"Full post URL (LinkedIn, Twitter/X, Instagram, TikTok, Facebook, YouTube, Reddit)","name":"url","in":"query"},{"schema":{"type":"string","enum":["x","instagram","tiktok","linkedin","facebook","youtube","reddit"],"description":"Optional override when the URL host doesn't disambiguate the platform."},"required":false,"description":"Optional override when the URL host doesn't disambiguate the platform.","name":"platform","in":"query"}],"responses":{"200":{"description":"Enriched post data with minted post_id","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/NormalizedPost"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}}}}},"/v1/posts/{post_id}":{"get":{"operationId":"enrichment_post_get","tags":["Enrichment"],"summary":"Get enriched post","description":"Retrieve an enriched post by `post_id` — either the opaque `pid_…` token returned in discover/search/profile-posts items and `/v1/posts/lookup` responses, OR a bare platform ID (e.g. tweet id) paired with the `platform` query. Both forms are first-class. A raw URL in the path param is unsupported: encoded slashes die at the API gateway with a bare 404 before the handler runs. Use `/v1/posts/lookup?url=…` instead.","parameters":[{"schema":{"type":"string","description":"Opaque pid_… token (returned in discover/search/profile-posts items and /v1/posts/lookup responses) OR a bare platform ID paired with the `platform` query — both forms are first-class. Do NOT pass a raw post URL: encoded slashes die at the API gateway and return a bare 404 before the handler runs. Use /v1/posts/lookup?url=… when you only have a URL."},"required":true,"description":"Opaque pid_… token (returned in discover/search/profile-posts items and /v1/posts/lookup responses) OR a bare platform ID paired with the `platform` query — both forms are first-class. Do NOT pass a raw post URL: encoded slashes die at the API gateway and return a bare 404 before the handler runs. Use /v1/posts/lookup?url=… when you only have a URL.","name":"post_id","in":"path"},{"schema":{"type":"string","enum":["x","instagram","tiktok","linkedin","facebook","youtube","reddit"],"description":"Required only when `post_id` is a bare platform ID; ignored when a synthetic pid_ token is supplied."},"required":false,"description":"Required only when `post_id` is a bare platform ID; ignored when a synthetic pid_ token is supplied.","name":"platform","in":"query"}],"responses":{"200":{"description":"Enriched post data","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/NormalizedPost"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"type":"post","platform":{"source":"instagram","name":"Instagram","id":"1000000000000000005_1000000005","url":"https://www.instagram.com/reel/EXAMPLE5/"},"publishedAt":"2026-02-04T18:39:36.000Z","content":{"text":"Example caption: packing day 📦\n#smallbusiness #shoplocal","author":{"id":"1000000005","username":"example_creator","name":"Alex Example","profileUrl":"https://instagram.com/example_creator"},"media":[{"type":"video","url":"https://media.example.com/posts/example-reel-5.mp4","thumbnail":"https://media.example.com/posts/example-reel-5.jpg"}],"metrics":{"likes":20508,"comments":634,"shares":13726}},"post_id":"pid_eyJwIjoiaW5zdGFncmFtIiwiayI6Imh0dHBzOi8vd3d3Lmluc3RhZ3JhbS5jb20vcmVlbC9FWEFNUExFNS8iLCJpIjoiMTAwMDAwMDAwMDAwMDAwMDAwNV8xMDAwMDAwMDA1In0"},"meta":{"request_id":"req_example"}}}}}}}}}},"/v1/posts/{post_id}/comments":{"get":{"operationId":"enrichment_post_comments","tags":["Enrichment"],"summary":"Get post comments","description":"Retrieve comments or replies on a post. Same `post_id` semantics as `/v1/posts/{post_id}`. `cursor` is honored on x / instagram / tiktok / linkedin / facebook / youtube; reddit's scan_reddit_post_page tool has no pagination, so `cursor` is ignored on reddit (the response carries every retrievable comment in one call).","parameters":[{"schema":{"type":"string","description":"Opaque pid_… token (returned in discover/search/profile-posts items and /v1/posts/lookup responses) OR a bare platform ID paired with the `platform` query — both forms are first-class. Do NOT pass a raw post URL: encoded slashes die at the API gateway and return a bare 404 before the handler runs. Use /v1/posts/lookup?url=… when you only have a URL."},"required":true,"description":"Opaque pid_… token (returned in discover/search/profile-posts items and /v1/posts/lookup responses) OR a bare platform ID paired with the `platform` query — both forms are first-class. Do NOT pass a raw post URL: encoded slashes die at the API gateway and return a bare 404 before the handler runs. Use /v1/posts/lookup?url=… when you only have a URL.","name":"post_id","in":"path"},{"schema":{"type":"string","enum":["x","instagram","tiktok","linkedin","facebook","youtube","reddit"],"description":"Required only when `post_id` is a bare platform ID; ignored when a synthetic pid_ token is supplied."},"required":false,"description":"Required only when `post_id` is a bare platform ID; ignored when a synthetic pid_ token is supplied.","name":"platform","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"}],"responses":{"200":{"description":"Post comments","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PostComment"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"id":"18000000000000011","text":"Example comment: incredible","author":{"id":"1000000011","username":"example_fan_one","profilePicture":"https://media.example.com/avatars/example-fan-one.jpg"},"createdAt":"2026-06-09T14:17:59.000Z","likes":7},{"id":"18000000000000012","text":"Example comment: 🔥","author":{"id":"1000000012","username":"example_fan_two","profilePicture":"https://media.example.com/avatars/example-fan-two.jpg"},"createdAt":"2026-06-09T14:17:29.000Z","likes":8},{"id":"18000000000000013","text":"Example comment: teach me","author":{"id":"1000000013","username":"example_fan_three","profilePicture":"https://media.example.com/avatars/example-fan-three.jpg"},"createdAt":"2026-06-09T16:22:45.000Z","likes":5}]},"meta":{"request_id":"req_example","next_cursor":"eyJtIjoiZXhhbXBsZS1jb21tZW50cy1jdXJzb3IifQ==::sid::0f1e2d3c-0001-4b5a-8c7d-0000000000c1"}}}}}}}}}},"/v1/posts/{post_id}/reactors":{"get":{"operationId":"enrichment_post_reactors","tags":["Enrichment"],"summary":"Get post reactors","description":"Retrieve the people who reacted to or liked a post, with their identity — LinkedIn reactors (with reaction type) or Instagram likers. Supported on LinkedIn and Instagram today; other platforms return 400. Same `post_id` semantics as `/v1/posts/{post_id}`. LinkedIn returns up to ~50 reactors per request (which may span more than one upstream page) — follow `meta.next_cursor` to page deeper; Instagram returns all likers in one call (no pagination). `reactionType` filters LinkedIn reactions only.","parameters":[{"schema":{"type":"string","description":"Opaque pid_… token (returned in discover/search/profile-posts items and /v1/posts/lookup responses) OR a bare platform ID paired with the `platform` query — both forms are first-class. Do NOT pass a raw post URL: encoded slashes die at the API gateway and return a bare 404 before the handler runs. Use /v1/posts/lookup?url=… when you only have a URL."},"required":true,"description":"Opaque pid_… token (returned in discover/search/profile-posts items and /v1/posts/lookup responses) OR a bare platform ID paired with the `platform` query — both forms are first-class. Do NOT pass a raw post URL: encoded slashes die at the API gateway and return a bare 404 before the handler runs. Use /v1/posts/lookup?url=… when you only have a URL.","name":"post_id","in":"path"},{"schema":{"type":"string","enum":["x","instagram","tiktok","linkedin","facebook","youtube","reddit"],"description":"Required only when `post_id` is a bare platform ID; ignored when a synthetic pid_ token is supplied."},"required":false,"description":"Required only when `post_id` is a bare platform ID; ignored when a synthetic pid_ token is supplied.","name":"platform","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page"},"required":false,"description":"Pagination cursor for next page","name":"cursor","in":"query"},{"schema":{"type":"string","enum":["LIKE","PRAISE","APPRECIATION","EMPATHY","INTEREST","ENTERTAINMENT"],"description":"Filter to a single reaction type: LIKE | PRAISE (Celebrate) | APPRECIATION (Support) | EMPATHY (Love) | INTEREST (Insightful) | ENTERTAINMENT (Funny). Omit for all types."},"required":false,"description":"Filter to a single reaction type: LIKE | PRAISE (Celebrate) | APPRECIATION (Support) | EMPATHY (Love) | INTEREST (Insightful) | ENTERTAINMENT (Funny). Omit for all types.","name":"reactionType","in":"query"}],"responses":{"200":{"description":"Post reactors (single page)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PostReactor"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"author":{"type":"Member","name":"Riley Example","headline":"Example headline: operations lead","profileUrl":"https://www.linkedin.com/in/example-riley-2001/","publicIdentifier":"example-riley-2001"},"reactionType":"EMPATHY"},{"author":{"type":"Member","name":"Casey Example","headline":"Example headline: product designer at Example Studio","profileUrl":"https://www.linkedin.com/in/example-casey-2002/","publicIdentifier":"example-casey-2002"},"reactionType":"LIKE"},{"author":{"type":"Member","name":"Morgan Example","headline":"Example headline: marketing specialist at Example Agency","profileUrl":"https://www.linkedin.com/in/example-morgan-2003/","publicIdentifier":"example-morgan-2003"},"reactionType":"LIKE"}]},"meta":{"request_id":"req_example","next_cursor":"eyJzdGFydCI6NTAsImNvdW50Ijo1MCwidG90YWwiOjAsInBhZ2luYXRpb25Ub2tlbiI6ImV4YW1wbGUtcGFnZS10b2tlbiJ9"}}}}}}}}}},"/v1/profiles/{platform}/{username}":{"get":{"operationId":"enrichment_profile_get","tags":["Enrichment"],"summary":"Get social profile","description":"Retrieve a social media profile by platform and username.","parameters":[{"schema":{"type":"string","enum":["x","instagram","tiktok","linkedin","facebook","youtube","reddit"],"description":"Social platform"},"required":true,"description":"Social platform","name":"platform","in":"path"},{"schema":{"type":"string","description":"Username or handle (without @)"},"required":true,"description":"Username or handle (without @)","name":"username","in":"path"}],"responses":{"200":{"description":"Profile data","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/NormalizedProfile"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"type":"profile","id":"0b1c2d3e-0001-5a6b-8c7d-000000000501","platform":{"source":"instagram","name":"Instagram","id":"example_brand","url":"https://www.instagram.com/example_brand"},"content":{"name":"Example Brand","bio":"Example bio: tools for every entrepreneur","url":"https://www.instagram.com/example_brand","profilePicture":"https://media.example.com/avatars/example-brand.jpg"},"metrics":{"followers":2513954},"metadata":{"following":1697,"mediaCount":3678,"isVerified":true,"isBusiness":true,"isPrivate":false,"externalUrl":"https://www.example.com/"}},"meta":{"request_id":"req_example"}}}}}}}}}},"/v1/profiles/{platform}/{username}/posts":{"get":{"operationId":"enrichment_profile_posts","tags":["Enrichment"],"summary":"Get user's recent posts","description":"Retrieve recent posts from a user's profile on the specified platform. For YouTube, `type` is required — YouTube splits a channel's uploads into separate `videos` (long-form) and `shorts` streams that must be fetched independently. Call this endpoint twice (once per type) if you want both.","parameters":[{"schema":{"type":"string","enum":["x","instagram","tiktok","linkedin","facebook","youtube","reddit"],"description":"Social platform"},"required":true,"description":"Social platform","name":"platform","in":"path"},{"schema":{"type":"string","description":"Username or handle (without @)"},"required":true,"description":"Username or handle (without @)","name":"username","in":"path"},{"schema":{"type":"string","enum":["videos","shorts"],"description":"YouTube only — selects which upload stream to fetch. Required when `platform=youtube`."},"required":false,"description":"YouTube only — selects which upload stream to fetch. Required when `platform=youtube`.","name":"type","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page. One request returns one page; follow `meta.next_cursor` for deeper history."},"required":false,"description":"Pagination cursor for next page. One request returns one page; follow `meta.next_cursor` for deeper history.","name":"cursor","in":"query"}],"responses":{"200":{"description":"User's posts (single page)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NormalizedPost"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"type":"post","platform":{"source":"instagram","name":"Instagram","id":"1000000000000000031_1000000030","url":"https://www.instagram.com/p/EXAMPLE31/"},"publishedAt":"2026-07-02T15:16:00.000Z","content":{"text":"Example post: meet your store's new AI assistant","author":{"id":"1000000030","username":"example_brand","name":"Example Brand","profileUrl":"https://instagram.com/example_brand"},"media":[{"type":"video","url":"https://media.example.com/posts/example-31-1.mp4","thumbnail":"https://media.example.com/posts/example-31-1.jpg"}],"metrics":{"likes":86,"comments":8,"views":35668}},"post_id":"pid_eyJwIjoiaW5zdGFncmFtIiwiayI6Imh0dHBzOi8vd3d3Lmluc3RhZ3JhbS5jb20vcC9FWEFNUExFMzEvIiwiaSI6IjEwMDAwMDAwMDAwMDAwMDAwMzFfMTAwMDAwMDAzMCJ9"},{"type":"post","platform":{"source":"instagram","name":"Instagram","id":"1000000000000000032_1000000030","url":"https://www.instagram.com/p/EXAMPLE32/"},"publishedAt":"2026-06-30T16:01:04.000Z","content":{"text":"Example post: still not over these summer edition updates","author":{"id":"1000000030","username":"example_brand","name":"Example Brand","profileUrl":"https://instagram.com/example_brand"},"media":[{"type":"image","url":"https://media.example.com/posts/example-32-1.jpg","thumbnail":"https://media.example.com/posts/example-32-1-thumb.jpg"},{"type":"video","url":"https://media.example.com/posts/example-32-2.mp4","thumbnail":"https://media.example.com/posts/example-32-2.jpg"},{"type":"image","url":"https://media.example.com/posts/example-32-3.jpg","thumbnail":"https://media.example.com/posts/example-32-3-thumb.jpg"}],"metrics":{"likes":387,"comments":30}},"post_id":"pid_eyJwIjoiaW5zdGFncmFtIiwiayI6Imh0dHBzOi8vd3d3Lmluc3RhZ3JhbS5jb20vcC9FWEFNUExFMzIvIiwiaSI6IjEwMDAwMDAwMDAwMDAwMDAwMzJfMTAwMDAwMDAzMCJ9"},{"type":"post","platform":{"source":"instagram","name":"Instagram","id":"1000000000000000033_1000000030","url":"https://www.instagram.com/p/EXAMPLE33/"},"publishedAt":"2026-06-29T16:23:18.000Z","content":{"text":"Example post: you get the point. right?","author":{"id":"1000000030","username":"example_brand","name":"Example Brand","profileUrl":"https://instagram.com/example_brand"},"media":[{"type":"image","url":"https://media.example.com/posts/example-33-1.jpg","thumbnail":"https://media.example.com/posts/example-33-1-thumb.jpg"},{"type":"image","url":"https://media.example.com/posts/example-33-2.jpg","thumbnail":"https://media.example.com/posts/example-33-2-thumb.jpg"},{"type":"image","url":"https://media.example.com/posts/example-33-3.jpg","thumbnail":"https://media.example.com/posts/example-33-3-thumb.jpg"}],"metrics":{"likes":532,"comments":38}},"post_id":"pid_eyJwIjoiaW5zdGFncmFtIiwiayI6Imh0dHBzOi8vd3d3Lmluc3RhZ3JhbS5jb20vcC9FWEFNUExFMzMvIiwiaSI6IjEwMDAwMDAwMDAwMDAwMDAwMzNfMTAwMDAwMDAzMCJ9"}]},"meta":{"request_id":"req_example","next_cursor":"eyJpIjoiMTAwMDAwMDAwMDAwMDAwMDAzMCIsImciOiJleGFtcGxlLXBhZ2UtdG9rZW4ifQ==::sid::0f1e2d3c-0002-4b5a-8c7d-0000000000c2"}}}}}}}}}},"/v1/profiles/{platform}/{username}/following":{"get":{"operationId":"enrichment_profile_following","tags":["Enrichment"],"summary":"Get accounts a user follows","description":"Retrieve the accounts a user follows on the specified platform. Supported on x, instagram, tiktok, and facebook. One request returns one page (~50–70 accounts); follow `meta.next_cursor` in the response to page deeper.","parameters":[{"schema":{"type":"string","enum":["x","instagram","tiktok","facebook"],"description":"Social platform (x, instagram, tiktok, facebook)"},"required":true,"description":"Social platform (x, instagram, tiktok, facebook)","name":"platform","in":"path"},{"schema":{"type":"string","description":"Username or handle (without @)"},"required":true,"description":"Username or handle (without @)","name":"username","in":"path"},{"schema":{"type":"string","description":"Pagination cursor for the next page. One request returns one page; pass back the `meta.next_cursor` returned in the response for more."},"required":false,"description":"Pagination cursor for the next page. One request returns one page; pass back the `meta.next_cursor` returned in the response for more.","name":"cursor","in":"query"}],"responses":{"200":{"description":"Accounts the user follows (single page)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FollowedAccount"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}}}}},"/v1/videos/{video_id}/transcript":{"get":{"operationId":"enrichment_video_transcript","tags":["Enrichment"],"summary":"Get video transcript","description":"Retrieve the transcript for a YouTube video.","parameters":[{"schema":{"type":"string","description":"YouTube video ID"},"required":true,"description":"YouTube video ID","name":"video_id","in":"path"}],"responses":{"200":{"description":"Video transcript","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/VideoTranscript"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"data":[{"text":"","startMs":0,"durationMs":28875},{"text":"Example transcript: today we're packing the first orders from the new collection.","startMs":0,"durationMs":5560},{"text":"\n","startMs":2150,"durationMs":3410}]},"meta":{"request_id":"req_example"}}}}}}}}}},"/v1/companies/{platform}/search":{"get":{"operationId":"enrichment_company_search","tags":["Enrichment"],"summary":"Search company directory","description":"Search a platform's company directory by name. LinkedIn dispatches to the Vetric companies search; Facebook dispatches to the Meta Ad Library (returning page_alias and ig_username natively). Other platforms return 400 'platform not supported'.","parameters":[{"schema":{"type":"string","enum":["x","instagram","tiktok","linkedin","facebook","youtube","reddit"],"description":"Platform (linkedin and facebook supported today)"},"required":true,"description":"Platform (linkedin and facebook supported today)","name":"platform","in":"path"},{"schema":{"type":"string","minLength":1,"description":"Search query (typically a brand name)"},"required":true,"description":"Search query (typically a brand name)","name":"q","in":"query"},{"schema":{"type":"string","description":"Pagination cursor for next page. One request returns one page; follow `meta.next_cursor` for more."},"required":false,"description":"Pagination cursor for next page. One request returns one page; follow `meta.next_cursor` for more.","name":"cursor","in":"query"},{"schema":{"type":"string","description":"ISO 2-letter country code (Facebook / Meta Ad Library only)"},"required":false,"description":"ISO 2-letter country code (Facebook / Meta Ad Library only)","name":"country","in":"query"}],"responses":{"200":{"description":"Company search results (single page)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/CompanyProfile"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}}}}},"/v1/companies/{platform}/{identifier}":{"get":{"operationId":"enrichment_company_get","tags":["Enrichment"],"summary":"Get company profile","description":"Retrieve a company profile (org page, not a personal user profile) by identifier on the specified platform. LinkedIn supported today.","parameters":[{"schema":{"type":"string","enum":["x","instagram","tiktok","linkedin","facebook","youtube","reddit"],"description":"Platform (linkedin supported today)"},"required":true,"description":"Platform (linkedin supported today)","name":"platform","in":"path"},{"schema":{"type":"string","description":"Company URL, slug, or numeric identifier"},"required":true,"description":"Company URL, slug, or numeric identifier","name":"identifier","in":"path"}],"responses":{"200":{"description":"Company profile","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CompanyProfile"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"platform":"linkedin","name":"Example Company","publicIdentifier":"example-company","universalName":"example-company","linkedinId":1000001,"urn":"urn:li:fsd_company:1000001","url":"https://www.linkedin.com/company/example-company/","logo":"https://media.example.com/logos/example-company-400x400.png","backgroundImage":"https://media.example.com/covers/example-company-cover.jpg","headline":"Example Company makes commerce better for everyone","followersCount":1092017,"employeeCountRange":{"start":10001,"end":null},"industry":[{"name":"Software Development","urn":"urn:li:fsd_industryV2:4"}]},"meta":{"request_id":"req_example"}}}}}}}}}},"/v1/companies/{platform}/{identifier}/jobs":{"get":{"operationId":"enrichment_company_jobs","tags":["Enrichment"],"summary":"Get company jobs","description":"Retrieve job listings for a company on the specified platform. One request returns one page; follow `meta.next_cursor` in the response to page deeper.","parameters":[{"schema":{"type":"string","enum":["x","instagram","tiktok","linkedin","facebook","youtube","reddit"],"description":"Platform (linkedin supported today)"},"required":true,"description":"Platform (linkedin supported today)","name":"platform","in":"path"},{"schema":{"type":"string","description":"Company URL, slug, or numeric identifier"},"required":true,"description":"Company URL, slug, or numeric identifier","name":"identifier","in":"path"},{"schema":{"type":"string","description":"Pagination cursor for the next page. One request returns one page; pass back the `meta.next_cursor` returned in the response for more."},"required":false,"description":"Pagination cursor for the next page. One request returns one page; pass back the `meta.next_cursor` returned in the response for more.","name":"cursor","in":"query"}],"responses":{"200":{"description":"Company job listings","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LinkedInJobResult"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"company":"Example Company","listing_date":"2026-07-02T17:38:33.000Z","location":"Toronto, ON (On-site)","subtitle":null,"title":"Security Operations Analyst (Toronto)","url":"https://www.linkedin.com/jobs/view/example-security-operations-analyst-4000000001","urn":"urn:li:fs_normalized_jobPosting:4000000001"},{"company":"Example Company","listing_date":"2026-07-02T11:46:59.000Z","location":"NAMER (Remote)","subtitle":null,"title":"Enterprise Account Executive (Americas)","url":"https://www.linkedin.com/jobs/view/example-enterprise-account-executive-4000000002","urn":"urn:li:fs_normalized_jobPosting:4000000002"},{"company":"Example Company","listing_date":"2026-07-02T05:38:31.000Z","location":"NAMER (Remote)","subtitle":null,"title":"Staff Product Data Scientist - Developer Productivity (Americas)","url":"https://www.linkedin.com/jobs/view/example-staff-product-data-scientist-4000000003","urn":"urn:li:fs_normalized_jobPosting:4000000003"}]},"meta":{"request_id":"req_example","next_cursor":"eyJjb3VudCI6MTAwLCJzdGFydCI6MTAwLCJ0b3RhbCI6MTQyLCJwYWdpbmF0aW9uVG9rZW4iOm51bGx9"}}}}}}}}}},"/v1/companies/{platform}/{identifier}/people":{"get":{"operationId":"enrichment_company_people","tags":["Enrichment"],"summary":"Get company people","description":"Retrieve people associated with a company on the specified platform. One request returns one page; follow `meta.next_cursor` in the response to page deeper.","parameters":[{"schema":{"type":"string","enum":["x","instagram","tiktok","linkedin","facebook","youtube","reddit"],"description":"Platform (linkedin supported today)"},"required":true,"description":"Platform (linkedin supported today)","name":"platform","in":"path"},{"schema":{"type":"string","description":"Company URL, slug, or numeric identifier"},"required":true,"description":"Company URL, slug, or numeric identifier","name":"identifier","in":"path"},{"schema":{"type":"string","description":"Pagination cursor for the next page. One request returns one page; pass back the `meta.next_cursor` returned in the response for more."},"required":false,"description":"Pagination cursor for the next page. One request returns one page; pass back the `meta.next_cursor` returned in the response for more.","name":"cursor","in":"query"}],"responses":{"200":{"description":"Company people","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LinkedInCompanyPerson"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"items":[{"name":"Alex Example","position":"Merchant Success Lead at Example Company","location":"Manchester","publicIdentifier":"example-alex-1001","urn":"urn:li:fsd_profile:ACoAAExampleProfile00000000000000000001","url":"https://www.linkedin.com/in/example-alex-1001","image":"https://media.example.com/avatars/example-alex-1001.jpg"},{"name":"Jordan Example","position":"Brand Marketing Associate at Example Company","location":"Leeds","publicIdentifier":"example-jordan-1002","urn":"urn:li:fsd_profile:ACoAAExampleProfile00000000000000000002","url":"https://www.linkedin.com/in/example-jordan-1002","image":"https://media.example.com/avatars/example-jordan-1002.jpg"},{"name":"Sam Example","position":"Student at Example College","location":"Greater London","publicIdentifier":"example-sam-1003","urn":"urn:li:fsd_profile:ACoAAExampleProfile00000000000000000003","url":"https://www.linkedin.com/in/example-sam-1003","image":"https://media.example.com/avatars/example-sam-1003.jpg"}]},"meta":{"request_id":"req_example","next_cursor":"eyJjb3VudCI6MTAsInN0YXJ0IjoxMCwidG90YWwiOjEwMDAsInBhZ2luYXRpb25Ub2tlbiI6bnVsbH0="}}}}}}}}}},"/v1/companies/{platform}/{identifier}/posts":{"get":{"operationId":"enrichment_company_posts","tags":["Enrichment"],"summary":"Get company posts","description":"Retrieve recent posts published by a company on the specified platform. Each item carries a minted `post_id`, matching the profile posts shape. Company posts return a single page in practice; the `cursor` param and `meta.next_cursor` mirror the profile-posts contract for forward compatibility.","parameters":[{"schema":{"type":"string","enum":["x","instagram","tiktok","linkedin","facebook","youtube","reddit"],"description":"Platform (linkedin supported today)"},"required":true,"description":"Platform (linkedin supported today)","name":"platform","in":"path"},{"schema":{"type":"string","description":"Company URL, slug, or numeric identifier"},"required":true,"description":"Company URL, slug, or numeric identifier","name":"identifier","in":"path"},{"schema":{"type":"string","description":"Pagination cursor for the next page. One request returns one page; pass back the `meta.next_cursor` returned in the response for more."},"required":false,"description":"Pagination cursor for the next page. One request returns one page; pass back the `meta.next_cursor` returned in the response for more.","name":"cursor","in":"query"}],"responses":{"200":{"description":"Company posts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NormalizedPost"}}},"required":["items"]},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}}}}},"/v1/brand-search":{"get":{"tags":["Brand Search"],"summary":"Search brand posts","description":"Full-text search across all brand posts. Filter by brand, category, platform, dataset, or date range. Results are ranked by relevance.","parameters":[{"schema":{"type":"string","minLength":1,"description":"Search query (required)","example":"sustainability"},"required":true,"description":"Search query (required)","name":"q","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Filter to a specific brand","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":false,"description":"Filter to a specific brand","name":"brand_id","in":"query"},{"schema":{"type":"string","description":"Filter to brands in a category","example":"retail"},"required":false,"description":"Filter to brands in a category","name":"category_id","in":"query"},{"schema":{"type":"string","description":"Filter by platform (e.g. instagram, tiktok, twitter)","example":"instagram"},"required":false,"description":"Filter by platform (e.g. instagram, tiktok, twitter)","name":"platform","in":"query"},{"schema":{"type":"string","enum":["owned_media","mentions"],"description":"Filter by dataset: owned_media (brand-published) or mentions (earned/mention)"},"required":false,"description":"Filter by dataset: owned_media (brand-published) or mentions (earned/mention)","name":"dataset","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter posts on or after this date (ISO 8601)","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Filter posts on or after this date (ISO 8601)","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter posts on or before this date (ISO 8601)","example":"2026-03-31T23:59:59Z"},"required":false,"description":"Filter posts on or before this date (ISO 8601)","name":"end_date","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"Maximum number of results to return (1–100)","example":25},"required":false,"description":"Maximum number of results to return (1–100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination — pass meta.next_cursor from the previous response"},"required":false,"description":"Cursor for pagination — pass meta.next_cursor from the previous response","name":"cursor","in":"query"}],"responses":{"200":{"description":"Search results ranked by relevance","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SearchResult"}},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":[{"id":"0d1e2f3a-0001-4b2c-8d3e-000000000401","brand_id":null,"brand_name":null,"platform":"reddit","ownership":"mention","text":"Example post: weekly e-commerce news recap. This week: a marketplace tests AI-generated search previews, a storefront platform asks regulators for lighter AI rules, and a big-box retailer adds 30-minute restaurant delivery. What did I miss?","url":"https://www.reddit.com/r/example_ecommerce/comments/example401/weekly_ecommerce_news_recap/","posted_at":"2026-06-08T22:00:42.290Z","fetched_at":"2026-06-09T15:50:54.737Z","source_type":"FORUM","sentiment_polarity":"NEGATIVE","rank":0.092856124},{"id":"0d1e2f3a-0002-4b2c-8d3e-000000000402","brand_id":null,"brand_name":null,"platform":"reddit","ownership":"mention","text":"Example post: weekly e-commerce news recap. This week: a subscription-discount program draws a class action, a parcel carrier signs a multi-year last-mile deal, and a social platform opens its store integration to all advertisers.","url":"https://www.reddit.com/r/example_ecommerce/comments/example402/weekly_ecommerce_news_recap/","posted_at":"2026-06-01T21:53:53.269Z","fetched_at":"2026-06-12T13:47:37.767Z","source_type":"FORUM","sentiment_polarity":"NEUTRAL","rank":0.092856124},{"id":"0d1e2f3a-0003-4b2c-8d3e-000000000403","brand_id":null,"brand_name":null,"platform":"reddit","ownership":"mention","text":"Example post: my store's carrier keeps reusing the same tracking number for two unrelated shipments. Can someone explain how the storefront fetches tracking numbers for labels printed in the admin?","url":"https://www.reddit.com/r/example_storedevs/comments/example403/tracking_number_reused/","posted_at":"2026-06-10T20:23:53.223Z","fetched_at":"2026-06-11T03:42:52.748Z","source_type":"FORUM","sentiment_polarity":"NEGATIVE","rank":0.09066558}],"meta":{"request_id":"req_example","total":208,"total_pages":70,"next_cursor":"ZXhhbXBsZS1jdXJzb3I.ZXhhbXBsZQ"}}}}}}},"400":{"description":"Invalid search query","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/evidence-search":{"get":{"operationId":"evidence_search","tags":["Evidence Search"],"summary":"Search evidence by meaning","description":"Semantic search for evidence across every corpus Waldo has indexed at once — audience posts, brand mentions, owned media and unaffiliated news — ranked by meaning rather than by matching terms. One embedding space spans all of them, so a query finds the same conversation whether it was collected as an audience post or as a mention of a brand; each result reports which corpora it belongs to. Results are APPROXIMATE nearest neighbours, not an exhaustive match set: retrieval is bounded by an ANN scan budget, so a matching post can be missed, and a post with no stored embedding (short text, or collected before embedding was wired) is unfindable here regardless of the query. Top-K only — there is no pagination, and no total is reported. For exhaustive term-based enumeration with a stable cursor, use GET /v1/brand-search instead.","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":500,"description":"What you are looking for, in natural language. Matched by MEANING, not by terms — this is not tsquery syntax, so quoting and boolean operators buy nothing. Use GET /v1/brand-search for term matching.","example":"customers giving up on the battery after a few months"},"required":true,"description":"What you are looking for, in natural language. Matched by MEANING, not by terms — this is not tsquery syntax, so quoting and boolean operators buy nothing. Use GET /v1/brand-search for term matching.","name":"q","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Narrow to posts owned by, or mentioning, this brand.","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":false,"description":"Narrow to posts owned by, or mentioning, this brand.","name":"brand_id","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Narrow to posts collected for this audience.","example":"sneaker-enthusiasts"},"required":false,"description":"Narrow to posts collected for this audience.","name":"audience_id","in":"query"},{"schema":{"type":"string","enum":["mentions","owned_media","audience","unlinked"],"description":"Narrow to one corpus. Omit to search all four at once, which is the point of the endpoint.","example":"mentions"},"required":false,"description":"Narrow to one corpus. Omit to search all four at once, which is the point of the endpoint.","name":"corpus","in":"query"},{"schema":{"type":"string","enum":["SOCIAL","NEWS","FORUM","REVIEW","PODCAST","BLOG"],"description":"Filter by the post's stored source type. **Differs from `/brands/{brand_id}/mentions`**, where `source_type` takes only `SOCIAL` or `NEWS` and each expands to several stored values (`SOCIAL` → SOCIAL+FORUM+REVIEW, `NEWS` → everything else). Here all six stored values are addressable individually, so `NEWS` means exactly NEWS. Note that only `SOCIAL`, `NEWS` and `REVIEW` are written for new posts; `FORUM`, `PODCAST` and `BLOG` match only posts collected before source type was derived from the platform.","example":"SOCIAL"},"required":false,"description":"Filter by the post's stored source type. **Differs from `/brands/{brand_id}/mentions`**, where `source_type` takes only `SOCIAL` or `NEWS` and each expands to several stored values (`SOCIAL` → SOCIAL+FORUM+REVIEW, `NEWS` → everything else). Here all six stored values are addressable individually, so `NEWS` means exactly NEWS. Note that only `SOCIAL`, `NEWS` and `REVIEW` are written for new posts; `FORUM`, `PODCAST` and `BLOG` match only posts collected before source type was derived from the platform.","name":"source_type","in":"query"},{"schema":{"type":"string","description":"Filter by platform (e.g. instagram, twitter, reddit)","example":"reddit"},"required":false,"description":"Filter by platform (e.g. instagram, twitter, reddit)","name":"platform","in":"query"},{"schema":{"type":"string","description":"Filter by region","example":"us"},"required":false,"description":"Filter by region","name":"region","in":"query"},{"schema":{"type":"string","enum":["POSITIVE","NEGATIVE","NEUTRAL","MIXED"],"description":"Filter by analyzer sentiment polarity (matches the `sentiment_polarity` field). Mentions not yet analyzed carry no polarity and are excluded by any value of this filter.","example":"NEGATIVE"},"required":false,"description":"Filter by analyzer sentiment polarity (matches the `sentiment_polarity` field). Mentions not yet analyzed carry no polarity and are excluded by any value of this filter.","name":"sentiment","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter mentions on or after this date (ISO 8601)","example":"2026-03-01T00:00:00Z"},"required":false,"description":"Filter mentions on or after this date (ISO 8601)","name":"start_date","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"Filter mentions on or before this date (ISO 8601)","example":"2026-03-31T23:59:59Z"},"required":false,"description":"Filter mentions on or before this date (ISO 8601)","name":"end_date","in":"query"},{"schema":{"type":["number","null"],"minimum":0,"maximum":1,"description":"Drop results scoring below this cosine similarity. Omit it for no floor, which is the default. Calibrate on your own results rather than on a fixed number: run the query without a floor, look at where the scores fall off, and set it there. Scores are not comparable across different queries — a short query scores lower against everything — so a threshold tuned on one query will not transfer to another. For scale: in our pilot, an audience theme and a brand-mention theme describing the same conversation scored 0.938.","example":0.5},"required":false,"description":"Drop results scoring below this cosine similarity. Omit it for no floor, which is the default. Calibrate on your own results rather than on a fixed number: run the query without a floor, look at where the scores fall off, and set it there. Scores are not comparable across different queries — a short query scores lower against everything — so a threshold tuned on one query will not transfer to another. For scale: in our pilot, an audience theme and a brand-mention theme describing the same conversation scored 0.938.","name":"min_similarity","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Maximum number of results to return (1–100). This endpoint is top-K only — there is no cursor and no further page.","example":20},"required":false,"description":"Maximum number of results to return (1–100). This endpoint is top-K only — there is no cursor and no further page.","name":"limit","in":"query"}],"responses":{"200":{"description":"Nearest evidence, most similar first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EvidenceResult"}},"meta":{"$ref":"#/components/schemas/EvidenceSearchMeta"}},"required":["data","meta"]}}}},"400":{"description":"Invalid query or parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Brand or audience not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/brands/{brand_id}/creative-patterns":{"get":{"operationId":"brand_creative_patterns","tags":["Brands"],"summary":"Creative hook and angle patterns","description":"The creative hook and angle frames a brand is running, as a leaderboard: each frame with how many distinct creatives carry it, the analyzer labels behind it, and example ads.","parameters":[{"schema":{"type":"string","format":"uuid","description":"Brand ID to analyze","example":"b1a2c3d4-e5f6-7890-abcd-ef1234567890"},"required":true,"description":"Brand ID to analyze","name":"brand_id","in":"path"},{"schema":{"type":"string","enum":["7d","30d","90d"],"default":"30d","description":"Time window for analysis. Defaults to 30d.","example":"30d"},"required":false,"description":"Time window for analysis. Defaults to 30d.","name":"window","in":"query"}],"responses":{"200":{"description":"Hook and angle frames the brand is running","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CreativePatterns"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/account":{"get":{"tags":["Account"],"summary":"Get account","description":"Returns account profile information for the authenticated team, including entity counts (brands, categories, audiences).","responses":{"200":{"description":"Account profile","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AccountProfile"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"account_id":"1000","email":null,"entities":{"brands":18,"categories":129,"audiences":150},"requests_this_month":0},"meta":{"request_id":"req_example"}}}}}}}}}},"/v1/account/balance":{"get":{"tags":["Account"],"summary":"Get credit balance","description":"Returns the team's credit balance for the current billing period: remaining balance, used, limit, plan, and period bounds.","responses":{"200":{"description":"Credit balance","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AccountBalance"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"balance":10000,"used":0,"limit":0,"plan":null,"status":null,"period":{"start":null,"end":null,"days_remaining":null}},"meta":{"request_id":"req_example"}}}}}}}}}},"/v1/account/usage":{"get":{"tags":["Account"],"summary":"Get usage","description":"Returns API usage breakdown for the current billing period. V1 returns placeholder data; metering will be available in a future version.","responses":{"200":{"description":"Usage breakdown","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AccountUsage"},"meta":{"$ref":"#/components/schemas/Meta"}},"required":["data","meta"]},"examples":{"sample":{"summary":"Sample response","value":{"data":{"period":{"start":"2026-06-01","end":"2026-06-30"},"total_calls":0,"by_domain":[]},"meta":{"request_id":"req_example"}}}}}}}}}}},"webhooks":{},"x-tagGroups":[{"name":"Brand","tags":["Brands","Platforms","Owned Media","Executives","Executive Media","Paid Media","Mentions","Competitive"]},{"name":"Brand (Beta)","tags":["Brand Overview","Competitive Analysis"]},{"name":"Categories","tags":["Categories"]},{"name":"Topics","tags":["Topics"]},{"name":"Trends","tags":["Trends"]},{"name":"Audiences","tags":["Audiences"]},{"name":"Search","tags":["Brand Search","Evidence Search"]},{"name":"Discover","tags":["Discover"]},{"name":"Enrichment","tags":["Enrichment"]},{"name":"Account & Access","tags":["Account","API Keys"]}]}