Documentationbreadcrumb arrow Grafana Cloudbreadcrumb arrow Platformbreadcrumb arrow Workflowsbreadcrumb arrow Referencebreadcrumb arrow Blueprintsbreadcrumb arrow Broadcast key updates to Microsoft Teams
Public preview Grafana Cloud
Last reviewed: November 9, 2026

Broadcast key updates to Microsoft Teams

Note

Grafana Workflows is currently in public preview. Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available.

Keep stakeholders informed by sharing every key update on a critical or major incident in a Microsoft Teams channel.

This Grafana Workflows blueprint is in the Incidents category of the Blueprints library.

Before you begin

To use this blueprint, you need:

Steps

Steps run in order from first to last. A step inside a switch branch runs only when Workflows chooses that branch.

StepIDTypeDescription
Build the status linestatus-linetransformShows the status change when the key update changed it, otherwise the current status. No changes needed.
Post the update to Teamspost-updatemsteams.message.postPosts the key update as an Adaptive Card. Pick the Teams team and stakeholder channel.

For the inputs and outputs of each step type, refer to Step and trigger types reference.

Before you turn on the workflow, customize any steps that need input from you, such as a channel ID or a schedule name. Each step’s description says what to set.

Workflow definition

Save this definition as a YAML file to create the workflow with gcx, the Workflows API, or Terraform, or give it to a coding agent as an example. Replace FOLDER_UID with the UID of the folder for the workflow. Blueprints start disabled, so finish customizing the steps before you set enabled to true. For details, refer to Manage workflows as code.

YAML
apiVersion: workflows.ext.grafana.app/v1alpha1
kind: Definition
metadata:
  name: broadcast-key-updates-teams
  annotations:
    grafana.app/folder: <FOLDER_UID>
spec:
  name: Broadcast key updates to Microsoft Teams
  enabled: false
  startWhen:
    matchingRules:
      - eventNameRegex: 'grafana_irm_app\.incident\.updated'
        filter: "inputs.data.eventKind == 'incident_added_key_update' && inputs.data.newSeverity.matches('(?i)^(critical|major)$') && !resources.incident.event.isDrill"
    schedules: []
  steps:
    - id: status-line
      type: transform
      name: Build the status line
      description: Shows the status change when the key update changed it, otherwise the current status. No changes needed.
      inputs:
        template: "${has(inputs.data.previousStatus) ? inputs.data.previousStatus + ' → ' + inputs.data.newStatus : inputs.data.newStatus}"
    - id: post-update
      type: msteams.message.post
      name: Post the update to Teams
      description: Posts the key update as an Adaptive Card. Pick the Teams team and stakeholder channel.
      inputs:
        teamID: ''
        channelID: ''
        messageText: 'Incident update: ${resources.incident.event.title}'
        adaptiveCard: |
          {
            "type": "AdaptiveCard",
            "version": "1.4",
            "body": [
              {
                "type": "TextBlock",
                "text": ${json_stringify('Incident update: ' + resources.incident.event.title)},
                "size": "Medium",
                "weight": "Bolder",
                "wrap": true
              },
              {
                "type": "FactSet",
                "facts": [
                  {
                    "title": "Status",
                    "value": ${json_stringify(steps['status-line'].outputs.result)}
                  },
                  {
                    "title": "Severity",
                    "value": ${json_stringify(inputs.data.newSeverity)}
                  }
                ]
              },
              {
                "type": "TextBlock",
                "text": ${json_stringify(inputs.data.content)},
                "wrap": true
              }
            ],
            "actions": [
              {
                "type": "Action.OpenUrl",
                "title": "Open incident",
                "url": "${resources.incident.event.overviewURL}"
              }
            ]
          }

How it works

This section explains when the workflow runs and how its steps work together.

When it runs

This blueprint starts on the grafana_irm_app.incident.updated event.

Its trigger filter starts a run only when this CEL expression is true:

text
inputs.data.eventKind == 'incident_added_key_update' && inputs.data.newSeverity.matches('(?i)^(critical|major)$') && !resources.incident.event.isDrill

How the steps fit together

These notes cover how the steps connect and which Workflows behaviors the blueprint relies on.

  • Triggers on eventKind incident_added_key_update.
  • The event already contains the update content (Markdown), newStatus and newSeverity, and previousStatus or previousSeverity only when the update changed them, so the workflow reads them straight from inputs.data.
  • has() checks whether previousStatus is present.
  • The trigger filter limits broadcasts to Critical and Major incidents and skips drills.
  • A transform step builds the status line once, and the Adaptive Card reuses it.
  • Free text (the title, status names, severity, and update content) is inserted into the card JSON with json_stringify() so quotes and newlines stay valid JSON.
  • The incident URL is system-generated, so it goes inside a quoted string directly.
  • Customize the severity filter, the Teams team and channel, and the card layout.

Next steps