> ## Documentation Index
> Fetch the complete documentation index at: https://docs.powabase.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Workflows

> Workflows are DAG-based automation pipelines that chain together LLM calls, code execution, conditions, and agent runs into deterministic, repeatable processes.

## What is a Workflow?

A Workflow is a directed acyclic graph (DAG) of blocks connected by edges. Each block performs a specific action: calling an LLM, running code, evaluating a condition, or executing an agent. Data flows from block to block through the edges. Unlike orchestrations (where the coordinator decides what happens), workflows follow a fixed, predetermined path every time.

## Block Types

The block registry accepts these canonical types (plus the back-compat aliases `function` for `code` and `api_call` for `general_api`):

| Block         | Description                                                                                  | Key Config                                                                                |
| ------------- | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| starter       | Manual / API trigger — declares the workflow's input variables                               | None (variables are passed at execution time)                                             |
| webhook       | HTTP trigger — exposes the workflow at `POST /api/webhooks/{webhook_id}` once deployed/armed | `webhook_id` (UUID, you mint it via API or the studio mints it for you), `webhook_secret` |
| agent         | Runs an existing agent with a message                                                        | `agent_id`, `message` (template with `{{variables.x}}` interpolation)                     |
| orchestration | Delegates to a multi-agent coordinator                                                       | `orchestration_id`, `message`                                                             |
| code          | Executes custom Python or JavaScript                                                         | Language, source, input mappings                                                          |
| condition     | Branches the flow based on a boolean expression                                              | Expression evaluated against upstream outputs                                             |
| split         | Parallel fan-out — runs downstream branches concurrently                                     | Branch selection rules                                                                    |
| platform\_api | Calls a platform resource (KB search, agent run, etc.)                                       | Resource type + parameters                                                                |
| general\_api  | Calls an external HTTP API                                                                   | URL, method, headers, body template                                                       |
| response      | Returns the workflow result back to the caller                                               | Result template referencing upstream block outputs                                        |

Unknown block types are rejected at `PUT /api/workflows/{id}/graph` with `400 Unknown block type`.

## Graph Execution

When you execute a workflow, the engine evaluates blocks in topological order. Each block receives the outputs of its upstream blocks as input. Condition blocks create branches, and only the matching branch continues execution. The workflow finishes when all output blocks have been reached.

<Frame caption="Workflow DAG with branching logic">
  <img src="https://mintcdn.com/powabase/B-6sRgQRCSKyNrPg/diagrams/workflow-execution.svg?fit=max&auto=format&n=B-6sRgQRCSKyNrPg&q=85&s=35b6ce480a7f35787a894a96ab667bb7" alt="Workflow execution DAG: Input block → LLM block (processes input) → Condition block (branches based on result) → Branch A: Output A / Branch B: Output B. Blocks are connected by directional edges showing data flow." width="766" height="210" data-path="diagrams/workflow-execution.svg" />
</Frame>

## Programmatic vs Copilot

You can build workflows two ways. The programmatic approach uses the PUT /api/workflows/\{id}/graph endpoint to define blocks and edges as JSON. The Copilot approach uses natural language: describe what you want, and the AI copilot generates the workflow graph for you. Both produce the same underlying graph structure.

## Variables and references

Workflow blocks pass data to downstream blocks through their `output`. To reference an upstream block's output from another block's config, use **angle-bracket reference syntax**:

```
<blockId.output>
<blockId.output.field>
<blockId.output.field.nested>
```

The resolver walks the dotted path against the upstream block's output dict. Block IDs may contain letters, digits, underscores, hyphens, and spaces, so `<Lookup Customer.output.email>` is valid.

Two contexts:

* **Inside a string** (most block configs): every `<blockId.output.field>` placeholder gets substituted as a string. `"Hello <fetch.output.name>!"` becomes `"Hello Alice!"`.
* **Inside a JSON value** (e.g. `general_api` body, `code` inputs, agent block messages): if the entire string is one reference, the resolved value is returned **with its original type** (so you can pass a number, array, or object, not just a string). `"<extract.output.tags>"` returns `["foo", "bar"]` rather than `'["foo", "bar"]'`.

