FlashConnect Documentação Falar no WhatsApp

API REST do WhatsApp da FlashConnect

A API REST da FlashConnect envia e lê mensagens do WhatsApp oficial (Cloud API da Meta) com uma chave ck_live_ no header Authorization. São 8 rotas que aceitam chave de API (envio, histórico, mídia, conversa, contato, agente, agenda e tarefas), controladas por 14 escopos. Fora da janela de 24 horas só passa template aprovado, e listar conversas, contatos e números é feito pelo servidor MCP com a mesma chave.

Atualizado em

Qual é a URL base da API do WhatsApp da FlashConnect?

Todas as rotas ficam sob uma única base e respondem JSON:

https://qqyphyubrxyouaqicdbo.supabase.co/functions/v1
  • Corpo e respostas em JSON (content-type: application/json). Datas em ISO 8601.
  • Tudo é por conta (tenant): a chave só enxerga os números, conversas e configurações da própria empresa. Recurso de outra conta responde 404, nunca 403.
  • Erros têm sempre o formato { "erro": "mensagem", "codigo": "CODIGO" }. A lista completa está em códigos de erro da API.
  • A FlashConnect usa a API oficial do WhatsApp (Cloud API da Meta): as regras de janela de 24 h e de templates são da Meta e valem aqui também.

Como autenticar na API?

Toda chamada leva o header Authorization: Bearer <chave>. A chave de API começa com ck_live_.

Authorization: Bearer ck_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • Onde gerar: no painel, em Integrações → Nova chave (você escolhe os escopos) ou em Conectar IA (a chave já sai com todos os escopos). Só dono ou admin da conta gera chave, e a conta precisa ter cartão cadastrado.
  • Uma vez só: o segredo aparece apenas na criação. Guardamos só o hash SHA-256 dele; se perder, gere outra.
  • Revogar: pelo painel, em Integrações. Chave revogada responde 401 CHAVE_REVOGADA na hora.
  • Escopo: chave sem o escopo da rota responde 403 ESCOPO_INSUFICIENTE.
  • O prefixo ck_test_ é reservado e ainda não é emitido.

O painel chama as mesmas rotas com o login do usuário (JWT). Usuário logado tem todos os escopos; a diferença de comportamento aparece no envio (veja abaixo).

Quais são os escopos da chave de API?

São 14 escopos. Oito liberam rotas REST; seis valem só para as ferramentas do servidor MCP, que usa a mesma chave. Sem escolher nada, a chave nasce com messages:send, messages:read e agent:read.

EscopoLibera na API RESTLibera no MCP
messages:sendPOST /whatsapp-sendenviar_mensagem
messages:readGET /messages-list, POST /media-downloadlistar_conversas, ler_conversa
conversations:writePOST /conversation-updateatualizar_conversa
contacts:writePOST /contato-updateatualizar_contato
contacts:readnenhumabuscar_contatos
agent:readGET /agent-configver_agente, listar_agentes, listar_catalogo
agent:writenenhumasalvar_agente, salvar_produto, remover_produto, salvar_conhecimento, remover_conhecimento
agenda:readGET /agendalistar_agendas, horarios_livres, listar_agendamentos
agenda:writePOST /agenda, PATCH /agendamarcar_agendamento, alterar_agendamento
tasks:writeGET, POST e PATCH /tarefaslistar_tarefas, criar_tarefa, alterar_tarefa
templates:readnenhumalistar_templates
templates:writenenhumacriar_template
webhooks:readnenhumalistar_webhooks
webhooks:writenenhumacriar_webhook, alterar_webhook, remover_webhook

Atenção: GET /tarefas (listar) também exige tasks:write; não existe tasks:read. As ferramentas status_setup e listar_numeros do MCP não exigem escopo.

Quais endpoints aceitam chave de API?

