monitoring
Endpoints

Monitoring & Webhooks

10–50 Credits pro 30-Tage-Zyklus, je nach Rhythmus

Ein Signal ist eine Änderung im Handelsregister, aufbereitet in einem einheitlichen Format. Mit der Signals-API durchsuchst Du solche Änderungen über alle Unternehmen hinweg. Monitoring geht den umgekehrten Weg: Du wählst ein Unternehmen aus, wir prüfen es regelmäßig und schicken Dir jede neue Änderung als signierten Webhook. Im Webhook steckt unter data.signal das vollständige Signal in genau demselben Schema wie in der Signals-API – dieselben Blöcke event, organization, parties, register_entry, source und details. Du verarbeitest die Payload also direkt weiter, ohne einen zweiten API-Aufruf.

Voraussetzungen: Monitoring steht jedem Account offen, mit dem aktuellen Themenkatalog auch ohne Bezahlplan. Einen eigenen Zugang zur Signals-API brauchst Du dafür nicht – Monitoring läuft unabhängig davon und wird getrennt abgerechnet. Ein Monitor braucht einen aktiven, verifizierten Webhook-Endpunkt und genügend Credits für den gewählten Rhythmus (10–50 Credits je 30 Tage). Abgebucht wird erst, wenn die kostenlose Baseline durchgelaufen ist und der Monitor aktiv wird.

Welche Themen Dein Tarif abdeckt

Jeder Monitor prüft dieselben sieben Themen und filtert Doppelungen heraus. Erst unmittelbar vor dem Versand entscheidet Dein Tarif, was tatsächlich zugestellt wird. Einen Themenfilter pro Monitor gibt es nicht.

Themen-Code Thema Verfügbar ab
NEW_REGISTRATIONS New registrations Jeder Account, auch ohne Bezahlplan
MASTER_DATA_CHANGES Master data changes Jeder Account, auch ohne Bezahlplan
CLOSURES Closures & dissolutions Jeder Account, auch ohne Bezahlplan
ROLE_HOLDER_CHANGES Management changes Jeder Account, auch ohne Bezahlplan
CAPITAL_CHANGES Capital changes Jeder Account, auch ohne Bezahlplan
INSOLVENCIES Insolvencies Pro und Max
TRANSFORMATIONS Transformations & M&A Nur Max

Wechselst Du in einen kleineren Tarif, läuft der Monitor weiter. Themen, die Dein Tarif noch abdeckt, werden normal zugestellt; die übrigen fallen weg und werden auch später nicht nachgeliefert. Bereits verschickte Nachrichten bleiben unverändert und lassen sich weiterhin erneut senden. Nach einem Upgrade gilt der neue Zugriff für alles, was ab diesem Zeitpunkt neu gefunden wird – was vorher passiert ist, holen wir nicht nach.

So richtest Du Monitoring ein

  1. Ruf die Preisvorschau für Dein Wunsch-Intervall ab und prüfe, dass entitled true ist – so weißt Du vorher, was ein Zyklus kostet.
  2. Leg einen Webhook-Endpunkt an; dafür brauchst Du ein Admin-Token mit der Ability account:keys. Die Antwort enthält das Signatur-Secret (whsec_…) genau einmal, also speichere es sofort.
  3. Bau in Deinem Empfänger die Signaturprüfung und das Challenge-Echo ein. Erst danach rufst Du die Verify-Aktion des Endpunkts auf.
  4. Leg den Monitor an: entity_id, ein Intervall zwischen 1 und 30 Tagen und die ID des verifizierten Endpunkts.
  5. Du bekommst sofort HTTP 202 zurück, während im Hintergrund die kostenlose Baseline läuft. Frag den Monitor ab und warte auf den Status active – vorher wird nichts zugestellt.

Authentifizierung und Abilities

Zugangsdaten gehören bei allen folgenden Pfaden ausschließlich in den Header; die Antworten sind private, no-store. Abilities werden wörtlich geprüft: Ein altes Token mit Wildcard zählt nicht als Admin-Zugang.

