{
  "openapi": "3.1.0",
  "info": {
    "title": "Readyt Public API",
    "version": "1.0.0",
    "summary": "Reddit thread discovery and AI visibility (GEO) analysis.",
    "description": "Programmatic access to the analysis engines behind readyt.ai.\n\n## When to use this API\n\nCall it to answer: does a brand show up when AI engines are asked for a recommendation in its\ncategory, who is recommended instead, which sources feed those answers, and which Reddit threads\na brand should be present in. It is the right tool for AI/LLM visibility checks (ChatGPT, Claude,\nPerplexity, Google AI Overviews), generative engine optimisation (GEO) audits, subreddit research,\nsubreddit rule checks, and buying-intent thread discovery.\n\nIt is not a general web search or scraping API, and it does not post anything to Reddit.\n\n## Asynchronous by design\n\nEvery analysis is a job. `POST` starts it and returns an id with `202 Accepted`; `GET` with that id\npolls until `status` is `done` or `error`. Analyses take about 30 seconds, lead discovery about two\nminutes. Results are cached upstream for 30 days per (tool, input), so a repeated call can come back\n`done` on the first poll.\n\n## Authentication\n\nNone. The endpoints are open. A contact email is required on write calls because the finished report\nis emailed there, and the per-email daily quota is keyed on it.\n\n## Rate limits\n\nEvery response carries RFC 9331 `RateLimit` headers, and a 429 carries `Retry-After`. Two layers\napply: this gateway (60 read requests / 60s, 10 write requests / 3600s) and the analysis engines' own daily quotas (250/day globally and 4/day per email per tool for analyses; 150/day and 2/day per email for lead discovery). Engine quotas reset at 00:00 UTC.\n\n## Versioning and deprecation\n\nThe version is in the URL path: `https://www.readyt.ai/api/v1/...`. Additive changes (new fields, new\nendpoints) ship inside a version without notice, so ignore unknown fields. Breaking changes ship as a\nnew path version. When a version is deprecated, every one of its responses carries `Deprecation`\n(RFC 9745) and `Sunset` (RFC 8594) headers plus `Link: rel=\"successor-version\"`, and it keeps working\nfor at least six months after the `Deprecation` date.\n\n## MCP\n\nThe same engines are exposed as MCP tools over Streamable HTTP at `https://www.readyt.ai/api/mcp`.\nManifest: `https://www.readyt.ai/.well-known/mcp.json`.",
    "contact": {
      "name": "Readyt",
      "email": "hello@readyt.ai",
      "url": "https://www.readyt.ai/developers"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://www.readyt.ai/terms.html"
    },
    "termsOfService": "https://www.readyt.ai/terms.html"
  },
  "servers": [
    {
      "url": "https://www.readyt.ai/api/v1",
      "description": "Production, v1"
    }
  ],
  "security": [],
  "externalDocs": {
    "description": "Developer documentation",
    "url": "https://www.readyt.ai/developers"
  },
  "x-api-versions": {
    "v1": {
      "status": "current",
      "since": "2026-08-23",
      "deprecation": null,
      "sunset": null,
      "successor": null
    }
  },
  "x-rate-limits": {
    "gateway": [
      {
        "policy": "read",
        "limit": 60,
        "window_seconds": 60
      },
      {
        "policy": "write",
        "limit": 10,
        "window_seconds": 3600
      }
    ],
    "upstream_daily_quotas": {
      "analyses": {
        "global_per_day": 250,
        "per_email_per_tool_per_day": 4
      },
      "leads": {
        "global_per_day": 150,
        "per_email_per_day": 2
      }
    },
    "reset": "Engine quotas reset at 00:00 UTC."
  },
  "x-mcp": {
    "endpoint": "https://www.readyt.ai/api/mcp",
    "transport": "streamable-http",
    "manifest": "https://www.readyt.ai/.well-known/mcp.json"
  },
  "tags": [
    {
      "name": "Discovery",
      "description": "Service and capability discovery."
    },
    {
      "name": "Analyses",
      "description": "AI visibility and Reddit research jobs."
    },
    {
      "name": "Leads",
      "description": "Buying-intent Reddit thread discovery."
    }
  ],
  "paths": {
    "/": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "operationId": "getServiceDescription",
        "summary": "Service description",
        "description": "Endpoints, versioning policy, rate limits and documentation links.",
        "responses": {
          "200": {
            "description": "Service description.",
            "headers": {
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "429": {
            "description": "Gateway rate limit reached.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tools": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "operationId": "listTools",
        "summary": "List analysis tools",
        "description": "The tool ids accepted by `POST /analyses`, with the input each expects and when to use it.",
        "responses": {
          "200": {
            "description": "Tool catalogue.",
            "headers": {
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tools": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Tool"
                      }
                    },
                    "usage": {
                      "type": "object"
                    }
                  }
                },
                "example": {
                  "tools": [
                    {
                      "id": "geo-report",
                      "title": "GEO report",
                      "summary": "How ChatGPT, Claude and Perplexity talk about a brand today: whether it is named, who is recommended instead, and which sources feed those answers.",
                      "input": {
                        "kind": "domain",
                        "description": "A domain or URL, e.g. \"acme.com\"",
                        "example": "acme.com"
                      },
                      "when_to_use": "The caller asks whether a company shows up in AI answers, or wants an AI-visibility baseline."
                    },
                    {
                      "id": "geo-index",
                      "title": "GEO index",
                      "summary": "The brands AI engines name most for a product category, in order.",
                      "input": {
                        "kind": "category",
                        "description": "A product category",
                        "example": "project management tools"
                      },
                      "when_to_use": "The caller asks who the AI engines recommend in a market, or wants a category leaderboard."
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Gateway rate limit reached.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/analyses": {
      "post": {
        "tags": [
          "Analyses"
        ],
        "operationId": "startAnalysis",
        "summary": "Start an analysis",
        "description": "Starts an asynchronous analysis and returns its id. Poll `GET /analyses?id=` until it is done.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartAnalysis"
              },
              "example": {
                "tool": "geo-report",
                "input": "acme.com",
                "email": "you@example.com"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Analysis started (or served from the 30-day cache, in which case `status` is already `done`).",
            "headers": {
              "Location": {
                "description": "Where to poll the run.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StartedAnalysis"
                },
                "example": {
                  "id": "0f4d2b1e-7c3a-4a1b-9f2e-5d6c7b8a9012",
                  "tool": "geo-report",
                  "input": "acme.com",
                  "status": "running",
                  "cached": false,
                  "poll_url": "https://www.readyt.ai/api/v1/analyses?id=0f4d2b1e-7c3a-4a1b-9f2e-5d6c7b8a9012",
                  "poll_after_seconds": 5
                }
              }
            }
          },
          "400": {
            "description": "Unknown tool, missing input, or invalid email.",
            "headers": {
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Gateway rate limit or engine daily quota reached.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The analysis engine is unavailable.",
            "headers": {
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Analyses"
        ],
        "operationId": "getAnalysis",
        "summary": "Poll an analysis",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "The id returned by `POST /analyses`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current state of the run.",
            "headers": {
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalysisState"
                }
              }
            }
          },
          "400": {
            "description": "Malformed id.",
            "headers": {
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No analysis with that id.",
            "headers": {
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/leads": {
      "post": {
        "tags": [
          "Leads"
        ],
        "operationId": "startLeadDiscovery",
        "summary": "Start Reddit lead discovery",
        "description": "Profiles the site, scans this month's threads in the matching communities and returns the five highest-scoring buying-intent threads. Takes about two minutes.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartLeads"
              },
              "example": {
                "site_url": "acme.com",
                "email": "you@example.com"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Run started.",
            "headers": {
              "Location": {
                "description": "Where to poll the run.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StartedLeads"
                }
              }
            }
          },
          "400": {
            "description": "Invalid site or email.",
            "headers": {
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Gateway rate limit or engine daily quota reached.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The lead discovery engine is unavailable.",
            "headers": {
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Leads"
        ],
        "operationId": "getLeadDiscovery",
        "summary": "Poll a lead discovery run",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "The id returned by `POST /leads`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current state of the run.",
            "headers": {
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LeadsState"
                }
              }
            }
          },
          "400": {
            "description": "Malformed id.",
            "headers": {
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No run with that id.",
            "headers": {
              "RateLimit": {
                "description": "RFC 9331 state of the policy that applied to this request, e.g. `\"read\";r=58;t=42`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "RFC 9331 declaration of every enforced policy, e.g. `\"read\";q=60;w=60, \"write\";q=10;w=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the current window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-API-Version": {
                "description": "API version that served the response.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine-readable code.",
                "enum": [
                  "invalid_json",
                  "invalid_input",
                  "invalid_email",
                  "invalid_site",
                  "invalid_id",
                  "unknown_tool",
                  "not_found",
                  "method_not_allowed",
                  "rate_limited",
                  "quota_exceeded",
                  "upstream_error"
                ]
              },
              "message": {
                "type": "string"
              },
              "retry_after_seconds": {
                "type": "integer"
              }
            }
          }
        }
      },
      "Tool": {
        "type": "object",
        "required": [
          "id",
          "title",
          "summary",
          "input",
          "when_to_use"
        ],
        "properties": {
          "id": {
            "type": "string",
            "enum": [
              "geo-report",
              "geo-index",
              "citation-tracker",
              "subreddit-finder",
              "subreddit-rules-analyzer",
              "reddit-keyword-tool",
              "reddit-reply-generator",
              "shadowban-karma-checker"
            ]
          },
          "title": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "when_to_use": {
            "type": "string"
          },
          "input": {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "example": {
                "type": "string"
              }
            }
          }
        }
      },
      "StartAnalysis": {
        "type": "object",
        "required": [
          "tool",
          "input",
          "email"
        ],
        "properties": {
          "tool": {
            "type": "string",
            "enum": [
              "geo-report",
              "geo-index",
              "citation-tracker",
              "subreddit-finder",
              "subreddit-rules-analyzer",
              "reddit-keyword-tool",
              "reddit-reply-generator",
              "shadowban-karma-checker"
            ],
            "description": "Which analysis to run. See `GET /tools`."
          },
          "input": {
            "type": "string",
            "minLength": 2,
            "maxLength": 300,
            "description": "The subject of the analysis; its meaning depends on the tool."
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Where the finished report is sent. Also keys the per-email daily quota."
          }
        }
      },
      "StartedAnalysis": {
        "type": "object",
        "required": [
          "id",
          "status",
          "poll_url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "tool": {
            "type": "string",
            "enum": [
              "geo-report",
              "geo-index",
              "citation-tracker",
              "subreddit-finder",
              "subreddit-rules-analyzer",
              "reddit-keyword-tool",
              "reddit-reply-generator",
              "shadowban-karma-checker"
            ]
          },
          "input": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "running",
              "done"
            ]
          },
          "cached": {
            "type": "boolean",
            "description": "True when an identical analysis from the last 30 days was reused."
          },
          "poll_url": {
            "type": "string",
            "format": "uri"
          },
          "poll_after_seconds": {
            "type": "integer"
          }
        }
      },
      "AnalysisState": {
        "type": "object",
        "required": [
          "id",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "running",
              "done",
              "error"
            ]
          },
          "result": {
            "description": "Present once `status` is `done`.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/AnalysisResult"
              },
              {
                "type": "null"
              }
            ]
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "poll_after_seconds": {
            "type": "integer"
          }
        }
      },
      "AnalysisResult": {
        "type": "object",
        "description": "Shape shared by every analysis tool.",
        "properties": {
          "summary": {
            "type": "string",
            "description": "One sentence stating the result."
          },
          "lines": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Up to six \"Label — value\" findings."
          },
          "body": {
            "type": "string",
            "description": "Optional longer passage, e.g. the drafted reply."
          }
        }
      },
      "StartLeads": {
        "type": "object",
        "required": [
          "site_url",
          "email"
        ],
        "properties": {
          "site_url": {
            "type": "string",
            "description": "The site to find Reddit leads for, e.g. \"acme.com\"."
          },
          "email": {
            "type": "string",
            "format": "email"
          }
        }
      },
      "StartedLeads": {
        "type": "object",
        "required": [
          "id",
          "status",
          "poll_url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "site_url": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "running"
            ]
          },
          "poll_url": {
            "type": "string",
            "format": "uri"
          },
          "poll_after_seconds": {
            "type": "integer"
          },
          "typical_duration_seconds": {
            "type": "integer"
          }
        }
      },
      "LeadsState": {
        "type": "object",
        "required": [
          "id",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "running",
              "processing",
              "done",
              "error"
            ]
          },
          "stage": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "analyzing",
              "scanning",
              "scoring",
              null
            ]
          },
          "category": {
            "type": [
              "string",
              "null"
            ],
            "description": "The niche the engine inferred from the site."
          },
          "result": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "partial": {
                    "type": "boolean",
                    "description": "True when fewer than five threads cleared the quality bar."
                  },
                  "scanned": {
                    "type": "integer",
                    "description": "Threads examined."
                  },
                  "leads": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/Lead"
                    }
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "poll_after_seconds": {
            "type": "integer"
          }
        }
      },
      "Lead": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "subreddit": {
            "type": "string"
          },
          "author": {
            "type": "string"
          },
          "body_snippet": {
            "type": "string"
          },
          "age_days": {
            "type": "integer"
          },
          "comments": {
            "type": "integer"
          },
          "upvotes": {
            "type": "integer"
          },
          "score": {
            "type": "integer",
            "description": "Buying-intent fit, 0-100."
          },
          "contexte": {
            "type": "string",
            "description": "Why this thread is relevant."
          },
          "angle": {
            "type": "string",
            "description": "Suggested reply angle."
          }
        }
      }
    }
  }
}