RotaO que fazEscopo
POST /whatsapp-sendEnvia texto, template, imagem, vídeo, documento, áudio, figurinha ou mensagem interativamessages:send
GET /messages-listHistórico de uma conversa, paginadomessages:read
POST /media-downloadLink temporário da mídia de uma mensagem (áudio para transcrever, imagem para analisar)messages:read
POST /conversation-updateModo IA/humano, estado, etiquetas, atendente, agente e equipeconversations:write
POST /contato-updateNome, e-mail, tags, notas e opt-out do contatocontacts:write
GET /agent-configConfiguração do agente de IA, produtos, conhecimento, agenda, regras e equipesagent:read
GET · POST · PATCH /agendaAgendas, horários livres, criar, remarcar e cancelar agendamentosagenda:read / agenda:write
GET · POST · PATCH /tarefasListar, criar e alterar cartões do quadro de tarefastasks:write

Não aceitam chave de API (só o login do painel): api-key-create (criar chave) e a criação de templates. Para criar template ou webhook por máquina, use as ferramentas criar_template e criar_webhook do MCP.

Subir arquivo para enviar (media-upload)

Para enviar um arquivo que não está num link público, suba antes em POST /media-upload (multipart, campo arquivo) com a chave de API (escopo messages:send) e use o caminho devolvido em midia_caminho. Limites da Meta: imagem JPEG/PNG até 5 MB, figurinha WebP até 500 KB, vídeo MP4 e áudio até 16 MB, documento até 50 MB.

curl -X POST https://qqyphyubrxyouaqicdbo.supabase.co/functions/v1/media-upload \
  -H "Authorization: Bearer ck_live_SUA_CHAVE" \
  -F "arquivo=@catalogo.pdf"
# → {"caminho": "<tenant>/<uuid>.pdf", "mime": "application/pdf", "url": "…", "tamanho": 123456}

Como enviar mensagem no WhatsApp pela API?

POST /whatsapp-send · escopo messages:send.

CampoTipoObrigatórioNotas
phone_number_idstringsimNúmero de origem: o phone_number_id da Meta (veja listar_numeros no MCP ou o campo numero.phone_number_id dos eventos)
parastringsimTelefone do contato no formato internacional, só dígitos, 8 a 15 (ex.: 5511999990000)
tipostringnãotext (padrão), template, image, video, document, audio, sticker ou interactive
textostringse textConteúdo da mensagem
templateobjetose template{ "nome", "idioma"?, "componentes"? }. idioma padrão pt_BR; componentes no formato da Cloud API (parâmetros das variáveis)
midia_urlstringse mídia*URL https:// pública; a Meta baixa o arquivo de lá
midia_caminhostringse mídia*Alternativa a midia_url: o caminho de um arquivo já guardado na FlashConnect (devolvido por media-upload ou media-download). Precisa ser da sua conta
midia_mimestringnãoTipo do arquivo, gravado no histórico
legendastringnãoLegenda de imagem, vídeo ou documento. Figurinha não aceita
nome_arquivostringnãoNome exibido do documento
vozbooleannãoEm audio OGG/Opus, true envia como nota de voz
interativoobjetose interactiveObjeto interactive da Cloud API (botões, lista), repassado como está
autorstringnãoia ou humano. Padrão: ia com chave de API, humano com login

* Tipos de mídia (image, video, document, audio, sticker) exigem midia_url ou midia_caminho.

Regras do envio

  • Janela de 24 h. Texto livre, mídia e interativas só passam se o contato escreveu nas últimas 24 h. Fora disso (ou sem conversa) a API responde 409 JANELA_EXPIRADA antes de chamar a Meta. Só template aprovado passa sempre.
  • Primeira mensagem. Template para um número que nunca falou com você cria o contato e a conversa na hora.
  • Opt-out. Contato marcado com opt_out não recebe template (409 OPT_OUT).
  • Número pronto. O número precisa estar registrado na Cloud API (409 NUMERO_NAO_REGISTRADO) e com a conexão válida (409 SEM_CREDENCIAL).
  • Modo da conversa. Envio por chave de API não muda o modo. Envio por login numa conversa em modo ia faz a pessoa assumir a conversa (modo humano) e emite conversation.handoff.
  • Assinatura. Com a assinatura pausada, cancelada ou aguardando cartão, o envio por chave responde 402 (ASSINATURA_PAUSADA ou ASSINATURA_PENDENTE).
  • Status. A mensagem é gravada com status sent; entregue, lida e falha chegam depois pelo webhook message.status.

