
# Changelog'a webhook aboneliği oluşturun

`POST https://api.keenauth.com/v1/accounts/{account_id}/changelog-subscriptions` · hesap sahibi veya yönetici

Seçtiğiniz kategorilerden birindeki bir [değişiklik günlüğü](/docs/changelog) girdisi yayımlandığında `changelog.entry_published` webhook'u alan, kendi HTTPS uç noktanızı kaydeder. İstek, `keenauth login` kimlik bilgileriyle yapılır: hesap, giriş yaptığınız hesap olmalı ve bu hesabın sahibi veya yöneticisi olmalısınız. Bir hesap en fazla 5 etkin abonelik sahip olabilir.

Her aboneliğin, yanıtta yalnızca bir kez döndürülen kendi imzalama sırrı vardır. Teslimatlar Standard Webhooks standardını izler: her istek `webhook-id`, `webhook-timestamp` ve `webhook-signature` üstbilgilerini taşır; imza (`v1,<base64>`), `<webhook-id>.<webhook-timestamp>.<body>` üzerinden hesaplanan bir HMAC-SHA256'dır. HMAC anahtarı, `idp_whsec_` öneki sonrasındaki 43 karakterin kodladığı 32 bayttır (base62, big-endian); son 6 karakter bir sağlama toplamıdır ve anahtarın parçası değildir. Gövdeye güvenmeden önce imzayı doğrulayın ve geçerli zamandan çok uzak olan zaman damgalarını reddedin (Standard Webhooks kütüphaneleri 5 dakikaya izin verir).

URL'ye kişisel veri, kimlik bilgisi veya jeton koymayın: URL abonelikle birlikte saklanır ve hesabın her sahibine ve yöneticisine gösterilir.

## İstek

Üstbilgiler:

