# Get Step Types

GET https://services.leadconnectorhq.com/workflows/step-types

Browse or fetch the action and trigger schemas available to a sub-account, so a definition can be built against real field names before saving.

Every response is paged and every entry carries its full field schema, including the `assetReferences` that say which fields must hold IDs of assets that already exist. Default page size is 20.

Narrow with `types`, which matches on the step type **key** and matches partially — `email` returns `send_email` as well as `email`. Use `query` instead to match names and descriptions too. Page with `limit` and `skip`.

## Authentication

Send `Authorization: Bearer <token>` using:

- **Sub-Account token: OAuth access token or Private Integration Token.** Scopes: `workflows.readonly`

## Parameters

### Header Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `Version` | string | Yes | API Version |

### Query Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `locationId` | string | Yes | Sub-account (location) ID the workflow belongs to |
| `types` | string | No | Comma-separated step type filters (max 50 terms). Each term matches any step type whose **key** contains it, so `email` returns `send_email` as well as `email`, and an exact key still matches itself. Matching looks only at the type key — not the name or description — so a step merely described as emailing something will not appear.  A term matching nothing is reported in `notFound`. Results are paged like any other request. |
| `kind` | string | No | Restrict results to actions or triggers |
| `query` | string | No | Free-text match over type, name and description — broader than `types`, which matches the type key only. Ignored when `types` is supplied. |
| `limit` | number | No | Page size. Kept small by default because every entry carries its full field schema. |
| `skip` | number | No | Number of results to skip before the page starts |

## OpenAPI Specification