Resposta 200

{
  "ok": true,
  "wa_message_id": "wamid.HBgNNTUxMTk5OTk5MDAwMBUCABEYEjQ1...",
  "message_id": "9b2f1c7e-5d0a-4c1e-8f3b-2a6d4e8c1f90",
  "conversation_id": "4e7a2b91-3c5d-4f6e-9a8b-1c2d3e4f5a6b",
  "autor": "ia"
}

Erros possíveis: 400 (campo inválido), 402, 404 NUMERO_NAO_ENCONTRADO, 409 (JANELA_EXPIRADA, OPT_OUT, NUMERO_NAO_REGISTRADO, SEM_CREDENCIAL) e 502 quando a Meta recusa, com o codigo_meta original. Detalhes em códigos de erro.

curl: texto dentro da janela

BASE=https://qqyphyubrxyouaqicdbo.supabase.co/functions/v1
KEY=ck_live_...

curl -s -X POST "$BASE/whatsapp-send" \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{"phone_number_id":"123456789012345","para":"5511999990000","texto":"Olá! Posso ajudar?"}'

curl: template com variável (funciona fora da janela)

curl -s -X POST "$BASE/whatsapp-send" \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{
    "phone_number_id": "123456789012345",
    "para": "5511999990000",
    "tipo": "template",
    "template": {
      "nome": "lembrete_consulta",
      "idioma": "pt_BR",
      "componentes": [
        { "type": "body", "parameters": [ { "type": "text", "text": "Ana" }, { "type": "text", "text": "14h" } ] }
      ]
    }
  }'

curl: imagem com legenda

curl -s -X POST "$BASE/whatsapp-send" \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{"phone_number_id":"123456789012345","para":"5511999990000","tipo":"image","midia_url":"https://exemplo.com/cardapio.jpg","legenda":"Cardápio de hoje"}'

JavaScript (fetch)

const BASE = "https://qqyphyubrxyouaqicdbo.supabase.co/functions/v1";
const KEY = process.env.FLASHCONNECT_API_KEY; // ck_live_...

async function enviar(phoneNumberId, para, texto) {
  const res = await fetch(`${BASE}/whatsapp-send`, {
    method: "POST",
    headers: { Authorization: `Bearer ${KEY}`, "content-type": "application/json" },
    body: JSON.stringify({ phone_number_id: phoneNumberId, para, texto }),
  });
  const corpo = await res.json();
  if (!res.ok) {
    // ex.: 409 JANELA_EXPIRADA -> mande um template
    throw new Error(`${res.status} ${corpo.codigo ?? ""}: ${corpo.erro}`);
  }
  return corpo; // { ok, wa_message_id, message_id, conversation_id, autor }
}

Como ler o histórico de uma conversa?

GET /messages-list?conversation_id=<uuid>&limite=50[&antes_de=<ISO>] · escopo messages:read.

  • limite de 1 a 200 (padrão 50). As mensagens vêm em ordem cronológica, a mais antiga primeiro.
  • Paginação por cursor: enquanto tem_mais for true, repita a chamada com antes_de = proximo_antes_de.
  • autor: contato, humano, ia ou sistema. sistema são envios automáticos (lembrete de agenda, automação, mensagem de transferência ou encerramento): trate como contexto, não como fala do agente.
  • direcao: inbound (do contato) ou outbound (enviada).
