Automation Run
An automation run is a single execution of one of your automations. The API lets you list the runs you may see — optionally filtered by app, automation, workspace and status — and retrieve an individual run together with its logs.
You see the runs of automations that belong to apps in a workspace you administrate. Only the last 30 days of runs are retained, and simulation runs (the ones produced by testing an automation in the editor) are never returned.
Requires a user API key
Both endpoints require a user API key. An automation API key authenticates an automation, not a person, and
therefore carries no workspace role to check — using one here returns a 401. See
Authentication.
List automation runs
Returns a page of runs, newest first, without their logs. All body parameters are optional — an empty body lists every run you may see.
Body Parameters
| Parameter | Type | Description |
|---|---|---|
cursor | string | Cursor of the previous page. Mutually exclusive with the filters below — see Pagination. |
limit | integer | Page size. Between 1 and 500. Defaults to 50. |
app_ids | integer[] | Only runs of automations belonging to these apps. Max 100 ids. Only database apps can have automations. |
workflow_ids | integer[] | Only runs of these automations. Max 100 ids. |
workspace_ids | integer[] | Only runs of automations in these workspaces. Max 100 ids. |
status | string[] | Only runs in these statuses. One or more of pending, running, completed, failed, cancelled. |
created_at_from | string | Only runs created at or after this instant. Inclusive. See Filtering by date. |
created_at_to | string | Only runs created at or before this instant. Inclusive. See Filtering by date. |
Every id you name must be one you may see: an app, automation or workspace you do not administrate is rejected with
a 401 rather than silently dropped from the filter.
The example below requests the 2 most recent failed runs of the automations in the app with ID 42.
- cURL
- JSON
curl -X POST https://api.tapeapp.com/v1/automation-run \
-u user_key_replace_with_your_api_key: \
-H "Content-Type: application/json" \
--data '{
"app_ids": [42],
"status": ["failed"],
"limit": 2
}'
{
"app_ids": [42],
"status": ["failed"],
"limit": 2
}
{
"total": 37,
"workflow_runs": [
{
"id": 9001,
"workflow_automation_id": 88,
"workflow_automation_name": "Notify on new lead",
"workflow_automation_revision_id": 3,
"app_id": 42,
"app_name": "Leads",
"workspace_id": 7,
"status": "failed",
"created_at": "2024-01-18 08:12:04",
"completed_at": "2024-01-18 08:12:09",
"num_consumed_actions": 2,
"triggered_on_record_id": 5001,
"triggered_on_record_revision_id": 4,
"triggered_by_automation_id": null
},
{
"id": 8974,
"workflow_automation_id": 88,
"workflow_automation_name": "Notify on new lead",
"workflow_automation_revision_id": 3,
"app_id": 42,
"app_name": "Leads",
"workspace_id": 7,
"status": "failed",
"created_at": "2024-01-17 22:47:51",
"completed_at": "2024-01-17 22:47:55",
"num_consumed_actions": 1,
"triggered_on_record_id": 4987,
"triggered_on_record_revision_id": 1,
"triggered_by_automation_id": 71
}
],
"cursor": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3b3JrZmxvd1J1bklkIjo4OTc0LCJleHAiOjE2NTA2MTg3Nzh9.iY5TnLSBDGCnFXbStcrLPTmP6MATnS_JKywbvC4tx3g"
}
Response fields
| Field | Type | Description |
|---|---|---|
total | integer | Number of runs matching the filters, across all pages. See Pagination. |
workflow_runs | array | The page itself. Each entry is a run — see The run object. |
cursor | string | Cursor of the last run on this page. Pass it back to fetch the next one. null on the last page. |
The run object
Each entry in workflow_runs — and the workflow_run returned when retrieving a single run — has these fields:
| Field | Type | Description |
|---|---|---|
id | integer | ID of the run. |
workflow_automation_id | integer | The automation this run executed. |
workflow_automation_name | string | Name of the automation. |
workflow_automation_revision_id | integer | The revision of the automation this run executed. |
app_id | integer | The app the automation belongs to. |
app_name | string | Name of that app. |
workspace_id | integer | The workspace the app belongs to. |
status | string | See Statuses. |
created_at | string | When the run was created, in UTC (YYYY-MM-DD HH:mm:ss). |
completed_at | string | When the run finished, in UTC. null while the run is still pending or running. |
num_consumed_actions | integer | Number of action credits this run consumed. |
triggered_on_record_id | integer | The record this run executed on. null if the run was not triggered by a record. |
triggered_on_record_revision_id | integer | The revision of that record. null if the run was not triggered by a record. |
triggered_by_automation_id | integer | The automation that started this run, if it was called by another automation. null otherwise. |
Timestamps use the Tape API datetime format described under Date & Timezone — always
UTC, with no T separator, no Z suffix and no milliseconds.
Statuses
| Status | Description |
|---|---|
pending | The run is scheduled and has not started executing yet. |
running | The run is currently executing. |
completed | The run finished successfully. |
failed | The run finished with an error. |
cancelled | The run was cancelled before it could finish. |
Filtering by date
created_at_from and created_at_to restrict the listing to runs whose created_at falls within a window. Both
use the Tape API datetime format — YYYY-MM-DD HH:mm:ss, always UTC, no T separator and no Z suffix (see
Date & Timezone) — and both bounds are inclusive. Either may be given on its own.
curl -X POST https://api.tapeapp.com/v1/automation-run \
-u user_key_replace_with_your_api_key: \
-H "Content-Type: application/json" \
--data '{
"created_at_from": "2024-01-18 00:00:00",
"created_at_to": "2024-01-18 23:59:59"
}'
created_at_fromnever reaches past retention: a value older than the retained window is treated as the start of the window, so you can safely pass an open-ended lower bound.created_at_tohas no such bound.created_at_frommust be at or beforecreated_at_to; otherwise the request is rejected with a400.
Pagination
Results are paginated with a cursor. To fetch the next page, send the cursor from the
previous response on its own — optionally alongside limit:
curl -X POST https://api.tapeapp.com/v1/automation-run \
-u user_key_replace_with_your_api_key: \
-H "Content-Type: application/json" \
--data '{
"cursor": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
The filters that produced a page are carried inside the cursor, so you must not re-send them with it. A request
containing both a cursor and any of app_ids, workflow_ids, workspace_ids, status, created_at_from or
created_at_to is rejected with a 400 rather than one silently winning over the other.
Runs are returned newest first (descending by run ID). You have reached the end of the list when cursor is
null.
total is a snapshot
total is measured once, when you request the first page, and then held constant for the rest of the walk.
Automations keep running and old runs keep ageing out of the retention window while you paginate, so the number of
runs you actually receive may differ slightly from it.
Retention
Only runs from the last 30 days are available. Beyond that they are neither listable nor retrievable. Runs of deleted automations, and simulation runs from the automation editor, are never returned.
Retrieve an automation run
Retrieve the run with the specified workflow_run_id, including its logs. The run itself carries the same fields
as in a listing (see The run object), plus a logs array.
curl https://api.tapeapp.com/v1/automation-run/9001 \
-u user_key_replace_with_your_api_key:
{
"workflow_run": {
"id": 9001,
"workflow_automation_id": 88,
"workflow_automation_name": "Notify on new lead",
"workflow_automation_revision_id": 3,
"app_id": 42,
"app_name": "Leads",
"workspace_id": 7,
"status": "failed",
"created_at": "2024-01-18 08:12:04",
"completed_at": "2024-01-18 08:12:09",
"num_consumed_actions": 2,
"triggered_on_record_id": 5001,
"triggered_on_record_revision_id": 4,
"triggered_by_automation_id": null,
"logs": [
{
"id": "9001-trigger",
"type": "trigger",
"status": "success",
"label": "Trigger",
"messages": [],
"action_id": null,
"record_id": 5001,
"logged_at": "2024-01-18 08:12:04"
},
{
"id": "9001-filter",
"type": "filter",
"status": "success",
"label": "Filter",
"messages": [],
"action_id": null,
"record_id": 5001,
"logged_at": "2024-01-18 08:12:05"
},
{
"id": "9001-action-a1b2c3-1",
"type": "action",
"status": "success",
"label": "Send email",
"messages": [
{ "message": "Email sent to [email protected]", "level": "success" }
],
"action_id": "a1b2c3",
"record_id": 5001,
"logged_at": "2024-01-18 08:12:07"
},
{
"id": "9001-action-d4e5f6-1",
"type": "action",
"status": "failure",
"label": "Create record",
"messages": [
{ "message": "Required field \"Name\" is missing.", "level": "error" }
],
"action_id": "d4e5f6",
"record_id": null,
"logged_at": "2024-01-18 08:12:09"
}
]
}
}
The log object
A run is a sequence of steps: the trigger that started it, the filter that decided whether to proceed, and one entry per action executed. This is the same view of a run you get in the Automation Center and in its CSV export — not the raw internal event stream.
| Field | Type | Description |
|---|---|---|
id | string | Stable identifier of the step within its run — a durable handle, not a position. See below. |
type | string | trigger, filter, action, or exception. |
status | string | Outcome of the step: in_progress, success, failure, skipped or cancelled. |
label | string | Human-readable name of the step, e.g. "Trigger" or "Send email". |
messages | array | The messages the step logged. Each has a message and a level (info, warn, error, success, or null). |
action_id | string | The automation action this step executed. null for trigger, filter and exception steps. |
record_id | integer | The record this step acted on, where it acted on one. null otherwise. |
logged_at | string | When the step was logged, in UTC (YYYY-MM-DD HH:mm:ss). |
Step ids are "{run_id}-trigger" and "{run_id}-filter" for the trigger and filter. An action step also carries
the execution it belongs to — "{run_id}-action-{action_id}-{execution_id}" — because an action inside a loop runs
more than once, and each execution is its own step. An exception step is synthesized when a run failed without any
individual step recording the failure.
Log labels and messages are always English
type, status and level are stable, machine-readable values and are never translated. label and message are
prose, and this endpoint always renders them in English, regardless of the language of the user whose API key is
used.
Unavailable runs return 401, never 404
Tape IDs are globally unique, so a run ID belonging to another organization is still a perfectly well-formed ID.
To avoid turning this endpoint into a way of probing which run IDs exist, every run that is not available to you
answers the same 401 — whether it does not exist, was deleted, was a simulation, has aged out of the retention
window, or lives in a workspace you do not administrate.
Validation errors
A malformed body returns a 400 validation error. For example, sending a cursor together with a filter:
{
"status_code": 400,
"endpoint": "/v1/automation-run",
"error_code": "validation_error",
"error_message": "Body must match exactly one schema in oneOf."
}
The same applies to a limit outside 1–500, a filter array with more than 100 ids, an unknown status, a
created_at_from or created_at_to that is not a valid YYYY-MM-DD HH:mm:ss datetime, an unknown body property,
or a run ID that is not an integer.
A created_at_from later than created_at_to is likewise a 400:
{
"status_code": 400,
"endpoint": "/v1/automation-run",
"error_code": "validation_error",
"error_message": "\"created_at_from\" must be before or equal to \"created_at_to\"."
}
See Errors for the full list of error codes.
Rate limit credits
Listing automation runs costs 2x the base credits; retrieving a single run costs 1x. See
Request limits for details on how rate limiting works.