---
title: "Use the API | Grafana Cloud documentation"
description: "Create, update, delete, run, and inspect Grafana Workflows over HTTP with a service account token, including how to read step outputs from workflow runs."
---

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

# Use the API

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

Use the Grafana Workflows API to manage workflows from scripts, continuous integration (CI) jobs, and other systems. You can create and update workflows, run a workflow on demand, and read the result of every step.

The API has two parts:

- The *definitions endpoints* create, read, update, and delete workflows.
- The *run endpoints* run workflows and return their results.

For every parameter, field, and error code, refer to [Workflows API reference](/docs/grafana-cloud/platform/workflows/reference/api).

> Caution
> 
> The run endpoints might change during public preview. Build your scripts on the fields this page documents, and plan to update them before general availability.

## Before you begin

Before you call the API, make sure you have:

- A Grafana Cloud stack with the Workflows app installed.
- A service account with the Editor basic role and edit access to the folder for your workflows. For details, refer to [Manage access](/docs/grafana-cloud/platform/workflows/manage-access).
- A token for that service account. In Grafana, navigate to **Administration** &gt; **Users and access** &gt; **Service accounts** to create one. For details, refer to [Service accounts](/docs/grafana-cloud/security-and-account-management/authentication-and-permissions/service-accounts/).
- The UID of the folder for your workflows. Open the folder in Grafana and copy the UID from the URL, which has the form `/dashboards/f/<FOLDER_UID>/`.
- A Bash-compatible shell, such as the terminal on macOS or Linux, or Windows Subsystem for Linux (WSL).
- Optional: `jq`, a command-line JSON tool. Most examples use only `curl`. The examples that also use `jq` say so.

## Set up your environment

Save your stack URL and token in environment variables. The examples on this page use them, and they last until you close the terminal.

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
export GRAFANA_URL="https://<STACK_SLUG>.grafana.net"
export GRAFANA_TOKEN="<SERVICE_ACCOUNT_TOKEN>"
```

Next, find your stack’s *namespace*, which has the form `stacks-<STACK_ID>`, for example, `stacks-1234567`. Your stack ID appears on your stack’s details page in the Grafana Cloud portal. If you have `jq`, you can also look up the namespace with the following command:

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
curl -s -H "Authorization: Bearer $GRAFANA_TOKEN" \
  "$GRAFANA_URL/api/frontend/settings" | jq -r .namespace
```

Save the namespace and the base URLs for the two parts of the API:

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
export NAMESPACE="stacks-<STACK_ID>"
export DEFS="$GRAFANA_URL/apis/workflows.ext.grafana.app/v1alpha1/namespaces/$NAMESPACE/definitions"
export RUNS_API="$GRAFANA_URL/api/plugins/grafana-workflows-app/resources/api/v1"
```

## List workflows

To list every workflow the service account can access, send a `GET` request:

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
curl -s -H "Authorization: Bearer $GRAFANA_TOKEN" "$DEFS"
```

The response contains an `items` list with one definition for each workflow. The following example shows one workflow with no steps:

JSON ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```json
{
  "apiVersion": "workflows.ext.grafana.app/v1alpha1",
  "kind": "DefinitionList",
  "items": [
    {
      "apiVersion": "workflows.ext.grafana.app/v1alpha1",
      "kind": "Definition",
      "metadata": {
        "name": "incident-kickoff",
        "namespace": "stacks-1234567",
        "uid": "543a49fd-b2b8-4b91-8a68-ec2a2a5c5ea9",
        "resourceVersion": "2099486562503979008",
        "annotations": {
          "grafana.app/folder": "ffvibaiepdc74e"
        }
      },
      "spec": {
        "name": "Incident kickoff",
        "enabled": true,
        "startWhen": {
          "matchingRules": [
            {
              "eventNameRegex": "grafana_irm_app\\.incident\\.updated",
              "filter": "inputs.data.eventKind == 'incident_created'"
            }
          ],
          "schedules": []
        },
        "steps": []
      }
    }
  ]
}
```

Grafana adds `metadata.uid` and `metadata.resourceVersion` to every workflow. You need `metadata.uid` to read a workflow’s runs, and `metadata.resourceVersion` to replace a workflow.

