Interne REST-API

Datenversorgung für interne Tools — nur mit gültigem API-Key zugänglich.

Öffentliche, rate-limitierte API ohne Key: Öffentliche API-Dokumentation →

Base URLhttps://api.gemeindeverzeichnis.de/api/internal

Authentication

Base-URL: https://api.gemeindeverzeichnis.de/api/internal/ — kein Redirect, kein Header-Verlust. Bitte immer diese Domain verwenden.

Alle Anfragen benötigen einen Bearer-Token im Authorization-Header.

Authorization: Bearer <INTERNAL_API_KEY>

Bei fehlendem oder falschem Key: HTTP 404 (nicht 401) — um die Existenz des Endpunkts nicht zu verraten.

Rate Limits

Die interne API ist vom öffentlichen Rate-Limiter ausgenommen. Es gibt kein erzwungenes Limit pro Minute. Die List- und Einzeleintrags-Endpunkte werden 5 Minuten serverseitig gecacht. Der /changes-Endpunkt ist immer unkached (no-store).

GET/api/internal/gemeinden

Gemeindeliste mit Filtern

Gibt eine paginierte Liste aller Gemeinden zurück. Unterstützt Filterung nach Bundesland, Gemeindetyp und Freitextsuche. Nutzt Cursor-basierte Paginierung.

Query-Parameter

ParameterTypPflichtBeschreibung
bundeslandstringNeinAGS des Bundeslandes (2-stellig, z.B. 08 für BW)
satzartstringNein60 = Gemeinde, 50 = Gemeindefreies Gebiet
qstringNeinFreitextsuche in Name, normalisiertem Namen, AGS
cursorstringNeinAGS des letzten Elements der Vorseite
limitintegerNeinEinträge pro Seite. Standard: 100, max: 500
fieldsstringNeinSparse Fieldset: kommagetrennte Feldliste (z.B. fields=ags,name,email_pattern). Nur Array-Syntax wird nicht unterstützt.

Beispiel

curl -H "Authorization: Bearer <KEY>" \
  "https://api.gemeindeverzeichnis.de/api/internal/gemeinden?bundesland=08&limit=50"

Response

{
  "data": [
    {
      "ags": "08111000",
      "name": "Stuttgart",
      "bundesland_text": "Baden-Württemberg",
      "population_total": 626275,
      "chief_admin_name_full": "Dr. Frank Nopper",
      "chief_admin_job_title": "Oberbürgermeister",
      "chief_admin_gender": "male",
      "chief_admin_salutation_german": "Sehr geehrter Herr Dr. Nopper",
      "chief_admin_email": "oberbuergemeister@stuttgart.de",
      "contact_email": "poststelle@stuttgart.de",
      "website": "https://www.stuttgart.de"
    }
  ],
  "meta": {
    "total": 1101,
    "count": 50,
    "cursor": "08115081",
    "has_more": true,
    "generated_at": "2026-04-22T01:48:00.000Z",
    "data_freshness": "2026-04-22T02:00:00Z"
  }
}

Solange meta.has_more === true, den Wert aus meta.cursor als ?cursor= im nächsten Request übergeben.

GET/api/internal/gemeinden/{ags}

Einzeleintrag per AGS

Gibt einen einzelnen Eintrag zurück. Nutzt einen In-Memory-Hash-Map für O(1)-Lookup — schneller als der Listendpunkt für einzelne Einträge.

Pfad-Parameter

ParameterTypBeschreibung
agsstring8-stellig (Gemeinde) oder 12-stellig (Verbandsgemeinde/VVG), z.B. 08111000

Beispiel

curl -H "Authorization: Bearer <KEY>" \
  "https://api.gemeindeverzeichnis.de/api/internal/gemeinden/08111000"

Response

{
  "data": {
    "ags": "08111000",
    "name": "Stuttgart",
    ...
  }
}

Response-Header

HeaderBeschreibung
X-Wikidata-TimestampISO-Zeitstempel des letzten Wikidata-Updates für diesen Eintrag
X-Data-Generated-AtZeitstempel der Response-Generierung

Gibt 400 zurück wenn AGS nicht 8-stellig numerisch ist. Gibt 404 zurück wenn die Gemeinde nicht gefunden wurde.

GET/api/internal/gemeinden/changes

Delta-Sync: geänderte Einträge

Gibt nur Gemeinden zurück, deren wikidata_person_timestamp nach dem angegebenen since-Zeitpunkt liegt. Ideal für tägliche Sync-Jobs — nur abholen was sich geändert hat. Response ist nie gecacht.

Query-Parameter

ParameterTypPflichtBeschreibung
sincestringJaISO 8601 Datetime, z.B. 2026-04-20T00:00:00Z
cursorstringNeinAGS des letzten Elements der Vorseite
limitintegerNeinStandard: 100, max: 500

