# Run a workflow

> Start a run, read it to the end, cancel it, and how retries, repairs and pricing work.

Source: https://docs.fous.com/guides/workflows/run
Index: https://docs.fous.com/llms.txt

## Start a run

`POST /v1/workflows/{id}/runs` starts a run manually, whether the workflow is enabled or not.

```bash
curl https://api.fous.com/v1/workflows/wf_01m6vnc9ewe3za9g5kqvd8yrkp/runs \
  -H "Authorization: Bearer $FOUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "input": { "status": "open" }, "wait": 30 }'
```

`input` provides the trigger's [inputs](https://docs.fous.com/guides/workflows/triggers.md#inputs). Defaults fill in omitted values, and numbers and booleans are parsed from text. A missing required value returns `400 invalid_request`. A workflow that is not ready returns `409` with `reason: "workflow_incomplete"`.

`wait` (0 to 60 seconds, default 0) holds the response: `200` if the run ended within that time, otherwise `202`.

## Read the run

`GET /v1/workflows/{id}/runs/{run_id}` returns a run, finished or in progress, with each step's input and output in `steps`. Add `?wait=60` (0 to 60 seconds) and the answer is held until the run ends: `200` once it ended, `202` while it goes on, so you don't have to poll. `GET /v1/workflows/{id}/runs` lists the workflow's runs, newest first, without their steps (`limit` is 1 to 100, default 20; `before` is the id of the last run you read, and `has_more` says whether there are older ones). A workflow run's id also works on [`GET /v1/runs/{id}`](https://docs.fous.com/guides/runs.md).

| `status` | Meaning |
| --- | --- |
| `queued` | Waiting to start. |
| `running` | Executing a step. |
| `waiting` | Paused until `resume_at`: on a delay, before a retry, while a method is being repaired, or while a scheduled run waits for someone to sign an account in again or for credits. |
| `completed` | Finished, or a filter ended it early. |
| `failed` | A step failed permanently. `error` gives the step (`step`, `path`) and the reason. |
| `canceled` | Canceled by a person, or the workflow was disabled while the run was queued or waiting to retry. |
| `skipped` | Its schedule came due while the previous run had not finished. |

`credits` is what the run cost. A run with its steps has `output`: what the last step that did something gave (a method's `data`, any other step's output), `null` until it completes. A method step's own run also appears in [`GET /v1/runs`](https://docs.fous.com/guides/runs.md#run-history), under `method_run_id`.

In `steps`, `seq` is the execution order, `key` is the step's key, and `path` is where it ran: `per_item.notify[2]` is the step `notify` in the third item of the loop `per_item`. A step's `status` is `running` while it executes and `waiting` while it waits to be retried. A filter that stops the run ends as `filtered`. `attempts` lists each failed attempt, and `waiting` describes what the step is waiting for.

`POST /v1/workflows/{id}/runs/{run_id}/cancel` cancels a run that has not ended and answers with it updated. A method run in progress is stopped and free; steps that already finished stay charged. Canceling a run that has ended returns `409 conflict`.

## Reliability

Workflows run unattended, so a step that fails temporarily does not fail the run.

- **Retries.** Transient failures (a site's 5xx, a timeout, a dropped connection, a rate limit, a brief Fous outage, or a webhook's 5xx, 408 or 429) are retried after 20 seconds, 2 minutes, 10 minutes and 30 minutes, for 5 attempts in total. A longer `Retry-After` from the site is honored, up to 1 hour. While it waits, the step is `waiting` with `waiting: { reason: "retry", until, attempt: 2, of: 5 }`, and the run waits too. Failed attempts cost nothing.
- **No duplicate writes.** A write method whose attempt may have reached the site is never sent again, even after a repair: the step fails and tells you to check the site. Webhook retries carry the same `Idempotency-Key` header so receivers can discard duplicates. An email is never delivered twice.
- **Repairs.** If a method stops working and Fous is repairing it, the step waits for the repair (`waiting.reason: "repair"`) and then runs on the repaired version. If the repair cannot fix the method, the step fails.
- **Failure emails.** When a run started by a schedule or webhook fails permanently, the workflow's creator gets one email, and no more until one of its runs completes. Runs started manually or through the API send no email.
- **Signed-out accounts and credits.** When a scheduled run's step finds its account needs signing in, or your organization has no credits for it, the step waits (`waiting: { reason: "connection", site, connection_id, connect_url, until }`, or `reason: "credits"`) and goes on by itself as soon as someone signs in or credits are added. Nothing is run or charged while it waits, and the waiting run shows up as one run, not one per scheduled time. If nothing changes within 23 hours of the run's start, the run fails (a failure email goes out, as above), so a daily schedule's next run always starts and waits again. Runs started manually or by the API fail at once with the sign-in link or `insufficient_credits`.
- **Waiting emails.** A login lost during a run sends the sign-in email, which lists the workflows waiting on it, and running out of credits sends its own email. When the account was already signed out, or credits were already at zero, before a scheduled run started, its creator gets one email when the run starts waiting, with the link to sign in or add credits.
- **One run at a time.** If a schedule comes due while the previous run is still in progress, the new run is recorded as `skipped` with the reason, and the schedule continues as usual. Disabling a workflow cancels the runs its schedule or webhook queued and those waiting to retry or for a repair. Runs started manually continue, as do runs already executing.
- **Worker recovery.** If a worker restarts mid-run, another worker resumes the run from the current step. A method run still in progress is never started again: the worker reattaches to it by ID and waits for its answer. A method run whose server stopped ends as interrupted within about 10 minutes; a read is then retried, and a write that may have reached the site is not.
- **Data limit.** A run holds at most 64 MB of step data. A step whose output would exceed that fails before its output is stored, and is not charged.

## Pricing

A run costs 1 credit for each action step that runs: methods, AI, transforms, emails and webhooks. Steps inside a For each count once per item. Triggers, For each, filters and delays are free, and failed steps cost nothing. Each method step is an ordinary [run](https://docs.fous.com/guides/runs.md). In Usage, all of a workflow's charges appear under its name.

`GET /v1/workflows` and `GET /v1/workflows/{id}` give the price of a full run in `cost`: `credits` for the steps outside a For each, and `per_item` for each item a For each processes (`null` when there is none).

```json
{ "cost": { "credits": 1, "per_item": 2 } }
```

This is one top-level method step and a For each with two steps: at most 21 credits for 10 items. A run that a filter ends early costs less, and `credits` on the run is the actual cost. A step your organization cannot pay for fails with `error.code: "insufficient_credits"`, and the run stops there; a scheduled run [waits for credits](#reliability) instead.

AI features (drafting from a sentence, the assistant, writing transform code) cost no credits within your plan's [AI messages](https://docs.fous.com/guides/billing.md#builds-and-ai). With no credits left, they return `402 insufficient_credits` before starting.

## Limits on Free

A limit reached on Free returns `403 plan_limit` with `limit.kind`. There is no limit on the number of workflows.

| `limit.kind` | When | Limit on Free |
| --- | --- | --- |
| `api` | Enabling a schedule or webhook. | Paid plans only. |
| `chat_messages` | AI messages: the assistants, drafting a workflow from a sentence and writing a transform's code. | A high limit that only stops abuse, shared by all. |
| `builds` | Building a pending step's method, like any other build. | 3 in total. `limit.value` is `3`. |
| `sites` | A build that would add a method on a new website. | 1 site. |

An email step addressed outside your organization fails with `limit.kind: "email_recipients"` on Free, Starter and Pro. On any plan, more than 10 AI calls a minute return `429 rate_limited` with `limit.kind: "ai_per_minute"`; below Enterprise, more than 20 AI messages a minute return `429` with `limit.kind: "chat_per_minute"`.
