VAI · API de integração

Referência para quem integra um sistema externo ao VAI (Vendedor Automático Inteligente). Escrita a partir das rotas em produção, não de um plano: o que está aqui existe hoje, e o que ainda não existe está marcado como tal.

Base: https://api.vendedorautomaticointeligente.com


1. O modelo: uma conta por operação

O VAI isola dados por conta. Conversas, leads, modelos de mensagem, campanhas e números de WhatsApp pertencem a uma conta e não atravessam para outra. Toda leitura é filtrada pela conta de quem chamou, e todo registro nasce carimbado com ela.

Numa rede com várias unidades, o desenho é uma conta do VAI por unidade:

Isso não é configuração: é como o sistema é construído. A regra vale inclusive para chamadas de API, então uma chave emitida para a unidade A não alcança a unidade B mesmo que o id da outra seja informado à mão.


2. Autenticação

Hoje existem dois caminhos, e eles servem a propósitos diferentes.

2.1 Chave por conta (recomendada para integração)

Usada hoje pelo endpoint de eventos. A chave pertence a uma conta e vai no cabeçalho:

Authorization: Bearer vai_xxxxxxxxxxxxxxxxxxxxxxxx

A conta é resolvida a partir da chave, nunca de um id no corpo da requisição. É isso que impede um sistema externo de disparar ação na conta errada.

2.2 Token de usuário

As rotas de conversa, modelo de mensagem e envio hoje autenticam com token de usuário, a mesma credencial que o aplicativo usa. Funciona para integrar já, com duas ressalvas: é a credencial de uma pessoa, e não tem escopo.

Em aberto: estender a chave por conta (2.1) aos endpoints das seções 4 a 6, com escopo por recurso. É o primeiro item a combinar numa integração nova.


3. Eventos: o sistema externo avisa o VAI

POST /api/v1/eventos · chave por conta

Um acontecimento no sistema do cliente (cadastro, pagamento, assinatura cancelada) entra no VAI e pode iniciar ou encerrar automações.

{
  "evento": "usuario.cadastrado",
  "id_externo": "cliente-8842",
  "contato": {
    "telefone": "5511960730881",
    "nome": "Ana Souza",
    "email": "[email protected]"
  },
  "dados": { "plano": "pro", "unidade": "tatuape" }
}
Campo Regra
evento obrigatório, até 80 caracteres, [A-Za-z0-9._-]. O vocabulário é de quem envia
id_externo opcional. Repetir o mesmo par evento + id não dispara de novo
contato.telefone obrigatório, com DDI e DDD
dados opcional, até 40 campos escalares. Viram variáveis na mensagem ({{plano}})

Resposta 202:

{
  "sucesso": true,
  "conta": "Unidade Tatuapé ([email protected])",
  "evento_id": 1010,
  "fluxos": 1,
  "encerrados": 0,
  "mensagem": "1 fluxo(s) iniciado(s)."
}

O nome da conta volta na resposta de propósito: chave trocada é o erro mais caro dessa integração, e assim ele aparece no primeiro envio, não semanas depois.

fluxos é quantas automações começaram; encerrados, quantas cadências foram interrompidas para aquele contato. Um mesmo evento pode fazer as duas coisas: usuario.cadastrado inicia a trilha de boas-vindas e, ao mesmo tempo, tira a pessoa da prospecção.

Reenvio é regra em integração: com id_externo, a segunda chamada responde duplicado: true e não repete nada.


4. Modelos de mensagem (templates da Meta)

Ciclo completo dentro do VAI: escrever, submeter à Meta, acompanhar aprovação e usar no disparo.

Verbo Rota O que faz
GET /api/message-templates lista os modelos da conta, com status e variáveis
POST /api/message-templates cria o modelo no VAI
POST /api/message-templates/meta/draft monta o rascunho no formato da Meta
POST /api/message-templates/{id}/submit-meta submete para aprovação
POST /api/message-templates/{id}/sync-meta traz o status atual de volta
POST /api/message-templates/sync-meta-todos sincroniza a conta inteira
POST /api/message-templates/{id}/duplicate copia um modelo existente
DELETE /api/message-templates/{id} remove
POST /api/ai/generate-template gera o texto do modelo com IA

Fluxo normal: cria, submete, e a Meta devolve PENDING na maioria dos casos. A aprovação vem depois, de forma assíncrona, e aparece no sync-meta. Os status espelham os da Meta: pendente, aprovado, rejeitado.

Submeter um modelo já enviado devolve 422: a segunda submissão do mesmo modelo é sempre engano.

O VAI monta as amostras que a Meta exige para cada variável do corpo, então o integrador não precisa inventar exemplos para passar na revisão.


5. Conversas e envio