To get one workflow, add its ID to the URL:

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
curl -s -H "Authorization: Bearer $GRAFANA_TOKEN" "$DEFS/incident-kickoff"
```

## Create a workflow

To create a workflow, follow these steps:

1. Save the following definition as `hello-workflow.json`, and replace *FOLDER\_UID* with your folder UID.
   
   The workflow has no trigger, so it runs only when you start it. Its one step builds a greeting from the `who` input.
   
   JSON ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy
   
   ```json
   {
     "apiVersion": "workflows.ext.grafana.app/v1alpha1",
     "kind": "Definition",
     "metadata": {
       "name": "hello-workflow",
       "annotations": {
         "grafana.app/folder": "<FOLDER_UID>"
       }
     },
     "spec": {
       "name": "Hello workflow",
       "enabled": true,
       "startWhen": {
         "matchingRules": [],
         "schedules": []
       },
       "steps": [
         {
           "id": "greet",
           "name": "Build greeting",
           "type": "transform",
           "inputs": {
             "template": "Hello ${has(inputs.who) ? inputs.who : 'world'}"
           }
         }
       ]
     }
   }
   ```
2. Send the file in a `POST` request:
   
   Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy
   
   ```bash
   curl -s -X POST \
     -H "Authorization: Bearer $GRAFANA_TOKEN" \
     -H "Content-Type: application/json" \
     --data @hello-workflow.json \
     "$DEFS"
   ```
   
   If the request succeeds, the response is the saved definition, including its `metadata.uid`. If the definition has a problem, the response is a `400 Bad Request` error that names each problem:
   
   JSON ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy
   
   ```json
   {
     "kind": "Status",
     "status": "Failure",
     "message": "admission webhook \"validate-workflows.workflows.svc\" denied the request: step \"greet\" is missing required field \"template\" for type \"transform\"",
     "code": 400
   }
   ```
3. Confirm the workflow exists. Open the Workflows app, go to **Manage workflows**, and find **Hello workflow**.

To add triggers, schedules, secrets, and branches to a definition, refer to [Create workflows](/docs/grafana-cloud/platform/workflows/create-workflows/#write-a-workflow-definition) and [Configure triggers](/docs/grafana-cloud/platform/workflows/configure-triggers).

### Check a definition without saving it

To have Workflows check a definition without saving it, add `?dryRun=All` to a create or update request. You can use this check in a CI job to catch mistakes before you merge a change.

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
curl -s -X POST \
  -H "Authorization: Bearer $GRAFANA_TOKEN" \
  -H "Content-Type: application/json" \
  --data @hello-workflow.json \
  "$DEFS?dryRun=All"
```

## Update a workflow

You can update a workflow in two ways:

- **Replace** the whole definition with a `PUT` request.
- **Patch** only the fields you want to change with a `PATCH` request.

### Replace a workflow

To replace a workflow, send the complete definition with the workflow’s current `metadata.resourceVersion`. Workflows uses the version to make sure you don’t overwrite a change that someone made after you read the workflow.

The following script uses `jq`. It reads the current `resourceVersion`, adds it to your file, and sends the result:

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
rv=$(curl -s -H "Authorization: Bearer $GRAFANA_TOKEN" "$DEFS/hello-workflow" \
  | jq -r .metadata.resourceVersion)

jq --arg rv "$rv" '.metadata.resourceVersion = $rv' hello-workflow.json \
  | curl -s -X PUT \
      -H "Authorization: Bearer $GRAFANA_TOKEN" \
      -H "Content-Type: application/json" \
      --data @- \
      "$DEFS/hello-workflow"
```

If someone changed the workflow after you read it, the API returns `409 Conflict`. Get the workflow again, make your change again, and retry.

### Turn a workflow on or off

To change a single field, send a *merge patch*, which contains only the fields you want to change. The following example turns off a workflow:

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
curl -s -X PATCH \
  -H "Authorization: Bearer $GRAFANA_TOKEN" \
  -H "Content-Type: application/merge-patch+json" \
  --data '{"spec": {"enabled": false}}' \
  "$DEFS/hello-workflow"
```

