{"openapi":"3.1.0","info":{"title":"Baugesuche Schweiz API","description":"\nFree, self-service API for Swiss building-permit publications (**Baugesuche**),\naggregated daily from 14 cantonal Amtsblatt sources via the public amtsblattportal.ch\nAPI. Harmonized into one model (`bgch.v1`) across the ≥3 XML dialects the sources\nactually use, with the original source XML preserved verbatim alongside it.\n\n**Legal disclaimer:** the only legally binding document is the signed official PDF\nlinked from every record (`source.official_pdf_url` / `links.pdf`). Everything else\nhere — JSON, harmonized XML, titles, descriptions — is this aggregator's best-effort\nrepresentation, not an official publication.\n\n**Infinite-history guarantee:** nothing is ever pruned. Every publication ever\ningested stays queryable and its `xml_original`/PDF links stay resolvable for as\nlong as this service runs — safe to build long-lived mirrors, archives, or agents\nagainst `/changes`.\n\n**Auth & rate limits:** anonymous requests are allowed at 120 req/h/IP. A free,\nself-service API key (`POST /keys`, double opt-in by email) raises that to\n5000 req/h — pass it as `Authorization: Bearer bg_<key>`. Every response carries\n`X-RateLimit-Limit` / `X-RateLimit-Remaining` / `X-RateLimit-Reset`; a 429 carries\n`Retry-After`.\n\n**Start here:** the human + agent quickstart with copy-paste curl/Python/JS examples\nlives at [`/api`](/api). Agent-optimized full reference: [`/llms-full.txt`](/llms-full.txt).\nFor AI agents there is also an **MCP server** (Model Context Protocol, streamable HTTP)\nat [`/mcp`](/mcp) exposing `search_baugesuche`, `get_baugesuch` and `get_coverage`.\n","version":"1.0"},"servers":[{"url":"https://baugesuche.switchli.ch","description":"Production"}],"paths":{"/api/v1/publications":{"get":{"tags":["publications"],"summary":"List publications (keyset-paginated)","description":"Filtered, keyset-paginated listing of bgch.v1 publications. Stable under infinite history: page continuation never uses OFFSET.","operationId":"list_publications_api_v1_publications_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"canton","in":"query","required":false,"schema":{"type":"string","description":"CSV of canton codes.","examples":["ZH,BE"],"default":"","title":"Canton"},"description":"CSV of canton codes."},{"name":"category","in":"query","required":false,"schema":{"type":"string","description":"CSV of category codes (see /meta for the full list).","examples":["energie_heizung"],"default":"","title":"Category"},"description":"CSV of category codes (see /meta for the full list)."},{"name":"municipality","in":"query","required":false,"schema":{"type":"string","description":"CSV of exact municipality names.","examples":["Winterthur"],"default":"","title":"Municipality"},"description":"CSV of exact municipality names."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Free-text substring match across title, description, municipality and Projektverfasser.","examples":["Wärmepumpe"],"default":"","title":"Q"},"description":"Free-text substring match across title, description, municipality and Projektverfasser."},{"name":"from","in":"query","required":false,"schema":{"type":"string","description":"Publication date lower bound (inclusive), ISO 8601 date.","examples":["2026-06-01"],"default":"","title":"From"},"description":"Publication date lower bound (inclusive), ISO 8601 date."},{"name":"to","in":"query","required":false,"schema":{"type":"string","description":"Publication date upper bound (inclusive), ISO 8601 date.","examples":["2026-07-01"],"default":"","title":"To"},"description":"Publication date upper bound (inclusive), ISO 8601 date."},{"name":"ingested_since","in":"query","required":false,"schema":{"type":"string","description":"Only records first ingested at/after this ISO 8601 timestamp.","examples":["2026-07-01T00:00:00+00:00"],"default":"","title":"Ingested Since"},"description":"Only records first ingested at/after this ISO 8601 timestamp."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"Opaque pagination cursor from a previous response's `next_cursor`.","examples":["MjAyNi0wNy0wMXxpZC1hYmMxMjM"],"default":"","title":"Cursor"},"description":"Opaque pagination cursor from a previous response's `next_cursor`."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Page size, max 200.","examples":[50],"default":50,"title":"Limit"},"description":"Page size, max 200."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationsPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/publications/{pid}.xml":{"get":{"tags":["publications"],"summary":"Get one publication (bgch.v1 harmonized XML)","operationId":"get_publication_xml_api_v1_publications__pid__xml_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"pid","in":"path","required":true,"schema":{"type":"string","title":"Pid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}},"application/xml":{}}},"404":{"description":"No publication with this id."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/publications/{pid}/original.xml":{"get":{"tags":["publications"],"summary":"Get the official source XML (passthrough)","description":"Byte-for-byte as originally fetched from amtsblattportal.ch. 404 if this record hasn't been backfilled yet — see refetch_originals.py.","operationId":"get_publication_original_xml_api_v1_publications__pid__original_xml_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"pid","in":"path","required":true,"schema":{"type":"string","title":"Pid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}},"application/xml":{}}},"404":{"description":"Not backfilled yet, or not found."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/publications/{pid}":{"get":{"tags":["publications"],"summary":"Get one publication (bgch.v1 JSON)","operationId":"get_publication_api_v1_publications__pid__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"pid","in":"path","required":true,"schema":{"type":"string","title":"Pid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Publication"}}}},"404":{"description":"No publication with this id."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/changes":{"get":{"tags":["changes"],"summary":"Incremental sync — records changed since a timestamp","description":"For agents/mirrors polling deltas: pass `next_since` from this response back as `since` to continue. Ordered by ingested_at, not publication_date — never splits a batch across pages.","operationId":"changes_api_v1_changes_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"since","in":"query","required":true,"schema":{"type":"string","description":"ISO 8601 timestamp; only records ingested strictly after this.","examples":["2026-07-01T00:00:00+00:00"],"title":"Since"},"description":"ISO 8601 timestamp; only records ingested strictly after this."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Soft page-size cap (see description).","examples":[200],"default":200,"title":"Limit"},"description":"Soft page-size cap (see description)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangesPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/meta":{"get":{"tags":["meta"],"summary":"Coverage, taxonomy and service metadata","operationId":"meta_api_v1_meta_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Meta"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/keys":{"post":{"tags":["keys"],"summary":"Request a free API key (double opt-in)","description":"Free, self-service, no approval needed. Sends a verification email; the actual key is generated and shown exactly once, at the verify link — only its SHA-256 hash is ever stored.","operationId":"request_key_api_v1_keys_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyRequestAck"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}}},"components":{"schemas":{"CantonCoverage":{"properties":{"code":{"type":"string","title":"Code","examples":["ZH"]},"label":{"type":"string","title":"Label","examples":["Zürich"]},"count":{"type":"integer","title":"Count","description":"Total publications on file for this canton (infinite history)."}},"type":"object","required":["code","label","count"],"title":"CantonCoverage"},"CategoryInfo":{"properties":{"code":{"type":"string","title":"Code","examples":["energie_heizung"]},"label":{"type":"string","title":"Label","examples":["Energie & Heizung"]}},"type":"object","required":["code","label"],"title":"CategoryInfo"},"ChangesPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Publication"},"type":"array","title":"Items","description":"Records first ingested at/after `since`, oldest first."},"next_since":{"type":"string","title":"Next Since","description":"Pass as `since` on the next poll to continue exactly where this page left off."},"count":{"type":"integer","title":"Count","description":"Number of items in this page."}},"type":"object","required":["items","next_since","count"],"title":"ChangesPage"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"KeyRequest":{"properties":{"email":{"type":"string","title":"Email","description":"Email address to send the double-opt-in verification link to.","examples":["you@example.com"]}},"type":"object","required":["email"],"title":"KeyRequest"},"KeyRequestAck":{"properties":{"status":{"type":"string","title":"Status","examples":["verification_sent"]},"message":{"type":"string","title":"Message","examples":["Check your inbox at you@example.com for the verification link."]}},"type":"object","required":["status","message"],"title":"KeyRequestAck"},"Links":{"properties":{"html":{"type":"string","title":"Html","description":"Human-facing detail page on this site."},"json":{"type":"string","title":"Json","description":"This record as bgch.v1 JSON."},"xml":{"type":"string","title":"Xml","description":"This record as bgch.v1 harmonized XML."},"xml_original":{"type":"string","title":"Xml Original","description":"Official source XML passthrough; 404 until backfilled for older records."},"pdf":{"type":"string","title":"Pdf","description":"Signed official PDF, proxied with a human filename."}},"type":"object","required":["html","json","xml","xml_original","pdf"],"title":"Links"},"Location":{"properties":{"raw":{"type":"string","title":"Raw","description":"Address/location as published, unparsed.","default":"","examples":["Bahnhofstrasse 12, 8400 Winterthur"]}},"type":"object","title":"Location"},"Meta":{"properties":{"total_publications":{"type":"integer","title":"Total Publications","description":"Total publications on file, all time (never pruned)."},"oldest_publication_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Oldest Publication Date","description":"Oldest publication_date on file, ISO 8601."},"newest_publication_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Newest Publication Date","description":"Newest publication_date on file, ISO 8601."},"municipalities_count":{"type":"integer","title":"Municipalities Count","description":"Distinct municipalities represented."},"cantons":{"items":{"$ref":"#/components/schemas/CantonCoverage"},"type":"array","title":"Cantons","description":"Per-canton record counts."},"categories":{"items":{"$ref":"#/components/schemas/CategoryInfo"},"type":"array","title":"Categories","description":"The frozen D-005 category taxonomy with labels."},"schema_url":{"type":"string","title":"Schema Url","description":"OpenAPI schema for this API."},"docs_url":{"type":"string","title":"Docs Url","description":"Human-readable API docs."},"mcp_url":{"type":"string","title":"Mcp Url","description":"Planned MCP (Model Context Protocol) server location for agent tooling."},"infinite_history":{"type":"boolean","title":"Infinite History","description":"Guarantee: this API never prunes historical records.","default":true},"disclaimer":{"type":"string","title":"Disclaimer","description":"Legal disclaimer: only the signed official PDF is legally binding."}},"type":"object","required":["total_publications","municipalities_count","cantons","categories","schema_url","docs_url","mcp_url","disclaimer"],"title":"Meta"},"Municipality":{"properties":{"name":{"type":"string","title":"Name","description":"Municipality name as published.","examples":["Winterthur"]},"slug":{"type":"string","title":"Slug","description":"URL-safe slug used in /gemeinde/{slug}.","examples":["winterthur"]}},"type":"object","required":["name","slug"],"title":"Municipality"},"Publication":{"properties":{"id":{"type":"string","title":"Id","description":"Stable internal identifier (opaque, source-derived).","examples":["3f1c2a90-3b1a-4e6a-9c1a-000000000000"]},"publication_number":{"type":"string","title":"Publication Number","description":"Official publication number.","default":"","examples":["2026-012345"]},"source":{"$ref":"#/components/schemas/Source"},"canton":{"type":"string","title":"Canton","description":"Canton code (ISO 3166-2:CH; CH for cross-cantonal municipal tenants).","examples":["ZH"]},"municipality":{"$ref":"#/components/schemas/Municipality"},"publication_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publication Date","description":"Official publication date, ISO 8601.","examples":["2026-07-01"]},"expiration_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expiration Date","description":"Official expiration/decision date, ISO 8601, if published."},"entry_deadline":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entry Deadline","description":"Einsprache-/Auflagefrist deadline, ISO 8601, if published."},"title":{"type":"string","title":"Title","description":"Official title as published.","default":""},"description":{"type":"string","title":"Description","description":"Project description as published.","default":""},"categories":{"items":{"type":"string"},"type":"array","title":"Categories","description":"Static taxonomy D-005 codes (multi-label, frozen set — see /meta).","examples":[["energie_heizung","solar_pv"]]},"building_contractor":{"type":"string","title":"Building Contractor","description":"Bauherrschaft, as officially published (display string).","default":""},"project_framer":{"type":"string","title":"Project Framer","description":"Projektverfasser, as officially published (display string).","default":""},"location":{"$ref":"#/components/schemas/Location"},"parcel":{"type":"string","title":"Parcel","description":"Parcel / zone reference, as published.","default":""},"ingested_at":{"type":"string","title":"Ingested At","description":"When this aggregator first stored the record, ISO 8601 UTC.","examples":["2026-07-01T04:31:02+00:00"]},"links":{"$ref":"#/components/schemas/Links"},"_disclaimer":{"type":"string","title":"Disclaimer","description":"Legal disclaimer: only the signed official PDF is legally binding."}},"type":"object","required":["id","source","canton","municipality","location","ingested_at","links","_disclaimer"],"title":"Publication","description":"bgch.v1 — the harmonized data model (AGENT_FIRST_PLAN.md, \"Data model\nbgch.v1\"). JSON here is canonical; /publications/{id}.xml serializes the\nidentical model as XML."},"PublicationsPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Publication"},"type":"array","title":"Items","description":"Page of publications, newest publication_date first."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as `cursor` to fetch the next page; null when there is no further page."},"total":{"type":"integer","title":"Total","description":"Total records matching the filters, independent of pagination."}},"type":"object","required":["items","total"],"title":"PublicationsPage"},"Source":{"properties":{"tenant":{"type":"string","title":"Tenant","description":"Source-system tenant key on amtsblattportal.ch.","examples":["kabzh"]},"subrubric":{"type":"string","title":"Subrubric","description":"Source sub-rubric code this record was polled under.","examples":["BP-ZH01"]},"official_detail_url":{"type":"string","title":"Official Detail Url","description":"Human-facing detail page on the cantonal Amtsblatt portal.","examples":["https://amtsblatt.zh.ch/#!/search/publications/detail/abcd-1234"]},"official_pdf_url":{"type":"string","title":"Official Pdf Url","description":"Official signed PDF, as served by amtsblattportal.ch.","examples":["https://amtsblattportal.ch/api/v1/publications/abcd-1234/pdf"]}},"type":"object","required":["tenant","subrubric","official_detail_url","official_pdf_url"],"title":"Source"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"HTTPBearer":{"type":"http","description":"Free API key from POST /keys, format `bg_<32 urlsafe chars>`. Anonymous requests are allowed at a lower rate limit.","scheme":"bearer"}}},"tags":[{"name":"publications","description":"Query and fetch individual bgch.v1 publications (JSON/XML/original)."},{"name":"changes","description":"Incremental sync for agents and mirrors — poll deltas by ingested_at."},{"name":"meta","description":"Coverage, taxonomy and service metadata — start here."},{"name":"keys","description":"Free, self-service API keys (double opt-in by email)."}]}