Abonner un webhook au journal des modifications

POST https://api.keenauth.com/v1/accounts/{account_id}/changelog-subscriptions · propriétaire du compte ou administrateur

Enregistre un point de terminaison HTTPS qui vous appartient et qui reçoit un webhook changelog.entry_published chaque fois qu'une entrée du journal des modifications appartenant à l'une des catégories choisies est publiée. La requête est effectuée avec les identifiants de keenauth login : le compte doit être celui dans lequel vous vous êtes connecté, et vous devez en être le propriétaire ou un administrateur. Un compte peut avoir au plus 5 abonnements activés.

Chaque abonnement possède son propre secret de signature, renvoyé une seule fois dans la réponse. Les livraisons suivent Standard Webhooks : chaque requête contient les en-têtes webhook-id, webhook-timestamp et webhook-signature, et la signature (v1,<base64>) est un HMAC-SHA256 calculé sur <webhook-id>.<webhook-timestamp>.<body>. La clé HMAC correspond aux 32 octets encodés par les 43 caractères qui suivent le préfixe idp_whsec_ (base62, big-endian) ; les 6 derniers caractères forment une somme de contrôle et ne font pas partie de la clé. Vérifiez la signature et rejetez un horodatage trop éloigné de l'heure actuelle (les bibliothèques Standard Webhooks acceptent 5 minutes) avant de faire confiance au contenu.

Ne placez pas de données personnelles, d'identifiants ou de jetons dans l'URL : elle est stockée avec l'abonnement et affichée à tous les propriétaires et administrateurs du compte.

Requête

En-têtes :

En-tête Obligatoire Description
Authorization oui DPoP <access token> : le jeton d'accès reçu par la CLI lors de votre connexion.
DPoP oui Une preuve DPoP pour cette requête (htm POST, htu l'URL de cette requête), signée avec la clé à laquelle le jeton d'accès est lié ; elle contient le hachage du jeton d'accès et le nonce du serveur.
Content-Type oui application/json.
Idempotency-Key non 16 à 64 caractères parmi A-Z, a-z, 0-9, _ et -. Répéter la requête avec la même clé et le même corps dans les 24 heures renvoie le même abonnement sans le secret, avec secret_redacted: true et l'en-tête Idempotent-Replayed: true.

Corps :

Champ Obligatoire Description
url oui Le point de terminaison : https, port 443, un nom d'hôte (pas une adresse IP ni un nom local uniquement tel que .localhost, .local ou .internal), sans informations d'utilisateur ni fragment, au plus 2048 octets.
categories non Parmi api, sdk, deprecation, security et incident, chacune au plus une fois. Omettez le champ pour recevoir toutes les catégories ; un tableau vide est refusé.

Réponse

201 Created avec Cache-Control: no-store :

Champ Description
id L'abonnement (chlg_…).
account_id Le compte (acct_…).
url Le point de terminaison.
categories Les catégories reçues, dans l'ordre api, sdk, deprecation, security, incident.
status enabled, ou disabled lorsque les livraisons ont continué d'échouer.
created_at Date de création de l'abonnement (RFC 3339, UTC).
signing_secret Le secret de signature (idp_whsec_…). Renvoyé uniquement dans cette réponse ; conservez-le dans votre gestionnaire de secrets.
secret_redacted true lors d'une rejouabilité idempotente, qui ne contient pas signing_secret.

Erreurs

Statut Code Cas
400 malformed_request Le corps n'est pas du JSON, ou l'en-tête Idempotency-Key est répété, vide ou mal formé.
400 unknown_field Le corps contient un champ autre que url et categories.
401 unauthenticated Aucun jeton d'accès n'a été envoyé.
401 invalid_token Le jeton d'accès est invalide, expiré ou n'appartient pas à la CLI ; reconnectez-vous avec keenauth login.
401 invalid_dpop_proof La preuve DPoP est absente, répétée ou ne correspond pas à la requête ou à la clé du jeton.
401 use_dpop_nonce Réessayez avec une preuve contenant le nonce de l'en-tête de réponse DPoP-Nonce.
401 insufficient_user_authentication L'authentification multifacteur est requise (ou, pour les propriétaires et administrateurs, une clé d'accès ou une clé de sécurité) ; reconnectez-vous.
403 insufficient_permissions Vous n'êtes ni propriétaire ni administrateur du compte.
403 account_restricted Le statut du compte ne permet pas de modifications.
403 quota_exceeded Le compte possède déjà 5 abonnements activés (errors[].code changelog_subscription_limit_exceeded).
404 not_found Le compte n'existe pas, n'est pas celui dans lequel vous vous êtes connecté, ou vous n'en êtes pas membre.
413 payload_too_large Le corps dépasse 8 Kio.
415 unsupported_media_type Le corps n'est pas application/json.
422 validation_failed url est absent ou invalide, une catégorie est inconnue ou répétée, categories est vide, ou un champ a un type incorrect.
422 idempotency_key_reuse Le Idempotency-Key a été utilisé avec un autre corps dans les 24 heures.
429 rate_limited Plus de 10 abonnements ont été créés pour le compte au cours de la dernière heure ; attendez Retry-After.

