prospex
Anmelden

Die Zefix-REST-API: Endpunkte, Zugang und Identifikatoren

10 Min. Lesezeit

Zefix fasst die Einträge aller 26 kantonalen Handelsregister in einem eidgenössischen Index zusammen. Die meisten begegnen ihm als Suchfeld auf zefix.admin.ch. Seine REST-API ermöglicht Firmenabfragen über UID oder EHRA-ID und Suchen nach Name. Sie liefert auch Beziehungsdaten und tägliche Handelsregisterpublikationen. Der Zugang ist gratis, aber das Bundesamt für Justiz muss zuerst Zugangsdaten ausstellen.

Verwenden Sie REST für gezielte Abfragen und Beziehungsdaten. Für einen Massendurchlauf des Registers verwenden Sie den weiter unten beschriebenen LINDAS-Datensatz.

API-Zugangsdaten anfordern

Jeder Endpunkt verlangt HTTP-Basic-Authentifizierung, in der OpenAPI-Spezifikation als Zefix-Credentials bezeichnet. Anfragen ohne Authorization-Header liefern 401, auch Firmenabfragen und Suchen.

Benutzername und Passwort erhalten Sie beim Bundesamt für Justiz über [email protected]. Stellen Sie sich kurz vor und beschreiben Sie Ihr Vorhaben samt erwartetem Volumen. Verwenden Sie beides als HTTP-Basic-Zugangsdaten. Konfigurieren Sie sie einmal beim Erzeugen des HTTP-Clients.

Die Dokumentation nennt kein Rate Limit. Wir halten von uns aus einen Mindestabstand von 0.5 Sekunden zwischen zwei Anfragen ein und wiederholen 429 und 5xx mit exponentiellem Backoff. Dieser Anfragerhythmus hat in unserem Produktivbetrieb keine Drosselung ausgelöst. Er hält den Datenverkehr auch bis zur Veröffentlichung eines formalen Limits moderat.

Die aktuelle OpenAPI-Spezifikation prüfen

Zefix veröffentlicht eine OpenAPI-3.1-Spezifikation für die REST-API. Die rohe Spezifikation und die Swagger-Oberfläche sind online verfügbar. Am 12. August 2026 wies die Spezifikation API-Version 2.7.2.3 aus.

Prüfen Sie sie auf aktuelle Endpunkte und Feldnamen. Bestätigen Sie Enum-Werte und Validierungsregeln, bevor Sie eine Anbindung aktualisieren.

Daneben gibt es eine Integrationsumgebung. Verwenden Sie sie zum Testen von Authentifizierung und Identifikatorformatierung. Prüfen Sie dort auch gültige Antworten und Fehlerbehandlung.

Basis-URL und Endpunkte

Der Server ist https://www.zefix.admin.ch/ZefixPublicREST, die Operationen liegen unter /api/v1. Version 2.7.2.3 publiziert diese zehn Operationen:

PfadMethodeAntwort
/company/uid/{id}GETFirmendatensatz in einem einelementigen Array
/company/ehraid/{id}GETFirmendatensatz als Objekt
/company/chid/{id}GETFirmendatensatz in einem einelementigen Array
/company/searchPOSTSuchergebnis-Datensätze
/legalFormGETRechtsformen mit ihren Codes
/registryOfCommerceGETDie kantonalen Registerämter
/registryOfCommerce/byBfsCommunityId/{id}GETDas Amt, das eine Gemeinde abdeckt
/communityGETPolitische Gemeinden mit BFS-Nummern
/sogc/{id}GETEine SHAB-Publikation
/sogc/bydate/{date}GETAlle SHAB-Publikationen eines Tages

Firmenabfragen liefern 404, wenn kein Datensatz existiert. Die UID- und CH-ID-Routen liefern ein einelementiges Array, die EHRA-ID-Route ein Objekt. Normalisieren Sie die Antwort, bevor Sie sie weitergeben.

