Skill: devarogundade/flowfi (version 1.0.3)

--- name: flowfi description: REST API instructions for FlowFi—authorization, smart accounts, workflows (AI generate, edit, deploy, undeploy, delete, pause, resume, stop), execution (list, start, cancel, events), WebSocket (workflow-status namespace, subscribe execution/workflow/simulation), price (token/USD), templates (list, get, clone), DTO/request/response shapes (pagination, workflow, template, execution), and workflow knowledge base. Use when integrating with the backend API or when the user asks about workflow, execution, real-time, price, templates, DTOs, or auth endpoints. --- # FlowFi OpenClaw skill Instructions for the **FlowFi** backend API. Base URL is the backend API root (e.g. `https://api.seimoney.link`). Protected routes use **JWT** via `Authorization: Bearer <token>`. **Grouped docs** (content split by topic): | Topic | File | |-------|------| | Authorization | [docs/authorization.md](docs/authorization.md) | | Smart accounts | [docs/smart-accounts.md](docs/smart-accounts.md) | | AI workflows (generate, suggestions, edit by prompt) | [docs/ai-workflows.md](docs/ai-workflows.md) | | Workflows (lifecycle, deploy/undeploy/pause/resume/stop/delete, list, draft) | [docs/workflows.md](docs/workflows.md) | | DTOs & request/response shapes | [docs/dto.md](docs/dto.md) | | Execution (REST) | [docs/execution.md](docs/execution.md) | | WebSocket (real-time) | [docs/websocket.md](docs/websocket.md) | | Price | [docs/price.md](docs/price.md) | | Templates | [docs/templates.md](docs/templates.md) | | Endpoint summary table | [docs/summary.md](docs/summary.md) | See **[docs/README.md](docs/README.md)** for the full index. **Quick entry points:** Generate workflow → `POST /ai/generate-workflow` (prompt + smartAccountId). Deploy → `POST /workflows/:id/deploy`. List workflows → `GET /workflows`. Real-time → WebSocket namespace `/workflow-status`; subscribe to execution/workflow/simulation.

path: README.md
content: # OpenClaw

OpenClaw provides skills and instructions for integrating with the **FlowFi** backend API. Use it when you need to call FlowFi workflows, smart accounts, or auth endpoints (e.g. from an agent or external client).

## How it works

- The **user** generates a JWT (e.g. via the FlowFi app or auth flow) and sends it to OpenClaw.
- OpenClaw uses that token in the `Authorization: Bearer <token>` header for all FlowFi API requests.

---

## How to generate a workflow with AI

1. **Get a smart account ID** — `GET /smart-accounts` (with JWT). Use one of the returned `id` values.
2. **Generate from a prompt** — `POST /ai/generate-workflow` with JSON body:
   - `prompt` (required): natural-language description, e.g. *"When ETH price goes above 3500, send me a Telegram message"*
   - `smartAccountId` (required): the smart account ID from step 1
3. The API returns the new workflow (`id`, `name`, `nodes`, `connections`) in **draft** status.

---

## What to do next

| Goal | What to do |
|------|------------|
| **Run the workflow** | **Deploy** — `POST /workflows/:id/deploy`. Status becomes **active**; it runs on its triggers/schedule. |
| **Change the workflow** | **Undeploy** first if it’s active or paused: `POST /workflows/:id/undeploy`. Then **edit by prompt**: `POST /ai/workflow/:id/prompt` or `PATCH /workflows/:id`. |
| **Get AI edit ideas** | `GET /ai/workflow/:id/suggestions` — returns short suggestions (e.g. "Add a delay", "Add a notification"). |
| **Pause running** | `POST /workflows/:id/pause`. Resume with `POST /workflows/:id/resume`. |
| **Stop and make editable** | `POST /workflows/:id/undeploy` — status goes back to **draft**. |
| **End the workflow** | `POST /workflows/:id/stop` — status **ended**; no more runs (you can deploy again later). |
| **Remove permanently** | **Delete** — `DELETE /workflows/:id`. Safe for any status; backend stops the scheduler if needed. |
| **List workflows** | `GET /workflows` with optional `?status=draft`, `?smartAccountId=...`, pagination. |
| **Run once / watch runs** | **Start run** — `POST /executions/workflows/:workflowId/start`. **List runs** — `GET /executions` or `GET /executions/workflows/:workflowId`. **Real-time** — WebSocket namespace `/workflow-status`; subscribe to `execution` or `workflow` for live status and history refresh. |
| **Start from a template** | **List** — `GET /templates` or `GET /templates/categories`. **Clone** — `POST /templates/:id/clone` with `smartAccountId` (and optional `name`, `network`) to create a **draft** workflow; then edit and deploy. |

