{
  "openapi": "3.1.0",
  "info": {
    "title": "Positive Search — Agents Gate API",
    "version": "1.2.0",
    "description": "Free JSON API for a news-sentiment index from -1 (extremely bearish) to +1 (extremely bullish) for Bitcoin, Gold and Oil. Recomputed hourly, plus an immediate extra run when the asset's price moves sharply. Open: no key, no account, no quota. The index measures the tone of news coverage; it does not forecast price. Every reading is a snapshot with a timestamp — quote fetched_at with the value, re-fetch after expires_at. Canonical machine entry point: /.well-known/agents-gate.json. Human page: /agents-gate.",
    "contact": { "email": "hi@positivesearch.app" }
  },
  "servers": [{ "url": "https://positivesearch.app" }],
  "paths": {
    "/.well-known/agents-gate.json": {
      "get": {
        "summary": "Agents Gate — everything at once",
        "description": "One request returns the current readings for all three assets (index, blended, timestamps, top narratives), honest limits, the endpoint map, citation rules and verification artifacts. Start here.",
        "responses": { "200": { "description": "Gate document", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } } }
      }
    },
    "/api/v35/latest": {
      "get": {
        "summary": "Current reading for one asset",
        "parameters": [{ "$ref": "#/components/parameters/asset" }],
        "responses": {
          "200": { "description": "Latest run", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Reading" } } } },
          "404": { "description": "No data computed yet" }
        }
      }
    },
    "/api/v35/sentiment": {
      "get": {
        "summary": "Index history, last 7 days",
        "description": "The blended index of every saved run in the last 7 days — the same series the site's chart draws. Older history is not served over HTTP; it is archived in a tamper-evident hash chain (see the gate's tamper_evident_history).",
        "parameters": [{ "$ref": "#/components/parameters/asset" }],
        "responses": { "200": { "description": "Time series", "content": { "application/json": { "schema": {
          "type": "object",
          "properties": {
            "asset": { "type": "string" },
            "series": { "type": "array", "items": { "type": "object", "properties": {
              "t": { "type": "integer", "description": "Unix epoch seconds of the run" },
              "v": { "type": "number", "description": "Blended index at that run, -1..+1" } } } }
          }, "additionalProperties": true } } } } }
      }
    },
    "/api/v35/candles": {
      "get": {
        "summary": "Price candles for the same instrument",
        "description": "Hourly OHLC for a 7-day window from Pyth benchmarks (BTC: Crypto.BTC/USD, Gold: Metal.XAU/USD, Oil: Brent spot), aligned with the index window.",
        "parameters": [{ "$ref": "#/components/parameters/asset" }],
        "responses": { "200": { "description": "TradingView-style history object (t/o/h/l/c arrays)", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } } }
      }
    },
    "/api/v35/polymarket": {
      "get": {
        "summary": "Prediction-market leg (BTC and OIL only)",
        "description": "Crowd price-expectation skew read from Polymarket's public price-ladder markets: per-ladder legs with liquidity, 24h volume and skew, blended by fresh money. A structural, slow signal — touch-by-deadline odds, not an hourly read.",
        "parameters": [{ "$ref": "#/components/parameters/assetPoly" }],
        "responses": { "200": { "description": "Blended expectations", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } } }
      }
    },
    "/api/v35/go": {
      "get": {
        "summary": "Redirect to a source article",
        "parameters": [{ "name": "a", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Opaque article id (gid) from a reading's articles or narrative members" }],
        "responses": { "302": { "description": "Redirect to the original article" } }
      }
    }
  },
  "components": {
    "parameters": {
      "asset": { "name": "asset", "in": "query", "required": false, "schema": { "type": "string", "enum": ["BTC", "GOLD", "OIL"], "default": "BTC" } },
      "assetPoly": { "name": "asset", "in": "query", "required": false, "schema": { "type": "string", "enum": ["BTC", "OIL"], "default": "BTC" } }
    },
    "schemas": {
      "Reading": {
        "type": "object",
        "description": "One run of the index for one asset. index = news alone; blended = news folded with X chatter and Polymarket odds — blended is the headline number the site shows and the one to quote.",
        "properties": {
          "asset": { "type": "string", "enum": ["BTC", "GOLD", "OIL"] },
          "index": { "type": "number", "minimum": -1, "maximum": 1, "description": "News-only sentiment index" },
          "blended": { "type": "number", "minimum": -1, "maximum": 1, "description": "News + X + Polymarket. Quote this one." },
          "fetched_at": { "type": "string", "format": "date-time", "description": "When this reading was measured (UTC)" },
          "expires_at": { "type": "string", "format": "date-time", "description": "When it stops being the current reading. if now > expires_at → re-fetch" },
          "refresh_seconds": { "type": "integer", "description": "Nominal recompute cadence (3600)" },
          "is_stale": { "type": "boolean", "description": "true — this reading has outlived expires_at: historical, not current" },
          "trigger": { "type": "string", "enum": ["hourly", "price-move"], "description": "What started this run: the hourly schedule, or a sharp price move (extra run)" },
          "change_1h": { "type": ["number", "null"], "description": "Blended (news+X) index now minus ~1 hour ago; null when no run exists near that moment" },
          "change_24h": { "type": ["number", "null"], "description": "Same, versus ~24 hours ago" },
          "change_7d": { "type": ["number", "null"], "description": "Same, versus ~7 days ago (the edge of the served history window)" },
          "state": { "type": "string", "enum": ["flat", "slightly_bullish", "mildly_bullish", "strongly_bullish", "extremely_bullish", "slightly_bearish", "mildly_bearish", "strongly_bearish", "extremely_bearish"], "description": "Machine-readable label of blended, using the exact thresholds the site's dashboard uses: |v| < 0.005 flat, < 0.15 slightly, < 0.35 mildly, < 0.60 strongly, else extremely" },
          "methodology_version": { "type": "string", "description": "Opaque comparability label (e.g. v4-2026-07-19): readings sharing it are computed the same way and comparable with each other; a different label marks a break in the series" },
          "confidence_basis": { "type": "object", "description": "Facts to compose your own confidence from — deliberately NO invented composite scalar", "properties": {
            "articles_scored": { "type": "integer", "description": "Headlines scored in this run" },
            "distinct_sources": { "type": "integer", "description": "Distinct publishers among them" },
            "fresh_share_24h": { "type": ["number", "null"], "description": "Share of articles published within the last 24h" },
            "cross_source_agreement": { "type": ["number", "null"], "description": "Mass-weighted mean of per-narrative agreement (1 − σ of member scores)" } } },
          "bull_share": { "type": "number", "minimum": 0, "maximum": 1, "description": "Bullish share of conviction-weighted news mass (0.5 = balanced)" },
          "narratives": { "type": "array", "items": { "$ref": "#/components/schemas/Narrative" } },
          "x": { "type": "object", "additionalProperties": true, "description": "X (Twitter) sentiment card from curated trusted handles; carries its own fetched_at and stale flag" },
          "articles": { "type": "array", "items": { "$ref": "#/components/schemas/Article" }, "description": "Every scored headline of this run" }
        },
        "additionalProperties": true
      },
      "Narrative": {
        "type": "object",
        "description": "A recurring story extracted from the run's headlines. mass is the bar length on the site; wide coverage counts by design (echo included).",
        "properties": {
          "label": { "type": "string" },
          "summary": { "type": "string" },
          "sentiment": { "type": "number", "minimum": -1, "maximum": 1 },
          "mass": { "type": "number", "description": "Σ materiality over member articles — the narrative's weight" },
          "count": { "type": "integer", "description": "Member articles" },
          "sources": { "type": "integer", "description": "Distinct publishers" },
          "agreement": { "type": "number", "minimum": 0, "maximum": 1, "description": "1 − σ of member scores: how much the member articles agree on direction" },
          "members": { "type": "array", "items": { "$ref": "#/components/schemas/Article" } }
        },
        "additionalProperties": true
      },
      "Article": {
        "type": "object",
        "properties": {
          "title": { "type": "string" },
          "source": { "type": "string" },
          "score": { "type": "number", "minimum": -1, "maximum": 1 },
          "url": { "type": "string" },
          "published": { "type": "string", "format": "date-time" },
          "age_hours": { "type": "number" }
        },
        "additionalProperties": true
      }
    }
  }
}