Operation Erforderlicher Zugang
Preise, Monitore, Endpunkte, Zustellungen und Events lesenx-api-key oder Bearer-Token mit account:read.
Monitore anlegen, ändern, pausieren, fortsetzen und archivieren; Endpunkte verifizieren und testen; Zustellungen erneut sendenx-api-key oder Bearer-Token mit account:read und zusätzlich der Ability monitoring:manage.
Endpunkte anlegen, Secret rotieren, aktivieren, deaktivieren und archivierenBearer-Admin-Token mit account:read und der Ability account:keys. Ein normaler API-Key reicht für diese Operationen nicht.

Auf jedem /v1/account-Pfad wird der Query-Parameter ?api_key= abgewiesen. Sonst stünden Deine Zugangsdaten in URLs und in jedem Access-Log.

Idempotency-Key bei jeder schreibenden Anfrage

Schick bei jedem POST, PATCH und DELETE einen eigenen Idempotency-Key mit. Er sorgt dafür, dass eine Anfrage, die Du nach einem Timeout oder Netzwerkfehler wiederholst, kein zweites Mal wirkt: keine doppelte Credit-Buchung, kein zweites Secret, kein doppelter Statuswechsel.

Idempotency-Key: monitor-create-01J7MZ1VN8N6FZQ2
  • Ein Schlüssel besteht aus 1 bis 128 ASCII-Zeichen – Buchstaben, Ziffern, Punkt, Unterstrich, Doppelpunkt und Bindestrich. Das erste Zeichen muss ein Buchstabe oder eine Ziffer sein.
  • Wiederholst Du innerhalb von 24 Stunden dieselbe Anfrage mit demselben Schlüssel und denselben Parametern, bekommst Du exakt die gespeicherte Antwort zurück: gleicher Body, gleicher HTTP-Status. Am Header Idempotency-Status siehst Du, ob die Operation gerade ausgeführt wurde (created) oder ob Du eine Wiederholung bekommst (replayed).
  • Verwendest Du denselben Schlüssel mit anderen Parametern, antwortet die API mit 409 idempotency_conflict.
  • Alle Monitor-Operationen, das Anlegen, Rotieren, Aktivieren, Deaktivieren und Archivieren von Endpunkten sowie das erneute Senden einer Zustellung kannst Du gefahrlos mit demselben Schlüssel wiederholen. Nimm dafür nie einen neuen – genau der alte Schlüssel verhindert die doppelte Wirkung.
  • Verify und Test sprechen mit Deinem Server. Antwortet einer der beiden mit 409 idempotency_in_progress (Header Idempotency-Status: processing), lässt sich nicht mehr feststellen, ob Dein Empfänger die Anfrage schon gesehen hat. Stoppe dann automatische Wiederholungen und melde Dich beim Support: weder später erneut versuchen noch einen neuen Schlüssel nehmen. Ein 503 bedeutet dagegen, dass gar nichts ausgeführt wurde – der Schlüssel bleibt unbenutzt.
  • Ist ein Schlüssel älter als das Replay-Fenster, antwortet die API mit 409 idempotency_key_expired, statt eine Operation mit Secret oder Credits noch einmal auszuführen. Sprich vor einer Wiederholung mit dem Support.

Alle Endpunkte im Überblick

Alle 18 Monitoring-Routen liegen unter /api/v1/account. GET-Aufrufe kosten nichts. Jede schreibende Anfrage braucht einen Idempotency-Key.

