---
title: "Execute Tool"
method: POST
path: "/workflows/v1/tools/{tool_id}/execute"
tags: ["Tools"]
---

# Execute Tool

`POST /workflows/v1/tools/{tool_id}/execute`

Execute a saved custom tool against the supplied argument values and return its output.

Runtime failures are returned as HTTP 200 with ``success=False`` and a clean ``error`` message
(see :func:`execute_tool_inline`).

## Path parameters

- `tool_id` string, required

## Request body

- ToolExecuteRequest
  - `args` object — Argument values to invoke the tool with, keyed by the tool's parameter names.
  - `dry_run` boolean — When True, side-effecting tools (writes/sends/unknown) are validated but NOT executed - no external effect occurs and a simulated result is returned. Pure/read-only tools run normally.
  - `dynamic_variables` object — Test values for {{dynamic}} placeholders in the tool config (endpoint/headers/body/code). Resolved before execution to mirror the live workflow runtime. The team's global variables are applied automatically, exactly as the live runtime does; values supplied here override them.
  - `runtime_variables` object — Test values for [[runtime]] placeholders in the tool config (endpoint/headers/body/code). Resolved before execution to mirror the live workflow runtime.

## Response `200`

Successful Response

- ToolExecuteResponse — The API's name for :class:`ToolExecutionResult`. Subclassed rather than aliased so the published OpenAPI schema keeps its name while the shape itself lives in the framework, shared with every other caller that executes a tool.
  - `success` boolean, required
  - `result` unknown
  - `error` string, nullable — Full human-readable error description when success is False. Always set on failure.
  - `latency_ms` integer, nullable — Wall-clock execution time in milliseconds.
  - `dry_run` boolean — Whether this run was a validate-only dry run.
  - `side_effect` string, nullable — The tool's side-effect classification (none/reads/writes/sends/unknown).
  - `error_type` string, nullable — Error category: validation | timeout | runtime | connection | http_status | not_found.
  - `error_code` string, nullable — Machine-readable error code: HTTP status (e.g. '404') for external API tools, or the exception class name (e.g. 'ValueError') otherwise.
  - `field_errors` object, nullable — Per-argument validation messages keyed by the offending field name.
  - `truncated` boolean — Whether the result was truncated because it was too large.
  - `bound_arguments` BoundArgumentReport[], nullable — Arguments the workflow supplies from its own variables rather than the caller: what each one is bound to, whether it resolved, and the shape of the value — never a value read from a variable. A list of records rather than a name→value map, so the provenance travels with each entry; see BoundArgumentReport for why that matters.
    - `argument_name` string, required
    - `source` string, required — The binding's source namespace: runtime | dynamic | auto | literal.
    - `variable_path` string, nullable — The variable this argument is bound to.
    - `required` boolean — Whether the argument must have a value for the tool to run.
    - `overrides_caller_value` boolean — Whether the binding wins over a value the caller supplied.
    - `status` string, required — resolved (the variable answered) | default (it did not, and the binding's default stood in) | unresolved (it did not, and the binding is required) | caller_value_kept (the caller supplied this argument and the binding does not override, so nothing was resolved at all).
    - `resolved_from` string, nullable — Which namespace answered: runtime | dynamic | literal | default.
    - `value_type` string, nullable — Type name of the value the tool will actually receive for this argument.
    - `value_summary` string, nullable — Bounded structural description — key count, item count, length. Never content.
    - `value` unknown
    - `value_truncated` boolean — Whether a reported config-sourced value was truncated.
  - `effective_result_runtime_variable_name` string, nullable — The runtime variable this tool's result belongs in, read from the config that actually ran. For a tool attached by tool_id that is the *saved* tool's name, which the attachment does not carry — so a caller that stores the result must use this rather than reading the config it passed in. None only when the config could not be resolved at all, since naming a variable for a config that never resolved would be a guess.
  - `result_variable_updates` object, nullable — Runtime variables the tool's own config asks for its result to be mapped onto — result_variable_mappings plus expand_result_into_runtime_variables. None when the config declares neither (the common case); an empty map means it declared some and none could be produced. Like the name above, these are reachable only after the by-reference merge.
  - `result_workflow_variable_updates` object, nullable — The same, for mappings the tool declares with scope='workflow'. Kept separate rather than merged because they belong in a different store — the run's shared memory rather than this thread's — and a caller that wrote them to the thread instead would give each one a thread-local shadow that then wins over it everywhere. A caller with no workflow run (the Test-Tool routes) has nowhere to put these and may ignore them.
  - `result_mapping_errors` string[], nullable — Required result mappings that could not be satisfied. The tool still SUCCEEDED — a mapping failure is a statement about the workflow's expectation of the result, not about the call — so this is populated alongside success=True and a full result.

## Other responses

- `422` — Validation Error

## Changes

- **2026-08-24** `777675c8a285` — 4 info
  - added the optional property `effective_result_runtime_variable_name` to the response with the `200` status
  - added the optional property `result_mapping_errors` to the response with the `200` status
  - added the optional property `result_variable_updates` to the response with the `200` status
  - added the optional property `result_workflow_variable_updates` to the response with the `200` status
- **2026-08-20** `47b3d1acadda` — 1 info
  - added the optional property `bound_arguments` to the response with the `200` status
- **2026-07-21** `d276be705570` — 9 info
  - added the new optional request property `dry_run`
  - added the new optional request property `dynamic_variables`
  - added the new optional request property `runtime_variables`
  - added the optional property `dry_run` to the response with the `200` status
  - …5 more

[Change history](https://skmtc.dev/interactly/apis/interactly-api-3/changes/workflows/v1/tools/:tool_id/execute/post.md)

---

[API](https://skmtc.dev/interactly/apis/interactly-api-3.md) · [All operations](https://skmtc.dev/interactly/apis/interactly-api-3/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/interactly/interactly-api-3/revisions/35cbea12a781/schema)
