Skip to main content

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:

TriggerBody
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

POSThttps://api.tapeapp.com/v1/automation/{automation_id}/manual-run

Executes the automation with real side effects, at-least-once. The trigger filter is applied — a record that does not match produces no run.

➡️ Request
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 }'
⬅️ Response
{ "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

POSThttps://api.tapeapp.com/v1/automation/{automation_id}/simulate

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.

➡️ Request
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

GEThttps://api.tapeapp.com/v1/automation/{automation_id}/validate

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.

➡️ Request
curl https://api.tapeapp.com/v1/automation/4021/validate -u user_key_replace_with_your_api_key:
⬅️ Response
{
"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.