Webhook für das Changelog abonnieren
POST https://api.keenauth.com/v1/accounts/{account_id}/changelog-subscriptions · Kontoinhaber oder Administrator
Registriert einen eigenen HTTPS-Endpunkt, der einen changelog.entry_published-Webhook empfängt, sobald ein Changelog-Eintrag in einer der gewählten Kategorien veröffentlicht wird. Die Anfrage wird mit den Zugangsdaten von keenauth login gestellt: Das Konto muss dasjenige sein, bei dem Sie angemeldet sind, und Sie müssen dessen Inhaber oder Administrator sein. Ein Konto kann höchstens 5 aktivierte Abonnements haben.
Jedes Abonnement hat ein eigenes Signaturgeheimnis, das in der Antwort einmalig zurückgegeben wird. Die Zustellung folgt Standard Webhooks: Jede Anfrage enthält die Header webhook-id, webhook-timestamp und webhook-signature, und die Signatur (v1,<base64>) ist ein HMAC-SHA256 über <webhook-id>.<webhook-timestamp>.<body>. Der HMAC-Schlüssel sind die 32 Bytes, die die 43 Zeichen nach dem Präfix idp_whsec_ kodieren (Base62, Big-Endian); die letzten 6 Zeichen sind eine Prüfsumme und gehören nicht zum Schlüssel. Prüfen Sie die Signatur und lehnen Sie einen Zeitstempel ab, der zu weit von der aktuellen Zeit entfernt ist (die Standard-Webhooks-Bibliotheken erlauben 5 Minuten), bevor Sie dem Inhalt vertrauen.
Legen Sie keine personenbezogenen Daten, Zugangsdaten oder Token in die URL: Sie wird mit dem Abonnement gespeichert und allen Inhabern und Administratoren des Kontos angezeigt.
Anfrage
Header:
| Header | Pflicht | Beschreibung |
|---|---|---|
Authorization |
ja | DPoP <access token>: das Zugriffstoken, das die CLI beim Anmelden erhalten hat. |
DPoP |
ja | Ein DPoP-Nachweis für diese Anfrage (htm POST, htu die URL dieser Anfrage), signiert mit dem Schlüssel, an den das Zugriffstoken gebunden ist; er enthält den Hash des Zugriffstokens und den Server-Nonce. |
Content-Type |
ja | application/json. |
Idempotency-Key |
nein | 16 bis 64 Zeichen aus A-Z, a-z, 0-9, _ und -. Wiederholt man die Anfrage mit demselben Schlüssel und Inhalt innerhalb von 24 Stunden, wird dasselbe Abonnement ohne das Geheimnis zurückgegeben, mit secret_redacted: true und dem Header Idempotent-Replayed: true. |
Anfragetext:
| Feld | Pflicht | Beschreibung |
|---|---|---|
url |
ja | Der Endpunkt: https, Port 443, ein Hostname (keine IP-Adresse und kein nur lokal gültiger Name wie .localhost, .local oder .internal), ohne Benutzerinformationen oder Fragment, höchstens 2048 Byte. |
categories |
nein | Beliebige der Werte api, sdk, deprecation, security und incident, jeweils höchstens einmal. Lassen Sie das Feld weg, um alle Kategorien zu erhalten; ein leeres Array wird abgelehnt. |
Antwort
201 Created mit Cache-Control: no-store:
| Feld | Beschreibung |
|---|---|
id |
Das Abonnement (chlg_…). |
account_id |
Das Konto (acct_…). |
url |
Der Endpunkt. |
categories |
Die empfangenen Kategorien in der Reihenfolge api, sdk, deprecation, security, incident. |
status |
enabled, oder disabled, wenn Zustellungen wiederholt fehlschlagen. |
created_at |
Zeitpunkt der Erstellung des Abonnements (RFC 3339, UTC). |
signing_secret |
Das Signaturgeheimnis (idp_whsec_…). Wird nur in dieser Antwort zurückgegeben; speichern Sie es in Ihrem Secret-Manager. |
secret_redacted |
true bei einer idempotenten Wiederholung, die kein signing_secret enthält. |
Fehler
| Status | Code | Wann |
|---|---|---|
| 400 | malformed_request |
Der Anfragetext ist kein JSON, oder der Header Idempotency-Key ist mehrfach vorhanden, leer oder fehlerhaft. |
| 400 | unknown_field |
Der Anfragetext enthält ein anderes Feld als url und categories. |
| 401 | unauthenticated |
Es wurde kein Zugriffstoken gesendet. |
| 401 | invalid_token |
Das Zugriffstoken ist ungültig, abgelaufen oder gehört nicht zur CLI; melden Sie sich erneut mit keenauth login an. |
| 401 | invalid_dpop_proof |
Der DPoP-Nachweis fehlt, ist mehrfach vorhanden oder passt weder zur Anfrage noch zum Schlüssel des Tokens. |
| 401 | use_dpop_nonce |
Wiederholen Sie die Anfrage mit einem Nachweis, der den Nonce aus dem Antwortheader DPoP-Nonce enthält. |
| 401 | insufficient_user_authentication |
Multi-Faktor-Authentifizierung (bzw. für Inhaber und Administratoren ein Passkey oder Sicherheitsschlüssel) ist erforderlich; melden Sie sich erneut an. |
| 403 | insufficient_permissions |
Sie sind kein Inhaber und kein Administrator des Kontos. |
| 403 | account_restricted |
Der Status des Kontos erlaubt keine Änderungen. |
| 403 | quota_exceeded |
Das Konto hat bereits 5 aktivierte Abonnements (errors[].code changelog_subscription_limit_exceeded). |
| 404 | not_found |
Das Konto existiert nicht, ist nicht das Konto, bei dem Sie angemeldet sind, oder Sie sind dort kein Mitglied. |
| 413 | payload_too_large |
Der Anfragetext ist größer als 8 KiB. |
| 415 | unsupported_media_type |
Der Anfragetext ist nicht application/json. |
| 422 | validation_failed |
url fehlt oder ist ungültig, eine Kategorie ist unbekannt oder mehrfach angegeben, categories ist leer, oder ein Feld hat den falschen Typ. |
| 422 | idempotency_key_reuse |
Der Idempotency-Key wurde innerhalb von 24 Stunden mit einem anderen Anfragetext verwendet. |
| 429 | rate_limited |
In der letzten Stunde wurden für das Konto mehr als 10 Abonnements erstellt; warten Sie Retry-After ab. |
Webhook-Zustellung
Wenn ein Eintrag veröffentlicht wird, sendet KeenAuth einen POST an die URL jedes aktivierten Abonnements, dessen Kategorien eine der Kategorien des Eintrags enthalten. Derselbe Eintrag wird einem Abonnement nie zweimal gesendet.
Anfrage
| Header | Beschreibung |
|---|---|
Content-Type |
application/json. |
webhook-id |
Die Ereigniskennung id (evt_…). Sie ist bei jeder Wiederholung desselben Eintrags gleich, verwenden Sie sie daher, um Duplikate zu ignorieren. |
webhook-timestamp |
Unix-Zeit in Sekunden, zu der dieser Versuch signiert wurde. Sie ist bei jedem Versuch neu. |
webhook-signature |
v1,<base64>: der oben beschriebene HMAC-SHA256 über <webhook-id>.<webhook-timestamp>.<body>. |
Der Anfragetext ist höchstens 16 KiB groß. KeenAuth folgt keinen Weiterleitungen.
Ereignis
{
"id": "evt_01jb0000000000000000000000",
"type": "changelog.entry_published",
"schema_version": 1,
"occurred_at": "2026-11-04T00:00:00Z",
"recorded_at": "2026-11-04T08:30:12Z",
"data": {
"id": "2026-11-04-example",
"url": "https://docs.keenauth.com/en/changelog/#2026-11-04-example",
"title": "Example entry",
"date_published": "2026-11-04T00:00:00Z",
"tags": ["deprecation"],
"categories": ["api", "deprecation"],
"surfaces": [{"kind": "api", "name": "management-v1", "version": "v1"}],
"breaking": false,
"sunset_at": "2027-11-04"
}
}
| Feld | Beschreibung |
|---|---|
id |
Das Ereignis (evt_…), identisch mit dem Header webhook-id. |
type |
Immer changelog.entry_published. |
schema_version |
Immer 1. Innerhalb von Version 1 können data neue optionale Felder hinzugefügt werden; ignorieren Sie unbekannte Felder. |
occurred_at |
Zeitpunkt der Veröffentlichung des Eintrags (RFC 3339). |
recorded_at |
Zeitpunkt, zu dem KeenAuth die Zustellung eingereiht hat (RFC 3339). |
data.id, data.url, data.title, data.date_published |
Der Eintrag, wie in den Changelog-Feeds. |
data.tags |
Ein oder mehrere der Werte added, changed, fixed, removed, deprecation, security, breaking und incident. |
data.categories |
Die Abonnement-Kategorien, zu denen der Eintrag gehört. |
data.surfaces |
Die betroffenen Oberflächen: kind (api, sdk, cli, provider, mcp oder docs), name und, sofern bekannt, version. |
data.breaking |
true, wenn die Änderung inkompatibel ist. |
data.sunset_at |
Das Entfernungsdatum einer Veralterung (YYYY-MM-DD), andernfalls null. |
Das maschinenlesbare Schema ist changelog.entry_published.v1.
Antworten und Wiederholungen
Antworten Sie innerhalb von 15 Sekunden mit einem beliebigen 2xx-Status. Der Antworttext wird ignoriert. Jedes andere Ergebnis ist ein fehlgeschlagener Versuch und wird wiederholt: ein Verbindungs- oder TLS-Fehler, ein Timeout, eine Weiterleitung, 429, 5xx und jeder andere Status außer 410. Der erste Versuch erfolgt sofort; die folgenden etwa 1 Minute, 5 Minuten, 30 Minuten, 2 Stunden, 8 Stunden, 24 Stunden und 36 Stunden nach dem vorherigen Fehlschlag (jedes Intervall variiert um bis zu 10 Prozent), insgesamt 8 Versuche in etwa 3 Tagen.
Schlägt der achte Versuch fehl, wird die Zustellung aufgegeben und das Abonnement deaktiviert (status disabled). Bereits für das Abonnement eingereihte Zustellungen werden abgebrochen.
410 Gone
Antworten Sie mit 410 Gone, um KeenAuth mitzuteilen, dass Sie keine Zustellungen mehr wünschen. Das Abonnement wird sofort ohne weitere Versuche deaktiviert, und seine eingereihten Zustellungen werden abgebrochen. Ein deaktiviertes Abonnement wird nicht wieder aktiviert und zählt nicht zum Limit von 5; erstellen Sie ein neues, um wieder Einträge zu erhalten. Jede Deaktivierung wird im Audit-Log des Kontos als changelog.subscription_disabled festgehalten, mit dem Grund receiver_gone, permanent_failure oder schedule_exhausted.
Beispiel
curl -X POST https://api.keenauth.com/v1/accounts/acct_01jb0000000000000000000000/changelog-subscriptions \
-H "Authorization: DPoP $ACCESS_TOKEN" \
-H "DPoP: $DPOP_PROOF" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: changelog-hooks-2026-10" \
-d '{"url": "https://hooks.example.com/keenauth/changelog", "categories": ["deprecation", "security"]}'