Przejdź do treści głównej
Deweloperzy Webhooki

Publikuj wiadomości webhookiem

Webhook to URL, który publikuje w twojej społeczności. Wyślij na niego JSON z czegokolwiek, co potrafi wykonać żądanie HTTP, na przykład z CI, monitoringu, zadania cron albo skryptu, a wiadomość pojawi się na kanale.

Co możesz z tym zrobić

  • Publikuj tekst albo kartęZwykły tekst albo karta z tytułem, kolorem, markdownem, polami i obrazami.
  • Dołączaj plikiDo pięciu plików na wiadomość: logi, raporty, zrzuty ekranu.
  • Dodawaj przyciskiLinki albo przyciski, które zmieniają kartę lub łączą się z twoją usługą.
  • Zmieniaj ją późniejOdpowiedź zawiera callback URL do aktualizacji lub usunięcia wiadomości.

W aplikacji

$ curl -X POST "$MSSGS_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-H "X-Mssgs-Signature: sha256=$SIG" \
-d '{"message_container": {"title": "Build #1847 zakończony sukcesem", ...}}'
{"success": true, "message_id": "aZZ1a2b-..."}

Jedno żądanie z CI, jedna karta na #deploys. Nazwa u góry to nazwa nadana webhookowi.

Szybki start

  1. Utwórz webhook

    W aplikacji desktopowej otwórz w swojej społeczności Manage Server → Webhooks, utwórz webhook, wybierz kanały, na których może publikować, i skopiuj URL dla kanału. Wygląda tak:

    url
    https://mss.gs/api/v1/webhook/{webhook_guid}/{token}/{channel_guid}
  2. Wyślij wiadomość

    Podpisz JSON sekretem webhooka i wyślij go POST-em. Webhook utworzony w aplikacji desktopowej zawsze ma sekret: skopiuj go z pola Webhook Secret w ustawieniach webhooka.

    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. Odczytaj odpowiedź

    Odpowiedź zawiera id wiadomości i callback_url, którym później zmienisz wiadomość.

    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-..."
    }
Każdy, kto ma URL i sekret, może publikować na tym kanale. Nie umieszczaj ich w publicznych repozytoriach ani w kodzie po stronie klienta.

Co można wysłać

Wiadomość to albo forma skrócona (tekst z tytułem i kolorem), albo pełna karta, a każda z nich może zawierać przyciski i pliki. Nazwa u góry karty to zawsze nazwa samego webhooka. W ustawieniach webhooka decydujesz też, czy może publikować obrazy i oznaczać ludzi.

Forma skrócona

Wystarcza do większości alertów.

json
{
  "content": "Server backup completed at 03:00 UTC",
  "color": "green",
  "title": "Backup Bot"
}
PoleTypCo robi
contentstringTekst wiadomości. Wymagany, chyba że wysyłasz kartę lub pliki.
colorstringblue (domyślnie), green, orange, red, yellow lub purple.
titlestringTytuł nad tekstem. Domyślnie nazwa webhooka.

Pełna karta

Wyślij message_container, aby dostać kartę z tytułem jako linkiem, podtytułem, markdownem, polami i obrazami. Przez webhook karta przyjmuje type, color, title, title_url, sub_title, description, fields, avatar_url, image_url, image_base64, images oraz pola loadera. Pigułka statusu, odznaka, statystyki diffu i zwinięte rozumowanie są zarezerwowane dla odpowiedzi na komendy. Wszystkie pola opisuje strona karty wiadomości.

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 zakończony sukcesem

Na main przechodzi 212 z 212 testów.
Duration
2m 34s
Commit
1a2b3c4

Przyciski

Dodaj tablicę actions, aby umieścić przyciski pod wiadomością. Jak działają, opisuje strona przyciski.

Pliki

Publikuj z wiadomością prawdziwe pliki: log, raport, zrzut ekranu. Wyświetlają się jak każdy inny załącznik, jako wiersz do pobrania, a obrazy, wideo i audio bezpośrednio w wiadomości. Wiadomość z samymi plikami też jest w porządku: pomiń content i kartę.

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"
    }
  ]
}
PoleTypCo robi
namestringNazwa, pod jaką plik się pobiera. Wymagana. Ścieżka jest skracana do ostatniego członu.
content_base64stringBajty pliku w base64, surowe albo jako URI data:. mssgs przechowuje plik, a w wiadomości zostawia tylko link.
mime_typestringTyp zawartości content_base64. Domyślnie text/plain.
urlstringPlik już hostowany w mssgs: ścieżka /static/... albo URL https://mss.gs/....
Dla każdego pliku wyślij dokładnie jedno z dwóch: content_base64 albo url. Oba naraz albo żadne to błąd.
LimitWartość
Pliki na wiadomość5
Rozmiar pliku po zdekodowaniu8 MB
Nazwa pliku200 znaków
Całe żądanieOkoło 10 MB. Base64 powiększa plik o jedną trzecią, więc pojedynczy plik większy niż mniej więcej 7 MB się nie zmieści.

Dlaczego url przyjmuje tylko adresy mssgs

URL webhooka często trafia do paneli innych usług. Jeśli wycieknie, nie może pozwolić nikomu sprawić, by aplikacja każdego członka pobierała plik z wybranego przez niego serwera. Jeśli twój plik jest gdzie indziej, wyślij go jako content_base64, a mssgs będzie go hostować.

Nieudane przesłanie pliku nie blokuje wiadomości

Pliki są sprawdzane z góry, ale przesyłane później. Jeśli przesyłanie się nie powiedzie, ten plik zostaje pominięty, a reszta wiadomości i tak zostaje opublikowana, bez błędu: lepiej stracić plik niż raport. Jeśli plik jest ważny, sprawdź, czy dotarł.