Method Path Popis
GET /v1/account/monitoring/pricing Zeigt den aktuellen Preis für ein poll_interval_days (Standard 30) und ob Dein Account Monitoring nutzen kann.
GET /v1/account/monitors Listet bis zu 100 nicht archivierte Monitore, die neuesten zuerst.
POST /v1/account/monitors Startet die kostenlose Baseline im Hintergrund und gibt den Monitor mit HTTP 202 zurück.
GET /v1/account/monitors/{publicId} Gibt einen Monitor mit seinem laufenden Abrechnungszyklus und den 20 letzten Prüfläufen zurück. Bei einem erfolgreichen Lauf zählt events_new die neuen, für Deinen Tarif freigegebenen Benachrichtigungen – mehrere Endpunkte erhöhen den Wert nicht. Ein fortgesetzter Lauf kann Zwischenstände zeigen, ein nicht finanzierter fehlgeschlagener Lauf Kandidaten, die nie zugestellt wurden.
PATCH /v1/account/monitors/{publicId} Ändert poll_interval_days zum aktuellen Preis – nur für die Zukunft, ohne Erstattung und ohne verpasste Prüfungen nachzuholen.
POST /v1/account/monitors/{publicId}/pause Pausiert die künftigen Prüfungen eines aktiven Monitors. Die Historie bleibt erhalten, ein bereits bezahlter Zyklus wird nicht erstattet. In jedem anderen Status – auch bei initializing – antwortet der Aufruf mit HTTP 200 und ändert nichts; vor der Aktivierung musst Du archivieren.
POST /v1/account/monitors/{publicId}/resume Prüft Tarif, Ziel, Policy und Guthaben erneut und nimmt den Monitor wieder auf. Eine unfertige Baseline wird dabei neu gestartet.
DELETE /v1/account/monitors/{publicId} Archiviert den Monitor und seine Endpunkt-Zuordnungen dauerhaft. Das ist auch der Weg, einen Monitor noch vor der Aktivierung zu stoppen, bevor der Rhythmuspreis gebucht wird.
GET /v1/account/webhook-endpoints Listet alle nicht archivierten Webhook-Endpunkte. URLs und die Werte Deiner eigenen Header sind maskiert.
POST /v1/account/webhook-endpoints Legt einen Endpunkt an und gibt sein Signatur-Secret genau einmal zurück.
POST /v1/account/webhook-endpoints/{publicId}/verify Schickt eine signierte Challenge und aktiviert den Endpunkt, sobald sie korrekt beantwortet wurde – das passiert nur im Status pending_verification. Ist der Endpunkt schon verifiziert oder deaktiviert, bekommst Du seinen bestehenden Zustand zurück, ohne dass eine Anfrage rausgeht. Aktiviert wird er dadurch nicht; dafür rufst Du enable auf.
POST /v1/account/webhook-endpoints/{publicId}/rotate-secret Stellt ein neues Signatur-Secret aus. Sieben Tage lang tragen normale Zustellungen, Tests und Beispiele zusätzlich eine Signatur mit dem alten Secret; Verifizierungs-Challenges nur mit dem neuen.
POST /v1/account/webhook-endpoints/{publicId}/test Schickt sofort ein signiertes endpoint.test-Event und gibt das echte Zustellergebnis zurück.
POST /v1/account/webhook-endpoints/{publicId}/{state} Setzt den Endpunkt auf enable oder disable. Aktivieren geht nur, wenn er schon einmal verifiziert war.
DELETE /v1/account/webhook-endpoints/{publicId} Archiviert den Endpunkt. Monitore, die dadurch kein verifiziertes Ziel mehr haben, werden pausiert.
GET /v1/account/webhook-deliveries Listet die 50 neuesten Zustellungen, auf Wunsch gefiltert nach der Public-ID eines Deiner Endpunkte.
POST /v1/account/webhook-deliveries/{publicId}/retry Sendet eine Zustellung im Status exhausted oder blocked_endpoint noch einmal – mit exakt derselben gespeicherten Nachricht.
GET /v1/account/webhook-events Listet die 50 neuesten Events mit ihren Metadaten und zeigt, ob die gespeicherten Daten noch verfügbar sind.

Diese Listen sind bewusst begrenzt und nicht paginiert: 100 Monitore, 50 Zustellungen, 50 Events. Für alle Account-Routen zusammen gilt ein Limit von 30 Anfragen pro Minute; schreibende Anfragen sind zusätzlich auf 10 pro Minute begrenzt, Verify, Rotate und Test auf 6 pro Minute.

1. Empfänger anlegen und verifizieren

Beim Anlegen bekommt der Endpunkt den Status pending_verification, und Du bekommst das Signatur-Secret im Klartext. Speichere es sofort – ein zweites Mal siehst Du es nicht. Fragst Du den Endpunkt später ab, zeigen wir nur den Host; ein vorhandener Pfad wird mit … abgekürzt, und von Deinen eigenen Headern siehst Du nur die Namen.

