Content API
11 cities · 55 tours · 396 places. Read-only JSON. No key, no signup, no rate limits.
The Bad Historian tour catalogue as JSON: which tours exist, where they walk, how long they take and what they cost. It is a static build artefact, regenerated every time the site deploys, so it is fast, cacheable, and never down independently of the site. It carries no tour narration — see What is not in it below.
Quick start
curl https://badhistorian.com/api/tours.json Endpoints
-
/api/catalog.json— Catalogue root — counts and the URL template for every other endpoint. -
/api/health.json— How fresh this snapshot is, and how many records it holds. -
/api/cities.json— Every published city, with tour and attraction counts. -
/api/cities/chicago.json— One city, expanded with all of its tours and attractions. -
/api/tours.json— Every published tour: title, description, neighbourhood, type, duration, price. -
/api/tours/san-francisco/flower-power-rainbow-flags.json— One tour with its ordered stops — titles, coordinates, geofence radius, one-line blurb. -
/api/attractions.json— Every published place, with coordinates and category. -
/api/openapi.json— OpenAPI 3.1 description of all of the above.
Fields that are currently empty
subtitle and tags exist in the schema but are not yet
populated — always null and []. They are kept in the
response so clients written today keep working when the data lands. Filter and
describe using tour_type, neighborhood and
description.
What is not in it
This is the catalogue, not the writing. The API returns no narration — no transcripts, no excerpts or previews of them, no stop audio, and no quiz facts. There is no endpoint that returns them and no parameter that unlocks them. The stories are the thing you buy, and they live in the app.
What you do get for each stop is its title, position on the route, coordinates and one-line description — enough to say what a tour walks past and how far it goes.
Authentication and limits
There are none. No key, no token, no registration, no quota. Please cache
responses rather than re-fetching in a loop, and identify your client with a
descriptive User-Agent so we can tell agents apart from scrapers.
The full statement is at /auth.md.
Using it
Attribution is appreciated but not required. Content remains ours under the
Terms of Service;
the API is a convenience for building on top of it, not a licence to republish the
tours wholesale. Our robots.txt declares
ai-train=no, search=yes, ai-input=yes — you are welcome to read this
data to answer someone's question, and asked not to train on it. Reproducing the
catalogue wholesale as a competing listing is not what this is for.
Machine-readable discovery
-
/.well-known/api-catalog— RFC 9727 linkset pointing at this API -
/.well-known/ai-catalog.json— ARD capability manifest -
/.well-known/agent-skills/index.json— Agent Skills discovery index -
/llms.txt— Plain-language site summary -
/auth.md— Authentication — there is none, and why
The homepage also returns Link headers
(api-catalog, service-desc, service-doc,
describedby) and registers WebMCP tools in supporting browsers.