# Workflows

> Chain your methods into a process with a trigger and steps, on a schedule or from a webhook, then create, run and start it from your code.

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

A workflow adds a schedule, loops, filters and delivery to your [methods](https://docs.fous.com/guides/methods.md). A trigger starts each run: manually, on a schedule, or through a webhook. Steps then run in order, and each step can read the output of the steps before it.

Define a workflow as JSON, as on this page, or describe it in a sentence and let Fous [draft it from your methods](https://docs.fous.com/guides/workflows/create.md). To connect Slack, Zapier, Make, n8n or an ERP, add a webhook step that posts to their URL, or have them call the workflow's webhook trigger.

This example lists open invoices on a portal, stops if there are none, summarizes the rest, and posts the summary to a webhook.

## Create it

```bash
curl https://api.fous.com/v1/workflows \
  -H "Authorization: Bearer $FOUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Open invoices digest",
    "definition": {
      "trigger": {
        "type": "webhook",
        "inputs": [
          { "key": "status", "type": "string", "default": "open" }
        ]
      },
      "steps": [
        {
          "key": "invoices",
          "name": "List invoices",
          "type": "method",
          "method": "portal.example.com/list_invoices",
          "input": { "status": "{{trigger.status}}" }
        },
        {
          "key": "any",
          "name": "Only if there are invoices",
          "type": "filter",
          "conditions": [
            { "value": "{{steps.invoices.data.invoices | length}}", "op": "gt", "compare": "0" }
          ]
        },
        {
          "key": "summary",
          "name": "Summarize",
          "type": "ai",
          "prompt": "Write a short digest of these invoices, grouped by supplier, with the total due for each.\n\n{{steps.invoices.data.invoices}}"
        },
        {
          "key": "post",
          "name": "Post the digest",
          "type": "webhook",
          "url": "https://hooks.example.com/finance",
          "body": { "text": "{{steps.summary.text}}" }
        }
      ]
    }
  }'
```

Returns `201` with the saved workflow, disabled, including its `id`, `definition`, `webhook_url` and `cost`. `cost.credits` is the price of a full run: 3 credits here, one for each of the three action steps (the filter is free). Fous validates the definition against your methods first and returns all validation errors at once, each with its path.

## Run it

Any workflow can be run manually, whether it is enabled or not. `input` provides the trigger's inputs, and `wait` holds the response for up to 60 seconds (default 0).

```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 }'
```

`200` means the run ended within `wait`. `202` means it is still running; use its `id` to read it.

## Read the run

Poll the run by `id` until it ends:

```bash
curl https://api.fous.com/v1/workflows/wf_01m6vnc9ewe3za9g5kqvd8yrkp/runs/wfr_01m6vhajhdehdac64kftqt13je \
  -H "Authorization: Bearer $FOUS_API_KEY"
```

A `status` of `queued`, `running` or `waiting` means the run is in progress. It ends as `completed`, `failed` or `canceled`. `credits` is what the run cost, and `steps` has one entry per step with its input and output:

```json
{
  "id": "wfr_01m6vhajhdehdac64kftqt13je",
  "workflow_id": "wf_01m6vnc9ewe3za9g5kqvd8yrkp",
  "status": "completed",
  "trigger": "api",
  "input": { "status": "open" },
  "error": null,
  "credits": 3,
  "steps": [
    {
      "seq": 1,
      "key": "invoices",
      "type": "method",
      "status": "completed",
      "input": { "status": "open" },
      "output": {
        "status": "completed",
        "data": {
          "invoices": [
            { "number": "INV-1042", "supplier": "Acme Ltd", "total": 1800, "due": "2026-12-01" }
          ]
        },
        "run_id": "run_01m6vhajhrf0gaxcn1qsvdwj7k",
        "error": null
      },
      "error": null
    }
  ]
}
```

This example shows only the first entry of `steps` and omits timestamps. [Run a workflow](https://docs.fous.com/guides/workflows/run.md#read-the-run) lists every status.

## Start it from a webhook

The workflow already has a webhook trigger, so enabling it is all that remains:

```bash
curl -X PATCH https://api.fous.com/v1/workflows/wf_01m6vnc9ewe3za9g5kqvd8yrkp \
  -H "Authorization: Bearer $FOUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true }'
```

The response repeats `webhook_url`. Any client that can send an HTTP POST can now start a run without an API key, because the URL itself is the secret. The JSON body is the run's input:

```bash
curl https://api.fous.com/v1/hooks/whk_3q9ZxK0cLm2vT8yR5nB1wJ7dF4hG6sPa \
  -H "Content-Type: application/json" \
  -d '{ "status": "overdue" }'
```

Returns `202` with `{ "run_id": "wfr_…", "workflow_id": "wf_…" }`. Read that run the same way. To run on a schedule instead, use a `schedule` trigger: see [Triggers](https://docs.fous.com/guides/workflows/triggers.md).

## Go further

- [Create a workflow](https://docs.fous.com/guides/workflows/create.md): from a sentence or from JSON, streaming the draft, and building missing methods.
- [Run a workflow](https://docs.fous.com/guides/workflows/run.md): statuses, retries, repairs and pricing.
- [Triggers](https://docs.fous.com/guides/workflows/triggers.md): inputs, schedules and webhooks.
- [Steps](https://docs.fous.com/guides/workflows/steps.md): every step type, templates and code.