curl -X POST 'https://handelsregister.ai/api/v1/account/webhook-endpoints' \
  -H 'Authorization: Bearer YOUR_ADMIN_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: endpoint-create-01J7MZ1VN8N6FZQ2' \
  --data '{
    "name": "Production receiver",
    "url": "https://hooks.example.com/handelsregister",
    "headers": {"x-tenant": "customer-42"}
  }'
{
  "endpoint": {
    "id": "wep_01j7n0...",
    "name": "Production receiver",
    "url": "hooks.example.com/…",
    "status": "pending_verification",
    "verified_at": null,
    "header_names": ["x-tenant"],
    "consecutive_failures": 0,
    "created_at": "2026-08-02T12:00:00+00:00"
  },
  "signing_secret": "whsec_STORE_THIS_VALUE_NOW",
  "meta": {"request_credit_cost": 0, "credits_remaining": 1250}
}

Ziele in Produktion müssen öffentlich erreichbare HTTPS-URLs auf Port 443 sein. IP-Adressen statt Hostnamen, Zugangsdaten in der URL, private oder reservierte Ziele und Weiterleitungen lehnen wir ab. Pro Account kannst Du 10 Endpunkte einrichten, pro Endpunkt 10 eigene Header. Diese Header werden nur gesendet und nie zurückgegeben; Transport-Header und alles, was mit webhook- beginnt, kannst Du nicht überschreiben.

Verifizierungs-Handshake

Eine Challenge geht nur an einen Endpunkt im Status pending_verification: Er bekommt einen signierten endpoint.verification-Body. Prüfe die Standard-Webhooks-Signatur, antworte mit einem beliebigen 2xx-Status und gib data.challenge unverändert im Response-Header webhook-verification zurück. Nur wenn alles davon stimmt, wird verified=true gesetzt. Bei einem bereits verifizierten oder deaktivierten Endpunkt liefert verify nur den bestehenden Zustand – ohne Anfrage an Deinen Server und ohne Statuswechsel. Aktiviert wird er dabei nicht; dafür rufst Du enable separat auf. Verify ist auf sechs Aufrufe pro Minute begrenzt.

POST /handelsregister HTTP/1.1
content-type: application/json
webhook-id: msg_01j7n1...
webhook-timestamp: 1785667200
webhook-signature: v1,BASE64_HMAC

{
  "id": "msg_01j7n1...",
  "type": "endpoint.verification",
  "timestamp": "2026-08-02T12:00:00.000Z",
  "schema_version": 1,
  "data": {"challenge": "40f2..."}
}
HTTP/1.1 204 No Content
webhook-verification: 40f2...
curl -X POST \
  'https://handelsregister.ai/api/v1/account/webhook-endpoints/wep_01j7n0.../verify' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Idempotency-Key: endpoint-verify-01J7MZ1VN8N6FZQ2'

2. Monitor anlegen

Du brauchst eine kanonische entity_id, mindestens einen aktiven Endpunkt und ein ganzzahliges Intervall zwischen 1 und 30 Tagen. Abgerechnet wird zum Preis, der beim Start des Zyklus gilt. Pro Unternehmen läuft ein Monitor, pro Account höchstens 50 gleichzeitig. Dazu kommt ein Limit von 50 Neuanlagen je 24 Stunden – inzwischen wieder archivierte Monitore zählen dabei mit.

# Fetch the current price and policy version first
curl 'https://handelsregister.ai/api/v1/account/monitoring/pricing?poll_interval_days=7' \
  -H 'x-api-key: YOUR_API_KEY'

# Queue a free baseline; this request itself charges zero credits
curl -X POST 'https://handelsregister.ai/api/v1/account/monitors' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: monitor-create-01J7MZ1VN8N6FZQ2' \
  --data '{
    "entity_id": "cc78cf0b230aeae35c6df7ba31989bb9",
    "label": "BMW AG",
    "poll_interval_days": 7,
    "endpoint_ids": ["wep_01j7n0..."]
  }'
HTTP/1.1 202 Accepted
Idempotency-Status: created

