Documentationbreadcrumb arrow Grafana Cloudbreadcrumb arrow Alerts and IRMbreadcrumb arrow Workflowsbreadcrumb arrow Step and trigger types reference
Grafana Cloud
Last reviewed: May 21, 2026

Step and trigger types reference

Note

Grafana Workflows is currently in private preview. Grafana Labs offers support on a best-effort basis, and breaking changes might occur prior to the feature being made generally available.

Step types

Steps are the individual actions in a workflow. They execute in order from first to last. Each step has a type, an ID, and a set of inputs. Every step produces outputs that later steps can reference through the workflow context using CEL expressions, for example, ${steps.my-step.outputs.responseBody}.

For details on connecting steps with the workflow context, refer to Use CEL expressions.

General

HTTP call (http.call)

Make an HTTP request to any URL with any method and body. Supports bearer token and basic authentication using secrets.

Inputs:

NameTypeRequiredDescription
methodstringYesHTTP method, for example, GET, POST, PUT, DELETE.
urlstringYesThe request URL.
bodystringNoThe request body.
headersarray (string)NoRequest headers.
authMethodstringNoAuthentication method: bearer or basic.
authSecretsecretStringNoSecret for bearer token authentication. Refer to Manage secrets.
authUsernamesecretStringNoUsername for basic authentication. Refer to Manage secrets.
authPasswordsecretStringNoPassword for basic authentication. Refer to Manage secrets.

Outputs:

NameTypeDescription
responseCodeintThe HTTP response status code.
responseBodystringThe response body.
responseHeadersarray (string)The response headers.

Execute code (code.execute)

Run sandboxed code inside a workflow. The full workflow context is available as a built-in variable, and additional named arguments can be passed as a JSON object. Code runs in an isolated sandbox with no network access and a temporary filesystem.

Currently supported languages: Python.

Inputs:

NameTypeRequiredDescription
languagestringYesProgramming language to execute. Currently supported: python.
codestringYesSource code to execute in the sandbox.
argsobjectNoNamed arguments passed to the code as a JSON object. Deserialized into the appropriate type for each language (e.g. dict in Python). Values support CEL expressions.

Outputs:

NameTypeDescription
stdoutstringStandard output captured from execution.
stderrstringStandard error output captured from execution.
successboolWhether execution completed without error.
errorstringError message if execution failed.

Injected variables:

Two variables are automatically available inside the sandbox:

VariableTypeDescription
contextdictThe full workflow execution context, including trigger inputs, previous step outputs, and resolved resources. Mirrors the data available to CEL expressions. Secrets are never included.
argsdictThe evaluated JSON object from the step’s args parameter. Empty dict ({}) when args is not set.

The context variable has the following structure:

JSON
{
  "inputs": { },
  "steps": {
    "step-id": {
      "outputs": { }
    }
  },
  "resources": {
    "incident": { },
    "alertgroup": { }
  }
}
  • context["inputs"] contains the trigger event data or manual test input.
  • context["steps"] contains outputs from all previously executed steps, keyed by step ID.
  • context["resources"] contains resolved resource data (incidents, alert groups). The secret namespace is always stripped before code execution.

Example: process data from a previous step

This example shows a workflow where a code step reads the response from an earlier HTTP call, processes it, and outputs structured JSON for a downstream filter step:

YAML
steps:
  - id: fetch-status
    type: http.call
    name: "Get service status"
    inputs:
      method: "GET"
      url: "https://api.example.com/status"

  - id: analyze
    type: code.execute
    name: "Analyze status response"
    inputs:
      language: python
      code: |
        import json

        response = context["steps"]["fetch-status"]["outputs"]["responseBody"]
        data = json.loads(response)

        unhealthy = [s for s in data.get("services", []) if s["status"] != "healthy"]
        threshold = args.get("threshold", 1)

        print(json.dumps({
            "unhealthy_count": len(unhealthy),
            "unhealthy_services": [s["name"] for s in unhealthy],
            "should_alert": len(unhealthy) >= threshold,
        }))
      args:
        threshold: "${inputs.alertThreshold}"

  - id: check-alert
    type: filter
    name: "Alert if threshold exceeded"
    inputs:
      condition: "steps['analyze'].outputs.success == true"
      failOnExit: "true"

Example: simple scheduled check

