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

# Gerenciar Flows

> Crie, liste e gerencie WhatsApp Flows no canal do WhatsApp Oficial

# Gerenciar Flows

O comando **Flows** gerencia os [WhatsApp Flows](https://developers.facebook.com/docs/whatsapp/flows) do canal do WhatsApp Oficial. Flows são experiências interativas (formulários, cadastros, fluxos de atendimento) que rodam dentro do próprio WhatsApp.

As operações usam `POST /api/v1/message/SendCommand` com `content.type: "FLOWS"`, variando o `commandType` conforme a operação desejada. Resposta síncrona: `{ "packageId": "..." }`; resultado via webhook.

## Operações disponíveis

| Operação | commandType | Descrição | Status exigido |
| - | - | - | - |
| Listar | `LIST` | Lista todos os Flows do business | — |
| Criar | `CREATE` | Cria um novo Flow | — |
| Atualizar | `UPDATE` | Atualiza nome, categorias ou endpoint de um Flow | `Draft` |
| Upload de asset | `UPLOAD_ASSET` | Envia o Flow JSON (a estrutura do formulário) | — |
| Publicar | `PUBLISH` | Publica o Flow (torna-o utilizável) | `Draft` |
| Deprecar | `DEPRECATE` | Depreca o Flow (não pode mais ser enviado) | `Published` |
| Deletar | `DELETE` | Remove o Flow | `Draft` |
| Preview | `PREVIEW` | Gera URL de preview do Flow | — |
| Sincronizar | `SYNC` | Sincroniza Flows da Meta com a plataforma | — |
| Atualizar cache | `REFRESH` | Atualiza o cache local de um Flow específico | — |

A Meta só aceita algumas operações em determinados status. Fora do status exigido, a operação falha e o webhook chega com `success: false`.

<Note>
  Os Flows pertencem ao **business** (WABA), não a um número específico. O `channelId` identifica a conta cujas credenciais autenticam a requisição à Meta.
</Note>

## Respostas

Cada operação responde por webhook. O `type` indica o formato do payload e o `commandType` indica a operação que o originou, no padrão `FLOWS_<OPERAÇÃO>_RESPONSE`:

| Operação | `type` | `commandType` |
| - | - | - |
| `LIST` | `FLOWS_LIST_RESPONSE` | `FLOWS_LIST_RESPONSE` |
| `CREATE` | `FLOWS_DETAIL_RESPONSE` | `FLOWS_CREATE_RESPONSE` |
| `UPDATE` | `FLOWS_DETAIL_RESPONSE` | `FLOWS_UPDATE_RESPONSE` |
| `UPLOAD_ASSET` | `FLOWS_DETAIL_RESPONSE` | `FLOWS_UPLOAD_ASSET_RESPONSE` |
| `PUBLISH` | `FLOWS_DETAIL_RESPONSE` | `FLOWS_PUBLISH_RESPONSE` |
| `DEPRECATE` | `FLOWS_DETAIL_RESPONSE` | `FLOWS_DEPRECATE_RESPONSE` |
| `REFRESH` | `FLOWS_DETAIL_RESPONSE` | `FLOWS_REFRESH_RESPONSE` |
| `DELETE` | `FLOWS_RESPONSE` | `FLOWS_DELETE_RESPONSE` |
| `PREVIEW` | `FLOWS_PREVIEW_RESPONSE` | `FLOWS_PREVIEW_RESPONSE` |
| `SYNC` | `FLOWS_SYNC_RESPONSE` | `FLOWS_SYNC_RESPONSE` |

O formato é o mesmo no sucesso e na falha: se um `CREATE` falhar, o webhook continua sendo `FLOWS_DETAIL_RESPONSE` / `FLOWS_CREATE_RESPONSE`, com `success: false` e o motivo em `error`.

## Listar Flows

```json theme={null}
{
  "channelId": "uuid-do-canal-oficial",
  "content": {
    "type": "FLOWS",
    "commandType": "LIST"
  }
}
```

<ParamField body="content.flowId" type="uuid">
  Filtro opcional. Quando informado, retorna apenas o Flow específico (GET unitário) em vez da lista completa. Ambos os caminhos respondem `FLOWS_LIST_RESPONSE`. Se o Flow não existir, a resposta vem com `success: false` e `error` iniciando com `FLOW_NOT_FOUND` — não como lista vazia.
</ParamField>

<ParamField body="content.wabaPhoneNumberId" type="string">
  Filtro opcional. Restringe à WABA deste número.
</ParamField>

### Webhook de resposta

```json theme={null}
{
  "content": {
    "type": "FLOWS_LIST_RESPONSE",
    "commandType": "FLOWS_LIST_RESPONSE",
    "success": true,
    "count": 1,
    "flows": [
      {
        "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "name": "cadastro_cliente",
        "categories": ["SIGN_UP"],
        "status": "Published",
        "wabaId": "104857392019283",
        "businessId": "66666666-7777-8888-9999-aaaaaaaaaaaa",
        "endpointUri": null,
        "jsonVersion": "3.1",
        "dataApiVersion": "v19.0",
        "wabaFlowId": "1234567890",
        "createdAt": "2026-08-19T14:20:44Z",
        "updatedAt": "2026-08-20T10:00:00Z"
      }
    ]
  }
}
```

### Campos do Flow (`flows[]`)

| Campo | Tipo | Descrição |
| - | - | - |
| `id` | `uuid` | Identificador do Flow na MessageFy |
| `name` | `string` | Nome do Flow |
| `categories` | `string[]` | Categorias do Flow (ex.: `SIGN_UP`, `CUSTOMER_SUPPORT`) |
| `status` | `string` | Status normalizado (`Draft`, `Published`, `Deprecated`, `Blocked`, `Throttled`) |
| `wabaId` | `string` | WABA dona do Flow |
| `businessId` | `uuid` | Business dono do Flow |
| `endpointUri` | `string` \| `null` | Endpoint HTTPS do Flow (quando é data\_channel) |
| `jsonVersion` | `string` | Versão do Flow JSON |
| `dataApiVersion` | `string` | Versão da Data API da Meta |
| `validationErrors` | `array` | Erros de validação da Meta na última tentativa (criação, upload de asset ou publicação), no formato original. Ausente quando não há erro |
| `wabaFlowId` | `string` | Id do Flow na Meta |
| `createdAt` | `string` (ISO 8601) | Data de criação |
| `updatedAt` | `string` (ISO 8601) \| `null` | Data da última atualização |

## Criar Flow

O CREATE exige que o canal tenha um número conectado: o Flow é criado na WABA desse número. As demais operações usam apenas as credenciais da conta.

```json theme={null}
{
  "channelId": "uuid-do-canal-oficial",
  "correlationId": "flow-cadastro",
  "content": {
    "type": "FLOWS",
    "commandType": "CREATE",
    "name": "cadastro_cliente",
    "categories": ["SIGN_UP"],
    "publish": false
  }
}
```

<ParamField body="content.name" type="string" required>
  Nome do Flow.
</ParamField>

<ParamField body="content.categories" type="string[]" required>
  Categorias do Flow (ex.: `SIGN_UP`, `CUSTOMER_SUPPORT`, `APPOINTMENT_BOOKING`). Deve conter pelo menos uma.
</ParamField>

<ParamField body="content.endpointUri" type="string">
  Endpoint HTTPS do Flow, quando ele é data\_channel (o Flow troca dados com seu servidor em tempo real).
</ParamField>

<ParamField body="content.cloneFlowId" type="string">
  Id **na Meta** (`wabaFlowId`, não o `id` da MessageFy) de um Flow existente para clonar. A Flows API da Meta duplica a estrutura.
</ParamField>

<ParamField body="content.flowJson" type="object">
  Flow JSON opaco (a estrutura do formulário). Opcional no CREATE — pode ser enviado depois via `UPLOAD_ASSET`.
</ParamField>

<ParamField body="content.publish" type="boolean" default="false">
  Publica o Flow logo após criá-lo. Quando `true`, o Flow já nasce publicado.
</ParamField>

### Webhook de resposta

O CREATE retorna `FLOWS_DETAIL_RESPONSE`:

```json theme={null}
{
  "correlationId": "flow-cadastro",
  "content": {
    "type": "FLOWS_DETAIL_RESPONSE",
    "commandType": "FLOWS_CREATE_RESPONSE",
    "success": true,
    "flow": {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "name": "cadastro_cliente",
      "categories": ["SIGN_UP"],
      "status": "Draft",
      "wabaId": "104857392019283",
      "businessId": "66666666-7777-8888-9999-aaaaaaaaaaaa",
      "wabaFlowId": "1234567890",
      "createdAt": "2026-09-29T10:00:00Z"
    }
  }
}
```

Guarde o `flow.id` — é o `flowId` usado nas demais operações.

## Upload de asset (Flow JSON)

Envia a estrutura do formulário (Flow JSON) para um Flow existente.

```json theme={null}
{
  "channelId": "uuid-do-canal-oficial",
  "content": {
    "type": "FLOWS",
    "commandType": "UPLOAD_ASSET",
    "flowId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "flowJson": { "version": "3.1", "screens": [] }
  }
}
```

<ParamField body="content.flowId" type="uuid" required>
  Identificador do Flow alvo.
</ParamField>

<ParamField body="content.flowJson" type="object" required>
  Flow JSON opaco. A MessageFy não valida o conteúdo — a Meta valida contra o schema da versão.
</ParamField>

### Webhook de resposta

Retorna `FLOWS_DETAIL_RESPONSE` com o Flow atualizado.

## Atualizar Flow

Atualiza nome, categorias ou endpoint de um Flow em `Draft` — a Meta não permite editar os metadados de um Flow publicado. Pelo menos um campo deve ser informado.

```json theme={null}
{
  "channelId": "uuid-do-canal-oficial",
  "content": {
    "type": "FLOWS",
    "commandType": "UPDATE",
    "flowId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "name": "cadastro_cliente_v2"
  }
}
```

<ParamField body="content.flowId" type="uuid" required>
  Identificador do Flow a atualizar.
</ParamField>

<ParamField body="content.name" type="string">
  Novo nome do Flow.
</ParamField>

<ParamField body="content.categories" type="string[]">
  Novas categorias do Flow.
</ParamField>

<ParamField body="content.endpointUri" type="string">
  Novo endpoint HTTPS do Flow.
</ParamField>

### Webhook de resposta

Retorna `FLOWS_DETAIL_RESPONSE` com o Flow atualizado.

## Publicar Flow

Publica um Flow em rascunho, tornando-o utilizável em mensagens.

```json theme={null}
{
  "channelId": "uuid-do-canal-oficial",
  "content": {
    "type": "FLOWS",
    "commandType": "PUBLISH",
    "flowId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  }
}
```

### Webhook de resposta

Retorna `FLOWS_DETAIL_RESPONSE` com `status: "Published"`.

## Deprecar Flow

Depreca um Flow em `Published`. Um Flow deprecado não pode mais ser enviado em novas mensagens.

```json theme={null}
{
  "channelId": "uuid-do-canal-oficial",
  "content": {
    "type": "FLOWS",
    "commandType": "DEPRECATE",
    "flowId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  }
}
```

### Webhook de resposta

Retorna `FLOWS_DETAIL_RESPONSE` com `status: "Deprecated"`.

## Deletar Flow

Remove um Flow em `Draft`. A Meta não permite excluir um Flow já publicado — para tirá-lo de uso, depreque-o.

```json theme={null}
{
  "channelId": "uuid-do-canal-oficial",
  "content": {
    "type": "FLOWS",
    "commandType": "DELETE",
    "flowId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  }
}
```

### Webhook de resposta

Retorna `FLOWS_RESPONSE` com `commandType: "FLOWS_DELETE_RESPONSE"`, sem payload além de `success`.

## Preview do Flow

Gera uma URL de preview do Flow, válida por 30 dias.

```json theme={null}
{
  "channelId": "uuid-do-canal-oficial",
  "content": {
    "type": "FLOWS",
    "commandType": "PREVIEW",
    "flowId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "invalidate": false
  }
}
```

<ParamField body="content.invalidate" type="boolean" default="false">
  Quando `true`, força a Meta a gerar uma nova URL de preview em vez de reaproveitar a atual.
</ParamField>

### Webhook de resposta

```json theme={null}
{
  "content": {
    "type": "FLOWS_PREVIEW_RESPONSE",
    "commandType": "FLOWS_PREVIEW_RESPONSE",
    "success": true,
    "previewUrl": "https://business.facebook.com/wa/manage/flows/...",
    "expiresAt": "2026-10-29T10:00:00Z"
  }
}
```

| Campo | Tipo | Descrição |
| - | - | - |
| `previewUrl` | `string` | URL de preview do Flow |
| `expiresAt` | `string` (ISO 8601) \| `null` | Data de expiração da URL |

## Sincronizar Flows

Sincroniza os Flows da Meta com a plataforma. Útil para importar Flows criados diretamente no Meta Business Manager.

```json theme={null}
{
  "channelId": "uuid-do-canal-oficial",
  "content": {
    "type": "FLOWS",
    "commandType": "SYNC"
  }
}
```

<ParamField body="content.wabaPhoneNumberId" type="string">
  Restringe a sincronização à WABA deste número.
</ParamField>

### Webhook de resposta

```json theme={null}
{
  "content": {
    "type": "FLOWS_SYNC_RESPONSE",
    "commandType": "FLOWS_SYNC_RESPONSE",
    "success": true,
    "imported": 3,
    "updated": 1,
    "unchanged": 5,
    "skipped": 0,
    "totalFromMeta": 9,
    "wabas": [
      {
        "wabaId": "104857392019283",
        "success": true,
        "imported": 3,
        "updated": 1,
        "unchanged": 5,
        "skipped": 0,
        "totalFromMeta": 9
      }
    ]
  }
}
```

| Campo | Tipo | Descrição |
| - | - | - |
| `imported` | `integer` | Flows novos importados |
| `updated` | `integer` | Flows existentes atualizados |
| `unchanged` | `integer` | Flows sem alteração |
| `skipped` | `integer` | Flows ignorados |
| `totalFromMeta` | `integer` | Total de Flows retornados pela Meta |
| `wabas` | `object[]` \| `null` | Detalhe por WABA (uma WABA pode falhar sem derrubar as outras) |

### Campos de `wabas[]`

| Campo | Tipo | Descrição |
| - | - | - |
| `wabaId` | `string` | Identificador da WABA |
| `success` | `boolean` | `true` se a sincronização desta WABA foi bem-sucedida |
| `imported` | `integer` | Flows novos importados desta WABA |
| `updated` | `integer` | Flows atualizados desta WABA |
| `unchanged` | `integer` | Flows sem alteração desta WABA |
| `skipped` | `integer` | Flows ignorados desta WABA |
| `totalFromMeta` | `integer` | Total de Flows desta WABA retornados pela Meta |
| `error` | `string` | Descrição do erro. Presente só quando `success` é `false` |

## Atualizar cache (Refresh)

Atualiza o cache local de um Flow específico, buscando os dados mais recentes da Meta.

```json theme={null}
{
  "channelId": "uuid-do-canal-oficial",
  "content": {
    "type": "FLOWS",
    "commandType": "REFRESH",
    "flowId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  }
}
```

### Webhook de resposta

Retorna `FLOWS_DETAIL_RESPONSE` com os dados atualizados do Flow.

## Erros

### Validação na entrada (HTTP 400)

A estrutura mínima do comando é validada antes de o pacote ser aceito. Nesses casos o `SendCommand` responde `400` na hora, sem webhook:

| Código | Quando |
| - | - |
| `FLOW_NAME_REQUIRED` | `CREATE` sem `name` |
| `FLOW_CATEGORIES_REQUIRED` | `CREATE` sem `categories` |
| `FLOW_CATEGORIES_EMPTY` | `CREATE` com `categories` vazio |
| `FLOW_ID_REQUIRED` | `UPDATE`, `UPLOAD_ASSET`, `PUBLISH`, `DEPRECATE`, `DELETE`, `PREVIEW` ou `REFRESH` sem `flowId` |
| `FLOW_JSON_REQUIRED` | `UPLOAD_ASSET` sem `flowJson` |
| `FLOW_UPDATE_EMPTY` | `UPDATE` sem nenhum de `name`, `categories` ou `endpointUri` |

### Falha no processamento (webhook)

Falhas depois que o pacote foi aceito (Flow em status incompatível, erro da Meta, Flow inexistente) chegam no webhook da própria operação, com `success: false`. Exemplo de um `PUBLISH` recusado:

```json theme={null}
{
  "content": {
    "type": "FLOWS_DETAIL_RESPONSE",
    "commandType": "FLOWS_PUBLISH_RESPONSE",
    "success": false,
    "error": "Descrição da falha"
  }
}
```

<Warning>
  Um `200 OK` no SendCommand significa apenas que o pacote foi aceito para processamento. O resultado real (sucesso ou falha) chega via webhook. Monitore o `success` do webhook para confirmar o desfecho.
</Warning>

## Exemplo completo

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api-dev.messagefy.io/api/v1/message/SendCommand \
    -H "Content-Type: application/json" \
    -H "X-API-KEY: sua-api-key" \
    -d '{
      "channelId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "correlationId": "flow-cadastro",
      "content": {
        "type": "FLOWS",
        "commandType": "CREATE",
        "name": "cadastro_cliente",
        "categories": ["SIGN_UP"],
        "publish": false
      }
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api-dev.messagefy.io/api/v1/message/SendCommand",
      headers={
          "Content-Type": "application/json",
          "X-API-KEY": "sua-api-key"
      },
      json={
          "channelId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
          "correlationId": "flow-cadastro",
          "content": {
              "type": "FLOWS",
              "commandType": "CREATE",
              "name": "cadastro_cliente",
              "categories": ["SIGN_UP"],
              "publish": False
          }
      }
  )

  print(response.json())
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    "https://api-dev.messagefy.io/api/v1/message/SendCommand",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-API-KEY": "sua-api-key",
      },
      body: JSON.stringify({
        channelId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        correlationId: "flow-cadastro",
        content: {
          type: "FLOWS",
          commandType: "CREATE",
          name: "cadastro_cliente",
          categories: ["SIGN_UP"],
          publish: false,
        },
      }),
    }
  );

  const data = await response.json();
  console.log(data);
  ```
</CodeGroup>

<Tip>
  Após criar o Flow (`CREATE`), envie o Flow JSON via `UPLOAD_ASSET` e depois publique via `PUBLISH`.
  Use o Flow publicado em mensagens de template com botão `flow` — veja [Mensagem de Template](/mensagens/template).
</Tip>