curl -s "$BASE/messages-list?conversation_id=4e7a2b91-3c5d-4f6e-9a8b-1c2d3e4f5a6b&limite=20" \
  -H "Authorization: Bearer $KEY"
{
  "conversation": {
    "id": "4e7a2b91-3c5d-4f6e-9a8b-1c2d3e4f5a6b",
    "contact_id": "7c1d2e3f-4a5b-4c6d-8e9f-0a1b2c3d4e5f",
    "phone_number_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "modo": "ia",
    "estado": "aberta",
    "etiquetas": ["orcamento"],
    "janela_expira_em": "2026-10-24T13:05:00.000Z",
    "ultima_msg_em": "2026-10-23T13:05:00.000Z",
    "contacts": { "wa_id": "5511999990000", "nome": "Ana Souza", "nome_perfil": "Ana" }
  },
  "mensagens": [
    {
      "id": "0f1e2d3c-4b5a-4968-8776-655443322110",
      "wa_message_id": "wamid.HBgN...",
      "direcao": "inbound",
      "autor": "contato",
      "tipo": "text",
      "conteudo": "Oi, vocês abrem sábado?",
      "midia_url": null, "midia_mime": null, "midia_caminho": null, "midia_nome": null, "midia_erro": null,
      "status": "delivered",
      "erro_codigo": null, "erro_detalhe": null,
      "template_nome": null,
      "criado_em": "2026-10-23T13:05:00.000Z"
    }
  ],
  "tem_mais": false,
  "proximo_antes_de": null
}

O phone_number_id da conversa é o id interno do número na FlashConnect, não o da Meta. Erros: 400 e 404 CONVERSA_NAO_ENCONTRADA.

Como baixar áudio, imagem e documento recebidos?

POST /media-download · escopo messages:read · corpo { "message_id": "<uuid>" }.

A FlashConnect baixa da Meta toda mídia recebida para o próprio armazenamento. Esta rota devolve um link assinado, válido por 1 hora, e baixa na hora se ainda não tiver baixado. O media_id que vem no webhook não abre sem o token da Meta: use sempre o message.id nesta rota.

curl -s -X POST "$BASE/media-download" \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{"message_id":"0f1e2d3c-4b5a-4968-8776-655443322110"}'
{
  "url": "https://qqyphyubrxyouaqicdbo.supabase.co/storage/v1/object/sign/...",
  "expira_em": "2026-10-23T14:05:00.000Z",
  "mime": "audio/ogg",
  "nome": null,
  "caminho": "…/recebidas/0f1e2d3c-4b5a-4968-8776-655443322110.ogg"
}

Erros: 404 MENSAGEM_NAO_ENCONTRADA; 410 quando não há como obter o arquivo (mensagem sem mídia, mídia expirada na Meta antes de ser salva); 503 em falha passageira, que vale tentar de novo.

Como passar a conversa para um humano (ou devolver para a IA)?

POST /conversation-update · escopo conversations:write.

CampoTipoNotas
conversation_iduuidObrigatório
modoia | humanohumano pausa o agente de IA e registra assumida_em
estadoaberta | pendente | resolvidaresolvida registra resolvida_em
etiquetasstring[]Substitui a lista (máximo 20)
atribuido_auuid | nullAtendente da mesma conta
agente_iduuid | nullAgente de IA especialista que passa a conduzir; null volta ao agente do número ou ao padrão
equipe_iduuid | nullEquipe responsável. Com modo: "humano" e sem atribuido_a, a regra de distribuição da conta escolhe o atendente dentro da equipe
motivostring até 200Livre; vai no evento de handoff

Envie ao menos um campo além de conversation_id (motivo sozinho não conta). Mudança de modo emite conversation.handoff; estado que vira resolvida emite conversation.resolved. Trocar só agente ou equipe não emite evento.

curl -s -X POST "$BASE/conversation-update" \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{"conversation_id":"4e7a2b91-3c5d-4f6e-9a8b-1c2d3e4f5a6b","modo":"humano","motivo":"cliente pediu atendente"}'

Resposta 200: { "ok": true, "conversation": { id, contact_id, phone_number_id, modo, estado, etiquetas, atribuido_a, agente_id, equipe_id, assumida_em, resolvida_em } }. Erros: 400, 404 (CONVERSA_NAO_ENCONTRADA, USUARIO_NAO_ENCONTRADO, AGENTE_NAO_ENCONTRADO, EQUIPE_NAO_ENCONTRADA).

Como o meu backend lê a configuração do agente de IA?