---

## Capabilities summary

- **Smart accounts** — List and get smart accounts; use an account `id` as `smartAccountId` when creating workflows.
- **Workflows** — Generate with AI, get suggestions, edit by prompt, **deploy**, **undeploy**, **pause**, **resume**, **stop**, **delete**, list.
- **Execution** — List runs (all or by workflow), **start** a run, get one execution, **cancel**, get **events** (and per-node events).
- **WebSocket** — Real-time updates: connect to namespace `/workflow-status` with JWT; **subscribe** to execution, workflow, or simulation to receive status and node updates (and `workflow:update` / `workflow:history:refresh`).
- **Price** — **GET** `/price?symbol=BNB` (one token USD price); **GET** `/price/prices` (BNB + ETH). No auth.
- **Templates** — **GET** `/templates` (list with filters), `/templates/display`, `/templates/categories`, `/templates/:id` (full); **POST** `/templates/:id/clone` (JWT) creates a draft workflow from a template.
- **Knowledge** — The backend uses a workflow knowledge base (valid node types, structure) for AI generation; no API to fetch it; see [SKILL.md](SKILL.md#knowledge-workflow-generation) for prompt tips and node types. Templates follow the same structure; use templates for starting points.
- **Auth** — Long-lived bearer tokens and revoke (sign-in is done by the user outside OpenClaw).

---

## API reference

Full REST API details, **request/response DTOs** (pagination, auth, AI/workflows, templates, execution, price, error shape), and example prompts are in **[SKILL.md](SKILL.md)**. See the **DTO and request/response shapes** section for exact JSON request bodies and response types.

Quick reference:

| Action | Method | Endpoint |
|--------|--------|----------|
| List smart accounts | GET | `/smart-accounts` |
| Generate workflow (AI) | POST | `/ai/generate-workflow` |
| Get suggestions | GET | `/ai/workflow/:id/suggestions` |
| Edit by prompt | POST | `/ai/workflow/:id/prompt` |
| Deploy | POST | `/workflows/:id/deploy` |
| Undeploy | POST | `/workflows/:id/undeploy` |
| Delete | DELETE | `/workflows/:id` |
| Pause | POST | `/workflows/:id/pause` |
| Resume | POST | `/workflows/:id/resume` |
| Stop | POST | `/workflows/:id/stop` |
| List workflows | GET | `/workflows` |
| **Execution** | | |
| List executions | GET | `/executions` |
| Start execution | POST | `/executions/workflows/:workflowId/start` |
| List workflow runs | GET | `/executions/workflows/:workflowId` |
| Get execution | GET | `/executions/:id` |
| Cancel execution | DELETE | `/executions/:id/cancel` |
| Execution events | GET | `/executions/:id/events` |
| Node events | GET | `/executions/:id/events/node/:nodeId` |
| **Price** | | |
| Token price | GET | `/price?symbol=BNB` (no auth). Response: `{ symbol, priceUsd }`. |
| BNB/ETH prices | GET | `/price/prices` (no auth). Response: `{ BNB, ETH }` (strings). |
| **Templates** | | |
| List templates | GET | `/templates` (no auth) |
| Display info | GET | `/templates/display` (no auth) |
| By category | GET | `/templates/categories` (no auth) |
| Get template | GET | `/templates/:id` (no auth) |
| Clone template | POST | `/templates/:id/clone` |

**WebSocket:** Connect to `/workflow-status` with JWT in `auth.token` or query `token`. Subscribe with `subscribe:execution`, `subscribe:workflow`, or `subscribe:simulation` (body: `{ executionId }`, `{ workflowId }`, `{ simulationId }`). You receive `execution:status`, `execution:node-status`, `workflow:update`, `workflow:history:refresh`, and simulation events. See [SKILL.md](SKILL.md) for full event list and optional client `workflow:update` to push edits.

**Knowledge:** AI generation uses a server-side workflow knowledge base (valid node types and structure). See [SKILL.md – Knowledge](SKILL.md#knowledge-workflow-generation) for how to craft better prompts and which node types exist.

Base URL is your FlowFi backend (e.g. `https://api.flowfi.com`).


path: docs/ai-workflows.md
content: # AI workflows

## Generate workflow

**POST** `/ai/generate-workflow`

Creates a new workflow from a natural-language prompt using AI. The workflow is created in the database with status **draft**.

**Request body (JSON):**

| Field           | Type   | Required | Description                          |
|----------------|--------|----------|--------------------------------------|
| `prompt`       | string | yes      | User description of the workflow     |
| `smartAccountId` | string | yes    | Smart account ID to attach           |

**Example:**

```json
{
  "prompt": "When ETH price drops below 2000, send a Telegram notification",
  "smartAccountId": "0x..."
}
```

**Response:** `200` — workflow object with `id`, `name`, `nodes`, `connections`.

---

## Get workflow suggestions

**GET** `/ai/workflow/:id/suggestions`

Returns AI-generated edit suggestions for a workflow (e.g. four short actionable edit ideas). Used by "Edit workflow with AI" UI.

**Path:** `id` = workflow ID (owner must match authenticated user).

**Response:** `200` — `{ "suggestions": string[] }` (e.g. 4 suggestion strings).

---

## Edit workflow by prompt

**POST** `/ai/workflow/:id/prompt`

Edits an existing workflow using a natural-language prompt. Updates name, nodes, connections, and variables. Workflow must be **draft** (undeploy first if deployed).

**Path:** `id` = workflow ID.

**Request body (JSON):**

| Field   | Type   | Required | Description                    |
|--------|--------|----------|--------------------------------|
| `prompt` | string | yes     | Edit instruction (e.g. "Add a 5s delay") |

**Response:** `200` — `{ "message": string, "workflow": Workflow }`.


path: docs/authorization.md
content: # Authorization

The user generates a JWT (e.g. via the app) and sends it to OpenClaw. Use that token for all API calls below.

**Long-lived API token (bearer):** **POST** `/auth/bearer-token`  
Requires existing JWT in `Authorization: Bearer <token>`.

| Field              | Type   | Required | Description        |
|--------------------|--------|----------|--------------------|
| `expiresInSeconds` | number | yes      | 60–31536000 (1 yr) |

Response: new JWT to use as `Authorization: Bearer <token>` for API clients.

**Revoke all bearer tokens:** **POST** `/auth/bearer-token/revoke` (with JWT). Session sign-in tokens are not affected.

**Using the token:** For all protected routes, send header:  
`Authorization: Bearer <your-jwt>`.


path: docs/dto.md
content: # DTO and request/response shapes

Use these shapes when building requests or parsing responses. All request bodies are JSON; responses are JSON unless noted.

## Pagination (query + list responses)

**Query params** (where supported: workflows, smart-accounts, executions, templates, comments, execution events):

| Param     | Type   | Default | Description                          |
|----------|--------|--------|--------------------------------------|
| `page`   | number | 1      | Page index (min 1)                   |
| `limit`  | number | 10     | Items per page (1–100)               |
| `sortBy` | string | —      | Field to sort by                     |
| `sortOrder` | string | DESC | `ASC` or `DESC`                     |
| `search` | string | —      | Search term (where supported)        |

**Paginated response:** `{ data: T[], meta: { page, limit, total, totalPages, hasNext, hasPrev } }`.

## Auth

**POST /auth/bearer-token**  
Request: `{ expiresInSeconds: number }` (60–31536000).  
Response: `{ [REDACTED_SECRET], expiresAt?: number }` — use `token` as `Authorization: Bearer <token>`.

## AI / workflows

**POST /ai/generate-workflow**  
Request: `{ prompt: string, smartAccountId: string }`.  
Response: workflow object (see Workflow below).

**POST /ai/workflow/:id/prompt**  
Request: `{ prompt: string }`.  
Response: `{ message: string, workflow: Workflow }`.

**GET /ai/workflow/:id/suggestions**  
Response: `{ suggestions: string[] }`.

**POST /workflows** (create workflow manually)  
Request: `{ name: string, nodes: WorkflowNode[], connections: Connection[], variables?: WorkflowVariable[], smartAccountId: string, config?: WorkflowConfig }`.  
- **WorkflowNode:** `{ id, definitionId, type: "settings"|"node", title, x, y, config?: Record<string, string> }`.  
- **Connection:** `{ id, fromNode, fromPort, toNode, toPort }`.  
- **WorkflowVariable:** `{ key, value, defaultValue?, description? }`.  
Response: workflow object.

**PATCH /workflows/:id**  
Request: partial `{ name?, nodes?, connections?, variables? }`. Do not send `status`; use deploy/undeploy/pause/resume.  
Response: workflow object.

**POST /workflows/:id/variables**  
Request: `{ key: string, value?: string, defaultValue?: string, description?: string }`. **Important:** `key` must start with `"user."` (e.g. `user.threshold`).  
Response: updated variables or success.

## Workflow (response shape)

Workflow object: `{ id, name, status, nodes, connections, variables?, config?, smartAccountId, commentCount?, executionCount?, createdAt, updatedAt }`.  
- **status:** `"draft" | "active" | "paused" | "archived" | "ended"`.  
- **nodes:** array of WorkflowNode.  
- **connections:** array of Connection.

## Templates

**GET /templates** (and **GET /templates/display**)  
Response: `{ data: TemplateDisplayInfo[], meta }` (list) or `TemplateDisplayInfo[]` (display).  
**TemplateDisplayInfo:** `{ id, name, description, category, uses, steps, setupTime, price, nodeCount, connectionCount, featured? }`.

**GET /templates/:id**  
Response: full template `{ id, name, description, category, nodes, connections, variables?, uses, steps, setupTime, price, featured? }`.

**POST /templates/:id/clone**  
Request: `{ smartAccountId: string, name?: string, network?: string }`.  
Response: created workflow (draft).

## Execution

**POST /executions/workflows/:workflowId/start**  
Response: execution object `{ id, workflowId, status, startedAt, completedAt?, error?, result? }`. **status:** `"pending" | "running" | "completed" | "failed" | "cancelled"`.

**GET /executions**, **GET /executions/workflows/:workflowId**  
Response: `{ data: Execution[], meta }`.

**GET /executions/:id/events**  
Response: `{ data: ExecutionEvent[], meta }`. Event: `{ id, executionId, eventType, level, message, nodeId?, nodeDefinitionId?, metadata?, createdAt }`.

## Price (no auth)

**GET /price**  
Query: `symbol?: string` (e.g. `BNB`, `ETH`, `BTC`; default `BNB`).  
Response: **TokenPriceResponse** — `{ symbol: string, priceUsd: string }`. `priceUsd` is `"0"` on failure.

**GET /price/prices**  
No request body or query.  
Response: **TokenPricesResponse** — `{ BNB: string, ETH: string }`. USD prices as strings.

## Errors

API errors: `{ statusCode: number, message: string, error?: string }`. Use `statusCode` for HTTP status; `message` for user-facing text.


path: docs/execution.md
content: # Execution (REST)

Workflow runs (executions) and their events. All require JWT.

**List all executions for the user:** **GET** `/executions`  
Query: `page`, `limit`, `sortBy`, `sortOrder`, `status`.

**Start a run:** **POST** `/executions/workflows/:workflowId/start`  
Starts one execution of an **active** workflow. Returns the created execution.

**List executions for a workflow:** **GET** `/executions/workflows/:workflowId`  
Query: `page`, `limit`, `sortBy`, `sortOrder`, `search`, `status`.

**Get one execution:** **GET** `/executions/:id`

**Cancel a running execution:** **DELETE** `/executions/:id/cancel`

**Get events for an execution:** **GET** `/executions/:id/events`  
Query: `page`, `limit`, `sortBy`, `sortOrder`, `search`, `eventType`, `level`. Returns execution events (e.g. node start/complete, errors).

**Get events for a specific node in an execution:** **GET** `/executions/:id/events/node/:nodeId`


path: docs/price.md
content: # Price

Token prices in USD (e.g. for display, billing, or workflow logic). **No auth required** — both endpoints are public.

| Method | Endpoint | Description | Response |
|--------|----------|-------------|----------|
| GET | `/price` | One token price in USD | `TokenPriceResponse` |
| GET | `/price/prices` | BNB and ETH prices in USD | `TokenPricesResponse` |

**GET /price**

Query: `symbol` (optional, string). Token symbol, e.g. `BNB`, `ETH`, `BTC`. Default `BNB`.

**Response (200):** `TokenPriceResponse` — `{ symbol: string, priceUsd: string }`. Uses cached CoinMarketCap; returns `priceUsd: "0"` on failure.

**GET /price/prices**

No query or body.

**Response (200):** `TokenPricesResponse` — `{ BNB: string, ETH: string }`. USD prices as strings. Used by builder/billing UIs.


path: docs/README.md
content: # FlowFi OpenClaw — grouped docs

Content is split by topic. Links are relative to this folder.

| Doc | Content |
|-----|--------|
| [authorization.md](authorization.md) | JWT, bearer token, revoke, using the token |
| [smart-accounts.md](smart-accounts.md) | List/get smart accounts, workflow count |
| [ai-workflows.md](ai-workflows.md) | Generate workflow, suggestions, edit by prompt |
| [workflows.md](workflows.md) | Workflow API, lifecycle, deploy/undeploy/pause/resume/stop/delete, list, draft |
| [dto.md](dto.md) | Pagination, auth/workflow/template/execution/price DTOs, errors |
| [execution.md](execution.md) | Executions REST: list, start, cancel, events |
| [websocket.md](websocket.md) | Real-time: namespace, subscribe, server events, client workflow:update |
| [price.md](price.md) | Token price, BNB/ETH prices (no auth) |
| [templates.md](templates.md) | List, display, categories, get, clone |
| [knowledge.md](knowledge.md) | Workflow knowledge base, node types, structure |
| [summary.md](summary.md) | Full endpoint summary table |


path: docs/smart-accounts.md
content: # Smart accounts

**List smart accounts:** **GET** `/smart-accounts`  
Requires JWT. Returns smart accounts for the authenticated user. Supports pagination: `page`, `limit`, `sortBy`, `sortOrder`, `search` (query params).

**Get one smart account:** **GET** `/smart-accounts/:id`  
Requires JWT. User must own the smart account.

**Get workflow count for a smart account:** **GET** `/smart-accounts/:id/workflows/count`  
Response: `{ "count": number }`.

Use a smart account `id` from these endpoints as `smartAccountId` when calling `POST /ai/generate-workflow` or creating workflows.


path: docs/summary.md
content: # Summary

| Action                | Method | Endpoint                              |
|-----------------------|--------|----------------------------------------|
| Bearer token          | POST   | `/auth/bearer-token`                   |
| List smart accounts   | GET    | `/smart-accounts`                      |
| Get smart account     | GET    | `/smart-accounts/:id`                  |
| Workflow count        | GET    | `/smart-accounts/:id/workflows/count`  |
| Generate workflow     | POST   | `/ai/generate-workflow`                |
| Get suggestions       | GET    | `/ai/workflow/:id/suggestions`         |
| Edit by prompt        | POST   | `/ai/workflow/:id/prompt`              |
| Deploy                | POST   | `/workflows/:id/deploy`                |
| Undeploy              | POST   | `/workflows/:id/undeploy`              |
| Delete                | DELETE | `/workflows/:id`                      |
| Pause                 | POST   | `/workflows/:id/pause`                |
| Resume                | POST   | `/workflows/:id/resume`                |
| Stop                  | POST   | `/workflows/:id/stop`                 |
| List workflows        | GET    | `/workflows`                          |
| List executions       | GET    | `/executions`                         |
| Start execution       | POST   | `/executions/workflows/:workflowId/start` |
| List workflow runs    | GET    | `/executions/workflows/:workflowId`   |
| Get execution        | GET    | `/executions/:id`                    |
| Cancel execution      | DELETE | `/executions/:id/cancel`              |
| Execution events     | GET    | `/executions/:id/events`             |
| Node events          | GET    | `/executions/:id/events/node/:nodeId` |
| Token price          | GET    | `/price?symbol=BNB` (no auth)         |
| BNB/ETH prices       | GET    | `/price/prices` (no auth)             |
| List templates       | GET    | `/templates` (no auth)                |
| Display info         | GET    | `/templates/display` (no auth)        |
| By category          | GET    | `/templates/categories` (no auth)     |
| Get template         | GET    | `/templates/:id` (no auth)            |
| Clone template       | POST   | `/templates/:id/clone`                 |

**WebSocket:** Connect to namespace `/workflow-status` with JWT; use `subscribe:execution`, `subscribe:workflow`, `subscribe:simulation` (and unsubscribe) for real-time execution/workflow/simulation updates.

**Knowledge:** Workflow AI uses a server-side knowledge base (valid node types and structure); see [Knowledge](knowledge.md). No API to fetch it. **Templates** are pre-built workflows (same structure); list via `GET /templates` or `GET /templates/categories`; clone via `POST /templates/:id/clone` to create a draft.

Protected REST routes require `Authorization: Bearer <jwt>`. User is inferred from JWT; workflow and smart-account ownership is enforced by `smartAccountAddress` / `userId`.


path: docs/templates.md
content: # Templates

Pre-built workflow templates. List and get are **public** (no auth); **clone** requires JWT and creates a new **draft** workflow from a template.

**List templates:** **GET** `/templates`

Query: `page`, `limit`, `sortBy`, `sortOrder`, `search`, `category`, `featured` (boolean string), `minPrice`, `maxPrice`. Returns `{ data: TemplateDisplayInfo[], meta }` — display info only (no `nodes`/`connections`/`variables`). Each item: `id`, `name`, `description`, `category`, `uses`, `steps`, `setupTime`, `price`, `featured`, `nodeCount`, `connectionCount`.

**All templates (display only):** **GET** `/templates/display`  
Returns array of template display info (no nodes/connections/variables).

**Templates by category:** **GET** `/templates/categories`  
Returns `Record<category, TemplateDisplayInfo[]>` (templates grouped by category).

**Get one template (full):** **GET** `/templates/:id`  
Returns full template including `nodes`, `connections`, `variables` (for preview or clone). No auth.

**Clone template:** **POST** `/templates/:id/clone`  
Requires JWT. Creates a new workflow in **draft** from the template, attached to the given smart account.

**Request body (JSON):**

| Field           | Type   | Required | Description                          |
|----------------|--------|----------|--------------------------------------|
| `smartAccountId` | string | yes    | Smart account to attach the new workflow to |
| `name`         | string | no       | Workflow name (default: template name + " - Copy") |
| `network`      | string | no       | Network for settings (e.g. bsc, ethereum) |

**Response:** `200` — the created workflow (draft). Template `uses` count is incremented.

**Template knowledge:** Templates follow the same workflow structure as the workflow knowledge base (settings → trigger → nodes, valid definitionIds). Use `GET /templates` or `GET /templates/categories` to discover template IDs and categories; cloning gives users a starting point they can then edit via `POST /ai/workflow/:id/prompt` or `PATCH /workflows/:id` and deploy.


path: docs/websocket.md
content: # WebSocket (real-time)

**Namespace:** `/workflow-status` (e.g. `wss://api.example.com/workflow-status`).

**Authentication:** Connect with JWT in handshake:
- `auth.token` or query `token`. Invalid/missing token disconnects.

**Subscribe (client → server):**

| Message (event) | Body | Effect |
|-----------------|------|--------|
| `subscribe:execution` | `{ executionId: string }` | Join room for this execution; receive `execution:status`, `execution:node-status`. |
| `unsubscribe:execution` | `{ executionId?: string }` | Leave room. |
| `subscribe:workflow` | `{ workflowId: string }` | Join room for workflow; receive `workflow:update`, `workflow:history:refresh`. |
| `unsubscribe:workflow` | `{ workflowId?: string }` | Leave room. |
| `subscribe:simulation` | `{ simulationId: string }` | Join room for simulation; receive `simulation:status`, `simulation:node-status`. |
| `unsubscribe:simulation` | `{ simulationId?: string }` | Leave room. |

**Server → client events:**

| Event | When | Payload |
|-------|------|---------|
| `execution:status` | Execution state changes | `{ executionId, status, progress?, timestamp?, ... }` |
| `execution:node-status` | Node starts/completes in a run | `{ executionId, nodeId, ... }` |
| `workflow:update` | Workflow nodes/connections/name/variables updated (e.g. after edit) | `{ type: 'updated', workflow, changes, timestamp }` |
| `workflow:history:refresh` | Execution list for workflow changed (e.g. new run started/finished) | `{ executionId?, reason? }` |
| `simulation:status` | Simulation state | `{ simulationId, ... }` |
| `simulation:node-status` | Simulation node step | `{ simulationId, nodeId, ... }` |

**Client can push workflow edits over WebSocket:**  
Send `workflow:update` with body `{ workflowId, update: { nodes?, connections?, name?, variables? } }`. Server persists and broadcasts to other subscribers; response `{ success, message? }` or `{ success: false, error }`.


path: docs/workflows.md
content: # Workflow REST API

Instructions for FlowFi REST endpoints. Base URL is the backend API root (e.g. `https://api.seimoney.link`). Workflow and smart-account endpoints require **JWT** (see [Authorization](authorization.md)).

## How to generate a workflow with AI

1. **Get a smart account ID** — Call `GET /smart-accounts` (with JWT). Pick an account `id` to attach the workflow to.
2. **Generate from a natural-language prompt** — Call `POST /ai/generate-workflow` with JSON body:
   - `prompt` (required): user description, e.g. "When ETH price goes above 3500, send me a Telegram message"
   - `smartAccountId` (required): the smart account ID from step 1
3. **Response** — Returns the new workflow object with `id`, `name`, `nodes`, `connections`. The workflow is created in **draft** status.

**Example request:**

```json
POST /ai/generate-workflow
{
  "prompt": "When ETH price drops below 2000, send a Telegram notification",
  "smartAccountId": "0x..."
}
```

---

## What to do next (workflow lifecycle)

| Goal | Action |
|------|--------|
| **Run the workflow** | Deploy it: `POST /workflows/:id/deploy`. Workflow becomes **active** and runs on its triggers/schedule. |
| **Change the workflow** | If it's **active** or **paused**, call `POST /workflows/:id/undeploy` first. Then use `POST /ai/workflow/:id/prompt` (or `PATCH /workflows/:id`) to edit. |
| **Get AI edit ideas** | `GET /ai/workflow/:id/suggestions` returns short suggestions (e.g. "Add a delay", "Add a notification"). |
| **Apply an edit with AI** | `POST /ai/workflow/:id/prompt` with a prompt like "Add a 10 second delay after the price check". Workflow must be **draft** (undeploy first if deployed). |
| **Temporarily stop running** | `POST /workflows/:id/pause` (active → paused). Resume with `POST /workflows/:id/resume`. |
| **Stop and make editable again** | `POST /workflows/:id/undeploy` (active/paused/ended → draft). |
| **End the workflow** | `POST /workflows/:id/stop` (sets status to **ended**; no more runs). Can deploy again later. |
| **Remove the workflow permanently** | `DELETE /workflows/:id`. Safe for any status (backend stops scheduler if needed). |

---

## Capabilities (quick reference)

- **List smart accounts** — `GET /smart-accounts`; use an `id` as `smartAccountId` when generating workflows.
- **Generate workflow with AI** — `POST /ai/generate-workflow` with `prompt` and `smartAccountId`; creates a **draft**.
- **Get edit suggestions** — `GET /ai/workflow/:id/suggestions` for short AI edit ideas.
- **Edit by prompt** — `POST /ai/workflow/:id/prompt`; workflow must be **draft** (undeploy first if deployed).
- **Deploy** — `POST /workflows/:id/deploy` → draft/ended becomes **active** and runnable.
- **Undeploy** — `POST /workflows/:id/undeploy` → back to **draft** so you can edit.
- **Pause / Resume** — `POST /workflows/:id/pause`, `POST /workflows/:id/resume` (active ↔ paused).
- **Stop** — `POST /workflows/:id/stop` → **ended** (no more runs; can deploy again later).
- **Delete** — `DELETE /workflows/:id` removes the workflow permanently (any status).
- **List workflows** — `GET /workflows` with optional `?status=draft`, `?smartAccountId=...`, pagination.
- **Price** — `GET /price?symbol=BNB` (one token USD price, no auth); `GET /price/prices` (BNB + ETH, no auth).
- **Templates** — `GET /templates` (list, no auth), `GET /templates/display`, `GET /templates/categories`, `GET /templates/:id` (full); `POST /templates/:id/clone` (JWT) creates a draft workflow.

## Example prompts

**Generate workflow** (`POST /ai/generate-workflow` body `prompt`):

- "When ETH price goes above 3500, send me a Telegram message"
- "Every day at 9am, check Uniswap for WETH/USDC and post the price to Discord"
- "If gas is below 20 gwei, run a swap on Uniswap and notify me on Telegram"

**Edit workflow** (`POST /ai/workflow/:id/prompt` body `prompt`):

- "Add a 10 second delay after the price check"
- "Change the threshold to 4000"
- "Add an email notification when the workflow runs"

---

## Deploy workflow

**POST** `/workflows/:id/deploy`

Deploys a workflow so it can run (schedule/triggers). Workflow must be **draft** or **ended**; must have a smart account assigned.

**Path:** `id` = workflow ID.

**Response:** `200` — updated workflow (e.g. `status: 'active'`).

**Errors:** `400` if already deployed or missing smart account.

---

## Undeploy workflow

**POST** `/workflows/:id/undeploy`

Stops a deployed workflow and sets status back to **draft**. Required before editing a deployed workflow.

**Path:** `id` = workflow ID.

**Response:** `200` — updated workflow (`status: 'draft'`).

**Errors:** `400` if workflow is not deployed (e.g. already draft or archived).

---

## Delete workflow

**DELETE** `/workflows/:id`

Permanently removes a workflow. Safe for any status: if the workflow is **active**, **paused**, or **ended**, the backend stops the scheduler first, then deletes the workflow and its variables.

**Path:** `id` = workflow ID (owner must match authenticated user).

**Response:** `200` with no body on success.

---

## Pause workflow

**POST** `/workflows/:id/pause`

Temporarily stops a running workflow (active → paused). Triggers/schedule will not run until resumed.

**Path:** `id` = workflow ID.

**Response:** `200` — updated workflow (`status: 'paused'`).

**Errors:** `400` if workflow is not active.

---

## Resume workflow

**POST** `/workflows/:id/resume`

Resumes a paused workflow (paused → active).

**Path:** `id` = workflow ID.

**Response:** `200` — updated workflow (`status: 'active'`).

**Errors:** `400` if workflow is not paused.

---

## Stop workflow

**POST** `/workflows/:id/stop`

Stops the workflow and sets status to **ended**. No more runs; scheduler is stopped. You can deploy again later to reactivate.

**Path:** `id` = workflow ID.

**Response:** `200` — updated workflow (`status: 'ended'`).

**Errors:** `400` if workflow is draft or archived (not running).

---

## List workflows

**GET** `/workflows`

Returns workflows for the authenticated user. Supports query params: `status` (e.g. `draft`, `active`), `smartAccountId`, `page`, `limit`, `sortBy`, `sortOrder`, `search`.

---

## Draft workflows

- **Creating a draft:** `POST /ai/generate-workflow` and `POST /workflows` both create workflows with status **draft**.
- **Listing drafts:** `GET /workflows?status=draft` (optional query).
- **Editing:** Only draft (or ended) workflows can be edited. Use `POST /ai/workflow/:id/prompt` or `PATCH /workflows/:id` for draft workflows.
- **Deploy:** When ready, call `POST /workflows/:id/deploy` to move from draft to active.


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)