API & Agenten
Eine kostenlose, selbstbediente API für Schweizer Baugesuche — aggregiert
aus 14 kantonalen Amtsblatt-Quellen (über die öffentliche amtsblattportal.ch-API),
harmonisiert in ein Modell (bgch.v1) und als JSON & XML abrufbar.
Aktuell 2'926 Publikationen aus
13 Kantonen / 462 Gemeinden
(Stand: 10.07.2026, älteste: 09.06.2026).
Swagger-Docs OpenAPI JSON /meta (Live-Coverage) MCP-Server llms-full.txt llms.txt RSS
Garantie & rechtlicher Hinweis
- Never-Prune-Garantie: Es wird nichts gelöscht. Jede je erfasste
Publikation bleibt abfragbar, ihre XML-/PDF-Links bleiben auflösbar, solange dieser Dienst
läuft. Sicher, um langlebige Mirrors, Archive oder Agenten auf
/changeszu bauen. - Rechtsverbindlich ist ausschliesslich die signierte amtliche PDF-Publikation
(
source.official_pdf_url/links.pdfauf jedem Datensatz). Alles andere hier — JSON, harmonisiertes XML, Titel, Beschreibungen — ist die bestmögliche Darstellung dieses Aggregators, keine amtliche Publikation. - Maschinenformate: alle Datumsangaben sind ISO 8601 (
YYYY-MM-DD, Zeitstempel mit Zeitzone). Nur die Website-Anzeige nutztDD.MM.YYYY.
Auth & Rate-Limits
Zugriff ist ohne Anmeldung möglich. Ein kostenloser Key hebt das Limit an — mehr braucht es nicht.
| Limit | Header | |
|---|---|---|
| Anonym (pro IP) | 120 Requests / Stunde | X-RateLimit-Limit, -Remaining, -Reset; bei 429 zusätzlich Retry-After |
| Mit Key | 5000 Requests / Stunde |
Key mitgeben als HTTP-Header: Authorization: Bearer bg_<key>.
Key unten anfordern (Double-Opt-in per E-Mail, wird genau einmal angezeigt).
Quickstart
Startpunkt für Agenten: /llms-full.txt (vollständige Referenz, agent-optimiert) oder /api/docs (Swagger). Alle Beispiele unten funktionieren so wie sie sind (echte Werte).
curl — Liste, Filter, Cursor
# List + filter: energy/heating permits in canton Zürich matching "Wärmepumpe"
curl -s "https://baugesuche.switchli.ch/api/v1/publications?canton=ZH&category=energie_heizung&q=W%C3%A4rmepumpe&limit=5"
# With a free key (5000 req/h instead of 120):
curl -s -H "Authorization: Bearer bg_your_key_here" \
"https://baugesuche.switchli.ch/api/v1/publications?canton=ZH&limit=5"
# Follow the cursor to the next page: take next_cursor from the response above,
# pass it back as &cursor=... — stable under infinite history (no OFFSET).
curl -s "https://baugesuche.switchli.ch/api/v1/publications?canton=ZH&limit=5&cursor=NEXT_CURSOR_FROM_PREVIOUS_RESPONSE"
# One full record (JSON), incl. links to the official PDF/XML:
curl -s "https://baugesuche.switchli.ch/api/v1/publications/d22d21f6-e361-4655-bd1d-8c2350863cdb"
Python — urllib (no dependencies)
import json
import urllib.parse
import urllib.request
BASE = "https://baugesuche.switchli.ch/api/v1"
# API_KEY = "bg_your_key_here" # optional: raises the rate limit to 5000/h
def get(path, **params):
url = f"{BASE}{path}?" + urllib.parse.urlencode({k: v for k, v in params.items() if v})
req = urllib.request.Request(url, headers={"Accept": "application/json"})
# req.add_header("Authorization", "Bearer " + API_KEY) # uncomment with a key
with urllib.request.urlopen(req, timeout=15) as r:
return json.load(r)
# Filtered search
page = get("/publications", canton="ZH", category="energie_heizung", q="Wärmepumpe", limit=5)
print(page["total"], "matches")
for item in page["items"]:
print(item["publication_date"], item["municipality"]["name"], "-", item["title"][:70])
# Paginate every match with the keyset cursor
cursor = ""
while True:
page = get("/publications", canton="ZH", category="energie_heizung", limit=50, cursor=cursor)
for item in page["items"]:
pass # ... process item (bgch.v1 dict)
cursor = page["next_cursor"]
if not cursor:
break
JavaScript — fetch
const BASE = "https://baugesuche.switchli.ch/api/v1";
// const API_KEY = "bg_your_key_here"; // optional: 5000 req/h
async function search(params) {
const qs = new URLSearchParams(params).toString();
const res = await fetch(`${BASE}/publications?${qs}`, {
headers: {
"Accept": "application/json",
// "Authorization": `Bearer ${API_KEY}`, // uncomment with a key
},
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
const page = await search({ canton: "ZH", category: "energie_heizung", q: "Wärmepumpe", limit: 5 });
console.log(page.total, "matches");
for (const item of page.items) {
console.log(item.publication_date, item.municipality.name, item.title);
}
// Next page: search({ canton: "ZH", limit: 50, cursor: page.next_cursor })
MCP-Server (für KI-Agenten)
Der differenzierende Teil: ein Model-Context-Protocol-Server über
Streamable HTTP unter https://baugesuche.switchli.ch/mcp. Agenten (z. B. Claude) verbinden
sich direkt und rufen Tools auf — ohne eigenen API-Client zu schreiben.
| Tool | Zweck |
|---|---|
search_baugesuche | Volltext-/Filtersuche (Kanton, Kategorie, Gemeinde, Datum) → bgch.v1-Datensätze. |
get_baugesuch | Ein vollständiger Datensatz per ID, inkl. Links zur amtlichen PDF/XML. |
get_coverage | Abgedeckte Kantone, Zahlen, ältester/neuester Datensatz, Garantie & Hinweis. |
Verbindung (Claude Desktop / Agent-Config), stateless — keine Session nötig:
{
"mcpServers": {
"baugesuche": {
"type": "streamable-http",
"url": "https://baugesuche.switchli.ch/mcp"
}
}
}
Roher JSON-RPC-Aufruf über Streamable HTTP (Antwort ist Server-Sent-Events; die
JSON-RPC-Nutzlast steht in der data:-Zeile):
curl -s -X POST "https://baugesuche.switchli.ch/mcp" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"search_baugesuche",
"arguments":{"query":"Wärmepumpe","canton":"ZH","limit":3}}}'
Kostenlosen API-Key anfordern
Optional — nur nötig, wenn 120 Requests/Stunde nicht reichen. Sie erhalten eine Bestätigungs-E-Mail (Double-Opt-in); der Key wird danach genau einmal angezeigt. Wir speichern nur den SHA-256-Hash.
Endpunkte & weiterführende Links
| Endpunkt | Zweck |
|---|---|
GET /api/v1/meta | Coverage, Taxonomie, Zahlen, Schema-/Docs-/MCP-URLs — hier starten. |
GET /api/v1/publications | Gefilterte, keyset-paginierte Liste (bgch.v1). |
GET /api/v1/publications/{id} | Ein Datensatz als JSON (.xml harmonisiert, /original.xml amtliches Passthrough). |
GET /api/v1/changes?since=… | Inkrementeller Sync über ingested_at für Agenten/Mirrors. |
POST /api/v1/keys | Kostenloser Key (Double-Opt-in per E-Mail). |
/api/docs | Interaktive Swagger-Dokumentation. |
/api/v1/openapi.json | OpenAPI-3-Schema (Codegen). |
/mcp | MCP-Server (Streamable HTTP, POST) für Agenten — Details & Beispiel oben. |
/llms-full.txt | Vollständige agent-optimierte Referenz (Plain Text). |
/feed.xml | RSS, unterstützt dieselben Filter-Parameter. |
Kanton-Codes
ZH Zürich · BE Bern · SZ Schwyz · OW Obwalden · NW Nidwalden · ZG Zug · SO Solothurn · BS Basel-Stadt · BL Basel-Landschaft · SH Schaffhausen · AR Appenzell A.Rh. · TI Tessin · VS Wallis · CH weitere Gemeinden.
Abdeckung: ZH ist von Gesetzes wegen vollständig; AG fehlt bewusst (nicht über amtsblattportal.ch publiziert).
Live-Zahlen pro Kanton: /api/v1/meta.
Kategorie-Codes (statische Taxonomie, multi-label)
energie_heizung Energie & Heizung · solar_pv Solar & PV · neubau_wohnen Neubau Wohnen · umbau_sanierung Umbau & Sanierung · abbruch Abbruch · kleinbauten Kleinbauten · gewerbe_industrie Gewerbe & Industrie · landwirtschaft Landwirtschaft · aussenanlagen_infrastruktur Aussenanlagen & Infrastruktur · sonstiges Sonstiges.