{"openapi":"3.1.0","info":{"title":"London Night Guide Content API","version":"1.0.0","summary":"Free, read-only content API for London nightlife information.","description":"London Night Guide is a free London nightlife concierge (guestlists, VIP tables, event planning). This spec covers the public machine surface: every content URL negotiates markdown for agents, `.md` path variants serve the same output, and discovery files (llms.txt, sitemap, RSS) are listed below. No authentication, no API keys, no rate-limit registration. There is no write API — bookings are confirmed by a human concierge via the forms at https://londonnightguide.com/book-guestlist/ and https://londonnightguide.com/book-vip-table/ or the WhatsApp links published in llms.txt. Unknown /api/* paths return a structured JSON error envelope.","contact":{"name":"London Night Guide Concierge","email":"concierge@londonnightguide.com","url":"https://londonnightguide.com/contact/"}},"externalDocs":{"description":"Human-readable API and agent documentation","url":"https://londonnightguide.com/developers/"},"servers":[{"url":"https://londonnightguide.com","description":"Production"}],"tags":[{"name":"content","description":"Posts, pages and archives (HTML/markdown negotiation)"},{"name":"markdown","description":"Explicit .md representations"},{"name":"discovery","description":"Machine-readable discovery files"},{"name":"meta","description":"API index and error contract"}],"paths":{"/":{"get":{"summary":"Homepage","description":"Site overview: featured venues, services, categories and FAQs. Serves text/html by default; send `Accept: text/markdown` (RFC 9110 q-values honoured) to receive a clean markdown representation of the same content. An Accept header that allows neither representation returns 406.","tags":["content"],"responses":{"200":{"description":"The page, as HTML or markdown depending on the Accept header.","headers":{"Vary":{"description":"Markdown responses always include Accept.","schema":{"type":"string"}}},"content":{"text/html":{"schema":{"type":"string"}},"text/markdown":{"schema":{"type":"string"}}}},"404":{"description":"Not found. The markdown body lists recovery links (homepage, llms.txt, sitemap, category hubs).","headers":{"Vary":{"description":"Always includes Accept.","schema":{"type":"string"}}},"content":{"text/markdown":{"schema":{"type":"string"}}}},"406":{"description":"The Accept header allows neither text/html nor text/markdown.","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/{slug}/":{"get":{"summary":"Post or page by slug","description":"Any of the ~700 content pages: venue guestlist pages, table booking pages, guides, blog posts. Slugs are enumerated in https://londonnightguide.com/sitemap.xml and https://londonnightguide.com/llms.txt. Serves text/html by default; send `Accept: text/markdown` (RFC 9110 q-values honoured) to receive a clean markdown representation of the same content. An Accept header that allows neither representation returns 406.","tags":["content"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Post or page slug, e.g. tape-club-guestlist","schema":{"type":"string"},"example":"tape-club-guestlist"}],"responses":{"200":{"description":"The page, as HTML or markdown depending on the Accept header.","headers":{"Vary":{"description":"Markdown responses always include Accept.","schema":{"type":"string"}}},"content":{"text/html":{"schema":{"type":"string"}},"text/markdown":{"schema":{"type":"string"}}}},"404":{"description":"Not found. The markdown body lists recovery links (homepage, llms.txt, sitemap, category hubs).","headers":{"Vary":{"description":"Always includes Accept.","schema":{"type":"string"}}},"content":{"text/markdown":{"schema":{"type":"string"}}}},"406":{"description":"The Accept header allows neither text/html nor text/markdown.","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/category/{slug}/":{"get":{"summary":"Category archive","description":"All pages in a category (clubs, events, dress-code, entry-fee, bottle-prices, …). Serves text/html by default; send `Accept: text/markdown` (RFC 9110 q-values honoured) to receive a clean markdown representation of the same content. An Accept header that allows neither representation returns 406.","tags":["content"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Category slug, e.g. clubs","schema":{"type":"string"},"example":"tape-club-guestlist"}],"responses":{"200":{"description":"The page, as HTML or markdown depending on the Accept header.","headers":{"Vary":{"description":"Markdown responses always include Accept.","schema":{"type":"string"}}},"content":{"text/html":{"schema":{"type":"string"}},"text/markdown":{"schema":{"type":"string"}}}},"404":{"description":"Not found. The markdown body lists recovery links (homepage, llms.txt, sitemap, category hubs).","headers":{"Vary":{"description":"Always includes Accept.","schema":{"type":"string"}}},"content":{"text/markdown":{"schema":{"type":"string"}}}},"406":{"description":"The Accept header allows neither text/html nor text/markdown.","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/tag/{slug}/":{"get":{"summary":"Tag archive","description":"All pages carrying a tag. Serves text/html by default; send `Accept: text/markdown` (RFC 9110 q-values honoured) to receive a clean markdown representation of the same content. An Accept header that allows neither representation returns 406.","tags":["content"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Tag slug","schema":{"type":"string"},"example":"tape-club-guestlist"}],"responses":{"200":{"description":"The page, as HTML or markdown depending on the Accept header.","headers":{"Vary":{"description":"Markdown responses always include Accept.","schema":{"type":"string"}}},"content":{"text/html":{"schema":{"type":"string"}},"text/markdown":{"schema":{"type":"string"}}}},"404":{"description":"Not found. The markdown body lists recovery links (homepage, llms.txt, sitemap, category hubs).","headers":{"Vary":{"description":"Always includes Accept.","schema":{"type":"string"}}},"content":{"text/markdown":{"schema":{"type":"string"}}}},"406":{"description":"The Accept header allows neither text/html nor text/markdown.","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/index.md":{"get":{"summary":"Homepage as markdown","tags":["markdown"],"responses":{"200":{"description":"Markdown overview of the site: services, open venues, categories, contact.","headers":{"Vary":{"description":"Always includes Accept.","schema":{"type":"string"}}},"content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/{slug}.md":{"get":{"summary":"Post or page as markdown","description":"Same content as /{slug}/ rendered as markdown. Sent with X-Robots-Tag: noindex (the canonical URL is /{slug}/).","tags":["markdown"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Post or page slug","schema":{"type":"string"},"example":"tape-club-guestlist"}],"responses":{"200":{"description":"The page as markdown: title, venue facts, body, FAQs, booking links.","headers":{"Vary":{"description":"Always includes Accept.","schema":{"type":"string"}}},"content":{"text/markdown":{"schema":{"type":"string"}}}},"404":{"description":"Not found. The markdown body lists recovery links (homepage, llms.txt, sitemap, category hubs).","headers":{"Vary":{"description":"Always includes Accept.","schema":{"type":"string"}}},"content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/category/{slug}.md":{"get":{"summary":"Category archive as markdown","tags":["markdown"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Category slug, e.g. clubs","schema":{"type":"string"},"example":"tape-club-guestlist"}],"responses":{"200":{"description":"Category title, description and a link list of member pages.","headers":{"Vary":{"description":"Always includes Accept.","schema":{"type":"string"}}},"content":{"text/markdown":{"schema":{"type":"string"}}}},"404":{"description":"Not found. The markdown body lists recovery links (homepage, llms.txt, sitemap, category hubs).","headers":{"Vary":{"description":"Always includes Accept.","schema":{"type":"string"}}},"content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/tag/{slug}.md":{"get":{"summary":"Tag archive as markdown","tags":["markdown"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Tag slug","schema":{"type":"string"},"example":"tape-club-guestlist"}],"responses":{"200":{"description":"Tag title and a link list of member pages.","headers":{"Vary":{"description":"Always includes Accept.","schema":{"type":"string"}}},"content":{"text/markdown":{"schema":{"type":"string"}}}},"404":{"description":"Not found. The markdown body lists recovery links (homepage, llms.txt, sitemap, category hubs).","headers":{"Vary":{"description":"Always includes Accept.","schema":{"type":"string"}}},"content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/llms.txt":{"get":{"summary":"Agent guide (llmstxt.org format)","description":"When to use this site, how to call it, and curated links to every key page.","tags":["discovery"],"responses":{"200":{"description":"The llms.txt file.","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/openapi.json":{"get":{"summary":"This specification","tags":["discovery"],"responses":{"200":{"description":"OpenAPI 3.1 document.","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/sitemap.xml":{"get":{"summary":"XML sitemap of all indexable URLs","tags":["discovery"],"responses":{"200":{"description":"Sitemap.","content":{"application/xml":{"schema":{"type":"string"}}}}}}},"/feed/":{"get":{"summary":"RSS feed of the 50 most recent posts","tags":["discovery"],"responses":{"200":{"description":"RSS 2.0 feed.","content":{"application/rss+xml":{"schema":{"type":"string"}}}}}}},"/api":{"get":{"summary":"API index","description":"JSON directory of the public endpoints, documentation and discovery files.","tags":["meta"],"responses":{"200":{"description":"Index of the API surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiIndex"}}}},"405":{"description":"Any method other than GET/HEAD.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/{path}":{"get":{"summary":"Unknown API path","description":"There are no other public API endpoints. Any unknown path under /api/ returns a structured JSON error with a resolution hint (all methods).","tags":["meta"],"parameters":[{"name":"path","in":"path","required":true,"description":"Any unrecognised API path.","schema":{"type":"string"}}],"responses":{"404":{"description":"Structured JSON error envelope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}}},"components":{"schemas":{"ApiError":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["status","code","message","hint"],"properties":{"status":{"type":"integer","description":"HTTP status code.","example":404},"code":{"type":"string","description":"Machine-readable error code.","example":"not_found"},"message":{"type":"string","description":"Human-readable explanation.","example":"No API endpoint exists at /api/example."},"hint":{"type":"string","description":"How to resolve the error.","example":"GET https://londonnightguide.com/api for an endpoint index."}}}}},"ApiIndex":{"type":"object","required":["name","documentation","openapi","endpoints"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"documentation":{"type":"string","format":"uri"},"openapi":{"type":"string","format":"uri"},"llms_txt":{"type":"string","format":"uri"},"sitemap":{"type":"string","format":"uri"},"authentication":{"type":"string","const":"none"},"endpoints":{"type":"array","items":{"type":"object","required":["method","path"],"properties":{"method":{"type":"string"},"path":{"type":"string"},"description":{"type":"string"}}}},"booking":{"type":"string"}}}}}}