Ana içeriğe geç
Geliştiriciler Webhook’lar

Webhook ile mesaj gönder

Webhook, topluluğuna mesaj gönderen bir URL’dir. CI, izleme, bir cron işi ya da bir betik gibi HTTP isteği yapabilen herhangi bir şeyden ona JSON gönder, mesaj kanalda görünsün.

Neler yapabilirsin

  • Metin ya da kart gönderDüz metin ya da başlığı, rengi, markdown’ı, alanları ve görselleri olan bir kart.
  • Dosya ekleMesaj başına en fazla beş dosya: loglar, raporlar, ekran görüntüleri.
  • Düğme ekleBağlantılar ya da kartı değiştiren veya servisine ulaşan düğmeler.
  • Sonradan değiştirYanıt, mesajı güncellemek ya da silmek için bir callback URL içerir.

Uygulamada

$ curl -X POST "$MSSGS_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-H "X-Mssgs-Signature: sha256=$SIG" \
-d '{"message_container": {"title": "Build #1847 başarılı", ...}}'
{"success": true, "message_id": "aZZ1a2b-..."}

CI’dan tek istek, #deploys kanalında tek kart. En üstteki ad, webhook’a verdiğin addır.

Hızlı başlangıç

  1. Webhook’u oluştur

    Masaüstü uygulamasında topluluğunun Manage Server → Webhooks bölümünü aç, bir webhook oluştur, mesaj gönderebileceği kanalları seç ve bir kanalın URL’sini kopyala. Şu biçimdedir:

    url
    https://mss.gs/api/v1/webhook/{webhook_guid}/{token}/{channel_guid}
  2. Mesaj gönder

    JSON’u webhook’un gizli anahtarıyla imzala ve POST et. Masaüstü uygulamasında oluşturulan bir webhook’un her zaman bir gizli anahtarı vardır: onu webhook’un ayarlarındaki Webhook Secret alanından kopyala.

    bash
    BODY='{"content": "Build #1847 passed on main"}'
    SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$MSSGS_WEBHOOK_SECRET" | sed 's/^.* //')
    
    curl -X POST "$MSSGS_WEBHOOK_URL" \
      -H "Content-Type: application/json" \
      -H "X-Mssgs-Signature: sha256=$SIG" \
      -d "$BODY"
  3. Yanıtı oku

    Yanıt sana mesajın id’sini ve mesajı sonradan değiştirmek için bir callback_url verir.

    json
    {
      "success": true,
      "message_id": "aZZ1a2b-...",
      "callback_url": "https://mss.gs/api/v1/trigger-callback/8f14e45f-...",
      "stream_url": "https://mss.gs/api/v1/instant/6b1e...c0?token=a1b2c3d4-..."
    }
URL’ye ve gizli anahtara sahip olan herkes o kanala mesaj gönderebilir. İkisini de herkese açık depolardan ve istemci tarafı koddan uzak tut.

Neler gönderebilirsin

Bir mesaj ya kısa biçimdedir (başlığı ve rengi olan bir metin) ya da tam bir karttır; ikisi de düğme ve dosya taşıyabilir. Kartın üstündeki ad her zaman webhook’un kendi adıdır. Webhook’un ayarlarında ayrıca görsel gönderip gönderemeyeceğine ve kişilerden bahsedip bahsedemeyeceğine de karar verirsin.

Kısa biçim

Çoğu uyarı için yeterli.

json
{
  "content": "Server backup completed at 03:00 UTC",
  "color": "green",
  "title": "Backup Bot"
}
AlanTürNe yapar
contentstringMesaj metni. Kart ya da dosya göndermiyorsan zorunlu.
colorstringblue (varsayılan), green, orange, red, yellow ya da purple.
titlestringMetnin üstünde bir başlık. Varsayılan olarak webhook’un adı.

Tam bir kart

Bağlantılı başlığı, alt başlığı, markdown’ı, alanları ve görselleri olan bir kart için bir message_container gönder. Webhook üzerinden bir kart type, color, title, title_url, sub_title, description, fields, avatar_url, image_url, image_base64, images ve yükleme alanlarını kabul eder. Durum kapsülü, rozet, diff istatistikleri ve katlanmış akıl yürütme komut yanıtları içindir. Tüm alanlar mesaj kartları sayfasında.

json
{
  "message_container": {
    "type": "embed_message",
    "color": "green",
    "title": "Build #1847 passed",
    "title_url": "https://ci.example.com/builds/1847",
    "description": "All 212 tests green on **main**.",
    "fields": [
      { "field": "Duration", "value": "2m 34s" },
      { "field": "Commit", "value": "1a2b3c4" }
    ]
  }
}
deploys
System
Message from CI

Build #1847 başarılı

main üzerinde 212 testin hepsi yeşil.
Duration
2m 34s
Commit
1a2b3c4

Düğmeler

Mesajın altına düğme koymak için bir actions dizisi ekle. Nasıl çalıştıkları düğmeler sayfasında.

Dosyalar

