---
title: "Announce on-call changes in Microsoft Teams | Grafana Cloud documentation"
description: "Announce on-call changes in a Microsoft Teams channel so everyone knows who to contact."
---

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

# Announce on-call changes in Microsoft Teams

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

Announce on-call changes in a Microsoft Teams channel so everyone knows who to contact.

This Grafana Workflows blueprint is in the **On-call** 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                                                                                                     |
|-----------------------------|----------------------|------------------------|-----------------------------------------------------------------------------------------------------------------|
| Only this schedule          | `only-this-schedule` | `filter`               | Stops the run unless the change happened on your schedule. Put the exact IRM schedule name between the quotes.  |
| Build the announcement card | `build-card`         | `code.execute`         | Builds an Adaptive Card that lists who is now on call and who joined or left. Edit the card layout if you like. |
| Post to Teams               | `post-card`          | `msteams.message.post` | Posts the announcement. Pick the Teams team and channel where people look for on-call contacts.                 |

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: announce-on-call-changes-teams
  annotations:
    grafana.app/folder: <FOLDER_UID>
spec:
  name: Announce on-call changes in Microsoft Teams
  enabled: false
  startWhen:
    matchingRules:
      - eventNameRegex: 'grafana_irm_app\.schedule\.updated'
    schedules: []
  steps:
    - id: only-this-schedule
      type: filter
      name: Only this schedule
      description: Stops the run unless the change happened on your schedule. Put the exact IRM schedule name between the quotes.
      inputs:
        condition: "inputs.data.schedule.name == ''"
    - id: build-card
      type: code.execute
      name: Build the announcement card
      description: Builds an Adaptive Card that lists who is now on call and who joined or left. Edit the card layout if you like.
      inputs:
        language: 'python'
        code: |
          import json

          data = context["inputs"]["data"]

          def names(users):
              return ", ".join(u.get("username") or u.get("email") or "unknown" for u in users) or "nobody"

          card = {
              "type": "AdaptiveCard",
              "version": "1.4",
              "body": [
                  {
                      "type": "TextBlock",
                      "text": f"On-call update: {data['schedule']['name']}",
                      "size": "Medium",
                      "weight": "Bolder",
                      "wrap": True,
                  },
                  {
                      "type": "FactSet",
                      "facts": [
                          {"title": "Now on call", "value": names(data.get("currentOnCall", []))},
                          {"title": "Joined", "value": names(data.get("usersAdded", []))},
                          {"title": "Left", "value": names(data.get("usersRemoved", []))},
                      ],
                  },
              ],
          }
          print(json.dumps(card))
    - id: post-card
      type: msteams.message.post
      name: Post to Teams
      description: Posts the announcement. Pick the Teams team and channel where people look for on-call contacts.
      inputs:
        teamID: ''
        channelID: ''
        messageText: 'On-call update: ${inputs.data.schedule.name}'
        adaptiveCard: "${steps['build-card'].outputs.stdout}"
```

## 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.schedule.updated` event.

### How the steps fit together

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

- Triggers on `grafana_irm_app.schedule.updated`, which fires when on-call users change.
- A filter step limits it to one schedule, because the event fires for every schedule in the stack.
- A Python `code.execute` step reads `currentOnCall`, `usersAdded`, and `usersRemoved` from context\[“inputs”]\[“data”] and builds the Adaptive Card.
- Python is used here because joining lists of names is easy in Python and awkward in CEL, which has no string join.
- The script prints the card as JSON, and stdout is passed straight to the `adaptiveCard` input of `msteams.message.post`.
- Customize the schedule name, the Teams team and channel, and the card layout.

## 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)
