# Webhook'lar

> Kaynak yazımları, izin değişiklikleri ve tamamlanmış belgeler için imzalı, yeniden denenen, ince olaylar; TypeScript, Dart ve Python'da imza doğrulaması ile.

Source: https://developers.anpheros.com/tr/guides/webhooks

Anpheros Platform, projenizde bir şey olduğunda sunucunuzu çağırabilir: bir kaynak yazıldı, bir kişi erişim izni verdi veya geri çekti, bir belge tamamlandı. Olaylar **ince** olaylardır: kimlikler, tür, sürüm — asla klinik içerik değil. İhtiyacınız olursa kaynağı API aracılığıyla okuyun. Her teslimat imzalıdır; güvenmeden önce imzayı doğrulayın.

## Bir uç nokta kaydedin

```bash
curl -X POST $BASE/v1/webhooks -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"url": "https://your.app/anpheros/hook", "events": ["resource.created", "consent.revoked"], "description": "prod"}'
```

Yanıt, `secret` (`whsec_…`) **bir kez** içerir. Saklayın; imzaları doğrulamak için ona ihtiyacınız olacak.
`events`, `["*"]` veya şunlardan herhangi birini kabul eder:

| tür | ne zaman | `data` |
|---|---|---|
| `resource.created` / `resource.updated` / `resource.deleted` | projeniz bir FHIR kaynağı (REST v1, FHIR API veya bir paket) yazdı — **veya başka bir proje erişiminiz olan bir kayda yazdı** (hastayı siz oluşturdunuz veya aktif bir yetkiniz var); o zaman `data.external`, `true` olur ve `data.source` kimin yazdığını söyler: `author_type` (hasta / uygulayıcı / cihaz / içe aktarma / yapay zeka), `organization` (yazarın adına hareket ettiği görünen ad), `practitioner` (biliniyorsa dizinden gelen ad), `source_system` | `resource_type`, `id`, `patient` (gördüğünüz kimlik), `version`, `last_updated` ve harici yazımlar için `external`, `source` |
| `consent.granted` | bir kişi uygulamanıza izin sayfasından erişim izni verdi (veya kaydını bağlayan güvenilir bir uygulama) | `grant_id`, `patient`, `application_id`, `scopes`, `purpose`, `expires_at` |
| `consent.revoked` | kişi (veya platform) bir yetkiyi sonlandırdı | yukarıdakilerle aynı artı `revoked_at`, `reason` |
| `document.finalized` | bir belge yüklemesi tamamlandı ve sağlama toplamı alındı | `id`, `patient`, `content_type`, `size`, `sha256` |
| `proposal.created` | bir yapay zeka aracısı görebildiğiniz bir kayda yazma önerdi; kişinin onayını bekliyor | `id`, `patient`, `action`, `resource_type` |
| `ping` | test teslimatı istediniz | `endpoint` |

Uç noktalar proje **ve ortama** göre belirlenir: bir `sk_test_` anahtarı sandbox uç noktalarını yönetir,
bir `sk_live_` anahtarı ise üretim uç noktalarını yönetir. URL'ler herkese açık `https://` uç noktaları olmalıdır. Kayıt (ve `url`'deki herhangi bir sonraki değişiklik) yerel, özel, bağlantı-yerel, meta veri ve diğer ayrılmış adresleri — `localhost`, `127.0.0.1`, `::1`, `10.0.0.0/8`, `192.168.0.0/16`, `fd00::/8` ve benzerleri — ve bunlara çözümleyen adları reddeder; bu, `400` `invalid` alanında `url` ile olur; bu sandbox'ta da geçerlidir. Her teslimat adresi tekrar kontrol eder ve yalnızca az önce kontrol ettiği IP adreslerine bağlanır, bu nedenle daha sonra özel bir ağa işaret eden bir ad (DNS yeniden bağlama) hiçbir şey almaz. Geliştirme sırasında kendi makinenizde olay almak için, bunu genel bir HTTPS tüneli aracılığıyla sunun ve tünelin adresini kaydedin.
Proje ve ortam başına en fazla 10 uç nokta.

## Teslimat

```
POST https://your.app/anpheros/hook
Content-Type: application/json
User-Agent: Anpheros-Webhooks/1.0
Anpheros-Event: resource.created
Anpheros-Event-Id: evt_…
Anpheros-Delivery: whd_…
Anpheros-Signature: t=1789800000,v1=5f3a…

{"id":"evt_…","type":"resource.created","created_at":"2026-09-19T12:00:00.000Z","environment":"production",
 "project":"proj_…","data":{"resource_type":"Observation","id":"…","patient":"…","version":1,"last_updated":"…"}}
```

10 saniye içinde herhangi bir `2xx` ile yanıt verin. Bunun dışındaki herhangi bir durum (veya zaman aşımı) başarısızlık olarak kabul edilir ve teslimat, 24 saate kadar (10 deneme) geri çekilme ile yeniden denenir, ardından `exhausted` olarak işaretlenir.
Teslimatlar en az bir kez yapılır ve sıra dışı gelebilir: yinelenenleri önlemek için `Anpheros-Event-Id` ve eski güncellemeleri yok saymak için `data.version` kullanın.

## İmzayı Doğrulama

`v1`, `<t>.<raw body>` üzerinde gizlinizle HMAC-SHA256'dır; `t` 5 dakikadan eskiyse reddedin.

```ts
import { verifyWebhookSignature } from '@anpheros/sdk';
app.post('/anpheros/hook', express.raw({ type: 'application/json' }), async (req, res) => {
  const ok = await verifyWebhookSignature({ secret: process.env.ANPHEROS_WEBHOOK_SECRET!, header: req.header('anpheros-signature'), body: req.body });
  if (!ok) return res.status(400).end();
  const event = JSON.parse(req.body.toString());
  // … enqueue and return quickly
  res.status(204).end();
});
```

```dart
import 'package:anpheros_sdk/anpheros_sdk.dart';
final ok = verifyWebhookSignature(secret: secret, header: request.headers['anpheros-signature'], body: rawBodyBytes);
```

```python
import hmac, hashlib, time
def verify(secret: str, header: str, body: bytes, tolerance=300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    if abs(time.time() - int(parts["t"])) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts["v1"])
```

## İşletme

- `GET /v1/webhooks/{id}/deliveries?status=failed` — en yeni önce, durum kodu ve hatasıyla birlikte günlük.
- `POST /v1/webhooks/{id}/deliveries/{delivery_id}/redeliver` — şimdi bir tane daha gönder.
- `POST /v1/webhooks/{id}/ping` — bir test olayı.
- `POST /v1/webhooks/{id}/rotate` — yeni sır (eski hemen durur; boşluk kaldıramıyorsanız önce sunucunuzu güncelleyin: ikinci bir uç nokta kaydedin, ardından eskini silin).
- `PATCH /v1/webhooks/{id}` ile `{"active": false}` teslimatları duraklatır; uç noktayı sildiğinizde bekleyenler düşürülür.

Her iki SDK da bunu `webhooks` (`create`, `list`, `get`, `update`, `delete`, `rotateSecret`, `ping`, `deliveries`, `redeliver`) altında sunar.