Bir mesajla gerçek dosyalar gönder: bir log, bir rapor, bir ekran görüntüsü. Diğer ekler gibi görünürler: bir indirme satırı olarak ya da görseller, video ve ses için doğrudan mesajın içinde. Yalnızca dosyalardan oluşan bir mesaj da olur: content alanını ve kartı çıkar.

json
{
  "message_container": {
    "color": "orange",
    "title": "Log dump: ios",
    "description": "DMs stopped arriving after switching networks"
  },
  "attachments": [
    {
      "name": "mssgs-logs-20260803-141205.log",
      "content_base64": "MjAyNi0wOC0wMyAxNDoxMjowNSBbV1NdIGNvbm5lY3RlZAo=",
      "mime_type": "text/plain"
    }
  ]
}
AlanTürNe yapar
namestringDosyanın indirildiğinde alacağı ad. Zorunlu. Bir yol verilirse yalnızca son parçası kalır.
content_base64stringDosyanın baytları base64 olarak, ham ya da bir data: URI’si biçiminde. mssgs dosyayı saklar ve mesajda yalnızca bir bağlantı tutar.
mime_typestringcontent_base64 içeriğinin türü. Varsayılan text/plain.
urlstringmssgs’te zaten barındırılan bir dosya: bir /static/... yolu ya da bir https://mss.gs/... URL’si.
Her dosya için content_base64 ya da url alanlarından tam olarak birini gönder. İkisi birden ya da hiçbiri hatadır.
LimitDeğer
Mesaj başına dosya5
Çözüldükten sonra dosya başına boyut8 MB
Dosya adı200 karakter
İsteğin tamamıYaklaşık 10 MB. Base64 bir dosyayı üçte bir büyütür, bu yüzden yaklaşık 7 MB’tan büyük tek bir dosya sığmaz.

url neden yalnızca mssgs adreslerini kabul ediyor

Bir webhook URL’si çoğu zaman başka panolara yapıştırılır. Sızan bir URL, birinin her üyenin uygulamasına kendi seçtiği bir sunucudan dosya çektirmesine izin vermemeli. Dosyan başka bir yerdeyse onu content_base64 olarak gönder, mssgs barındırsın.

Başarısız bir yükleme mesajı başarısız kılmaz

Dosyalar önceden kontrol edilir ama sonradan yüklenir. Bir yükleme başarısız olursa o dosya dışarıda kalır ve mesajın geri kalanı hata vermeden yine gönderilir: dosyayı kaybetmek raporu kaybetmekten iyidir. Bir dosya önemliyse ulaştığını kontrol et.

Komut satırından bir dosya

bash
BODY='{"attachments":[{"name":"report.csv","content_base64":"'"$(base64 < report.csv | tr -d '\n')"'","mime_type":"text/csv"}]}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$MSSGS_WEBHOOK_SECRET" | sed 's/^.* //')

printf '%s' "$BODY" | curl -sS -X POST "$MSSGS_WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -H "X-Mssgs-Signature: sha256=$SIG" \
  --data-binary @-

İstekleri imzalama

Gizli anahtarı olan bir webhook yalnızca onu bildiğini kanıtlayan istekleri kabul eder ve masaüstü uygulamasında oluşturulan bir webhook’un her zaman bir gizli anahtarı vardır (ayarlarındaki Webhook Secret). Ham istek gövdesini gizli anahtarla HMAC-SHA256 kullanarak imzala ve küçük harfli hex özeti X-Mssgs-Signature başlığında sha256=<hex> olarak gönder.

javascript
import crypto from 'node:crypto';

const body = JSON.stringify({ content: 'Deploy finished' });
const signature = crypto.createHmac('sha256', process.env.MSSGS_WEBHOOK_SECRET)
  .update(body)
  .digest('hex');

await fetch(process.env.MSSGS_WEBHOOK_URL, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Mssgs-Signature': `sha256=${signature}`
  },
  body
});
Geçerli bir imzası olmayan istek 401 ve {"error": "INVALID_SIGNATURE"} alır. Yalnızca gizli anahtarı olmayan bir webhook, örneğin MCP üzerinden webhook_secret olmadan oluşturulan bir webhook, imzasız istekleri kabul eder.

GitHub’ın kendi X-Hub-Signature-256 başlığı da kabul edilir, bu yüzden aynı gizli anahtara sahip bir GitHub webhook’u olduğu gibi çalışır. İmzada zaman damgası yoktur, dolayısıyla yakalanmış bir isteğin yeniden gönderilmesini engellemez: asıl önemli sır URL’nin kendisi olarak kalır.

Yanıtlar ve hatalar

Gönderilen bir mesaj, id’si ve onu 30 dakika boyunca güncellemek ya da silmek için bir callback_url ile döner.

json
{
  "success": true,
  "message_id": "aZZ1a2b-...",
  "callback_url": "https://mss.gs/api/v1/trigger-callback/8f14e45f-...",
  "stream_url": "https://mss.gs/api/v1/instant/6b1e...c0?token=a1b2c3d4-..."
}
Yalnızca durum koduna değil, gövdeye de bak. Reddedilen bir payload nedenini gövdede bir error kodu olarak taşır. Durum kodu ne olursa olsun, error anahtarı olan her gövdeyi başarısızlık olarak say.
http
HTTP/1.1 200 OK
Content-Type: application/json

