{
  "openapi": "3.1.0",
  "info": {
    "title": "Rhetoric Audit API",
    "version": "2.1.4",
    "summary": "Forensic media analysis API",
    "description": "Endpoints for single-article forensic analysis (FME v18.6) and multi-source Intelligence Briefs across X, Reddit, YouTube, News, and the open Web. All endpoints require an authenticated Supabase session (see securitySchemes).",
    "contact": {
      "name": "Rhetoric Audit",
      "url": "https://www.rhetoricaudit.com",
      "email": "support@rhetoricaudit.com"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://www.rhetoricaudit.com/terms"
    },
    "termsOfService": "https://www.rhetoricaudit.com/terms"
  },
  "servers": [
    { "url": "https://www.rhetoricaudit.com", "description": "Production" }
  ],
  "tags": [
    { "name": "Analysis", "description": "Per-article forensic analysis (FME)" },
    { "name": "Intelligence", "description": "Multi-source Intelligence Briefs" },
    { "name": "User", "description": "Account and credit management" }
  ],
  "security": [{ "supabaseSession": [] }],
  "paths": {
    "/api/analyze": {
      "post": {
        "tags": ["Analysis"],
        "summary": "Run forensic analysis on an article",
        "description": "Runs the Forensic Ideological Analysis Engine (FME v18.6) on the supplied article text or URL. Returns 13 diagnostic metrics including bias spectrum placement, propaganda index, 24-type fallacy detection, and strategic silence findings. Consumes 1 credit.",
        "operationId": "analyzeArticle",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/AnalyzeRequest" },
              "examples": {
                "byUrl": {
                  "summary": "Analyze by URL",
                  "value": { "url": "https://example.com/article" }
                },
                "byText": {
                  "summary": "Analyze raw text",
                  "value": { "text": "Full article text here…", "source_url": "https://example.com/article" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Analysis complete",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/AnalyzeResult" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/InsufficientCredits" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/intelligence/analyze": {
      "post": {
        "tags": ["Intelligence"],
        "summary": "Generate a multi-source Intelligence Brief",
        "description": "Fetches signals from X, Reddit, YouTube, News, and the open Web for the supplied query, then analyses them for authenticity, emotion profile, primary narratives, and contagion risk. Consumes 2 credits.",
        "operationId": "createIntelligenceBrief",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/IntelligenceBriefRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Brief generated",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/IntelligenceBriefResult" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/InsufficientCredits" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/intelligence/briefs": {
      "get": {
        "tags": ["Intelligence"],
        "summary": "List the caller's Intelligence Briefs",
        "operationId": "listIntelligenceBriefs",
        "parameters": [
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "maximum": 100 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
        ],
        "responses": {
          "200": {
            "description": "Paginated briefs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "briefs": { "type": "array", "items": { "$ref": "#/components/schemas/IntelligenceBriefSummary" } },
                    "total": { "type": "integer" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/intelligence/briefs/{id}": {
      "get": {
        "tags": ["Intelligence"],
        "summary": "Fetch a single Intelligence Brief",
        "operationId": "getIntelligenceBrief",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Brief",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/IntelligenceBriefResult" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "description": "Not found" }
        }
      }
    },
    "/api/user/credits": {
      "get": {
        "tags": ["User"],
        "summary": "Get the caller's current credit balance",
        "operationId": "getUserCredits",
        "responses": {
          "200": {
            "description": "Credit balance",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "credits_remaining": { "type": "integer", "example": 8 },
                    "plan": { "type": "string", "example": "free" }
                  },
                  "required": ["credits_remaining"]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/user/profile": {
      "get": {
        "tags": ["User"],
        "summary": "Get the caller's profile",
        "operationId": "getUserProfile",
        "responses": {
          "200": {
            "description": "User profile",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": { "type": "string", "format": "uuid" },
                    "email": { "type": "string", "format": "email" },
                    "plan": { "type": "string" },
                    "credits_remaining": { "type": "integer" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "supabaseSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "sb-access-token",
        "description": "Supabase session cookie set by the web auth flow at /auth/login."
      }
    },
    "schemas": {
      "AnalyzeRequest": {
        "type": "object",
        "description": "Provide exactly one of `url` or `text`.",
        "properties": {
          "url": { "type": "string", "format": "uri", "description": "Public URL of the article to analyze." },
          "text": { "type": "string", "description": "Raw article text." },
          "source_url": { "type": "string", "format": "uri", "description": "Optional source URL when submitting raw text." }
        },
        "oneOf": [
          { "required": ["url"] },
          { "required": ["text"] }
        ]
      },
      "AnalyzeResult": {
        "type": "object",
        "description": "Forensic analysis output. 13 diagnostic metrics.",
        "properties": {
          "bias_spectrum": {
            "type": "object",
            "properties": {
              "position": { "type": "integer", "minimum": 0, "maximum": 100 },
              "label": { "type": "string", "example": "Center-Right" },
              "frame": { "type": "string", "example": "Populist-Nationalist" },
              "reasoning": { "type": "string" }
            }
          },
          "propaganda_index": {
            "type": "object",
            "properties": {
              "score": { "type": "integer", "minimum": 0, "maximum": 100 },
              "severity": { "type": "string", "enum": ["low", "moderate", "high", "critical"] }
            }
          },
          "logical_fallacies": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": { "type": "string" },
                "count": { "type": "integer" },
                "quotes": { "type": "array", "items": { "type": "string" } }
              }
            }
          },
          "strategic_silence": {
            "type": "object",
            "properties": {
              "findings": { "type": "array", "items": { "type": "string" } },
              "severity": { "type": "string", "enum": ["low", "moderate", "high"] }
            }
          },
          "emotional_resonance": {
            "type": "object",
            "properties": {
              "fear": { "type": "number", "minimum": 0, "maximum": 1 },
              "hope": { "type": "number", "minimum": 0, "maximum": 1 },
              "urgency": { "type": "number", "minimum": 0, "maximum": 1 }
            }
          },
          "intellectual_depth": {
            "type": "object",
            "properties": {
              "dok_level": { "type": "integer", "minimum": 1, "maximum": 4 },
              "rationale": { "type": "string" }
            }
          },
          "source_reliability": { "type": "number", "minimum": 0, "maximum": 1 },
          "publisher_name": { "type": "string" },
          "author_name": { "type": "string" },
          "analytical_synthesis": { "type": "string" }
        }
      },
      "IntelligenceBriefRequest": {
        "type": "object",
        "required": ["query"],
        "properties": {
          "query": { "type": "string", "description": "Search query or topic to brief." },
          "sources": {
            "type": "array",
            "items": { "type": "string", "enum": ["x", "reddit", "youtube", "news", "web"] },
            "default": ["x", "reddit", "youtube", "news", "web"]
          },
          "time_range": { "type": "string", "enum": ["1h", "6h", "24h", "7d", "30d"], "default": "24h" }
        }
      },
      "IntelligenceBriefSummary": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "query": { "type": "string" },
          "created_at": { "type": "string", "format": "date-time" },
          "authenticity_score": { "type": "integer", "minimum": 0, "maximum": 100 },
          "contagion_risk": { "type": "string", "enum": ["low", "moderate", "elevated", "high"] }
        }
      },
      "IntelligenceBriefResult": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "query": { "type": "string" },
          "executive_summary": { "type": "string" },
          "authenticity_score": { "type": "integer", "minimum": 0, "maximum": 100 },
          "emotion_profile": {
            "type": "object",
            "properties": {
              "fear": { "type": "number" },
              "outrage": { "type": "number" },
              "hope": { "type": "number" },
              "urgency": { "type": "number" },
              "pride": { "type": "number" }
            }
          },
          "primary_narratives": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": { "type": "string" },
                "dominance": { "type": "number", "minimum": 0, "maximum": 1 },
                "drivers": { "type": "array", "items": { "type": "string" } }
              }
            }
          },
          "signal_distribution": {
            "type": "object",
            "additionalProperties": { "type": "integer" },
            "example": { "x": 88, "reddit": 42, "youtube": 17, "news": 21, "web": 34 }
          },
          "risk_assessment": {
            "type": "object",
            "properties": {
              "contagion_risk": { "type": "string", "enum": ["low", "moderate", "elevated", "high"] },
              "spread_likelihood_24h": { "type": "number", "minimum": 0, "maximum": 1 },
              "reasoning": { "type": "string" }
            }
          },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "code": { "type": "string" }
        },
        "required": ["error"]
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid Supabase session.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "InsufficientCredits": {
        "description": "Credit balance too low for this operation.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "RateLimited": {
        "description": "Per-user rate limit exceeded.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  },
  "externalDocs": {
    "description": "Product overview",
    "url": "https://www.rhetoricaudit.com"
  }
}
