Finanzamts-Schnittstelle für Programme

Steuersoft Tools · zuständiges Amt und Zuständigkeitsbezirk als JSON · Zugang mit Schlüssel
← Zur Finanzamtsuche
Was die Schnittstelle beantwortet. Dieselben beiden Fragen wie die Finanzamtsuche, nur für aufrufende Programme: Welches Amt ist für diesen Wohnsitz zuständig? und welcher Bezirk gehört zu dieser Amtsnummer? Grundlage ist das amtliche Verzeichnis der Finanzämter (Bundeszentralamt für Steuern), Stand Ämter, zugeordnete Gemeinden. Antworten sind JSON in UTF-8, jede Antwort führt den Datenstand mit.

Zwei Zusagen, auf die man sich verlassen kann — und muss

1. Die Antwort ist immer eine Liste, nie ein einzelnes Amt

Von den Postleitzahlen im Verzeichnis führen zu mehreren Ämtern, von den Gemeindeschlüsseln . In Berlin sind 17 Ämter für dieselbe Gemeinde zuständig, in Hamburg 10, in Köln 7. Was dort entscheidet — Bezirk, Straße oder Anfangsbuchstabe des Nachnamens — steht im amtlichen Verzeichnis nicht. Eine Schnittstelle, die in diesen Fällen eines der Ämter zurückgibt, liefert mit hoher Wahrscheinlichkeit das falsche.

Deshalb: aemter ist stets ein Array, und eindeutig sagt ausdrücklich, ob genau ein Amt zuständig ist. Bei eindeutig: false erklärt hinweis den Grund. Aufrufende Programme sollten in diesem Fall nachfragen statt zu wählen — die verlässliche Auskunft steht im letzten Steuerbescheid.

2. Der Gemeindeschlüssel ist der belastbare Schlüssel, die Postleitzahl ein Behelf

Der achtstellige amtliche Gemeindeschlüssel bezeichnet die Gemeinde eindeutig. Eine Postleitzahl kann dagegen bis zu 39 Gemeinden umfassen und über Gemeindegrenzen hinweg reichen. Wer den Schlüssel führt, sollte ags benutzen; plz ist für die Fälle gedacht, in denen nur die Anschrift bekannt ist.

Zugang

Basisadressehttps://tools.steuersoft.de/api
VerfahrenGET für die Auskunft, HEAD zum reinen Nachsehen (Kopfzeilen mit ETag, kein Rumpf). Antwort application/json; charset=utf-8.
ZugangsschlüsselErforderlich. Jeder Aufruf führt ihn als Kopfzeile mit — entweder X-API-Key: <Schlüssel> oder Authorization: Bearer <Schlüssel>. Ohne Schlüssel antwortet die Schnittstelle mit 401, mit gesperrtem Schlüssel mit 403. Schlüssel werden von Steuersoft vergeben und sind jederzeit widerrufbar.
Nicht in der AdresseDer Schlüssel wird ausschließlich als Kopfzeile angenommen, ?key=… wird abgewiesen. Grund: das Zugriffsprotokoll führt die angefragte Adresse mit — ein Schlüssel darin wäre dauerhaft mitgeschrieben.
Aufruf aus dem BrowserTechnisch erlaubt (Access-Control-Allow-Origin: *), aber nicht empfohlen: der Schlüssel läge dann im Seitenquelltext der aufrufenden Anwendung und wäre damit für jeden lesbar. Die Schnittstelle gehört auf die Serverseite des aufrufenden Programms.
ZwischenspeicherCache-Control: public, max-age=3600. Das Verzeichnis wird monatlich fortgeschrieben; stand in jeder Antwort taugt zum Abgleich.
Häufigkeit20 Anfragen je Sekunde und Adresse, kurzzeitig mehr. Darüber antwortet der Dienst mit 429. Wer viele Fälle zuordnen muss, holt nicht einzeln ab, sondern einmal den Gesamtbestand und schlägt örtlich nach.
Fehler400 fehlende oder unbrauchbare Angabe · 401 Schlüssel fehlt oder unbekannt · 403 Schlüssel gesperrt · 404 Amtsnummer unbekannt · 429 zu häufig · 503 Verzeichnis vorübergehend nicht verfügbar. Der Text steht in detail.

