Dokümantasyon 07 / 10
Bildirim kanalları ve webhook imzası
Bildirimler, bir olay gerçekleştiğinde (ör. kesinti onaylandığında) seçtiğiniz kanallara gönderilir. Kullanılabilen kanal türleri ve aylık bildirim sayısı paketinize bağlıdır. Gönderimler kuyruk üzerinden yapılır ve geçici hatalarda yeniden denenir; gönderim geçmişini panelde Bildirimler sayfasında görebilirsiniz.
Olay türleri
| Olay | Ne zaman? |
|---|---|
monitor.down |
Kesinti onaylandığında (ardışık hata eşiğine ulaşıldığında). |
monitor.up |
Kesinti sona erdiğinde; kesinti süresiyle birlikte. |
monitor.flapping |
Son 60 dakikada 4 veya daha fazla onaylı durum değişikliği olduğunda. Sonraki 30 dakika tekrarlayan bildirimler bastırılır. |
incident.created, incident.updated, incident.resolved |
Status sayfası olaylarında. |
maintenance.scheduled, .started, .completed, .canceled, .reminder |
Planlı bakımlarda. |
target.verification_lost |
Hedef doğrulaması düştüğünde. |
domain.tls_expiring |
Özel domain sertifikası yenilenemediğinde. |
channel.test |
Paneldeki “Test” düğmesiyle. |
Bildirimlerde hedef adres maskelenir; parola, token ve header değerleri gibi sırlar hiçbir mesaja eklenmez.
Kanallar
- E-posta: Başlık, açıklama, alanlar ve panel bağlantısı içeren HTML + düz metin e-posta.
- Telegram: Bot üzerinden sohbet veya gruba mesaj.
- Slack: Gelen webhook (incoming webhook) adresine düz metin mesaj.
- Discord: Webhook adresine embed mesaj; kullanıcı/rol etiketlemeleri devre dışıdır.
- Genel webhook: JSON gövdeli, HMAC-SHA256 ile imzalanmış
POSTisteği.
Webhook adresleri yalnızca https:// ile başlayabilir (şifresiz http:// kabul edilmez) ve izleme hedefleriyle aynı ağ güvenlik politikasından geçer: özel/ayrılmış IP adreslerine gönderim yapılmaz, yönlendirme izlenmez, zaman aşımı 10 saniyedir. Alıcı 404 veya 410 dönerse gönderim yeniden denenmez.
Genel webhook biçimi
İstek başlıkları:
Content-Type: application/json
X-Isletme-Event: monitor.down
X-Isletme-Event-Id: 3f0c6f7e-...-uuid
X-Isletme-Signature: t=1767225600,v1=5d41402abc4b2a76b9719d911017c592...
Gövde:
{
"id": "3f0c6f7e-...-uuid",
"type": "monitor.down",
"created_at": "2026-01-01T00:00:00+00:00",
"title": "Kesinti: Ana site",
"message": "…",
"severity": "critical",
"url": "https://…/app/o/…/monitorler/…",
"data": { "…": "olaya özgü alanlar" }
}
severity değerleri: critical, warning, ok, info.
İmza doğrulama
X-Isletme-Signature başlığı virgülle ayrılmış parçalardan oluşur:
t=<unix zaman damgası>— gönderim zamanı (saniye).v1=<hex>—HMAC_SHA256(secret, t + "." + ham_gövde)değerinin küçük harfli onaltılık gösterimi.- Secret yenilendikten sonraki geçiş döneminde ikinci bir
v1=parçası, önceki secret ile hesaplanmış imzayı taşır. Herhangi birv1eşleşirse imza geçerlidir.
Önerilen doğrulama adımları:
- Gövdeyi ayrıştırmadan önce ham bayt olarak okuyun.
tdeğerinin şimdiki zamandan en fazla birkaç dakika farklı olduğunu kontrol edin (replay koruması; ör. 5 dakika).- İmzayı kendiniz hesaplayıp sabit zamanlı karşılaştırma ile
v1değerleriyle karşılaştırın. X-Isletme-Event-Iddeğerini saklayarak aynı olayın tekrar işlenmesini önleyin (yeniden denemelerde aynı kimlik gönderilir).
PHP örneği
$body = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_ISLETME_SIGNATURE'] ?? '';
$parts = [];
foreach (explode(',', $header) as $p) {
[$k, $v] = array_pad(explode('=', $p, 2), 2, '');
$parts[$k][] = $v;
}
$t = (int) ($parts['t'][0] ?? 0);
if (abs(time() - $t) > 300) { http_response_code(400); exit; }
$expected = hash_hmac('sha256', $t . '.' . $body, $secret);
$ok = false;
foreach ($parts['v1'] ?? [] as $sig) {
$ok = $ok || hash_equals($expected, $sig);
}
if (! $ok) { http_response_code(401); exit; }
Node.js örneği
const crypto = require('crypto');
function verify(rawBody, header, secret) {
const parts = header.split(',').map(p => p.split('='));
const t = Number((parts.find(([k]) => k === 't') || [])[1]);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return parts.filter(([k]) => k === 'v1').some(([, v]) =>
v.length === expected.length && crypto.timingSafeEqual(Buffer.from(v), Buffer.from(expected)));
}
Webhook'unuz 2xx dışında bir yanıt verirse gönderim başarısız sayılır ve yeniden denenir.
Bu belge ürünün mevcut davranışını anlatır. Bir tutarsızlık görürseniz lütfen bize bildirin.