{
  "openapi": "3.0.3",
  "info": {
    "title": "SCAND.Ai API",
    "description": "Independent AI industry monitoring. Track emerging controversies, key figures, noise levels, and state transitions across social media and news feeds.",
    "version": "1.0.0",
    "contact": { "url": "https://scand.ai" }
  },
  "servers": [{ "url": "https://scand.ai/api" }],
  "security": [{ "ApiKeyAuth": [] }],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key from scand.ai/pricing. Unauthenticated requests limited to 30/day."
      }
    },
    "schemas": {
      "Topic": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "slug": { "type": "string" },
          "title": { "type": "string" },
          "state": { "type": "string", "enum": ["trending", "spike", "controversy", "scandal", "resolved"] },
          "category": { "type": "string", "enum": ["safety", "ethics", "ip_copyright", "labor", "regulation", "corporate", "military", "other"], "nullable": true },
          "noise_level": { "type": "number", "minimum": 0, "maximum": 100 },
          "summary_press": { "type": "string", "nullable": true },
          "summary_simple": { "type": "string", "nullable": true },
          "key_points": { "type": "string", "nullable": true },
          "forecast": { "type": "string", "nullable": true },
          "tldr": { "type": "string", "nullable": true },
          "why_it_matters": { "type": "string", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "TopicDetail": {
        "allOf": [
          { "$ref": "#/components/schemas/Topic" },
          {
            "type": "object",
            "properties": {
              "parties": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "display_name": { "type": "string" },
                    "side": { "type": "string", "enum": ["critic", "defender", "neutral"] },
                    "stance_summary": { "type": "string", "nullable": true }
                  }
                }
              },
              "noise": {
                "type": "object",
                "properties": {
                  "reach": { "type": "number" },
                  "engagement": { "type": "number" },
                  "star_power": { "type": "number" },
                  "duration": { "type": "number" },
                  "cross_platform": { "type": "number" },
                  "polarity": { "type": "number" },
                  "industry_impact": { "type": "number" },
                  "total": { "type": "number" },
                  "decay": { "type": "number" }
                }
              }
            }
          }
        ]
      },
      "Star": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "slug": { "type": "string" },
          "display_name": { "type": "string" },
          "tier": { "type": "string", "enum": ["S", "A", "B", "C"] },
          "score": { "type": "number" },
          "bio": { "type": "string", "nullable": true },
          "avatar_url": { "type": "string", "nullable": true }
        }
      },
      "Pulse": {
        "type": "object",
        "properties": {
          "active": { "type": "integer", "description": "Active (non-resolved) topics with analysis" },
          "breaking": { "type": "integer", "description": "Topics in scandal state or noise >= 80" },
          "updates_today": { "type": "integer", "description": "Content items ingested in last 24h" },
          "hottest": {
            "type": "object",
            "nullable": true,
            "properties": {
              "slug": { "type": "string" },
              "title": { "type": "string" },
              "noise_delta": { "type": "number" }
            }
          },
          "content_1h": { "type": "integer" },
          "content_24h": { "type": "integer" },
          "analyses_24h": { "type": "integer" },
          "accent_t": { "type": "integer", "minimum": 0, "maximum": 4, "nullable": true, "description": "AUTO-accent bucket on the blue→plum→red activity ramp (0 calm … 2 typical/plum … 4 hot). null until the nightly DSA cron has run." }
        }
      },
      "Activity": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "star_id": { "type": "integer" },
          "display_name": { "type": "string" },
          "source": { "type": "string" },
          "headline": { "type": "string" },
          "engagement_score": { "type": "number" },
          "url": { "type": "string", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string" }
        }
      }
    }
  },
  "paths": {
    "/topics": {
      "get": {
        "summary": "List active topics",
        "description": "Returns up to 50 active AI controversy topics, ordered by noise level.",
        "tags": ["Topics"],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Array of topics",
            "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Topic" } } } }
          }
        }
      }
    },
    "/topics/{slug}": {
      "get": {
        "summary": "Get topic detail",
        "description": "Full topic with parties, noise breakdown, and analysis.",
        "tags": ["Topics"],
        "parameters": [
          { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Topic detail",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TopicDetail" } } }
          },
          "404": {
            "description": "Topic not found",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/stars": {
      "get": {
        "summary": "List tracked stars",
        "description": "Key figures in AI tracked by SCAND.Ai, with influence tier and score.",
        "tags": ["Stars"],
        "responses": {
          "200": {
            "description": "Array of stars",
            "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Star" } } } }
          }
        }
      }
    },
    "/stars/{slug}": {
      "get": {
        "summary": "Get star detail",
        "description": "Star with identities (social accounts) and associated controversies.",
        "tags": ["Stars"],
        "parameters": [
          { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Star detail" },
          "404": { "description": "Star not found" }
        }
      }
    },
    "/activity": {
      "get": {
        "summary": "Star activity feed",
        "description": "Latest notable posts from tracked stars. Filter by star_id.",
        "tags": ["Activity"],
        "parameters": [
          { "name": "star_id", "in": "query", "schema": { "type": "integer" }, "description": "Filter by star ID" }
        ],
        "responses": {
          "200": {
            "description": "Array of activity items",
            "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Activity" } } } }
          }
        }
      }
    },
    "/pulse": {
      "get": {
        "summary": "Live platform stats",
        "description": "Real-time counts: active topics, breaking stories, content velocity, hottest topic.",
        "tags": ["Stats"],
        "responses": {
          "200": {
            "description": "Pulse data",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Pulse" } } }
          }
        }
      }
    },
    "/ws": {
      "get": {
        "summary": "WebSocket connection",
        "description": "Upgrade to WebSocket for real-time events: noise_update, state_change, new_topic.",
        "tags": ["Real-time"],
        "responses": {
          "101": { "description": "WebSocket upgrade" }
        }
      }
    },
    "/export/topics": {
      "get": {
        "summary": "Export all topics (NDJSON)",
        "description": "Full dataset export including parties, timeline, and noise history. Requires Pro or Enterprise API key.",
        "tags": ["Export"],
        "security": [{ "ApiKeyAuth": [] }],
        "responses": {
          "200": {
            "description": "NDJSON stream — one topic per line",
            "content": { "application/x-ndjson": {} }
          },
          "403": { "description": "Pro/Enterprise API key required" }
        }
      }
    },
    "/export/stats": {
      "get": {
        "summary": "Export aggregate stats",
        "description": "Platform-wide statistics: content by source, daily volume, analysis coverage. Requires Pro or Enterprise API key.",
        "tags": ["Export"],
        "security": [{ "ApiKeyAuth": [] }],
        "responses": {
          "200": {
            "description": "Stats JSON",
            "content": { "application/json": {} }
          },
          "403": { "description": "Pro/Enterprise API key required" }
        }
      }
    },
    "/alerts": {
      "get": {
        "summary": "List alert preferences",
        "description": "List configured email alert preferences for the authenticated API key.",
        "tags": ["Alerts"],
        "security": [{ "ApiKeyAuth": [] }],
        "responses": {
          "200": { "description": "Array of alert preferences" },
          "401": { "description": "API key required" }
        }
      },
      "post": {
        "summary": "Create alert preference",
        "description": "Create an email alert to receive notifications when controversies match your criteria.",
        "tags": ["Alerts"],
        "security": [{ "ApiKeyAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email", "frequency"],
                "properties": {
                  "email": { "type": "string", "format": "email" },
                  "frequency": { "type": "string", "enum": ["instant", "daily", "weekly"] },
                  "min_noise": { "type": "integer", "default": 50, "description": "Minimum noise level to trigger alert (0-100)" },
                  "categories": { "type": "array", "items": { "type": "string", "enum": ["safety", "ethics", "ip_copyright", "labor", "regulation", "corporate", "military", "other"] } }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Alert created", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "integer" } } } } } },
          "400": { "description": "Missing or invalid parameters" },
          "401": { "description": "API key required" }
        }
      }
    },
    "/alerts/{id}": {
      "delete": {
        "summary": "Delete alert preference",
        "tags": ["Alerts"],
        "security": [{ "ApiKeyAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": { "description": "Alert deleted" },
          "404": { "description": "Alert not found" }
        }
      }
    },
    "/billing/checkout": {
      "post": {
        "summary": "Create Stripe checkout session",
        "description": "Initiate a Stripe Checkout session for a Pro or Enterprise subscription.",
        "tags": ["Billing"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["tier", "email"],
                "properties": {
                  "tier": { "type": "string", "enum": ["pro", "enterprise"] },
                  "email": { "type": "string", "format": "email" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Checkout session URL", "content": { "application/json": { "schema": { "type": "object", "properties": { "url": { "type": "string", "format": "uri" } } } } } },
          "400": { "description": "Invalid parameters" },
          "503": { "description": "Billing not configured" }
        }
      }
    },
    "/webhooks": {
      "get": {
        "summary": "List webhooks",
        "description": "List registered webhook endpoints for the authenticated API key.",
        "tags": ["Webhooks"],
        "security": [{ "ApiKeyAuth": [] }],
        "responses": {
          "200": { "description": "Array of webhook configurations" }
        }
      },
      "post": {
        "summary": "Create webhook",
        "description": "Register a webhook URL to receive events: topic.created, topic.state_change, noise.spike, content.breaking.",
        "tags": ["Webhooks"],
        "security": [{ "ApiKeyAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["url", "events"],
                "properties": {
                  "url": { "type": "string", "format": "uri" },
                  "events": { "type": "array", "items": { "type": "string", "enum": ["topic.created", "topic.state_change", "noise.spike", "content.breaking"] } }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Webhook created with signing secret" },
          "403": { "description": "Pro/Enterprise API key required" }
        }
      }
    },
    "/webhooks/{id}": {
      "delete": {
        "summary": "Delete webhook",
        "tags": ["Webhooks"],
        "security": [{ "ApiKeyAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": { "description": "Webhook deleted" },
          "404": { "description": "Webhook not found" }
        }
      }
    }
  }
}
