---
title: "Microsoft Teams incident bridge | Grafana Cloud documentation"
description: "Open a Microsoft Teams bridge for every critical incident and announce it in your Teams incident channel with a join button."
---

> For a curated documentation index, see [llms.txt](/llms.txt). For the complete documentation index, see [llms-full.txt](/llms-full.txt).

# Microsoft Teams incident bridge

> Note
> 
> Grafana Workflows is currently in [public preview](https://grafana.com/docs/release-life-cycle/). Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available.

Open a Microsoft Teams bridge for every critical incident and announce it in your Teams incident channel with a join button.

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

## Before you begin

To use this blueprint, you need:

- Grafana IRM set up on your stack.
- The Grafana IRM Microsoft Teams integration. For details, refer to [Microsoft Teams integration for Grafana IRM](https://grafana.com/docs/grafana-cloud/alerting-and-irm/irm/integrations/chat-and-collaboration/ms-teams/).

## Steps

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

Expand table

| Step                                | ID                | Type                     | Description                                                                                                                                                                                                                                      |
|-------------------------------------|-------------------|--------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Create the bridge meeting           | `create-meeting`  | `msteams.meeting.create` | Creates a Teams meeting for the incident bridge. Set `organizerEmail` to the Microsoft Entra user who owns the meeting, for example a shared incident-bridge account. Change the duration in `endDateTime` if your incidents usually run longer. |
| Announce the bridge in Teams        | `announce-bridge` | `msteams.message.post`   | Posts an Adaptive Card with the join link. Pick the Teams team and channel where responders gather.                                                                                                                                              |
| Add the bridge link to the incident | `record-bridge`   | `incident.add-note`      | Records the join link on the incident timeline. No changes needed.                                                                                                                                                                               |

For the inputs and outputs of each step type, refer to [Step and trigger types reference](https://grafana.com/docs/grafana-cloud/platform/workflows/reference/step-trigger-types).

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](https://grafana.com/docs/grafana-cloud/platform/workflows/as-code).

YAML ![Copy code to clipboard](https://grafana.com/media/images/icons/icon-copy-small-2.svg) Copy

```yaml
apiVersion: workflows.ext.grafana.app/v1alpha1
kind: Definition
metadata:
  name: teams-incident-bridge
  annotations:
    grafana.app/folder: <FOLDER_UID>
spec:
  name: Microsoft Teams incident bridge
  enabled: false
  runOnceFor: 'teams-bridge:${inputs.data.incidentID}'
  startWhen:
    matchingRules:
      - eventNameRegex: 'grafana_irm_app\.incident\.updated'
        filter: "resources.incident.event.status == 'active' && resources.incident.event.severity.matches('(?i)^critical$')"
    schedules: []
  steps:
    - id: create-meeting
      type: msteams.meeting.create
      name: Create the bridge meeting
      description: >-
        Creates a Teams meeting for the incident bridge. Set organizerEmail to the Microsoft Entra
        user who owns the meeting, for example a shared incident-bridge account. Change the
        duration in endDateTime if your incidents usually run longer.
      inputs:
        organizerEmail: ''
        subject: 'Incident bridge: ${resources.incident.event.title}'
        startDateTime: '${now()}'
        endDateTime: "${now() + duration('2h')}"
    - id: announce-bridge
      type: msteams.message.post
      name: Announce the bridge in Teams
      description: Posts an Adaptive Card with the join link. Pick the Teams team and channel where responders gather.
      inputs:
        teamID: ''
        channelID: ''
        messageText: 'Critical incident: ${resources.incident.event.title}'
        adaptiveCard: |
          {
            "type": "AdaptiveCard",
            "version": "1.4",
            "body": [
              {
                "type": "TextBlock",
                "text": "Critical incident declared",
                "size": "Large",
                "weight": "Bolder",
                "color": "Attention"
              },
              {
                "type": "TextBlock",
                "text": ${json_stringify(resources.incident.event.title)},
                "wrap": true
              },
              {
                "type": "FactSet",
                "facts": [
                  {
                    "title": "Incident",
                    "value": "${inputs.data.incidentID}"
                  },
                  {
                    "title": "Severity",
                    "value": ${json_stringify(resources.incident.event.severity)}
                  },
                  {
                    "title": "Status",
                    "value": "${resources.incident.event.status}"
                  }
                ]
              }
            ],
            "actions": [
              {
                "type": "Action.OpenUrl",
                "title": "Join the bridge",
                "url": "${steps['create-meeting'].outputs.joinURL}"
              },
              {
                "type": "Action.OpenUrl",
                "title": "Open incident",
                "url": "${resources.incident.event.overviewURL}"
              }
            ]
          }
    - id: record-bridge
      type: incident.add-note
      name: Add the bridge link to the incident
      description: Records the join link on the incident timeline. No changes needed.
      inputs:
        incidentID: '${inputs.data.incidentID}'
        message: "Teams bridge is open: ${steps['create-meeting'].outputs.joinURL}"
```

## 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 ![Copy code to clipboard](https://grafana.com/media/images/icons/icon-copy-small-2.svg) Copy

```text
resources.incident.event.status == 'active' && resources.incident.event.severity.matches('(?i)^critical$')
```

It runs at most once for each run-once key. This blueprint’s key is `teams-bridge:${inputs.data.incidentID}`, so a later event with the same key doesn’t start another run. For details, refer to [Deduplicate workflow runs](https://grafana.com/docs/grafana-cloud/platform/workflows/build/triggers/#deduplicate-workflow-runs).

### How the steps fit together

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

- Runs once per incident when an active incident is Critical, using the same trigger filter plus `runOnceFor` pattern as Major incident kickoff.
- `msteams.meeting.create` books a meeting on the organizer’s calendar from `now()` to `now()` + 2h, which shows CEL time arithmetic; timestamps render as RFC 3339 UTC strings.
- `msteams.message.post` sends an Adaptive Card.
- The card is a JSON string.
- Free text such as the incident title and the admin-defined severity label is inserted with `json_stringify()`, which quotes and escapes it, so quotes or newlines cannot break the JSON.
- Values the system generates (the incident ID, the status, and URLs) cannot contain quotes, so they go inside a quoted string directly, for example “`${inputs.data.incidentID}`”.
- The bridge link is then recorded on the incident timeline.
- Customize the organizer email (a Microsoft Entra user the Teams app can create meetings for), the Teams team and channel, the meeting length, and the card text.

## Next steps

- [Blueprints](https://grafana.com/docs/grafana-cloud/platform/workflows/reference/blueprints)
- [Start from a blueprint](https://grafana.com/docs/grafana-cloud/platform/workflows/build/use-blueprints)
- [Manage workflows as code](https://grafana.com/docs/grafana-cloud/platform/workflows/as-code)
- [Step and trigger types reference](https://grafana.com/docs/grafana-cloud/platform/workflows/reference/step-trigger-types)
