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

# Build an AI-Powered Workflow with Flowmatic Graphs

> Build a Flowmatic workflow that uses an AI node to process CSV data with a natural language prompt and send personalized emails to matching customers.

Flowmatic's `AI` node lets you describe what you want to do with your data in plain English. Under the hood it sends your prompt — along with the upstream data — to a large language model powered by Groq, then structures the response into named output fields that subsequent nodes can reference. This guide walks you through building a complete workflow that reads a CSV of customers, uses an AI node to identify top raters, and sends each of them a personalized coupon email.

## Prerequisites

Before you begin, make sure you have the following:

<CardGroup cols={2}>
  <Card title="Access Token" icon="key">
    Obtained by calling `POST /api/auth/login`. Pass it as `Authorization: Bearer <accessToken>` on every request.
  </Card>

  <Card title="Upload ID" icon="file-csv">
    An `uploadId` returned after uploading your CSV file. Follow the [Upload Data](/guides/upload-data) guide if you haven't done this yet.
  </Card>
</CardGroup>

<Note>
  The `AI` node requires a Groq API key to be configured on the Flowmatic server. If you are self-hosting, consult the self-hosting setup guide to configure the required Groq API key before starting the server. If you are using Flowmatic Cloud, this is handled for you automatically.
</Note>

## Understanding the AI node

The `AI` node accepts two main configuration fields:

