API-Dokumentation
Die Firmenwatch-API liefert die Handelsregister- und Konkurspublikationen des Schweizerischen Handelsamtsblatts in normalisierter Form: Firmensuche, Einzelabfrage per UID, Organe, Historie, Ereignisstrom und UID-Prüfung. Die Schnittstelle ist eine REST-API mit JSON-Antworten, sie setzt keine besondere Bibliothek voraus.
Schnellstart
Alle Pfade liegen unter https://firmenwatch.ch/api/v1. Ausser /health trägt jede Anfrage den API-Schlüssel im Authorization-Kopf. Die folgende Abfrage liefert aktive Aktiengesellschaften im Kanton Zürich, nach der letzten Änderung sortiert.
curl -s "https://firmenwatch.ch/api/v1/companies?canton=ZH&legal_form=0106&limit=2" \
-H "Authorization: Bearer fw_live_xxxxxxxxxxxxxxxxxxxxxxxx"{
"data": [
{
"uid": "CHE-000.000.000",
"name": "Muster Handels AG",
"slug": "muster-handels-ag-zuerich",
"legal_form_code": "0106",
"legal_form": "Aktiengesellschaft",
"status": "active",
"seat": "Zürich",
"canton": "ZH",
"address": {
"care_of": null,
"street": "Musterstrasse",
"house_number": "12",
"po_box": null,
"zip": "8001",
"town": "Zürich"
},
"purpose": "Handel mit Waren aller Art, insbesondere mit Büromaterial.",
"capital": { "nominal": 250000, "paid": 250000, "currency": "CHF" },
"industry": { "code": "46.90", "label": "Grosshandel ohne ausgeprägten Schwerpunkt" },
"first_registered_at": "2019-03-14",
"deleted_at": null,
"last_event_at": "2026-08-24",
"url": "https://firmenwatch.ch/firma/muster-handels-ag-zuerich"
}
],
"total": 1,
"limit": 2,
"offset": 0
}Alle Beispieldaten dieser Seite sind erfunden. Die UID CHE-000.000.000 bezeichnet keine eingetragene Rechtseinheit.
Authentifizierung
Die Authentifizierung erfolgt über einen Bearer-Token. Produktivschlüssel beginnen mit fw_live_. Es wird nur der Hash gespeichert; geht ein Schlüssel verloren, erstellen Sie im Konto einen neuen und widerrufen den alten. Der Schlüssel gehört ausschliesslich auf den Server: er trägt die Rechte des Kontos und darf nicht in Browser-Code, Mobil-Apps oder öffentliche Repositorien gelangen. Ein kompromittierter Schlüssel wird im Konto widerrufen und ersetzt.
Authorization: Bearer fw_live_xxxxxxxxxxxxxxxxxxxxxxxxFehlt der Kopf oder ist der Schlüssel unbekannt, antwortet die API mit HTTP 401 und dem Code unauthorized. Anfragen über unverschlüsseltes HTTP werden abgewiesen.
Konventionen
- Datum und Zeit. Datumsangaben folgen ISO 8601 im Format
2026-08-26. Zeitstempel sind UTC. - UID. Entgegengenommen werden
CHE-000.000.000,CHE000000000und000000000. Zurückgegeben wird immer die kanonische Schreibweise mit Bindestrich und Punkten. - Listen. Mehrwertige Filter im Ereignisstrom werden kommagetrennt übergeben, etwa
cantons=ZH,ZG,AG. Die Werte sind oder-verknüpft, verschiedene Parameter und-verknüpft. - Blätterung.
limitundoffsetsteuern die Seiten. Bei der Firmensuche nennttotaldie Gesamtzahl der Treffer. Für laufende Ereignis-Abholungen istsince_iddem Versatz vorzuziehen. - Leere Felder. Nicht erhobene Werte sind
null, nicht der leere String. Bedingte Felder wienext_since_idwerden nur geliefert, wenn sie einen Wert haben. - Zeichensatz. Antworten sind UTF-8. Umlaute und Akzente werden unverändert aus der Publikation übernommen.
Endpunkte
Sieben Endpunkte decken den gesamten Funktionsumfang ab. Alle Pfade sind relativ zu https://firmenwatch.ch/api/v1.
Firmensuche
Volltext- und Facettensuche über alle eingetragenen Rechtseinheiten. Ohne Suchbegriff stehen aktive, zuletzt veränderte Einträge zuoberst.
| Name | Typ | Pflicht | Bedeutung |
|---|---|---|---|
| q | string | — | Suchbegriff. Trifft Firmenname oder UID. |
| canton | string | — | Ein Kantonskürzel, z. B. ZH. |
| legal_form | string | — | Ein Rechtsformcode nach eCH-0097. 0106 ist die AG, 0107 die GmbH. |
| zip | string | — | Eine Postleitzahl des Domizils. |
| status | string | — | active, in_liquidation, bankrupt oder deleted. |
| limit | integer | — | Datensätze pro Seite. 1 bis 100, Vorgabe 25. |
| offset | integer | — | Versatz für die Blätterung. 0 bis 100 000, Vorgabe 0. |
curl -s -G "https://firmenwatch.ch/api/v1/companies" \
-H "Authorization: Bearer fw_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
--data-urlencode "q=Muster Handels" \
--data-urlencode "canton=ZH" \
--data-urlencode "status=active" \
--data-urlencode "limit=25"{
"data": [
{
"uid": "CHE-000.000.000",
"name": "Muster Handels AG",
"slug": "muster-handels-ag-zuerich",
"legal_form_code": "0106",
"legal_form": "Aktiengesellschaft",
"status": "active",
"seat": "Zürich",
"canton": "ZH",
"capital": { "nominal": 250000, "paid": 250000, "currency": "CHF" },
"last_event_at": "2026-08-24",
"url": "https://firmenwatch.ch/firma/muster-handels-ag-zuerich"
}
],
"total": 1,
"limit": 25,
"offset": 0
}Einzelabfrage per UID
Stammdaten einer Rechtseinheit samt bekannten Organen und den 50 neuesten Ereignissen. Der Pfadparameter nimmt jede übliche UID-Schreibweise entgegen.
| Name | Typ | Pflicht | Bedeutung |
|---|---|---|---|
| uid | string | ja | CHE-000.000.000 oder 000000000. |
curl -s "https://firmenwatch.ch/api/v1/companies/CHE-000.000.000" \
-H "Authorization: Bearer fw_live_xxxxxxxxxxxxxxxxxxxxxxxx"{
"data": {
"uid": "CHE-000.000.000",
"name": "Muster Handels AG",
"slug": "muster-handels-ag-zuerich",
"legal_form_code": "0106",
"legal_form": "Aktiengesellschaft",
"status": "active",
"seat": "Zürich",
"canton": "ZH",
"address": {
"care_of": "c/o Muster Treuhand AG",
"street": "Musterstrasse",
"house_number": "12",
"po_box": null,
"zip": "8001",
"town": "Zürich"
},
"purpose": "Handel mit Waren aller Art, insbesondere mit Büromaterial.",
"capital": { "nominal": 250000, "paid": 250000, "currency": "CHF" },
"industry": { "code": "46.90", "label": "Grosshandel ohne ausgeprägten Schwerpunkt" },
"first_registered_at": "2019-03-14",
"deleted_at": null,
"last_event_at": "2026-08-24",
"url": "https://firmenwatch.ch/firma/muster-handels-ag-zuerich",
"officers": [
{
"name": "Muster, Anna",
"kind": "person",
"first_name": "Anna",
"last_name": "Muster",
"place_of_origin": "Bern",
"function": "Mitglied des Verwaltungsrates",
"role": "director",
"signature": "Einzelunterschrift",
"active": true,
"from": "2019-03-14",
"to": null
}
],
"timeline": [
{
"id": 4812993,
"type": "address_change",
"occurred_at": "2026-08-24",
"canton": "ZH",
"summary": "Neues Domizil: Musterstrasse 12, 8001 Zürich.",
"severity": 40,
"payload": {
"field": "address",
"after": "Musterstrasse 12, 8001 Zürich"
}
}
]
}
}Organe
Die eingetragenen Personen mit Funktion und Zeichnungsberechtigung. Standardmässig nur amtierende Organe.
| Name | Typ | Pflicht | Bedeutung |
|---|---|---|---|
| uid | string | ja | Pfadparameter. UID der Rechtseinheit. |
| include_former | boolean | — | Ausgeschiedene Organe mitliefern. Vorgabe false. |
curl -s "https://firmenwatch.ch/api/v1/companies/CHE-000.000.000/officers?include_former=true" \
-H "Authorization: Bearer fw_live_xxxxxxxxxxxxxxxxxxxxxxxx"{
"data": [
{
"name": "Muster, Anna",
"kind": "person",
"first_name": "Anna",
"last_name": "Muster",
"place_of_origin": "Bern",
"function": "Mitglied des Verwaltungsrates",
"role": "director",
"signature": "Einzelunterschrift",
"active": true,
"from": "2019-03-14",
"to": null
},
{
"name": "Beispiel, Peter",
"kind": "person",
"first_name": "Peter",
"last_name": "Beispiel",
"place_of_origin": "Basel",
"function": "Geschäftsführer",
"role": "managing_officer",
"signature": "Kollektivunterschrift zu zweien",
"active": false,
"from": "2019-03-14",
"to": "2024-11-06"
}
],
"uid": "CHE-000.000.000"
}Historie
Die neuesten normalisierten Ereignisse zu einer UID, neueste zuerst.
| Name | Typ | Pflicht | Bedeutung |
|---|---|---|---|
| uid | string | ja | Pfadparameter. UID der Rechtseinheit. |
| limit | integer | — | Datensätze. 1 bis 200, Vorgabe 50. |
curl -s "https://firmenwatch.ch/api/v1/companies/CHE-000.000.000/events?limit=50" \
-H "Authorization: Bearer fw_live_xxxxxxxxxxxxxxxxxxxxxxxx"{
"data": [
{
"id": 4790112,
"type": "officer_removed",
"occurred_at": "2024-11-06",
"canton": "ZH",
"summary": "Beispiel, Peter, Geschäftsführer, ist ausgeschieden.",
"severity": 50,
"payload": {
"persons": [{ "name": "Beispiel, Peter", "role": "managing_officer" }]
}
}
],
"uid": "CHE-000.000.000"
}Ereignisstrom
Der chronologische Strom aller Publikationen. Grundlage für Lead-Feeds und Portfolioüberwachung.
| Name | Typ | Pflicht | Bedeutung |
|---|---|---|---|
| types | string | — | Ereignistypen, kommagetrennt, z. B. new_registration,bankruptcy_opened. |
| cantons | string | — | Kantonskürzel, kommagetrennt. |
| zips | string | — | Postleitzahlen, kommagetrennt. |
| legal_forms | string | — | Rechtsformcodes nach eCH-0097, kommagetrennt. |
| industries | string | — | NOGA-Codes, kommagetrennt. |
| keywords | string | — | Stichwörter in Firmenname oder Zweck, kommagetrennt. |
| exclude_keywords | string | — | Auszuschliessende Stichwörter, kommagetrennt. |
| capital_min | number | — | Mindestkapital. |
| capital_max | number | — | Höchstkapital. |
| from | date | — | Frühestes Publikationsdatum, einschliesslich. |
| to | date | — | Spätestes Publikationsdatum, einschliesslich. |
| since_id | integer | — | Nur Ereignisse mit höherer ID. Empfohlen für die laufende Abholung. |
| min_severity | integer | — | Mindest-Relevanz von 0 bis 100. |
| limit | integer | — | Datensätze. 1 bis 1 000, Vorgabe 100. |
| offset | integer | — | Versatz ohne since_id; im Cursor-Modus ignoriert. |
Mit since_id lässt sich der Strom lückenlos abholen: die höchste bereits verarbeitete ID mitgeben, das Feld next_since_id der Antwort speichern und beim nächsten Abruf verwenden. Eine Blätterung über Datum und Versatz verliert dagegen Ereignisse, sobald an einem Tag mehrere Publikationen nachträglich eintreffen.
curl -s -G "https://firmenwatch.ch/api/v1/events" \
-H "Authorization: Bearer fw_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
--data-urlencode "types=new_registration" \
--data-urlencode "cantons=ZH,ZG" \
--data-urlencode "since_id=4812993" \
--data-urlencode "limit=100"{
"data": [
{
"id": 4813004,
"type": "new_registration",
"occurred_at": "2026-08-25",
"summary": "Neueintragung: Muster Handels AG",
"severity": 60,
"payload": {
"legalForm": "Aktiengesellschaft",
"capital": "250000.00"
},
"company": {
"uid": "CHE-000.000.000",
"name": "Muster Handels AG",
"legal_form": "Aktiengesellschaft",
"canton": "ZH",
"address": {
"care_of": null,
"street": "Musterstrasse",
"house_number": "12",
"zip": "8001",
"town": "Zürich"
},
"purpose": "Handel mit Waren aller Art.",
"capital": 250000,
"industry": "Grosshandel ohne ausgeprägten Schwerpunkt",
"url": "https://firmenwatch.ch/firma/muster-handels-ag-zuerich"
}
}
],
"limit": 100,
"next_since_id": 4813004
}UID prüfen und normalisieren
Prüft Format und Prüfziffer nach der Spezifikation des Bundesamts für Statistik (Modulo 11 mit den Gewichten 5, 4, 3, 2, 7, 6, 5, 4) und schlägt die UID anschliessend im Bestand nach.
| Name | Typ | Pflicht | Bedeutung |
|---|---|---|---|
| uid | string | ja | UID in beliebiger Schreibweise, mit oder ohne Präfix CHE. |
| Name | Typ | Pflicht | Bedeutung |
|---|---|---|---|
| valid | boolean | — | Format und Prüfziffer sind korrekt. |
| normalized | string | null | — | Kanonische Schreibweise, null bei ungültiger UID. |
| found | boolean | — | Die UID ist im Firmenwatch-Bestand vorhanden. |
| company | Company | null | — | Stammdaten, sofern gefunden. |
Eine formal gültige UID muss nicht eingetragen sein: valid undfound sind bewusst getrennt. Für eine Onboarding-Prüfung ist in der Regel beides zu verlangen.
curl -s -X POST "https://firmenwatch.ch/api/v1/uid/validate" \
-H "Authorization: Bearer fw_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"uid":"CHE-000.000.000"}'{
"data": {
"valid": true,
"normalized": "CHE-000.000.000",
"found": false,
"company": null
}
}Betriebszustand
Zeigt, bis zu welchem SHAB-Publikationsdatum der Bestand nachgeführt ist. Geeignet für die eigene Überwachung.
Dieser Endpunkt ist öffentlich und benötigt keinen API-Schlüssel. Bei veralteten Daten oder nicht erreichbarer Datenbank antwortet er mit HTTP 503.
curl -s "https://firmenwatch.ch/api/v1/health"{
"ok": true,
"latest_publication": "2026-08-25",
"data_age_days": 1,
"entities": 0,
"events": 0,
"publications": 0
}Die Zahlen im Beispiel sind Platzhalter. Massgebend ist der Wert, den die Schnittstelle zum Abfragezeitpunkt zurückgibt.
Datenmodell
Company, Officer und zwei schlanke Ereignisvarianten tragen die Schnittstelle. Die vollständigen Typen stehen in der OpenAPI-Beschreibung.
Company
| Name | Typ | Pflicht | Bedeutung |
|---|---|---|---|
| uid | string | ja | Kanonische UID, z. B. CHE-000.000.000. |
| name | string | ja | Firmenwortlaut gemäss Handelsregister. |
| slug | string | ja | Bezeichner des öffentlichen Profils unter /firma/. |
| legal_form_code | string | null | — | Rechtsformcode nach eCH-0097. |
| legal_form | string | null | — | Deutsche Bezeichnung der Rechtsform. |
| status | string | ja | active, in_liquidation, bankrupt oder deleted. |
| seat | string | null | — | Politische Gemeinde des Sitzes. |
| canton | string | null | ja | Kantonskürzel, sofern vorhanden. |
| address | object | — | care_of, street, house_number, po_box, zip, town. |
| purpose | string | null | — | Zweckumschreibung. |
| capital | object | — | nominal, paid, currency. |
| industry | object | null | — | code und label nach NOGA, sofern klassifiziert. |
| first_registered_at | date | null | — | Datum der Ersteintragung. |
| deleted_at | date | null | — | Datum der Löschung, sofern erfolgt. |
| last_event_at | date | null | — | Publikationsdatum des jüngsten Ereignisses. |
| url | string | — | Öffentliches Firmenprofil auf firmenwatch.ch. |
Officer
| Name | Typ | Pflicht | Bedeutung |
|---|---|---|---|
| name | string | ja | Nachname, Vorname wie publiziert. |
| kind | string | ja | person oder legal_entity. |
| first_name | string | null | — | Vorname, sofern trennbar. |
| last_name | string | null | — | Nachname, sofern trennbar. |
| place_of_origin | string | null | — | Amtlich publizierter Heimatort. |
| function | string | null | — | Funktion, z. B. Mitglied des Verwaltungsrates. |
| role | string | null | — | Normalisierte Rolle. |
| signature | string | null | — | Zeichnungsberechtigung im Wortlaut der Publikation. |
| active | boolean | ja | Ob das Organ aktuell eingetragen ist. |
| from | date | null | — | Publikationsdatum des Eintritts. |
| to | date | null | — | Publikationsdatum des Austritts, null bei amtierendem Organ. |
Event
| Name | Typ | Pflicht | Bedeutung |
|---|---|---|---|
| id | integer | ja | Monoton steigend, geeignet für since_id. |
| type | string | ja | Normalisierter Ereignistyp, siehe Liste unten. |
| occurred_at | date | ja | SHAB-Publikationsdatum. |
| canton | string | null | — | Kanton der publizierenden Stelle. |
| summary | string | null | — | Eine Zeile Klartext zum Ereignis. |
| severity | integer | — | Relevanz von 0 bis 100. Konkurs und Löschung liegen oben. |
| payload | JSON | null | — | Strukturierte Details des Ereignistyps. |
FeedEvent
Der globale Ereignisstrom liefert dieselben Kernfelder, ergänzt umcompany mit UID, Firmenname, Rechtsform, Kanton, Adresse, Zweck, Nominalkapital, Branche und Profil-URL. Der Kanton steht dort im Firmenobjekt.
Ereignistypen
new_registration name_change address_change
seat_change purpose_change capital_change
legal_form_change officer_added officer_removed
auditor_change liquidation_opened liquidation_closed
deletion bankruptcy_opened bankruptcy_suspended
bankruptcy_closed moratorium debt_enforcement
branch_opened branch_closed merger
otherFehlerreferenz
Fehler tragen stets denselben Rumpf. Der HTTP-Status nennt die Klasse, das Feld code den genauen Grund. message ist für Menschen bestimmt und kann sich ändern; Programme werten ausschliesslich code aus.
{
"error": {
"code": "invalid_request",
"message": "Der Parameter limit muss zwischen 1 und 100 liegen.",
"details": { "parameter": "limit", "value": "500" }
}
}| Code | HTTP | Anlass |
|---|---|---|
| unauthorized | 401 | Kein Authorization-Kopf, unbekannter oder widerrufener Schlüssel. |
| forbidden | 403 | Der Schlüssel ist gültig, das Abonnement aber nicht aktiv. |
| not_found | 404 | Die angefragte UID ist nicht im sichtbaren Bestand. |
| invalid_request | 400 | Pflichtfeld fehlt, UID ist ungültig oder der JSON-Rumpf ist fehlerhaft. |
| rate_limited | 429 | Zu viele Anfragen im laufenden Minutenfenster. |
| quota_exceeded | 402 | Das Monatskontingent des Tarifs ist ausgeschöpft. |
| internal | 500 | Unerwarteter Fehler auf unserer Seite. Wiederholung nach kurzer Wartezeit ist zulässig. |
Ratenbegrenzung
Jede authentifizierte Antwort trägt den Stand des laufenden Minutenfensters in drei Kopfzeilen. Wird das Fenster überschritten, antwortet die API mit HTTP 429 und dem Code rate_limited.
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 297
X-RateLimit-Reset: 1787654400| Name | Typ | Pflicht | Bedeutung |
|---|---|---|---|
| X-RateLimit-Limit | integer | — | Zulässige Anfragen im laufenden Fenster. |
| X-RateLimit-Remaining | integer | — | Im laufenden Fenster verbleibende Anfragen. |
| X-RateLimit-Reset | integer | — | Unix-Zeit in Sekunden, zu der das Fenster zurücksetzt. |
Empfohlen ist ein Wiederholungsversuch mit exponentiell wachsender Wartezeit, beginnend bei einer Sekunde. Wer den Ereignisstrom abholt, fährt mit einem Abruf alle fünf Minuten und since_id besser als mit häufigem Blättern.
Kontingente je Tarif
Das Monatskontingent zählt beantwortete Anfragen. Ist es ausgeschöpft, antwortet die API mit HTTP 402 und dem Code quota_exceeded, bis der nächste Abrechnungsmonat beginnt oder der Tarif gewechselt wird.
- Preis
- CHF 0/Monat
- Kontingent
- 200 Abfragen im Monat
- Rate
- 20 pro Minute
- Überschreitung
- gesperrt statt verrechnet
- Preis
- CHF 29/Monat
- Kontingent
- 1'000 Abfragen im Monat
- Rate
- 40 pro Minute
- Überschreitung
- gesperrt statt verrechnet
- Preis
- CHF 79/Monat
- Kontingent
- 5'000 Abfragen im Monat
- Rate
- 60 pro Minute
- Überschreitung
- gesperrt statt verrechnet
- Preis
- CHF 199/Monat
- Kontingent
- 25'000 Abfragen im Monat
- Rate
- 180 pro Minute
- Überschreitung
- gesperrt statt verrechnet
- Preis
- CHF 449/Monat
- Kontingent
- 150'000 Abfragen im Monat
- Rate
- 600 pro Minute
- Überschreitung
- gesperrt statt verrechnet
Verbindlich sind die Werte im Konto unter /app/api; dort steht auch der laufende Verbrauch. Jede Antwort trägt ausserdem die Kopfzeilen X-RateLimit-Limit, X-RateLimit-Remaining und X-RateLimit-Reset — damit lässt sich die Begrenzung im eigenen System auslesen, statt sie fest zu verdrahten.
Versionierung
Die Version steht im Pfad. Innerhalb von v1 kommen ausschliesslich Felder und Endpunkte hinzu; bestehende Felder werden weder umbenannt noch entfernt. Clients müssen unbekannte Felder tolerieren. Ein Bruch dieser Zusage erfolgt nur über einen neuen Pfad.
Die maschinenlesbare Beschreibung liegt unter /api/v1/openapi.json und ist die massgebende Quelle für SDK-Generatoren und Testwerkzeuge.
curl -s https://firmenwatch.ch/api/v1/openapi.json -o firmenwatch-openapi.json