Livraison des webhooks

Lorsqu'une entrée est publiée, KeenAuth envoie une POST à l'URL de chaque abonnement activé dont les catégories incluent l'une des catégories de l'entrée. La même entrée n'est jamais envoyée deux fois au même abonnement.

Requête

En-tête Description
Content-Type application/json.
webhook-id L'identifiant de l'événement id (evt_…). Il est identique à chaque nouvelle tentative pour la même entrée ; utilisez-le pour ignorer les doublons.
webhook-timestamp Heure Unix en secondes à laquelle cette tentative a été signée. Elle change à chaque tentative.
webhook-signature v1,<base64> : le HMAC-SHA256 décrit ci-dessus, calculé sur <webhook-id>.<webhook-timestamp>.<body>.

Le corps fait au plus 16 Kio. KeenAuth ne suit pas les redirections.

Événement

{
  "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"
  }
}
Champ Description
id L'événement (evt_…), identique à l'en-tête webhook-id.
type Toujours changelog.entry_published.
schema_version Toujours 1. De nouveaux champs facultatifs peuvent être ajoutés à data dans la version 1 ; ignorez les champs que vous ne connaissez pas.
occurred_at Date de publication de l'entrée (RFC 3339).
recorded_at Date à laquelle KeenAuth a mis la livraison en file d'attente (RFC 3339).
data.id, data.url, data.title, data.date_published L'entrée, comme dans les flux du journal des modifications.
data.tags Une ou plusieurs valeurs parmi added, changed, fixed, removed, deprecation, security, breaking et incident.
data.categories Les catégories d'abonnement auxquelles appartient l'entrée.
data.surfaces Les surfaces concernées : kind (api, sdk, cli, provider, mcp ou docs), name et, lorsqu'elle est connue, version.
data.breaking true lorsque la modification est incompatible.
data.sunset_at La date de retrait d'une obsolescence (YYYY-MM-DD), sinon null.

Le schéma lisible par machine est changelog.entry_published.v1.

Réponses et nouvelles tentatives

Répondez avec un statut 2xx dans un délai de 15 secondes. Le corps de la réponse est ignoré. Tout autre résultat est une tentative échouée et est réessayée : une erreur de connexion ou TLS, un délai dépassé, une redirection, 429, 5xx et tout autre statut sauf 410. La première tentative est effectuée immédiatement ; les suivantes environ 1 minute, 5 minutes, 30 minutes, 2 heures, 8 heures, 24 heures et 36 heures après l'échec précédent (chaque intervalle varie jusqu'à 10 pour cent), soit 8 tentatives sur environ 3 jours au total.

Si la huitième tentative échoue, la livraison est abandonnée et l'abonnement est désactivé (status disabled). Les livraisons déjà en file d'attente pour cet abonnement sont annulées.

410 Gone

Répondez 410 Gone pour indiquer à KeenAuth que vous ne souhaitez plus recevoir de livraisons. L'abonnement est immédiatement désactivé, sans nouvelle tentative, et ses livraisons en file d'attente sont annulées. Un abonnement désactivé ne peut pas être réactivé et ne compte pas dans la limite de 5 ; créez-en un nouveau pour recevoir à nouveau des entrées. Chaque désactivation est consignée dans le journal d'audit du compte sous changelog.subscription_disabled, avec la raison receiver_gone, permanent_failure ou schedule_exhausted.

Exemple

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"]}'