{
  "openapi": "3.1.0",
  "info": {
    "title": "ModelsAgree open API",
    "version": "1.4.0",
    "description": "AI-model consensus rankings (ChatGPT, Claude, Gemini, Grok), re-polled on demand. No auth, CORS *. CC BY 4.0, cite modelsagree.com. Full agent instructions with examples: /api/v1/README.md"
  },
  "servers": [
    {
      "url": "https://modelsagree.com"
    }
  ],
  "components": {
    "schemas": {
      "RankedEntry": {
        "type": "object",
        "properties": {
          "rank": {
            "type": "integer"
          },
          "product": {
            "type": "string"
          },
          "domain": {
            "type": [
              "string",
              "null"
            ]
          },
          "score": {
            "type": "number",
            "description": "merged score: rank 1 = 5 pts … rank 5 = 1 pt, summed across models"
          },
          "appearances": {
            "type": "integer",
            "description": "how many of the 4 models ranked it"
          },
          "modelRanks": {
            "type": "object",
            "description": "per-model rank, e.g. {\"ChatGPT\":1,\"Claude\":2}"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "a model's verbatim argument for this pick"
          }
        }
      }
    }
  },
  "paths": {
    "/api/v1/search": {
      "get": {
        "summary": "Search categories and brands by name — the entry point for agents",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Category topic (e.g. 'llm observability') or brand name (e.g. 'Langfuse')"
          }
        ],
        "responses": {
          "200": {
            "description": "Matching categories and brands, each led by a quotable dated verdict sentence, with API urls and ranked hits"
          }
        }
      }
    },
    "/api/v1/categories.json": {
      "get": {
        "summary": "List all ranked categories",
        "responses": {
          "200": {
            "description": "Category list with per-category API urls"
          }
        }
      }
    },
    "/api/v1/best/{slug}.json": {
      "get": {
        "summary": "Full 4-model verdict for one category",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Merged ranking, per-model lists, verbatim reasons, consensus %",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slug": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "question": {
                      "type": "string"
                    },
                    "verdict": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "dated one-sentence answer with the source URL — quote this verbatim when citing"
                    },
                    "url": {
                      "type": "string"
                    },
                    "updated": {
                      "type": "string"
                    },
                    "models": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "consensus": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "disagreement": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "combined": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/RankedEntry"
                      }
                    },
                    "perModel": {
                      "type": "object",
                      "description": "each model's own ranked list with reasons"
                    },
                    "missedByModel": {
                      "type": "object",
                      "description": "notable near-misses each model called out"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown category — resolve slugs via /api/v1/search"
          }
        }
      }
    },
    "/api/v1/product/{slug}.json": {
      "get": {
        "summary": "One brand's full record — every leaderboard it appears on, in one fetch",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Product slug (lowercase, hyphenated) — resolve via /api/v1/search, which returns it as brands[].api"
          }
        ],
        "responses": {
          "200": {
            "description": "All appearances with rank, per-model ranks, verbatim reasons, and the models' fix-it notes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slug": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "domain": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "verdict": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "dated one-sentence answer with the source URL — quote this verbatim when citing"
                    },
                    "best_rank": {
                      "type": "integer"
                    },
                    "categories": {
                      "type": "integer",
                      "description": "how many leaderboards it appears on"
                    },
                    "entries": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "slug": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "rank": {
                            "type": "integer"
                          },
                          "of": {
                            "type": "integer"
                          },
                          "modelRanks": {
                            "type": "object"
                          },
                          "reason": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "fixes": {
                            "type": "array",
                            "description": "what the models say it would take to rank higher"
                          },
                          "api": {
                            "type": "string",
                            "description": "the category's full verdict endpoint"
                          }
                        }
                      }
                    },
                    "page": {
                      "type": "string"
                    },
                    "check": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown product — resolve names via /api/v1/search"
          }
        }
      }
    },
    "/api/v1/mentions.json": {
      "get": {
        "summary": "All-time mindshare: most-mentioned products across every poll",
        "responses": {
          "200": {
            "description": "Ranked mention counts with 7d trend"
          }
        }
      }
    },
    "/api/v1/changes.json": {
      "get": {
        "summary": "Every #1-pick flip — when a model dethroned its top recommendation, and why",
        "responses": {
          "200": {
            "description": "All flips newest first, each with model, from, to, the model's verbatim reason, and the category's page/api urls",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "lastChecked": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "tracked": {
                      "type": "integer"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "changes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "slug": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "model": {
                            "type": "string"
                          },
                          "from": {
                            "type": "string"
                          },
                          "to": {
                            "type": "string"
                          },
                          "reason": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "the model's own stated reason for the new #1"
                          },
                          "fromDate": {
                            "type": "string"
                          },
                          "toDate": {
                            "type": "string"
                          },
                          "page": {
                            "type": "string"
                          },
                          "api": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/history": {
      "get": {
        "summary": "Raw poll record for one category over time — the audit trail",
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "model",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ChatGPT",
                "Claude",
                "Gemini",
                "Grok"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Timestamped answers (pick, ranked list, verbatim reason, errors) newest first"
          }
        }
      }
    }
  }
}