* **`prompt`** — A free-form natural language instruction. You can embed template expressions like `{{ds.rows}}` directly inside the prompt string to inject upstream data at runtime.
* **`output`** — An array of named output field definitions. Each entry specifies a `name` (the key you'll reference downstream) and a `type` (`"string"`, `"array"`, `"number"`, or `"boolean"`). The LLM is instructed to return a JSON object conforming to this schema.

Once the AI node finishes, every field you declared in `output` becomes available as `{{nodeId.fieldName}}` in downstream nodes. For a node with `id: "ai"` and an output field named `customers`, you'd reference the result as `{{ai.customers}}`.

## How template variables work in this workflow

The graph in this guide uses four nodes connected in sequence:

| Node ID | Type         | Role                                                                         |
| ------- | ------------ | ---------------------------------------------------------------------------- |
| `t`     | TRIGGER      | Starts the pipeline                                                          |
| `ds`    | DATA\_SOURCE | Loads CSV rows as `{{ds.rows}}`                                              |
| `ai`    | AI           | Filters and drafts copy; outputs `{{ai.customers}}` and `{{ai.messageBody}}` |
| `out`   | OUTPUT       | Iterates `{{ai.customers}}` and sends one email per item                     |

Inside the `OUTPUT` node's `forEach` loop, `{{item.fieldName}}` refers to a single element of the array being iterated — so `{{item.email}}` and `{{item.name}}` resolve to the email and name of whichever customer is being processed in the current iteration.

## Building the workflow

<Steps>
  <Step title="Authenticate and obtain your access token">
    If you don't already have an access token, log in with your Flowmatic credentials:

    ```bash theme={null}
    curl -X POST https://api.flowmatic.io/api/auth/login \
      -H "Content-Type: application/json" \
      -d '{ "email": "you@example.com", "password": "yourpassword" }'
    ```

    The response contains both an `accessToken` (short-lived) and a `refreshToken` (long-lived):

    ```json theme={null}
    {
      "accessToken": "eyJ...",
      "refreshToken": "eyJ..."
    }
    ```

    Store the `accessToken` in an environment variable for convenience:

    ```bash theme={null}
    export FM_TOKEN="eyJ..."
    ```
  </Step>

  <Step title="Upload your CSV data">
    Upload the customer CSV that the workflow will process. If you've already done this, skip ahead and use your existing `uploadId`.

    ```bash theme={null}
    curl -X POST https://api.flowmatic.io/api/uploads \
      -H "Authorization: Bearer $FM_TOKEN" \
      -F "file=@customers.csv"
    ```

    You'll receive an `uploadId` in return:

    ```json theme={null}
    { "uploadId": "upload_abc123xyz" }
    ```

    Your CSV should include at least `name`, `email`, and `rating` columns:

    ```csv theme={null}
    name,email,rating
    Alice Johnson,alice@example.com,5
    Bob Smith,bob@example.com,3
    Carol White,carol@example.com,5
    ```
  </Step>

  <Step title="Create the workflow">
    With your `uploadId` in hand, submit the full workflow definition. Replace `<your-upload-id>` with the actual value from the previous step.

    ```bash theme={null}
    curl -X POST https://api.flowmatic.io/api/workflows \
      -H "Authorization: Bearer $FM_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Reward top raters",
        "graph": {
          "nodes": [
            { "id": "t",  "type": "TRIGGER",     "data": {} },
            { "id": "ds", "type": "DATA_SOURCE", "data": { "uploadId": "<your-upload-id>" } },
            { "id": "ai", "type": "AI", "data": {
                "prompt": "From these customers pick those who rated above 4 stars. Rows: {{ds.rows}}. Send coupon code SAVE20 for 20% off.",
                "output": [
                  { "name": "customers", "type": "array" },
                  { "name": "messageBody", "type": "string" }
                ]
            }},
            { "id": "out", "type": "OUTPUT", "data": {
                "forEach": "{{ai.customers}}",
                "to": "{{item.email}}",
                "subject": "Thanks {{item.name}}",
                "body": "Hi {{item.name}}, {{ai.messageBody}}"
            }}
          ],
          "edges": [
            { "source": "t",  "target": "ds" },
            { "source": "ds", "target": "ai" },
            { "source": "ai", "target": "out" }
          ]
        }
      }'
    ```

    A successful response returns HTTP `201` with the full workflow object, including a generated `id`:

    ```json theme={null}
    {
      "id": "wf_abc123",
      "name": "Reward top raters",
      "graph": { "nodes": [...], "edges": [...] },
      "createdAt": "2024-06-01T10:00:00Z"
    }
    ```

    Save the workflow `id` — you'll need it to trigger a run.
  </Step>

  <Step title="Run the workflow">
    Trigger an execution by posting to the run endpoint:

    ```bash theme={null}
    curl -X POST https://api.flowmatic.io/api/workflows/wf_abc123/run \
      -H "Authorization: Bearer $FM_TOKEN"
    ```

    The API responds with HTTP `202` and a run identifier:

    ```json theme={null}
    { "runId": "run_xyz789", "status": "PENDING" }
    ```

    The run is now queued. See the [Run & Monitor](/guides/run-and-monitor) guide for instructions on polling for completion and inspecting per-node output.
  </Step>
</Steps>

## Understanding the full JSON body

Here is the complete workflow definition for reference, with annotations explaining each node's role:

```json theme={null}
{
  "name": "Reward top raters",
  "graph": {
    "nodes": [
      { "id": "t",  "type": "TRIGGER",     "data": {} },
      { "id": "ds", "type": "DATA_SOURCE", "data": { "uploadId": "<your-upload-id>" } },
      { "id": "ai", "type": "AI", "data": {
          "prompt": "From these customers pick those who rated above 4 stars. Rows: {{ds.rows}}. Send coupon code SAVE20 for 20% off.",
          "output": [
            { "name": "customers", "type": "array" },
            { "name": "messageBody", "type": "string" }
          ]
      }},
      { "id": "out", "type": "OUTPUT", "data": {
          "forEach": "{{ai.customers}}",
          "to": "{{item.email}}",
          "subject": "Thanks {{item.name}}",
          "body": "Hi {{item.name}}, {{ai.messageBody}}"
      }}
    ],
    "edges": [
      { "source": "t",  "target": "ds" },
      { "source": "ds", "target": "ai" },
      { "source": "ai", "target": "out" }
    ]
  }
}
```

**Node breakdown:**

* **`t` (TRIGGER)** — The entry point of every Flowmatic workflow. It has no configuration and simply starts the execution chain.
* **`ds` (DATA\_SOURCE)** — Fetches the uploaded CSV and exposes all rows as `{{ds.rows}}`, an array of objects where each key corresponds to a CSV column header.
* **`ai` (AI)** — Receives the rows via the prompt template, instructs the LLM to select customers with a rating above 4 and compose a coupon message. It returns two structured fields: `customers` (an array of matching customer objects) and `messageBody` (a string with the promotional copy).
* **`out` (OUTPUT)** — Iterates over `{{ai.customers}}` and sends one email per entry. The `to`, `subject`, and `body` fields each use `{{item.*}}` to personalize each email with data from the current row.

<Tip>
  If you want deterministic filtering without an LLM (for example, in a testing environment or when a Groq API key isn't available), use the `FILTER` node instead. See the [Filter Workflow](/guides/build-filter-workflow) guide for a drop-in alternative that produces the same email-sending behavior using a rule expression.
</Tip>

<Warning>
  Be explicit in your AI node prompt about the expected output format. If the LLM returns a structure that doesn't match the `output` schema you declared, the node will fail and the run will be marked as `FAILED`. Clear, specific prompts yield more reliable structured output.
</Warning>
