Ga naar hoofdinhoud
Developer Guide

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.

Berichtstructuur
{
  "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
  }
}
Zo ziet het eruit in de chat
Message from Github Notifications acme/acme-core
alex opened pull request #144 Open
Resolve outlying hamlet to dominant nearby city
A hamlet is the smallest OSM settlement class …
18:45 +86 -38 2 files

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_requestgit-pull-requestPR geopend / open
pull_request_closedgit-pull-request-closedPR gesloten zonder merge
merge / mergedgit-mergePR gemerged
commitgit-commitGepushte commit
issuecircle-dotIssue geopend / open
issue_closedcircle-checkIssue gesloten
checkcircle-checkCI geslaagd / succes

Aanbevolen kleurmapping (GitHub)

Event status.label status.color status.icon
PR geopendOpengreenpull_request
PR draftDraftgraypull_request
PR gemergedMergedpurplemerged
PR gesloten zonder mergeClosedredpull_request_closed
Issue geopendOpengreenissue
Issue geslotenClosedpurpleissue_closed
Commit gepushtCommitgraycommit
CI geslaagdPassinggreencheck
CI gefaaldFailingredgeen

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"
Loader-kaart
{
  "message_container": {
    "type": "embed_message",
    "bot_name": "Assistant",
    "color": "blue",
    "loader": true,
    "loader_text": "Thinking…",
    "loader_sub_text": "Searching your documents"
  }
}
Zo ziet het eruit in de chat
Message from Assistant
Thinking… Searching your documents
18:45

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.

Antwoord met thinking
{
  "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…"
  }
}
Zo ziet het eruit in de chat · klik de toggle
Message from Assistant
marius: how late is the standup?
Standup is at 09:30.
Checked the channel history for the recurring invite…
18:45

Voorbeelden

Commit gepusht
{
  "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
  }
}
Zo ziet het eruit in de chat
Message from Github Notifications acme/acme-core
alex pushed to master Commit
Fix reverse-geocode city resolution for outlying hamlets
18:45 +86 -38 2 files
CI-resultaat (zonder diff-stats)
{
  "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" }
  }
}
Zo ziet het eruit in de chat
Message from CI acme/acme-core
Build passed on master Passing
18:45

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.

Basis action message
{
  "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"
}
Zo ziet het eruit in de chat
Message from mssgs
Message Title
Message description
18:45
Button Text

Verplichte velden

Veld Beschrijving
typeMoet "action_message" zijn
message_containerBerichtinhoud en stijl. Gebruik "system_message" voor de geverifieerde systeembadge
actionsArray met knopacties
channel_guidDoelkanaal-identifier
server_guidDoelserver-identifier
idUnieke bericht-identifier

Optionele velden

Veld Beschrijving
expire_in_secondsAfteltimer in seconden
cmsAanmaaktijdstip (standaard de huidige tijd)

Visuele stijl

Containerkleuren

  • orange: amber waarschuwingsstijl
  • green: succes / positieve actie
  • red: fout / destructieve actie
  • blue: informatie / neutraal
  • purple: speciaal / premium
  • yellow: 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

ws:send
{
  "action": "ws:send",
  "payload": {
    "method": "YOUR_METHOD_NAME",
    "param1": "value1",
    "param2": "value2"
  }
}

Berichtupdates

local:update_message
{
  "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

local:remove_message
{
  "action": "local:remove_message"
}

Conditionele uitvoering

Triggers kunnen conditioneel draaien op basis van het resultaat van de vorige trigger:

Conditie Gedrag
geenDraait altijd
"previous:success"Alleen als de vorige trigger slaagde
"previous:failed"Alleen als de vorige trigger faalde
"failed"Alleen als de vorige trigger faalde
Meerstapsactie met succes- en faalpad
{
  "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:

1

Plaats een loader-kaart

Stuur een embed_message met loader: true en een korte loader_text.

2

Doe het werk

Je bot verwerkt het verzoek terwijl de spinner zichtbaar is.

3

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.

1
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.

2
200 ← message_container + actions
Je reply wordt een kaart

Antwoord met JSON en de kaart verschijnt in het kanaal: titel, beschrijving, status en knoppen.

3
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.

4
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.

# deploys
jasper 18:45 /deploy
Message from Deploy Bot acme/acme-core
Deploy v2.1.0 to production? Ready
All 42 checks passed. Last commit: 1a2b3c4.
18:45
DeployCancel
Message from Deploy Bot acme/acme-core
Deploying… Step 2/3: running migrations
18:45
Message from Deploy Bot acme/acme-core
Deploy complete Live
v2.1.0 is now live on production.
18:45

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.type niet 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