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

# Reply flows

> Branch after a campaign reply: send a follow-up message, reply buttons, a list, or a WhatsApp Flow form based on what the recipient chose.

<Note>
  Reply flows are a beta. Your team must be enrolled before the API accepts
  reply flow requests; other teams receive `403 feature_unavailable`.
</Note>

A reply flow is a short, fixed conversation that starts when a recipient replies
to a campaign message. Each step can send one message and then waits for the
recipient's next reply. The reply decides which step runs next.

## How a reply flow runs

1. Create a reply flow revision with the Messaging API
   ([Create project campaign reply flow](/api-reference/messaging/campaigns/create-project-campaign-reply-flow))
   or the Platform API
   ([Create campaign reply flow](/api-reference/platform/campaigns/create-campaign-reply-flow)).
2. Attach it to a draft or scheduled campaign
   ([Messaging](/api-reference/messaging/campaigns/set-project-campaign-reply-flow),
   [Platform](/api-reference/platform/campaigns/set-campaign-reply-flow)).
3. When a campaign message is sent, the flow starts for that recipient on the
   entry step, which sends nothing and waits for the first reply.
4. A reply that matches one of the step's branches moves the recipient to the
   next step, which sends its message. A reply that matches nothing is ignored.

STOP and START replies are handled first and never move a flow forward. When
your team has STOP/START keyword capture on, your own opt-out and opt-in
keywords also take precedence: a flow branch on one of those words never fires.
A recipient on your opt-out list receives no reply flow messages, and opting
out ends their flow.

## Limits

| Limit | Value |
| - | - |
| Steps per flow | 2 to 12, with no loops |
| Branches per step | 3 |
| Reply buttons per message | 3 |
| List rows per message | 10 |
| Button or list message body | 1,024 bytes |
| Time to reply to a step | 30 minutes |
| Flow lifetime per recipient | 24 hours |
| Active flows per recipient and number | 1; a new campaign does not start a second flow while one is active |

A revision cannot be edited. To change a flow, create a new revision with the
same `flowKey` and a higher `revision`, then attach it to a new campaign. A
launched campaign keeps the revision it launched with.

## Branches

Each branch has a `match` and the step it moves `to`:

* `choice`: the recipient tapped a reply button (`replyKind: "button"`) or a
  list row (`replyKind: "list"`) with this `id`. A step that sends buttons or a
  list can branch only on the choices it offers.
* `keyword`: the reply text equals this keyword, ignoring case. A reply that
  quotes the step's message always counts. An unquoted reply counts only when
  this is the recipient's only waiting flow and no other campaign message
  reached them since the step's message. Built-in STOP and START words cannot
  be flow keywords.
* `flow_submission`: the recipient submitted the Flow form this step sent.
  Polymorfa does not store the form answers.

## Messages a step can send

| `send.kind` | Sends | Numbers |
| - | - | - |
| `text` | A text message | All |
| `buttons` | A message with up to 3 reply buttons | All; Official numbers send it as an interactive message |
| `list` | A message with a list of up to 10 rows | All; Official numbers send it as an interactive message |
| `flow_form` | A published WhatsApp Flow form | Official numbers only |

A `flow_form` step on a linked number ends the recipient's flow without
sending. Follow-up messages use the same sending checks, funding, and number
protection as other messages from that number. If Polymorfa cannot confirm
whether a follow-up message reached WhatsApp, it never sends it again. It checks
the send record: a confirmed send continues the flow, and a message that was
never sent, or a flow that reaches its 24-hour lifetime first, ends the flow.

## Example

```json theme={null}
{
  "name": "Order help",
  "definition": {
    "entryNodeId": "start",
    "nodes": [
      { "id": "start", "edges": [{ "match": { "kind": "keyword", "value": "help" }, "to": "menu" }] },
      {
        "id": "menu",
        "send": {
          "kind": "buttons",
          "body": "What do you need help with?",
          "buttons": [{ "id": "track", "text": "Track order" }, { "id": "return", "text": "Return" }]
        },
        "edges": [
          { "match": { "kind": "choice", "replyKind": "button", "id": "track" }, "to": "track" },
          { "match": { "kind": "choice", "replyKind": "button", "id": "return" }, "to": "return" }
        ]
      },
      { "id": "track", "send": { "kind": "text", "text": "Reply with your order number." }, "edges": [] },
      { "id": "return", "send": { "kind": "text", "text": "Start your return at example.com/returns." }, "edges": [] }
    ]
  }
}
```

Button and list replies also reach your webhooks as `message.received` events
with `payload.replyChoice`. See [Webhooks](/api/webhooks).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.