Run & simulate
Internal beta — not released yet
The Automation API is an internal beta and is not released yet. Its endpoints and payloads are not final and may change or be withdrawn at any time without notice.
Run an automation against a payload (real side effects), simulate it (a dry run with none), and validate a definition without executing it. All require a user API key and workspace-admin access.
The run body is trigger-aware
Manual run and simulate share one body. You send the payload the automation's trigger expects — the automation (named in the path) already fixes the trigger, so there's no discriminator to restate:
| Trigger | Body |
|---|---|
record-based (record_created, record_updated, record_deleted, date_field_arrived, comment, automation_called, weblink_clicked) | { "record_id": <id> } |
webhook_received | { "webhook_payload": <object or string> } or { "use_last_received_webhook_payload": true } |
periodic / no trigger | {} |
A well-formed body that doesn't match the automation's actual trigger is rejected with a 400.
Manual-run and simulate ignore paused
Both execute the automation's stored definition regardless of its paused flag — activation is not a
precondition. Only a broken definition is refused (409). This is deliberately different from the
call-automation endpoint, which silently produces no run for a paused
target. So manual-run is the way to test-fire an automation without taking it live; pausing does not protect against it.
Asynchronous — no run ID is returned
Both answer 202 with a fixed message and no run ID (the run row is minted only after filtering, in the worker).
To observe the result, poll the Automation Run API — its per-automation listing
includes both real and simulation runs — and match on the record. Both endpoints cost 1x base credits; a real run
additionally consumes automation action credits, reported as num_consumed_actions on the run.
Reading run logs — they arrive after the run turns terminal
A run's per-action logs are buffered and land asynchronously after the run flips to a terminal status
(completed / failed), a beat behind the always-present trigger and filter steps. Poll for the specific log entry
you need rather than gating on logs.length > 0, which can return before an action's entry is in. And not every
successful step yields a per-action success log: control-flow containers (conditional, for_loop),
collected_records_collect_referenced_records, and create_pdf complete at the run level with no per-action entry —
for those, treat a terminal completed without a setup failure as the success signal.
Run an automation
Executes the automation with real side effects, at-least-once. The trigger filter is applied — a record that does not match produces no run.
curl -X POST https://api.tapeapp.com/v1/automation/4021/manual-run \
-u user_key_replace_with_your_api_key: \
-H "Content-Type: application/json" \
--data '{ "record_id": 5001 }'
{ "message": "Use the automation-run API to poll the run. Based on queueing and limitations, this may be delayed." }
Errors: 404 (automation or record unavailable), 409 (the automation is broken), 401, 400 (bad ID or a body
that doesn't match the trigger). record_id must resolve to a live record in the automation's app — a
soft-deleted, foreign-app or non-existent id all 404 before the run is scheduled. (This is why
current_record_restore can only be exercised by deleting the record within the run, via an upstream
current_record_delete.)
Comment-trigger runs need an existing comment
For a record_comment_or_reply_created automation, a manual run resolves the record's most-recent existing
comment/reply as the trigger's current-comment context. A record that has no comment/reply produces no run —
the endpoint still answers 202, but nothing is created.
Simulate an automation
A dry run with no side effects, over the automation's stored definition. It always produces a simulation run, which is excluded from most run listings but visible in the per-automation listing and retrievable by ID. The body is identical to Run. Simulating also requires you can view the target record.
curl -X POST https://api.tapeapp.com/v1/automation/4021/simulate \
-u user_key_replace_with_your_api_key: \
-H "Content-Type: application/json" \
--data '{ "record_id": 5001 }'
Validate an automation
Recomputes, server-side, whether the current definition is executable — a fresh verdict that can differ from the
stored broken flag (create and update don't re-validate). No request body.
curl https://api.tapeapp.com/v1/automation/4021/validate -u user_key_replace_with_your_api_key:
{
"valid": false,
"errors": [
{ "code": "action_app_missing", "message": "An action references an app that no longer exists.", "action_id": "a1b2c3", "app_id": 42, "deactivated": false }
]
}
valid is true when there is no active (non-deactivated) error. Each entry uses the same shape and
broken-reason codes as broken_reason on the automation object.
valid: true is not a guarantee of an executable run
Validation is not exhaustive. Some references are only checked for presence, not resolved — for example a
collect_app_view_records app_view_id is checked only for being non-empty, so a bogus view id passes validate and
fails only at run time. Treat validate as catching the catalogued faults, not as proof the run will succeed.
Calling another automation, or a weblink?
The endpoints that let one automation call another, or mint a weblink, are the execution backends of those actions — see Advanced / Sandbox.