Berichten posten met een webhook
Een webhook is een URL die in je community post. Stuur er JSON naartoe vanuit alles wat een HTTP-request kan doen, zoals CI, monitoring, een cronjob of een script, en het bericht verschijnt in het kanaal.
Wat je kunt doen
- Tekst of een kaart postenPlatte tekst, of een kaart met een titel, een kleur, markdown, velden en afbeeldingen.
- Bestanden bijvoegenTot vijf bestanden per bericht: logs, rapporten, screenshots.
- Knoppen toevoegenLinks, of knoppen die de kaart veranderen of je service aanroepen.
- Later aanpassenHet antwoord bevat een callback-URL om het bericht bij te werken of te verwijderen.
In de app
Eén request vanuit CI, één kaart in #deploys. De naam bovenaan is de naam die je de webhook hebt gegeven.
Snel aan de slag
Maak de webhook aan
Open in de desktop-app bij je community Server beheren → Webhooks, maak een webhook aan, kies de kanalen waarin hij mag posten en kopieer de URL voor een kanaal. Die ziet er zo uit:
urlhttps://mss.gs/api/v1/webhook/{webhook_guid}/{token}/{channel_guid}Stuur een bericht
Onderteken de JSON met het secret van de webhook en POST hem. Een webhook die je in de desktop-app maakt, heeft er altijd een: kopieer hem bij Webhook Secret in de instellingen van de webhook.
bashBODY='{"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"Lees het antwoord
Het antwoord geeft je het bericht-id, en een
callback_urlom het bericht later aan te passen.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-..." }
Wat je kunt sturen
Een bericht is de korte vorm (tekst met een titel en een kleur) of een volledige kaart, en allebei kunnen ze knoppen en bestanden meekrijgen. De naam bovenaan de kaart is altijd de eigen naam van de webhook. In de instellingen van de webhook bepaal je ook of hij afbeeldingen mag posten en mensen mag noemen.
Korte vorm
Genoeg voor de meeste meldingen.
{
"content": "Server backup completed at 03:00 UTC",
"color": "green",
"title": "Backup Bot"
}| Veld | Type | Wat het doet |
|---|---|---|
content | string | De berichttekst. Verplicht, tenzij je een kaart of bestanden stuurt. |
color | string | blue (standaard), green, orange, red, yellow of purple. |
title | string | Een titel boven de tekst. Standaard de naam van de webhook. |
Een volledige kaart
Stuur een message_container voor een kaart met een gelinkte titel, een subtitel, markdown, velden en afbeeldingen. Via een webhook kent een kaart type, color, title, title_url, sub_title, description, fields, avatar_url, image_url, image_base64, images en de loadervelden. De statuspill, de badge, de diff-stats en de ingeklapte redenering zijn voor antwoorden op commando's. Elk veld staat bij berichtkaarten.
{
"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" }
]
}
}Knoppen
Voeg een actions-array toe om knoppen onder het bericht te zetten. Hoe ze werken lees je bij knoppen.
Bestanden
Post echte bestanden bij een bericht: een log, een rapport, een screenshot. Ze verschijnen zoals elke andere bijlage, als downloadregel of, bij afbeeldingen, video en audio, direct in het bericht. Een bericht met alleen bestanden mag ook: laat content en de kaart weg.
{
"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"
}
]
}| Veld | Type | Wat het doet |
|---|---|---|
name | string | De bestandsnaam waaronder het wordt gedownload. Verplicht. Van een pad blijft alleen het laatste deel over. |
content_base64 | string | De bytes van het bestand als base64, kaal of als data:-URI. mssgs slaat het bestand op en bewaart alleen een link op het bericht. |
mime_type | string | Het content type van content_base64. Standaard text/plain. |
url | string | Een bestand dat al op mssgs staat: een /static/...-pad of een https://mss.gs/...-URL. |
content_base64 of url. Allebei, of geen van beide, is een fout.| Limiet | Waarde |
|---|---|
| Bestanden per bericht | 5 |
| Grootte per bestand, na decoderen | 8 MB |
| Bestandsnaam | 200 tekens |
| Het hele request | Ongeveer 10 MB. Base64 maakt een bestand een derde groter, dus één bestand van meer dan zo'n 7 MB past er niet in. |
Waarom url alleen mssgs-adressen accepteert
Een webhook-URL wordt vaak in andere dashboards geplakt. Een gelekte URL mag iemand niet de kans geven om de app van elk lid een bestand te laten ophalen van een server die hij zelf kiest. Staat je bestand ergens anders, stuur het dan als content_base64 en mssgs host het voor je.
Een mislukte upload laat het bericht niet mislukken
Bestanden worden vooraf gecontroleerd, maar pas daarna geüpload. Mislukt een upload, dan valt dat bestand weg en wordt de rest van het bericht gewoon gepost, zonder foutmelding: het bestand kwijtraken is beter dan het hele rapport kwijtraken. Is een bestand belangrijk, controleer dan of het is aangekomen.
Een bestand vanaf de commandline
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 @-Requests ondertekenen
Een webhook met een secret accepteert alleen requests die bewijzen dat ze dat secret kennen, en een webhook die je in de desktop-app maakt, heeft er altijd een (Webhook Secret in zijn instellingen). Onderteken de ruwe request body met HMAC-SHA256 en het secret, en stuur de hex-digest in kleine letters mee in de header X-Mssgs-Signature, als sha256=<hex>.
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
});401 en {"error": "INVALID_SIGNATURE"}. Alleen een webhook zonder secret, zoals een die via MCP is aangemaakt zonder webhook_secret, accepteert requests zonder handtekening.De eigen header X-Hub-Signature-256 van GitHub wordt ook geaccepteerd, dus een GitHub-webhook met hetzelfde secret werkt meteen. De handtekening bevat geen tijdstempel en houdt dus niet tegen dat een onderschept request opnieuw wordt verstuurd: de URL blijft het geheim waar het om draait.
Antwoorden en fouten
Een bericht dat is gepost, komt terug met zijn id en een callback_url om het 30 minuten lang bij te werken of te verwijderen.
{
"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-..."
}error-code in de body. Behandel elke body met een error-sleutel als een mislukking, wat de statuscode ook is.HTTP/1.1 200 OK
Content-Type: application/json
{ "error": "ATTACHMENT_TOO_LARGE" }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}`);
}Heeft het bericht knoppen, dan bevat het antwoord ook een stream_url: een live stream van de antwoorden, reacties en knopdrukken op dat bericht, 10 minuten open, of een uur als je "sse_event_extended_timeout": true meestuurt. Zie live-updates.
Statuscodes
| Status | Wanneer |
|---|---|
401 | De webhook heeft een secret en de handtekening ontbreekt of klopt niet. |
403 | Deze webhook mag niet in dat kanaal posten. |
404 | Er is geen webhook op deze URL. |
413 | Het request is te groot. |
429 | Te veel requests. Doe het rustiger aan en probeer het opnieuw. |
502 | Het bericht kon niet worden afgeleverd. Probeer het opnieuw. |
Foutcodes
| Code | Betekenis |
|---|---|
MISSING_CONTENT | Niets om te posten: geen tekst, geen kaart en geen bestanden. |
INVALID_MESSAGE_CONTAINER | message_container is geen object. |
INVALID_MESSAGE_CONTAINER_TYPE | Het kaarttype is niet embed_message of system_message. |
MISSING_MESSAGE_CONTAINER_DESCRIPTION | Een kaart heeft een beschrijving nodig, tenzij het een loader is. |
MISSING_MESSAGE_CONTAINER_LOADER_TEXT | Een loaderkaart heeft loader_text nodig. |
INVALID_WEBHOOK_BINDING | Deze webhook mag niet in dat kanaal posten. |
INVALID_SIGNATURE | De handtekening-header ontbreekt of klopt niet. |
REQUEST_BODY_TOO_LARGE | Het request is groter dan de limiet. |
PUBLISH_FAILED | Het bericht kon niet worden afgeleverd. |
INVALID_ACTIONS_FORMAT, INVALID_ACTION_MISSING_FIELDS, DUPLICATE_ACTION_ID, INVALID_TRIGGERS_FORMAT, INVALID_TRIGGER_MISSING_ACTION, INVALID_TRIGGER_ACTION_NOT_ALLOWED | Er klopt iets niet aan een knop. Zie knoppen. |
Fouten bij bestanden
| Code | Betekenis |
|---|---|
INVALID_ATTACHMENTS_FORMAT | attachments is geen lijst, of een item is geen object. |
TOO_MANY_ATTACHMENTS | Meer dan vijf bestanden. |
MISSING_ATTACHMENT_NAME | Een bestand heeft geen naam. |
INVALID_ATTACHMENT_NAME | Van de naam blijft niets bruikbaars over, zoals bij ... |
MISSING_ATTACHMENT_SOURCE | Geen url en geen content_base64. |
AMBIGUOUS_ATTACHMENT_SOURCE | Zowel url als content_base64. |
INVALID_ATTACHMENT_BASE64 | De base64 is niet te decoderen. |
ATTACHMENT_TOO_LARGE | Een bestand is na decoderen groter dan 8 MB. |
INVALID_ATTACHMENT_URL | De url is geen mssgs-adres. |
Limieten
| Limiet | Waarde |
|---|---|
| Grootte van een request | Ongeveer 10 MB |
| Bestanden per bericht | 5, van maximaal 8 MB per stuk |
| Beschrijving van een kaart | Tot 50.000 bytes. Voorbij 1.000 bytes zien leden het begin en een knop Meer tonen. |
| Het bericht achteraf bijwerken | 30 minuten, via callback_url |
| Live stream van een bericht met knoppen | 10 minuten, of een uur op verzoek |
Requests hebben een rate limit. Krijg je een 429, wacht dan voordat je opnieuw stuurt, en bundel meldingen die in golven binnenkomen tot één bericht.
GitHub, UniFi en App Store Connect
Wijs een van deze services naar een webhook-URL en mssgs herkent hem en post een nette kaart, zonder dat je zelf een payload hoeft te schrijven. Zie integraties. Deze antwoorden met {"success": true} en zonder callback-URL.
| Bron | Herkend aan | Wat het post |
|---|---|---|
| GitHub | De header x-github-event | Pushes, pull requests en reviews, issues en reacties, branches en tags, releases. Een reeks wijzigingen aan één issue of pull request wordt samengevoegd tot één kaart. |
| UniFi Protect | De user agent protect-alarm-manager | Aanbellen, beweging, en mensen, voertuigen of pakketten die je camera's zien. |
| App Store Connect | De body van de melding of de header x-apple-signature | Meldingen van App Store Connect. |