YAML
steps:
  - id: run-check
    type: code.execute
    inputs:
      language: python
      code: |
        has_inputs = len(context.get("inputs", {})) > 0
        print(f"Scheduled run, has trigger inputs: {has_inputs}")

Downstream steps reference code output using CEL expressions, for example, ${steps['analyze'].outputs.stdout}.

Flow control

Transform (transform)

Evaluate a template string with embedded CEL expressions to generate dynamic content. Use ${expression} syntax to embed expressions that reference workflow inputs and previous step outputs.

Inputs:

NameTypeRequiredDescription
templatestringYesA template string with embedded ${expression} placeholders.

Outputs:

NameTypeDescription
resultstringThe rendered template string.

Filter (filter)

Gate workflow execution on a CEL condition. If the condition evaluates to false, the workflow stops and no further steps execute.

Inputs:

NameTypeRequiredDescription
conditionstringYesA CEL expression that evaluates to a boolean.
failOnExitboolNoWhen true, the workflow fails instead of exiting silently when the condition is false.

Outputs:

NameTypeDescription
matchedbooltrue if the condition matched, false otherwise.

Switch (switch)

Conditionally execute different sets of steps based on CEL expressions. Each branch has a condition and its own list of steps. The first branch whose condition evaluates to true runs. Include a default branch with no condition as a fallback.

Branches:

A switch step uses a branches array instead of inputs. Each branch has a condition (a CEL expression) and a steps list. Omit the condition to mark a branch as the default fallback.

YAML
- id: route-by-severity
  type: switch
  branches:
    - condition: "inputs.data.severity == 'critical'"
      steps:
        - id: page-oncall
          type: irm.page-team
          inputs:
            teamIdentifier: "platform"
    - steps:
        - id: post-update
          type: slack.message.post
          inputs:
            channelID: "C0123456789"
            messageText: "Non-critical incident received"

Outputs:

NameTypeDescription
matchedCasestringThe matched condition string, default for the default branch, or empty when no match.
matchedBranchIndexintThe zero-based index of the matched branch. Returns -1 when no branch matched.
errorstringAn error message if evaluation failed. Empty on success.

Wait (wait)

Pause workflow execution for a specified number of seconds.

Inputs:

NameTypeRequiredDescription
secondsintYesThe number of seconds to wait.

Outputs:

NameTypeDescription
waitedSecondsintThe number of seconds the step waited.

Incident

Incident steps operate on Grafana Incidents. You can pass incident IDs directly or reference them from incident resources loaded into the workflow context. For details on loading incident data, refer to Load incident data.

Create incident (incident.create)

Create a new Grafana Incident with a title, severity, and optional labels.

Inputs:

NameTypeRequiredDescription
titlestringYesTitle of the incident.
statusstringNoDescribe the current status of the incident.
severitystringYesSeverity of the incident. Default values are pending, critical, major, and minor. Your instance may have additional custom severities depending on your configuration.
labelsarray (object)NoLabels to attach to the incident. Each label has a key and label field.

Outputs:

NameTypeDescription
successbooltrue if the incident was created successfully.
incidentIDstringThe identifier of the created incident.
errorstringAn error message if the operation failed.

Add participant to incident (incident.add-participant)

Add a user to a Grafana Incident with a specific role.

Inputs:

NameTypeRequiredDescription
incidentIDstringYesThe incident ID.
userIDstringYesThe user ID or email address of the participant.
rolestringNoThe participant role: commander, investigator, or observer. Defaults to observer.

Outputs:

NameTypeDescription
successbooltrue if the participant was added successfully.
didChangebooltrue if the participant was newly added.
incidentIDstringThe incident ID.
errorstringAn error message if the operation failed.

Set incident field (incident.set-field)

Update a field on a Grafana Incident, including title, status, severity, or role assignments.

Inputs:

NameTypeRequiredDescription
incidentIDstringYesThe incident ID.
fieldstringYesThe field to update, for example, title, status, severity, role.
valuestringYesThe new value for the field.
userIDstringNoRequired when field is role. The user ID to assign the role to.

Outputs:

NameTypeDescription
successbooltrue if the field was updated successfully.
incidentIDstringThe incident ID.
errorstringAn error message if the operation failed.

Slack

Create Slack channel (slack.channel.create)

Create a new public or private Slack channel.

Inputs:

NameTypeRequiredDescription
channelNamestringYesThe name for the new channel.
isPrivateboolNoSet to true to create a private channel.

Outputs:

