{
  "openapi": "3.0.3",
  "info": {
    "title": "SEOforGPT Public API",
    "version": "1.0.0",
    "description": "HTTP API for scripts, CI, and backends used by the SEOforGPT MCP server. Hosted remote MCP and local stdio clients both call this surface. Authenticate with `Authorization: Bearer` using a Supabase session JWT, a user API key (`sgpt_...`), or an OAuth-managed connector key issued by hosted MCP (same header; those keys are hidden from the Settings UI). API key management (`/v1/keys`) requires a JWT. Base path is `/v1` under the deployed host.",
    "contact": {
      "email": "hey@seoforgpt.io"
    }
  },
  "servers": [{ "url": "https://www.seoforgpt.io/api", "description": "Production (Netlify rewrite to Supabase Edge Function)" }],
  "tags": [
    { "name": "Projects", "description": "User projects" },
    { "name": "Analyze", "description": "Visibility runs" },
    { "name": "Content", "description": "Generated content" },
    { "name": "Readiness", "description": "Website LLM readiness" },
    { "name": "Prompts", "description": "Prompt suggestions" },
    { "name": "Reports", "description": "Reports and latest run" },
    { "name": "Keys", "description": "User API keys (JWT only)" }
  ],
  "paths": {
    "/v1/projects": {
      "get": {
        "operationId": "listProjects",
        "summary": "List projects",
        "tags": ["Projects"],
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": {
            "description": "Projects for the authenticated user",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ProjectListResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/v1/analyze/project": {
      "post": {
        "operationId": "analyzeProject",
        "summary": "Run visibility using saved project prompts",
        "tags": ["Analyze"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["projectId"],
                "properties": {
                  "projectId": { "type": "string", "format": "uuid", "description": "Project UUID" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Analysis completed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnalyzeResponse" } } } },
          "202": { "description": "Analysis accepted (async)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnalyzeResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/v1/analyze/custom": {
      "post": {
        "operationId": "analyzeCustom",
        "summary": "Run custom visibility (ad hoc prompts)",
        "tags": ["Analyze"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["projectId", "brand", "prompts"],
                "properties": {
                  "projectId": { "type": "string", "format": "uuid" },
                  "brand": { "type": "string" },
                  "prompts": {
                    "type": "array",
                    "items": {
                      "oneOf": [{ "type": "string" }, { "type": "object", "properties": { "prompt": { "type": "string" } }, "required": ["prompt"] }]
                    },
                    "maxItems": 20
                  },
                  "competitors": { "type": "array", "items": { "type": "string" } }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Custom analysis completed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnalyzeCustomResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/v1/analyze": {
      "post": {
        "operationId": "analyzeDispatcher",
        "summary": "Analyze (legacy dispatcher)",
        "description": "Supports testId, projectId+brand+prompts (custom), legacy crawl fields, or projectId alone (same as /analyze/project). Prefer /v1/analyze/project or /v1/analyze/custom.",
        "tags": ["Analyze"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "type": "object", "additionalProperties": true }
            }
          }
        },
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnalyzeResponse" } } } },
          "202": { "description": "Accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnalyzeResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/v1/generate-content": {
      "post": {
        "operationId": "generateContent",
        "summary": "Generate content (blog, LinkedIn, thread)",
        "tags": ["Content"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["projectId", "platform", "topic"],
                "properties": {
                  "projectId": { "type": "string", "format": "uuid" },
                  "platform": { "type": "string", "enum": ["blog", "linkedin", "thread"] },
                  "topic": { "type": "string" },
                  "metadata": { "type": "object", "additionalProperties": true }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GenerateContentResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/v1/readiness": {
      "post": {
        "operationId": "checkReadiness",
        "summary": "Run website LLM readiness check",
        "tags": ["Readiness"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["projectId"],
                "properties": {
                  "projectId": { "type": "string", "format": "uuid" },
                  "forceRerun": { "type": "boolean" },
                  "url": { "type": "string", "description": "Optional URL override" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReadinessResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/v1/suggest-prompts": {
      "post": {
        "operationId": "suggestPrompts",
        "summary": "Suggest prompts from crawl record",
        "tags": ["Prompts"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["crawlRecordId"],
                "properties": {
                  "crawlRecordId": { "type": "string", "format": "uuid" },
                  "projectId": { "type": "string", "format": "uuid" },
                  "brand": { "type": "string" },
                  "competitors": { "type": "array", "items": { "type": "string" } }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SuggestPromptsResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/v1/reports/latest": {
      "get": {
        "operationId": "getLatestReport",
        "summary": "Get latest report for a project",
        "tags": ["Reports"],
        "security": [{ "bearerAuth": [] }],
        "parameters": [
          { "name": "projectId", "in": "query", "required": true, "schema": { "type": "string", "format": "uuid" } },
          { "name": "source", "in": "query", "required": false, "schema": { "type": "string", "enum": ["main", "custom"], "default": "main" } },
          { "name": "view", "in": "query", "required": false, "schema": { "type": "string", "enum": ["raw", "summary", "full"], "default": "summary" } }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReportResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/v1/reports/{reportId}": {
      "get": {
        "operationId": "getReportById",
        "summary": "Get report by id",
        "tags": ["Reports"],
        "security": [{ "bearerAuth": [] }],
        "parameters": [
          { "name": "reportId", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "view", "in": "query", "required": false, "schema": { "type": "string", "enum": ["raw", "summary", "full"], "default": "summary" } }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReportResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/v1/keys": {
      "post": {
        "operationId": "createApiKey",
        "summary": "Create API key (JWT only)",
        "tags": ["Keys"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": { "type": "string" },
                  "expires_at": { "type": "string", "format": "date-time", "nullable": true }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateKeyResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      },
      "get": {
        "operationId": "listApiKeys",
        "summary": "List API keys (JWT only)",
        "tags": ["Keys"],
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KeyListResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/v1/keys/{keyId}": {
      "delete": {
        "operationId": "deleteApiKey",
        "summary": "Delete API key (JWT only)",
        "tags": ["Keys"],
        "security": [{ "bearerAuth": [] }],
        "parameters": [{ "name": "keyId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
        "responses": {
          "200": { "description": "Deleted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteKeyResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT or API key",
        "description": "Send `Authorization: Bearer <token>`. Use a Supabase access token or a user API key (`sgpt_...`). Key management routes require a JWT."
      }
    },
    "schemas": {
      "ApiError": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message", "request_id"],
            "properties": {
              "code": { "type": "string", "example": "RATE_LIMITED" },
              "message": { "type": "string" },
              "details": { "nullable": true },
              "request_id": { "type": "string", "format": "uuid" }
            }
          }
        }
      },
      "BillingMeta": {
        "type": "object",
        "description": "Plan and quota snapshot (shape may evolve)",
        "additionalProperties": true
      },
      "ProjectListResponse": {
        "type": "object",
        "properties": {
          "data": { "type": "array", "items": { "type": "object", "additionalProperties": true } },
          "meta": { "$ref": "#/components/schemas/BillingMeta" }
        }
      },
      "AnalyzeResponse": {
        "type": "object",
        "properties": {
          "data": { "type": "object", "additionalProperties": true },
          "meta": { "$ref": "#/components/schemas/BillingMeta" }
        }
      },
      "AnalyzeCustomResponse": {
        "type": "object",
        "properties": {
          "data": { "type": "object", "additionalProperties": true },
          "meta": { "$ref": "#/components/schemas/BillingMeta" }
        }
      },
      "GenerateContentResponse": {
        "type": "object",
        "properties": {
          "data": { "type": "object", "additionalProperties": true },
          "meta": { "$ref": "#/components/schemas/BillingMeta" }
        }
      },
      "ReadinessResponse": {
        "type": "object",
        "properties": {
          "data": { "type": "object", "additionalProperties": true },
          "meta": { "$ref": "#/components/schemas/BillingMeta" }
        }
      },
      "SuggestPromptsResponse": {
        "type": "object",
        "properties": {
          "data": { "type": "object", "additionalProperties": true },
          "meta": { "$ref": "#/components/schemas/BillingMeta" }
        }
      },
      "ReportResponse": {
        "type": "object",
        "properties": {
          "data": { "type": "object", "additionalProperties": true },
          "meta": { "$ref": "#/components/schemas/BillingMeta" }
        }
      },
      "CreateKeyResponse": {
        "type": "object",
        "properties": {
          "data": { "type": "object", "additionalProperties": true },
          "meta": { "$ref": "#/components/schemas/BillingMeta" }
        }
      },
      "KeyListResponse": {
        "type": "object",
        "properties": {
          "data": { "type": "array", "items": { "type": "object", "additionalProperties": true } },
          "meta": { "$ref": "#/components/schemas/BillingMeta" }
        }
      },
      "DeleteKeyResponse": {
        "type": "object",
        "properties": {
          "data": { "type": "object", "additionalProperties": true },
          "meta": { "$ref": "#/components/schemas/BillingMeta" }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid input",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      },
      "Unauthorized": {
        "description": "Missing or invalid bearer token",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      },
      "PaymentRequired": {
        "description": "Billing or quota gate",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      },
      "Conflict": {
        "description": "Conflict (e.g. API key limit)",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      },
      "RateLimited": {
        "description": "Rate limit exceeded. When applicable, the response includes `Retry-After` and `X-RateLimit-*` headers.",
        "headers": {
          "Retry-After": { "schema": { "type": "string" }, "description": "Seconds until reset" },
          "X-RateLimit-Limit": { "schema": { "type": "string" } },
          "X-RateLimit-Remaining": { "schema": { "type": "string" } },
          "X-RateLimit-Reset": { "schema": { "type": "string" }, "description": "Unix timestamp" }
        },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      },
      "InternalError": {
        "description": "Server error",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      }
    }
  }
}