{
  "monitor": {
    "id": "mon_01j7n2...",
    "type": "organization.signals",
    "entity_id": "cc78cf0b230aeae35c6df7ba31989bb9",
    "label": "BMW AG",
    "poll_interval_days": 7,
    "status": "initializing",
    "status_reason": null,
    "pricing_policy_version": "2026-08.v2",
    "baseline_completed_at": null,
    "activated_at": null,
    "last_succeeded_at": null,
    "next_poll_at": null,
    "created_at": "2026-08-02T12:01:00+00:00"
  },
  "meta": {
    "baseline_queued": true,
    "billing": {
      "charged_credits": 0,
      "new_cycle": false,
      "floor_transaction_id": null
    },
    "request_credit_cost": 0,
    "credits_remaining": 1250
  }
}

POST /monitors löst noch keine Prüfung aus und bucht keine Credits ab: Der Aufruf legt den Monitor an, stellt die Baseline in die Warteschlange und antwortet mit HTTP 202, baseline_queued=true und charged_credits=0. Die Baseline erfasst alle sieben Themen und merkt sich, was davon bereits bekannt ist – auch für Themen, die Dein Tarif nicht zustellen darf. Was vor dem Start passiert ist, wird nie zugestellt. Aktiv wird der Monitor erst, wenn die Baseline vollständig durchgelaufen ist. Solange er initializing ist, stoppst Du ihn nur per DELETE; Pause bleibt bis zum Status active wirkungslos.

Abrechnung

  • Zuerst läuft die kostenlose Baseline. Danach prüfen wir Tarif, Ziel, Policy und Guthaben in einem Zug noch einmal, buchen den Preis für Deinen Rhythmus ab, starten einen rollierenden 30-Tage-Zyklus und setzen den Monitor auf active.
  • Der Zyklus hat einen Festpreis je Rhythmus: täglich 50, alle 3 Tage 40, wöchentlich 20, monatlich 10 Credits. Ein Intervall ohne eigenen Preis wird zum nächsthäufigeren Rhythmus abgerechnet — alle 4 Tage kostet also so viel wie alle 3 Tage, weil häufiger geprüft wird als wöchentlich. Der Preis deckt die für den Rhythmus erwarteten Prüfungen ab (ceil(30 / Intervall)); jede darüber hinausgehende Prüfung, etwa ein Nachhol-Lauf nach einer Störung, kostet 2 Credits. Tarif, Themenmix und ein Ergebnis ohne berechtigte/neue Signale ändern daran nichts. Fehlgeschlagene oder überholte Prüfungen verursachen keine zusätzliche Laufbuchung.
  • Die Preisvorschau rechnet mit ceil(30 / poll_interval_days) Prüfungen. Wann eine Prüfung genau läuft, verteilen wir innerhalb eines Zeitfensters – verlass Dich also nicht auf eine bestimmte Uhrzeit.
  • Zur Verlängerung startet ein aktiver Monitor einen neuen 30-Tage-Zyklus und bucht dessen Rhythmuspreis genau einmal. Verpasste Zeitfenster rechnen wir weder einzeln ab noch datieren wir sie zurück. Nach einer Störung kann eine zusammengefasste Nachhol-Prüfung laufen (outage_catchup); sie zählt wie eine normale Prüfung des Zyklus und kostet nur dann die im Zyklus festgehaltenen 2 Credits, wenn das Kontingent schon aufgebraucht ist.
  • Pause wirkt nur auf einen aktiven Monitor, der dann auf paused_user steht. In jedem anderen Status antwortet die API mit HTTP 200, ohne etwas zu tun – die Baseline läuft weiter, und der Monitor wird später ganz normal aktiviert und abgerechnet. Willst Du das verhindern, archiviere ihn per DELETE. Weder Pausieren noch Archivieren erstattet einen bereits bezahlten Zyklus.
  • Setzt Du einen Monitor innerhalb eines laufenden, bereits bezahlten Zyklus fort, kostet das nichts extra. Ist der Zyklus abgelaufen, beginnt ein neuer und wird berechnet.
  • Ob Du der aktuellen Pricing-Policy zugestimmt hast, prüfen wir bei der Aktivierung, beim Fortsetzen, beim Ändern des Intervalls und immer dann, wenn zur Verlängerung ein neuer Zyklus beginnt. Innerhalb eines bezahlten Zyklus bleiben Preis und Konditionen eingefroren – eine spätere Änderung der Policy pausiert Deinen Monitor also nicht mitten im Zyklus.
  • Vor jeder Veröffentlichung prüfen wir Deinen aktuellen Tarif erneut. Nach einem Downgrade werden neu gefundene Signale, die Dein Tarif nicht abdeckt, verworfen: keine Zustellung, kein Eintrag in events_new. Themen, die Dein Tarif weiter abdeckt, laufen normal, und bereits verschickte Nachrichten bleiben unverändert. Fehlt das verifizierte Ziel oder das Guthaben für eine fällige Zusatzprüfung, pausiert der Monitor, bevor etwas rausgeht. Eine fällige Zusatzbuchung ist immer abgeschlossen, bevor die Webhooks dieses Laufs verschickt werden.