Eine vollständige UID-Abfrage

Das folgende Beispiel akzeptiert eine UID in beiden Formaten, normalisiert sie, wiederholt bei transienten Fehlern und entpackt das einelementige Array:

import re
import time

import httpx

NORMALISED_UID = re.compile(r"CHE(\d{3})(\d{3})(\d{3})", re.IGNORECASE)
PRINTED_UID = re.compile(r"CHE-\d{3}\.\d{3}\.\d{3}", re.IGNORECASE)


def format_uid(value: str) -> str:
    uid = value.strip().upper()
    if PRINTED_UID.fullmatch(uid):
        return uid
    if match := NORMALISED_UID.fullmatch(uid):
        return f"CHE-{match.group(1)}.{match.group(2)}.{match.group(3)}"
    raise ValueError(f"Invalid Swiss UID: {value!r}")


def company_by_uid(client: httpx.Client, uid: str) -> dict | None:
    api_uid = format_uid(uid)
    for attempt in range(3):
        response = client.get(f"/company/uid/{api_uid}")

        if response.status_code == 404:
            return None
        if response.status_code == 429 or response.status_code >= 500:
            if attempt == 2:
                response.raise_for_status()
            time.sleep(2**attempt)
            continue

        response.raise_for_status()
        data = response.json()
        return data[0] if isinstance(data, list) and data else data

    raise RuntimeError("Unreachable")


with httpx.Client(
    base_url="https://www.zefix.admin.ch/ZefixPublicREST/api/v1",
    auth=httpx.BasicAuth(USERNAME, PASSWORD),
    headers={"Accept": "application/json"},
    timeout=30.0,
) as client:
    company = company_by_uid(client, "CHE444420929")

UID-Format für die Abfrage

Die Schweizer Unternehmens-Identifikationsnummer hat eine kanonische Druckform, CHE-444.420.929, und eine normalisierte Form ohne Interpunktion, CHE444420929. SHAB-Publikationen tragen die normalisierte Form. Interne Datensätze speichern oft die normalisierte Form. Die Route /company/uid/{id} erwartet die Druckform.

Akzeptieren Sie beide Formen an der Schnittstelle und wandeln Sie die normalisierte Form um, bevor Sie den Anfragepfad bauen. Die Funktion format_uid oben validiert die Eingabe und stoppt fehlerhafte Identifikatoren vor dem API-Aufruf mit einer Exception.

Antwortfelder einer Firmenabfrage

Identität, Status, Adresse und Kapital sind Felder der obersten Ebene. Beziehungen wie Zweigniederlassungen und Übernahmen sind Arrays von Firmenverweisen. Dies sind die Zefix-Namen der Felder, die wir lesen:

  • name, ehraid, uid, chid: die Identität.
  • legalSeat und legalSeatId, address, canton: wo sie sitzt.
  • status: ACTIVE, CANCELLED, BEING_CANCELLED. Filtern oder kennzeichnen Sie gelöschte Einträge, bevor Sie den Datensatz weiterverarbeiten.
  • capitalNominal und die Währung dazu. Lesen Sie den Wert über Decimal(str(value)) ein. Damit vermeiden Sie die Rundungsfehler von float.
  • deletionDate: gesetzt, wenn der Eintrag aus dem aktiven Register entfernt wurde.
  • cantonalExcerptWeb: die URL zum Auszug des kantonalen Registers, dem beglaubigten Dokument.
  • oldNames: frühere Namen mit einer Reihenfolgenummer, was den Abgleich der Namenshistorie in den eigenen Daten ermöglicht.
  • headOffices, furtherHeadOffices, branchOffices, hasTakenOver, wasTakenOverBy, auditCompanies: je eine Liste von Firmenverweisen mit Name, EHRA-ID und meistens einer UID.

