{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://spec.openapis.org/oas/3.1/dialect/base",
  "info": {
    "title": "Analyst Consensus API — CryptoQuant",
    "version": "2.2.0",
    "summary": "What curated analysts say about crypto, stocks, indices and commodities, as numbers.",
    "description": "What curated analysts on X, CryptoQuant, Seeking Alpha, TradingView and Substack (plus licensed sell-side ratings on equities) say about 1712 assets — crypto, US and KR equities, index ETFs, commodities — as numbers: the daily Analyst Consensus Index (−100 … +100, one series per asset), a per-asset consensus breakdown (bull / bear case, viewpoints grouped by thesis, source posts), per-analyst stance series, and each analyst's accuracy track record.\n\n**Two access levels.** Public, no key (per-IP rate limit, CDN-cached): `GET /assets` (the asset registry + every enum), `GET /consensus` without a key (the LATEST index point for any asset with the bull / bear case), `GET /analyst-views`, `GET /calls`, `GET /analysts/top`, `GET /analysts/{handle}`. Every public payload carries `page_url` (link it), `cite_as` and `data_by` (\"Data by CryptoQuant Consensus\" — show it with the numbers). With an API key (`X-API-Key` header or `api_key` query parameter): the index HISTORY (`GET /consensus` with `days`) and `GET /consensus/breakdown` on any plan; the per-analyst series `GET /sentiment` on the Premium and Enterprise plans only (`PLAN_REQUIRED` below). Keys are provisioned with the CryptoQuant Premium plan or an Enterprise agreement; there is no self-serve key endpoint on this host. **Raw source text** (the original post title / text) is provided under an Integration agreement only, per API key (`api_keys.raw_access`, never a plan): `GET /consensus/breakdown` sends `sources[].statement` on a cleared key and a ≤ 200-character `sources[].excerpt` + url on every other key — Premium, Enterprise and admin-owned keys included; the key-free `/analyst-views` and `/calls` excerpts follow the same rule. Integration use that needs the original text: contact sales@cryptoquant.com (`x-raw-source-text`). Thesis, narratives, index and labels are the same on every plan.\n\n**Conventions.** Dates: `date` = UTC calendar day `YYYY-MM-DD`; `date-time` = RFC 3339 / ISO 8601 with offset, UTC. Index and stance series are end-of-day: the current UTC day is excluded until complete, so values never change retroactively. No pagination anywhere: a series comes back whole (`days` is capped by the plan, 36,500 = everything; the full BTC history is ≈ 1,950 rows); lists are capped by `limit` (1–50). Sorting is fixed per endpoint and stated in its description. Filters combine with AND. Every error is the `Error` object: branch on `code`, read `message`, follow `docs_url`; `x-errors` lists every code with its recovery. Every operation carries `x-plan` (who may call it).\n\n**Agents.** Import this document as a ChatGPT GPT Action (Authentication: None for the public operations) or any OpenAPI tool loader; the Markdown version of these docs is `/llms.txt`; the same data is an MCP server at `/mcp` (Streamable HTTP, no auth). Pass `via=chatgpt|claude|…` so the links you show carry the right `utm_source`.\n\n**Freshness.** Index and stance series: end-of-day UTC. The breakdown is recomputed daily (English by 04:00 UTC, translations by 06:00 UTC); its opinion counts refresh every 4 hours. Public payloads are CDN-cached 5 minutes (track record and assets: 1 hour).\n\nHuman docs: https://docs.cryptoquant.com/sentiment/overview · how the numbers are made: https://consensus.cryptoquant.com/methodology · Markdown for agents: https://consensus.cryptoquant.com/llms.txt",
    "contact": {
      "name": "CryptoQuant — API access and Enterprise data",
      "url": "https://cryptoquant.com/get-in-touch",
      "email": "support@cryptoquant.com"
    },
    "termsOfService": "https://consensus.cryptoquant.com/terms",
    "license": {
      "name": "Proprietary — CryptoQuant Terms of Service",
      "url": "https://consensus.cryptoquant.com/terms"
    }
  },
  "externalDocs": {
    "description": "API documentation (human) — the Sentiment Data tab of the CryptoQuant API docs, rendered from this file",
    "url": "https://docs.cryptoquant.com/sentiment/overview"
  },
  "servers": [
    {
      "url": "https://consensus.cryptoquant.com/api/v1",
      "description": "Analyst Consensus by CryptoQuant"
    }
  ],
  "security": [
    {
      "ApiKeyHeader": []
    },
    {
      "ApiKeyQuery": []
    }
  ],
  "tags": [
    {
      "name": "Registry",
      "description": "Public, no API key. The assets the API covers and every enum it uses."
    },
    {
      "name": "Consensus",
      "description": "The Analyst Consensus Index: latest point public (no key); history and the per-asset breakdown with an API key."
    },
    {
      "name": "Analyst views",
      "description": "Public, no API key. What analysts are saying: narratives, per-analyst views, the newest calls."
    },
    {
      "name": "Analyst track record",
      "description": "Public, no API key. Who to trust: accuracy scores, ranks and badges per analyst."
    },
    {
      "name": "Analyst stance",
      "description": "Premium / Enterprise API key. One analyst's daily stance on an asset."
    }
  ],
  "x-plans": {
    "description": "API-key plans (subscription_plans). An API key carries its own plan; the site session plan is separate. `pro` is the pre-2026-10 Enterprise row and behaves as `enterprise`. raw_source_text is NOT a plan right: every plan row receives the excerpt (excerpt only: the first ≤ 200 characters of the original post (sentence / word boundary, original language) + the source url); only a key cleared under an Integration agreement (per-key raw_access — see x-raw-source-text) receives the original statement (original statement (full post title / text) — Integration agreement keys only (per-key raw_access clearance, not a plan); contact sales@cryptoquant.com).",
    "plans": {
      "none": {
        "label": "No key",
        "endpoints": [
          "/assets",
          "/consensus (latest point)",
          "/analyst-views",
          "/calls",
          "/analysts/top",
          "/analysts/{handle}"
        ],
        "rate_limit_per_minute": 60,
        "daily_request_limit": null,
        "history": "latest point only",
        "raw_source_text": "excerpt"
      },
      "free": {
        "label": "Free",
        "endpoints": [
          "everything public",
          "/consensus (latest point only, flat object)",
          "/consensus/breakdown (sources as excerpts)"
        ],
        "rate_limit_per_minute": 10,
        "daily_request_limit": 100,
        "max_days_history": 7,
        "history": "latest point only; /sentiment → 401 PLAN_REQUIRED",
        "raw_source_text": "excerpt"
      },
      "premium": {
        "label": "Premium",
        "endpoints": [
          "everything (breakdown sources as excerpts unless the key holds Integration raw access)"
        ],
        "rate_limit_per_minute": 1000,
        "daily_request_limit": null,
        "max_days_history": 36500,
        "history": "full",
        "raw_source_text": "excerpt",
        "how_to_get": "https://cryptoquant.com/pricing"
      },
      "enterprise": {
        "label": "Enterprise",
        "endpoints": [
          "everything (breakdown sources as excerpts unless the key holds Integration raw access)"
        ],
        "rate_limit_per_minute": 1000,
        "daily_request_limit": null,
        "max_days_history": 36500,
        "history": "full",
        "raw_source_text": "excerpt",
        "how_to_get": "https://cryptoquant.com/get-in-touch"
      },
      "pro": {
        "label": "Enterprise (legacy row)",
        "same_as": "enterprise",
        "raw_source_text": "excerpt"
      }
    },
    "raw_source_text": {
      "statement": "original statement (full post title / text) — Integration agreement keys only (per-key raw_access clearance, not a plan); contact sales@cryptoquant.com",
      "excerpt": "excerpt only: the first ≤ 200 characters of the original post (sentence / word boundary, original language) + the source url",
      "field": "BreakdownResponse.source_text names the shape a response carries; /analyst-views and /calls are always excerpts",
      "integration_key": "statement"
    },
    "plan_ids": [
      "free",
      "pro",
      "premium",
      "enterprise"
    ]
  },
  "x-raw-source-text": {
    "field": "GET /consensus/breakdown → sources[].statement (BreakdownSource); every other surface carries sources[].excerpt / excerpt",
    "access": "Integration agreement only — granted per API key (api_keys.raw_access = true), never by plan: a Premium, Enterprise or admin-owned key without the clearance receives the excerpt + source url",
    "how_to_get": "Integration use that needs the original source text: contact sales@cryptoquant.com",
    "contact_email": "sales@cryptoquant.com",
    "contact_url": "https://cryptoquant.com/get-in-touch",
    "request": "source_text=statement on /consensus/breakdown asks for it explicitly; without the clearance the answer is 403 RAW_ACCESS_REQUIRED (contact_email, docs_url) — the default (no parameter) is what the key may receive",
    "excerpt_rule": "excerpt only: the first ≤ 200 characters of the original post (sentence / word boundary, original language) + the source url",
    "docs_url": "https://docs.cryptoquant.com/sentiment/plans-and-access#raw-source-text"
  },
  "x-errors": {
    "API_KEY_REQUIRED": {
      "status": 401,
      "recovery": "Send the key in the X-API-Key header (or the api_key query parameter). The key-free endpoints (/assets, /analysts/*, /analyst-views, /calls, /consensus without days) need none."
    },
    "INVALID_API_KEY": {
      "status": 401,
      "recovery": "The key is unknown, inactive, expired, or its subscription is not active. Do not retry with the same key; obtain a valid one."
    },
    "PLAN_REQUIRED": {
      "status": 401,
      "recovery": "The key's plan cannot read this endpoint. required_plans names the plans that can: upgrade at upgrade_url or contact sales at contact_url. Do not retry on the same plan."
    },
    "RAW_ACCESS_REQUIRED": {
      "status": 403,
      "recovery": "The original source statement (full post text) is provided under an Integration agreement only, per key (not a plan: premium, enterprise and admin-owned keys without it get the excerpt). Drop source_text=statement to receive the ≤ 200-character excerpt + source link, or contact sales@cryptoquant.com (contact_email) for Integration raw-text access. Do not retry unchanged."
    },
    "DAILY_LIMIT_EXCEEDED": {
      "status": 429,
      "recovery": "Free plan daily quota used (limit / used). It resets at 00:00 UTC; wait, or upgrade."
    },
    "RATE_LIMIT_EXCEEDED": {
      "status": 429,
      "recovery": "Per-minute (keyed: your plan's rate_limit_per_minute; key-free: per-IP) limit hit. Wait retry_after seconds (header Retry-After), then retry; spread calls over the minute."
    },
    "INVALID_PARAMETER": {
      "status": 400,
      "recovery": "A query parameter is malformed or outside its accepted values: param names it and message lists what is accepted. Fix the request; never retry it unchanged."
    },
    "UNKNOWN_ASSET": {
      "status": 400,
      "recovery": "The asset is not registered. Resolve the name or ticker through GET /api/v1/assets (symbol, key, name, aliases) and retry with that symbol."
    },
    "ANALYST_NOT_FOUND": {
      "status": 404,
      "recovery": "No tracked analyst matches. Pick a handle from GET /api/v1/analysts/top?asset=<symbol> (field handle) and retry."
    },
    "ANALYST_NOT_ELIGIBLE": {
      "status": 404,
      "recovery": "The analyst exists but is excluded from the stance pipeline (feed, company account, stakeholder). Not retryable."
    },
    "NO_DATA": {
      "status": 404,
      "recovery": "No rows for that analyst × asset pair in the queried range. Not retryable; try another asset the analyst covers (covered_assets on /analysts/{handle})."
    },
    "SERVICE_UNAVAILABLE": {
      "status": 503,
      "recovery": "An upstream list was unavailable. Retry after a few seconds with the same request."
    },
    "INTERNAL_ERROR": {
      "status": 500,
      "recovery": "Our fault. Retry once after a few seconds; if it persists, report the full URL to support."
    }
  },
  "x-conventions": {
    "dates": "`date` = UTC calendar day YYYY-MM-DD (format: date). `date-time` = RFC 3339 / ISO 8601 with an explicit offset (`Z` or `+00:00`), always UTC. The current UTC day is never in a series.",
    "pagination": "None. Series return the whole requested range in one response (`days`, capped by the plan). Lists are capped by `limit` (1–50, clamped silently). There is no cursor, offset or page parameter.",
    "filters": "Query filters combine with AND. Unknown parameters are ignored. Enum parameters outside their values → 400 INVALID_PARAMETER with the accepted list in `message`.",
    "sorting": "Fixed per endpoint: series oldest first by date; /calls newest first; /analysts/top by accuracy_score desc (ties: sample size, then handle); /assets in registry order.",
    "enums": "Every enum is closed and listed in full in this document; `GET /assets` returns them at runtime under `enums`.",
    "caching": "Public payloads: CDN 5 min (`as_of` = generation time); track record and assets: CDN 1 h. Keyed responses are never cached."
  },
  "x-mcp": {
    "url": "https://consensus.cryptoquant.com/mcp",
    "transport": "streamable-http",
    "auth": "none",
    "tools": [
      "get_consensus",
      "get_analyst_views",
      "get_top_analysts",
      "get_analyst_profile",
      "get_recent_calls"
    ]
  },
  "x-alternatives": {
    "cryptoquant_alpha_api": {
      "description": "CryptoQuant Premium keys can also read the Analyst Consensus Index (BTC, ETH, SOL; from/to/limit/order; Bearer auth) from the CryptoQuant Alpha Indicator API — same daily index, no breakdown / stance / track record.",
      "url": "https://alpha.cryptoquant.com/api/consensus/{asset}",
      "docs": "https://docs.cryptoquant.com/indicator-api/consensus"
    },
    "llms_txt": "https://consensus.cryptoquant.com/llms.txt",
    "openapi_yaml": "https://consensus.cryptoquant.com/openapi.yaml"
  },
  "paths": {
    "/assets": {
      "get": {
        "operationId": "listAssets",
        "tags": [
          "Registry"
        ],
        "summary": "Every covered asset + every enum (public, no API key)",
        "description": "The registry every `asset` parameter is resolved against — 1712 canonical assets (one underlying = one asset) plus their alias tickers, each with symbol, route key, name, class, category, market, coverage state and page URL — and the closed enums the other endpoints use (`enums`). Registry order (class, then symbol). Optional AND-filters: `asset_class`, `category`, `q` (substring of symbol / name / key). Public; CDN-cached one hour (`Cache-Control: public, s-maxage=3600, stale-while-revalidate=86400`); no DB read.",
        "security": [],
        "x-plan": {
          "access": "public",
          "api_key": "not required",
          "plans": [
            "none",
            "free",
            "premium",
            "enterprise"
          ],
          "rate_limit": "none (CDN-cached)",
          "daily_limit": "none",
          "cache": "CDN 1 h"
        },
        "parameters": [
          {
            "name": "asset_class",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "crypto",
                "equities",
                "indices",
                "commodities"
              ]
            },
            "description": "Keep only this asset class."
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "crypto",
                "us-equities",
                "indices",
                "commodities",
                "kr-equities"
              ]
            },
            "description": "Keep only this selector category (equities split into US / KR)."
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Case-insensitive substring of symbol, name or route key.",
            "example": "gold"
          }
        ],
        "responses": {
          "200": {
            "description": "The asset registry and the enums",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssetsResponse"
                },
                "example": {
                  "count": 2,
                  "rows": 3,
                  "filter": {
                    "asset_class": null,
                    "category": null,
                    "q": null
                  },
                  "asset_classes": {
                    "crypto": "Crypto",
                    "equities": "Equities",
                    "indices": "Indices & ETFs",
                    "commodities": "Commodities"
                  },
                  "categories": {
                    "crypto": "Crypto",
                    "us-equities": "US Equities",
                    "indices": "Indices & ETFs",
                    "commodities": "Commodities",
                    "kr-equities": "KR Equities"
                  },
                  "how_to_resolve": "Pass any of symbol, key, name, an alias or a retired symbol as `asset` on the other endpoints (case-insensitive); the response always reports the canonical symbol. coverage=pending assets have a page but no analyst data yet.",
                  "assets": [
                    {
                      "symbol": "BTC",
                      "name": "Bitcoin",
                      "key": "btc",
                      "asset_class": "crypto",
                      "category": "crypto",
                      "market": "Bitfinex",
                      "currency": "USD",
                      "source": "alpha",
                      "coverage": "live",
                      "canonical": null,
                      "aliases": [],
                      "retired_symbols": [],
                      "page_url": "https://consensus.cryptoquant.com/consensus/btc",
                      "identity": {
                        "asset_class": "crypto",
                        "uid": "bitcoin",
                        "chain_contract": null,
                        "exchange_mic": null,
                        "needs_review": false
                      }
                    },
                    {
                      "symbol": "GLD",
                      "name": "Gold",
                      "key": "gld",
                      "asset_class": "commodities",
                      "category": "commodities",
                      "market": "Commodity",
                      "currency": "USD",
                      "source": "alpha",
                      "coverage": "mapped",
                      "canonical": "XAU",
                      "aliases": [],
                      "retired_symbols": [],
                      "page_url": "https://consensus.cryptoquant.com/consensus/gld",
                      "identity": {
                        "asset_class": "etf",
                        "uid": "US78463V1070",
                        "chain_contract": null,
                        "exchange_mic": "XNYS",
                        "needs_review": false
                      }
                    },
                    {
                      "symbol": "005930",
                      "name": "Samsung Electronics",
                      "key": "005930",
                      "asset_class": "equities",
                      "category": "kr-equities",
                      "market": "KRX",
                      "currency": "KRW",
                      "source": "alpha",
                      "coverage": "mapped",
                      "canonical": null,
                      "aliases": [],
                      "retired_symbols": [],
                      "page_url": "https://consensus.cryptoquant.com/consensus/005930",
                      "identity": {
                        "asset_class": "equity",
                        "uid": "KR7005930003",
                        "chain_contract": null,
                        "exchange_mic": "XKRX",
                        "needs_review": false
                      }
                    }
                  ],
                  "enums": {
                    "asset_class": [
                      "crypto",
                      "equities",
                      "indices",
                      "commodities"
                    ],
                    "asset_category": [
                      "crypto",
                      "us-equities",
                      "indices",
                      "commodities",
                      "kr-equities"
                    ],
                    "asset_source": [
                      "alpha",
                      "sellside",
                      "unbias",
                      "legacy"
                    ],
                    "source_platform": [
                      "x",
                      "cryptoquant",
                      "seekingalpha",
                      "tradingview",
                      "substack",
                      "benzinga"
                    ],
                    "analyst_source": [
                      "twitter",
                      "cryptoquant",
                      "seekingalpha",
                      "tradingview",
                      "substack",
                      "other"
                    ],
                    "source_type": [
                      "tweet",
                      "quicktake",
                      "research",
                      "news",
                      "seekingalpha",
                      "tradingview",
                      "substack",
                      "youtube",
                      "telegram",
                      "bluesky"
                    ],
                    "sentiment_label": [
                      "bullish",
                      "bullish_nuance",
                      "neutral",
                      "bearish_nuance",
                      "bearish"
                    ],
                    "directional_label": [
                      "bullish",
                      "bullish_nuance",
                      "bearish_nuance",
                      "bearish"
                    ],
                    "stance": [
                      "bullish",
                      "bearish",
                      "neutral"
                    ],
                    "bias": [
                      "bullish",
                      "bearish",
                      "balanced"
                    ],
                    "tier_badge": [
                      "top1",
                      "top5",
                      "top10",
                      "tracked"
                    ],
                    "tier_reason": [
                      "excluded",
                      "ineligible",
                      "news_feed",
                      "company",
                      "unscored",
                      "insufficient_calls",
                      "pool_too_small"
                    ],
                    "breakdown_window": [
                      "1d",
                      "3d",
                      "7d",
                      "30d"
                    ],
                    "views_window": [
                      "7d",
                      "30d"
                    ],
                    "breakdown_lang": [
                      "en",
                      "ko",
                      "zh",
                      "ja",
                      "es",
                      "pt",
                      "ru",
                      "hi",
                      "de",
                      "fr",
                      "tr",
                      "vi",
                      "id",
                      "it",
                      "th",
                      "pl",
                      "nl",
                      "uk"
                    ],
                    "via": [
                      "chatgpt",
                      "claude",
                      "mcp",
                      "gemini",
                      "perplexity",
                      "api"
                    ],
                    "plan": [
                      "free",
                      "pro",
                      "premium",
                      "enterprise"
                    ]
                  },
                  "docs_url": "https://docs.cryptoquant.com/sentiment/assets",
                  "as_of": "2026-10-06T07:48:29.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`INVALID_PARAMETER` — asset_class / category outside their enum",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Invalid window",
                  "code": "INVALID_PARAMETER",
                  "message": "window must be one of: 1d, 3d, 7d, 30d",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                  "param": "window"
                }
              }
            }
          }
        }
      }
    },
    "/consensus": {
      "get": {
        "operationId": "getConsensusIndex",
        "tags": [
          "Consensus"
        ],
        "summary": "Analyst Consensus Index — latest point (public) or daily series (API key)",
        "description": "WITHOUT a key (the agent path): the latest end-of-day Analyst Consensus Index point for ANY registered asset — `consensus_index` (−100 all bearish … +100 all bullish), `consensus_index_30d_ma`, the bullish / bearish share, `total_analysts`, the one-line `bull_case` / `bear_case`, plus `page_url` / `cite_as` / `data_by` (`ConsensusPublic`, `plan:\"public\"`). Public, no API key. Per-IP limit 60 requests / minute (per function instance); CDN-cached 5 minutes (`Cache-Control: public, s-maxage=300, stale-while-revalidate=3600`). Use this for \"what do analysts think about X / is the market bullish on X\".\n\nWITH a key: the daily series for ANY registered asset (one series per asset the index publisher writes — crypto since 2021-06-01, equities / indices / commodities from their first coverage day; an asset without rows answers an empty series, `count: 0`) with the 30-day MA, a 90-day z-score, analyst and opinion counts, oldest first. Premium / Enterprise keys get `days` of history ending yesterday UTC (capped at the plan's max_days_history, 36,500 = everything); the FREE plan gets ONLY the latest point as a flat object with `plan:\"free\"` (`days` ignored). No pagination: the whole range is one response.",
        "security": [
          {},
          {
            "ApiKeyHeader": []
          },
          {
            "ApiKeyQuery": []
          }
        ],
        "x-plan": {
          "access": "public_or_api_key",
          "api_key": "optional: none = latest point, key = history",
          "plans": [
            "none",
            "free",
            "premium",
            "enterprise"
          ],
          "rate_limit": "free 10 / min, premium + enterprise 1000 / min",
          "daily_limit": "free 100 / UTC day, paid none",
          "cache": "none"
        },
        "parameters": [
          {
            "name": "asset",
            "in": "query",
            "required": false,
            "description": "Any registered asset, case-insensitive: the symbol (`BTC`, `NVDA`, `005930`, `XAU`), the route key (`bitcoin`, `samsung-electronics`), the display name (`Bitcoin`), an alias ticker (`GLD` → XAU) or a retired ticker (`MATIC` → POL). The response reports the canonical symbol. The full list: `GET /assets`. A market aggregate (`crypto-market`) is not accepted. Unknown → 400 `UNKNOWN_ASSET`.",
            "schema": {
              "type": "string",
              "default": "BTC"
            },
            "example": "NVDA"
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "Keyed only — days of history ending yesterday UTC. Positive integer (anything else → 400 INVALID_PARAMETER); silently capped at the plan's max_days_history (free 7, premium / enterprise 36500). Ignored without a key and on the free plan's single point.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 36500,
              "default": 7
            },
            "example": 365
          },
          {
            "name": "granularity",
            "in": "query",
            "required": false,
            "description": "Keyed only — `daily` is the only value (there is no hourly series); anything else → 400 INVALID_PARAMETER.",
            "schema": {
              "type": "string",
              "enum": [
                "daily"
              ],
              "default": "daily"
            }
          },
          {
            "name": "via",
            "in": "query",
            "required": false,
            "description": "The surface the agent runs on; sets `utm_source` on every link in the payload. Unknown values fall back to the default.",
            "schema": {
              "type": "string",
              "enum": [
                "chatgpt",
                "claude",
                "mcp",
                "gemini",
                "perplexity",
                "api"
              ],
              "default": "chatgpt"
            },
            "example": "claude"
          }
        ],
        "responses": {
          "200": {
            "description": "Latest point (no key: ConsensusPublic), series (premium / enterprise: ConsensusSeries) or latest point (free: ConsensusLatest). The three shapes are told apart by `plan` (public / absent / free).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests allowed per minute on your plan.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Daily-Limit": {
                "description": "Free plan only: requests allowed per UTC day.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Daily-Used": {
                "description": "Free plan only: requests used today, including this one.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ConsensusPublic"
                    },
                    {
                      "$ref": "#/components/schemas/ConsensusSeries"
                    },
                    {
                      "$ref": "#/components/schemas/ConsensusLatest"
                    }
                  ]
                },
                "examples": {
                  "public_no_key": {
                    "summary": "No key — latest point for NVDA",
                    "value": {
                      "asset": "NVDA",
                      "asset_name": "NVIDIA",
                      "asset_class": "equities",
                      "date": "2026-10-05",
                      "consensus_index": 71.28,
                      "consensus_index_30d_ma": 75.85,
                      "bullish_percent": 86,
                      "bearish_percent": 14,
                      "total_analysts": 62,
                      "bull_case": "Early AI buildout plus cheap valuation fuels growth",
                      "bear_case": "Limited upside ahead; take profits and rotate",
                      "window": "30d",
                      "plan": "public",
                      "history": "The daily index history needs an API key (X-API-Key) — https://docs.cryptoquant.com/sentiment/overview",
                      "page_url": "https://consensus.cryptoquant.com/consensus/nvda?utm_source=api&utm_medium=gpt-action&utm_campaign=consensus",
                      "top_analysts_url": "https://consensus.cryptoquant.com/analysts?asset=nvda&sort=accuracy&utm_source=api&utm_medium=gpt-action&utm_campaign=consensus",
                      "methodology_url": "https://consensus.cryptoquant.com/methodology?utm_source=api&utm_medium=gpt-action&utm_campaign=consensus",
                      "cite_as": "Data by CryptoQuant Consensus — https://consensus.cryptoquant.com/consensus/nvda",
                      "data_by": "Data by CryptoQuant Consensus",
                      "as_of": "2026-10-06T07:48:24.833Z"
                    }
                  },
                  "series_paid_key": {
                    "summary": "Premium / Enterprise key — daily series",
                    "value": {
                      "asset": "BTC",
                      "period": {
                        "start": "2026-10-04",
                        "end": "2026-10-05"
                      },
                      "granularity": "daily",
                      "count": 2,
                      "data": [
                        {
                          "date": "2026-10-04",
                          "consensus_index": 48.73,
                          "consensus_index_30d_ma": 40.2,
                          "z_score": 1.09,
                          "avg_sentiment_score": 71.93,
                          "bullish_analysts": 122,
                          "bearish_analysts": 38,
                          "total_analysts": 160,
                          "bullish_opinions": 20,
                          "bearish_opinions": 7,
                          "total_opinions": 27
                        },
                        {
                          "date": "2026-10-05",
                          "consensus_index": 49.54,
                          "consensus_index_30d_ma": 40.37,
                          "z_score": 1.12,
                          "avg_sentiment_score": 72.22,
                          "bullish_analysts": 125,
                          "bearish_analysts": 35,
                          "total_analysts": 160,
                          "bullish_opinions": 26,
                          "bearish_opinions": 3,
                          "total_opinions": 29
                        }
                      ]
                    }
                  },
                  "latest_free_key": {
                    "summary": "Free key — latest point only",
                    "value": {
                      "asset": "BTC",
                      "date": "2026-10-05",
                      "consensus_index": 49.54,
                      "consensus_index_30d_ma": 40.37,
                      "z_score": 1.12,
                      "avg_sentiment_score": 72.22,
                      "bullish_analysts": 125,
                      "bearish_analysts": 35,
                      "total_analysts": 160,
                      "bullish_opinions": 26,
                      "bearish_opinions": 3,
                      "total_opinions": 29,
                      "plan": "free",
                      "upgrade_message": "Contact us for Enterprise access to full historical data"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`UNKNOWN_ASSET` (asset not registered / an aggregate) or `INVALID_PARAMETER` (days, granularity)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Unknown asset",
                  "code": "UNKNOWN_ASSET",
                  "message": "\"DOGE2\" is not a registered asset. Use a ticker, route key or name from https://consensus.cryptoquant.com/api/v1/assets (symbol / key / name / aliases, case-insensitive). Market aggregates are not assets.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                  "param": "asset"
                }
              }
            }
          },
          "401": {
            "description": "Keyed path only: `INVALID_API_KEY`. A request WITHOUT a key is never 401 — it gets the public snapshot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missing": {
                    "value": {
                      "error": "API key required",
                      "code": "API_KEY_REQUIRED",
                      "message": "Use the X-API-Key header or the api_key query parameter. Keys start with \"unbias_live_\".",
                      "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                      "docs": "https://docs.cryptoquant.com/sentiment/overview"
                    }
                  },
                  "invalid": {
                    "value": {
                      "error": "Invalid API key",
                      "code": "INVALID_API_KEY",
                      "message": "The key is unknown, inactive or expired, or its subscription is not active.",
                      "docs_url": "https://docs.cryptoquant.com/sentiment/errors"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Free plan only: `NO_DATA` when the last 90 days hold no rows",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "No data available",
                  "code": "NO_DATA",
                  "message": "No index rows for this asset in the last 90 days.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors"
                }
              }
            }
          },
          "429": {
            "description": "No key: per-IP limit (`RATE_LIMIT_EXCEEDED`, `Retry-After`). Key: per-minute limit, or on the free plan the daily limit (`DAILY_LIMIT_EXCEEDED`).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait (per-minute limit only).",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Daily limit only: the literal `midnight UTC`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "per_minute": {
                    "value": {
                      "error": "Rate limit exceeded",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Public endpoint: per-IP limit reached. Wait 37 s (Retry-After), or use an API key for higher limits.",
                      "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                      "retry_after": 37
                    }
                  },
                  "daily": {
                    "value": {
                      "error": "Daily API limit exceeded",
                      "code": "DAILY_LIMIT_EXCEEDED",
                      "message": "Free plan: the daily request quota is used up. It resets at 00:00 UTC; the Premium and Enterprise plans have no daily cap.",
                      "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                      "limit": 100,
                      "used": 100,
                      "reset": "Daily at midnight UTC",
                      "upgrade_url": "https://cryptoquant.com/pricing",
                      "contact_url": "https://cryptoquant.com/get-in-touch"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`INTERNAL_ERROR` — retry once after a few seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Internal server error",
                  "code": "INTERNAL_ERROR",
                  "message": "Something went wrong on our side. Retry once after a few seconds; if it persists, report the URL to support.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors"
                }
              }
            }
          }
        }
      }
    },
    "/consensus/breakdown": {
      "get": {
        "operationId": "getConsensusBreakdown",
        "tags": [
          "Consensus"
        ],
        "summary": "Per-asset consensus breakdown — snapshot (API key, any plan; the original source text only on a key with Integration raw access)",
        "description": "One point-in-time snapshot of an asset's analyst consensus for a window: directional opinion counts and shares, the latest daily index + z-score (null for an asset without an index series), the bull-case / bear-case sentences, the viewpoints grouped by thesis with their analysts and source posts. `lang` localises the generated text (titles, cases); source posts stay in their original language. Recomputed daily; opinion counts every 4 hours. Any plan, including free (counts against the free daily limit). **Source text per key** (`source_text` + `note` in the response): a key cleared under an Integration agreement (per-key raw_access, not a plan) gets `sources[].statement` = the original post title / text; every other key — Free, Premium, Enterprise, admin-owned — gets `sources[].excerpt` = the first ≤ 200 characters + `url` instead. `source_text=statement` asks for the original explicitly and is refused with 403 `RAW_ACCESS_REQUIRED` on a key without the clearance (Integration use: contact sales@cryptoquant.com). Viewpoint `title` / `thesis`, the bull / bear case, the index and the labels are identical on every plan.",
        "x-plan": {
          "access": "api_key",
          "api_key": "required",
          "plans": [
            "free",
            "premium",
            "enterprise"
          ],
          "rate_limit": "free 10 / min, premium + enterprise 1000 / min",
          "daily_limit": "free 100 / UTC day, paid none",
          "cache": "none",
          "raw_source_text": {
            "free": "excerpt",
            "premium": "excerpt",
            "enterprise": "excerpt",
            "pro": "excerpt",
            "admin": "excerpt",
            "integration_key": "statement"
          },
          "raw_source_text_rule": {
            "statement": "original statement (full post title / text) — Integration agreement keys only (per-key raw_access clearance, not a plan); contact sales@cryptoquant.com",
            "excerpt": "excerpt only: the first ≤ 200 characters of the original post (sentence / word boundary, original language) + the source url"
          },
          "raw_source_text_contact": "sales@cryptoquant.com"
        },
        "parameters": [
          {
            "name": "asset",
            "in": "query",
            "required": false,
            "description": "Asset SYMBOL, upper-cased by the server (`btc` → `BTC`); NOT resolved through the registry — route keys / names are not accepted here, and an unknown symbol comes back as an empty breakdown (no viewpoints, null index), not a 400. Use the `symbol` from `GET /assets`.",
            "schema": {
              "type": "string",
              "default": "BTC"
            },
            "example": "BTC"
          },
          {
            "name": "window",
            "in": "query",
            "required": false,
            "description": "Window of the opinion counts and viewpoints.",
            "schema": {
              "type": "string",
              "enum": [
                "1d",
                "3d",
                "7d",
                "30d"
              ],
              "default": "3d"
            }
          },
          {
            "name": "lang",
            "in": "query",
            "required": false,
            "description": "Output language of the generated text (bull / bear case, viewpoint titles); a missing translation falls back to English.",
            "schema": {
              "type": "string",
              "enum": [
                "en",
                "ko",
                "zh",
                "ja",
                "es",
                "pt",
                "ru",
                "hi",
                "de",
                "fr",
                "tr",
                "vi",
                "id",
                "it",
                "th",
                "pl",
                "nl",
                "uk"
              ],
              "default": "en"
            }
          },
          {
            "name": "source_text",
            "in": "query",
            "required": false,
            "description": "Which source-text field to receive. Omitted = what the key may receive (statement on a key with Integration raw access, excerpt otherwise). `statement` on a key without the clearance → 403 RAW_ACCESS_REQUIRED (contact sales@cryptoquant.com); `excerpt` is always allowed.",
            "schema": {
              "type": "string",
              "enum": [
                "statement",
                "excerpt"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Breakdown snapshot — `source_text` says which source field the key received",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests allowed per minute on your plan.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Daily-Limit": {
                "description": "Free plan only: requests allowed per UTC day.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Daily-Used": {
                "description": "Free plan only: requests used today, including this one.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BreakdownResponse"
                },
                "examples": {
                  "integration": {
                    "summary": "Key with Integration raw access (api_keys.raw_access): sources[].statement",
                    "value": {
                      "asset": {
                        "symbol": "BTC",
                        "name": "Bitcoin"
                      },
                      "updated_at": "2026-10-06T03:34:55+00:00",
                      "window": "3d",
                      "lang": "en",
                      "source_text": "statement",
                      "note": "sources[].statement = the original post title / text (this key holds Integration raw-text access). Viewpoint title / thesis, bull / bear case, index and labels are the same on every plan.",
                      "summary": {
                        "total_opinions": 56,
                        "bullish_opinions": 46,
                        "bearish_opinions": 10,
                        "bullish_pct": 82,
                        "bearish_pct": 18,
                        "consensus_index": 49.54,
                        "z_score": 1.12
                      },
                      "overall": {
                        "bull_case": {
                          "title": "Regulatory wins and dovish data fuel breakout"
                        },
                        "bear_case": {
                          "title": "Macro pressure and resistance threaten deeper pullback"
                        }
                      },
                      "analyst_consensus": {
                        "bullish": [
                          {
                            "id": "a3f1c2d4-7b8e-4a90-9c1d-2e3f4a5b6c7d",
                            "stance": "bullish",
                            "analyst_count": 2,
                            "title": "BTC's first weekly close above the 50WMA in 45 weeks: bear market lows look in",
                            "thesis": "50WMA reclaim",
                            "analysts": [
                              {
                                "handle": "CryptoMichNL",
                                "display_name": "Michael van de Poppe",
                                "avatar_url": "https://pbs.twimg.com/profile_images/1890745133325676544/kcXk6nZx_400x400.jpg",
                                "x_url": "https://x.com/CryptoMichNL",
                                "profile_url": null
                              },
                              {
                                "handle": "the_daily_digits",
                                "display_name": "The Daily Digits",
                                "avatar_url": null,
                                "x_url": null,
                                "profile_url": "https://cryptoquant.com/profile/u/QKJizHT"
                              }
                            ],
                            "sources": [
                              {
                                "analyst_handle": "CryptoMichNL",
                                "statement": "What to expect from #Bitcoin? Honestly, I don't think we're done with the run.",
                                "url": "https://x.com/CryptoMichNL/status/2103900910501990879",
                                "source_type": "tweet",
                                "published_at": "2026-09-26T17:34:00+00:00"
                              },
                              {
                                "analyst_handle": "the_daily_digits",
                                "statement": "$2.1B sits on $95K BTC calls for Oct 30, Deribit's biggest strike.",
                                "url": "https://cryptoquant.com/insights/quicktake/6ac453b68fa8e62507c0bf1b",
                                "source_type": "quicktake",
                                "published_at": "2026-10-06T01:49:42+00:00"
                              }
                            ]
                          }
                        ],
                        "bearish": []
                      }
                    }
                  },
                  "premium": {
                    "summary": "Any other key — Premium / Free / Enterprise / admin without the clearance: sources[].excerpt (≤ 200 characters) + url",
                    "value": {
                      "asset": {
                        "symbol": "BTC",
                        "name": "Bitcoin"
                      },
                      "updated_at": "2026-10-06T03:34:55+00:00",
                      "window": "3d",
                      "lang": "en",
                      "source_text": "excerpt",
                      "note": "sources[].excerpt = the first ≤ 200 characters of the original post (sentence / word boundary, original language) + url; the full statement is provided under an Integration agreement only — contact sales@cryptoquant.com. Viewpoint title / thesis, bull / bear case, index and labels are the same on every plan.",
                      "summary": {
                        "total_opinions": 56,
                        "bullish_opinions": 46,
                        "bearish_opinions": 10,
                        "bullish_pct": 82,
                        "bearish_pct": 18,
                        "consensus_index": 49.54,
                        "z_score": 1.12
                      },
                      "overall": {
                        "bull_case": {
                          "title": "Regulatory wins and dovish data fuel breakout"
                        },
                        "bear_case": {
                          "title": "Macro pressure and resistance threaten deeper pullback"
                        }
                      },
                      "analyst_consensus": {
                        "bullish": [
                          {
                            "id": "a3f1c2d4-7b8e-4a90-9c1d-2e3f4a5b6c7d",
                            "stance": "bullish",
                            "analyst_count": 2,
                            "title": "BTC's first weekly close above the 50WMA in 45 weeks: bear market lows look in",
                            "thesis": "50WMA reclaim",
                            "analysts": [
                              {
                                "handle": "CryptoMichNL",
                                "display_name": "Michael van de Poppe",
                                "avatar_url": "https://pbs.twimg.com/profile_images/1890745133325676544/kcXk6nZx_400x400.jpg",
                                "x_url": "https://x.com/CryptoMichNL",
                                "profile_url": null
                              },
                              {
                                "handle": "the_daily_digits",
                                "display_name": "The Daily Digits",
                                "avatar_url": null,
                                "x_url": null,
                                "profile_url": "https://cryptoquant.com/profile/u/QKJizHT"
                              }
                            ],
                            "sources": [
                              {
                                "analyst_handle": "CryptoMichNL",
                                "excerpt": "What to expect from #Bitcoin? Honestly, I don't think we're done with the run.",
                                "url": "https://x.com/CryptoMichNL/status/2103900910501990879",
                                "source_type": "tweet",
                                "published_at": "2026-09-26T17:34:00+00:00"
                              },
                              {
                                "analyst_handle": "the_daily_digits",
                                "excerpt": "$2.1B sits on $95K BTC calls for Oct 30, Deribit's biggest strike.",
                                "url": "https://cryptoquant.com/insights/quicktake/6ac453b68fa8e62507c0bf1b",
                                "source_type": "quicktake",
                                "published_at": "2026-10-06T01:49:42+00:00"
                              }
                            ]
                          }
                        ],
                        "bearish": []
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`INVALID_PARAMETER` — window / lang / source_text outside their enum (`message` lists the accepted values)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Invalid window",
                  "code": "INVALID_PARAMETER",
                  "message": "window must be one of: 1d, 3d, 7d, 30d",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                  "param": "window"
                }
              }
            }
          },
          "401": {
            "description": "Missing key → `API_KEY_REQUIRED`; unknown / inactive / expired key or inactive subscription → `INVALID_API_KEY`. `Authorization: Bearer` is not read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missing": {
                    "value": {
                      "error": "API key required",
                      "code": "API_KEY_REQUIRED",
                      "message": "Use the X-API-Key header or the api_key query parameter. Keys start with \"unbias_live_\".",
                      "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                      "docs": "https://docs.cryptoquant.com/sentiment/overview"
                    }
                  },
                  "invalid": {
                    "value": {
                      "error": "Invalid API key",
                      "code": "INVALID_API_KEY",
                      "message": "The key is unknown, inactive or expired, or its subscription is not active.",
                      "docs_url": "https://docs.cryptoquant.com/sentiment/errors"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`RAW_ACCESS_REQUIRED` — `source_text=statement` on a key without Integration raw access (per-key clearance, not a plan). Drop the parameter for the excerpt + url, or contact sales@cryptoquant.com (contact_email) for Integration raw-text access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Integration agreement required",
                  "code": "RAW_ACCESS_REQUIRED",
                  "message": "The original source statement (full post text) is provided under an Integration agreement only, per key (not a plan: premium, enterprise and admin-owned keys without it get the excerpt). Drop source_text=statement to receive the ≤ 200-character excerpt + source link, or contact sales@cryptoquant.com (contact_email) for Integration raw-text access. Do not retry unchanged.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/plans-and-access#raw-source-text",
                  "contact_email": "sales@cryptoquant.com",
                  "contact_url": "https://cryptoquant.com/get-in-touch"
                }
              }
            }
          },
          "429": {
            "description": "Per-minute limit (`RATE_LIMIT_EXCEEDED`, header `Retry-After: 60`) or, on the free plan, the daily limit (`DAILY_LIMIT_EXCEEDED`, header `X-RateLimit-Reset: midnight UTC`).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait (per-minute limit only).",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Daily limit only: the literal `midnight UTC`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "per_minute": {
                    "value": {
                      "error": "Rate limit exceeded",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Public endpoint: per-IP limit reached. Wait 37 s (Retry-After), or use an API key for higher limits.",
                      "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                      "retry_after": 37
                    }
                  },
                  "daily": {
                    "value": {
                      "error": "Daily API limit exceeded",
                      "code": "DAILY_LIMIT_EXCEEDED",
                      "message": "Free plan: the daily request quota is used up. It resets at 00:00 UTC; the Premium and Enterprise plans have no daily cap.",
                      "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                      "limit": 100,
                      "used": 100,
                      "reset": "Daily at midnight UTC",
                      "upgrade_url": "https://cryptoquant.com/pricing",
                      "contact_url": "https://cryptoquant.com/get-in-touch"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`INTERNAL_ERROR` — retry once after a few seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Internal server error",
                  "code": "INTERNAL_ERROR",
                  "message": "Something went wrong on our side. Retry once after a few seconds; if it persists, report the URL to support.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors"
                }
              }
            }
          }
        }
      }
    },
    "/analyst-views": {
      "get": {
        "operationId": "getAnalystViews",
        "tags": [
          "Analyst views"
        ],
        "summary": "What analysts are saying about an asset (public, no API key)",
        "description": "The asset page's Analyst Views as JSON: the bull / bear case, the `narratives` (viewpoints grouped by thesis, with analyst and post counts and a summary) and the `analyst_views` — each tracked analyst with ≥ 3 directional posts and a ≥ 60 % consistent side in the window, with their thesis, ONE quotable `excerpt` (the first ≤ 200 characters of one post, original language — the full statement is provided under an Integration agreement only — per API key, contact sales@cryptoquant.com), its `source_url` and the analyst page (`profile_url`); most active first, at most 12 (`analyst_views_total` says how many qualified). Public, no API key. Per-IP limit 60 requests / minute (per function instance); CDN-cached 5 minutes (`Cache-Control: public, s-maxage=300, stale-while-revalidate=3600`). Backs the MCP tool get_analyst_views. Quote excerpts with their source link; show `data_by`.",
        "security": [],
        "x-plan": {
          "access": "public",
          "api_key": "not required",
          "plans": [
            "none",
            "free",
            "premium",
            "enterprise"
          ],
          "rate_limit": "60 requests / minute per IP",
          "daily_limit": "none",
          "cache": "CDN 5 min"
        },
        "parameters": [
          {
            "name": "asset",
            "in": "query",
            "required": false,
            "description": "Any registered asset, case-insensitive: the symbol (`BTC`, `NVDA`, `005930`, `XAU`), the route key (`bitcoin`, `samsung-electronics`), the display name (`Bitcoin`), an alias ticker (`GLD` → XAU) or a retired ticker (`MATIC` → POL). The response reports the canonical symbol. The full list: `GET /assets`. A market aggregate (`crypto-market`) is not accepted. Unknown → 400 `UNKNOWN_ASSET`.",
            "schema": {
              "type": "string",
              "default": "BTC"
            },
            "example": "NVDA"
          },
          {
            "name": "window",
            "in": "query",
            "required": false,
            "description": "Window of the posts considered.",
            "schema": {
              "type": "string",
              "enum": [
                "7d",
                "30d"
              ],
              "default": "30d"
            }
          },
          {
            "name": "via",
            "in": "query",
            "required": false,
            "description": "The surface the agent runs on; sets `utm_source` on every link in the payload. Unknown values fall back to the default.",
            "schema": {
              "type": "string",
              "enum": [
                "chatgpt",
                "claude",
                "mcp",
                "gemini",
                "perplexity",
                "api"
              ],
              "default": "chatgpt"
            },
            "example": "claude"
          }
        ],
        "responses": {
          "200": {
            "description": "Narratives and per-analyst views",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Per-IP requests allowed per minute (60).",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute for this IP.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalystViewsResponse"
                },
                "example": {
                  "asset": "BTC",
                  "asset_name": "Bitcoin",
                  "window": "30d",
                  "bullish_posts": 105,
                  "bearish_posts": 62,
                  "bullish_pct": 63,
                  "bearish_pct": 37,
                  "bull_case": "Regulatory wins and dovish data fuel breakout",
                  "bear_case": "Macro pressure and resistance threaten deeper pullback",
                  "narratives": [
                    {
                      "theme": "EXCHANGE HACK",
                      "headline": "Bitget drained for $387.5M as DPRK hackers spoof backend approvals",
                      "stance": "bearish",
                      "analyst_count": 8,
                      "post_count": 8,
                      "summary": "Bitget's breach was first reported at $351.6M and later revised up by about $35M to $387.5M. Attackers used spoofed transaction approvals from a compromised backend rather than stolen keys. The $464M User Protection Fund covers the loss but shrinks to about $76.5M."
                    }
                  ],
                  "analyst_views": [
                    {
                      "handle": "CryptoMichNL",
                      "name": "Michael van de Poppe",
                      "stance": "bullish",
                      "thesis": "BTC run not over; momentum into October targets ~$90,000 resistance, followed by consolidation and a midterm-driven correction that is a buying opportunity before a new all-time high",
                      "excerpt": "What to expect from #Bitcoin?\n\nHonestly, I don't think we're done with the run. Sure, we can have some red weeks in between, but I'm eyeing the $90,000 area as the coming resistance to be, after…",
                      "source_url": "https://x.com/CryptoMichNL/status/2103900910501990879",
                      "source_type": "tweet",
                      "published_at": "2026-09-26T17:34:00+00:00",
                      "post_count": 14,
                      "consistency_pct": 100,
                      "profile_url": "https://consensus.cryptoquant.com/analyst/CryptoMichNL?utm_source=api&utm_medium=gpt-action&utm_campaign=analyst-views"
                    }
                  ],
                  "analyst_views_total": 14,
                  "note": "analyst_views = analysts with ≥ 3 directional posts on the asset in the window and a ≥ 60 % consistent side; excerpt = the first ≤ 200 characters of one post (original language), quote it with the source_url — the full statement is provided under an Integration agreement only — contact sales@cryptoquant.com. bullish_pct / bearish_pct are post shares (neutral excluded); the Analyst Consensus Index is on /api/v1/consensus.",
                  "page_url": "https://consensus.cryptoquant.com/consensus/btc?utm_source=api&utm_medium=gpt-action&utm_campaign=analyst-views",
                  "top_analysts_url": "https://consensus.cryptoquant.com/analysts?asset=btc&sort=accuracy&utm_source=api&utm_medium=gpt-action&utm_campaign=analyst-views",
                  "methodology_url": "https://consensus.cryptoquant.com/methodology?utm_source=api&utm_medium=gpt-action&utm_campaign=analyst-views",
                  "cite_as": "Data by CryptoQuant Consensus — https://consensus.cryptoquant.com/consensus/btc",
                  "data_by": "Data by CryptoQuant Consensus",
                  "as_of": "2026-10-06T07:48:25.102Z"
                }
              }
            }
          },
          "400": {
            "description": "`UNKNOWN_ASSET` or `INVALID_PARAMETER` (window)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Unknown asset",
                  "code": "UNKNOWN_ASSET",
                  "message": "\"DOGE2\" is not a registered asset. Use a ticker, route key or name from https://consensus.cryptoquant.com/api/v1/assets (symbol / key / name / aliases, case-insensitive). Market aggregates are not assets.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                  "param": "asset"
                }
              }
            }
          },
          "429": {
            "description": "Per-IP limit on the key-free path (60 requests / minute per function instance). Wait `Retry-After` seconds, or use an API key for higher limits.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Rate limit exceeded",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "message": "Public endpoint: per-IP limit reached. Wait 37 s (Retry-After), or use an API key for higher limits.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                  "retry_after": 37
                }
              }
            }
          },
          "500": {
            "description": "`INTERNAL_ERROR` — retry once after a few seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Internal server error",
                  "code": "INTERNAL_ERROR",
                  "message": "Something went wrong on our side. Retry once after a few seconds; if it persists, report the URL to support.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors"
                }
              }
            }
          }
        }
      }
    },
    "/calls": {
      "get": {
        "operationId": "getRecentCalls",
        "tags": [
          "Analyst views"
        ],
        "summary": "Newest analyst calls on an asset (public, no API key)",
        "description": "The newest directional calls on one asset, newest first by `published_at`: a call = one bullish / bearish post about the asset by a tracked, eligible analyst (neutral posts are not calls). Each row: analyst, stance, the post's `excerpt` (first ≤ 200 characters, original language — never the full text without a key cleared under an Integration agreement), `source_url`, `published_at`, `profile_url`. Public, no API key. Per-IP limit 60 requests / minute (per function instance); CDN-cached 5 minutes (`Cache-Control: public, s-maxage=300, stale-while-revalidate=3600`). Backs the MCP tool get_recent_calls. History / bulk stays with the keyed API.",
        "security": [],
        "x-plan": {
          "access": "public",
          "api_key": "not required",
          "plans": [
            "none",
            "free",
            "premium",
            "enterprise"
          ],
          "rate_limit": "60 requests / minute per IP",
          "daily_limit": "none",
          "cache": "CDN 5 min"
        },
        "parameters": [
          {
            "name": "asset",
            "in": "query",
            "required": false,
            "description": "Any registered asset, case-insensitive: the symbol (`BTC`, `NVDA`, `005930`, `XAU`), the route key (`bitcoin`, `samsung-electronics`), the display name (`Bitcoin`), an alias ticker (`GLD` → XAU) or a retired ticker (`MATIC` → POL). The response reports the canonical symbol. The full list: `GET /assets`. A market aggregate (`crypto-market`) is not accepted. Unknown → 400 `UNKNOWN_ASSET`.",
            "schema": {
              "type": "string",
              "default": "BTC"
            },
            "example": "NVDA"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Rows to return, clamped to 1–50 silently; unparsable = 10.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            },
            "example": 20
          },
          {
            "name": "via",
            "in": "query",
            "required": false,
            "description": "The surface the agent runs on; sets `utm_source` on every link in the payload. Unknown values fall back to the default.",
            "schema": {
              "type": "string",
              "enum": [
                "chatgpt",
                "claude",
                "mcp",
                "gemini",
                "perplexity",
                "api"
              ],
              "default": "chatgpt"
            },
            "example": "claude"
          }
        ],
        "responses": {
          "200": {
            "description": "Newest calls",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Per-IP requests allowed per minute (60).",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute for this IP.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecentCallsResponse"
                },
                "example": {
                  "asset": "BTC",
                  "asset_name": "Bitcoin",
                  "count": 2,
                  "calls": [
                    {
                      "handle": "trader1sz",
                      "name": "TraderSZ",
                      "stance": "bearish",
                      "excerpt": "now what do you think happens if $BTC takes a little sneeze? https://t.co/E6YKg42FtY",
                      "source_url": "https://x.com/trader1sz/status/2107313628827251104",
                      "source_type": "tweet",
                      "published_at": "2026-10-06T03:34:55+00:00",
                      "profile_url": "https://consensus.cryptoquant.com/analyst/trader1sz?utm_source=api&utm_medium=gpt-action&utm_campaign=calls"
                    },
                    {
                      "handle": "the_daily_digits",
                      "name": "The Daily Digits",
                      "stance": "bullish",
                      "excerpt": "$2.1B sits on $95K BTC calls for Oct 30, Deribit's biggest strike.\n\nFutures OI lags 13% below its $29.3B peak.\n\nMax pain sits at $78K, 9% under spot.",
                      "source_url": "https://cryptoquant.com/insights/quicktake/6ac453b68fa8e62507c0bf1b",
                      "source_type": "quicktake",
                      "published_at": "2026-10-06T01:49:42+00:00",
                      "profile_url": "https://consensus.cryptoquant.com/analyst/the_daily_digits?utm_source=api&utm_medium=gpt-action&utm_campaign=calls"
                    }
                  ],
                  "definition": "A call = one directional (bullish / bearish) post about this asset by a tracked, eligible analyst; neutral posts are not calls. Newest first. excerpt = the first ≤ 200 characters of the post (original language); quote it with its source_url and the analyst's profile_url — the full statement is provided under an Integration agreement only (contact sales@cryptoquant.com).",
                  "page_url": "https://consensus.cryptoquant.com/consensus/btc?utm_source=api&utm_medium=gpt-action&utm_campaign=calls",
                  "top_analysts_url": "https://consensus.cryptoquant.com/analysts?asset=btc&sort=accuracy&utm_source=api&utm_medium=gpt-action&utm_campaign=calls",
                  "methodology_url": "https://consensus.cryptoquant.com/methodology?utm_source=api&utm_medium=gpt-action&utm_campaign=calls",
                  "cite_as": "Data by CryptoQuant Consensus — https://consensus.cryptoquant.com/consensus/btc",
                  "data_by": "Data by CryptoQuant Consensus",
                  "as_of": "2026-10-06T07:48:25.838Z"
                }
              }
            }
          },
          "400": {
            "description": "`UNKNOWN_ASSET`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Unknown asset",
                  "code": "UNKNOWN_ASSET",
                  "message": "\"DOGE2\" is not a registered asset. Use a ticker, route key or name from https://consensus.cryptoquant.com/api/v1/assets (symbol / key / name / aliases, case-insensitive). Market aggregates are not assets.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                  "param": "asset"
                }
              }
            }
          },
          "429": {
            "description": "Per-IP limit on the key-free path (60 requests / minute per function instance). Wait `Retry-After` seconds, or use an API key for higher limits.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Rate limit exceeded",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "message": "Public endpoint: per-IP limit reached. Wait 37 s (Retry-After), or use an API key for higher limits.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                  "retry_after": 37
                }
              }
            }
          },
          "500": {
            "description": "`INTERNAL_ERROR` — retry once after a few seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Internal server error",
                  "code": "INTERNAL_ERROR",
                  "message": "Something went wrong on our side. Retry once after a few seconds; if it persists, report the URL to support.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors"
                }
              }
            }
          }
        }
      }
    },
    "/analysts/top": {
      "get": {
        "operationId": "getTopAnalysts",
        "tags": [
          "Analyst track record"
        ],
        "summary": "Top analysts for an asset by accuracy (public, no API key)",
        "description": "The asset's analysts ranked by accuracy_score among those active in the last three calendar months — the same rows and order as the site's /analysts list sorted by accuracy (ties: sample size, then handle). Public; CDN-cached for one hour (`Cache-Control: public, s-maxage=3600, stale-while-revalidate=86400`). Accuracy scoring covers crypto assets today: other asset classes return `scored: false` with null scores and the list in activity order. Backs the MCP tool get_top_analysts.",
        "security": [],
        "x-plan": {
          "access": "public",
          "api_key": "not required",
          "plans": [
            "none",
            "free",
            "premium",
            "enterprise"
          ],
          "rate_limit": "none (CDN-cached)",
          "daily_limit": "none",
          "cache": "CDN 1 h"
        },
        "parameters": [
          {
            "name": "asset",
            "in": "query",
            "required": false,
            "description": "Registered asset symbol or route key (BTC, ETH, SOL, NVDA, 005930 …), case-insensitive. Unknown → 400 UNKNOWN_ASSET.",
            "schema": {
              "type": "string",
              "default": "BTC"
            },
            "example": "BTC"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Rows to return, clamped to 1–50 silently; unparsable = 20.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            },
            "example": 5
          }
        ],
        "responses": {
          "200": {
            "description": "Ranked analysts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TopAnalystsResponse"
                },
                "example": {
                  "asset": "BTC",
                  "asset_name": "Bitcoin",
                  "asset_class": "crypto",
                  "as_of": "2026-10-06T07:48:27.635Z",
                  "scored": true,
                  "ranking": "accuracy_score desc among analysts active in the last three calendar months (ties: sample size, then handle)",
                  "tier_asset_class": "crypto",
                  "count": 1,
                  "total_ranked": 72,
                  "total_tracked": 125,
                  "analysts": [
                    {
                      "rank": 1,
                      "tier": {
                        "asset_class": "crypto",
                        "tier": 1,
                        "badge": "top1",
                        "label": "Top 1%",
                        "eligible": true,
                        "reason": null,
                        "pool_rank": 2,
                        "pool_size": 108,
                        "percentile": 1.8519,
                        "score_version": "v20",
                        "computed_at": "2026-10-06T00:59:17.501379+00:00"
                      },
                      "handle": "CarpeNoctom",
                      "name": "CarpeNoctom",
                      "profile_url": "https://consensus.cryptoquant.com/analyst/CarpeNoctom",
                      "source_url": "https://x.com/CarpeNoctom",
                      "sources": [
                        "twitter"
                      ],
                      "role": "PM & Head of Trading",
                      "company": "Canary Capital",
                      "category": null,
                      "citation_count": null,
                      "accuracy_score": 69.9,
                      "accuracy_sample_size": 2081,
                      "call_count": 5374,
                      "bull_score": 76,
                      "bear_score": 50.3,
                      "short_score": 51,
                      "long_score": 63.3,
                      "balanced_score": 50.3,
                      "bullish_bias_pct": 54,
                      "bias": "balanced",
                      "last_post_at": "2026-10-02T21:04:12+00:00"
                    }
                  ],
                  "score_notes": {
                    "accuracy_score": "Overall accuracy, 0–100: an Empirical-Bayes-adjusted hit rate of the analyst's directional calls against subsequent price moves, shrunk toward the pool mean when the sample is small. Comparative — rank analysts on the same asset by it; it is NOT a win probability.",
                    "accuracy_sample_size": "Number of evaluated calls behind accuracy_score. Treat scores with a sample below ~10 as weak evidence."
                  },
                  "list_url": "https://consensus.cryptoquant.com/analysts?asset=btc&sort=accuracy",
                  "methodology_url": "https://consensus.cryptoquant.com/methodology",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/analyst-track-record"
                }
              }
            }
          },
          "400": {
            "description": "`UNKNOWN_ASSET`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Unknown asset",
                  "code": "UNKNOWN_ASSET",
                  "message": "\"DOGE2\" is not a registered asset. Use a ticker, route key or name from https://consensus.cryptoquant.com/api/v1/assets (symbol / key / name / aliases, case-insensitive). Market aggregates are not assets.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                  "param": "asset"
                }
              }
            }
          },
          "503": {
            "description": "`SERVICE_UNAVAILABLE` — the analyst list could not be loaded; retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Analyst list unavailable",
                  "code": "SERVICE_UNAVAILABLE",
                  "message": "The analyst list could not be loaded. Try again shortly.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors"
                }
              }
            }
          }
        }
      }
    },
    "/analysts/{handle}": {
      "get": {
        "operationId": "getAnalystTrackRecord",
        "tags": [
          "Analyst track record"
        ],
        "summary": "One analyst's track record (public, no API key)",
        "description": "The analyst page's numbers as JSON: stored accuracy scores, category ranks, overall rank, best top-10 placement, call counts split per source and recent bias, covered assets, profile and source URLs. `{handle}` is the X handle, the /analyst/<slug> page slug or a `platform:slug` id; a leading @ is ignored and URL-encoding is decoded. Hidden, ineligible, company, news-feed and sell-side rows are 404 `ANALYST_NOT_FOUND`. Public; CDN-cached for one hour. Backs the MCP tool get_analyst_profile.",
        "security": [],
        "x-plan": {
          "access": "public",
          "api_key": "not required",
          "plans": [
            "none",
            "free",
            "premium",
            "enterprise"
          ],
          "rate_limit": "none (CDN-cached)",
          "daily_limit": "none",
          "cache": "CDN 1 h"
        },
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "caprioleio",
            "description": "X handle / page slug / `platform:slug` id (case-insensitive)."
          }
        ],
        "responses": {
          "200": {
            "description": "Track record",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalystTrackRecord"
                },
                "example": {
                  "handle": "caprioleio",
                  "name": "Charles Edwards",
                  "slug": "caprioleio",
                  "profile_url": "https://consensus.cryptoquant.com/analyst/caprioleio",
                  "source_url": "https://x.com/caprioleio",
                  "sources": [
                    "twitter"
                  ],
                  "role": "Founder & CEO",
                  "company": "Capriole Investments",
                  "follower_count": 0,
                  "is_verified": false,
                  "category": "macro",
                  "activity": {
                    "last_activity_at": "2026-10-02T12:34:42+00:00",
                    "active_last_3_months": true
                  },
                  "track_record": {
                    "accuracy_score": 70.8,
                    "accuracy_sample_size": 1624,
                    "call_count": 2276,
                    "bull_score": 89.8,
                    "bear_score": 39.8,
                    "short_score": 63.9,
                    "long_score": 77,
                    "balanced_score": 39.8,
                    "overall_rank": {
                      "rank": 6,
                      "total": 109
                    },
                    "category_ranks": {
                      "bull": {
                        "rank": 1,
                        "total": 111
                      },
                      "bear": {
                        "rank": 51,
                        "total": 111
                      },
                      "short": {
                        "rank": 20,
                        "total": 91
                      },
                      "long": {
                        "rank": 29,
                        "total": 111
                      }
                    },
                    "best_ranking": {
                      "category": "bull",
                      "rank": 1,
                      "label": "Bull Accuracy",
                      "priority": 2
                    },
                    "scored": true,
                    "tier": {
                      "asset_class": "crypto",
                      "tier": 1,
                      "badge": "top1",
                      "label": "Top 1%",
                      "eligible": true,
                      "reason": null,
                      "pool_rank": 7,
                      "pool_size": 106,
                      "percentile": 6.6038,
                      "score_version": "v20r-btc-amp31-dir",
                      "computed_at": "2026-10-02T21:16:07.550877+00:00"
                    },
                    "tiers": {
                      "crypto": {
                        "asset_class": "crypto",
                        "tier": 1,
                        "badge": "top1",
                        "label": "Top 1%",
                        "eligible": true,
                        "reason": null,
                        "pool_rank": 7,
                        "pool_size": 106,
                        "percentile": 6.6038,
                        "score_version": "v20r-btc-amp31-dir",
                        "computed_at": "2026-10-02T21:16:07.550877+00:00"
                      }
                    }
                  },
                  "calls": {
                    "total": 1778,
                    "bullish": 1160,
                    "bearish": 618,
                    "neutral": 542,
                    "by_source": {
                      "x": 1778,
                      "cryptoquant": 0,
                      "news": 0,
                      "tradingview": 0,
                      "seekingalpha": 0,
                      "substack": 0,
                      "benzinga": 0,
                      "other": 0
                    },
                    "definition": "A call is one directional (bullish or bearish) item about one tracked asset, over the whole stored history: X posts, TradingView ideas, Seeking Alpha articles (title + summary), Substack posts and sell-side analyst ratings. An article on several tickers is one call per ticker on each asset page and counts once per article × ticker pair in its author's total.",
                    "recent_bullish_bias_pct": 70,
                    "recent_bias": "bullish"
                  },
                  "covered_assets": [
                    {
                      "symbol": "BTC",
                      "asset_class": "crypto",
                      "last_post_at": "2026-09-23T04:02:49+00:00"
                    },
                    {
                      "symbol": "SPY",
                      "asset_class": "indices",
                      "last_post_at": "2026-08-05T06:40:15+00:00"
                    }
                  ],
                  "citation_count": null,
                  "score_notes": {
                    "accuracy_score": "Overall accuracy, 0–100: an Empirical-Bayes-adjusted hit rate of the analyst's directional calls against subsequent price moves, shrunk toward the pool mean when the sample is small. Comparative — rank analysts on the same asset by it; it is NOT a win probability.",
                    "accuracy_sample_size": "Number of evaluated calls behind accuracy_score. Treat scores with a sample below ~10 as weak evidence."
                  },
                  "methodology_url": "https://consensus.cryptoquant.com/methodology",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/analyst-track-record",
                  "as_of": "2026-10-06T07:48:28.011Z"
                }
              }
            }
          },
          "404": {
            "description": "`ANALYST_NOT_FOUND` — no such tracked analyst (`message` points to /analysts/top for valid handles)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Analyst not found",
                  "code": "ANALYST_NOT_FOUND",
                  "message": "No tracked analyst \"nobody\". Valid handles are listed by GET https://consensus.cryptoquant.com/api/v1/analysts/top?asset=<symbol>.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors"
                }
              }
            }
          }
        }
      }
    },
    "/sentiment": {
      "get": {
        "operationId": "getAnalystStance",
        "tags": [
          "Analyst stance"
        ],
        "summary": "One analyst's daily stance on an asset (Premium / Enterprise API key)",
        "description": "Daily stance / sentiment score of one analyst on one asset, oldest first. Identify the analyst by `handle` (case-insensitive) or `analyst_id` (UUID); `asset` is any registered asset (symbol, key, name or alias — canonical symbol in the response). Premium / Enterprise keys (and the legacy Enterprise row) get `days` of history ending yesterday UTC; a FREE key is refused with 401 `PLAN_REQUIRED` (Ki 2026-10-06 — before that date the free plan got the latest point, the `StanceLatest` shape is kept for the day a free per-analyst tier returns). A pair with no rows answers `count: 0`. Field set depends on the stance pipeline flag: `stance` / `confidence` / `post_count` appear once it is on, `sentiment_score_key_calls` is then always null.",
        "x-plan": {
          "access": "premium_or_enterprise",
          "api_key": "required",
          "plans": [
            "premium",
            "enterprise"
          ],
          "error_below": "PLAN_REQUIRED",
          "rate_limit": "1000 / min",
          "daily_limit": "none",
          "cache": "none"
        },
        "parameters": [
          {
            "name": "handle",
            "in": "query",
            "required": false,
            "description": "Analyst handle (required unless analyst_id is given); valid handles come from /analysts/top. Case-insensitive.",
            "schema": {
              "type": "string"
            },
            "example": "caprioleio"
          },
          {
            "name": "analyst_id",
            "in": "query",
            "required": false,
            "description": "Analyst UUID (alternative to handle; wins when both are given).",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "c897b6ac-0cf2-41f2-98d5-84b7464cef41"
          },
          {
            "name": "asset",
            "in": "query",
            "required": false,
            "description": "Any registered asset, case-insensitive: the symbol (`BTC`, `NVDA`, `005930`, `XAU`), the route key (`bitcoin`, `samsung-electronics`), the display name (`Bitcoin`), an alias ticker (`GLD` → XAU) or a retired ticker (`MATIC` → POL). The response reports the canonical symbol. The full list: `GET /assets`. A market aggregate (`crypto-market`) is not accepted. Unknown → 400 `UNKNOWN_ASSET`.",
            "schema": {
              "type": "string",
              "default": "BTC"
            },
            "example": "BTC"
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "Days of history ending yesterday UTC. Positive integer (else 400 INVALID_PARAMETER); silently capped at the plan's max_days_history (36500 on premium / enterprise).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 36500,
              "default": 30
            },
            "example": 90
          }
        ],
        "responses": {
          "200": {
            "description": "Series (premium / enterprise: StanceSeries). StanceLatest is the reserved free-plan shape (not served today).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests allowed per minute on your plan.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Daily-Limit": {
                "description": "Free plan only: requests allowed per UTC day.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Daily-Used": {
                "description": "Free plan only: requests used today, including this one.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/StanceSeries"
                    },
                    {
                      "$ref": "#/components/schemas/StanceLatest"
                    }
                  ]
                },
                "examples": {
                  "series": {
                    "summary": "Premium / Enterprise key",
                    "value": {
                      "analyst_id": "c897b6ac-0cf2-41f2-98d5-84b7464cef41",
                      "asset": "BTC",
                      "period": {
                        "start": "2026-10-04",
                        "end": "2026-10-05"
                      },
                      "count": 2,
                      "data": [
                        {
                          "date": "2026-10-04",
                          "sentiment_score": 80,
                          "sentiment_score_key_calls": null,
                          "key_calls_count": 7
                        },
                        {
                          "date": "2026-10-05",
                          "sentiment_score": 82,
                          "sentiment_score_key_calls": null,
                          "key_calls_count": 5
                        }
                      ]
                    }
                  },
                  "latest_free_reserved": {
                    "summary": "Reserved free-plan shape (401 PLAN_REQUIRED today)",
                    "value": {
                      "analyst_id": "c897b6ac-0cf2-41f2-98d5-84b7464cef41",
                      "asset": "BTC",
                      "date": "2026-10-05",
                      "sentiment_score": 82,
                      "sentiment_score_key_calls": null,
                      "key_calls_count": 5,
                      "plan": "free",
                      "upgrade_message": "Contact us for Enterprise access to full historical sentiment data"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`INVALID_PARAMETER` (days; neither handle nor analyst_id → `error: \"analyst_id or handle parameter required\"`) or `UNKNOWN_ASSET`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Invalid window",
                  "code": "INVALID_PARAMETER",
                  "message": "window must be one of: 1d, 3d, 7d, 30d",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                  "param": "window"
                }
              }
            }
          },
          "401": {
            "description": "Missing key → `API_KEY_REQUIRED`; invalid key → `INVALID_API_KEY`; free-plan key → `PLAN_REQUIRED` (`required_plans`, `upgrade_url`, `contact_url`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missing": {
                    "value": {
                      "error": "API key required",
                      "code": "API_KEY_REQUIRED",
                      "message": "Use the X-API-Key header or the api_key query parameter. Keys start with \"unbias_live_\".",
                      "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                      "docs": "https://docs.cryptoquant.com/sentiment/overview"
                    }
                  },
                  "invalid": {
                    "value": {
                      "error": "Invalid API key",
                      "code": "INVALID_API_KEY",
                      "message": "The key is unknown, inactive or expired, or its subscription is not active.",
                      "docs_url": "https://docs.cryptoquant.com/sentiment/errors"
                    }
                  },
                  "plan": {
                    "value": {
                      "error": "Premium or Enterprise plan required",
                      "code": "PLAN_REQUIRED",
                      "message": "This key (Free plan) has no access to per-analyst data. Per-analyst endpoints are available on the Premium and Enterprise plans: subscribe to CryptoQuant Premium (upgrade_url) or contact CryptoQuant for Enterprise / trial access (contact_url).",
                      "docs_url": "https://docs.cryptoquant.com/sentiment/plans-and-access",
                      "plan": "FREE",
                      "required_plans": [
                        "premium",
                        "enterprise"
                      ],
                      "upgrade_url": "https://cryptoquant.com/pricing",
                      "contact_url": "https://cryptoquant.com/get-in-touch",
                      "upgradeUrl": "https://cryptoquant.com/pricing"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`ANALYST_NOT_FOUND`, `ANALYST_NOT_ELIGIBLE` (excluded / ineligible analysts) or `NO_DATA` (free-plan latest point, reserved)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Analyst not found",
                  "code": "ANALYST_NOT_FOUND",
                  "message": "No tracked analyst \"nobody\". Valid handles are listed by GET https://consensus.cryptoquant.com/api/v1/analysts/top?asset=<symbol>.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors"
                }
              }
            }
          },
          "429": {
            "description": "Per-minute limit (`RATE_LIMIT_EXCEEDED`, header `Retry-After: 60`) or, on the free plan, the daily limit (`DAILY_LIMIT_EXCEEDED`, header `X-RateLimit-Reset: midnight UTC`).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait (per-minute limit only).",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Daily limit only: the literal `midnight UTC`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "per_minute": {
                    "value": {
                      "error": "Rate limit exceeded",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Public endpoint: per-IP limit reached. Wait 37 s (Retry-After), or use an API key for higher limits.",
                      "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                      "retry_after": 37
                    }
                  },
                  "daily": {
                    "value": {
                      "error": "Daily API limit exceeded",
                      "code": "DAILY_LIMIT_EXCEEDED",
                      "message": "Free plan: the daily request quota is used up. It resets at 00:00 UTC; the Premium and Enterprise plans have no daily cap.",
                      "docs_url": "https://docs.cryptoquant.com/sentiment/errors",
                      "limit": 100,
                      "used": 100,
                      "reset": "Daily at midnight UTC",
                      "upgrade_url": "https://cryptoquant.com/pricing",
                      "contact_url": "https://cryptoquant.com/get-in-touch"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`INTERNAL_ERROR` — retry once after a few seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Internal server error",
                  "code": "INTERNAL_ERROR",
                  "message": "Something went wrong on our side. Retry once after a few seconds; if it persists, report the URL to support.",
                  "docs_url": "https://docs.cryptoquant.com/sentiment/errors"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Provisioned with the CryptoQuant Premium plan or an Enterprise agreement (no self-serve). Keys start with `unbias_live_`."
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "api_key",
        "description": "Same key as a query parameter (avoid in logged URLs)."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Every non-2xx body. Branch on `code`; `error` is the legacy short reason kept for pre-2026-10-06 clients.",
        "required": [
          "error",
          "code",
          "message",
          "docs_url"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Legacy short reason (\"Invalid asset\", \"API key required\", \"Rate limit exceeded\" …), unchanged wording."
          },
          "code": {
            "type": "string",
            "enum": [
              "API_KEY_REQUIRED",
              "INVALID_API_KEY",
              "PLAN_REQUIRED",
              "RAW_ACCESS_REQUIRED",
              "DAILY_LIMIT_EXCEEDED",
              "RATE_LIMIT_EXCEEDED",
              "INVALID_PARAMETER",
              "UNKNOWN_ASSET",
              "ANALYST_NOT_FOUND",
              "ANALYST_NOT_ELIGIBLE",
              "NO_DATA",
              "SERVICE_UNAVAILABLE",
              "INTERNAL_ERROR"
            ],
            "description": "Stable machine code. Status and recovery per code: see `x-errors` at the document root."
          },
          "message": {
            "type": "string",
            "description": "Human explanation, with the accepted values for a parameter error."
          },
          "docs_url": {
            "type": "string",
            "format": "uri",
            "description": "Where the error is documented (https://docs.cryptoquant.com/sentiment/errors, or the Plans & Access page for PLAN_REQUIRED)."
          },
          "param": {
            "type": "string",
            "description": "The offending query parameter (INVALID_PARAMETER, UNKNOWN_ASSET)."
          },
          "required_plans": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "premium",
                "enterprise"
              ]
            },
            "description": "Plans that may call the endpoint (PLAN_REQUIRED)."
          },
          "plan": {
            "type": "string",
            "description": "The key's current plan label, upper-cased (PLAN_REQUIRED)."
          },
          "upgrade_url": {
            "type": "string",
            "format": "uri",
            "description": "Self-serve upgrade (PLAN_REQUIRED, DAILY_LIMIT_EXCEEDED)."
          },
          "contact_url": {
            "type": "string",
            "format": "uri",
            "description": "Enterprise / sales contact (PLAN_REQUIRED, DAILY_LIMIT_EXCEEDED)."
          },
          "limit": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Daily quota (DAILY_LIMIT_EXCEEDED)."
          },
          "used": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Requests used today (DAILY_LIMIT_EXCEEDED)."
          },
          "reset": {
            "type": "string",
            "description": "When the quota resets (\"Daily at midnight UTC\")."
          },
          "retry_after": {
            "type": "integer",
            "minimum": 1,
            "description": "Seconds to wait (RATE_LIMIT_EXCEEDED; also the Retry-After header)."
          },
          "docs": {
            "type": "string",
            "format": "uri",
            "deprecated": true,
            "description": "Legacy alias of docs_url on API_KEY_REQUIRED."
          },
          "upgradeUrl": {
            "type": "string",
            "format": "uri",
            "deprecated": true,
            "description": "Legacy alias of upgrade_url on PLAN_REQUIRED."
          }
        }
      },
      "AssetRow": {
        "type": "object",
        "required": [
          "symbol",
          "name",
          "key",
          "asset_class",
          "category",
          "market",
          "currency",
          "source",
          "coverage",
          "canonical",
          "aliases",
          "retired_symbols",
          "page_url",
          "identity"
        ],
        "properties": {
          "symbol": {
            "type": "string",
            "description": "The symbol the API reports and accepts (`BTC`, `NVDA`, `005930`, `XAU`)."
          },
          "name": {
            "type": "string",
            "description": "Display name (also accepted as `asset`)."
          },
          "key": {
            "type": "string",
            "description": "Route key of the site page (`/consensus/<key>`; also accepted as `asset`)."
          },
          "asset_class": {
            "type": "string",
            "enum": [
              "crypto",
              "equities",
              "indices",
              "commodities"
            ]
          },
          "category": {
            "type": "string",
            "enum": [
              "crypto",
              "us-equities",
              "indices",
              "commodities",
              "kr-equities"
            ],
            "description": "Selector category: asset_class with equities split into US / KR by venue."
          },
          "market": {
            "type": "string",
            "description": "Listing venue / price-source label (`Bitfinex`, `NasdaqGS`, `KRX`, `Commodity`, `US`)."
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency of the price series (`USD`, `KRW`)."
          },
          "source": {
            "type": "string",
            "enum": [
              "alpha",
              "sellside",
              "unbias",
              "legacy"
            ],
            "description": "Registry provenance: `alpha` = CryptoQuant Alpha library, `sellside` = licensed ratings coverage only (no price series), `unbias` = crypto registered here, `legacy` = long-tail crypto tag."
          },
          "coverage": {
            "type": "string",
            "enum": [
              "live",
              "mapped",
              "pending"
            ],
            "description": "`live` = the crypto pipeline covers it; `mapped` = analysts / ratings mapped, data collecting; `pending` = page exists, no analyst data yet."
          },
          "canonical": {
            "type": [
              "string",
              "null"
            ],
            "description": "Set on an ALIAS ticker: the canonical symbol whose data it serves (`GLD` → `XAU`). null for a canonical asset."
          },
          "aliases": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Alias tickers of a canonical asset (`XAU` → [`GLD`])."
          },
          "retired_symbols": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Former tickers that still resolve to this asset (`POL` → [`MATIC`, `POLYGON`])."
          },
          "page_url": {
            "type": "string",
            "format": "uri"
          },
          "identity": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/AssetIdentity"
              },
              {
                "type": "null"
              }
            ],
            "description": "The asset's external identity — `asset_class` on the identity enum + `uid` (CoinGecko id / ISIN / internal code). Two assets may share a `symbol` (STX = Stacks and Seagate); the identity tells them apart. null for an unregistered long-tail ticker."
          }
        }
      },
      "AssetIdentity": {
        "type": "object",
        "required": [
          "asset_class",
          "uid",
          "chain_contract",
          "exchange_mic",
          "needs_review"
        ],
        "description": "One asset = one (asset_class, uid). The identity enum is finer than the registry `asset_class` (an ETF is `etf`, not `indices`; FX is `fx`). `uid` is null while the identity is still under review — never a guess.",
        "properties": {
          "asset_class": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "crypto",
              "equity",
              "etf",
              "index",
              "commodity",
              "fx",
              null
            ],
            "description": "Identity class; null for a series the enum has no value for yet (rate series)."
          },
          "uid": {
            "type": [
              "string",
              "null"
            ],
            "description": "crypto = CoinGecko id (`bitcoin`, `cosmos`); equity / etf = ISIN (`US67066G1040`); index / commodity / fx = internal code (`SPX`, `XAU`, `EURUSD`)."
          },
          "chain_contract": {
            "type": [
              "string",
              "null"
            ],
            "description": "Crypto tokens only: `<coingecko platform>:<contract address>`; null for native coins and every other class."
          },
          "exchange_mic": {
            "type": [
              "string",
              "null"
            ],
            "description": "equity / etf only: ISO 10383 MIC of the listing venue (`XNAS`, `XNYS`, `ARCX`, `XKRX`)."
          },
          "needs_review": {
            "type": "boolean",
            "description": "true while the identity lookup is unconfirmed (uid null)."
          }
        }
      },
      "AssetsResponse": {
        "type": "object",
        "required": [
          "count",
          "rows",
          "assets",
          "enums",
          "as_of"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "minimum": 0,
            "description": "Canonical assets in the response (alias tickers not counted)."
          },
          "rows": {
            "type": "integer",
            "minimum": 0,
            "description": "Rows in `assets` (canonical + alias tickers)."
          },
          "filter": {
            "type": "object",
            "properties": {
              "asset_class": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "category": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "q": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "asset_classes": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "asset_class → label."
          },
          "categories": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "category → label."
          },
          "how_to_resolve": {
            "type": "string"
          },
          "assets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssetRow"
            }
          },
          "enums": {
            "type": "object",
            "description": "Every closed value set the API uses, listed in full.",
            "required": [
              "asset_class",
              "asset_category",
              "source_platform",
              "source_type",
              "sentiment_label",
              "stance",
              "plan"
            ],
            "properties": {
              "asset_class": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "crypto",
                    "equities",
                    "indices",
                    "commodities"
                  ]
                }
              },
              "asset_category": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "crypto",
                    "us-equities",
                    "indices",
                    "commodities",
                    "kr-equities"
                  ]
                }
              },
              "asset_source": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "alpha",
                    "sellside",
                    "unbias",
                    "legacy"
                  ]
                }
              },
              "source_platform": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "x",
                    "cryptoquant",
                    "seekingalpha",
                    "tradingview",
                    "substack",
                    "benzinga"
                  ]
                },
                "description": "Where tracked analysts publish (`x` = X / Twitter; `benzinga` = licensed sell-side ratings)."
              },
              "analyst_source": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "twitter",
                    "cryptoquant",
                    "seekingalpha",
                    "tradingview",
                    "substack",
                    "other"
                  ]
                }
              },
              "source_type": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "tweet",
                    "quicktake",
                    "research",
                    "news",
                    "seekingalpha",
                    "tradingview",
                    "substack",
                    "youtube",
                    "telegram",
                    "bluesky"
                  ]
                },
                "description": "Stored `source_type` of a post."
              },
              "sentiment_label": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "bullish",
                    "bullish_nuance",
                    "neutral",
                    "bearish_nuance",
                    "bearish"
                  ]
                },
                "description": "Per-post classifier labels, bullish → bearish."
              },
              "directional_label": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "bullish",
                    "bullish_nuance",
                    "bearish_nuance",
                    "bearish"
                  ]
                },
                "description": "The labels that count as a call / vote (everything but neutral)."
              },
              "stance": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "bullish",
                    "bearish",
                    "neutral"
                  ]
                }
              },
              "bias": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "bullish",
                    "bearish",
                    "balanced"
                  ]
                }
              },
              "tier_badge": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "top1",
                    "top5",
                    "top10",
                    "tracked"
                  ]
                }
              },
              "tier_reason": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "excluded",
                    "ineligible",
                    "news_feed",
                    "company",
                    "unscored",
                    "insufficient_calls",
                    "pool_too_small"
                  ]
                }
              },
              "breakdown_window": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "1d",
                    "3d",
                    "7d",
                    "30d"
                  ]
                }
              },
              "views_window": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "7d",
                    "30d"
                  ]
                }
              },
              "breakdown_lang": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "en",
                    "ko",
                    "zh",
                    "ja",
                    "es",
                    "pt",
                    "ru",
                    "hi",
                    "de",
                    "fr",
                    "tr",
                    "vi",
                    "id",
                    "it",
                    "th",
                    "pl",
                    "nl",
                    "uk"
                  ]
                }
              },
              "via": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "chatgpt",
                    "claude",
                    "mcp",
                    "gemini",
                    "perplexity",
                    "api"
                  ]
                }
              },
              "plan": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "free",
                    "pro",
                    "premium",
                    "enterprise"
                  ]
                }
              }
            }
          },
          "docs_url": {
            "type": "string",
            "format": "uri"
          },
          "as_of": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "DailyIndexPoint": {
        "type": "object",
        "required": [
          "date",
          "consensus_index",
          "consensus_index_30d_ma",
          "z_score",
          "bullish_analysts",
          "bearish_analysts",
          "total_analysts"
        ],
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "description": "UTC calendar day (end-of-day value; the current UTC day is never included)."
          },
          "consensus_index": {
            "type": [
              "number",
              "null"
            ],
            "minimum": -100,
            "maximum": 100,
            "description": "Daily raw Analyst Consensus Index: weighted bullish − bearish votes over total, −100 (all bearish) … +100 (all bullish). null = no vote that day."
          },
          "consensus_index_30d_ma": {
            "type": [
              "number",
              "null"
            ],
            "minimum": -100,
            "maximum": 100,
            "description": "30-day moving average of consensus_index (null until enough history)."
          },
          "z_score": {
            "type": [
              "number",
              "null"
            ],
            "description": "90-day rolling z-score of the 30-day MA, computed on its 0–100 rescale, 2 decimals. The site colours z ≥ +0.8 bullish and z ≤ −1.5 bearish."
          },
          "avg_sentiment_score": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "deprecated": true,
            "description": "Legacy unweighted mean sentiment (0–100). null once the stance pipeline is on; use consensus_index."
          },
          "bullish_analysts": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Analysts whose latest stance that day was bullish."
          },
          "bearish_analysts": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "total_analysts": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "bullish_analysts + bearish_analysts (neutral analysts do not vote)."
          },
          "bullish_opinions": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Directional posts published that day, bullish."
          },
          "bearish_opinions": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "total_opinions": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          }
        }
      },
      "ConsensusPublic": {
        "type": "object",
        "description": "No key: the latest end-of-day index point for the asset (what the asset page's band shows) with the bull / bear case and the links to quote.",
        "required": [
          "asset",
          "asset_name",
          "asset_class",
          "date",
          "consensus_index",
          "plan",
          "page_url",
          "cite_as",
          "data_by",
          "as_of"
        ],
        "properties": {
          "asset": {
            "type": "string",
            "description": "Canonical symbol."
          },
          "asset_name": {
            "type": "string"
          },
          "asset_class": {
            "type": "string",
            "enum": [
              "crypto",
              "equities",
              "indices",
              "commodities"
            ]
          },
          "date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "UTC day of the reading (null = no index yet for this asset)."
          },
          "consensus_index": {
            "type": [
              "number",
              "null"
            ],
            "minimum": -100,
            "maximum": 100,
            "description": "Analyst Consensus Index: −100 all bearish … +100 all bullish (one analyst = one vote, decay × accuracy weighted; see /methodology)."
          },
          "consensus_index_30d_ma": {
            "type": [
              "number",
              "null"
            ],
            "minimum": -100,
            "maximum": 100
          },
          "bullish_percent": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "description": "round((consensus_index + 100) / 2) — the bullish share the site shows."
          },
          "bearish_percent": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "description": "100 − bullish_percent."
          },
          "total_analysts": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Analysts voting in that day's index."
          },
          "bull_case": {
            "type": [
              "string",
              "null"
            ],
            "description": "One-line bull case for the window (null when no bullish consensus formed)."
          },
          "bear_case": {
            "type": [
              "string",
              "null"
            ]
          },
          "window": {
            "type": "string",
            "enum": [
              "30d"
            ],
            "description": "Window of the bull / bear case."
          },
          "plan": {
            "type": "string",
            "enum": [
              "public"
            ]
          },
          "history": {
            "type": "string",
            "description": "How to get the daily history (API key)."
          },
          "page_url": {
            "type": "string",
            "format": "uri",
            "description": "The canonical page on the site for this answer, UTM-tagged for the calling surface (`via`). Link it in every answer."
          },
          "top_analysts_url": {
            "type": "string",
            "format": "uri",
            "description": "The asset's analysts ranked by accuracy (site page)."
          },
          "methodology_url": {
            "type": "string",
            "format": "uri",
            "description": "How the numbers are made."
          },
          "cite_as": {
            "type": "string",
            "description": "Attribution line + the untagged canonical URL, e.g. \"Data by CryptoQuant Consensus — https://consensus.cryptoquant.com/consensus/btc\"."
          },
          "data_by": {
            "type": "string",
            "enum": [
              "Data by CryptoQuant Consensus"
            ],
            "description": "Show this next to the numbers."
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "description": "Generation time of the payload (UTC)."
          }
        }
      },
      "AgentNarrative": {
        "type": "object",
        "required": [
          "stance",
          "analyst_count",
          "post_count"
        ],
        "properties": {
          "theme": {
            "type": [
              "string",
              "null"
            ],
            "description": "Short thesis label (e.g. \"ETF FLOWS\")."
          },
          "headline": {
            "type": [
              "string",
              "null"
            ]
          },
          "stance": {
            "type": "string",
            "enum": [
              "bullish",
              "bearish",
              "neutral"
            ]
          },
          "analyst_count": {
            "type": "integer",
            "minimum": 0
          },
          "post_count": {
            "type": "integer",
            "minimum": 0
          },
          "summary": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "AgentAnalystView": {
        "type": "object",
        "required": [
          "handle",
          "stance",
          "thesis",
          "post_count",
          "consistency_pct",
          "profile_url"
        ],
        "properties": {
          "handle": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "stance": {
            "type": "string",
            "enum": [
              "bullish",
              "bearish"
            ]
          },
          "thesis": {
            "type": "string",
            "description": "The analyst's representative thesis in the window."
          },
          "excerpt": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "description": "The first ≤ 200 characters of the representative post (sentence / word boundary, ellipsis when cut, original language). Quote with source_url; the full statement is provided under an Integration agreement only — per API key, contact ' + SALES_EMAIL + '."
          },
          "source_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "The underlying post."
          },
          "source_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "tweet",
              "quicktake",
              "research",
              "news",
              "seekingalpha",
              "tradingview",
              "substack",
              "youtube",
              "telegram",
              "bluesky",
              null
            ],
            "description": "Stored source type of the post."
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "post_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Directional posts by the analyst on the asset in the window."
          },
          "consistency_pct": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Share of those posts on the dominant side (≥ 60)."
          },
          "profile_url": {
            "type": "string",
            "format": "uri",
            "description": "The analyst page (cite this)."
          }
        }
      },
      "AnalystViewsResponse": {
        "type": "object",
        "required": [
          "asset",
          "asset_name",
          "window",
          "narratives",
          "analyst_views",
          "analyst_views_total",
          "page_url",
          "cite_as",
          "data_by",
          "as_of"
        ],
        "properties": {
          "asset": {
            "type": "string"
          },
          "asset_name": {
            "type": "string"
          },
          "window": {
            "type": "string",
            "enum": [
              "7d",
              "30d"
            ]
          },
          "bullish_posts": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Directional posts in the window, bullish (post share — the index is on /consensus)."
          },
          "bearish_posts": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "bullish_pct": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 100
          },
          "bearish_pct": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 100
          },
          "bull_case": {
            "type": [
              "string",
              "null"
            ]
          },
          "bear_case": {
            "type": [
              "string",
              "null"
            ]
          },
          "narratives": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AgentNarrative"
            }
          },
          "analyst_views": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AgentAnalystView"
            },
            "description": "Most active first, at most 12."
          },
          "analyst_views_total": {
            "type": "integer",
            "minimum": 0,
            "description": "How many analysts qualified (the page lists them all)."
          },
          "note": {
            "type": "string",
            "description": "What the fields mean — quote the caveat with the numbers."
          },
          "page_url": {
            "type": "string",
            "format": "uri",
            "description": "The canonical page on the site for this answer, UTM-tagged for the calling surface (`via`). Link it in every answer."
          },
          "top_analysts_url": {
            "type": "string",
            "format": "uri",
            "description": "The asset's analysts ranked by accuracy (site page)."
          },
          "methodology_url": {
            "type": "string",
            "format": "uri",
            "description": "How the numbers are made."
          },
          "cite_as": {
            "type": "string",
            "description": "Attribution line + the untagged canonical URL, e.g. \"Data by CryptoQuant Consensus — https://consensus.cryptoquant.com/consensus/btc\"."
          },
          "data_by": {
            "type": "string",
            "enum": [
              "Data by CryptoQuant Consensus"
            ],
            "description": "Show this next to the numbers."
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "description": "Generation time of the payload (UTC)."
          }
        }
      },
      "AgentCall": {
        "type": "object",
        "required": [
          "handle",
          "stance",
          "excerpt",
          "published_at",
          "profile_url"
        ],
        "properties": {
          "handle": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "stance": {
            "type": "string",
            "enum": [
              "bullish",
              "bearish"
            ]
          },
          "excerpt": {
            "type": "string",
            "maxLength": 200,
            "description": "The first ≤ 200 characters of the call's post (sentence / word boundary, ellipsis when cut, original language); never the full text on this key-free endpoint."
          },
          "source_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "source_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "tweet",
              "quicktake",
              "research",
              "news",
              "seekingalpha",
              "tradingview",
              "substack",
              "youtube",
              "telegram",
              "bluesky",
              null
            ]
          },
          "published_at": {
            "type": "string",
            "format": "date-time"
          },
          "profile_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "RecentCallsResponse": {
        "type": "object",
        "required": [
          "asset",
          "asset_name",
          "count",
          "calls",
          "definition",
          "page_url",
          "cite_as",
          "data_by",
          "as_of"
        ],
        "properties": {
          "asset": {
            "type": "string"
          },
          "asset_name": {
            "type": "string"
          },
          "count": {
            "type": "integer",
            "minimum": 0
          },
          "calls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AgentCall"
            },
            "description": "Newest first."
          },
          "definition": {
            "type": "string",
            "description": "What a call is — quote with the list."
          },
          "page_url": {
            "type": "string",
            "format": "uri",
            "description": "The canonical page on the site for this answer, UTM-tagged for the calling surface (`via`). Link it in every answer."
          },
          "top_analysts_url": {
            "type": "string",
            "format": "uri",
            "description": "The asset's analysts ranked by accuracy (site page)."
          },
          "methodology_url": {
            "type": "string",
            "format": "uri",
            "description": "How the numbers are made."
          },
          "cite_as": {
            "type": "string",
            "description": "Attribution line + the untagged canonical URL, e.g. \"Data by CryptoQuant Consensus — https://consensus.cryptoquant.com/consensus/btc\"."
          },
          "data_by": {
            "type": "string",
            "enum": [
              "Data by CryptoQuant Consensus"
            ],
            "description": "Show this next to the numbers."
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "description": "Generation time of the payload (UTC)."
          }
        }
      },
      "ConsensusSeries": {
        "type": "object",
        "description": "Premium / Enterprise plans: the requested window, oldest first.",
        "required": [
          "asset",
          "period",
          "granularity",
          "count",
          "data"
        ],
        "properties": {
          "asset": {
            "type": "string",
            "description": "Canonical symbol."
          },
          "period": {
            "type": "object",
            "required": [
              "start",
              "end"
            ],
            "properties": {
              "start": {
                "type": "string",
                "format": "date",
                "description": "First UTC day requested (today − days)."
              },
              "end": {
                "type": "string",
                "format": "date",
                "description": "Yesterday UTC."
              }
            }
          },
          "granularity": {
            "type": "string",
            "enum": [
              "daily"
            ]
          },
          "count": {
            "type": "integer",
            "minimum": 0,
            "description": "Rows in `data` (0 for an asset without index rows in the range)."
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DailyIndexPoint"
            }
          }
        }
      },
      "ConsensusLatest": {
        "type": "object",
        "description": "Free plan: the latest end-of-day point as a flat object (no `data` array).",
        "required": [
          "asset",
          "date",
          "plan"
        ],
        "allOf": [
          {
            "$ref": "#/components/schemas/DailyIndexPoint"
          },
          {
            "type": "object",
            "properties": {
              "asset": {
                "type": "string"
              },
              "plan": {
                "type": "string",
                "enum": [
                  "free"
                ]
              },
              "upgrade_message": {
                "type": "string"
              }
            }
          }
        ]
      },
      "BreakdownAnalyst": {
        "type": "object",
        "required": [
          "handle",
          "display_name",
          "avatar_url",
          "x_url",
          "profile_url"
        ],
        "properties": {
          "handle": {
            "type": "string"
          },
          "display_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatar_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "May be a generated placeholder."
          },
          "x_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Only when the X handle is known — never synthesised."
          },
          "profile_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "CryptoQuant profile, when the author has one."
          }
        }
      },
      "BreakdownSource": {
        "type": "object",
        "description": "One source post. Exactly one of `statement` (only on a key with Integration raw access — per-key clearance, not a plan: the original title or text) or `excerpt` (every other key: the first ≤ 200 characters) is present; `BreakdownResponse.source_text` says which.",
        "required": [
          "analyst_handle",
          "url",
          "source_type",
          "published_at"
        ],
        "oneOf": [
          {
            "required": [
              "statement"
            ]
          },
          {
            "required": [
              "excerpt"
            ]
          }
        ],
        "properties": {
          "analyst_handle": {
            "type": [
              "string",
              "null"
            ]
          },
          "statement": {
            "type": "string",
            "description": "Original post title or text, original language — provided under an Integration agreement only, per API key (api_keys.raw_access); absent on every other key whatever its plan (Premium, Enterprise, admin). Integration use that needs the original text: contact sales@cryptoquant.com."
          },
          "excerpt": {
            "type": "string",
            "maxLength": 200,
            "description": "The first ≤ 200 characters of the original post (sentence / word boundary, ellipsis when cut, original language) — every key without Integration raw access; absent on a cleared key. Read the full post at `url`."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The underlying post."
          },
          "source_type": {
            "type": "string",
            "enum": [
              "tweet",
              "quicktake",
              "research",
              "news",
              "seekingalpha",
              "tradingview",
              "substack",
              "youtube",
              "telegram",
              "bluesky"
            ],
            "description": "Stored source type (`tweet` = X, `quicktake` = CryptoQuant)."
          },
          "published_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BreakdownViewpoint": {
        "type": "object",
        "required": [
          "id",
          "stance",
          "analyst_count",
          "title",
          "thesis",
          "analysts",
          "sources"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Cluster id (opaque)."
          },
          "stance": {
            "type": "string",
            "enum": [
              "bullish",
              "bearish"
            ]
          },
          "analyst_count": {
            "type": "integer",
            "minimum": 0
          },
          "title": {
            "type": [
              "string",
              "null"
            ],
            "description": "Localised when `lang` ≠ en and a translation exists."
          },
          "thesis": {
            "type": [
              "string",
              "null"
            ],
            "description": "Short thesis label the viewpoint is grouped by."
          },
          "analysts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BreakdownAnalyst"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BreakdownSource"
            }
          }
        }
      },
      "BreakdownResponse": {
        "type": "object",
        "required": [
          "asset",
          "updated_at",
          "window",
          "lang",
          "source_text",
          "note",
          "summary",
          "overall",
          "analyst_consensus"
        ],
        "properties": {
          "asset": {
            "type": "object",
            "required": [
              "symbol",
              "name"
            ],
            "properties": {
              "symbol": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Most recent source post in the response (now when none)."
          },
          "window": {
            "type": "string",
            "enum": [
              "1d",
              "3d",
              "7d",
              "30d"
            ]
          },
          "lang": {
            "type": "string",
            "enum": [
              "en",
              "ko",
              "zh",
              "ja",
              "es",
              "pt",
              "ru",
              "hi",
              "de",
              "fr",
              "tr",
              "vi",
              "id",
              "it",
              "th",
              "pl",
              "nl",
              "uk"
            ]
          },
          "source_text": {
            "type": "string",
            "enum": [
              "statement",
              "excerpt"
            ],
            "description": "Which source-text field this key received: `statement` (original statement (full post title / text) — Integration agreement keys only (per-key raw_access clearance, not a plan); contact sales@cryptoquant.com) or `excerpt` (excerpt only: the first ≤ 200 characters of the original post (sentence / word boundary, original language) + the source url)."
          },
          "note": {
            "type": "string",
            "description": "One sentence saying what sources[] carries on this plan — show it with the sources."
          },
          "summary": {
            "type": "object",
            "required": [
              "total_opinions",
              "bullish_opinions",
              "bearish_opinions",
              "bullish_pct",
              "bearish_pct",
              "consensus_index",
              "z_score"
            ],
            "properties": {
              "total_opinions": {
                "type": "integer",
                "minimum": 0,
                "description": "bullish_opinions + bearish_opinions (neutral excluded)."
              },
              "bullish_opinions": {
                "type": "integer",
                "minimum": 0
              },
              "bearish_opinions": {
                "type": "integer",
                "minimum": 0
              },
              "bullish_pct": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 0,
                "maximum": 100,
                "description": "null when total_opinions is 0."
              },
              "bearish_pct": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 0,
                "maximum": 100
              },
              "consensus_index": {
                "type": [
                  "number",
                  "null"
                ],
                "minimum": -100,
                "maximum": 100,
                "description": "Latest daily index; does not vary by window; null for an asset without an index series."
              },
              "z_score": {
                "type": [
                  "number",
                  "null"
                ]
              }
            }
          },
          "overall": {
            "type": "object",
            "required": [
              "bull_case",
              "bear_case"
            ],
            "properties": {
              "bull_case": {
                "type": "object",
                "required": [
                  "title"
                ],
                "properties": {
                  "title": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Null when no bullish consensus has formed."
                  }
                }
              },
              "bear_case": {
                "type": "object",
                "required": [
                  "title"
                ],
                "properties": {
                  "title": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                }
              }
            }
          },
          "analyst_consensus": {
            "type": "object",
            "required": [
              "bullish",
              "bearish"
            ],
            "properties": {
              "bullish": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BreakdownViewpoint"
                }
              },
              "bearish": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BreakdownViewpoint"
                }
              }
            }
          }
        }
      },
      "StancePoint": {
        "type": "object",
        "required": [
          "date",
          "sentiment_score",
          "sentiment_score_key_calls",
          "key_calls_count"
        ],
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "description": "UTC calendar day."
          },
          "stance": {
            "type": [
              "number",
              "null"
            ],
            "minimum": -100,
            "maximum": 100,
            "description": "Canonical analyst stance on the asset for the day (−100 bearish … +100 bullish). Present only while the stance pipeline flag is on."
          },
          "confidence": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1,
            "description": "Confidence of `stance`, 0–1 (present with it)."
          },
          "post_count": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Directional posts behind `stance` (present with it)."
          },
          "sentiment_score": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "description": "0 (bearish) … 100 (bullish), integer-rounded. With the stance pipeline on it is the alias round((stance + 100) / 2)."
          },
          "sentiment_score_key_calls": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "deprecated": true,
            "description": "Score over golden (explicit price-direction) calls only; null when none, always null once the stance pipeline is on."
          },
          "key_calls_count": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Golden calls that day; aliases post_count once the stance pipeline is on."
          }
        }
      },
      "StanceSeries": {
        "type": "object",
        "description": "Premium / Enterprise plans: the requested window, oldest first.",
        "required": [
          "analyst_id",
          "asset",
          "period",
          "count",
          "data"
        ],
        "properties": {
          "analyst_id": {
            "type": "string",
            "format": "uuid"
          },
          "asset": {
            "type": "string",
            "description": "Canonical symbol."
          },
          "period": {
            "type": "object",
            "required": [
              "start",
              "end"
            ],
            "properties": {
              "start": {
                "type": "string",
                "format": "date"
              },
              "end": {
                "type": "string",
                "format": "date",
                "description": "Yesterday UTC."
              }
            }
          },
          "count": {
            "type": "integer",
            "minimum": 0
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StancePoint"
            }
          }
        }
      },
      "StanceLatest": {
        "type": "object",
        "description": "Reserved free-plan shape (not served since 2026-10-06): the latest end-of-day point as a flat object.",
        "required": [
          "analyst_id",
          "asset",
          "date",
          "plan"
        ],
        "properties": {
          "analyst_id": {
            "type": "string",
            "format": "uuid"
          },
          "asset": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date",
            "description": "UTC calendar day."
          },
          "stance": {
            "type": [
              "number",
              "null"
            ],
            "minimum": -100,
            "maximum": 100,
            "description": "Canonical analyst stance on the asset for the day (−100 bearish … +100 bullish). Present only while the stance pipeline flag is on."
          },
          "confidence": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1,
            "description": "Confidence of `stance`, 0–1 (present with it)."
          },
          "post_count": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Directional posts behind `stance` (present with it)."
          },
          "sentiment_score": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "description": "0 (bearish) … 100 (bullish), integer-rounded. With the stance pipeline on it is the alias round((stance + 100) / 2)."
          },
          "sentiment_score_key_calls": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "deprecated": true,
            "description": "Score over golden (explicit price-direction) calls only; null when none, always null once the stance pipeline is on."
          },
          "key_calls_count": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Golden calls that day; aliases post_count once the stance pipeline is on."
          },
          "plan": {
            "type": "string",
            "enum": [
              "free"
            ]
          },
          "upgrade_message": {
            "type": "string"
          }
        }
      },
      "AccuracyTier": {
        "type": "object",
        "description": "Accuracy percentile-tier badge for one asset class (Ki 2026-09-30). What people see is the badge, stated against all analysts: tier 1 = \"Top 1%\" (top 10% of the eligible tracked pool), 5 = \"Top 5%\" (top 50%), 10 = \"Top 10%\" (the rest of the eligible pool); null = \"Tracked\" (no badge, `reason` says why). Computed daily from the stored accuracy score; the precise position (pool_rank / pool_size / percentile) is for detail views and agents only.",
        "required": [
          "asset_class",
          "tier",
          "badge",
          "label",
          "eligible",
          "reason"
        ],
        "properties": {
          "asset_class": {
            "type": "string",
            "enum": [
              "crypto",
              "equities",
              "indices",
              "commodities",
              "macro"
            ]
          },
          "tier": {
            "type": [
              "integer",
              "null"
            ],
            "enum": [
              1,
              5,
              10,
              null
            ],
            "description": "Badge number: 1 = Top 1%, 5 = Top 5%, 10 = Top 10%; null = no badge (Tracked)."
          },
          "badge": {
            "type": "string",
            "enum": [
              "top1",
              "top5",
              "top10",
              "tracked"
            ],
            "description": "Stable key for the UI (i18n / icon)."
          },
          "label": {
            "type": "string",
            "enum": [
              "Top 1%",
              "Top 5%",
              "Top 10%",
              "Tracked"
            ],
            "description": "English badge text."
          },
          "eligible": {
            "type": "boolean",
            "description": "True when the analyst is inside the class pool (scored, not excluded, ≥ 30 directional calls). A thin pool (< 10) keeps eligible=true with tier null and reason pool_too_small."
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "excluded",
              "ineligible",
              "news_feed",
              "company",
              "unscored",
              "insufficient_calls",
              "pool_too_small",
              null
            ],
            "description": "Why tier is null; null when a tier is set. unscored = no accuracy score for this asset class."
          },
          "pool_rank": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 1,
            "description": "Midrank position from the top inside the eligible pool (1 = best; tied analysts share one position, e.g. 2.5)."
          },
          "pool_size": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Eligible analysts in the class when computed."
          },
          "percentile": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "description": "100 × pool_rank / pool_size: position from the top in percent (0 = best)."
          },
          "score_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Score source the tier was computed from (`v20`, or an active alternative such as `v20r-btc-amp31-dir`)."
          },
          "computed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "TopAnalystEntry": {
        "type": "object",
        "required": [
          "rank",
          "tier",
          "handle",
          "profile_url",
          "sources",
          "accuracy_score",
          "call_count",
          "bias"
        ],
        "properties": {
          "rank": {
            "type": "integer",
            "minimum": 1,
            "description": "Position in the asset's accuracy ranking among analysts active in the last three calendar months."
          },
          "tier": {
            "allOf": [
              {
                "$ref": "#/components/schemas/AccuracyTier"
              }
            ],
            "description": "The badge for the requested asset's class (tier_asset_class) — show this, not accuracy_score."
          },
          "handle": {
            "type": "string",
            "description": "X handle, or `<platform>:<slug>` for a platform-only analyst."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "profile_url": {
            "type": "string",
            "format": "uri",
            "description": "The analyst page on the site (cite this)."
          },
          "source_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Where the analyst publishes (X, CryptoQuant, TradingView, Seeking Alpha, Substack)."
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "twitter",
                "cryptoquant",
                "seekingalpha",
                "tradingview",
                "substack",
                "other"
              ]
            },
            "description": "Stored provenance of the analyst row (`twitter` = X)."
          },
          "role": {
            "type": [
              "string",
              "null"
            ]
          },
          "company": {
            "type": [
              "string",
              "null"
            ]
          },
          "category": {
            "type": [
              "string",
              "null"
            ],
            "description": "Analyst category label (e.g. `technical`, `macro`); free text, null when unset."
          },
          "citation_count": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Times cited by name in tracked news articles."
          },
          "accuracy_score": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "description": "Overall accuracy, 0–100: Empirical-Bayes-adjusted hit rate of directional calls vs. subsequent price, shrunk toward the pool mean for small samples. Comparative within an asset; NOT a win probability."
          },
          "accuracy_sample_size": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Evaluated calls behind accuracy_score; below ~10 is weak evidence."
          },
          "call_count": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "All-time directional (bullish or bearish) posts on tracked assets."
          },
          "bull_score": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "description": "Accuracy, 0–100, on calls made in bull market phases."
          },
          "bear_score": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "description": "Accuracy, 0–100, on calls made in bear market phases."
          },
          "short_score": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "description": "Accuracy, 0–100, of calls evaluated over the short horizon."
          },
          "long_score": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "description": "Accuracy, 0–100, of calls evaluated over the long horizon."
          },
          "balanced_score": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "description": "Mean of bull_score and bear_score when both exist."
          },
          "bullish_bias_pct": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "description": "Share of bullish among recent directional calls on the asset (50 = balanced). A stance, not a quality signal."
          },
          "bias": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "bullish",
              "bearish",
              "balanced",
              null
            ]
          },
          "last_post_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "TopAnalystsResponse": {
        "type": "object",
        "required": [
          "asset",
          "asset_name",
          "asset_class",
          "as_of",
          "scored",
          "ranking",
          "tier_asset_class",
          "count",
          "total_ranked",
          "total_tracked",
          "analysts",
          "score_notes"
        ],
        "properties": {
          "asset": {
            "type": "string"
          },
          "asset_name": {
            "type": "string"
          },
          "asset_class": {
            "type": "string",
            "enum": [
              "crypto",
              "equities",
              "indices",
              "commodities"
            ]
          },
          "as_of": {
            "type": "string",
            "format": "date-time"
          },
          "scored": {
            "type": "boolean",
            "description": "false = accuracy scoring does not cover this asset yet; scores are null and the order is the list order."
          },
          "ranking": {
            "type": "string",
            "description": "Plain-language statement of the sort rule."
          },
          "tier_asset_class": {
            "type": "string",
            "enum": [
              "crypto",
              "equities",
              "indices",
              "commodities",
              "macro"
            ],
            "description": "The asset class each entry's `tier` was read for."
          },
          "count": {
            "type": "integer",
            "minimum": 0
          },
          "total_ranked": {
            "type": "integer",
            "minimum": 0
          },
          "total_tracked": {
            "type": "integer",
            "minimum": 0
          },
          "analysts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TopAnalystEntry"
            }
          },
          "score_notes": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "What each score field means — quote the caveat with the number."
          },
          "list_url": {
            "type": "string",
            "format": "uri"
          },
          "methodology_url": {
            "type": "string",
            "format": "uri"
          },
          "docs_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "AnalystTrackRecord": {
        "type": "object",
        "required": [
          "handle",
          "slug",
          "profile_url",
          "sources",
          "activity",
          "track_record",
          "calls",
          "covered_assets",
          "as_of"
        ],
        "properties": {
          "handle": {
            "type": "string",
            "description": "X handle, or `<platform>:<slug>` for a platform-only analyst."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "profile_url": {
            "type": "string",
            "format": "uri",
            "description": "The analyst page on the site (cite this)."
          },
          "source_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Where the analyst publishes (X, CryptoQuant, TradingView, Seeking Alpha, Substack)."
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "twitter",
                "cryptoquant",
                "seekingalpha",
                "tradingview",
                "substack",
                "other"
              ]
            },
            "description": "Stored provenance of the analyst row (`twitter` = X)."
          },
          "role": {
            "type": [
              "string",
              "null"
            ]
          },
          "company": {
            "type": [
              "string",
              "null"
            ]
          },
          "category": {
            "type": [
              "string",
              "null"
            ],
            "description": "Analyst category label (e.g. `technical`, `macro`); free text, null when unset."
          },
          "slug": {
            "type": "string",
            "description": "Page slug (`/analyst/<slug>`)."
          },
          "follower_count": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "is_verified": {
            "type": "boolean"
          },
          "activity": {
            "type": "object",
            "required": [
              "last_activity_at",
              "active_last_3_months"
            ],
            "properties": {
              "last_activity_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "active_last_3_months": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "null = no activity on record (new or seed-only analyst), not \"inactive\"."
              }
            }
          },
          "track_record": {
            "type": "object",
            "required": [
              "accuracy_score",
              "call_count",
              "overall_rank",
              "category_ranks",
              "scored",
              "tier",
              "tiers"
            ],
            "properties": {
              "accuracy_score": {
                "type": [
                  "number",
                  "null"
                ],
                "minimum": 0,
                "maximum": 100,
                "description": "Overall accuracy, 0–100: Empirical-Bayes-adjusted hit rate of directional calls vs. subsequent price, shrunk toward the pool mean for small samples. Comparative within an asset; NOT a win probability."
              },
              "accuracy_sample_size": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 0,
                "description": "Evaluated calls behind accuracy_score; below ~10 is weak evidence."
              },
              "call_count": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 0,
                "description": "All-time directional (bullish or bearish) posts on tracked assets."
              },
              "bull_score": {
                "type": [
                  "number",
                  "null"
                ],
                "minimum": 0,
                "maximum": 100,
                "description": "Accuracy, 0–100, on calls made in bull market phases."
              },
              "bear_score": {
                "type": [
                  "number",
                  "null"
                ],
                "minimum": 0,
                "maximum": 100,
                "description": "Accuracy, 0–100, on calls made in bear market phases."
              },
              "short_score": {
                "type": [
                  "number",
                  "null"
                ],
                "minimum": 0,
                "maximum": 100,
                "description": "Accuracy, 0–100, of calls evaluated over the short horizon."
              },
              "long_score": {
                "type": [
                  "number",
                  "null"
                ],
                "minimum": 0,
                "maximum": 100,
                "description": "Accuracy, 0–100, of calls evaluated over the long horizon."
              },
              "balanced_score": {
                "type": [
                  "number",
                  "null"
                ],
                "minimum": 0,
                "maximum": 100,
                "description": "Mean of bull_score and bear_score when both exist."
              },
              "overall_rank": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "rank": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "total": {
                    "type": "integer",
                    "minimum": 1
                  }
                },
                "description": "Rank by accuracy_score among every analyst holding one."
              },
              "category_ranks": {
                "type": "object",
                "properties": {
                  "bull": {
                    "type": [
                      "object",
                      "null"
                    ],
                    "properties": {
                      "rank": {
                        "type": "integer",
                        "minimum": 1
                      },
                      "total": {
                        "type": "integer",
                        "minimum": 1
                      }
                    }
                  },
                  "bear": {
                    "type": [
                      "object",
                      "null"
                    ],
                    "properties": {
                      "rank": {
                        "type": "integer",
                        "minimum": 1
                      },
                      "total": {
                        "type": "integer",
                        "minimum": 1
                      }
                    }
                  },
                  "short": {
                    "type": [
                      "object",
                      "null"
                    ],
                    "properties": {
                      "rank": {
                        "type": "integer",
                        "minimum": 1
                      },
                      "total": {
                        "type": "integer",
                        "minimum": 1
                      }
                    }
                  },
                  "long": {
                    "type": [
                      "object",
                      "null"
                    ],
                    "properties": {
                      "rank": {
                        "type": "integer",
                        "minimum": 1
                      },
                      "total": {
                        "type": "integer",
                        "minimum": 1
                      }
                    }
                  }
                }
              },
              "best_ranking": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "category": {
                    "type": "string",
                    "enum": [
                      "bull",
                      "bear",
                      "short",
                      "long",
                      "overall"
                    ]
                  },
                  "rank": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "label": {
                    "type": "string"
                  },
                  "priority": {
                    "type": "integer"
                  }
                },
                "description": "The analyst's best top-10 placement across the categories, if any."
              },
              "scored": {
                "type": "boolean"
              },
              "tier": {
                "description": "Headline badge: the best tier across the analyst's scored asset classes (1 < 5 < 10, then class order). null = nothing stored for the analyst (show \"Tracked\").",
                "anyOf": [
                  {
                    "type": "object",
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/AccuracyTier"
                      }
                    ]
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "tiers": {
                "type": "object",
                "additionalProperties": {
                  "$ref": "#/components/schemas/AccuracyTier"
                },
                "description": "Every asset class with a stored tier row, keyed by class. A class absent here is unscored for this analyst."
              }
            }
          },
          "calls": {
            "type": [
              "object",
              "null"
            ],
            "required": [
              "total",
              "bullish",
              "bearish",
              "neutral",
              "by_source",
              "definition",
              "recent_bullish_bias_pct",
              "recent_bias"
            ],
            "properties": {
              "total": {
                "type": "integer",
                "minimum": 0
              },
              "bullish": {
                "type": "integer",
                "minimum": 0
              },
              "bearish": {
                "type": "integer",
                "minimum": 0
              },
              "neutral": {
                "type": "integer",
                "minimum": 0,
                "description": "Neutral labelled posts — reported for context, never a call."
              },
              "by_source": {
                "type": [
                  "object",
                  "null"
                ],
                "description": "The analyst's directional calls per source over the whole stored history (sums to `total`). `benzinga` is always 0 for a tracked analyst (sell-side authors are not on the roster). null while the breakdown function is not on the database.",
                "required": [
                  "x",
                  "cryptoquant",
                  "news",
                  "tradingview",
                  "seekingalpha",
                  "substack",
                  "benzinga",
                  "other"
                ],
                "properties": {
                  "x": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "cryptoquant": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "news": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "tradingview": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "seekingalpha": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "substack": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "benzinga": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "other": {
                    "type": "integer",
                    "minimum": 0
                  }
                }
              },
              "definition": {
                "type": "string",
                "description": "What one call is: one directional (bullish or bearish) item about one tracked asset, every source, whole history; an article on several tickers counts once per article × ticker pair."
              },
              "recent_bullish_bias_pct": {
                "type": [
                  "number",
                  "null"
                ],
                "minimum": 0,
                "maximum": 100,
                "description": "Bullish share of the last 30 directional posts within three months."
              },
              "recent_bias": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "bullish",
                  "bearish",
                  "balanced",
                  null
                ]
              }
            }
          },
          "covered_assets": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "symbol",
                "asset_class",
                "last_post_at"
              ],
              "properties": {
                "symbol": {
                  "type": "string"
                },
                "asset_class": {
                  "type": "string",
                  "enum": [
                    "crypto",
                    "equities",
                    "indices",
                    "commodities"
                  ]
                },
                "last_post_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time"
                }
              }
            },
            "description": "Most recent post first."
          },
          "citation_count": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "score_notes": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "methodology_url": {
            "type": "string",
            "format": "uri"
          },
          "docs_url": {
            "type": "string",
            "format": "uri"
          },
          "as_of": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    }
  }
}
