{
  "openapi": "3.1.0",
  "info": {
    "title": "ListMySaaS API",
    "version": "1.0.0",
    "description": "Official REST API and agent integration surface for ListMySaaS (https://listmysaas.xyz) — a curated SaaS directory for founders, makers, and indie hackers.\n\n### Authentication & Onboarding\n- **Zero-Auth Access:** All directory query endpoints (`/api/v1/tools`, `/api/v1/categories`) and browser-based SEO analysis endpoints operate with zero authentication. No API keys or registration are required for agent tool calls.\n- **Free Tier:** Public reads and single-page diagnostic audits are 100% free.\n\n### Versioning & Deprecation Policy\n- **Path Versioning:** All endpoints are versioned under `/api/v1/`.\n- **Deprecation Policy:** When an endpoint or version is deprecated, responses will include `Deprecation: @<timestamp>` and `Sunset: <date>` HTTP headers at least 90 days before retirement.",
    "x-api-versioning-policy": {
      "strategy": "uri-path",
      "currentVersion": "v1",
      "deprecationHeaders": ["Deprecation", "Sunset", "Link"],
      "noticePeriodDays": 90
    },
    "contact": {
      "name": "ListMySaaS Support",
      "url": "https://listmysaas.xyz/contact",
      "email": "contact@listmysaas.xyz"
    },
    "license": {
      "name": "MIT",
      "url": "https://opensource.org/licenses/MIT"
    }
  },
  "servers": [
    {
      "url": "https://listmysaas.xyz",
      "description": "Production Server"
    }
  ],
  "paths": {
    "/api/v1/tools": {
      "get": {
        "operationId": "listTools",
        "summary": "List and search SaaS tools",
        "description": "Retrieve a paginated list of curated SaaS directory tools. Supports keyword search across tool names, taglines, categories, and tags, as well as filtering by category or featured status.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Keyword search across tool name, tagline, description, and tags.",
            "schema": {
              "type": "string",
              "example": "ai"
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Filter by exact category name (e.g. 'Artificial Intelligence', 'Productivity', 'Marketing', 'Developer Tools', 'SEO').",
            "schema": {
              "type": "string",
              "example": "Artificial Intelligence"
            }
          },
          {
            "name": "featured",
            "in": "query",
            "required": false,
            "description": "Set to 'true' to return only featured/promoted listings.",
            "schema": {
              "type": "string",
              "enum": ["true", "false"],
              "example": "true"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of results to return (1-100, default 50).",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Number of records to skip for pagination (default 0).",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of SaaS tools matching query parameters.",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimit-Limit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimit-Remaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ToolListResponse" }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters.",
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/{slug}": {
      "get": {
        "operationId": "getToolBySlug",
        "summary": "Get SaaS tool profile details",
        "description": "Fetch detailed profile metadata for a specific SaaS tool by its slug identifier, including description, website URL, pricing plan, badge verification, and related alternatives.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Unique URL slug identifier of the tool (e.g. 'prompt-builder', 'sendlens').",
            "schema": {
              "type": "string",
              "example": "prompt-builder"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tool profile details.",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimit-Limit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimit-Remaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ToolDetailResponse" }
              }
            }
          },
          "404": {
            "description": "Tool not found.",
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          }
        }
      }
    },
    "/api/v1/categories": {
      "get": {
        "operationId": "listCategories",
        "summary": "List all SaaS categories",
        "description": "Retrieve all 30+ SaaS categories with descriptive introductions, live tool counts, and category URLs.",
        "responses": {
          "200": {
            "description": "List of categories with tool counts.",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimit-Limit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimit-Remaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CategoryListResponse" }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/heading-analyzer": {
      "post": {
        "operationId": "analyzeHeadings",
        "summary": "Analyze heading structure & content length",
        "description": "Extracts and audits the H1-H6 heading hierarchy, body word count, paragraph counts, image alt tags, and internal/external link structure for any public URL.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/UrlAuditRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Heading and content analysis results.",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimit-Limit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimit-Remaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/HeadingAnalyzerResponse" }
              }
            }
          },
          "400": {
            "description": "Missing or invalid URL.",
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          },
          "502": {
            "description": "Failed to fetch HTML from target URL.",
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/meta-analyzer": {
      "post": {
        "operationId": "analyzeMetaTags",
        "summary": "Analyze SEO meta tags and social tags",
        "description": "Extracts and evaluates basic HTML metadata (title, description, canonical, robots, viewport) and social tags (OpenGraph, Twitter Cards, Hreflang) with a calculated 0-100 SEO score.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/UrlAuditRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Meta tags evaluation and score.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/MetaAnalyzerResponse" }
              }
            }
          },
          "400": {
            "description": "Invalid input.",
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          },
          "502": {
            "description": "Target website fetch failure.",
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/og-preview": {
      "post": {
        "operationId": "previewOpenGraph",
        "summary": "Generate OpenGraph card preview & image probe",
        "description": "Extracts OpenGraph and Twitter card parameters and probes the social share image dimensions and reachability.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/UrlAuditRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OpenGraph data and probed image specs.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OgPreviewResponse" }
              }
            }
          },
          "400": {
            "description": "Invalid URL parameter.",
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          },
          "502": {
            "description": "Target fetch error.",
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          }
        }
      }
    },
    "/api/v1/health": {
      "get": {
        "operationId": "getHealthStatus",
        "summary": "System liveness and health status",
        "description": "Returns operational status, API version, and discovery links.",
        "responses": {
          "200": {
            "description": "Service is healthy and operational.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "pass" },
                    "version": { "type": "string", "example": "1.0.0" },
                    "service": { "type": "string", "example": "ListMySaaS API" },
                    "timestamp": { "type": "string", "format": "date-time" },
                    "uptimeSeconds": { "type": "integer" },
                    "links": { "type": "object" }
                  },
                  "required": ["status", "version", "service", "timestamp"]
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "headers": {
      "RateLimit-Limit": {
        "description": "The maximum number of requests allowed in the current time window.",
        "schema": { "type": "integer", "example": 100 }
      },
      "RateLimit-Remaining": {
        "description": "The number of remaining requests allowed in the current time window.",
        "schema": { "type": "integer", "example": 99 }
      },
      "RateLimit-Reset": {
        "description": "The number of seconds remaining until the rate limit window resets.",
        "schema": { "type": "integer", "example": 60 }
      }
    },
    "schemas": {
      "ProblemDetails": {
        "type": "object",
        "description": "RFC 9457 Problem Details error response object.",
        "properties": {
          "ok": { "type": "boolean", "example": false },
          "status": { "type": "integer", "example": 400 },
          "type": { "type": "string", "example": "https://listmysaas.xyz/docs/errors#invalid_input" },
          "title": { "type": "string", "example": "INVALID INPUT" },
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "string", "example": "INVALID_INPUT" },
              "message": { "type": "string", "example": "Missing 'url' parameter in request body." },
              "hint": { "type": "string", "example": "Provide a valid HTTP/HTTPS URL: { \"url\": \"https://example.com\" }" },
              "param": { "type": "string", "example": "url" },
              "details": { "type": "object" }
            },
            "required": ["code", "message"]
          },
          "instance": { "type": "string", "example": "/api/v1/tools/heading-analyzer" }
        },
        "required": ["ok", "status", "error"]
      },
      "UrlAuditRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Public website URL to inspect and audit.",
            "example": "https://example.com"
          }
        },
        "required": ["url"]
      },
      "Tool": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string", "example": "Prompt Builder" },
          "slug": { "type": "string", "example": "prompt-builder" },
          "tagline": { "type": "string", "example": "AI Prompt Generator and Optimizer" },
          "description": { "type": "string" },
          "category": { "type": "string", "example": "Artificial Intelligence" },
          "websiteUrl": { "type": "string", "format": "uri" },
          "logoUrl": { "type": "string", "format": "uri" },
          "plan": { "type": "string", "example": "Free" },
          "isFeatured": { "type": "boolean" },
          "isPremium": { "type": "boolean" },
          "score": { "type": "number", "example": 3.5 },
          "tags": { "type": "array", "items": { "type": "string" } },
          "url": { "type": "string", "format": "uri" },
          "markdownUrl": { "type": "string", "format": "uri" },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" }
        },
        "required": ["id", "name", "slug", "tagline", "category", "websiteUrl", "score"]
      },
      "ToolListResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean", "example": true },
          "total": { "type": "integer", "example": 120 },
          "limit": { "type": "integer", "example": 50 },
          "offset": { "type": "integer", "example": 0 },
          "hasMore": { "type": "boolean", "example": true },
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Tool" }
          }
        },
        "required": ["ok", "total", "limit", "offset", "hasMore", "data"]
      },
      "ToolDetailResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean", "example": true },
          "data": {
            "allOf": [
              { "$ref": "#/components/schemas/Tool" },
              {
                "type": "object",
                "properties": {
                  "alternativesUrl": { "type": "string", "format": "uri" },
                  "relatedTools": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": { "type": "string" },
                        "slug": { "type": "string" },
                        "tagline": { "type": "string" },
                        "category": { "type": "string" },
                        "url": { "type": "string", "format": "uri" }
                      }
                    }
                  }
                }
              }
            ]
          }
        },
        "required": ["ok", "data"]
      },
      "Category": {
        "type": "object",
        "properties": {
          "slug": { "type": "string", "example": "artificial-intelligence" },
          "name": { "type": "string", "example": "Artificial Intelligence" },
          "intro": { "type": "string" },
          "blurb": { "type": "string" },
          "toolCount": { "type": "integer", "example": 25 },
          "url": { "type": "string", "format": "uri" },
          "markdownUrl": { "type": "string", "format": "uri" },
          "bestUrl": { "type": "string", "format": "uri" }
        },
        "required": ["slug", "name", "toolCount", "url"]
      },
      "CategoryListResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean", "example": true },
          "total": { "type": "integer", "example": 30 },
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Category" }
          }
        },
        "required": ["ok", "total", "data"]
      },
      "HeadingAnalyzerResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean", "example": true },
          "data": {
            "type": "object",
            "properties": {
              "url": { "type": "string" },
              "finalUrl": { "type": "string" },
              "status": { "type": "integer" },
              "headings": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "level": { "type": "integer" },
                    "text": { "type": "string" }
                  }
                }
              },
              "headingCounts": {
                "type": "array",
                "items": { "type": "integer" }
              },
              "wordCount": { "type": "integer" },
              "charCount": { "type": "integer" },
              "warnings": {
                "type": "array",
                "items": { "type": "string" }
              }
            }
          }
        },
        "required": ["ok", "data"]
      },
      "MetaAnalyzerResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean", "example": true },
          "data": {
            "type": "object",
            "properties": {
              "url": { "type": "string" },
              "summary": {
                "type": "object",
                "properties": {
                  "score": { "type": "integer", "example": 95 },
                  "titleOk": { "type": "boolean" },
                  "descriptionOk": { "type": "boolean" },
                  "canonicalOk": { "type": "boolean" },
                  "ogComplete": { "type": "boolean" },
                  "twitterComplete": { "type": "boolean" }
                }
              }
            }
          }
        },
        "required": ["ok", "data"]
      },
      "OgPreviewResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean", "example": true },
          "data": {
            "type": "object",
            "properties": {
              "url": { "type": "string" },
              "title": { "type": "string" },
              "description": { "type": "string" },
              "image": { "type": "string", "nullable": true },
              "siteName": { "type": "string", "nullable": true },
              "warnings": {
                "type": "array",
                "items": { "type": "string" }
              }
            }
          }
        },
        "required": ["ok", "data"]
      }
    }
  }
}