NameTypeDescription
channelIDstringThe Slack channel ID.
channelNamestringThe final channel name assigned by Slack.

Post message to Slack channel (slack.message.post)

Post a message to a Slack channel. Supports plain text, Block Kit blocks for rich formatting, attachments, and threaded replies.

Inputs:

NameTypeRequiredDescription
channelIDstringYesThe Slack channel ID to post to.
messageTextstringNoPlain text message content.
blocksstringNoA JSON string of Slack Block Kit blocks for rich formatting.
threadTsstringNoThe timestamp of a parent message to reply in a thread.
replyBroadcastboolNoSet to true to also post the reply to the channel.
attachmentsstringNoA JSON array string of Slack message attachments.

Outputs:

NameTypeDescription
messageIDstringThe posted message ID.

Archive Slack channel (slack.channel.archive)

Archive a Slack channel.

Inputs:

NameTypeRequiredDescription
channelIDstringYesThe Slack channel ID to archive.

Outputs:

NameTypeDescription
successbooltrue if the channel was archived successfully.

Add bookmark to Slack channel (slack.channel.add-bookmark)

Add a bookmark link to a Slack channel.

Inputs:

NameTypeRequiredDescription
channelIDstringYesThe Slack channel ID.
bookmarkTitlestringYesThe title for the bookmark.
bookmarkUrlstringYesThe URL for the bookmark.
bookmarkEmojistringNoAn emoji to display with the bookmark.

Outputs:

NameTypeDescription
bookmarkIDstringThe ID of the created bookmark.

Add users to Slack channel (slack.channel.add-users)

Invite users to a Slack channel by their Slack user IDs.

Inputs:

NameTypeRequiredDescription
channelIDstringYesThe Slack channel ID.
usersarray (string)YesA list of Slack user IDs to invite.

Outputs:

NameTypeDescription
successbooltrue if the users were added successfully.

IRM

Page user via IRM (irm.page-user)

Create an IRM/OnCall escalation to page a user by email address.

Inputs:

NameTypeRequiredDescription
userIDstringYesEmail address of the user to page (for example alice@example.com).
importantboolNoSet to true to mark the escalation as important. Defaults to false.
messagestringNoA message to attach to the escalation.

Outputs:

NameTypeDescription
oncallUserIDstringThe resolved OnCall user ID used in the escalation.
escalationIDstringThe created escalation ID.
statestringThe escalation state returned by IRM, for example, triggered.
alertGroupURLstringA permalink to the related IRM alert group, if returned. Otherwise empty.
errorstringAn error message if the operation failed. Empty on success.

Page team via IRM (irm.page-team)

Create an IRM/OnCall escalation to page an entire team. Optionally associates the escalation with an incident, which invites team members to join the incident, and includes urgency and message context.

Inputs:

NameTypeRequiredDescription
teamIdentifierstringYesThe team identifier value, interpreted according to identifierType.
identifierTypestringNoIdentifier mode: id (default, OnCall team ID) or name (exact team name match).
incidentIDstringNoAn incident ID to associate with the escalation. The team is invited to join the incident.
importantboolNoSet to true to mark the escalation as important. Defaults to false.
messagestringNoA message to attach to the escalation.

Outputs:

NameTypeDescription
escalationIDstringThe created escalation ID.
statestringThe escalation state returned by OnCall, for example, triggered.
alertGroupURLstringA permalink to the related IRM alert group, if returned. Otherwise empty.
errorstringAn error message if the operation failed. Empty on success.

Invite user to incident (irm.invite-user-to-incident)

Create an IRM escalation to invite a user to an incident.

Inputs:

NameTypeRequiredDescription
userIDstringYesEmail address of the user to invite (for example alice@example.com).
incidentIDstringYesID of the incident to associate with the escalation.
importantboolNoSet to true to mark the escalation as important. Defaults to false.
messagestringNoA message to attach to the escalation.

Outputs:

NameTypeDescription
oncallUserIDstringThe resolved OnCall user ID used in the escalation.
escalationIDstringThe created escalation ID.
statestringThe escalation state returned by IRM, for example, triggered.
alertGroupURLstringA permalink to the related alert group, if returned. Otherwise empty.
errorstringAn error message if the operation failed. Empty on success.

Invite user to alert group (irm.invite-user-to-alert-group)

Create an IRM escalation to invite a user to an alert group.

Inputs:

