# Get Workflow Definition

GET https://services.leadconnectorhq.com/workflows/{workflowId}/definition

**Limited availability.** The workflow API is currently enabled for selected sub-accounts only; any other sub-account receives 403 `WORKFLOW_API_NOT_ENABLED_FOR_LOCATION`.

Read a workflow as a complete definition. The `definition` object is accepted verbatim by Update Workflow Definition, so it round-trips.

The definition's `version` is the workflow's own counter. Leave it as it comes back: sending it unchanged on update is what stops a concurrent edit in the builder from being silently overwritten.

## 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. Send `v3`. |

### Path Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `workflowId` | string | Yes | Workflow ID |

### Query Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `locationId` | string | Yes | Sub-account (location) ID the workflow belongs to |

## OpenAPI Specification

```json
{
  "openapi": "3.0.0",
  "info": {
    "title": "LeadConnector API",
    "version": "v3"
  },
  "servers": [
    {
      "url": "https://services.leadconnectorhq.com"
    }
  ],
  "paths": {
    "/workflows/{workflowId}/definition": {
      "get": {
        "summary": "Get Workflow Definition",
        "operationId": "getWorkflowDefinition",
        "description": "**Limited availability.** The workflow API is currently enabled for selected sub-accounts only; any other sub-account receives 403 `WORKFLOW_API_NOT_ENABLED_FOR_LOCATION`.\n\nRead a workflow as a complete definition. The `definition` object is accepted verbatim by Update Workflow Definition, so it round-trips.\n\nThe definition's `version` is the workflow's own counter. Leave it as it comes back: sending it unchanged on update is what stops a concurrent edit in the builder from being silently overwritten.",
        "parameters": [
          {
            "name": "Version",
            "in": "header",
            "description": "API Version. Send `v3`.",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "v3"
              ]
            }
          },
          {
            "name": "workflowId",
            "required": true,
            "in": "path",
            "description": "Workflow ID",
            "schema": {
              "example": "b1b0de82-3efb-4d63-83f6-13c50aef208c",
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Sub-account (location) ID the workflow belongs to",
            "schema": {
              "example": "ve9EPM428h8vShlRW1KT",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetWorkflowDefinitionResponseDto"
                }
              }
            }
          },
          "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 workflow API is not enabled for this sub-account (code `WORKFLOW_API_NOT_ENABLED_FOR_LOCATION`). Not a token or scope failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowApiNotEnabledDto"
                }
              }
            }
          },
          "404": {
            "description": "No such workflow in this location",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowNotFoundDto"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowDefinitionUnprocessableDto"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Two limits apply, and either can refuse a request. The integration (OAuth app or private integration) has a daily quota and a 10-second burst limit for this sub-account, reported in the `X-RateLimit-*` headers; for private integrations the daily quota is shared by every private integration token of the sub-account. The sub-account also has its own budget per 10-second window, shared by every token used for it, with reads (get step types, get definition, search) and writes (validate, create, update, change status, delete) counted separately. No header reports the sub-account budget, so a 429 while `X-RateLimit-Remaining` and `X-RateLimit-Daily-Remaining` are both above 0 means that budget is spent. `Retry-After` is not sent: if `X-RateLimit-Daily-Remaining` is 0, wait `X-RateLimit-Daily-Reset` milliseconds; otherwise wait 10 seconds, then retry.",
            "headers": {
              "X-RateLimit-Max": {
                "description": "The integration's requests per burst window for this sub-account",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "The integration's 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": "The integration's daily request quota for this sub-account",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Daily-Remaining": {
                "description": "Requests left in the daily quota",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Daily-Reset": {
                "description": "Milliseconds until the daily quota resets",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "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": {
      "GetWorkflowDefinitionResponseDto": {
        "type": "object",
        "properties": {
          "workflowId": {
            "type": "string",
            "description": "Workflow ID",
            "example": "b1b0de82-3efb-4d63-83f6-13c50aef208c"
          },
          "status": {
            "type": "string",
            "description": "Whether the workflow is live. Read-only here — change it with Update Workflow Status, which is gated by the workflows.publish scope. It sits outside `definition` because the definition is sent back verbatim to Update Workflow Definition.",
            "enum": [
              "draft",
              "published"
            ],
            "example": "draft"
          },
          "definition": {
            "type": "object",
            "description": "The definition, in the same shape Update Workflow Definition accepts.",
            "additionalProperties": true,
            "example": {
              "version": 1,
              "name": "Welcome new contacts",
              "source": {
                "system": "api"
              },
              "triggers": [],
              "actions": [],
              "edges": []
            }
          },
          "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": [
          "workflowId",
          "status",
          "definition",
          "warnings"
        ],
        "title": "GetWorkflowDefinitionResponseDto"
      },
      "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",
            "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."
          }
        },
        "title": "WorkflowApiNotEnabledDto"
      },
      "WorkflowNotFoundDto": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "number",
            "description": "HTTP status code",
            "example": 404
          },
          "message": {
            "type": "string",
            "description": "Which workflow was not found, and in which sub-account",
            "example": "Workflow b1b0de82-3efb-4d63-83f6-13c50aef208c not found in location ve9EPM428h8vShlRW1KT"
          },
          "error": {
            "type": "string",
            "description": "HTTP error name",
            "example": "Not Found"
          }
        },
        "title": "WorkflowNotFoundDto"
      },
      "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": "`Too Many Requests` when the integration's quota is spent, `Too Many Requests !` when the sub-account budget is spent. Branch on the status code, not this text.",
            "example": "Too Many Requests !"
          }
        },
        "title": "WorkflowRateLimitedDto"
      }
    }
  }
}
```

## Code Examples

**cURL**

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

**Node.js**

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

try {
  const response = await fetch('https://services.leadconnectorhq.com/workflows/<workflowId>/definition?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/{workflowId}/definition"

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

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/<workflowId>/definition?locationId=<LOCATIONID>',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer <TOKEN>',
    'Version: v3',
  ],
]);

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

**Java**

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

**Go**

```go
package main

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

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

  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/<workflowId>/definition?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"] = "v3"

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

**PowerShell**

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

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