Ein Nachschlagen ohne Treffer ist kein Fehler: es antwortet mit 200, anzahl_aemter: 0 und einem hinweis.

Endpunkte

GET/api/finanzamt?ags=… | ?plz=… | ?ort=…
Zuständiges Amt zu einer Gemeinde. Genau einer der drei Parameter ist anzugeben.
ParameterBedeutung
agsAmtlicher Gemeindeschlüssel, achtstellig. Ein kürzerer Wert wirkt als Vorsatz und liefert alle Gemeinden darunter (z. B. 10 für das Saarland, 10044 für den Landkreis Saarlouis).
plzPostleitzahl, fünfstellig.
ortGemeinde- oder Ortsname, mindestens drei Zeichen. Teiltreffer genügen, Groß-/Kleinschreibung und Umlaute sind unerheblich (gross-gerau findet Groß-Gerau). Genaue Namensgleichheit steht oben.
gemeinden1 = zu jedem Amt gleich den vollständigen Zuständigkeitsbezirk mitliefern. Vorgabe 0.
limitHöchstzahl berücksichtigter Gemeindetreffer, 1–200, Vorgabe 20.
GET /api/finanzamt?ags=10044111

{
  "stand": "03.08.2026",
  "stand_quelle": "20260803_0846",
  "frage": { "ags": "10044111" },
  "eindeutig": true,
  "anzahl_aemter": 1,
  "anzahl_gemeinden": 1,
  "hinweis": null,
  "aemter": [ { "bufa_nr": "1010", "name": "Saarlouis", … } ],
  "gemeinden": [
    { "ags": "10044111", "name": "Dillingen/ Saar, Stadt",
      "plz": "66763", "kreis": "Saarlouis", "bufa_nr": "1010" }
  ]
}
GET/api/finanzamt/{amtsnummer}
Ein Amt anhand seiner vierstelligen Amtsnummer (Bundesfinanzamtsnummer) — mit Erreichbarkeit, Anschrift, Postfach, Bankverbindung der Finanzkasse und Servicezeiten. Mit ?gemeinden=1 zusätzlich der Bezirk.
GET /api/finanzamt/1010

{ "stand": "03.08.2026", …, "amt": { "bufa_nr": "1010", … } }
GET/api/finanzamt/{amtsnummer}/bezirk
Nur der Zuständigkeitsbezirk: alle dem Amt zugeordneten Gemeinden mit Schlüssel, Postleitzahl und Kreis. Die Gegenrichtung des Nachschlagens — geeignet, um im eigenen Programm eine Zuordnungstabelle aufzubauen.
GET /api/finanzamt/1010/bezirk

{ "stand": "03.08.2026", "bufa_nr": "1010",
  "bezeichnung": "Finanzamt Saarlouis", "bundesland": "Saarland",
  "ohne_bezirk": false, "anzahl": 13,
  "gemeinden": [ { "ags": "10044111", "name": "Dillingen/ Saar, Stadt",
                   "plz": "66763", "kreis": "Saarlouis" }, … ] }