Monitor-Lebenszyklus

Lies status_reason immer zusammen mit status. Pause wirkt nur auf aktive Monitore – in jedem anderen Status antwortet der Aufruf mit HTTP 200 und ändert nichts. Resume prüft alle Bedingungen für die Aktivierung noch einmal. DELETE archiviert dauerhaft und ist der einzige Weg, einen Monitor im Status initializing noch vor der Aktivierung zu stoppen.

StatusPopis
initializingDie Baseline läuft noch, Änderungen sind noch nicht zustellbar. Pause bewirkt in diesem Status nichts; per DELETE verhinderst Du die spätere Aktivierung.
activeDer Zyklus ist bezahlt, der Monitor wird planmäßig geprüft.
paused_userDu hast den Monitor selbst pausiert.
paused_configurationEs gibt kein aktives, verifiziertes Ziel mehr.
paused_entitlementDem Account ist kein einziges Monitoring-Thema zugänglich. Ein normales Downgrade führt nicht hierher – dabei bleibt der Monitor aktiv.
paused_billingEs fehlt Guthaben oder die Zustimmung zur aktuellen Pricing-Policy.
errorDie Quelle oder die Baseline ist mehrfach hintereinander fehlgeschlagen. Resume prüft alles noch einmal.
archivedDauerhaft archiviert und nicht mehr eingeplant.

Webhook-Envelope

Live-Änderungen haben immer type organization.signal.detected und schema_version 1. In data.signal steckt das vollständige, normalisierte Signal – Du kommst also ohne weiteren API-Aufruf aus. Felder ohne Wert fehlen einfach, und wenn die Nachricht sonst über 20 KiB käme, lassen wir die optionalen details und register_entry weg und setzen data.truncated=true. data.links.signal ist nur ein Komfort-Link auf die Signals-Detail-API: Die Zustellung ruft ihn weder auf noch rechnet sie ihn ab. Folgst Du ihm selbst, kostet das im Erfolgsfall 20 Credits; er kann auch 401, 402, 403 PLAN_REQUIRED, 404 oder einen Fehler der Gegenseite liefern.

{
  "id": "msg_01j7n3...",
  "event_id": "evt_01j7n3...",
  "type": "organization.signal.detected",
  "timestamp": "2026-08-02T12:05:00.000Z",
  "schema_version": 1,
  "data": {
    "monitor": {
      "id": "mon_01j7n2...",
      "type": "organization.signals"
    },
    "signal": {
      "event": {
        "id": "SOURCE_EVENT_ID",
        "topic": "CAPITAL_CHANGES",
        "topic_name": {
          "de": "Kapitaländerungen",
          "en": "Capital changes"
        },
        "occurred_on": "2026-08-02",
        "announced_on": "2026-08-02",
        "date_basis": "REGISTER_ENTRY"
      },
      "organization": {
        "type": "ORGANIZATION",
        "entity_id": "cc78cf0b230aeae35c6df7ba31989bb9",
        "current_profile": {
          "name": "Example GmbH",
          "status": {"code": "ACTIVE"}
        }
      },
      "source": {"kind": "COMMERCIAL_REGISTER"}
    },
    "links": {
      "signal": "https://handelsregister.ai/api/v1/signals/SOURCE_EVENT_ID"
    }
  }
}