NameTypeRequiredDescription
userIDstringYesEmail address of the user to invite (for example alice@example.com).
alertGroupIDstringYesID of the alert group to associate with the escalation.
importantboolNoSet to true to mark the escalation as important. Defaults to false.

Outputs:

NameTypeDescription
oncallUserIDstringThe resolved OnCall user ID used in the escalation.
escalationIDstringThe created escalation ID.
statestringThe escalation state returned by IRM, for example, triggered.
alertGroupURLstringA permalink to the related alert group, if returned. Otherwise empty.
errorstringAn error message if the operation failed. Empty on success.

Get on-call users for a schedule (irm.schedule-current-oncall)

Look up the users currently on-call for an OnCall schedule. Use this step to drive subsequent paging or notification steps with the right responder.

Inputs:

NameTypeRequiredDescription
scheduleIdentifierstringYesThe schedule identifier value, interpreted according to identifierType.
identifierTypestringNoIdentifier mode: id (default, OnCall schedule ID) or name (exact name match).

Outputs:

NameTypeDescription
scheduleIDstringThe resolved OnCall schedule ID used for the lookup.
countintThe number of on-call users returned. 0 when no one is on-call.
usersarrayThe list of on-call user objects, including id, email, username, slack, and more.
shiftsarrayThe list of current shift entries, including shift_start, shift_end, and users.
errorstringAn error message if the operation failed. Empty on success.

Get on-call users for a team (irm.team-current-oncall)

Look up the users currently on-call for a team by resolving the team’s direct paging integration. Use this step when you want to notify whoever is on-call for a team without specifying a schedule.

Inputs:

NameTypeRequiredDescription
teamIdentifierstringYesThe team identifier value, interpreted according to identifierType.
identifierTypestringNoIdentifier mode: id (default, OnCall team ID) or name (exact name match).
routestringNoAn optional route ID for the team’s direct paging integration. If omitted, the default route is used.

Outputs:

NameTypeDescription
teamIDstringThe resolved OnCall team ID used for the lookup.
countintThe number of on-call users returned. 0 when no one is on-call.
usersarrayThe list of on-call user objects, including id, email, username, slack, and more.
shiftsarrayThe list of current shift entries, including shift_start, shift_end, and users.
errorstringAn error message if the operation failed. Empty on success.

Microsoft Teams

Steps that post messages to or create resources in Microsoft Teams.

Prerequisites:

Before using any Microsoft Teams step, install the Microsoft Teams app through Grafana IRM integrations and set up at least one hook for it. This creates the link between your Grafana stack and your Microsoft Teams tenant, which the workflow engine uses to look up your Azure tenant ID at runtime. You can disable or remove the hook once it’s set up. It only needs to exist long enough for the initial link to be created.

The msteams.meeting.create step needs the Calendars.ReadWrite application permission on the app registration used by your Microsoft Teams integration, with admin consent granted. New installs of the Microsoft Teams app already request and consent this permission automatically, so this step is only needed if the app was installed before msteams.meeting.create support was added. In that case, add the permission in the app registration’s API permissions page and grant admin consent for it. No additional Teams-specific admin setup is required.

Create Teams meeting (msteams.meeting.create)

Create a Microsoft Teams online meeting on behalf of an organizer, by creating an event with an online meeting attached on the organizer’s Outlook calendar. Requires the Calendars.ReadWrite Azure AD application permission. Refer to the Prerequisites above.

This adds an event to the organizer’s Outlook calendar, but the event is created with free/busy status set to free, so it doesn’t mark the organizer as busy or conflict with other meetings on their calendar.

To compute startDateTime or endDateTime relative to another timestamp, use CEL’s built-in timestamp() and duration() functions, for example ${timestamp(inputs.eventTime) + duration('1h')}. Refer to Use CEL expressions.

Inputs:

NameTypeRequiredDescription
organizerEmailstringYesEmail address of the meeting organizer, matched against either their mail or userPrincipalName attribute in Microsoft Entra. The meeting is created on their behalf.
subjectstringYesMeeting subject.
startDateTimestringYesMeeting start time, RFC 3339 format, for example 2026-06-11T10:00:00Z. Any timezone offset is accepted and converted to UTC before the meeting is created.
endDateTimestringNoMeeting end time, RFC 3339 format, converted to UTC the same way as startDateTime. Must be after startDateTime. Defaults to one hour after startDateTime if not set.

Outputs:

