# Get Workflow Logs

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

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

List the step-by-step execution history of one workflow, newest first. Each record is one step of one run for one contact or record, with its outcome and timing. It answers who and what: who entered, what happened to a contact, which steps failed and for whom. To answer how many, use Get Workflow Log Statistics.

**Before you call it.** Get `workflowId` from Search Workflows. Never pass a workflow name. To see what each step is, call Get Workflow Definition: its `actions[].id` matches `stepId` here.

**Step details.** `meta` says how the contact entered, why a step was skipped or failed, what a step did, whether a wait timed out, and why the contact left. A key is left out when it does not apply. Only the keys documented under `meta` are returned. New keys may be added later (see Compatibility).

**Paging.** The response holds `logs`, their `count`, and `nextCursor`. The first call (`action=first`, the default) returns the newest page. For the next (older) page, send `action=next` with `referenceId` and `referenceCreatedAt` from `nextCursor`, unchanged, and keep the same filters and dates. `nextCursor` is null when there are no more records. A cursor that does not match returns 422. A page holds at most 100 records, 15 by default.

**Dates.** Send `startDate` and `endDate` together (ISO 8601, UTC, at most 30 days apart). Without them, the last 30 days are returned. Logs are available for the last 60 days.

**Common questions.**
- Who entered the workflow: `statuses=added_to_workflow`
- Which steps failed, and for whom: `statuses=error,failed,failed_retry_limit_reached`
- What happened to one contact: `contactId=<contact ID>`
- Every step of one run: `executionId=<workflowStatusId of any record from that run>`

An empty `logs` list is a real answer: nothing matched in that window. A `workflowId` that does not exist in the sub-account, or is a folder, returns 404.

**Compatibility.** New optional fields, including new `meta` keys, and new values of `status`, `type` and `recordType` can appear at any time. Ignore fields you do not know, and treat an unknown value as other.

## Authentication

Send `Authorization: Bearer <token>` using:

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

## 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. Get it from Search Workflows. Never pass a workflow name |

### Query Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `locationId` | string | Yes | Sub-account (location) ID. It must be the sub-account the token belongs to, otherwise the request is refused with 403 |
| `limit` | number | No | Records per page, 1 to 100. Default 15 |
| `action` | string | No | `first` returns the newest page, which can also start with steps that are still running. `next` returns the next (older) page, starting at the record in `nextCursor`, and requires `referenceId` and `referenceCreatedAt`. Defaults to `first` |
| `referenceId` | string | No | `nextCursor.referenceId` from the previous response. Required with `next` |
| `referenceCreatedAt` | string | No | `nextCursor.referenceCreatedAt` from the previous response, sent unchanged. Required with `next` |
| `types` | array | No | Only steps of this type: a step `type` key, as listed by Get Step Types or in `actions[].type` of Get Workflow Definition, for example `email`. One type per call on this route. `drip` also matches `drip_queued` and `drip_resume`, and `if_else` also matches `condition`. New values can appear |
| `statuses` | array | No | Only steps with these outcomes (the `status` field). Repeat the parameter or send a comma-separated list. Values: `added_to_workflow` (the contact entered the workflow), `success` (the step ran), `error` and `failed` (the step did not complete), `failed_retry_limit_reached` (the step gave up after its retries), `retry` (the step will run again), `skipped` (the step did not run, for example because of DND, a time window or missing data), `waiting` (the contact is waiting at the step), `wait_finished` (a wait ended), `finished` (the contact left the workflow, see removedReason), `paused_due_to_draft_mode` (the workflow was unpublished while the contact was in it), `contact_merged` (the contact was merged into another contact), `drip_queued` (the contact is waiting in a drip step for its batch), `drip_resume` (the batch was released and the contact moved on), `processing` (the step has started and has not finished yet), and `winner_declared` (an A/B test step picked its winning path; the record has no contact). For every kind of failure, send `error`, `failed` and `failed_retry_limit_reached`. New values can appear |
| `startDate` | string | No | Start of the range, ISO 8601: a plain date (start of that day, UTC) or a full timestamp. Send it together with endDate. Defaults to 30 days ago. Logs are available for the last 60 days, so it cannot be earlier than that |
| `endDate` | string | No | End of the range, ISO 8601. A plain date includes the whole day. At most 30 days after startDate. Defaults to now |
| `contactId` | string | No | Only logs for this contact. Use the `contactId` of a record |
| `executionId` | string | No | Only the steps of one execution: one run of the workflow for one contact or record. Use the `workflowStatusId` of any record from that run |
| `recordId` | string | No | Only logs for one record, in workflows that run on records (opportunities, custom objects and so on) instead of contacts. Use the `recordId` of a record. Send it with recordType |
| `recordType` | string | No | Object type of recordId. Use the `recordType` of the same record. Values: `contact`, `opportunity`, `task`, `business`, `inbound_webhook`, or `custom_objects.<object key>` for a custom object, for example `custom_objects.cars`. New values can appear |

