{
  "openapi": "3.1.0",
  "info": {
    "title": "Bad Historian Content API",
    "version": "1.0.0",
    "summary": "Read-only catalogue of self-guided audio walking tours.",
    "description": "Every document is a static JSON file regenerated on each build of badhistorian.com.\n\nNo authentication is required and there are no rate limits — see /auth.md.\n\nNote: `subtitle` and `tags` are in the schema but not yet populated — always\nnull and empty respectively. Filter on `tour_type`, `neighborhood` and\n`description`.\n\nThis API describes the catalogue, not the writing. Tour narration is the paid\nproduct: no endpoint returns a transcript, an excerpt of one, the stop audio,\nor the quiz facts, and no parameter unlocks them.",
    "contact": {
      "name": "Bad Historian",
      "email": "hello@badhistorian.com",
      "url": "https://badhistorian.com"
    },
    "termsOfService": "https://badhistorian.com/terms"
  },
  "servers": [
    {
      "url": "https://badhistorian.com",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Human-readable docs",
    "url": "https://badhistorian.com/docs/api/"
  },
  "paths": {
    "/api/catalog.json": {
      "get": {
        "operationId": "getCatalogue",
        "summary": "API root — counts and endpoint templates",
        "tags": [
          "meta"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/health.json": {
      "get": {
        "operationId": "getStatus",
        "summary": "Freshness of the published snapshot",
        "tags": [
          "meta"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/cities.json": {
      "get": {
        "operationId": "listCities",
        "summary": "All published cities",
        "tags": [
          "cities"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "cities": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/City"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/cities/{city_slug}.json": {
      "get": {
        "operationId": "getCity",
        "summary": "One city, with its tours and attractions",
        "tags": [
          "cities"
        ],
        "parameters": [
          {
            "name": "city_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "chicago",
                "florence",
                "london",
                "mallorca",
                "new-orleans",
                "new-york",
                "northern-michigan",
                "paris",
                "rome",
                "san-francisco",
                "washington-dc"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/City"
                }
              }
            }
          }
        }
      }
    },
    "/api/tours.json": {
      "get": {
        "operationId": "listTours",
        "summary": "All published tours across every city",
        "tags": [
          "tours"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "tours": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TourSummary"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tours/{city_slug}/{tour_slug}.json": {
      "get": {
        "operationId": "getTour",
        "summary": "One tour, including its ordered stops",
        "tags": [
          "tours"
        ],
        "parameters": [
          {
            "name": "city_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "chicago",
                "florence",
                "london",
                "mallorca",
                "new-orleans",
                "new-york",
                "northern-michigan",
                "paris",
                "rome",
                "san-francisco",
                "washington-dc"
              ]
            }
          },
          {
            "name": "tour_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TourDetail"
                }
              }
            }
          }
        }
      }
    },
    "/api/attractions.json": {
      "get": {
        "operationId": "listAttractions",
        "summary": "All published attractions",
        "tags": [
          "attractions"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "attractions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Attraction"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Coordinates": {
        "type": "object",
        "properties": {
          "latitude": {
            "type": "number"
          },
          "longitude": {
            "type": "number"
          }
        },
        "required": [
          "latitude",
          "longitude"
        ]
      },
      "CityRef": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "country": {
            "type": "string"
          }
        },
        "required": [
          "slug",
          "name",
          "country"
        ]
      },
      "City": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "tagline": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "coordinates": {
            "$ref": "#/components/schemas/Coordinates"
          },
          "image_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "trailer_audio_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "tour_count": {
            "type": "integer"
          },
          "attraction_count": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "api_url": {
            "type": "string",
            "format": "uri"
          },
          "tours": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TourSummary"
            }
          },
          "attractions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Attraction"
            }
          }
        },
        "required": [
          "slug",
          "name",
          "country",
          "url"
        ]
      },
      "TourSummary": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "description": "Search name — the URL segment"
          },
          "title": {
            "type": "string",
            "description": "Editorial name — the hook"
          },
          "subtitle": {
            "type": [
              "string",
              "null"
            ],
            "description": "Plain name — what you are actually buying. Not yet populated: currently null on every tour."
          },
          "city": {
            "$ref": "#/components/schemas/CityRef"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "neighborhood": {
            "type": [
              "string",
              "null"
            ]
          },
          "tour_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Not yet populated: currently empty on every tour."
          },
          "duration_minutes": {
            "type": [
              "integer",
              "null"
            ]
          },
          "stop_count": {
            "type": [
              "integer",
              "null"
            ],
            "description": "null in list responses; populated on the per-tour document"
          },
          "price_usd": {
            "type": [
              "number",
              "null"
            ]
          },
          "currency": {
            "type": "string"
          },
          "is_free_preview": {
            "type": "boolean"
          },
          "cover_image_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "trailer_audio_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "api_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        },
        "required": [
          "slug",
          "title",
          "city",
          "url"
        ]
      },
      "TourDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TourSummary"
          },
          {
            "type": "object",
            "properties": {
              "stops": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Stop"
                }
              }
            },
            "required": [
              "stops"
            ]
          }
        ]
      },
      "Stop": {
        "type": "object",
        "properties": {
          "order": {
            "type": "integer",
            "description": "1-based position along the route"
          },
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "latitude": {
            "type": "number"
          },
          "longitude": {
            "type": "number"
          },
          "geofence_radius_meters": {
            "type": [
              "integer",
              "null"
            ]
          },
          "short_blurb": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_preview": {
            "type": "boolean"
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        },
        "required": [
          "order",
          "title",
          "latitude",
          "longitude"
        ]
      },
      "Attraction": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "city": {
            "$ref": "#/components/schemas/CityRef"
          },
          "category": {
            "type": "string",
            "enum": [
              "landmark",
              "museum",
              "monument",
              "park",
              "historic_site"
            ]
          },
          "short_blurb": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "coordinates": {
            "$ref": "#/components/schemas/Coordinates"
          },
          "image_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "is_free": {
            "type": "boolean"
          },
          "is_featured": {
            "type": "boolean"
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        },
        "required": [
          "slug",
          "name",
          "category",
          "coordinates"
        ]
      }
    }
  },
  "tags": [
    {
      "name": "meta",
      "description": "Catalogue and snapshot status"
    },
    {
      "name": "cities",
      "description": "Cities with published tours"
    },
    {
      "name": "tours",
      "description": "Walking tours and their stops"
    },
    {
      "name": "attractions",
      "description": "Individual places"
    }
  ]
}