GET/api/finanzaemter
Ohne jeden Parameter kommt der vollständige Bestand — alle Ämter des Bundesgebiets in einem Abruf. Mit gemeinden=1 zusätzlich je Amt sein Zuständigkeitsbezirk, also die komplette Zuordnung Gemeinde → Amt ( Zuordnungen). Zum Vorhalten im aufrufenden Programm.
ParameterBedeutung
— keiner —Der ganze Bestand. vollstaendig: true bestätigt, dass nichts abgeschnitten wurde.
gemeinden1 = je Amt den vollständigen Zuständigkeitsbezirk mitliefern. Das ist der Abruf für eine eigene Zuordnungstabelle.
bundeslandName des Landes, Teiltreffer genügt.
nameTeil des Amtsnamens, z. B. Körperschaften oder Bewertung.
ohne_bezirk1 = nur Ämter ohne regionalen Bezirk, 0 = nur Ämter mit Bezirk.
limit / offsetNur nötig, wenn seitenweise abgeholt werden soll. limit 1–600; 0 oder weggelassen heißt: alle. gesamt nennt stets die Zahl aller Treffer, vollstaendig sagt, ob die Antwort sie alle enthält.
GET /api/finanzaemter?gemeinden=1

{
  "stand": "03.08.2026",
  "vollstaendig": true,
  "gesamt": 593,
  "anzahl": 593,
  "anzahl_gemeinden": 10818,
  "aemter": [
    { "bufa_nr": "1010", "bezeichnung": "Finanzamt Saarlouis", …,
      "gemeinden": [ { "ags": "10044111", "name": "Dillingen/ Saar, Stadt",
                       "plz": "66763", "kreis": "Saarlouis" }, … ] }, …
  ]
}

Den ganzen Bestand abholen

Für eine eigene Zuordnungstabelle genügt ein Abruf. Er liefert alle Ämter samt ihren Gemeinden:

curl --compressed -H "X-API-Key: $STS_FA_KEY" \
     "https://tools.steuersoft.de/api/finanzaemter?gemeinden=1"

Etwa 1,4 MB unkomprimiert, rund 200 KB übertragen. Ohne gemeinden=1 sind es nur die Ämter ohne Bezirke (deutlich kleiner). Die Antwort ist je Datenstand unverändert dieselbe und wird in wenigen Millisekunden ausgeliefert.

Nachsehen, ob sich etwas geändert hat — ohne alles erneut zu laden

Der Bestand wird monatlich fortgeschrieben. Die Antwort trägt ein ETag; wer es beim nächsten Mal mitschickt, bekommt bei unverändertem Stand 304 Not Modified ohne Rumpf zurück:

# erster Abruf: ETag merken
curl -sD - -o bestand.json -H "X-API-Key: $STS_FA_KEY" \
     "https://tools.steuersoft.de/api/finanzaemter?gemeinden=1" | grep -i ^etag
# ETag: W/"20260803_0846-mit_gemeinden"

# spaeter: nur pruefen, ob es etwas Neues gibt
curl -s -o /dev/null -w "%{http_code}\n" -H "X-API-Key: $STS_FA_KEY" \
     -H 'If-None-Match: W/"20260803_0846-mit_gemeinden"' \
     "https://tools.steuersoft.de/api/finanzaemter?gemeinden=1"
# 304  -> unveraendert, nichts zu tun
# 200  -> neuer Stand, Rumpf enthaelt ihn

Noch einfacher geht es mit HEAD: das liefert nur die Kopfzeilen samt ETag und Content-Length, ganz ohne Rumpf — auch ohne dass der Aufrufer bedingte Anfragen beherrschen muss.

curl -sI -H "X-API-Key: $STS_FA_KEY" \
     "https://tools.steuersoft.de/api/finanzaemter?gemeinden=1" | grep -i etag
# ETag: W/"20260803_0846-mit_gemeinden"

Wer kein ETag auswerten will, vergleicht das Feld stand (bzw. stand_quelle) mit dem selbst vorgehaltenen Wert — es steht in jeder Antwort der Schnittstelle.

PowerShell

$kopf = @{ "X-API-Key" = $env:STS_FA_KEY }
$b = Invoke-RestMethod "https://tools.steuersoft.de/api/finanzaemter?gemeinden=1" -Headers $kopf
"{0} Ämter, {1} Gemeinden, Stand {2}" -f $b.gesamt, $b.anzahl_gemeinden, $b.stand

