Synergy Connect

Documentação

WhatsApp Flows

Um Flow é um formulário que o cliente preenche dentro do WhatsApp. Pela API você envia o Flow e recebe a resposta por webhook. Exige a feature waFlows no plano e o Flow criado no app.

Fluxo#

  1. Emita um flow_token com POST /v1/numbers/{phone_number_id}/flows/{flow_id}/token.
  2. Envie o Flow com POST /{version}/{phone_number_id}/messages, com o token em interactive.action.parameters.flow_token.
  3. Receba a resposta no webhook messages.

1. Emitir o token#

Escopo messages; o corpo tem até 4 KB. O token vale para este número, este Flow e este destinatário, por 3 dias. O destinatário vai no corpo (to: só dígitos, de 8 a 20, com DDI), nunca no caminho. context (opcional) é um objeto de textos validado pelo tipo do Flow.

Resposta 200: { "flow_token": "v1.…", "expires_at": "2026-01-04T00:00:00.000Z" }.

Erros: 400 (to ou context inválido, corpo acima de 4 KB), 403 código 1390007 (plano sem Flows), 404 (o Flow não é deste número), 409 código 1390008 (o Flow usa o endpoint de outro provedor, está em rascunho ou não pode ser enviado). Se o destinatário ainda não é contato do número, ele é criado ao emitir o token.

Exemplo

curl

curl -X POST 'https://api.synergyconnect.com.br/v1/numbers/106540352242922/flows/1234567890/token' \
  -H "Authorization: Bearer $SYNERGY_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"to":"5511999999999"}'

JavaScript

const res = await fetch('https://api.synergyconnect.com.br/v1/numbers/106540352242922/flows/1234567890/token', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SYNERGY_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ to: '5511999999999' }),
});
const { flow_token, expires_at } = await res.json();

Python

import os

import requests

res = requests.post(
    "https://api.synergyconnect.com.br/v1/numbers/106540352242922/flows/1234567890/token",
    headers={"Authorization": f"Bearer {os.environ['SYNERGY_API_KEY']}"},
    json={"to": "5511999999999"},
)
data = res.json()  # data["flow_token"], data["expires_at"]

2. Enviar o Flow#

O envio é o da Cloud API: uma mensagem interactive do tipo flow, ou um modelo com botão de Flow. O corpo vai à Meta sem alteração. O token é obrigatório quando o Flow usa o endpoint da Synergy; sem ele, 400 código 1390009.

Os campos do corpo (flow_message_version, flow_cta etc.) são os da Meta: a Synergy só lê o token. O envio de Flow também conta no limite de envios de Flow do plano (429 código 1390010 ao esgotar).

Exemplo

curl

curl -X POST 'https://api.synergyconnect.com.br/v25.0/106540352242922/messages' \
  -H "Authorization: Bearer $SYNERGY_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "messaging_product": "whatsapp",
    "to": "5511999999999",
    "type": "interactive",
    "interactive": {
      "type": "flow",
      "body": { "text": "Preencha o formulário" },
      "action": {
        "name": "flow",
        "parameters": {
          "flow_message_version": "3",
          "flow_id": "1234567890",
          "flow_cta": "Abrir",
          "flow_token": "'"$FLOW_TOKEN"'"
        }
      }
    }
  }'

JavaScript

const res = await fetch('https://api.synergyconnect.com.br/v25.0/106540352242922/messages', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SYNERGY_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    messaging_product: 'whatsapp',
    to: '5511999999999',
    type: 'interactive',
    interactive: {
      type: 'flow',
      body: { text: 'Preencha o formulário' },
      action: {
        name: 'flow',
        parameters: { flow_message_version: '3', flow_id: '1234567890', flow_cta: 'Abrir', flow_token },
      },
    },
  }),
});
console.log(res.status, await res.json());

Python

res = requests.post(
    "https://api.synergyconnect.com.br/v25.0/106540352242922/messages",
    headers={"Authorization": f"Bearer {os.environ['SYNERGY_API_KEY']}"},
    json={
        "messaging_product": "whatsapp",
        "to": "5511999999999",
        "type": "interactive",
        "interactive": {
            "type": "flow",
            "body": {"text": "Preencha o formulário"},
            "action": {
                "name": "flow",
                "parameters": {
                    "flow_message_version": "3",
                    "flow_id": "1234567890",
                    "flow_cta": "Abrir",
                    "flow_token": flow_token,
                },
            },
        },
    },
)
print(res.status_code, res.json())

3. Receber a resposta#

Quando o cliente envia o formulário, a Meta entrega uma mensagem interactive com nfm_reply. Ela chega no webhook que assina messages, com o value da Meta, sem alteração. response_json é um texto JSON com as respostas e o flow_token. O recebimento nunca é bloqueado pelo plano.

Use X-Synergy-Delivery-Id e o messages[].id para descartar repetições (Webhooks). A assinatura se valida como nos demais eventos. O campo flows da Meta (eventos de saúde do endpoint) não é entregue a webhooks.

JSON
{
  "object": "whatsapp_business_account",
  "entry": [{ "id": "102290129340398", "time": 1767225600, "changes": [{
    "field": "messages",
    "value": {
      "messaging_product": "whatsapp",
      "metadata": { "display_phone_number": "554430000000", "phone_number_id": "106540352242922" },
      "messages": [{
        "from": "5511999999999", "id": "wamid.…", "timestamp": "1767225600", "type": "interactive",
        "interactive": { "type": "nfm_reply", "nfm_reply": { "name": "flow", "body": "Sent", "response_json": "{\"flow_token\":\"v1.…\",\"nome\":\"Maria\"}" } }
      }]
    }
  }] }]
}
Exemplo

JavaScript

function onFlowReply(message) {
  if (message.type !== 'interactive' || message.interactive?.type !== 'nfm_reply') return;
  const answers = JSON.parse(message.interactive.nfm_reply.response_json);
  // answers.flow_token identifica o envio; o resto são os campos do formulário
}

Python

import json


def on_flow_reply(message):
    interactive = message.get("interactive", {})
    if message.get("type") != "interactive" or interactive.get("type") != "nfm_reply":
        return
    answers = json.loads(interactive["nfm_reply"]["response_json"])
    # answers["flow_token"] identifica o envio; o resto são os campos do formulário

Ficou com dúvida? Escreva para suporte@synergyconnect.com.br.