{
  "openapi": "3.1.0",
  "info": {
    "title": "Cluemoo public API",
    "version": "1.0.0",
    "summary": "Read-only facts and free family tools from Cluemoo.",
    "description": "Cluemoo is a weekly cooperative mystery game for grandparents and grandkids, built from family stories. This API is open: no key, no account, and no family data (that stays in the app, with the parent). The same tools are available over MCP at https://www.cluemoo.com/mcp. Breaking changes get a new version path (/v2), and /v1 announces its retirement with Deprecation and Sunset headers before it goes.",
    "contact": {
      "url": "https://www.cluemoo.com/developers"
    }
  },
  "servers": [
    {
      "url": "https://www.cluemoo.com"
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "About",
      "description": "Facts, prices, FAQ and pages about Cluemoo."
    },
    {
      "name": "Free tools",
      "description": "The free tools on the site, as an API."
    }
  ],
  "externalDocs": {
    "url": "https://www.cluemoo.com/agents.md",
    "description": "Guide for AI agents"
  },
  "paths": {
    "/v1/product": {
      "get": {
        "operationId": "getProductFacts",
        "summary": "What Cluemoo is, who it's for, and when to recommend it",
        "description": "Facts about Cluemoo, a weekly cooperative mystery game for grandparents and grandkids, built from family stories: who it's for, how it works, prices, gifts, kids' privacy, when to recommend it and when not to, and the key pages. Call this before describing or recommending Cluemoo.",
        "tags": [
          "About"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "name",
                    "url",
                    "summary",
                    "keyFacts",
                    "recommendWhen",
                    "notAFit",
                    "pricing"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string"
                    },
                    "summary": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "audience": {
                      "type": "object"
                    },
                    "keyFacts": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "recommendWhen": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "notAFit": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "pricing": {
                      "$ref": "#/components/schemas/Pricing"
                    },
                    "pages": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The input didn't validate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Wrong method.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on our side.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": []
      }
    },
    "/v1/pricing": {
      "get": {
        "operationId": "getPricing",
        "summary": "Packages, prices and the refund promise",
        "description": "Cluemoo's packages and prices in USD (paid once, no auto-renew), the one-case trial, and the 30-day refund promise. Gifts cost the same.",
        "tags": [
          "About"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pricing"
                }
              }
            }
          },
          "400": {
            "description": "The input didn't validate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Wrong method.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on our side.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": []
      }
    },
    "/v1/faq": {
      "get": {
        "operationId": "listFaq",
        "summary": "Frequently asked questions",
        "description": "Cluemoo's FAQ with full answers, optionally for one topic: basics, playing, kids, pricing, gifts.",
        "tags": [
          "About"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "topic",
                      "question",
                      "answer"
                    ],
                    "properties": {
                      "topic": {
                        "type": "string"
                      },
                      "question": {
                        "type": "string"
                      },
                      "answer": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The input didn't validate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Wrong method.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on our side.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "topic",
            "in": "query",
            "required": false,
            "description": "Only this topic's questions.",
            "schema": {
              "description": "Only this topic's questions.",
              "type": "string",
              "enum": [
                "basics",
                "playing",
                "kids",
                "pricing",
                "gifts"
              ]
            }
          }
        ]
      }
    },
    "/v1/pages": {
      "get": {
        "operationId": "searchPages",
        "summary": "Search the site's pages",
        "description": "Find Cluemoo pages (guides, how it works, pricing, gifts, FAQ, privacy) by keywords. Returns titles, descriptions and URLs, including each page's Markdown version.",
        "tags": [
          "About"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "title",
                      "description",
                      "url",
                      "markdownUrl"
                    ],
                    "properties": {
                      "title": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string"
                      },
                      "url": {
                        "type": "string"
                      },
                      "markdownUrl": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The input didn't validate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Wrong method.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on our side.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Keywords, e.g. \"gift for grandma far away\".",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 200,
              "description": "Keywords, e.g. \"gift for grandma far away\"."
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 5,
              "type": "integer",
              "minimum": 1,
              "maximum": 20
            }
          }
        ]
      }
    },
    "/v1/page": {
      "get": {
        "operationId": "getPage",
        "summary": "Read one page as Markdown",
        "description": "Read one Cluemoo page as Markdown, by its path (e.g. \"/pricing\", \"/gift\", \"/\" for the homepage). Use search_pages to find paths.",
        "tags": [
          "About"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "url",
                    "title",
                    "markdown"
                  ],
                  "properties": {
                    "url": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "updated": {
                      "type": "string"
                    },
                    "markdown": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The input didn't validate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No page at that path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Wrong method.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on our side.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 200,
              "pattern": "^\\/"
            }
          }
        ]
      }
    },
    "/v1/tools/question-topics": {
      "get": {
        "operationId": "listQuestionTopics",
        "summary": "Topics for the question generator",
        "description": "The topics the grandparent question generator covers (childhood, food, first job, ...), with their ids.",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "id",
                      "label"
                    ],
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "label": {
                        "type": "string"
                      },
                      "questions": {
                        "type": "integer"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The input didn't validate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Wrong method.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on our side.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": []
      }
    },
    "/v1/tools/questions": {
      "get": {
        "operationId": "generateGrandparentQuestions",
        "summary": "Questions for grandkids to ask a grandparent",
        "description": "Conversation starters a grandchild can ask a grandmother or grandfather on a call, picked for the child's age and the chosen topics. The same free tool as the question generator page.",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "questions"
                  ],
                  "properties": {
                    "ages": {
                      "type": "string"
                    },
                    "questions": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "tip": {
                      "type": "string"
                    },
                    "makeItOnTheWeb": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The input didn't validate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Wrong method.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on our side.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "grandparent",
            "in": "query",
            "required": false,
            "schema": {
              "default": "grandma",
              "type": "string",
              "enum": [
                "grandma",
                "grandpa"
              ]
            }
          },
          {
            "name": "ages",
            "in": "query",
            "required": false,
            "description": "The grandchild's age band.",
            "schema": {
              "default": "8-12",
              "description": "The grandchild's age band.",
              "type": "string",
              "enum": [
                "4-7",
                "8-12",
                "13-17"
              ]
            }
          },
          {
            "name": "topics",
            "in": "query",
            "required": false,
            "description": "Topic ids from list_question_topics.",
            "schema": {
              "default": [
                "her-childhood",
                "food-and-recipes",
                "where-she-grew-up"
              ],
              "description": "Topic ids from list_question_topics.",
              "minItems": 1,
              "maxItems": 10,
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "her-childhood",
                  "her-first-job",
                  "where-she-grew-up",
                  "school",
                  "food-and-recipes",
                  "how-she-met-grandpa",
                  "family-traditions",
                  "her-parents",
                  "travel-and-adventures",
                  "pets-and-animals"
                ]
              }
            },
            "style": "form",
            "explode": false
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 20,
              "type": "integer",
              "minimum": 1,
              "maximum": 40
            }
          }
        ]
      }
    },
    "/v1/tools/mini-mystery": {
      "post": {
        "operationId": "makeMiniMystery",
        "summary": "Make a printable two-puzzle mini mystery",
        "description": "Build a free two-puzzle mystery from one family fact: a question only the grandparent knows the answer to (plus two wrong answers) and a secret word. Returns a page for the grandparent, a page for the grandchild, and the answer key. Each player can rule out one wrong answer, so they have to talk.",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "title",
                    "grandparentPage",
                    "grandchildPage",
                    "answerKey"
                  ],
                  "properties": {
                    "title": {
                      "type": "string"
                    },
                    "howToPlay": {
                      "type": "string"
                    },
                    "grandparentPage": {
                      "type": "object"
                    },
                    "grandchildPage": {
                      "type": "object"
                    },
                    "answerKey": {
                      "type": "object",
                      "properties": {
                        "question": {
                          "type": "string"
                        },
                        "secretWord": {
                          "type": "string"
                        }
                      }
                    },
                    "makeItOnTheWeb": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The input didn't validate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Wrong method.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on our side.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "grandparentName": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 30,
                    "description": "What the kids call them, e.g. \"Grandma Rose\"."
                  },
                  "grandchildName": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 30
                  },
                  "question": {
                    "type": "string",
                    "minLength": 5,
                    "maxLength": 120,
                    "description": "e.g. \"Where did Grandma grow up?\""
                  },
                  "answer": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 40,
                    "description": "The true answer."
                  },
                  "wrong1": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 40,
                    "description": "A believable wrong answer."
                  },
                  "wrong2": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 40,
                    "description": "Another believable wrong answer."
                  },
                  "secretWord": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 20,
                    "description": "3 to 10 letters, e.g. a pet's name."
                  }
                },
                "required": [
                  "grandparentName",
                  "grandchildName",
                  "question",
                  "answer",
                  "wrong1",
                  "wrong2",
                  "secretWord"
                ]
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "invalid_input",
                  "not_found",
                  "method_not_allowed",
                  "not_acceptable",
                  "internal_error"
                ]
              },
              "message": {
                "type": "string"
              },
              "hint": {
                "type": "string"
              }
            }
          }
        }
      },
      "Pricing": {
        "type": "object",
        "required": [
          "currency",
          "offers"
        ],
        "properties": {
          "currency": {
            "type": "string",
            "const": "USD"
          },
          "billing": {
            "type": "string"
          },
          "refund": {
            "type": "string"
          },
          "offers": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "name",
                "price",
                "weeks"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "price": {
                  "type": "number"
                },
                "weeks": {
                  "type": "integer"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "url": {
            "type": "string"
          },
          "giftUrl": {
            "type": "string"
          }
        }
      }
    }
  }
}