# Zuordnungstabelle Gemeindeschlüssel -> Amtsnummer aufbauen
$zuordnung = @{}
foreach ($amt in $b.aemter) {
  foreach ($g in $amt.gemeinden) { $zuordnung[$g.ags] = $amt.bufa_nr }
}
$zuordnung["10044111"]   # 1010

Achtung bei der eigenen Tabelle: ein Gemeindeschlüssel kann zu mehreren Ämtern gehören (Berlin, Hamburg, Köln und weitere Großstädte). Wer wie oben stumpf zuweist, behält je Schlüssel nur das zuletzt gesehene Amt. Für diese Fälle eine Liste je Schlüssel führen — oder sie an der Zahl der Ämter erkennen und zurückfragen.

Selbst ausprobieren

Hierfür ist ein Zugangsschlüssel nötig. Er wird nicht in dieser Seite hinterlegt — diese Seite ist öffentlich. Eingetragen bleibt er nur im Speicher dieses Browsers und wird ausschließlich als Kopfzeile an die Schnittstelle geschickt.
Noch nichts abgerufen.

Beispiele zum Einsetzen: /api/finanzamt?ags=10044111 · /api/finanzamt?plz=10178 (mehrere Ämter) · /api/finanzamt?ort=Dillingen · /api/finanzamt/1010?gemeinden=1 · /api/finanzamt/1010/bezirk · /api/finanzaemter?bundesland=Saarland · /api/finanzaemter (ganzer Bestand) · /api/finanzaemter?gemeinden=1 (mit allen Gemeinden)

Felder eines Amtes

FeldInhalt
bufa_nrVierstellige Amtsnummer (Bundesfinanzamtsnummer). Eindeutig, geeignet als Schlüssel in eigenen Datenbeständen.
name · bezeichnungName des Amtes ohne bzw. mit vorangestelltem „Finanzamt“.
bundeslandLand, in dem das Amt liegt.
anschrift.artdienstsitz oder zentraler_posteingang. Wichtig: der Ämter teilen ihre Anschrift mit anderen — in Kiel 28, in Berlin 24, in Dresden 23. Diese Adresse ist der Posteingang des Landes, nicht das Dienstgebäude. anschrift.geteilt_mit_aemtern nennt die Zahl der Mitnutzer. Post dorthin muss die Amtsnummer tragen.
postfachPostfach des Amtes oder null. Für den Schriftwechsel meist die genauere Angabe als die Anschrift.
kontakt.mail_artpoststelle oder datenschutzbeauftragter. Wichtig: Von den hinterlegten Adressen gehören die meisten dem Datenschutzbeauftragten, nicht der Poststelle. Wer kontakt.mail ungeprüft für Steuerpost verwendet, schreibt an die falsche Stelle — dieses Feld sagt, welche Art vorliegt.
bankverbindungIBAN, BIC, Kreditinstitut und Kontoinhaber der Finanzkasse, oder null. IBAN ohne Leerzeichen.
oeffnungszeitenArray von Freitextzeilen, wie im Verzeichnis geführt. Nicht strukturiert und nicht für maschinelle Auswertung geeignet.
ohne_bezirktrue, wenn keine Gemeinden zugeordnet sind. Dahinter stehen überwiegend besondere Aufgaben — Grundsteuer-Bewertung und Groß-/Konzernbetriebsprüfung sind die größten Gruppen, dazu Körperschaften, Fahndung und Strafsachen, Verkehrsteuern, Erbschaft- und Schenkungsteuer —, teils Verwaltungsstellen anderer Ämter. Solche Ämter sind über den Wohnsitz nicht erreichbar, nur über Nummer oder Name.
anzahl_gemeindenGröße des Zuständigkeitsbezirks.

Felder können hinzukommen; vorhandene Felder werden nicht umbenannt und nicht in ihrer Bedeutung geändert. Ein aufrufendes Programm sollte unbekannte Felder überlesen.

Beispiele

Kommandozeile

curl -s -H "X-API-Key: $STS_FA_KEY" \
     "https://tools.steuersoft.de/api/finanzamt?ags=10044111"