Beispiel

curl -H "Authorization: Bearer <KEY>" \
  "https://api.gemeindeverzeichnis.de/api/internal/gemeinden/changes?since=2026-04-20T00:00:00Z"

Response

{
  "data": [ { "ags": "...", ... } ],
  "meta": {
    "since": "2026-04-20T00:00:00.000Z",
    "total_changed": 47,
    "count": 47,
    "cursor": null,
    "has_more": false,
    "generated_at": "2026-04-22T01:48:00.000Z"
  }
}

Nur Einträge mit bekanntem wikidata_person_timestamp erscheinen im Changes-Feed. Einträge ohne Wikidata-Treffer werden ausgelassen.

GET/api/internal/pendler/{ags}

Pendler-Zeitreihe 2013–2023 (API-Key erforderlich)

Gibt historische Ein- und Auspendlerzahlen einer Gemeinde zurück. Quelle: Pendleratlas / Bundesagentur für Arbeit, Daten für 2013–2023. Deckt ca. 10.750 Gemeinden ab (AGS 8-stellig).

Dieser Endpunkt erfordert einen Bearer-Token — identisch zu den anderen internen Endpunkten. Cache-Control: private, max-age=300.

Pfad-Parameter

ParameterTypBeschreibung
agsstring8-stellig numerisch, z.B. 09162000 für München

Query-Parameter

ParameterTypPflichtBeschreibung
yearintegerNeinEinzeljahr filtern (2013–2023). Ohne year: alle Jahre.

Alle Jahre (ohne year-Parameter)

curl -H "Authorization: Bearer <KEY>" \
  "https://api.gemeindeverzeichnis.de/api/internal/pendler/09162000"

# Response
{
  "ags": "09162000",
  "data": [
    { "year": 2013, "commute_in": 358212, "commute_out": 136819, "commute_within": 421338, "commute_saldo": 221393 },
    { "year": 2014, "commute_in": 368431, ... },
    ...
    { "year": 2023, "commute_in": 457594, "commute_out": 203136, "commute_within": 502434, "commute_saldo": 254458 }
  ]
}

Einzeljahr (?year=2020)

curl -H "Authorization: Bearer <KEY>" \
  "https://api.gemeindeverzeichnis.de/api/internal/pendler/09162000?year=2020"

# Response
{
  "ags": "09162000",
  "year": 2020,
  "commute_in": 413547,
  "commute_out": 183633,
  "commute_within": 483743,
  "commute_saldo": 229914
}

Fehler bei unbekanntem Jahr

# year=1990 existiert nicht
{
  "error": "Kein Datensatz für Jahr 1990",
  "available_years": [2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023]
}

Felder

FeldTypBeschreibung
commute_inintegerEinpendler (sozialversicherungspflichtig Beschäftigte, die von außerhalb einpendeln)
commute_outintegerAuspendler (Beschäftigte, die in eine andere Gemeinde auspendeln)
commute_withinintegerBinnenpendler (wohnen und arbeiten in der gleichen Gemeinde)
commute_saldointegerPendlersaldo: commute_in − commute_out (positiv = Einpendlerüberschuss)
yearintegerBerichtsjahr (2013–2023)

Die commute_*-Felder stehen auch im Gemeinde-Einzelabruf (/api/internal/gemeinden/{ags}) zur Verfügung und enthalten jeweils den Wert des neuesten verfügbaren Jahres. Für die vollständige Zeitreihe diesen Endpunkt verwenden.

Felder

Alle Endpunkte geben dieselbe Feldmenge zurück (Allowlist in frontend/lib/data.ts).

Identifikatoren

FeldBeschreibung
ags8-stellig für Gemeinden, 12-stellig für Verbandsgemeinden/VVG — VARCHAR(12) verwenden
ars12-stelliger Amtlicher Regionalschlüssel
uuidInterne Datensatz-ID
wikidata_idWikidata-Kennung (z.B. Q1022)
wikipedia_urlWikipedia-URL der Gemeinde

Typ & Klassifikation

FeldBeschreibung
satzartHierarchie-Ebene: 10=Land, 40=Kreis, 50=Gemeindeverband, 60=Gemeinde
satzart_textBezeichnung der Hierarchie-Ebene (z.B. "Gemeinde")
textkennzeichenNumerischer Typ-Code
textkennzeichen_text✅ Empfohlener Klartext-Gattungsbegriff (z.B. "Kreisfreie Stadt", "Gemeinde", "Markt") — Nachfolger von name_raw
is_citytrue wenn Gemeinde eine Stadt ist (aus textkennzeichen_text abgeleitet)
is_display_relevanttrue wenn Eintrag für Verzeichnisanzeige vorgesehen

Name