To turn the workflow back on, set `enabled` to `true`.

> Note
> 
> A merge patch replaces a list as a whole. To change one step, send the complete `steps` list, or replace the workflow with a `PUT` request.

## Delete a workflow

To delete a workflow, send a `DELETE` request to its URL:

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
curl -s -X DELETE \
  -H "Authorization: Bearer $GRAFANA_TOKEN" \
  "$DEFS/hello-workflow"
```

## Run a workflow

To run a saved workflow, send a `POST` request to its `run` endpoint. Use the workflow’s ID in the URL. Turn on the workflow first.

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
curl -s -X POST \
  -H "Authorization: Bearer $GRAFANA_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"inputs": {"who": "the on-call team"}}' \
  "$RUNS_API/workflows/hello-workflow/run"
```

The request returns when the run starts, before it finishes. The response identifies the run:

JSON ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```json
{
  "definition_uid": "061a6f48-a841-4ab3-bfde-9c4ad2ca3a2d",
  "definition_name": "hello-workflow",
  "instance_id": "jc7565f6rw8r",
  "execution_id": "b9d8112d-ae3f-45ea-9bce-5f7cd8435d4e",
  "status": "active",
  "triggering_event": "api",
  "created_at": "2026-09-23T18:11:19Z",
  "steps": []
}
```

Save `definition_uid`, `instance_id`, and `execution_id`. You need all three to read the run’s result.

### Pass inputs to a run

The `inputs` object in the request becomes the `inputs` object that steps read. In the preceding example, the step reads the value as `inputs.who`.

A workflow that normally starts from an event reads the event’s fields from `inputs.data`. To run one of these workflows with test data, put the fields in a `data` object:

JSON ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```json
{
  "inputs": {
    "data": {
      "incidentID": "123",
      "eventKind": "incident_created"
    }
  }
}
```

For the fields each event includes, refer to [Sample event payloads](/docs/grafana-cloud/platform/workflows/reference/event-payloads).