Plik z wiersza poleceń

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 @-

Podpisywanie żądań

Webhook z sekretem przyjmuje tylko żądania, które dowodzą, że go znają, a webhook utworzony w aplikacji desktopowej zawsze ma sekret (Webhook Secret w jego ustawieniach). Podpisz surowe body żądania algorytmem HMAC-SHA256 z użyciem sekretu i wyślij digest hex małymi literami w nagłówku X-Mssgs-Signature jako sha256=<hex>.

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
});
Żądanie bez prawidłowego podpisu dostaje 401 i {"error": "INVALID_SIGNATURE"}. Tylko webhook bez sekretu, na przykład utworzony przez MCP bez webhook_secret, przyjmuje niepodpisane żądania.

Akceptowany jest też własny nagłówek GitHuba X-Hub-Signature-256, więc webhook GitHuba z tym samym sekretem działa bez zmian. Podpis nie zawiera znacznika czasu, więc nie chroni przed ponownym wysłaniem przechwyconego żądania: to URL pozostaje sekretem, który się liczy.

Odpowiedzi i błędy

Opublikowana wiadomość wraca z id i callback_url, którym przez 30 minut możesz ją zaktualizować lub usunąć.

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-..."
}
Sprawdzaj body, nie tylko status. Odrzucony payload podaje powód w body jako kod error. Traktuj każde body z kluczem error jako błąd, niezależnie od kodu statusu.
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}`);
}

Gdy wiadomość ma przyciski, odpowiedź zawiera też stream_url: strumień na żywo z odpowiedziami, reakcjami i naciśnięciami przycisków na tej wiadomości, otwarty przez 10 minut albo godzinę, jeśli wyślesz "sse_event_extended_timeout": true. Zobacz aktualizacje na żywo.

Kody statusu

StatusKiedy
401Webhook ma sekret, a podpisu brakuje lub jest błędny.
403Ten webhook nie może publikować na tym kanale.
404Pod tym URL nie ma webhooka.
413Żądanie jest za duże.
429Za dużo żądań. Zwolnij i spróbuj ponownie.
502Nie udało się dostarczyć wiadomości. Spróbuj ponownie.

Kody błędów

KodZnaczenie
MISSING_CONTENTNie ma czego opublikować: brak tekstu, karty i plików.
INVALID_MESSAGE_CONTAINERmessage_container nie jest obiektem.
INVALID_MESSAGE_CONTAINER_TYPETyp karty to ani embed_message, ani system_message.
MISSING_MESSAGE_CONTAINER_DESCRIPTIONKarta potrzebuje opisu, chyba że jest loaderem.
MISSING_MESSAGE_CONTAINER_LOADER_TEXTKarta loadera potrzebuje loader_text.
INVALID_WEBHOOK_BINDINGTen webhook nie może publikować na tym kanale.
INVALID_SIGNATUREBrak nagłówka podpisu lub podpis jest błędny.
REQUEST_BODY_TOO_LARGEŻądanie przekracza limit rozmiaru.
PUBLISH_FAILEDNie udało się dostarczyć wiadomości.
INVALID_ACTIONS_FORMAT, INVALID_ACTION_MISSING_FIELDS, DUPLICATE_ACTION_ID, INVALID_TRIGGERS_FORMAT, INVALID_TRIGGER_MISSING_ACTION, INVALID_TRIGGER_ACTION_NOT_ALLOWEDCoś jest nie tak z przyciskiem. Zobacz przyciski.

Błędy plików

KodZnaczenie
INVALID_ATTACHMENTS_FORMATattachments nie jest listą albo któryś wpis nie jest obiektem.
TOO_MANY_ATTACHMENTSWięcej niż pięć plików.
MISSING_ATTACHMENT_NAMEPlik nie ma nazwy.
INVALID_ATTACHMENT_NAMEZ nazwy nie zostaje nic użytecznego, na przykład przy ...
MISSING_ATTACHMENT_SOURCEAni url, ani content_base64.
AMBIGUOUS_ATTACHMENT_SOURCEJednocześnie url i content_base64.
INVALID_ATTACHMENT_BASE64Nie da się zdekodować base64.
ATTACHMENT_TOO_LARGEPlik po zdekodowaniu ma ponad 8 MB.
INVALID_ATTACHMENT_URLurl nie jest adresem mssgs.

Limity

LimitWartość
Rozmiar żądaniaOkoło 10 MB
Pliki na wiadomość5, każdy do 8 MB
Opis kartyDo 50 000 bajtów. Powyżej 1000 bajtów członkowie widzą początek i przycisk Show more.
Aktualizacja wiadomości po publikacji30 minut, przez callback_url
Strumień na żywo wiadomości z przyciskami10 minut albo godzina na życzenie

Żądania mają limit częstotliwości. Gdy dostaniesz 429, odczekaj przed ponownym wysłaniem, a alerty, które przychodzą falami, łącz w jedną wiadomość.

GitHub, UniFi i App Store Connect

Skieruj jedną z tych usług na URL webhooka, a mssgs ją rozpozna i opublikuje porządną kartę, bez pisania payloadu. Zobacz integracje. Te usługi dostają w odpowiedzi {"success": true} i żadnego callback URL.

ŹródłoRozpoznawane poCo publikuje
GitHubNagłówek x-github-eventPushe, pull requesty i recenzje, issues i komentarze, gałęzie i tagi, wydania. Wiele zmian w krótkim czasie w jednym issue lub pull requeście trafia do jednej karty.
UniFi ProtectUser agent protect-alarm-managerDzwonek do drzwi, ruch oraz osoby, pojazdy lub paczki wykryte przez twoje kamery.
App Store ConnectTreść jego powiadomień lub nagłówek x-apple-signaturePowiadomienia App Store Connect.

Buduj dalej