The starter block's variables surface as `<starter.output.variableName>`, and you'll also see the older `{{variables.x}}` syntax in agent / code block templates. Both work; the angle-bracket form is canonical and applies to every block.

Unresolvable references (block not yet run, missing field) leave the placeholder string as-is so you can see what failed when inspecting block logs.

For condition blocks, the expression evaluator uses a Python-safe AST subset: comparisons, BoolOp (`and`/`or`/`not`), BinOp (`+`/`-`/`*`/`/`), attribute access, and subscripting. Function calls are not permitted.

## Scheduling

When a workflow's starter block has `schedule_enabled: true` in its config, deploying the workflow materializes a `schedule_config` on the workflow row and Celery's scheduler tick (every 30 seconds) fires runs at the configured cadence.

The starter block's config takes:

| Field                                   | Type                                 | Notes                                                                                             |
| --------------------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------- |
| `schedule_enabled`                      | bool                                 | Must be `true` for any scheduling to happen                                                       |
| `schedule_type`                         | `"interval"` \| `"cron"`             | Default `interval`                                                                                |
| `schedule_timezone`                     | IANA name                            | Default `UTC`                                                                                     |
| `schedule_start_at` / `schedule_end_at` | ISO 8601                             | Optional bounds; runs outside the window are skipped                                              |
| `schedule_max_runs`                     | int                                  | Optional cap; once reached, the workflow stops being scheduled                                    |
| `schedule_interval_value`               | int                                  | For `interval` type. Minimum effective interval is **60 seconds** even if you set a smaller value |
| `schedule_interval_unit`                | `"minutes"` \| `"hours"` \| `"days"` | For `interval` type. Default `minutes`                                                            |
| `schedule_cron`                         | cron expression                      | For `cron` type. Default `0 * * * *` (top of every hour). croniter syntax                         |

On `/deploy`, the platform reads these from the starter block, normalizes them into `schedule_config` on the workflow row, resets `schedule_run_count` to 0, and the tick worker picks it up. `/undeploy` clears `schedule_config` and stops further scheduled runs.

Scheduled runs execute as if invoked through `/execute`: the starter block's variables get whatever default values are configured (no per-run override is possible from the schedule itself).

## Deployment & Webhooks

Workflows expose two activation modes for their webhook block:

* **Deploy** (`POST /api/workflows/{id}/deploy`) sets `state = "deployed"`. The webhook accepts unlimited calls until you `undeploy`. Use this for production.
* **Arm** (`POST /api/workflows/{id}/arm`) leaves `state = "internal"` but opens a 10-minute window during which the webhook accepts exactly one call. After it fires (or expires), you must arm again. Use this for one-shot tests.

The `webhook_id` and `webhook_secret` live in the **webhook block's config**; they're stored on the block when you add it to the graph. The studio editor mints both client-side when you drag in a webhook block. Neither `/deploy` nor `/arm` returns secrets: `/deploy` returns `{"ok": true, "state": "deployed"}` and `/arm` returns `{"ok": true, "armed_until": "<iso8601>"}`. To retrieve credentials programmatically, fetch the workflow with `GET /api/workflows/{id}` and read them from the webhook block's config.

<Tip>
  **Webhook security**

  Each webhook block has a fixed `webhook_secret` set when the block was created; it does **not** rotate on arm/deploy. External callers include it as a `Bearer` token in the `Authorization` header (preferred) or as a `?token=` query parameter. There is no body-HMAC signature scheme and no replay-window beyond the 10-min arm TTL.
</Tip>

## Next Steps

<CardGroup cols={2}>
  <Card title="Workflows (Programmatic)" href="/guides/workflows-programmatic">
    Build a workflow step by step using the API.
  </Card>

  <Card title="Workflows (Copilot)" href="/guides/workflows-copilot">
    Build a workflow using natural language.
  </Card>

  <Card title="Workflows API Reference" href="/api-reference/workflows">
    Full endpoint documentation.
  </Card>
</CardGroup>