NameTypeDescription
meetingIDstringCalendar event ID for the created meeting.
joinURLstringJoin link to share with meeting participants.

Post message to Teams channel (msteams.message.post)

Post a text message or Adaptive Card to a Microsoft Teams channel. At least one of messageText or adaptiveCard is required. To reply in a thread, pass conversationID and threadActivityID from a previous Post Message step.

Inputs:

NameTypeRequiredDescription
teamIDstringYesMicrosoft Teams team ID. Use the team picker or a CEL expression.
channelIDstringYesMicrosoft Teams channel ID. Available channels are fetched from the team. Use the channel picker or a CEL expression.
messageTextstringNoPlain text message body. Required unless adaptiveCard is provided. When both are set, text is sent with the Adaptive Card.
adaptiveCardstringNoJSON string of an Adaptive Card object (the card body). Required unless messageText is provided.
conversationIDstringNoConversation ID from a prior Post Message step, for example ${steps.<id>.outputs.conversationID}. Required with threadActivityID.
threadActivityIDstringNoActivity ID of the parent message to reply to, for example ${steps.<id>.outputs.activityID}. Required with conversationID.

Outputs:

NameTypeDescription
conversationIDstringConversation ID for this message. Pass as conversationID on a later Post Message step to reply in the same thread.
activityIDstringActivity ID of the posted message. Pass as threadActivityID on a later Post Message step to reply to this message.

Trigger types

Triggers define when a workflow starts. You configure triggers in the startWhen section of a workflow definition. For details on configuring triggers, refer to Configure triggers.

Event trigger

An event trigger starts a workflow when an incoming event matches a regular expression pattern. Events arrive on NATS subjects following the format {app}.{instance-id}.{resource-type}.{event-type}. The engine strips the {instance-id} segment before matching, so your patterns are tested against {app}.{resource-type}.{event-type}.

You define event triggers using matching rules. Each rule contains a regex pattern that the engine tests against the stripped event name. If any rule matches, the workflow starts.

Configuration:

FieldTypeRequiredDescription
eventNameRegexstringYesA regular expression tested against the event name. The workflow starts if the pattern matches.

Example:

YAML
startWhen:
  matchingRules:
    - eventNameRegex: "grafana_irm_app\\.incident\\.updated"
    - eventNameRegex: "grafana_irm_app\\.alertgroup\\.updated"

A workflow can have multiple matching rules. The workflow triggers if any rule matches.

Available event sources

The following table lists the event sources that can trigger workflows:

AppResourceEventExample event nameDescription
grafana_irm_appincidentupdatedgrafana_irm_app.incident.updatedFires any time an incident is updated.
grafana_irm_appalertgroupupdatedgrafana_irm_app.alertgroup.updatedFires any time an alert group is updated.
grafana_irm_appscheduleupdatedgrafana_irm_app.schedule.updatedFires when the current on-call users change.

Event names follow the pattern {app}.{resource-type}.{event-type}.

Schedule trigger

A schedule trigger starts a workflow at recurring times using a cron expression. Schedules use the standard five-field Unix cron format and run in UTC.

Configuration:

FieldTypeRequiredDescription
(schedule)stringYesA five-field Unix cron expression in UTC, for example, 0 9 * * 1-5.

Example:

YAML
startWhen:
  schedules:
    - "0 9 * * 1-5"
    - "0 0 1 * *"

A workflow can have multiple schedules. Each schedule triggers the workflow independently.

Cron field reference:

FieldRangeSpecial characters
Minute0-59*, ,, -, /
Hour0-23*, ,, -, /
Day of month1-31*, ,, -, /
Month1-12*, ,, -, /
Day of week0-7 (0 and 7 are Sunday)*, ,, -, /

Manual trigger

A manual trigger starts a workflow from the editor on demand. Any workflow can be triggered manually regardless of whether it has event or schedule triggers configured.

To trigger a workflow manually in the editor, click Run and provide a CloudEvents-shaped JSON event in the Trigger Workflow dialog. For details, refer to Configure triggers.

Manual-only workflows have an empty startWhen section:

YAML
startWhen:
  matchingRules: []
  schedules: []

Combine triggers

A workflow can have both event and schedule triggers. The workflow starts when any matching rule matches an incoming event or when any schedule fires.

YAML
startWhen:
  matchingRules:
    - eventNameRegex: "grafana_irm_app\\.incident\\.updated"
  schedules:
    - "0 9 * * 1-5"