| Üstbilgi | Zorunlu | Açıklama |
| --- | --- | --- |
| `Authorization` | evet | `DPoP <access token>`: giriş yaptığınızda CLI'nin aldığı erişim jetonu. |
| `DPoP` | evet | Bu istek için bir DPoP kanıtı (`htm` `POST`, `htu` bu isteğin URL'si), erişim jetonunun bağlı olduğu anahtarla imzalanmış; erişim jetonunun özetini ve sunucu nonce'unu taşır. |
| `Content-Type` | evet | `application/json`. |
| `Idempotency-Key` | hayır | 16 ila 64 karakter uzunluğunda `A-Z`, `a-z`, `0-9`, `_` ve `-` karakterleri. Aynı anahtar ve gövdeyle 24 saat içinde yapılan yinelenen istek, sırrı olmadan aynı aboneliği döndürür; `secret_redacted: true` ve `Idempotent-Replayed: true` üstbilgisiyle birlikte. |

Gövde:

| Alan | Zorunlu | Açıklama |
| --- | --- | --- |
| `url` | evet | Uç nokta: `https`, 443 numaralı bağlantı noktası, bir ana bilgisayar adı (IP adresi veya `.localhost`, `.local` ya da `.internal` gibi yalnızca yerel bir ad değil), kullanıcı bilgisi veya parça (fragment) yok, en fazla 2048 bayt. |
| `categories` | hayır | `api`, `sdk`, `deprecation`, `security` ve `incident` değerlerinden herhangi biri, her biri en fazla bir kez. Tüm kategorileri almak için alanı çıkarın; boş bir dizi reddedilir. |

## Yanıt

`201 Created`, `Cache-Control: no-store` ile:

| Alan | Açıklama |
| --- | --- |
| `id` | Abonelik (`chlg_…`). |
| `account_id` | Hesap (`acct_…`). |
| `url` | Uç nokta. |
| `categories` | Alınan kategoriler, `api`, `sdk`, `deprecation`, `security`, `incident` sırasıyla. |
| `status` | `enabled`, ya da teslimatlar başarısız olmaya devam ettiğinde `disabled`. |
| `created_at` | Aboneliğin oluşturulduğu zaman (RFC 3339, UTC). |
| `signing_secret` | İmzalama sırrı (`idp_whsec_…`). Yalnızca bu yanıtta döndürülür; onu gizli bilgi yöneticinizde saklayın. |
| `secret_redacted` | `true`, idempotent yeniden oynatmada döner ve `signing_secret` içermez. |

## Hatalar

| Durum | Kod | Ne zaman |
| --- | --- | --- |
| 400 | `malformed_request` | Gövde JSON değil veya `Idempotency-Key` üstbilgisi yinelenmiş, boş ya da hatalı biçimde. |
| 400 | `unknown_field` | Gövdede `url` ve `categories` dışında bir alan var. |
| 401 | `unauthenticated` | Hiçbir erişim jetonu gönderilmedi. |
| 401 | `invalid_token` | Erişim jetonu geçersiz, süresi dolmuş veya CLI'ye ait değil; `keenauth login` ile yeniden giriş yapın. |
| 401 | `invalid_dpop_proof` | DPoP kanıtı eksik, yinelenmiş veya isteğe ya da jetonun anahtarına uymuyor. |
| 401 | `use_dpop_nonce` | `DPoP-Nonce` yanıt üstbilgisindeki nonce'u taşıyan bir kanıtla yeniden deneyin. |
| 401 | `insufficient_user_authentication` | Çok faktörlü kimlik doğrulama (ya da sahipler ve yöneticiler için bir passkey veya güvenlik anahtarı) gerekli; yeniden giriş yapın. |
| 403 | `insufficient_permissions` | Hesabın sahibi veya yöneticisi değilsiniz. |
| 403 | `account_restricted` | Hesabın durumu değişikliğe izin vermiyor. |
| 403 | `quota_exceeded` | Hesabın zaten 5 etkin aboneliği var (`errors[].code` `changelog_subscription_limit_exceeded`). |
| 404 | `not_found` | Hesap yok, giriş yaptığınız hesap değil veya bu hesabın üyesi değilsiniz. |
| 413 | `payload_too_large` | Gövde 8 KiB'den büyük. |
| 415 | `unsupported_media_type` | Gövde `application/json` değil. |
| 422 | `validation_failed` | `url` eksik veya geçersiz, bir kategori bilinmiyor veya yinelenmiş, `categories` boş ya da bir alanın türü yanlış. |
| 422 | `idempotency_key_reuse` | `Idempotency-Key` 24 saat içinde başka bir gövdeyle kullanıldı. |
| 429 | `rate_limited` | Son bir saatte hesap için 10'dan fazla abonelik oluşturuldu; `Retry-After` için bekleyin. |

## Webhook teslimi

Bir girdi yayımlandığında KeenAuth, kategorilerinden biri girdinin kategorilerinden birini içeren her etkin aboneliğin URL'sine bir `POST` gönderir. Aynı girdi, bir aboneliğe asla iki kez gönderilmez.

### İstek

| Üstbilgi | Açıklama |
| --- | --- |
| `Content-Type` | `application/json`. |
| `webhook-id` | `id` olayı (`evt_…`). Aynı girdinin her yeniden denemesinde aynıdır; yinelenenleri yok saymak için kullanın. |
| `webhook-timestamp` | Bu denemenin imzalandığı Unix zamanı (saniye cinsinden). Her denemede yenidir. |
| `webhook-signature` | `v1,<base64>`: yukarıda açıklanan HMAC-SHA256, `<webhook-id>.<webhook-timestamp>.<body>` üzerinden. |

Gövde en fazla 16 KiB'dir. KeenAuth yönlendirmeleri takip etmez.

### Olay

```json
{
  "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"
  }
}
```

| Alan | Açıklama |
| --- | --- |
| `id` | Olay (`evt_…`), `webhook-id` üstbilgisiyle aynı. |
| `type` | Her zaman `changelog.entry_published`. |
| `schema_version` | Her zaman `1`. Sürüm 1 içinde `data` nesnesine yeni isteğe bağlı alanlar eklenebilir; bilmediğiniz alanları yok sayın. |
| `occurred_at` | Girdinin yayımlandığı zaman (RFC 3339). |
| `recorded_at` | KeenAuth teslimatı kuyruğa aldığı zaman (RFC 3339). |
| `data.id`, `data.url`, `data.title`, `data.date_published` | Girdi, değişiklik günlüğü beslemelerindeki gibi. |
| `data.tags` | `added`, `changed`, `fixed`, `removed`, `deprecation`, `security`, `breaking` ve `incident` değerlerinden bir veya daha fazlası. |
| `data.categories` | Girdinin ait olduğu abonelik kategorileri. |
| `data.surfaces` | Etkilenen yüzeyler: `kind` (`api`, `sdk`, `cli`, `provider`, `mcp` veya `docs`), `name` ve biliniyorsa `version`. |
| `data.breaking` | Değişiklik kırıcıysa `true`. |
| `data.sunset_at` | Bir kullanımdan kaldırmanın kaldırılma tarihi (`YYYY-MM-DD`), aksi halde `null`. |

Makine tarafından okunabilir şema `changelog.entry_published.v1`.

### Yanıtlar ve yeniden denemeler

15 saniye içinde herhangi bir `2xx` durumuyla yanıt verin. Yanıt gövdesi yok sayılır. Diğer tüm sonuçlar başarısız deneme sayılır ve yeniden denenir: bağlantı veya TLS hatası, zaman aşımı, yönlendirme, `429`, `5xx` ve `410` dışındaki her durum. İlk deneme hemen yapılır; sonrakiler önceki başarısızlıktan sonra yaklaşık 1 dakika, 5 dakika, 30 dakika, 2 saat, 8 saat, 24 saat ve 36 saat sonra yapılır (her aralık en fazla yüzde 10 değişir); toplamda yaklaşık 3 gün içinde 8 deneme.

Sekizinci deneme de başarısız olursa teslimat iptal edilir ve abonelik devre dışı bırakılır (`status` `disabled`). Bu abonelik için zaten kuyruğa alınmış teslimatlar iptal edilir.

### 410 Gone

KeenAuth'a artık teslimat istemediğinizi bildirmek için `410 Gone` ile yanıt verin. Abonelik, başka deneme yapılmadan hemen devre dışı bırakılır ve kuyruğa alınmış teslimatları iptal edilir. Devre dışı bırakılmış bir abonelik yeniden etkinleştirilmez ve 5 aboneliklik sınıra dahil edilmez; girdileri yeniden almak için yeni bir abonelik oluşturun. Her devre dışı bırakma, hesap denetim günlüğüne `changelog.subscription_disabled` olarak, `receiver_gone`, `permanent_failure` veya `schedule_exhausted` nedeniyle kaydedilir.

## Örnek

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