FeldBeschreibung
nameAnzeigename (z.B. Stuttgart)
name_raw⚠ Deprecated — inkonsistentes Format (6+ Varianten), textkennzeichen_text verwenden
name_baseBasisname ohne Zusätze
normalized_display_nameNormalisiert für Suche
city_typeStadttyp-Zusatz (z.B. Landeshauptstadt)

Geografie

FeldBeschreibung
bundeslandBundesland-Kürzel (z.B. BW)
bundesland_textBundesland-Name
bundesland_agsBundesland-AGS (2-stellig)
kreis_agsKreis-AGS (5-stellig)
landkreis_textLandkreis-Name
gemeindeverband_textGemeindeverbands-Name
plz_arrayArray aller PLZ der Gemeinde
area_km2Fläche in km²

Bevölkerung

FeldBeschreibung
population_totalEinwohnerzahl gesamt
population_maleEinwohner männlich
population_femaleEinwohner weiblich
population_densityEinwohner pro km²
population_reference_dateStichtag der Bevölkerungsdaten
population_sourceDatenquelle

Pendler-Daten

FeldBeschreibung
commute_inEinpendler (neuestes verfügbares Jahr, siehe commute_year)
commute_outAuspendler
commute_withinBinnenpendler
commute_saldoPendlersaldo (commute_in − commute_out)
commute_yearBerichtsjahr des aktuellen Werts (i.d.R. 2023). Zeitreihe: GET /api/pendler/{ags}

Adresse Rathaus

FeldBeschreibung
address_verwaltungssitzVerwaltungssitz
address_strasseStraße und Hausnummer
address_plzPLZ des Rathauses
address_ortOrt des Rathauses

Kontakt

FeldBeschreibung
contact_phoneTelefon
contact_faxFax
contact_emailAllgemeine E-Mail-Adresse
websiteWebsite der Gemeinde
email_domainE-Mail-Domain (z.B. stuttgart.de)
email_patternErkanntes E-Mail-Muster

Bürgermeister / Verwaltungsleitung

FeldBeschreibung
chief_admin_name_fullVollständiger Name (z.B. Dr. Frank Nopper)
chief_admin_name_prefixTitel (z.B. Dr.)
chief_admin_name_givenVorname
chief_admin_name_middleZweiter Vorname
chief_admin_name_familyNachname
chief_admin_name_suffixNamenssuffix
chief_admin_job_titleAmtsbezeichnung (z.B. Oberbürgermeister)
chief_admin_partyPartei
chief_admin_genderGeschlecht: male / female / null (wenn confidence < 70)
chief_admin_gender_confidenceKonfidenz-Score 0–100
chief_admin_gender_sourceHerkunft des Genders: wikidata | firstname_classifier | null
chief_admin_salutation_germanDeutsche Anrede (null wenn confidence < 70)
chief_admin_salutation_neutral✅ Immer befüllt: gendered Anrede wenn confidence ≥ 70, sonst "Sehr geehrte Damen und Herren"
chief_admin_salutation_enEnglische Anrede (z.B. "Dear Mr Nopper" / "Dear Sir or Madam")
chief_admin_emailDirekte E-Mail-Adresse
chief_admin_birth_yearGeburtsjahr
chief_admin_amtsantrittJahr des Amtsantritts
chief_admin_wahlvorschlagWahlvorschlag / Partei
chief_admin_professional_statusBeruflicher Status
data_quality_flagsArray mit Flags: gender_unresolved | gender_low_confidence | no_wikidata | stale_wikidata | no_chief_admin

Zeitstempel

FeldBeschreibung
wikidata_person_timestampLetztes Wikidata-Update für diese Person
last_updatedLetztes Update des Eintrags
reference_dateStichtag der Gesamtdaten

Sync-Workflow

Empfohlenes Muster für einen Laravel-Consumer: vollständiger Erstimport über den Listendpunkt, danach tägliche Delta-Updates über den Changes-Endpunkt.

Erstimport

$cursor = null;
do {
    $response = Http::withToken($apiKey)
        ->get('https://api.gemeindeverzeichnis.de/api/internal/gemeinden', [
            'limit'  => 500,
            'cursor' => $cursor,
        ]);

    $body   = $response->json();
    $cursor = $body['meta']['cursor'];

    // Datensätze in Datenbank speichern

} while ($body['meta']['has_more']);

Täglicher Delta-Sync

$since = now()->subDay()->toIso8601String();

$response = Http::withToken($apiKey)
    ->get('https://api.gemeindeverzeichnis.de/api/internal/gemeinden/changes', [
        'since' => $since,
    ]);

$changed = $response->json()['data'];
// Nur geänderte Einträge aktualisieren

Fehlercodes

StatusBedeutung
200Erfolg
400Ungültiger Parameter (z.B. falsches AGS-Format oder fehlendes since)
404Nicht gefunden — oder unautorisiert (interne Endpunkte geben bei ungültigem Key 404 zurück)
500Interner Serverfehler