Verbo Rota Para quê
POST /api/conversations/start abre conversa com um número
GET /api/conversations/{id}/messages histórico
POST /api/conversations/{id}/send texto livre
POST /api/conversations/{id}/send-media documento, áudio, vídeo
POST /api/conversations/{id}/send-image imagem
POST /api/conversations/{id}/send-template modelo aprovado

Abrir conversa exige o número e a conexão de WhatsApp que vai falar:

{
  "phone_number": "5511960730881",
  "whatsapp_instance_name": "unidade-tatuape",
  "contact_name": "Ana Souza"
}

Texto livre aceita até 4096 caracteres em text. Vale a janela de 24 horas da Meta: fora dela, só modelo aprovado.

Modelo aprovado:

{
  "template_name": "confirmacao_agendamento",
  "language_code": "pt_BR",
  "parameters": ["Ana", "quinta-feira às 15h"]
}

Os dois canais convivem: API Oficial da Meta para modelo e escala, QR Code para mensagem livre. A conversa é a mesma dos dois lados; o histórico não se parte.


6. Recebimento: o VAI avisa o sistema externo

Ainda não existe. Hoje o VAI recebe os webhooks da Meta e da Evolution, normaliza e grava a conversa, mas não repassa para fora: a interface se atualiza por consulta interna.

Para um sistema externo receber mensagem nova e status de entrega, falta um webhook de saída por conta, com URL e segredo configuráveis, assinatura para o destino conferir a origem, e reentrega quando a chamada falha.

Duas decisões definem o desenho e precisam ser combinadas antes:

  1. entrega em tempo real ou busca por intervalo;
  2. status de entrega e leitura junto, ou só a mensagem recebida.

7. Entrar com a conta do Google

Serve para o cadastro e para o login. Quem nunca teve conta ganha uma; quem já tem, com a mesma caixa de e-mail, entra na dela.

Verbo Rota Para quê
GET /api/auth/google/redirect devolve para onde mandar a pessoa
GET /api/auth/google/callback o Google chama de volta; o VAI identifica e redireciona ao app
POST /api/auth/google/sessao troca o ticket pelo token de sessão

O caminho inteiro, na ordem:

  1. O app pede a URL em /api/auth/google/redirect e leva a pessoa para lá.
  2. Ela escolhe a conta no Google.
  3. O Google devolve para o callback, que identifica, cria a conta se precisar e redireciona para o app com ?google=TICKET (e &novo=1 em conta nova).
  4. O app troca o ticket pela sessão:
POST /api/auth/google/sessao
{ "ticket": "o valor que veio em ?google=" }

Resposta:

{
  "success": true,
  "token": "…",
  "user": { "…": "…" },
  "precisa_whatsapp": true
}

Por que um ticket e não o token. O token de sessão não pode viajar na barra de endereço: fica no histórico do navegador, no cabeçalho de referência e no log de qualquer proxy no caminho. O ticket vale uma vez só e expira em três minutos.

Conta existente. É vinculada automaticamente quando o Google confirma o e-mail verificado, e a senha antiga continua valendo. Sem e-mail verificado não há vínculo: seria possível tomar a conta de alguém criando um Google com o e-mail dela.

O que a conta nova tem, e o que falta. Nasce com nome, e-mail e foto, mais sete dias de teste. O e-mail já entra como verificado, então não há código para confirmar. O Google não entrega telefone, e por isso a resposta traz precisa_whatsapp: enquanto for true, o app deve pedir o WhatsApp, que é o que a trilha de ativação usa. CPF e data de nascimento só fazem falta na hora de assinar.

Erros voltam na URL do app, não como JSON, porque quem redireciona é o Google: ?google_erro=cancelado, expirado, falhou ou email_nao_verificado.


8. Provisionamento pela matriz

Criar contas, definir plano e gerir usuários existe sob /api/admin, protegido por sessão de administrador:

Verbo Rota
GET /api/admin/users
POST /api/admin/users
POST /api/admin/users/{id}/plan
DELETE /api/admin/users/{id}

Em aberto: expor esse grupo para a matriz por chave com escopo administrativo, de forma que ela crie e configure unidades sem sessão de navegador.


9. Erros

Código Quando
401 chave ausente, inválida ou revogada
403 a conta não tem permissão para o recurso
404 o recurso não existe ou pertence a outra conta
409 operação já em andamento
422 dado inválido, com a mensagem dizendo qual campo e por quê

O 404 em recurso de outra conta é deliberado: responder 403 confirmaria que o id existe em algum lugar.


10. Antes de escrever código

  1. Chave por conta para os endpoints das seções 4 a 6, em vez de token de usuário.
  2. Webhook de saída (seção 6), com as duas decisões da lista.
  3. Provisionamento por chave administrativa (seção 8).
  4. Ambiente de teste: uma conta com número conectado, para validar envio e modelo sem tocar em operação real.

Dúvida sobre algo que não está aqui: fale com a Agência Novo Foco. Este documento descreve o que existe em produção; o que ainda não existe está marcado como tal.