GET /agent-config?phone_number_id=<id da Meta>[&conversation_id=<uuid>] · escopo agent:read · resposta com Cache-Control: private, max-age=60.

O agente devolvido é, nesta ordem: o especialista definido na conversa (com conversation_id), o agente ligado ao número, ou o agente padrão da conta. Passe sempre o conversation_id do evento: sem ele, o especialista da conversa é ignorado. Veja como montar o agente em agentes de IA.

{
  "agente": { "id", "nome", "descricao", "ativo", "padrao", "persona", "objetivo", "instrucoes", "tom",
              "idioma", "saudacao", "mensagem_ausencia", "horario", "handoff_palavras", "handoff_automatico",
              "coleta_dados", "modelo", "temperatura", "max_mensagens_dia", "phone_number_id", "agenda_id",
              "pode_agendar", "pode_criar_tarefa", "criado_em", "atualizado_em" },
  "agenda":       { "id", "nome", "duracao_min", "antecedencia_min_horas", "janela_dias", "disponibilidade" },
  "produtos":     [ { "id", "nome", "descricao", "categoria", "preco", "moeda", "unidade", "sku", "imagem_url", "destaque", "atributos" } ],
  "conhecimento": [ { "id", "titulo", "conteudo", "tags" } ],
  "regras":       { "distribuicao", "somente_disponiveis", "devolver_ia_ao_resolver", "resolver_apos_horas",
                    "sla_primeira_resposta_min", "mensagem_transferencia", "mensagem_encerramento" },
  "equipes":      [ { "id", "nome", "descricao" } ],
  "tenant":       { "nome", "segmento", "timezone" },
  "numero":       { "id", "phone_number_id", "numero", "nome_verificado", "quality_rating", "messaging_limit", "registrado" }
}
  • Só produtos e conhecimento ativos; produtos em destaque primeiro.
  • agenda vem preenchida só se o agente pode agendar e tem uma agenda ativa; senão null, e o agente não deve oferecer horários.
  • agente.pode_criar_tarefa diz se o agente pode usar POST /tarefas. A plataforma não bloqueia: quem respeita a flag é o seu backend.
  • Se regras.mensagem_transferencia estiver preenchida, a plataforma já envia essa mensagem ao contato quando a conversa vai para humano. Não envie de novo.

Erros: 400, 404 NUMERO_NAO_ENCONTRADO, 404 CONVERSA_NAO_ENCONTRADA, 404 AGENTE_NAO_CONFIGURADO.

Como atualizar os dados de um contato?

POST /contato-update · escopo contacts:write. Identifique o contato por contato (telefone, só dígitos) ou contact_id (uuid), nunca os dois.

CampoTipoNotas
nomestring até 120 | nullNome dado pelo atendimento. O nome do perfil do WhatsApp fica em nome_perfil
emailstring | nullGravado em minúsculas
tagsstring[]Substitui a lista
adicionar_tags / remover_tagsstring[]Aplicadas sobre as tags atuais (ou sobre tags, se vier junto). Até 50 tags por contato, 50 caracteres cada
notasstring até 4.000 | nullAnotações livres
opt_outbooleantrue bloqueia envio de template para o contato
curl -s -X POST "$BASE/contato-update" \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{"contato":"5511999990000","nome":"Ana Souza","email":"ana@exemplo.com","adicionar_tags":["cliente"]}'

Resposta 200: { "ok": true, "contato": { id, wa_id, nome, nome_perfil, email, tags, notas, opt_out, atualizado_em } }. Erros: 400, 404 CONTATO_NAO_ENCONTRADO.

Como consultar horários e marcar agendamentos pela API?

Rota /agenda, para contas com o módulo de agenda. Datas com hora sempre em ISO 8601 com fuso (Z ou -03:00); sem fuso a API responde 400.