Den Schlüssel nicht in Skripte schreiben, sondern aus einer Umgebungsvariablen oder einer nur für den Dienstnutzer lesbaren Datei ziehen.

PowerShell

$kopf = @{ "X-API-Key" = $env:STS_FA_KEY }
$a = Invoke-RestMethod "https://tools.steuersoft.de/api/finanzamt?plz=66740" -Headers $kopf
if ($a.eindeutig) { $a.aemter[0].bezeichnung } else { Write-Warning $a.hinweis }

Delphi

uses System.Net.HttpClient, System.JSON, System.NetEncoding;

function ZustaendigesAmt(const AGemeindeschluessel: string): string;
var
  Client: THTTPClient;
  Antwort: IHTTPResponse;
  Wurzel: TJSONObject;
  Aemter: TJSONArray;
begin
  Result := '';
  Client := THTTPClient.Create;
  try
    // Zugangsschluessel als Kopfzeile, nie als Adressbestandteil.
    Client.CustomHeaders['X-API-Key'] := SchluesselAusKonfiguration;
    Antwort := Client.Get('https://tools.steuersoft.de/api/finanzamt?ags=' +
                          TNetEncoding.URL.Encode(AGemeindeschluessel));
    if Antwort.StatusCode <> 200 then Exit;
    Wurzel := TJSONObject.ParseJSONValue(Antwort.ContentAsString(TEncoding.UTF8)) as TJSONObject;
    try
      // Mehrere zustaendige Aemter sind moeglich (Berlin, Hamburg, Koeln).
      // Dann NICHT eines auswaehlen, sondern zurueckfragen.
      if not Wurzel.GetValue<Boolean>('eindeutig') then Exit;
      Aemter := Wurzel.GetValue<TJSONArray>('aemter');
      if Aemter.Count > 0 then
        Result := (Aemter.Items[0] as TJSONObject).GetValue<string>('bufa_nr');
    finally
      Wurzel.Free;
    end;
  finally
    Client.Free;
  end;
end;

JavaScript

// Serverseitig aufrufen — im Browser waere der Schluessel oeffentlich.
const r = await fetch('https://tools.steuersoft.de/api/finanzamt?plz=66740',
                      { headers: { 'X-API-Key': process.env.STS_FA_KEY } });
const a = await r.json();
if (!a.eindeutig) console.warn(a.hinweis);
console.log(a.aemter.map(x => `${x.bufa_nr} ${x.bezeichnung}`));

Was das Verzeichnis nicht enthält

Rechtlicher Rahmen

Der zurückgegebene Bezirk gibt die örtliche Zuständigkeit nach dem Wohnsitz wieder — für die Einkommensteuer natürlicher Personen also § 19 Abs. 1 AO. Abweichend gelten: § 20 AO für Körperschaften (Ort der Geschäftsleitung), § 21 AO für die Umsatzsteuer (mit eigener Verordnung für Unternehmer ohne Sitz im Inland), § 41a Abs. 1 EStG für die Lohnsteuer (Betriebsstättenfinanzamt), § 18 AO für gesonderte Feststellungen, § 22 AO für Realsteuermessbeträge und § 35 ErbStG für die Erbschaft- und Schenkungsteuer. Der Zuständigkeitswechsel beim Umzug tritt nach § 26 AO ein, sobald das neue Amt von den maßgeblichen Umständen erfährt. Die sachliche Zuständigkeit richtet sich nach § 17 AO in Verbindung mit dem Finanzverwaltungsgesetz.

Die Angaben stammen aus dem amtlichen Verzeichnis der Finanzämter (Bundeszentralamt für Steuern) und enthalten keine personenbezogenen Daten. Zuständigkeiten und Erreichbarkeiten können sich seit dem angegebenen Stand geändert haben; im Zweifel gilt die Auskunft des Amtes. Die Schnittstelle wird ohne Zusage einer Verfügbarkeit bereitgestellt.