Standard-Webhooks-Header prüfen

Die Signatur gilt für die rohen Bytes des Requests. Parse den JSON-Body also nicht, bevor Du geprüft hast: Einmal geparst und neu serialisiert stimmt die Signatur nicht mehr. Bei den Headernamen spielt Groß- und Kleinschreibung keine Rolle.

signed_content = webhook-id + "." + webhook-timestamp + "." + exact_raw_body
expected = base64(HMAC-SHA256(base64_decode(secret after "whsec_"), signed_content))
webhook-signature = "v1," + expected
  • Nimm das Präfix whsec_ weg, dekodiere den Rest streng als Base64 und bilde HMAC-SHA256 über webhook-id.webhook-timestamp.raw_body. Vergleiche das Base64-Ergebnis in konstanter Zeit mit jedem v1-Wert in webhook-signature.
  • Verwirf Nachrichten, deren Zeitstempel außerhalb Deiner Toleranz liegt, und dedupliziere danach über webhook-id. Bei einem Retry bleiben Nachrichten-ID und Body gleich; Zeitstempel und Signatur ändern sich mit jedem Versuch.
  • In den sieben Tagen nach einer Rotation tragen normale Zustellungen, endpoint.test-Anfragen und signierte Beispiele zwei Signaturen: eine mit dem neuen und eine mit dem alten Secret. Akzeptiere in dieser Zeit beide. Eine endpoint.verification-Challenge ist immer nur mit dem aktuellen Secret signiert.
  • Antworte schnell mit 2xx und erledige die eigentliche Verarbeitung danach in Deiner eigenen dauerhaften Queue. Zugestellt wird at-least-once: Dieselbe Nachricht kann mehrfach ankommen, und das darf bei Dir nichts doppelt auslösen.

Beispiel-Events aus der Oberfläche

Im Monitoring-Bereich kannst Du Dir bis zu 10 echte Signale als Beispiel schicken lassen, passend zu Deinem Tarif und aus einem begrenzten Ausschnitt der letzten 48 Monate. Die Liste kann Lücken haben und ist keine vollständige Historie. Das Senden ist kostenlos und prüft Deinen aktuellen Tarif erneut. Beispiele haben denselben Aufbau wie echte Events – data.monitor, data.signal und data.links –, tragen aber type organization.signal.sample und data.sample=true. Bei einem echten Ereignis fehlt data.sample immer.

Zustellung, Retries und automatische Abschaltung

Zu jeder Zustellung siehst Du ihren Status, die Anzahl der Versuche im aktuellen Durchlauf, das letzte HTTP- oder Fehlerergebnis, den nächsten geplanten Versuch und die abschließenden Zeitstempel. Ein erfolgreicher Prüflauf wird abgerechnet, bevor seine zurückgehaltenen Benachrichtigungen auf pending gehen.

