{
  "openapi": "3.1.1",
  "info": {
    "title": "Cartograph Country Quiz (capitals, flags, shapes, map — printable) API",
    "version": "1.0.0",
    "summary": "Make a geography quiz on capitals, flags, shapes or the map, with a printable sheet and answer key.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://cartographcountryquiz.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Make a geography quiz on capitals, flags, shapes or the map, with a printable sheet and answer key.",
        "description": "Makes a multiple-choice geography quiz for a region or the whole world: capitals, countries of capitals, flags, country shapes, or “find it on the map”. The same seed always gives the same questions, so a class can share one quiz. You get the questions with the answer key, a printable PDF quiz sheet (flag questions print the flag’s written description, map questions print a numbered blank map), and Markdown flashcards for Deckwright Study Cards. It is the quiz engine of the Cartograph app, which also schedules spaced reviews.\n\nMethodology:\n- Countries: 193 UN member states, the observers Holy See and Palestine, and Kosovo and Taiwan. Capital questions leave out Israel and Palestine (disputed capitals) and accept other official capitals and spellings when typed in the app (La Paz or Sucre, Pretoria, Cape Town or Bloemfontein …). Shape questions use the 177 Natural Earth outlines; map questions draw smaller countries as a dot at their capital.\n- Questions are drawn with a seeded generator (sfc32): the same quiz, region, number of questions, choices and seed give the same questions and the same option order everywhere.\n- Wrong options are plausible on purpose: flags with similar colours and layout for flag questions, countries of a similar size for shapes, and the same region for capitals and countries.\n- The PDF is laid out with the Printshop engine (vector PDF, embedded Noto fonts). Flag pictures are not embedded: flag questions print the flag’s written description from The World Factbook. Map questions print a numbered blank map with lines for the names. The last page is the answer key.\n- The Markdown cards use the Deckwright Study Cards format (Q:/A:), so the questions can be reviewed with spaced repetition there or in the Atlas tab of Cartograph.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "cartograph_country_quiz",
        "x-owner-app": "cartograph",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CartographCountryQuizInput"
              },
              "examples": {
                "example1": {
                  "summary": "Ten European capitals",
                  "value": {
                    "kind": "capital",
                    "region": "europe",
                    "count": 10,
                    "seed": "europe"
                  }
                },
                "example2": {
                  "summary": "Flags of Africa (eight questions)",
                  "value": {
                    "kind": "flag",
                    "region": "africa",
                    "count": 8,
                    "seed": "class-7b"
                  }
                },
                "example3": {
                  "summary": "Find South American countries on a blank map",
                  "value": {
                    "kind": "locate",
                    "region": "south-america",
                    "count": 12,
                    "seed": "map"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CartographCountryQuizResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "CartographCountryQuizInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "kind": {
            "title": "Quiz",
            "type": "string",
            "enum": [
              "capital",
              "country",
              "flag",
              "shape",
              "locate"
            ],
            "default": "capital"
          },
          "region": {
            "title": "Region",
            "type": "string",
            "enum": [
              "world",
              "africa",
              "asia",
              "europe",
              "north-america",
              "south-america",
              "oceania"
            ],
            "default": "europe"
          },
          "count": {
            "title": "Questions",
            "type": "integer",
            "minimum": 1,
            "maximum": 60,
            "default": 10
          },
          "choices": {
            "title": "Choices per question",
            "type": "integer",
            "minimum": 2,
            "maximum": 6,
            "default": 4
          },
          "seed": {
            "title": "Seed (same seed = same quiz)",
            "type": "string",
            "maxLength": 40,
            "default": "atlas"
          },
          "paper": {
            "title": "Paper for the sheet",
            "type": "string",
            "enum": [
              "a4",
              "letter",
              "a3"
            ],
            "default": "a4"
          }
        },
        "required": []
      },
      "CartographCountryQuizResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "settings",
              "pool",
              "questions",
              "pdf",
              "cards",
              "openInApp"
            ],
            "properties": {
              "settings": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "kind",
                  "region",
                  "count",
                  "choices",
                  "seed"
                ],
                "properties": {
                  "kind": {
                    "type": "string"
                  },
                  "region": {
                    "type": "string"
                  },
                  "count": {
                    "type": "integer"
                  },
                  "choices": {
                    "type": "integer"
                  },
                  "seed": {
                    "type": "string"
                  }
                }
              },
              "pool": {
                "type": "integer",
                "description": "Countries the quiz could ask about in this region."
              },
              "questions": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "n",
                    "id",
                    "iso2",
                    "question",
                    "options",
                    "answer",
                    "answerLetter"
                  ],
                  "properties": {
                    "n": {
                      "type": "integer"
                    },
                    "id": {
                      "type": "string",
                      "description": "Card id kind:ISO2 (the review history uses it)."
                    },
                    "iso2": {
                      "type": "string"
                    },
                    "question": {
                      "type": "string"
                    },
                    "options": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "answer": {
                      "type": "string"
                    },
                    "answerLetter": {
                      "type": "string"
                    }
                  }
                }
              },
              "pdf": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "artifactId",
                  "filename",
                  "mime",
                  "bytes",
                  "sha256",
                  "path"
                ],
                "properties": {
                  "artifactId": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string",
                    "description": "Download path on the same site (valid for about 2 hours)."
                  }
                }
              },
              "cards": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "artifactId",
                  "filename",
                  "mime",
                  "bytes",
                  "sha256",
                  "path"
                ],
                "properties": {
                  "artifactId": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string",
                    "description": "Download path on the same site (valid for about 2 hours)."
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}