> Note
> 
> A run you start through the API isn’t a Grafana IRM event, so Workflows doesn’t load the incident or alert group for you. To use `resources.incident.event` in these runs, declare the incident in the definition:
> 
> YAML ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy
> 
> ```yaml
> spec:
  resources:
    incidents:
      event: "incident://id/${inputs.data.incidentID}"
> ```
> 
> When an IRM event starts the workflow, this declaration loads the same incident, so the workflow behaves the same way in both cases. For details, refer to [Declare incident resources explicitly](/docs/grafana-cloud/platform/workflows/load-incident-data/#declare-incident-resources-explicitly).

### Test a draft definition

To run a definition without saving it first, send it to the `trigger` endpoint. The editor’s **Run** button uses this endpoint. The workflow doesn’t need to exist, and the draft runs even when it’s turned off. That makes the endpoint useful for testing changes before you save them.

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
curl -s -X POST \
  -H "Authorization: Bearer $GRAFANA_TOKEN" \
  -H "Content-Type: application/json" \
  --data @trigger-request.json \
  "$RUNS_API/workflows/hello-workflow/trigger"
```

The request contains the definition and an optional event. The following example leaves out the contents of `spec`. In your request, include the complete `spec`. Don’t send `hello-workflow.json` as this body. The trigger body holds the definition in a `definition` field.

JSON ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```json
{
  "definition": {
    "apiVersion": "workflows.ext.grafana.app/v1alpha1",
    "kind": "Definition",
    "metadata": {
      "name": "hello-workflow",
      "uid": "<DEFINITION_UID>"
    },
    "spec": {}
  },
  "event_data": {
    "id": "test-1",
    "type": "grafana-workflows.manual",
    "source": "my-script",
    "data": {
      "who": "the on-call team"
    }
  }
}
```

Steps read the fields under `event_data.data` as `inputs.data.*`. In this example, `event_data.data.who` is `inputs.data.who`.

If you’re testing changes to a saved workflow, include its `metadata.uid`. Without it, the run doesn’t appear in the workflow’s run history, and you can’t get its step results. You can still find the run in the list of all runs.

## Get the result of a run

Runs finish in the background. To get a run’s result, request it with the three IDs from the run response:

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
curl -s -H "Authorization: Bearer $GRAFANA_TOKEN" \
  "$RUNS_API/runs/<DEFINITION_UID>/<INSTANCE_ID>/<EXECUTION_ID>"
```

The response contains the run’s status and one entry for each step that ran. The following example leaves out some fields and the contents of `definition_spec`, which holds the definition as it was when the run started:

JSON ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```json
{
  "definition_name": "hello-workflow",
  "status": "completed",
  "created_at": "2026-09-23T18:11:19Z",
  "completed_at": "2026-09-23T18:11:20Z",
  "steps": [
    {
      "name": "greet",
      "step_name": "Build greeting",
      "step_type": "transform",
      "status": "completed",
      "inputs": { "template": "Hello the on-call team" },
      "outputs": { "result": "Hello the on-call team" },
      "error": null
    }
  ],
  "definition_spec": {}
}
```

Each step’s `inputs` show the values after Workflows filled in expressions. Inputs that hold secrets show `[REDACTED]` instead of the value.

### Wait for a run to finish

A run’s `status` is `active` while it runs, then `completed` or `failed`. The following script uses `jq`. It starts a run, checks its status every two seconds, and prints the result when the run finishes:

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
run=$(curl -s -X POST \
  -H "Authorization: Bearer $GRAFANA_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"inputs": {"who": "the on-call team"}}' \
  "$RUNS_API/workflows/hello-workflow/run")

run_path=$(echo "$run" | jq -r '"\(.definition_uid)/\(.instance_id)/\(.execution_id)"')

while true; do
  result=$(curl -s -H "Authorization: Bearer $GRAFANA_TOKEN" "$RUNS_API/runs/$run_path")
  run_status=$(echo "$result" | jq -r .status)
  if [ "$run_status" != "active" ]; then
    break
  fi
  sleep 2
done

echo "$result" | jq '{status, error_message, steps: [.steps[] | {name, status, outputs, error}]}'
```

When a run fails, the run’s `error_message` and each step’s `error` field explain why. For common causes, refer to [Troubleshoot workflows](/docs/grafana-cloud/platform/workflows/troubleshoot).

## List runs

To list recent runs across all workflows, send a `GET` request to the runs endpoint:

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
curl -s -H "Authorization: Bearer $GRAFANA_TOKEN" "$RUNS_API/runs?count=10"
```

To list the runs of one workflow, add its `metadata.uid` to the path. The following example lists only failed runs:

Bash ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```bash
curl -s -H "Authorization: Bearer $GRAFANA_TOKEN" \
  "$RUNS_API/runs/<DEFINITION_UID>?status=failed"
```

The response lists the newest runs first:

JSON ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```json
{
  "runs": [
    {
      "definition_uid": "061a6f48-a841-4ab3-bfde-9c4ad2ca3a2d",
      "definition_name": "hello-workflow",
      "definition_display_name": "Hello workflow",
      "instance_id": "jc7565f6rw8r",
      "execution_id": "b9d8112d-ae3f-45ea-9bce-5f7cd8435d4e",
      "status": "completed",
      "triggering_event": "api",
      "created_at": "2026-09-23T18:11:19Z",
      "completed_at": "2026-09-23T18:11:20Z"
    }
  ],
  "next_cursor": "jc7565f6rw8r:b9d8112d-ae3f-45ea-9bce-5f7cd8435d4e"
}
```

When more runs exist, the response includes `next_cursor`. To get the next page, pass that value in the `after` parameter. The list doesn’t include step results. To get them, request each run as described in [Get the result of a run](#get-the-result-of-a-run).

For all the filters you can use, refer to [List runs parameters](/docs/grafana-cloud/platform/workflows/reference/api/#list-runs-parameters).

## Next steps

- [Workflows API reference](/docs/grafana-cloud/platform/workflows/reference/api)
- [Use gcx](/docs/grafana-cloud/platform/workflows/as-code/use-gcx)
- [Observe workflow runs](/docs/grafana-cloud/platform/workflows/observe-runs)
