ghl_workflow_get_logs
List a workflow's step-by-step execution history, newest first, to see who entered, what each step did, and which steps failed and for which contacts.
Instructions
WORKFLOW API — limited availability: enabled for selected sub-accounts only; others get 403 WORKFLOW_API_NOT_ENABLED_FOR_LOCATION (not a token or scope problem). Suggested order: get step types -> build the definition -> validate (validate_workflow_definition, read-only) -> create (always lands in draft) -> publish via update status. Rate limits: integration daily quota + 10s burst (X-RateLimit-* headers) AND a per-sub-account budget per 10s window with reads and writes counted separately; no Retry-After is sent. Logs: default and max range 30 days; retained 60 days.
Get Workflow 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
Endpoint: GET /workflows/{workflowId}/logs (Version header: v3; source: v3/workflows-v3.json)
OAuth scopes: workflows.logs
Pagination params: limit — pass them to page through full result sets.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Records per page, 1 to 100. Default 15 | |
| types | 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 | |
| action | 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` | first |
| endDate | No | End of the range, ISO 8601. A plain date includes the whole day. At most 30 days after startDate. Defaults to now | |
| recordId | 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 | |
| statuses | 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 | |
| contactId | No | Only logs for this contact. Use the `contactId` of a record | |
| startDate | 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 | |
| locationId | Yes | Sub-account (location) ID. It must be the sub-account the token belongs to, otherwise the request is refused with 403 | |
| recordType | 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 | |
| workflowId | Yes | Workflow ID. Get it from Search Workflows. Never pass a workflow name | |
| executionId | 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 | |
| referenceId | No | `nextCursor.referenceId` from the previous response. Required with `next` | |
| referenceCreatedAt | No | `nextCursor.referenceCreatedAt` from the previous response, sent unchanged. Required with `next` |