{
  "openapi": "3.1.0",
  "info": {
    "title": "TopAlternativesTo",
    "version": "1.0.0",
    "summary": "Software comparison data, readable as markdown from any page URL.",
    "description": "Every page on this site has a markdown representation at the same URL.\nRequest it with `Accept: text/markdown`, or append `.md` to the path.\nContent negotiation follows acceptmarkdown.com: `Vary: Accept` is set,\nq-values are honoured, and a client that rejects both `text/html` and\n`text/markdown` gets a 406.\n\nThe site currently covers 359 tools, 358 alternatives guides, 59 categories and 39 articles.\nPrices come from each vendor pricing page and carry the URL and date they were checked.\n\nThere is also an MCP server at /api/mcp/mcp (Streamable HTTP, no auth)\nexposing search_tools, get_tool and get_alternatives. It is JSON-RPC, so it\nis not described as a path here; see /mcp for setup.\n\nThe /api/v1 endpoints are open: no key, no rate limit today, CORS enabled.\nThey are licensed CC BY 4.0, so reuse is fine with a visible link back.\n\nThe write endpoints below are form endpoints gated by Cloudflare Turnstile.\nThey are documented for completeness and are not usable by an unattended agent.",
    "contact": {
      "name": "TopAlternativesTo",
      "url": "https://topalternatives.to/help",
      "email": "hello@topalternatives.to"
    },
    "license": {
      "name": "Content is not licensed for redistribution",
      "url": "https://topalternatives.to/about"
    }
  },
  "servers": [
    {
      "url": "https://topalternatives.to"
    }
  ],
  "externalDocs": {
    "description": "Agent guide",
    "url": "https://topalternatives.to/llms.txt"
  },
  "tags": [
    {
      "name": "data",
      "description": "Verified pricing data as JSON. CC BY 4.0, attribution required."
    },
    {
      "name": "content",
      "description": "Read the site as markdown."
    },
    {
      "name": "discovery",
      "description": "Machine-readable index files."
    },
    {
      "name": "submissions",
      "description": "Browser-gated write endpoints."
    }
  ],
  "paths": {
    "/api/v1": {
      "get": {
        "tags": [
          "data"
        ],
        "operationId": "getApiIndex",
        "summary": "API index: counts, endpoints, licence",
        "responses": {
          "200": {
            "description": "Index.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools": {
      "get": {
        "tags": [
          "data"
        ],
        "operationId": "listTools",
        "summary": "List tools with verified pricing",
        "description": "Returns the verified pricing facts for each tool: what it costs, the vendor page\nthe price was read from, and the date a human confirmed it.\n\nEditorial content is not exposed. Verdicts, pros and cons, rankings and screenshots\nlive on the pages; use the `url` and `markdownUrl` fields to reach them.",
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Category slug. List them at /api/v1/categories.",
            "example": "crm"
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Substring match on name and tagline."
          },
          {
            "name": "free_tier",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            },
            "description": "Filter on the presence of a genuinely free plan."
          },
          {
            "name": "max_price",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Only tools whose disclosed starting price is at or below this. Quote-only tools are excluded."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of tools.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolList"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/{slug}": {
      "get": {
        "tags": [
          "data"
        ],
        "operationId": "getTool",
        "summary": "One tool by slug",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "notion"
          }
        ],
        "responses": {
          "200": {
            "description": "The tool.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Tool"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown slug.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/categories": {
      "get": {
        "tags": [
          "data"
        ],
        "operationId": "listCategories",
        "summary": "Every category with its tool and guide counts",
        "responses": {
          "200": {
            "description": "Categories.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/{path}.md": {
      "get": {
        "tags": [
          "content"
        ],
        "operationId": "getPageAsMarkdown",
        "summary": "Markdown representation of any page",
        "description": "Append `.md` to any site path. Equivalent to requesting the same path with\n`Accept: text/markdown`. Use `/index.md` for the homepage.\n\nKnown path shapes: `/tools/{slug}`, `/{slug}-alternatives`, `/categories/{slug}`,\n`/blog/{slug}`, `/help/{slug}`. Enumerate them from /sitemap.xml.",
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Site path without the leading slash, for example `tools/notion` or `notion-alternatives`.",
            "example": "tools/notion"
          }
        ],
        "responses": {
          "200": {
            "description": "Markdown representation.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "headers": {
              "Vary": {
                "schema": {
                  "type": "string"
                },
                "description": "Accept, Accept-Encoding"
              }
            }
          },
          "404": {
            "description": "No page at that path. The body is markdown listing where to look instead.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "406": {
            "description": "Client rejected both text/html and text/markdown.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "getSitemap",
        "summary": "Every indexable URL on the site",
        "responses": {
          "200": {
            "description": "Sitemap XML.",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "getLlmsTxt",
        "summary": "Agent guide: what the site is and where the main sections live",
        "responses": {
          "200": {
            "description": "Plain text guide.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/api/feedback": {
      "post": {
        "tags": [
          "submissions"
        ],
        "operationId": "submitFeedback",
        "summary": "Report a wrong or out of date fact on a page",
        "description": "Requires a Cloudflare Turnstile token obtained in a browser. Not callable unattended.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "message",
                  "turnstileToken"
                ],
                "properties": {
                  "message": {
                    "type": "string",
                    "minLength": 10,
                    "maxLength": 4000
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Optional."
                  },
                  "tool": {
                    "type": "string",
                    "description": "Optional tool slug the report is about."
                  },
                  "from": {
                    "type": "string",
                    "description": "Optional page path the report came from."
                  },
                  "turnstileToken": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or captcha failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Wrong method.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Upstream delivery failure. Retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/partnerships": {
      "post": {
        "tags": [
          "submissions"
        ],
        "operationId": "submitPartnership",
        "summary": "Pitch a partnership",
        "description": "Requires a Cloudflare Turnstile token obtained in a browser. Not callable unattended.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "email",
                  "message",
                  "turnstileToken"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "message": {
                    "type": "string",
                    "minLength": 10
                  },
                  "type": {
                    "type": "string",
                    "description": "Optional partnership type."
                  },
                  "turnstileToken": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted."
          },
          "400": {
            "description": "Validation or captcha failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Wrong method.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Upstream delivery failure. Retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/claim/start": {
      "post": {
        "tags": [
          "submissions"
        ],
        "operationId": "startClaim",
        "summary": "Send a verification code to a company email address",
        "description": "Requires a Cloudflare Turnstile token obtained in a browser. Not callable unattended. The address must be on the same domain as the tool website; free consumer domains are rejected.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "slug",
                  "email",
                  "turnstileToken"
                ],
                "properties": {
                  "slug": {
                    "type": "string",
                    "description": "Tool slug, as in /tools/{slug}."
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "turnstileToken": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Code sent."
          },
          "400": {
            "description": "Validation, captcha, or disallowed email domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown tool slug.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Wrong method.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Upstream delivery failure. Retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/claim/submit": {
      "post": {
        "tags": [
          "submissions"
        ],
        "operationId": "submitClaim",
        "summary": "Confirm a code and file a claim or change request",
        "description": "Requires a Cloudflare Turnstile token obtained in a browser. Not callable unattended. Nothing submitted here publishes automatically; every request is reviewed by a person.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "slug",
                  "email",
                  "code"
                ],
                "properties": {
                  "slug": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "code": {
                    "type": "string",
                    "description": "Six-digit code, valid for about 15 minutes."
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "claim",
                      "change"
                    ]
                  },
                  "message": {
                    "type": "string",
                    "description": "Required when action is change."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Filed for review."
          },
          "400": {
            "description": "Validation failure, or wrong or expired code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown tool slug.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Wrong method.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Upstream delivery failure. Retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "ok",
          "code",
          "message",
          "hint",
          "status"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code. Branch on this, not on message.",
            "examples": [
              "invalid_json",
              "missing_fields",
              "unknown_tool",
              "captcha_failed",
              "method_not_allowed",
              "unknown_endpoint"
            ]
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation."
          },
          "hint": {
            "type": "string",
            "description": "What the caller should do next."
          },
          "status": {
            "type": "integer"
          },
          "docs": {
            "type": "string",
            "format": "uri"
          },
          "error": {
            "type": "string",
            "description": "Deprecated alias of message, kept for existing form clients."
          }
        }
      },
      "Tool": {
        "type": "object",
        "required": [
          "slug",
          "name",
          "website",
          "categories",
          "pricing",
          "verifiedAt",
          "url"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "tagline": {
            "type": "string"
          },
          "website": {
            "type": "string",
            "format": "uri"
          },
          "vendor": {
            "type": "string"
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "pricing": {
            "type": "object",
            "properties": {
              "model": {
                "type": "string",
                "examples": [
                  "per-seat",
                  "usage-based",
                  "flat",
                  "quote-only"
                ]
              },
              "freeTier": {
                "type": "boolean"
              },
              "freeTrial": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "startingPrice": {
                "type": [
                  "object",
                  "null"
                ],
                "description": "Null when the vendor does not publish a price.",
                "properties": {
                  "amount": {
                    "type": "number"
                  },
                  "currency": {
                    "type": "string"
                  },
                  "period": {
                    "type": "string",
                    "enum": [
                      "month",
                      "year",
                      "one-time",
                      "usage"
                    ]
                  },
                  "unit": {
                    "type": "string"
                  }
                }
              },
              "sourceUrl": {
                "type": "string",
                "format": "uri",
                "description": "The vendor page the price was read from."
              },
              "checkedAt": {
                "type": "string",
                "format": "date",
                "description": "The day a human opened that page and confirmed it."
              }
            }
          },
          "status": {
            "type": "object",
            "description": "Present only when the tool has been acquired, is winding down, or is discontinued.",
            "properties": {
              "acquisition": {
                "type": "string",
                "enum": [
                  "operating",
                  "winding-down",
                  "shut-down"
                ]
              },
              "acquirer": {
                "type": "string"
              },
              "date": {
                "type": "string"
              },
              "source": {
                "type": "string",
                "format": "uri"
              }
            }
          },
          "verifiedAt": {
            "type": "string",
            "format": "date"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The full profile, with verdict, pros and cons and screenshots."
          },
          "markdownUrl": {
            "type": "string",
            "format": "uri"
          },
          "alternativesUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        }
      },
      "ToolList": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "count": {
            "type": "integer"
          },
          "license": {
            "type": "object"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Tool"
            }
          }
        }
      }
    }
  }
}