# Executions

> Follow a Nodaro workflow run node by node, read each node's result, list a workflow's past runs, and cancel a run now or after its running nodes finish.

Source: https://nodaro.ai/docs/developers/api/executions

An **execution** is one run of a whole workflow. It records the run's status, how many nodes have finished, the credits used, and the state and result of every node, and it groups the jobs the run created, one for each AI node. `POST /v1/workflows/:id/run` returns an `executionId`, and the execution endpoints follow that run to its end.

## Endpoints

| Method | Path | What it does |
| --- | --- | --- |
| `GET` | `/v1/workflow-executions/:id` | One run: its status, node counts, credits and the state of every node. |
| `GET` | `/v1/workflow-executions/:id/stream` | The same run as a stream of server-sent events. |
| `GET` | `/v1/workflows/:id/executions` | The runs of one workflow, in pages. |
| `POST` | `/v1/workflow-executions/:id/cancel` | Cancel a run, now or after its running nodes finish. |
| `GET` | `/v1/api/status/:execId` | The API-token lane: a run's status, node counts and credits used. |
| `GET` | `/v1/api/result/:execId` | The API-token lane: a finished run's outputs. |

The last two belong to the runs started with `POST /v1/api/run`. They are described in [Run a workflow with new input values](https://nodaro.ai/docs/developers/api/workflows#run-a-workflow-with-new-input-values).

## Get a run

**curl**

```bash
curl -s https://app.nodaro.ai/v1/workflow-executions/3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b \
  -H "Authorization: Bearer $NODARO_API_KEY"
```

**TypeScript SDK**

```ts
const { data } = await client.executions.get(executionId)
console.log(data.status, `${data.completedNodes}/${data.totalNodes}`)
```

**CLI**

```bash
nodaro executions get 3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b --json
```

```json
{
"data": {
"id": "3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b",
"workflowId": "8c2d7f1e-3a4b-4c5d-9e6f-7a8b9c0d1e2f",
"status": "running",
"triggerType": "manual",
"totalNodes": 4,
"completedNodes": 2,
"failedNodes": 0,
"totalCreditsUsed": 45,
"errorMessage": null,
"nodeStates": {
"text-prompt-1": { "status": "completed", "output": { "text": "a knight on a hill at dawn" } },
"generate-image-1": { "status": "completed", "output": { "imageUrl": "https://…/knight.png" } },
"generate-video-1": { "status": "running" },
"add-captions-1": { "status": "pending" }
},
"completedAt": null
}
}
```

| Field | Meaning |
| --- | --- |
| `status` | The run's status. See the table below. |
| `triggerType` | What started the run, such as `manual`, `webhook`, `schedule`, `app_run` or `single-node`. |
| `totalNodes`, `completedNodes`, `failedNodes` | Node counts. Show progress as `completedNodes / totalNodes`. |
| `totalCreditsUsed` | Credits used by the run so far. |
| `errorMessage` | Why the run failed or stopped, in words. |
| `nodeStates` | The state of every node, keyed by node id. |
| `completedAt` | When the run ended, or `null`. |

The id of a standalone single-node job also works here: the server answers with the same shape, describing that one node. An id that does not exist or is not yours answers `404`.

### Run statuses

| Status | Final | Meaning |
| --- | --- | --- |
| `pending` | No | The run is queued. |
| `running` | No | Nodes are running. |
| `stopping` | No | You cancelled with `after_current`: running nodes finish, then the run stops. |
| `completed` | Yes | The run finished. |
| `failed` | Yes | The run failed. `errorMessage` says why. |
| `cancelled` | Yes | The run was cancelled. |
| `timed_out` | Yes | The run timed out. |
| `discarded` | Yes | You cancelled with `discard`: running jobs finished without updating the canvas. |

### Node states

Each entry in `nodeStates` has a `status`: `pending`, `running`, `completed`, `failed` or `skipped`. A failed node also carries its `error`.

A completed node carries its result in `output`. The keys depend on the node's output: look for `url`, `imageUrl`, `videoUrl`, `audioUrl`, `resultUrl` or `text`, in that order.

A **failed** node can carry `output` too, when the run kept a structured result. The 3D scene authoring nodes are the case today: a scene whose visual review failed after every repair still published a draft, and the node fails with that draft in `output.plan`. Two rules follow:

- **Check for the field, not the status.** A `pending` or `running` node never has `output`, and other node types may keep results in future.
- **A present `output` is not success.** The node failed; it only kept something.

The SDK exports `nodeStateMayCarryOutput(status)`, which is `true` for `completed` and `failed`, and the same pair as `OUTPUT_BEARING_NODE_STATUSES`.

## Wait for a run to end

Poll every 2 to 5 seconds until the status is final:

**TypeScript SDK**

```ts
const { executionId } = await client.workflows.run(workflowId)

const final = ['completed', 'failed', 'cancelled', 'timed_out', 'discarded']
while (true) {
const { data } = await client.executions.get(executionId)
console.log(`${data.completedNodes}/${data.totalNodes} nodes done`)
if (final.includes(data.status)) {
if (data.status !== 'completed') throw new Error(`Run ${data.status}: ${data.errorMessage ?? 'no message'}`)
console.log(`Done. Used ${data.totalCreditsUsed} credits.`)
break
}
await new Promise((r) => setTimeout(r, 2_000))
}
```

**curl**

```bash
while true; do
STATUS=$(curl -s -H "Authorization: Bearer $NODARO_API_KEY" \
"https://app.nodaro.ai/v1/workflow-executions/$EXEC" | jq -r .data.status)
echo "Status: $STATUS"
case "$STATUS" in completed|failed|cancelled|timed_out|discarded) break;; esac
sleep 3
done
```

**CLI**

```bash
nodaro executions get 3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b --watch
```

With `--watch`, the CLI polls until the run ends and exits with code `0` on success, `2` when the run failed and `130` when it was cancelled. With `--json`, it prints the payload and exits normally, so check `.status` yourself.

`GET /v1/workflow-executions/:id/stream` sends the same run state as server-sent events while the run is in progress, and it carries the same node `output` rules as the read above. Polling is the simpler choice for most integrations.

## List a workflow's runs

`GET /v1/workflows/:id/executions` returns a workflow's runs in pages, as `{ data, nextCursor }`. The list includes the standalone single-node jobs of that workflow beside its full runs.

| Query | Meaning |
| --- | --- |
| `limit` | Page size. |
| `cursor` | The `nextCursor` of the previous page. |
| `status` | Comma-separated statuses, for example `pending,running`. |
| `source` | `editor` leaves out runs started by apps, webhooks and schedules. `all` includes them. |

**curl**

```bash
curl -s "https://app.nodaro.ai/v1/workflows/$WORKFLOW_ID/executions?limit=20&status=completed" \
  -H "Authorization: Bearer $NODARO_API_KEY"
```

**TypeScript SDK**

```ts
const { data, nextCursor } = await client.executions.listForWorkflow(workflowId, {
limit: 20,
status: 'completed',
})
```

## Cancel a run

`POST /v1/workflow-executions/:id/cancel` stops a run. The optional `mode` in the body decides what happens to the nodes already running:

| `mode` | What happens | Final status |
| --- | --- | --- |
| none | The run stops now. Running jobs are cancelled and their reserved credits are refunded. | `cancelled` |
| `after_current` | Running nodes finish, and their results land on the canvas and in your library. Then the run stops. | `stopping`, then final |
| `discard` | No new node starts. Running jobs cannot be stopped at the model, so they finish and are saved to your library, but their results are not written to the canvas. There is no refund, because those jobs completed. | `discarded` |

The answer is `{ "success": true }`.

**curl**

```bash
curl -s -X POST https://app.nodaro.ai/v1/workflow-executions/$EXEC/cancel \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mode": "after_current"}'
```

**TypeScript SDK**

```ts
await client.executions.cancel(executionId)                           // now
await client.executions.cancel(executionId, { mode: 'after_current' }) // after running nodes
await client.executions.cancel(executionId, { mode: 'discard' })       // stop scheduling
```

**CLI**

```bash
nodaro executions cancel 3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b                # now
nodaro executions cancel 3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b --mode stopping # after running nodes
```

To stop one generation instead of a whole run, cancel its job: see [Jobs](https://nodaro.ai/docs/developers/api/jobs#cancel-or-delete-a-job).

## Executions and jobs

A run's AI nodes each create a [job](https://nodaro.ai/docs/developers/api/jobs), and `nodeStates` carries each node's result once its job is done. Read the execution to follow the run as a whole. Read a job for the details of one generation: its `error_hint`, its `credit_status`, or everything that was sent to the model in `input_data`.

Runs that a trigger starts, such as a [Webhook Trigger](https://nodaro.ai/docs/nodes/automate/webhook-trigger) call or a [Schedule Trigger](https://nodaro.ai/docs/nodes/automate/schedule-trigger) firing, are executions too, with `triggerType` `webhook` or `schedule`. See [Webhooks](https://nodaro.ai/docs/developers/api/webhooks).

## Frequently asked questions

### What is the difference between an execution and a job?

An execution is one run of a whole workflow. It records the state of every node and groups the jobs the run created, one for each AI node. A job is a single generation, such as one image or one video render.

### How do I get the status of a workflow run?

Poll GET /v1/workflow-executions/:id every 2 to 5 seconds. It returns the run's status, how many nodes finished and failed, the credits used so far, and the state of every node. Stop when the status is completed, failed, cancelled, timed_out or discarded.

### How do I cancel a workflow run?

Send POST /v1/workflow-executions/:id/cancel. Without a mode it cancels at once and refunds the reserved credits. With mode after_current, the running nodes finish first. With mode discard, running jobs finish but new nodes do not start.

### Where is a node's result in an execution?

In nodeStates, under the node's id. A completed node carries its result in output, for example output.imageUrl, output.videoUrl, output.audioUrl or output.text.

### Can I list the past runs of a workflow?

Yes. GET /v1/workflows/:id/executions returns the workflow's runs in pages, and you can filter them by status and by where they were started.