{ "error": "ATTACHMENT_TOO_LARGE" }
javascript
const res = await fetch(webhookUrl, { method: 'POST', headers, body });
const reply = await res.json().catch(() => null);

// A rejected payload still comes back as 200: read the body.
if (!res.ok || (reply && reply.error)) {
  throw new Error(`webhook rejected: ${reply?.error ?? res.status}`);
}

Mesajda düğmeler varsa yanıtta bir stream_url de bulunur: o mesaja gelen yanıtların, tepkilerin ve düğme basışlarının canlı akışı. 10 dakika, "sse_event_extended_timeout": true gönderirsen bir saat açık kalır. Canlı güncellemeler sayfasına bak.

Durum kodları

DurumNe zaman
401Webhook’un bir gizli anahtarı var ve imza eksik ya da yanlış.
403Bu webhook o kanala mesaj gönderemez.
404Bu URL’de bir webhook yok.
413İstek çok büyük.
429Çok fazla istek. Yavaşla ve tekrar dene.
502Mesaj iletilemedi. Tekrar dene.

Hata kodları

KodAnlamı
MISSING_CONTENTGönderilecek bir şey yok: metin, kart ve dosya yok.
INVALID_MESSAGE_CONTAINERmessage_container bir nesne değil.
INVALID_MESSAGE_CONTAINER_TYPEKart türü embed_message ya da system_message değil.
MISSING_MESSAGE_CONTAINER_DESCRIPTIONBir kartın, yükleme kartı değilse, bir açıklamaya ihtiyacı vardır.
MISSING_MESSAGE_CONTAINER_LOADER_TEXTBir yükleme kartının loader_text alanına ihtiyacı vardır.
INVALID_WEBHOOK_BINDINGBu webhook o kanala mesaj gönderemez.
INVALID_SIGNATUREİmza başlığı eksik ya da yanlış.
REQUEST_BODY_TOO_LARGEİstek boyut limitinin üzerinde.
PUBLISH_FAILEDMesaj iletilemedi.
INVALID_ACTIONS_FORMAT, INVALID_ACTION_MISSING_FIELDS, DUPLICATE_ACTION_ID, INVALID_TRIGGERS_FORMAT, INVALID_TRIGGER_MISSING_ACTION, INVALID_TRIGGER_ACTION_NOT_ALLOWEDBir düğmede sorun var. Düğmeler sayfasına bak.

Dosya hataları

KodAnlamı
INVALID_ATTACHMENTS_FORMATattachments bir liste değil ya da bir öğesi nesne değil.
TOO_MANY_ATTACHMENTSBeşten fazla dosya.
MISSING_ATTACHMENT_NAMEBir dosyanın adı yok.
INVALID_ATTACHMENT_NAMEAddan geriye kullanılabilir bir şey kalmıyor, örneğin ...
MISSING_ATTACHMENT_SOURCENe url ne de content_base64 var.
AMBIGUOUS_ATTACHMENT_SOURCEHem url hem de content_base64 var.
INVALID_ATTACHMENT_BASE64base64 çözülemiyor.
ATTACHMENT_TOO_LARGEBir dosya çözüldükten sonra 8 MB’ı aşıyor.
INVALID_ATTACHMENT_URLurl bir mssgs adresi değil.

Limitler

LimitDeğer
İstek boyutuYaklaşık 10 MB
Mesaj başına dosya5 dosya, her biri en fazla 8 MB
Kart açıklamasıEn fazla 50.000 bayt. 1.000 bayt aşıldığında üyeler başlangıcı ve bir Show more düğmesi görür.
Mesajı sonradan güncellemecallback_url üzerinden 30 dakika
Düğmeli bir mesajın canlı akışı10 dakika ya da istek üzerine bir saat

İstekler hız sınırına tabidir. 429 aldığında yeniden göndermeden önce bekle ve art arda gelen uyarıları tek bir mesajda topla.

GitHub, UniFi ve App Store Connect

Bu servislerden birini bir webhook URL’sine yönlendir; mssgs onu tanır ve sen hiçbir payload yazmadan düzgün bir kart paylaşır. Entegrasyonlar sayfasına bak. Bunlara {"success": true} ile ve callback URL olmadan yanıt verilir.

KaynakNasıl tanınırNe paylaşır
GitHubx-github-event başlığıPush’lar, pull request’ler ve incelemeler, issue’lar ve yorumlar, dallar ve etiketler, sürümler. Bir issue ya da pull request’te art arda gelen değişiklikler tek bir kartta toplanır.
UniFi Protectprotect-alarm-manager user agent değeriKapı zili, hareket ve kameralarının algıladığı kişiler, araçlar ya da paketler.
App Store ConnectBildirim gövdesi ya da x-apple-signature başlığıApp Store Connect bildirimleri.

Geliştirmeye devam et