ChamadaEscopoO que faz
GET /agenda?acao=agendasagenda:readAgendas ativas: id, nome, descricao, duracao_min, disponibilidade, antecedencia_min_horas, janela_dias
GET /agenda?acao=horarios&agenda_id=&dia=YYYY-MM-DD[&dias=N]agenda:readHorários livres de 1 a 14 dias a partir de dia (data no fuso da conta). Já descontam disponibilidade, antecedência mínima, janela máxima e horários ocupados
GET /agenda?acao=agendamentos&contato= ou &conversation_id= [&futuros=true]agenda:readAté 100 agendamentos do contato, por data de início. futuros=true traz só os que ainda vão acontecer (inclui cancelados: confira status)
POST /agendaagenda:writeCria agendamento. Resposta 201
PATCH /agendaagenda:writeMuda status, remarca ou altera observações

Campos do POST /agenda

CampoTipoObrigatórioNotas
agenda_iduuidsimAgenda ativa da conta
inicioISO com fusosimPrecisa ser exatamente um inicio devolvido por acao=horarios. O fim é calculado pela duração da agenda
titulostring até 200simEx.: "Avaliação"
contatotelefonenãoLiga o agendamento ao contato e à conversa mais recente dele
conversation_iduuidnãoLiga à conversa e ao contato dela. Com contato junto, os dois precisam combinar
observacoesstring até 2.000não
product_iduuidnãoProduto ou serviço da conta

PATCH /agenda recebe agendamento_id e ao menos um de: status (marcado, confirmado, concluido, cancelado, faltou), inicio (remarca, com a mesma checagem de horário livre) ou observacoes. O lembrete automático só funciona quando o agendamento está ligado a uma conversa. Agendamento criado por chave de API fica com origem: "ia".

curl -s "$BASE/agenda?acao=horarios&agenda_id=2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f&dia=2026-10-26&dias=7" \
  -H "Authorization: Bearer $KEY"

curl -s -X POST "$BASE/agenda" \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{"agenda_id":"2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f","inicio":"2026-10-26T09:00:00-03:00","titulo":"Avaliação","conversation_id":"4e7a2b91-3c5d-4f6e-9a8b-1c2d3e4f5a6b"}'

curl -s -X PATCH "$BASE/agenda" \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{"agendamento_id":"6b8d0f2a-4c6e-4a1b-9d3f-5e7a9c1b3d5f","status":"cancelado"}'

Erros: 400 (incluindo CONVERSA_DE_OUTRO_CONTATO), 404 (AGENDA_NAO_ENCONTRADA, AGENDAMENTO_NAO_ENCONTRADO, CONTATO_NAO_ENCONTRADO, CONVERSA_NAO_ENCONTRADA, PRODUTO_NAO_ENCONTRADO), 409 AGENDA_INATIVA e 409 HORARIO_INDISPONIVEL: o horário não está entre os livres ou foi ocupado entre a consulta e a gravação. Consulte de novo e ofereça outro.

Como criar e concluir tarefas pela API?

Rota /tarefas, escopo tasks:write nos três métodos. Funciona com o quadro de tarefas da conta.

Campo do POSTTipoNotas
titulostring até 200Obrigatório
descricaostring até 4.000
prioridadebaixa | media | alta | urgentePadrão media
prazoISO com fuso
responsavel_iduuidAtendente da conta
conversation_id / contatouuid / telefoneMesma regra da agenda
etiquetasstring[]Máximo 20
  • POST cria a tarefa na primeira coluna do quadro que não é de conclusão. Resposta 201 com { "ok": true, "tarefa": { ... } }.
  • PATCH recebe tarefa_id e ao menos um de coluna_id, concluir: true, prioridade, prazo, responsavel_id, descricao. concluir move para a primeira coluna de conclusão; não combine com coluna_id.
  • GET ?conversation_id= ou ?contato= [&abertas=true]: até 100 tarefas, mais recentes primeiro.
curl -s -X POST "$BASE/tarefas" \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{"titulo":"Ligar para a Ana sobre o orçamento","prioridade":"alta","prazo":"2026-10-27T18:00:00-03:00","conversation_id":"4e7a2b91-3c5d-4f6e-9a8b-1c2d3e4f5a6b"}'

curl -s -X PATCH "$BASE/tarefas" \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{"tarefa_id":"8a0c2e4f-6b8d-4f1a-9c3e-5b7d9f1a3c5e","concluir":true}'