StatusPopis
withheldAus einer kostenpflichtigen Prüfung entstanden, aber erst zustellbar, wenn genau dieser Lauf abgerechnet ist.
pendingBereit für den ersten oder einen manuell ausgelösten Versuch.
in_flightWird gerade zugestellt.
retry_waitEin Versuch ist fehlgeschlagen; der nächste ist bereits eingeplant.
succeededDein Empfänger hat mit 2xx geantwortet.
blocked_endpointDer Endpunkt ist nicht erreichbar oder verstößt gegen die Regeln für ausgehende Anfragen.
exhaustedAlle automatischen Versuche sind aufgebraucht, oder Dein Empfänger hat 410 geantwortet.
cancelledDer auslösende Lauf wurde verworfen oder nicht bezahlt, oder der gespeicherte Body ist nicht mehr vorhanden.
  • Jede 2xx-Antwort zählt als Erfolg. Weiterleitungen folgen wir nie; sie gelten als Fehler, den wir wiederholen. Ein HTTP 410 beendet die Zustellung sofort und deaktiviert den Endpunkt.
  • Automatische Retries laufen mit zufälligem Abstand über bis zu 10 Versuche und rund drei Tage. Ein gültiges Retry-After berücksichtigen wir bei 429, 502, 503 und 504 bis maximal einen Tag. Exakte Zeitpunkte sind keine Zusage.
  • Fünf aufgebrauchte Zustellungen in Folge, die auf Deinen Empfänger zurückgehen, deaktivieren den Endpunkt. Eine erfolgreiche Zustellung setzt den Zähler zurück; Fehler auf unserer Seite zählen nicht mit.
  • Für einen manuellen Retry brauchst Du einen aktiven, verifizierten Endpunkt und den gespeicherten Body. webhook-id und Body bleiben identisch. Der öffentliche Zähler attempts beginnt für den neuen Durchlauf wieder bei 0; im Protokoll der einzelnen Versuche läuft attempt_number durchgehend weiter.
  • Die Test-Aktion erzeugt ein endpoint.test-Event und stellt es sofort zu. Ihre Antwort enthält deshalb das echte Zustellergebnis und nicht nur eine Bestätigung, dass etwas eingereiht wurde.

Datenschutz, Secrets und Aufbewahrung

Alle Account-Antworten sind private und no-store. Bevor eine gespeicherte Antwort wiederholt wird, prüfen wir, zu wem die Daten gehören: Eine Public-ID aus einem fremden Account liefert denselben 404 wie eine ID, die es gar nicht gibt.

  • Endpunkt-URLs, die Werte Deiner eigenen Header, Signatur-Secrets, Event-Daten und gespeicherte Nachrichten-Bodies liegen verschlüsselt. In Antworten sind URL-Pfade maskiert, und die Werte Deiner Header geben wir nie zurück.
  • Ein Signatur-Secret siehst Du im Klartext nur beim Anlegen und beim Rotieren eines Endpunkts. Genau diese Antwort lässt sich 24 Stunden lang über den Idempotency-Key wiederholen; danach ist der Body gelöscht.
  • Event-Daten und die exakten Nachrichten-Bodies bewahren wir 30 Tage auf. Danach bleiben in GET /webhook-events nur die Metadaten, und data_available steht auf false.
  • Die Metadaten der Zustellversuche bleiben 90 Tage erhalten. Ein abgelaufener Idempotency-Key bleibt ohne seine Antwort ebenfalls 90 Tage nachvollziehbar.
  • Für ausgehende Anfragen gilt: 5 Sekunden für den Verbindungsaufbau, 15 Sekunden insgesamt, keine Proxys, keine Weiterleitungen, und wir lesen höchstens 64 KiB der Antwort.

Fehler und was sie kosten

  • 400/422: ungültige Eingabe, eine URL- oder Header-Konfiguration, die wir nicht zulassen, eine fehlgeschlagene Verifizierung oder ein Statuswechsel, den es so nicht gibt.
  • 403: Deinem Account ist kein einziges Monitoring-Thema zugänglich, oder dem Token fehlt eine nötige Ability. 404: Die ID ist unbekannt oder gehört einem anderen Account.
  • 409: Für dieses Unternehmen gibt es schon einen Monitor, die Pricing-Policy ist veraltet, der Idempotency-Key kollidiert oder ist abgelaufen, oder eine Operation läuft noch. Nach pricing_policy_stale holst Du Dir einfach die aktuellen Preise.
  • 428: Bei einer schreibenden Anfrage fehlt der Idempotency-Key. 429: Du hast ein Limit überschritten.
  • 503 temporarily_unavailable: Monitoring führt gerade keine Operationen aus. Beim Anlegen und Fortsetzen eines Monitors, beim Verifizieren und Testen eines Endpunkts und beim erneuten Senden greift das, bevor irgendetwas passiert: Es lief nichts, Dein Idempotency-Key bleibt unbenutzt, und Du kannst ihn später wieder verwenden.
  • Fehler bei Validierung, Autorisierung, Quelle oder Zustellung kosten selbst keine Credits. Abgerechnet werden nur bezahlte Monitor-Zyklen und erfolgreich abgerechnete Zusatzprüfungen.