Botberichten
Rijke embed-kaarten, interactieve knoppen en live-bijgewerkte berichten voor bots
Overzicht
Bots plaatsen rijke berichten door een action_message te sturen. Het veld message_container.type bepaalt hoe de client het rendert:
embed_message: een rijke kaart met gekleurd accent, bot-header, klikbare titel, markdown-body, statusbadge, diff-stats, loader en inklapbare redenering. Gemaakt voor GitHub-notificaties, CI-resultaten, deploys en AI-assistenten.system_message: een geverifieerde systeemkaart met interactieve knoppen die triggerketens uitvoeren.
Waar past dit?
Je verstuurt deze payloads via dezelfde webhook- en trigger-integraties uit de API-documentatie. Deze gids beschrijft de volledige message containers: wat er in een kaart kan en hoe knoppen zich gedragen.
Embed-berichten
Een embed rendert met een gekleurd linkeraccent, een header "Message from {bot} · {badge}", een klikbare titel, een subtitel en een markdown-beschrijving.
{
"type": "action_message",
"channel_guid": "...",
"server_guid": "...",
"message_container": {
"type": "embed_message",
"bot_name": "Github Notifications",
"avatar_url": "https://avatars.githubusercontent.com/u/310687?v=4",
"badge": "acme/acme-core",
"color": "purple",
"title": "alex opened pull request #144",
"title_url": "https://github.com/acme/acme-core/pull/144",
"sub_title": "Resolve outlying hamlet to dominant nearby city",
"description": "A hamlet is the smallest OSM settlement class ...",
"status": { "label": "Open", "color": "green", "icon": "pull_request" },
"additions": 86,
"deletions": 38,
"files_changed": 2
}
}
Containervelden
| Veld | Type | Beschrijving |
|---|---|---|
type |
string | Moet "embed_message" zijn |
bot_name |
string | Getoond in de header: "Message from {bot_name}" |
badge |
string | Tweede header-chip na de botnaam (bijv. acme/acme-core) |
avatar_url |
string | Bot-/bron-avatar, over het systeemicoon. Volledige URL, of een pad dat de statische host als prefix krijgt |
color |
string | Linkeraccentkleur: blue (standaard), green, purple, red, orange, yellow |
title |
string | Vetgedrukte titelregel |
title_url |
string | Indien gezet wordt de titel een link die deze URL opent |
sub_title |
string | Tweede vetgedrukte regel onder de titel |
description |
string | Bodytekst. Ondersteunt markdown: vet, inline code, fenced codeblokken, quotes en checkboxes |
fields |
array | [{ "field": "...", "value": "..." }]: label/waarde-rijen met kopieerknop |
image_url / image_base64 |
string | Optionele afbeelding, rechts uitgelijnd |
Lange beschrijvingen
De server kan een lange description afkappen. In dat geval bevat het bericht message_big_embed_guid en toont de client een Show more-knop die de volledige body ophaalt.
Statusbadge & diff-stats
Allemaal optioneel. De status-badge rendert naast de titel; de diff-stats staan in de footer, rechts van de tijd. Elke combinatie kan; laat je alles weg, dan ziet de embed er precies uit als voorheen. Zonder title valt de statusbadge terug in de footergroep.
| Veld | Type | Beschrijving |
|---|---|---|
status |
object | string | Gekleurde statuspil. Een kale string wordt behandeld als { "label": <string> } |
status.label |
string | Piltekst, bijv. "Open", "Merged", "Passing". Vereist om de pil te renderen |
status.color |
string | green, purple, red, orange, yellow, blue, gray (standaard gray, of valt terug op de containerkleur) |
status.icon |
string | Optioneel icoon uit de vaste set hieronder. Onbekend/afwezig → geen icoon |
additions |
number | Toegevoegde regels → groen +86 |
deletions |
number | Verwijderde regels → rood -38 |
files_changed |
number | Gewijzigde bestanden → chip 2 files (1 file bij 1) |
status.icon-waarden
| Waarde | Icoon | Typisch gebruik |
|---|---|---|
pull_request | git-pull-request | PR geopend / open |
pull_request_closed | git-pull-request-closed | PR gesloten zonder merge |
merge / merged | git-merge | PR gemerged |
commit | git-commit | Gepushte commit |
issue | circle-dot | Issue geopend / open |
issue_closed | circle-check | Issue gesloten |
check | circle-check | CI geslaagd / succes |
Aanbevolen kleurmapping (GitHub)
| Event | status.label |
status.color |
status.icon |
|---|---|---|---|
| PR geopend | Open | green | pull_request |
| PR draft | Draft | gray | pull_request |
| PR gemerged | Merged | purple | merged |
| PR gesloten zonder merge | Closed | red | pull_request_closed |
| Issue geopend | Open | green | issue |
| Issue gesloten | Closed | purple | issue_closed |
| Commit gepusht | Commit | gray | commit |
| CI geslaagd | Passing | green | check |
| CI gefaald | Failing | red | geen |
Loader-status
Wanneer loader op true staat, toont de kaart een spinner met optionele teksten: een placeholder in "AI denkt na…"-stijl terwijl de bot nog werkt. title en description mogen in deze staat volledig weggelaten worden (ze renderen nog wel als ze aanwezig zijn).
| Veld | Type | Beschrijving |
|---|---|---|
loader |
boolean | true rendert het spinnerblok in plaats van de beschrijving |
loader_text |
string | Primaire regel naast de spinner, bijv. "Thinking…" |
loader_sub_text |
string | Kleinere, gedimde tweede regel, bijv. "Searching your documents" |
{
"message_container": {
"type": "embed_message",
"bot_name": "Assistant",
"color": "blue",
"loader": true,
"loader_text": "Thinking…",
"loader_sub_text": "Searching your documents"
}
}
De bot wist de loader door een UPDATE_MESSAGE te sturen met een vervangen message_container zonder loader en mét de definitieve inhoud; de client rendert de kaart op zijn plek opnieuw.
Thinking (inklapbare redenering)
Wanneer thinking een niet-lege string is, verschijnt onder de beschrijving een ingeklapte Show thinking-rij. Klikken klapt hem client-side uit. Zelfde markdown-ondersteuning als description. Typisch gebruik: de bot plaatst een loader-kaart en bewerkt die daarna tot het definitieve antwoord, met de redenering van het model achter de toggle.
{
"message_container": {
"type": "embed_message",
"bot_name": "Assistant",
"color": "blue",
"sub_title": "marius: how late is the standup?",
"description": "Standup is at **09:30**.",
"thinking": "Checked the channel history for the recurring invite…"
}
}
Voorbeelden
{
"message_container": {
"type": "embed_message",
"bot_name": "Github Notifications",
"badge": "acme/acme-core",
"color": "gray",
"title": "alex pushed to master",
"title_url": "https://github.com/acme/acme-core/commit/1a2b3c4",
"sub_title": "Fix reverse-geocode city resolution for outlying hamlets",
"status": { "label": "Commit", "color": "gray", "icon": "commit" },
"additions": 86,
"deletions": 38,
"files_changed": 2
}
}
{
"message_container": {
"type": "embed_message",
"bot_name": "CI",
"badge": "acme/acme-core",
"color": "green",
"title": "Build passed on master",
"status": { "label": "Passing", "color": "green", "icon": "check" }
}
}
Interactieve action messages
Action messages bevatten klikbare knoppen die meerdere acties na elkaar uitvoeren. Ze verschijnen met een systeemverificatiebadge en ondersteunen conditionele uitvoering op basis van eerdere actieresultaten.
{
"type": "action_message",
"message_container": {
"type": "system_message",
"color": "orange",
"title": "Message Title",
"description": "Message description"
},
"actions": [
{
"type": "button",
"color": "green",
"text": "Button Text",
"triggers": [
{
"action": "ws:send",
"payload": {
"method": "SOME_METHOD",
"data": "value"
}
}
]
}
],
"expire_in_seconds": 300,
"id": "unique-message-id"
}
Verplichte velden
| Veld | Beschrijving |
|---|---|
type | Moet "action_message" zijn |
message_container | Berichtinhoud en stijl. Gebruik "system_message" voor de geverifieerde systeembadge |
actions | Array met knopacties |
channel_guid | Doelkanaal-identifier |
server_guid | Doelserver-identifier |
id | Unieke bericht-identifier |
Optionele velden
| Veld | Beschrijving |
|---|---|
expire_in_seconds | Afteltimer in seconden |
cms | Aanmaaktijdstip (standaard de huidige tijd) |
Visuele stijl
Containerkleuren
orange: amber waarschuwingsstijlgreen: succes / positieve actiered: fout / destructieve actieblue: informatie / neutraalpurple: speciaal / premiumyellow: opgelet / aandacht
Knopkleuren
- Primair (
green,blue,purple): prominente actieknoppen - Secundair (
red,orange,yellow): secundaire of destructieve acties
Triggersysteem
Knoppen voeren meerdere acties na elkaar uit via de triggers-array. Elke trigger draait op volgorde, met conditionele uitvoering op basis van het succes of falen van de vorige trigger.
WebSocket-acties
{
"action": "ws:send",
"payload": {
"method": "YOUR_METHOD_NAME",
"param1": "value1",
"param2": "value2"
}
}
Berichtupdates
{
"action": "local:update_message",
"message_container": {
"color": "green",
"title": "Updated Title",
"description": "Updated description"
},
"actions": []
}
Beveiliging
Het bericht-type kan niet gewijzigd worden door een update. Dat voorkomt imitatie: een botkaart kan zichzelf nooit veranderen in een ander soort bericht.
Knoppen beheren bij een update:
- Stuur
"actions": []mee om alle knoppen te verwijderen na afronding - Stuur
"actions": [...]mee om knoppen te vervangen door nieuwe - Laat het
actions-veld weg om bestaande knoppen te behouden
Bericht verwijderen
{
"action": "local:remove_message"
}
Conditionele uitvoering
Triggers kunnen conditioneel draaien op basis van het resultaat van de vorige trigger:
| Conditie | Gedrag |
|---|---|
| geen | Draait altijd |
"previous:success" | Alleen als de vorige trigger slaagde |
"previous:failed" | Alleen als de vorige trigger faalde |
"failed" | Alleen als de vorige trigger faalde |
{
"type": "button",
"text": "Process Request",
"color": "green",
"triggers": [
{
"action": "ws:send",
"payload": {
"method": "PROCESS_DATA",
"request_id": "12345"
}
},
{
"condition": "previous:success",
"action": "local:update_message",
"message_container": {
"color": "green",
"title": "Processing Complete",
"description": "Your request was processed successfully"
}
},
{
"condition": "previous:failed",
"action": "local:update_message",
"message_container": {
"color": "red",
"title": "Processing Failed",
"description": "There was an error processing your request"
}
}
]
}
Verlooptimers
Berichten kunnen een afteltimer bevatten via expire_in_seconds. De client formatteert de resterende tijd automatisch:
- Onder 60 seconden: "45 seconds"
- Onder 60 minuten: "5 minutes 30 seconds"
- Boven 60 minuten: "1 hour 15 minutes"
- Verlopen: "This message has expired"; met verlopen berichten kan niet meer worden geklikt
Live updates
Beide berichttypes worden op hun plek bijgewerkt. Het gebruikelijke patroon voor AI-achtige bots:
Plaats een loader-kaart
Stuur een embed_message met loader: true en een korte loader_text.
Doe het werk
Je bot verwerkt het verzoek terwijl de spinner zichtbaar is.
Vervang de container
Stuur UPDATE_MESSAGE met de definitieve message_container: laat loader weg, voeg het antwoord toe en stop de redenering desgewenst achter thinking.
Zie het gebeuren
De hele loop op één plek: een commando vuurt je webhook af, je reply wordt een kaart, een knop-tik komt bij jou terug en je callback-update landt op zijn plek.
mssgs → POST jouw-webhook
Een commando vuurt je webhook af
Iemand typt /deploy. mssgs POST het bericht naar je endpoint, inclusief een callback_url voor dit bericht.
200 ← message_container + actions
Je reply wordt een kaart
Antwoord met JSON en de kaart verschijnt in het kanaal: titel, beschrijving, status en knoppen.
mssgs → POST jouw-webhook · [Action Triggered]
Een knop-tik komt bij jou terug
De tik vuurt de trigger opnieuw naar je server, met een verse callback_url.
PUT {callback_url} → 200
Je werkt de kaart op zijn plek bij
Eerst een loader terwijl jij het werk doet, daarna de eindstatus. Iedereen in het kanaal ziet de update live.
1a2b3c4.Best practices
Duidelijke knoptekst
Geef knoppen een beschrijvende text om verwarring te voorkomen.
Vang fouten af
Neem faalcondities op in triggerketens voor betere UX.
Redelijke timeouts
Gebruik passende expire_in_seconds-waarden voor tijdgevoelige acties.
Visuele hiërarchie
Gebruik kleuren consistent: groen voor positief, rood voor negatief.
Knoppenbeheer
Verwijder knoppen met "actions": [] na afronding, of vervang ze zodat ze passen bij elke workflowstaat.
Fouten & limieten
Foutafhandeling
- Gefaalde triggers stoppen de keten, tenzij een faalconditie matcht
- WebSocket-fouten worden gelogd en behandeld als falen
- Mislukte berichtupdates worden gelogd en behandeld als falen
- Triggers met faalcondities (
previous:failed,failed) draaien juist bij fouten
Limieten
- Aanbevolen maximum aantal triggers per knop: 10
- Berichtupdates kunnen het veld
message_container.typeniet wijzigen - WebSocket-payloadlimieten gelden ook voor trigger-payloads
- Met verlopen berichten kan niet meer worden geklikt
Vragen?
We helpen je graag met je bot.
developers@mss.gs