Erros: 400, 404 (TAREFA_NAO_ENCONTRADA, COLUNA_NAO_ENCONTRADA, USUARIO_NAO_ENCONTRADO, CONVERSA_NAO_ENCONTRADA, CONTATO_NAO_ENCONTRADO, SEM_COLUNA).

Como listar conversas, contatos e números?

Não existe rota REST para listas. Elas saem pelo servidor MCP, com a mesma chave, por uma chamada JSON-RPC tools/call:

Ferramenta MCPDevolveEscopo
listar_conversasConversas mais recentes, com filtros estado, modo, nao_lidas, busca e limite (padrão 20, máximo 100)messages:read
buscar_contatosContatos por nome, telefone, e-mail ou tag (padrão 20, máximo 100)contacts:read
listar_numerosNúmeros conectados com o phone_number_id da Meta, qualidade e limite de envionenhum
curl -s -X POST "$BASE/mcp" \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"listar_conversas","arguments":{"modo":"ia","limite":10}}}'

A resposta traz o resultado em result.structuredContent (objeto) e o mesmo JSON como texto em result.content[0].text. Erro de negócio volta com result.isError: true.

Como é o fluxo típico de um backend de IA?

  1. Recebe message.receivedPelo webhook de saída. Reaja só quando dados.conversation.modo for ia: em humano, uma pessoa está conduzindo.
  2. Lê o agenteGET /agent-config?phone_number_id=…&conversation_id=… com os valores do evento (pode guardar em cache por 60 s).
  3. Lê o contextoGET /messages-list?conversation_id=…&limite=30. Se a mensagem tem mídia, POST /media-download.
  4. RespondePOST /whatsapp-send com para = dados.contact.wa_id. Se precisar, agenda (/agenda), cria tarefa (/tarefas) e grava o que coletou (/contato-update).
  5. Passa para humano quando precisarPOST /conversation-update com modo: "humano", o motivo e, se quiser, a equipe_id. Depois disso, pare de responder.
  6. Acompanha a entregaPelo evento message.status (entregue, lida, falhou).

Perguntas frequentes

Como consigo uma chave de API da FlashConnect?

No painel, em Integrações (Nova chave) ou em Conectar IA. Só o dono ou um admin da conta pode gerar, e a conta precisa ter cartão cadastrado. O segredo começa com ck_live_ e aparece uma única vez: guardamos só o hash SHA-256, então não há como recuperá-lo depois.

Dá para enviar mensagem para quem nunca falou comigo pela API?

Sim, mas só com template aprovado pela Meta (tipo template no POST /whatsapp-send). A API cria o contato e a conversa na hora. Texto livre, mídia e mensagens interativas só passam dentro da janela de 24 horas desde a última mensagem do contato; fora dela a API responde 409 JANELA_EXPIRADA sem chamar a Meta.

Como listo conversas, contatos e números pela API?

Não há rota REST para listar. Use o servidor MCP com a mesma chave: as ferramentas listar_conversas, buscar_contatos e listar_numeros devolvem essas listas em JSON. O histórico de uma conversa específica sai pelo GET /messages-list.

Posso usar a API com o n8n, Make ou meu próprio backend?

Sim. Qualquer sistema que faça requisições HTTPS com o header Authorization: Bearer ck_live_ funciona. Para receber as mensagens do contato, cadastre um webhook de saída; para o n8n também há o nó MCP Client Tool apontando para o servidor MCP.

Uma chave pode ver dados de outra empresa?

Não. Cada chave pertence a uma única conta (tenant) e só enxerga números, conversas e configurações dela. Um recurso de outra conta responde 404, como se não existisse.

A mensagem enviada pela API aparece no painel?

Sim. Toda mensagem enviada fica gravada no histórico da conversa com autor ia (quando vem de chave de API) ou humano, e os status seguintes (entregue, lida, falhou) chegam pelo evento message.status do webhook.

Quer usar a FlashConnect?

O acesso está sendo liberado por convite. Fale com a gente no WhatsApp.

Pedir convite no WhatsApp