---
title: "Create flow"
method: POST
path: "/v1/senders/{senderId}/agent/flows"
tags: ["Agent Flows"]
---

# Create flow

`POST /v1/senders/{senderId}/agent/flows`

## Request

- Base URL: `https://api.zavu.dev`
- URL: `https://api.zavu.dev/v1/senders/{senderId}/agent/flows`
- Auth: HTTP bearer

Create a new flow for an agent.

## Path parameters

- `senderId` string, required

## Request body

- FlowCreateRequest
  - `name` string, required
  - `description` string
  - `trigger` FlowTrigger, required
    - `type` 'keyword' | 'intent' | 'always' | 'manual', 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.
    - `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` FlowStep[], 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` 'message' | 'collect' | 'condition' | 'tool' | 'llm' | 'transfer', required: Type of flow step.
    - `config` object, required: Step configuration (varies by type).
    - `nextStepId` string, nullable: ID of the next step to execute.
  - `enabled` boolean
  - `priority` integer

## Response `201`

Flow created.

- FlowResponse
  - `flow` AgentFlow, required
    - `id` string, required
    - `agentId` string, required
    - `name` string, required
    - `description` string, nullable
    - `trigger` FlowTrigger, required
      - `type` 'keyword' | 'intent' | 'always' | 'manual', 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.
      - `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` FlowStep[], required
      - `id` string, required: Unique step identifier.
      - `type` 'message' | 'collect' | 'condition' | 'tool' | 'llm' | 'transfer', required: Type of flow step.
      - `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

## Other responses

- `400`: Invalid request.
- `401`: Unauthorized.
- `404`: Agent not found.

---

[API](https://skmtc.dev/zavudev/apis/zavu-unified-messaging-layer-api.md) - [All operations](https://skmtc.dev/zavudev/apis/zavu-unified-messaging-layer-api/llms.txt) - [OpenAPI document](https://skmtc.dev/zavudev/apis/zavu-unified-messaging-layer-api/revisions/75bc777b0ffb?raw)