```json
{
  "openapi": "3.0.0",
  "info": {
    "title": "HighLevel API",
    "version": "v4"
  },
  "servers": [
    {
      "url": "https://services.leadconnectorhq.com"
    }
  ],
  "paths": {
    "/workflows/step-types": {
      "get": {
        "summary": "Get Step Types",
        "operationId": "getStepTypes",
        "description": "Browse or fetch the action and trigger schemas available to a sub-account, so a definition can be built against real field names before saving.\n\nEvery response is paged and every entry carries its full field schema, including the `assetReferences` that say which fields must hold IDs of assets that already exist. Default page size is 20.\n\nNarrow with `types`, which matches on the step type **key** and matches partially — `email` returns `send_email` as well as `email`. Use `query` instead to match names and descriptions too. Page with `limit` and `skip`.",
        "parameters": [
          {
            "name": "Version",
            "in": "header",
            "description": "API Version",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "v4"
              ]
            }
          },
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Sub-account (location) ID the workflow belongs to",
            "schema": {
              "example": "ve9EPM428h8vShlRW1KT",
              "type": "string"
            }
          },
          {
            "name": "types",
            "required": false,
            "in": "query",
            "description": "Comma-separated step type filters (max 50 terms). Each term matches any step type whose **key** contains it, so `email` returns `send_email` as well as `email`, and an exact key still matches itself. Matching looks only at the type key — not the name or description — so a step merely described as emailing something will not appear.\n\nA term matching nothing is reported in `notFound`. Results are paged like any other request.",
            "schema": {
              "example": "email,add_contact_tag",
              "type": "string"
            }
          },
          {
            "name": "kind",
            "required": false,
            "in": "query",
            "description": "Restrict results to actions or triggers",
            "schema": {
              "example": "action",
              "enum": [
                "action",
                "trigger"
              ],
              "type": "string"
            }
          },
          {
            "name": "query",
            "required": false,
            "in": "query",
            "description": "Free-text match over type, name and description — broader than `types`, which matches the type key only. Ignored when `types` is supplied.",
            "schema": {
              "example": "tag",
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Page size. Kept small by default because every entry carries its full field schema.",
            "schema": {
              "default": 20,
              "example": 20,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "Number of results to skip before the page starts",
            "schema": {
              "default": 0,
              "example": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StepTypesResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BadRequestDTO"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedDTO"
                }
              }
            }
          },
          "403": {
            "description": "The sub-account is not enrolled in the public workflow API. Not a scope failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowApiNotEnabledDto"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowDefinitionUnprocessableDto"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Every public token has a daily quota and a short burst limit, and this API adds a per-sub-account budget — reads and writes are counted separately, and create, update and validate all count as writes. Back off for `X-RateLimit-Interval-Milliseconds` and retry.",
            "headers": {
              "X-RateLimit-Max": {
                "description": "Requests allowed in the current burst window",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current burst window",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Interval-Milliseconds": {
                "description": "Length of the burst window",
                "schema": {
                  "type": "integer",
                  "example": 10000
                }
              },
              "X-RateLimit-Limit-Daily": {
                "description": "Daily request quota for the token",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Daily-Remaining": {
                "description": "Requests left in the daily quota",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Daily-Reset": {
                "description": "When the daily quota resets",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowRateLimitedDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": [
              "workflows.readonly"
            ]
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "name": "Authorization",
        "in": "header",
        "description": "Use the Access Token generated with user type as Sub-Account (OR) Private Integration Token of Sub-Account.",
        "type": "http"
      },
      "Location-Access": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "name": "Authorization",
        "in": "header",
        "description": "Use the Access Token generated with user type as Sub-Account (OR) Private Integration Token of Sub-Account.",
        "type": "http"
      },
      "Location-Access-Only": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "name": "Authorization",
        "in": "header",
        "description": "Use the Access Token generated with user type as Sub-Account.",
        "type": "http"
      },
      "Agency-Access": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "name": "Authorization",
        "in": "header",
        "description": "Use the Access Token generated with user type as Agency (OR) Private Integration Token of Agency.",
        "type": "http"
      },
      "Agency-Access-Only": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "name": "Authorization",
        "in": "header",
        "description": "Use the Access Token generated with user type as Agency.",
        "type": "http"
      }
    },
    "schemas": {
      "StepTypesResponseDto": {
        "type": "object",
        "properties": {
          "locationId": {
            "type": "string",
            "description": "Sub-account the catalog was scoped to",
            "example": "ve9EPM428h8vShlRW1KT"
          },
          "total": {
            "type": "number",
            "description": "Total matching step types before paging",
            "example": 1440
          },
          "count": {
            "type": "number",
            "description": "Number returned in this response",
            "example": 20
          },
          "skip": {
            "type": "number",
            "description": "The `skip` this page started at — echoed back so a caller paging through can tell which slice it received without tracking the request.",
            "example": 0
          },
          "stepTypes": {
            "description": "The step types",
            "example": [
              {
                "kind": "action",
                "type": "add_contact_tag",
                "name": "Add Contact Tag",
                "provider": "native"
              }
            ],
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "description": "Whether this is an action or a trigger",
                  "example": "action"
                },
                "type": {
                  "type": "string",
                  "description": "Type key to use in the definition",
                  "example": "add_contact_tag"
                },
                "name": {
                  "type": "string",
                  "description": "Display name",
                  "example": "Add Contact Tag"
                },
                "description": {
                  "type": "string",
                  "description": "What the step does",
                  "example": "Adds one or more tags to the contact"
                },
                "category": {
                  "type": "string",
                  "description": "Grouping shown in the builder",
                  "example": "Contact"
                },
                "provider": {
                  "type": "string",
                  "description": "Whether the step is native or from a marketplace app",
                  "example": "native"
                },
                "fields": {
                  "description": "Configurable fields. Returned in detail mode only.",
                  "example": [
                    {
                      "field": "tags",
                      "fieldType": "array",
                      "required": true
                    }
                  ],
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string",
                        "description": "Attribute name inside `attributes`",
                        "example": "tags"
                      },
                      "fieldType": {
                        "type": "string",
                        "description": "Value type",
                        "example": "array"
                      },
                      "required": {
                        "type": "boolean",
                        "description": "Whether the step will not save without it",
                        "example": true
                      },
                      "itemsType": {
                        "type": "string",
                        "description": "Element type when `fieldType` is `array`",
                        "example": "string"
                      },
                      "title": {
                        "type": "string",
                        "description": "Human label",
                        "example": "Tags"
                      },
                      "helpText": {
                        "type": "string",
                        "description": "Guidance shown next to the field",
                        "example": "Shown beneath the field in the builder"
                      },
                      "options": {
                        "description": "Allowed values, when constrained",
                        "example": [
                          {
                            "label": "Published",
                            "value": "published"
                          }
                        ],
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "assetType": {
                        "type": "string",
                        "description": "Set when this field must hold the ID of an existing asset of this type",
                        "example": "pipeline"
                      },
                      "hasDynamicOptions": {
                        "type": "boolean",
                        "description": "True when valid values must be looked up rather than hard-coded",
                        "example": true
                      }
                    },
                    "required": [
                      "field",
                      "fieldType",
                      "required"
                    ],
                    "title": "StepTypeFieldDto"
                  }
                },
                "assetReferences": {
                  "description": "Assets this step references. Returned in detail mode only.",
                  "example": [
                    {
                      "path": "tags",
                      "assetType": "TAG"
                    }
                  ],
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "path": {
                        "type": "string",
                        "description": "Where the ID lives in the definition",
                        "example": "attributes.pipeline_id"
                      },
                      "assetType": {
                        "type": "string",
                        "description": "Asset type the ID must refer to",
                        "example": "pipeline"
                      }
                    },
                    "required": [
                      "path",
                      "assetType"
                    ],
                    "title": "StepTypeAssetReferenceDto"
                  }
                },
                "triggerFilters": {
                  "type": "object",
                  "description": "Triggers only. `definitions` is the filter catalogue: one entry per configurable filter, with its `field`, `label`, `fieldType`, `required`, allowed `operators` and `valueSource`. `filtersComplete: false` means that list is partial — do not treat it as exhaustive. For marketplace triggers `feedNormalization: \"incomplete\"` means the same thing: `definitions` is a lower bound, because the app declared filters this projection could not normalize. `incompleteFields` names filters with no derivable operators, which cannot be authored.",
                  "additionalProperties": true,
                  "example": {
                    "filtersComplete": true,
                    "definitions": [
                      {
                        "field": "team_id",
                        "label": "Workspace",
                        "fieldType": "select",
                        "required": true,
                        "operators": [
                          {
                            "value": "eq",
                            "label": "is",
                            "requiresValue": true
                          }
                        ],
                        "valueSource": {
                          "kind": "dynamic"
                        }
                      }
                    ]
                  }
                }
              },
              "required": [
                "kind",
                "type",
                "name"
              ],
              "title": "StepTypeDto"
            }
          },
          "notFound": {
            "description": "`types` terms that matched no step type key",
            "example": [
              {
                "type": "made_up_type"
              }
            ],
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "description": "A `types` term that matched no step type key. Terms match partially, so this means nothing contained it — not that an exact key is missing.",
                  "example": "send_smss"
                }
              },
              "required": [
                "type"
              ],
              "title": "StepTypeNotFoundDto"
            }
          },
          "warnings": {
            "description": "Non-blocking findings",
            "example": [
              {
                "path": "actions[4]",
                "message": "Step has no incoming edges and may be unreachable."
              }
            ],
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "path": {
                  "type": "string",
                  "description": "Path within the definition",
                  "example": "actions[4]"
                },
                "message": {
                  "type": "string",
                  "description": "What to be aware of",
                  "example": "Action 'orphan-step' has no incoming edges and may be unreachable."
                },
                "type": {
                  "type": "string",
                  "description": "Step type the warning relates to",
                  "example": "sms"
                }
              },
              "title": "WorkflowDefinitionWarningDto"
            }
          }
        },
        "required": [
          "locationId",
          "total",
          "count",
          "skip",
          "stepTypes",
          "notFound",
          "warnings"
        ],
        "title": "StepTypesResponseDto"
      },
      "BadRequestDTO": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "number",
            "example": 400
          },
          "message": {
            "type": "string",
            "example": "Bad Request"
          }
        },
        "title": "BadRequestDTO"
      },
      "UnauthorizedDTO": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "number",
            "example": 401
          },
          "message": {
            "type": "string",
            "example": "Invalid token: access token is invalid"
          },
          "error": {
            "type": "string",
            "example": "Unauthorized"
          }
        },
        "title": "UnauthorizedDTO"
      },
      "WorkflowApiNotEnabledDto": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "number",
            "description": "HTTP status code",
            "example": 403
          },
          "error": {
            "type": "string",
            "description": "HTTP error name",
            "example": "Forbidden"
          },
          "code": {
            "type": "string",
            "description": "Stable code to branch on. Only ever this value for an enrolment refusal.",
            "example": "WORKFLOW_API_NOT_ENABLED_FOR_LOCATION"
          },
          "message": {
            "type": "string",
            "description": "Why the request was refused, and what to do about it",
            "example": "The workflow API is not enabled for location ve9EPM428h8vShlRW1KT. This is not a token or scope problem — the API is currently available to selected sub-accounts only, and this one is not among them. Contact HighLevel support to request access; no change to your integration or its scopes is needed."
          }
        },
        "title": "WorkflowApiNotEnabledDto"
      },
      "WorkflowDefinitionUnprocessableDto": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "number",
            "description": "HTTP status code",
            "example": 422
          },
          "message": {
            "description": "Validation errors describing why the request could not be processed",
            "example": [
              "Unprocessable Entity"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "error": {
            "type": "string",
            "description": "HTTP error name",
            "example": "Unprocessable Entity"
          },
          "errors": {
            "description": "Per-finding detail. This is what tells you which step is wrong.",
            "example": [
              {
                "code": "STEP_VALIDATION_FAILED",
                "message": "Action is missing a required field.",
                "stage": "attributes"
              }
            ],
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string",
                  "description": "Stable error code you can branch on",
                  "example": "MISSING_REQUIRED_FIELDS"
                },
                "message": {
                  "type": "string",
                  "description": "Human-readable explanation",
                  "example": "Body is required"
                },
                "path": {
                  "type": "string",
                  "description": "Path within the definition",
                  "example": "definition.actions[2].attributes.body"
                },
                "stage": {
                  "type": "string",
                  "description": "Which validation phase produced this",
                  "example": "schema"
                },
                "context": {
                  "type": "object",
                  "description": "Which step or asset the finding relates to",
                  "additionalProperties": true,
                  "example": {
                    "stepId": "9f2c1e40-…",
                    "stepName": "SMS",
                    "stepType": "sms"
                  }
                }
              },
              "title": "WorkflowDefinitionErrorDto"
            }
          }
        },
        "title": "WorkflowDefinitionUnprocessableDto"
      },
      "WorkflowRateLimitedDto": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "number",
            "description": "HTTP status code",
            "example": 429
          },
          "message": {
            "type": "string",
            "description": "Why the request was refused",
            "example": "Too Many Requests"
          }
        },
        "title": "WorkflowRateLimitedDto"
      }
    }
  }
}
```

## HighLevel SDK Examples

**Node.js** (`@gohighlevel/api-client`)

```javascript
import HighLevel from '@gohighlevel/api-client';