## OpenAPI Specification

```json
{
  "openapi": "3.0.0",
  "info": {
    "title": "LeadConnector API",
    "version": "v3"
  },
  "servers": [
    {
      "url": "https://services.leadconnectorhq.com"
    }
  ],
  "paths": {
    "/workflows/{workflowId}/logs": {
      "get": {
        "summary": "Get Workflow Logs",
        "operationId": "getWorkflowLogs",
        "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\nList the step-by-step execution history of one workflow, newest first. Each record is one step of one run for one contact or record, with its outcome and timing. It answers who and what: who entered, what happened to a contact, which steps failed and for whom. To answer how many, use Get Workflow Log Statistics.\n\n**Before you call it.** Get `workflowId` from Search Workflows. Never pass a workflow name. To see what each step is, call Get Workflow Definition: its `actions[].id` matches `stepId` here.\n\n**Step details.** `meta` says how the contact entered, why a step was skipped or failed, what a step did, whether a wait timed out, and why the contact left. A key is left out when it does not apply. Only the keys documented under `meta` are returned. New keys may be added later (see Compatibility).\n\n**Paging.** The response holds `logs`, their `count`, and `nextCursor`. The first call (`action=first`, the default) returns the newest page. For the next (older) page, send `action=next` with `referenceId` and `referenceCreatedAt` from `nextCursor`, unchanged, and keep the same filters and dates. `nextCursor` is null when there are no more records. A cursor that does not match returns 422. A page holds at most 100 records, 15 by default.\n\n**Dates.** Send `startDate` and `endDate` together (ISO 8601, UTC, at most 30 days apart). Without them, the last 30 days are returned. Logs are available for the last 60 days.\n\n**Common questions.**\n- Who entered the workflow: `statuses=added_to_workflow`\n- Which steps failed, and for whom: `statuses=error,failed,failed_retry_limit_reached`\n- What happened to one contact: `contactId=<contact ID>`\n- Every step of one run: `executionId=<workflowStatusId of any record from that run>`\n\nAn empty `logs` list is a real answer: nothing matched in that window. A `workflowId` that does not exist in the sub-account, or is a folder, returns 404.\n\n**Compatibility.** New optional fields, including new `meta` keys, and new values of `status`, `type` and `recordType` can appear at any time. Ignore fields you do not know, and treat an unknown value as other.",
        "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. Get it from Search Workflows. Never pass a workflow name",
            "schema": {
              "example": "a7321e66-8b68-4c10-afc7-4cc9744f17af",
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Sub-account (location) ID. It must be the sub-account the token belongs to, otherwise the request is refused with 403",
            "schema": {
              "example": "ve9EPM428h8vShlRW1KT",
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Records per page, 1 to 100. Default 15",
            "schema": {
              "example": 20,
              "type": "number"
            }
          },
          {
            "name": "action",
            "required": false,
            "in": "query",
            "description": "`first` returns the newest page, which can also start with steps that are still running. `next` returns the next (older) page, starting at the record in `nextCursor`, and requires `referenceId` and `referenceCreatedAt`. Defaults to `first`",
            "schema": {
              "default": "first",
              "example": "first",
              "enum": [
                "first",
                "next"
              ],
              "type": "string"
            }
          },
          {
            "name": "referenceId",
            "required": false,
            "in": "query",
            "description": "`nextCursor.referenceId` from the previous response. Required with `next`",
            "schema": {
              "example": "0123456789abcdef01234567",
              "type": "string"
            }
          },
          {
            "name": "referenceCreatedAt",
            "required": false,
            "in": "query",
            "description": "`nextCursor.referenceCreatedAt` from the previous response, sent unchanged. Required with `next`",
            "schema": {
              "example": "2026-09-25T10:00:00.000Z",
              "type": "string"
            }
          },
          {
            "name": "types",
            "required": false,
            "in": "query",
            "description": "Only steps of this type: a step `type` key, as listed by Get Step Types or in `actions[].type` of Get Workflow Definition, for example `email`. One type per call on this route. `drip` also matches `drip_queued` and `drip_resume`, and `if_else` also matches `condition`. New values can appear",
            "schema": {
              "example": [
                "email"
              ],
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "statuses",
            "required": false,
            "in": "query",
            "description": "Only steps with these outcomes (the `status` field). Repeat the parameter or send a comma-separated list. Values: `added_to_workflow` (the contact entered the workflow), `success` (the step ran), `error` and `failed` (the step did not complete), `failed_retry_limit_reached` (the step gave up after its retries), `retry` (the step will run again), `skipped` (the step did not run, for example because of DND, a time window or missing data), `waiting` (the contact is waiting at the step), `wait_finished` (a wait ended), `finished` (the contact left the workflow, see removedReason), `paused_due_to_draft_mode` (the workflow was unpublished while the contact was in it), `contact_merged` (the contact was merged into another contact), `drip_queued` (the contact is waiting in a drip step for its batch), `drip_resume` (the batch was released and the contact moved on), `processing` (the step has started and has not finished yet), and `winner_declared` (an A/B test step picked its winning path; the record has no contact). For every kind of failure, send `error`, `failed` and `failed_retry_limit_reached`. New values can appear",
            "schema": {
              "example": [
                "error",
                "failed"
              ],
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "startDate",
            "required": false,
            "in": "query",
            "description": "Start of the range, ISO 8601: a plain date (start of that day, UTC) or a full timestamp. Send it together with endDate. Defaults to 30 days ago. Logs are available for the last 60 days, so it cannot be earlier than that",
            "schema": {
              "example": "2026-06-01",
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "required": false,
            "in": "query",
            "description": "End of the range, ISO 8601. A plain date includes the whole day. At most 30 days after startDate. Defaults to now",
            "schema": {
              "example": "2026-06-30",
              "type": "string"
            }
          },
          {
            "name": "contactId",
            "required": false,
            "in": "query",
            "description": "Only logs for this contact. Use the `contactId` of a record",
            "schema": {
              "example": "exampleContactId0001",
              "type": "string"
            }
          },
          {
            "name": "executionId",
            "required": false,
            "in": "query",
            "description": "Only the steps of one execution: one run of the workflow for one contact or record. Use the `workflowStatusId` of any record from that run",
            "schema": {
              "example": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
              "type": "string"
            }
          },
          {
            "name": "recordId",
            "required": false,
            "in": "query",
            "description": "Only logs for one record, in workflows that run on records (opportunities, custom objects and so on) instead of contacts. Use the `recordId` of a record. Send it with recordType",
            "schema": {
              "example": "exampleRecordId00001",
              "type": "string"
            }
          },
          {
            "name": "recordType",
            "required": false,
            "in": "query",
            "description": "Object type of recordId. Use the `recordType` of the same record. Values: `contact`, `opportunity`, `task`, `business`, `inbound_webhook`, or `custom_objects.<object key>` for a custom object, for example `custom_objects.cars`. New values can appear",
            "schema": {
              "example": "opportunity",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowLogsResponseDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedDTO"
                }
              }
            }
          },
          "403": {
            "description": "The token does not have access to this sub-account (locationId), or the workflow API is not enabled for it (code `WORKFLOW_API_NOT_ENABLED_FOR_LOCATION`, not a token or scope problem)",
            "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": "The request is not valid. `message` lists what to fix",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnprocessableDTO"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Every public token has a daily quota and a short burst limit. Wait for `X-RateLimit-Interval-Milliseconds`, then 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": "Milliseconds until the daily quota resets",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowRateLimitedDto"
                }
              }
            }
          },
          "504": {
            "description": "The query ran past its time limit and was stopped. Narrow it as the message says, then try again. The same request sent again usually times out again",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowLogsTimeoutDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": [
              "workflows.logs"
            ]
          }
        ]
      }
    }
  },
  "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": {
      "WorkflowLogsResponseDto": {
        "type": "object",
        "properties": {
          "count": {
            "type": "number",
            "description": "Number of records in this response",
            "example": 15
          },
          "nextCursor": {
            "description": "Where the next (older) page starts: send `action=next` with these values and the same filters and dates. Null when there are no more records",
            "nullable": true,
            "allOf": [
              {
                "type": "object",
                "properties": {
                  "referenceId": {
                    "type": "string",
                    "description": "Send as `referenceId`",
                    "example": "0123456789abcdef01234567"
                  },
                  "referenceCreatedAt": {
                    "type": "string",
                    "description": "Send as `referenceCreatedAt`, unchanged",
                    "example": "2026-09-25T10:00:00.000Z"
                  }
                },
                "required": [
                  "referenceId",
                  "referenceCreatedAt"
                ],
                "title": "WorkflowLogsNextCursorDto"
              }
            ]
          },
          "logs": {
            "description": "The records, newest first",
            "example": [
              {
                "id": "0123456789abcdef01234567",
                "locationId": "ve9EPM428h8vShlRW1KT",
                "workflowId": "a7321e66-8b68-4c10-afc7-4cc9744f17af",
                "contactId": "exampleContactId0001",
                "workflowStatusId": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
                "stepId": "123e4567-e89b-12d3-a456-426614174000",
                "stepName": "Update Custom Value",
                "type": "update_custom_value",
                "status": "success",
                "contactName": "Alex Doe",
                "contactEmail": "alex@example.com",
                "meta": {},
                "createdAt": "2026-09-25T10:00:00.000Z"
              }
            ],
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "ID of this log record",
                  "example": "0123456789abcdef01234567"
                },
                "locationId": {
                  "type": "string",
                  "description": "Sub-account (location) that owns the workflow",
                  "example": "ve9EPM428h8vShlRW1KT"
                },
                "workflowId": {
                  "type": "string",
                  "description": "Workflow that produced this record",
                  "example": "a7321e66-8b68-4c10-afc7-4cc9744f17af"
                },
                "contactId": {
                  "type": "string",
                  "description": "Contact the step ran for. Empty string when the step did not run for a contact",
                  "example": "exampleContactId0001"
                },
                "workflowStatusId": {
                  "type": "string",
                  "description": "Execution ID. Every step of one run shares it. Send it as `executionId` to read that run only",
                  "example": "01ARZ3NDEKTSV4RRFFQ69G5FAV"
                },
                "stepId": {
                  "type": "string",
                  "description": "Step ID. Matches `actions[].id` in Get Workflow Definition. Group by it in Get Workflow Log Statistics. On if/else steps where `attributes.version` is 2, it is the ID of the branch that was taken, not the if/else step's ID, and `stepName` is that branch's name. To find the branch in Get Workflow Definition, match `stepName` to the if/else step's `attributes.branches[].name`, or to `attributes.noneBranchName` when no branch matched. Can be null",
                  "nullable": true,
                  "example": "123e4567-e89b-12d3-a456-426614174000"
                },
                "stepName": {
                  "type": "string",
                  "description": "Step name as shown in the builder when the step ran. On if/else steps where `attributes.version` is 2, it is the name of the branch that was taken",
                  "example": "Update Custom Value"
                },
                "type": {
                  "type": "string",
                  "description": "Step type key, the same key Get Step Types and Get Workflow Definition use, with these exceptions: if/else steps are logged as `condition`, wait steps as `wait_time`, `wait_reply` and similar, and drip steps as `drip`, `drip_queued` or `drip_resume`. Some records are not steps, for example `added_to_workflow` when a contact enters and `remove_from_workflow` when a contact leaves. Send it in `types` to filter. New values can appear",
                  "example": "update_custom_value"
                },
                "status": {
                  "type": "string",
                  "description": "Outcome of the step: `added_to_workflow` (the contact entered the workflow), `success` (the step ran), `error` and `failed` (the step did not complete), `failed_retry_limit_reached` (the step gave up after its retries), `retry` (the step will run again), `skipped` (the step did not run, for example because of DND, a time window or missing data), `waiting` (the contact is waiting at the step), `wait_finished` (a wait ended), `finished` (the contact left the workflow, see removedReason), `paused_due_to_draft_mode` (the workflow was unpublished while the contact was in it), `contact_merged` (the contact was merged into another contact), `drip_queued` (the contact is waiting in a drip step for its batch), `drip_resume` (the batch was released and the contact moved on), `processing` (the step has started and has not finished yet), and `winner_declared` (an A/B test step picked its winning path; the record has no contact). New values can appear",
                  "example": "success"
                },
                "recordId": {
                  "type": "string",
                  "description": "Record the step ran for, in workflows that run on records. Null otherwise",
                  "nullable": true,
                  "example": "exampleRecordId00001"
                },
                "recordType": {
                  "type": "string",
                  "description": "Object type of recordId: `contact`, `opportunity`, `task`, `business`, `inbound_webhook`, or `custom_objects.<object key>` for a custom object, for example `custom_objects.cars`. New values can appear",
                  "nullable": true,
                  "example": "opportunity"
                },
                "recordPrimaryProperty": {
                  "type": "string",
                  "description": "Display name of the record",
                  "nullable": true,
                  "example": "Acme renewal"
                },
                "contactName": {
                  "type": "string",
                  "description": "Contact name when the step ran",
                  "nullable": true,
                  "example": "Alex Doe"
                },
                "contactEmail": {
                  "type": "string",
                  "description": "Contact email when the step ran",
                  "nullable": true,
                  "example": "alex@example.com"
                },
                "meta": {
                  "type": "object",
                  "description": "Step details. Which keys appear depends on the step type and outcome, and a key is left out when it does not apply. Only the keys documented here are returned. New keys may be added later",
                  "properties": {
                    "addedSource": {
                      "type": "object",
                      "description": "How the contact entered the workflow and what added it. Present when the contact entered",
                      "properties": {
                        "source": {
                          "type": "string",
                          "description": "How the contact entered the workflow, for example `trigger`, `bulk_action` or `workflow`. New values can appear",
                          "example": "trigger"
                        },
                        "sourceName": {
                          "type": "string",
                          "description": "Name of what added the contact, for example the trigger name",
                          "example": "Contact Changed"
                        },
                        "id": {
                          "type": "string",
                          "description": "ID of what added the contact. For `trigger` it is the trigger ID (`triggers[].id` in Get Workflow Definition), for `bulk_action` the bulk action ID, for `workflow` the ID of the workflow that added the contact",
                          "example": "V538VIHDL5yvZ7V38eTy"
                        }
                      }
                    },
                    "skippedFor": {
                      "type": "object",
                      "description": "Present on skipped steps. Holds why the step was skipped",
                      "properties": {
                        "msg": {
                          "type": "string",
                          "description": "Why the step was skipped",
                          "example": "Contact is already part of this workflow and can not be added again."
                        }
                      }
                    },
                    "msg": {
                      "type": "string",
                      "description": "Information about the step. On most failed steps, the error text",
                      "example": "Unable to send e-mail, contact's e-mail is invalid"
                    },
                    "data": {
                      "type": "object",
                      "description": "The step's result",
                      "properties": {
                        "msg": {
                          "type": "string",
                          "description": "What the step did. On some failed steps, such as webhooks, the error text",
                          "example": "Email queued successfully."
                        }
                      }
                    },
                    "waitMeta": {
                      "type": "object",
                      "description": "Wait steps: how the wait ended",
                      "properties": {
                        "isTimedOut": {
                          "type": "boolean",
                          "description": "True when a wait step ended because it timed out",
                          "example": true
                        }
                      }
                    },
                    "removedFrom": {
                      "type": "object",
                      "description": "Present when the contact left the workflow. Holds why it left",
                      "properties": {
                        "type": {
                          "type": "string",
                          "description": "Why the contact left the workflow, for example `end_of_workflow`, `contact_reply_stop_response` or `goal_action`. The same values as `removedReason` in Get Workflow Log Statistics. Can be empty. New values can appear",
                          "example": "end_of_workflow"
                        }
                      }
                    }
                  },
                  "example": {
                    "skippedFor": {
                      "msg": "Contact is already part of this workflow and can not be added again."
                    }
                  }
                },
                "createdAt": {
                  "type": "string",
                  "description": "When the step was logged",
                  "example": "2026-09-25T10:00:00.000Z"
                }
              },
              "required": [
                "id",
                "locationId",
                "workflowId",
                "type",
                "status",
                "meta",
                "createdAt"
              ],
              "title": "WorkflowLogRecordDto"
            }
          }
        },
        "required": [
          "count",
          "nextCursor",
          "logs"
        ],
        "title": "WorkflowLogsResponseDto"
      },
      "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"
      },
      "UnprocessableDTO": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "number",
            "example": 422
          },
          "message": {
            "example": [
              "Unprocessable Entity"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "error": {
            "type": "string",
            "example": "Unprocessable Entity"
          }
        },
        "title": "UnprocessableDTO"
      },
      "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"
      },
      "WorkflowLogsTimeoutDto": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "number",
            "description": "HTTP status code",
            "example": 504
          },
          "message": {
            "type": "string",
            "description": "Why the query was stopped, and how to narrow it",
            "example": "The query took too long and was stopped. Try a shorter date range, for example 7 days. Sending the same request again will likely time out again."
          },
          "error": {
            "type": "string",
            "description": "HTTP error name",
            "example": "Gateway Timeout"
          }
        },
        "title": "WorkflowLogsTimeoutDto"
      }
    }
  }
}
```

## Code Examples

**cURL**

```bash
curl -L -X GET 'https://services.leadconnectorhq.com/workflows/<workflowId>/logs?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>/logs?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}/logs"

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>/logs?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>/logs?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>/logs?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>/logs?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>/logs?locationId=<LOCATIONID>' -Method 'GET' -Headers $headers
$response | ConvertTo-Json
```
