# Create flow

> Create a new flow for an agent.

`POST https://api.zavu.dev/v1/senders/{senderId}/agent/flows`

Create a new flow for an agent.

## Parameters

- `senderId` (path, string, required)

## Body

- `name` (string, required)
- `description` (string)
- `trigger` (object, required)
  - `type` (string, required): What starts a flow. - `keyword`: the message contains one of the words listed in `keywords`. Plain substring matching, so a word inside another word still counts. - `intent`: the message MEANS what `intent` describes, whatever words it uses. - `always`: any message starts it. - `manual`: reserved. Nothing starts a `manual` flow today — it is accepted and stored, and no message or endpoint runs it. One of: `keyword`, `intent`, `always`, `manual`.
  - `keywords` (string[]): Words that start the flow, for `keyword` triggers. Matched as substrings, case-insensitively, against the whole message: a flow on `info` also starts on "no quiero info". Use `intent` when that matters.
  - `intent` (string): One plain sentence describing what the contact wants, for `intent` triggers. Any language. The message is judged for meaning, not for words, so "kiero saber el presio" starts a flow whose intent is "quiere saber precios o cotizar", and "no quiero info de precios" starts nothing. A `keyword` or `always` flow with a higher `priority` is matched first and wins. At most 12 intent flows are considered per message, highest priority first. When the classification is unavailable or uncertain, the message is handled as if no intent matched, so a flow never starts on a guess.
- `steps` (object[], required): The first step runs on the message that started the flow. It cannot be a `condition` without a `defaultGoto`: nothing has been collected yet, so its conditions evaluate the same way on every message, and the request is refused with `400 invalid_request`. A flow that ends on that first message without replying hands the message to the agent, which answers it. A `transfer` step stays silent.
  - `id` (string, required): Unique step identifier.
  - `type` (string, required): Type of flow step. One of: `message`, `collect`, `condition`, `tool`, `llm`, `transfer`.
  - `config` (object, required): Step configuration (varies by type).
  - `nextStepId` (string, nullable): ID of the next step to execute.
- `enabled` (boolean)
- `priority` (integer)

## Responses

### 201

Flow created.

- `flow` (object, required)
  - `id` (string, required)
  - `agentId` (string, required)
  - `name` (string, required)
  - `description` (string, nullable)
  - `trigger` (object, required)
    - `type` (string, required): What starts a flow. - `keyword`: the message contains one of the words listed in `keywords`. Plain substring matching, so a word inside another word still counts. - `intent`: the message MEANS what `intent` describes, whatever words it uses. - `always`: any message starts it. - `manual`: reserved. Nothing starts a `manual` flow today — it is accepted and stored, and no message or endpoint runs it. One of: `keyword`, `intent`, `always`, `manual`.
    - `keywords` (string[]): Words that start the flow, for `keyword` triggers. Matched as substrings, case-insensitively, against the whole message: a flow on `info` also starts on "no quiero info". Use `intent` when that matters.
    - `intent` (string): One plain sentence describing what the contact wants, for `intent` triggers. Any language. The message is judged for meaning, not for words, so "kiero saber el presio" starts a flow whose intent is "quiere saber precios o cotizar", and "no quiero info de precios" starts nothing. A `keyword` or `always` flow with a higher `priority` is matched first and wins. At most 12 intent flows are considered per message, highest priority first. When the classification is unavailable or uncertain, the message is handled as if no intent matched, so a flow never starts on a guess.
  - `steps` (object[], required)
    - `id` (string, required): Unique step identifier.
    - `type` (string, required): Type of flow step. One of: `message`, `collect`, `condition`, `tool`, `llm`, `transfer`.
    - `config` (object, required): Step configuration (varies by type).
    - `nextStepId` (string, nullable): ID of the next step to execute.
  - `enabled` (boolean, required)
  - `priority` (integer, required): Priority when multiple flows match (higher = more priority).
  - `createdAt` (string<date-time>, required)
  - `updatedAt` (string<date-time>, required)

### 400

Invalid request.

- `code` (string, required)
- `message` (string, required)
- `details` (object)

### 401

Unauthorized.

- `code` (string, required)
- `message` (string, required)
- `details` (object)

### 404

Agent not found.

- `code` (string, required)
- `message` (string, required)
- `details` (object)

## Example

```bash
curl -X POST "https://api.zavu.dev/v1/senders/sender_abc123/agent/flows" \
  -H "Authorization: Bearer $ZAVUDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Lead Capture",
  "description": "Capture lead information",
  "trigger": {
    "type": "keyword",
    "keywords": [
      "info",
      "pricing",
      "demo"
    ]
  },
  "steps": [
    {
      "id": "welcome",
      "type": "message",
      "config": {
        "text": "Thanks for your interest! Let me get some info."
      },
      "nextStepId": "ask_name"
    },
    {
      "id": "ask_name",
      "type": "collect",
      "config": {
        "variable": "name",
        "prompt": "What'\''s your name?"
      }
    }
  ]
}'
```

```typescript
import Zavudev from "@zavudev/sdk";

const zavu = new Zavudev({ apiKey: process.env.ZAVUDEV_API_KEY });

const result = await zavu.senders.agent.flows.create("sender_abc123", {
  name: "Lead Capture",
  description: "Capture lead information",
  trigger: {
    type: "keyword",
    keywords: [
      "info",
      "pricing",
      "demo",
    ],
  },
  steps: [
    {
      id: "welcome",
      type: "message",
      config: {
        text: "Thanks for your interest! Let me get some info.",
      },
      nextStepId: "ask_name",
    },
    {
      id: "ask_name",
      type: "collect",
      config: {
        variable: "name",
        prompt: "What's your name?",
      },
    },
  ],
});

console.log(result);
```