Für Beziehungs-Arrays wählen Sie REST. Speichern Sie die EHRA-ID jedes Verweises, damit er über /company/ehraid/{id} aufgelöst werden kann. Behandeln Sie wasTakenOverBy als Registerbeziehung. Prüfen Sie die zugehörige Publikation, bevor Sie das Ereignis als Übernahme einordnen.

Wann die EHRA-ID wichtig ist

  • Die UID (uid) ist die Nummer, mit der die ganze Schweizer Verwaltung eine Rechtseinheit führt: Steuern, Mehrwertsteuer, Zoll, Sozialversicherungen und Handelsregister greifen darauf zu. Sie ist öffentlich, steht auf Rechnungen und ist der übliche Join-Schlüssel zwischen Datensätzen.
  • Die EHRA-ID (ehraid) ist die Zeilennummer des Registers selbst, eine schlichte Ganzzahl des eidgenössischen Amts für das Handelsregister. Sie identifiziert einen einzelnen Registereintrag.

Die LINDAS-URIs von Unternehmen verwenden die EHRA-ID: https://register.ld.admin.ch/zefix/company/{EHRA-ID}. Die Beziehungs-Arrays von Zefix tragen ebenfalls EHRA-IDs. Speichern Sie das Feld, wenn Sie Hauptsitz-, Zweigniederlassungs- oder Übernahmeverweise verfolgen wollen.

Eine Zweigniederlassung hat eine eigene EHRA-ID, teilt sich aber die UID mit ihrem Hauptsitz. Prüfen Sie, wie Zweigniederlassungen in Ihren Daten erscheinen, bevor Sie eine Zeile pro UID erzwingen.

Die REST-Antwort liefert beide Identifikatoren. Speichern Sie beide, damit Sie die Zuordnung bei der Datenübernahme befüllen können.

Die Suche nach Namen

/company/search ist ein POST mit einem CompanySearchQuery-Körper. Der vollständige Parametersatz:

FeldTypHinweise
nameStringPflicht, mindestens drei Zeichen. Trifft den Anfang des Namens, * ist der Platzhalter.
legalFormIdIntegerDie interne Rechtsform-ID, 1 bis 999.
legalFormUidStringDer öffentliche vierstellige Code aus eCH-0097.
registryOfCommerceIdIntegerEin kantonales Amt.
legalSeatIdIntegerEine Gemeinde, über ihre BFS-Nummer.
cantonStringDas zweibuchstabige Kürzel.
activeOnlyBooleanBeschränkt die Ergebnisse auf aktive Einträge.
response = client.post(
    "/company/search",
    json={"name": "Migros", "canton": "ZH", "activeOnly": True},
)
response.raise_for_status()
candidates = response.json()

Die Ortsfilter schliessen sich gegenseitig aus. Senden Sie eines von registryOfCommerceId, legalSeatId oder canton.

Der Namensabgleich beginnt am Anfang des Firmennamens. Eine Suche nach Migros findet Migros Bank AG. Für Genossenschaft Migros Zürich braucht es einen vorangestellten Platzhalter. Der Endpunkt bietet keine Paginierung mit Offset, Limit oder Cursor. Halten Sie die Anfrage spezifisch und filtern Sie die zurückgegebenen Kandidaten lokal.

Behandeln Sie die Treffer einer Namenssuche als Kandidaten. Vergleichen Sie UID und Rechtssitz. Prüfen Sie auch den Status, bevor Sie einen Datensatz übernehmen.

Rechtsformen, Gemeinden und Ämter auflösen

/legalForm, /registryOfCommerce und /community liefern kompakte Referenzlisten, die sich selten ändern. Über sie werden die numerischen IDs in Firmen- und Suchantworten lesbar. Wir halten jede Liste einen Tag im Cache und lösen die IDs lokal auf. Ein Firmendatensatz gibt Ihnen eine legalSeatId und eine Rechtsform-ID. Die Gemeindeliste macht aus der legalSeatId einen Ortsnamen samt Kanton. Die Rechtsformliste löst die zweite ID beispielsweise als «Aktiengesellschaft» mit ihrem eCH-Code auf.

