Skip to main content
Workflows are Metal’s automation engine. A workflow chains together steps such as data lookups, AI reasoning, and document generation to automate research that would otherwise be manual. Each execution of a workflow is a run.

Workflows and runs

  • A workflow is the definition: the steps, inputs, and configuration.
  • A run is a single execution of a workflow against specific inputs.
You manage definitions with the workflow endpoints and execute them by creating runs.

Running a workflow

1

Find the workflow

List your workflows to get the id of the one you want to run.
2

Create a run

Trigger a run with the inputs the workflow expects.
3

Check run status

Poll the run to follow its progress and read its output when it completes.
Runs are asynchronous. Creating a run returns immediately with a run record; poll GET /v1/workflow-runs/{id} (or use a webhook trigger) to track completion.

Conditional branch steps

A branch step runs one of two arms based on a condition, so a workflow can take different paths at run time — for example, escalate to human approval only when a score is low, or skip a report step when an optional input was not provided.
  • The condition is a single CEL expression that must evaluate to a boolean.
  • The step has two arms — then and else — and each arm is an ordinary list of steps.
  • Exactly one arm runs. Steps in the arm that did not run are recorded as skipped, and downstream references reaching into a skipped subtree render as empty rather than failing the run.
A condition can address:
  • input — the run’s inputs.
  • steps — outputs of steps that ran strictly before the branch. It cannot see either arm’s own children, since neither has run when the condition is evaluated.
  • triggeredBy — the Metal user ID that started the run. It is empty when the run was system-triggered.
  • now — the current time.
  • Inside an iterator, input.item is the current work item and the branch is evaluated once per item. The separate iterator root carries frame metadata: itemIndex, stepId, childStepId, and childStepIndex.
Use has(input.<key>) to test whether an optional input was supplied, and "<stepId>" in steps to guard a reference to a step that may not have run.

Nesting and validation

  • Branches can nest inside their own arms, and inside iterators. Nesting is capped at 3 branch levels deep, counted from the workflow root — an iterator does not reset the count.
  • Step IDs must be unique across the entire step tree, not just within one arm.
  • A cross-arm reference — one arm reading a step in the other — is rejected at authoring time, because the two never both run. A reference made after the branch to a step inside an arm is allowed but flagged as conditional.
  • Inside an iterator, arm children are restricted to inline-executable step types (agent, completion, tool, generateDocument, executeCode, and nested branch); humanInLoop and iterator are rejected inside a branch that itself sits in an iterator.
  • Plain message-approval humanInLoop steps are allowed in a branch arm; structured-review approval is not.

Workflow inputs

Each input in a workflow’s schema is either required or optional:
  • Required inputs must be supplied on every run. The Run form disables Run until each required field has a value, and names the specific fields that are still missing.
  • Optional inputs may be left blank. A blank optional field is omitted from the run payload entirely rather than sent as "" or [], which matters for typed fields like resource IDs where an empty string is not a valid value.
  • Inputs supplied by a trigger (webhook or event) and inputs meant for manual runs only are surfaced by the server’s effective input schema and handled separately from author-supplied fields — you do not need to fill them in yourself when creating a run against a triggered workflow.
Presence is declared in the builder alongside each input’s type, name, and default. A field whose default is blank reads as optional. A non-blank default keeps the field required, but the default fills it when omitted, so it never blocks a run. When creating a run via the API, only include the fields you want to set; omit optional fields you want left unset.

Managing runs

Beyond creating and reading runs, you can:
  • Retry a failed run: POST /v1/workflow-runs/{id}/retry
  • Re-run with the same inputs: POST /v1/workflow-runs/{id}/rerun
  • Cancel an in-progress run: POST /v1/workflow-runs/{id}/cancel
  • List runs for a workflow: GET /v1/workflows/{id}/runs

Versioning

Workflow definitions are versioned. You can list versions (GET /v1/workflows/{id}/versions) and restore a previous version (POST /v1/workflows/{id}/versions/restore) if a change needs to be rolled back.

Triggering from external systems

Workflows can be triggered by inbound webhooks in addition to API calls. This lets an external system kick off research when an event happens on its side. See Webhooks for how to configure and call a workflow’s webhook trigger.
Build and edit workflow definitions in the Metal app, then use the API to trigger and monitor runs programmatically. This keeps complex authoring visual while automation stays in code.