const ghl = new HighLevel({
  privateIntegrationToken: '<PRIVATE_INTEGRATION_TOKEN>'
});

const response = await ghl.workflows.getStepTypes({ locationId: '<LOCATIONID>' });
console.log(response);
```

**Python** (`gohighlevel-api-client`)

```python
from highlevel import HighLevel

client = HighLevel(
    private_integration_token='<PRIVATE_INTEGRATION_TOKEN>'
)

response = await client.workflows.get_step_types(locationId='<LOCATIONID>')
print(response)
```

**PHP** (`gohighlevel/api-client`)

```php
<?php
require_once 'vendor/autoload.php';

use HighLevel\HighLevel;
use HighLevel\HighLevelConfig;

$config = new HighLevelConfig([
    'privateIntegrationToken' => '<PRIVATE_INTEGRATION_TOKEN>'
]);
$ghl = new HighLevel($config);

$response = $ghl->workflows->getStepTypes(['locationId' => '<LOCATIONID>']);
echo json_encode($response, JSON_PRETTY_PRINT);
```

## Code Examples

**cURL**

```bash
curl -L -X GET 'https://services.leadconnectorhq.com/workflows/step-types?locationId=<LOCATIONID>' \
  -H 'Authorization: Bearer <TOKEN>' \
  -H 'Version: v4'