/registryOfCommerce/byBfsCommunityId/{id} beantwortet, welches kantonale Amt die Einträge einer bestimmten Gemeinde führt. Diese Zuordnung brauchen Sie für den beglaubigten kantonalen Auszug.

Tägliche SHAB-Publikationen einlesen

/sogc/bydate/{date} nimmt ein schlichtes 2026-08-12 und liefert jede Publikation des Schweizerischen Handelsamtsblatts dieses Tages, jeweils zusammen mit dem Kurzdatensatz der betroffenen Firma.

Eine Publikation trägt ihre sogcId, das publizierende kantonale Amt und dessen Kanton, Nummer und Datum des Tagesregisters, den formatierten message-Text und eine Liste von mutationTypes. mutationTypes ermöglicht es einer Pipeline, eine Kapitalerhöhung anders zu leiten als eine Adressänderung, ohne den juristischen Text zu parsen. /sogc/{id} holt eine Publikation über ihre Nummer zurück, wenn Sie die ID gespeichert haben und sie erneut lesen wollen.

Für die Änderungsverfolgung fragen Sie die Route einmal pro Kalendertag ab und speichern das letzte abgeschlossene Datum. Deduplizieren Sie Publikationen über die sogcId. Spielen Sie verpasste Tage nach einem Ausfall nach, und lassen Sie leere Publikationstage den Prüfpunkt vorrücken.

So entsteht ein Protokoll der im SHAB veröffentlichten Registerereignisse. Das ist effizienter, als jeden Firmendatensatz auf Änderungen hin abzufragen.

Für Masse nehmen Sie LINDAS

Verwenden Sie REST, wenn Sie von einer Firma, einem Identifikator oder einem Datum ausgehen oder wenn Sie die Beziehungsfelder von Zefix brauchen. Verwenden Sie LINDAS, wenn Sie einen grossen Teil des Registers durchlaufen wollen. Sein SPARQL-Datensatz überlappt mit der REST-API bei den Identitäts- und Adressfeldern und enthält zusätzlich den Zweckartikel. Der Entitätstyp heisst admin:ZefixOrganisation, und jede Entität hat einen stabilen URI der Form https://register.ld.admin.ch/zefix/company/{EHRA-ID}.

Für die oben aufgeführten Beziehungs-Arrays bleibt die REST-API die Quelle. Eine Massen-Pipeline kann ihre Grundgesamtheit aus LINDAS beziehen und die Firmen mit benötigten Beziehungen über REST ergänzen.

Fragen Sie die Daten unter https://ld.admin.ch/query per SPARQL ab. Die Keyset-Paginierung über den URI ersetzt OFFSET. Rufen Sie stapelweise die Felder für URIs ab, die grösser als der zuletzt verarbeitete sind. Eine leere Seite beendet den Lauf.

API-Grenzen

Firmenabfragen beschreiben den aktuellen Registerzustand. Für eine Feldhistorie müssen Sie Momentaufnahmen speichern. Die API bietet dafür keinen modifiedSince-Filter oder Webhook.

Für veröffentlichte Registerereignisse lesen Sie /sogc/bydate/{date} täglich ein. Das erspart es, das ganze Register abzufragen, um eine kleine Zahl von Änderungen zu finden. Der Leitfaden zur SHAB-API beschreibt die eigene API des Amtsblatts.

Zefix deckt Firmenidentität, Status, Adresse, Kapital und Registerbeziehungen ab. Einstellungsaktivität, Website-Änderungen, Marken und Presseberichterstattung kommen aus anderen Quellen. Wo Schweizer Unternehmensdaten tatsächlich liegen zeigt diese Datensätze.

Cookie-Einstellungen

Notwendige Cookies sind immer aktiv. Die anderen beiden sind eingeschaltet, sofern Sie sie nicht deaktivieren.