```

**Node.js**

```javascript
const options = {
  method: 'GET',
  headers: {
    Authorization: 'Bearer <TOKEN>',
    Version: 'v4'
  }
};

try {
  const response = await fetch('https://services.leadconnectorhq.com/workflows/step-types?locationId=<LOCATIONID>', options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

**Python**

```python
import requests

url = "https://services.leadconnectorhq.com/workflows/step-types"

headers = {
    "Authorization": "Bearer <TOKEN>",
    "Version": "v4"
}

params = {
    "locationId": "<LOCATIONID>"
}

response = requests.get(url, params=params, headers=headers)
print(response.json())
```

**PHP**

```php
<?php
$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => 'https://services.leadconnectorhq.com/workflows/step-types?locationId=<LOCATIONID>',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer <TOKEN>',
    'Version: v4',
  ],
]);

$response = curl_exec($curl);
curl_close($curl);
echo $response;
```

**Java**

```java
HttpResponse<String> response = Unirest
  .get("https://services.leadconnectorhq.com/workflows/step-types?locationId=<LOCATIONID>")
  .header("Authorization", "Bearer <TOKEN>")
  .header("Version", "v4")
  .asString();
```

**Go**

```go
package main

import (
  "fmt"
  "net/http"
  "io"
)

func main() {
  url := "https://services.leadconnectorhq.com/workflows/step-types?locationId=<LOCATIONID>"
  req, _ := http.NewRequest("GET", url, nil)
  req.Header.Add("Authorization", "Bearer <TOKEN>")
  req.Header.Add("Version", "v4")

  res, _ := http.DefaultClient.Do(req)
  defer res.Body.Close()
  body, _ := io.ReadAll(res.Body)
  fmt.Println(string(body))
}
```

**Ruby**

```ruby
require 'uri'
require 'net/http'

url = URI("https://services.leadconnectorhq.com/workflows/step-types?locationId=<LOCATIONID>")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = "Bearer <TOKEN>"
request["Version"] = "v4"

response = http.request(request)
puts response.read_body
```

**PowerShell**

```powershell
$headers = @{
  "Authorization" = "Bearer <TOKEN>"
  "Version" = "v4"
}

$response = Invoke-RestMethod -Uri 'https://services.leadconnectorhq.com/workflows/step-types?locationId=<LOCATIONID>' -Method 'GET' -Headers $headers
$response | ConvertTo-Json
```
