Evolution API Endpoints
Documentação completa dos endpoints da Evolution API utilizados no projeto pilot-status-nextjs-typescript-frontend-backend.
Baseado em: packages/evolution/src/
Sumário
- Instance Endpoints
- Message Endpoints
- Chat Endpoints
- Group Endpoints
- Evolution Webhooks
- Common Types
- Headers & Authentication
Instance Endpoints
1. Create Instance
Endpoint: POST /instance/create
Descrição: Cria uma nova instância do WhatsApp.
Request Body:
{
instanceName: string; // Nome da instância
number: string; // Número do assinante (apenas dígitos, sem "+")
qrcode?: boolean; // Default: true - Gerar QR Code
integration?: string; // Default: "WHATSAPP-BAILEYS"
syncFullHistory?: boolean; // Default: false
proxyFields?: Record<string, unknown>; // Campos de proxy (proxyHost, etc.)
extra?: Record<string, unknown>; // Campos extras
}
Response:
{
raw: unknown; // Resposta JSON bruta
state: string; // Estado da instância (ex: "open", "close", "connecting")
instanceApiKey: string | null; // API key da instância ("hash")
qrcodeBase64: string | null; // QR Code em base64
pairingCode: string | null; // Código de pareamento
}
2. Connect Instance
Endpoint: GET /instance/connect/:instanceName
Descrição: Conecta uma instância existente e retorna o QR Code.
Query Params:
number(opcional): Número do WhatsApp
Response:
{
raw: unknown;
qrcodeBase64: string | null;
pairingCode: string | null;
}
3. Connection State
Endpoint: GET /instance/connectionState/:instanceName
Descrição: Obtém o estado atual da conexão da instância.
Response:
{
state: string | null; // "open" | "close" | "connecting" | "not_found"
instanceName: string | null;
raw: unknown;
}
4. Set Presence
Endpoint: POST /instance/setPresence/:instanceName
Descrição: Define o estado de presença da instância (disponível, digitando, etc.).
Request Body:
{
presence: "available" | "unavailable" | "composing" | "recording" | "paused";
number?: string; // Chat JID quando scoping para conversa específica
delay?: number; // Milissegundos para manter a presença
}
Response:
{
status: number;
bodyText: string;
raw: unknown;
isConnectedSignal: boolean; // true quando status=201 e body não contém "close"
}
5. Restart Instance
Endpoint: POST /instance/restart/:instanceName
Descrição: Reinicia uma instância.
Response:
{
raw: unknown;
state: string | null;
instanceName: string | null;
hasReconnectBundle: boolean; // true quando body inclui payload QR (disconnect real)
isObjectObjectSignal: boolean; // true quando Evolution retorna erro "[object Object]"
bodyText: string;
}
6. Logout Instance
Endpoint: DELETE /instance/logout/:instanceName
Descrição: Faz logout de uma instância.
Response: void (no content on success)
7. Delete Instance
Endpoint: DELETE /instance/delete/:instanceName
Descrição: Deleta uma instância.
Response: void (no content on success)
Message Endpoints
1. Send Text Message
Endpoint: POST /message/sendText/:instanceName
Descrição: Envia uma mensagem de texto.
Request Body:
{
number: string; // Número do destinatário
text: string; // Conteúdo da mensagem
linkPreview?: boolean; // Habilita preview de link quando texto contém URL http(s)
}
Response:
{
raw: unknown;
keyId: string | null; // Evolution key.id da mensagem enviada
instanceId: string | null;
state: string | null; // instance.state no body (útil para detectar "close")
bodyText: string;
}
2. Send Buttons Message
Endpoint: POST /message/sendButtons/:instanceName
Descrição: Envia uma mensagem com botões interativos.
Request Body:
{
number: string;
title: string;
description: string;
footer?: string;
buttons: Array<Record<string, unknown>>;
thumbnailUrl?: string;
}
Response:
{
raw: unknown;
keyId: string | null;
instanceId: string | null;
state: string | null;
bodyText: string;
}
3. Send Media Message
Endpoint: POST /message/sendMedia/:instanceName
Descrição: Envia uma mensagem com mídia (imagem, vídeo, documento).
Request Body:
{
number: string;
mediatype: "image" | "video" | "document" | string;
mimetype: string;
media: string; // URL ou base64
caption?: string;
fileName?: string;
}
Response:
{
raw: unknown;
keyId: string | null;
instanceId: string | null;
state: string | null;
bodyText: string;
}
Chat Endpoints
1. Send Presence
Endpoint: POST /chat/sendPresence/:instanceName
Descrição: Envia sinal de presença para um chat (ex: digitando).
Request Body:
{
presence: "available" | "unavailable" | "composing" | "recording" | "paused";
number?: string; // Chat JID específico
delay?: number; // Milissegundos para manter o sinal
}
Response:
{
status: number;
bodyText: string;
raw: unknown;
isConnectedSignal: boolean; // true quando status=200/201 e body não contém "close"
}
Uso típico: Simular "digitando" antes de enviar mensagem:
// Calcula delay baseado no tamanho do texto: 600 + (tamanho * 35)ms
const typingDelayMs = Math.max(800, Math.min(5000, 600 + text.length * 35));
2. Find Status Message
Endpoint: POST /chat/findStatusMessage/:instanceName
Descrição: Busca histórico de status de mensagens por (remoteJid, keyId).
Request Body:
{
where: {
remoteJid: string;
id: string; // evolutionKeyId
};
page?: number; // Default: 1
offset?: number; // Default: 10
}
Response:
Array<{
status?: string;
keyId?: string;
remoteJid?: string;
}>
3. WhatsApp Numbers Info
Endpoint: POST /chat/whatsappNumbers/:instanceName
Descrição: Retorna informações sobre números de WhatsApp consultados.
Request Body:
{
numbers: string[]; // Lista de números para consultar
}
Response:
Array<{
number?: string;
exists?: boolean;
name?: string;
}>
Group Endpoints
1. Find Group Info
Endpoint: GET /group/findGroupInfos/:instanceName
Descrição: Obtém informações sobre um grupo.
Query Params:
groupJid(requerido): JID do grupoparticipants(opcional): Default "false" - Incluir participantes
Response:
{
subject: string | null; // Nome do grupo
raw: unknown;
}
Evolution Webhooks
Webhook Endpoint
Endpoint: POST /api/internal/webhook
Descrição: Recebe webhooks da Evolution API e processa eventos de mensagens e conexão.
Headers:
- Content-Type: application/json
Envelope Base:
interface EvolutionWebhookEnvelope {
date_time?: string; // ISO timestamp da Evolution
sender?: string; // Remetente
server_url?: string; // URL do servidor Evolution
apikey?: string; // API key
destination?: string; // Destinatário
}
1. Connection Update
Event: connection.update
Descrição: Recebido quando o estado da conexão da instância muda.
Propriedades Necessárias (Pilot Status):
{
event: "connection.update";
instance: string; // Nome da instância
data: {
state?: string; // "open" | "close" | "connecting"
instance?: string;
statusReason?: number;
};
}
O que a Pilot Status faz:
- Atualiza o estado da instância no banco de dados (
whatsappInstance.state) - Detecta transição de OPEN para CONNECTING e inicia loop de recuperação
- Marca
firstConnectedAtna primeira conexão bem-sucedida - Enfileira validação de instância após 15 segundos
- Envia alertas Pushover quando a instância é desconectada ou conectada pela primeira vez
- Envia notificações WhatsApp para usuários quando a instância é desconectada
- Despacha evento
number.connectedpara webhooks do cliente
Regras de Notificação:
- Conexão: envia alerta em qualquer primeiro sucesso
- Desconexão: envia apenas se estado for "close" e statusReason não for 401
- Logout: envia alerta de deslogado
2. Logout Instance
Event: logout.instance
Descrição: Recebido quando a instância é deslogada do WhatsApp.
Propriedades Necessárias (Pilot Status):
{
event: "logout.instance";
instance: string; // Nome da instância
data: unknown;
}
O que a Pilot Status faz:
- Define estado da instância como "LOGOUT"
- Envia alerta Pushover para desenvolvedores
- Envia notificação WhatsApp para usuários com texto personalizado
- Limpa cache de alertas de desconexão em Redis
Exemplo de Notificação WhatsApp:
Atenção: sua conexão WhatsApp "{displayName}" foi deslogada e precisa ser reconectada na Pilot Status.
3. Messages Upsert
Event: messages.upsert
Descrição: Recebido quando uma nova mensagem é criada ou atualizada (enviada ou recebida).
Propriedades Necessárias (Pilot Status):
{
event: "messages.upsert";
instance: string;
data: {
key?: {
id?: string; // ID único da mensagem (evolutionKeyId)
fromMe?: boolean; // true se enviado por nós
remoteJid?: string; // JID do remetente/destinatário
participant?: string; // Para grupos, participante
participantAlt?: string;
remoteJidAlt?: string;
addressingMode?: "lid" | "pn";
};
source?: string;
status?: string;
message?: Record<string, unknown>; // Conteúdo da mensagem
pushName?: string; // Nome do contato
instanceId?: string;
messageType?: string; // "conversation", "image", etc.
messageTimestamp?: number;
};
}
O que a Pilot Status faz:
Para Mensagens de Grupo:
- Detecta se é mensagem de grupo (
remoteJidcontém@g.us) - Extrai informações do participante (digits ou LID)
- Busca nome do grupo via API Evolution (com cache)
- Despacha webhook
message.grouppara clientes configurados - Persiste identidade WhatsApp para LIDs
- Ignora mensagens de grupos não "conversation"
- Ignora mensagens da instância do Pilot Status
Para Mensagens Diretas:
- Persiste JIDs da Evolution: Salva mapeamento
evolutionKeyId -> [remoteJid, remoteJidAlt] - Extrai conteúdo: Texto, mídia, botões, etc.
- Detecta respostas: Verifica se mensagem é quote/reply
- Correlaciona com mensagens enviadas: Busca última mensagem enviada para o mesmo contato
- Detecta opt-in: Busca token
optin <slug>na mensagem - Registra opt-in: Cria/atualiza registro em
projectWhatsAppOptIn - Despacha webhooks de opt-in: Evento
optin.createdpara clientes - Trata botão de reconexão: Intercepa resposta a notificação de desconexão
- Despacha webhooks de mensagem:
message.sent(sefromMe=true)message.reply(se é resposta)message.received(se é mensagem recebida)
- Aplica redação de PII: Remove dados sensíveis após período de retenção
- Persiste mensagens inbound: Guarda em
IncomingMessagepara debug
Fluxo de Opt-In:
Mensagem contém "optin <token>"
→ Busca projeto por slug ou ID
→ Cria registros de opt-in para todas as variantes de número
→ Atualiza lastSeenAt
→ Despacha webhooks optin.created para todos os endpoints configurados
Tratamento de Botão de Reconexão:
// Botão ID: RECONNECT_BTN_ID
// Correlação: RECONNECT_CORRELATION_KEY_PREFIX + <messageId>
// Ação: Enfileira nova notificação de desconexão
4. Messages Update
Event: messages.update
Descrição: Recebido quando o status de uma mensagem muda (SENT, DELIVERED, READ, FAILED).
Propriedades Necessárias (Pilot Status):
{
event: "messages.update";
instance: string;
data: {
keyId?: string; // ID da mensagem (evolutionKeyId)
fromMe?: boolean;
status?: string; // "PENDING", "SERVER_ACK", "DELIVERED", "READ", "ERROR"
messageId?: string; // ID interno da mensagem
remoteJid?: string;
instanceId?: string;
};
date_time?: string; // Timestamp do evento
}
Mapeamento de Status:
STATUS_MAP = {
"PENDING": "PENDING",
"SERVER_ACK": "SENT",
"DELIVERED": "DELIVERED",
"READ": "READ",
"ERROR": "FAILED",
}
O que a Pilot Status faz:
-
Busca mensagem no banco:
- Por
id(messageId interno) - Por
evolutionKeyId - Por
evolutionKeyId+evolutionInstanceId - Por
evolutionKeyId(fallback)
- Por
-
Valida atualização: Previne regressões de status (ex: READ → SENT)
-
Atualiza timestamps:
sentAtpara status SENTdeliveredAtpara status DELIVEREDreadAtpara status READfailedAtpara status FAILED
-
Persiste informações de erro:
errorMessage: Mensagem amigávelinternalErrorMessage: Detalhes técnicos
-
Persiste JIDs: Salva
remoteJideremoteJidAlt -
Registra no MessageTrace:
EVOLUTION_STATUS_UPDATE_RECEIVED: Evento recebidoMESSAGE_STATUS_UPDATED: Status atualizado no banco
-
Enfileira verificação de delivery:
- Quando status muda para SENT
- Job
sent-delivery-checkapós 60 segundos - 3 tentativas com backoff fixo de 30 segundos
-
Despacha webhooks do cliente:
message.failed: Quando status é FAILED e webhook está ativomessage.sent: Quando status é SENT, anterior não era SENT, e fromMe=truemessage.delivered: Quando status é DELIVERED e anterior não era DELIVEREDmessage.read: Quando status é READ e anterior não era READ
-
Respeita redação de PII: Remove dados sensíveis após retenção
-
Respeita subscrições de instância: Verifica se webhook está inscrito para a instância
Dispatch de Webhook (Quando mensagem não encontrada): Se não encontrar mensagem no banco, faz dispatch de nível tenant:
{
event: "message.sent" | "message.delivered" | "message.read" | "message.failed",
data: {
messageId: keyId || messageId,
internalMessageId: null,
destinationNumber: "+55...",
status: "SENT" | "DELIVERED" | "READ" | "FAILED",
sentAt?: ISO_STRING,
deliveredAt?: ISO_STRING,
readAt?: ISO_STRING,
failedAt?: ISO_STRING,
errorMessage?: string,
}
}
Eventos Internos de Webhook do Cliente
A Pilot Status despacha os seguintes eventos para webhooks dos clientes:
message.received
Triggerado quando: Mensagem recebida (não enviada por nós, não é resposta)
Payload:
{
event: "message.received",
data: {
fromMe: boolean;
from: string; // E.164 ou LID
fromName: string | null;
destinationNumber: string;
content: string;
receivedAt: string; // ISO timestamp
messageId: string; // Evolution keyId
correlationId?: string;
environment: "TEST" | "LIVE";
whatsappInstanceName?: string;
}
}
message.reply
Triggerado quando: Mensagem é resposta a mensagem enviada anteriormente
Payload:
{
event: "message.reply",
data: {
from: string;
fromName: string | null;
destinationNumber: string;
content: string; // Conteúdo da mensagem respondida
replyContent: string; // Conteúdo da resposta
receivedAt: string;
messageId: string;
quotedMessageId: string; // Evolution keyId da mensagem respondida
messageRepliedId?: string; // ID interno da mensagem respondida
correlationId?: string;
environment: "TEST" | "LIVE";
buttonId?: string; // Se resposta de botão
}
}
message.sent
Triggerado quando: Mensagem enviada atinge status SENT
Payload:
{
event: "message.sent",
data: {
messageId: string; // Evolution keyId
internalMessageId?: string; // ID interno
correlationId?: string;
environment: "TEST" | "LIVE";
destinationNumber: string;
content: string;
status: "SENT";
sentAt: string;
}
}
message.delivered
Triggerado quando: Mensagem atinge status DELIVERED
Payload:
{
event: "message.delivered",
data: {
messageId: string;
internalMessageId?: string;
correlationId?: string;
environment: "TEST" | "LIVE";
destinationNumber: string;
content: string;
status: "DELIVERED";
deliveredAt: string;
}
}
message.read
Triggerado quando: Mensagem atinge status READ
Payload:
{
event: "message.read",
data: {
messageId: string;
internalMessageId?: string;
correlationId?: string;
environment: "TEST" | "LIVE";
destinationNumber: string;
content: string;
status: "READ";
readAt: string;
}
}
message.failed
Triggerado quando: Mensagem atinge status FAILED
Payload:
{
event: "message.failed",
data: {
messageId: string;
internalMessageId?: string;
correlationId?: string;
environment: "TEST" | "LIVE";
destinationNumber: string;
content: string;
status: "FAILED";
failedAt: string;
errorMessage: string;
}
}
message.group
Triggerado quando: Mensagem recebida em grupo
Payload:
{
event: "message.group",
data: {
fromNumber: string; // E.164 ou LID do participante
fromName: string | null;
fromMe: boolean;
groupName: string | null;
content: string;
messageId: string;
groupId: string; // JID do grupo
happenedAt: string;
environment: "TEST" | "LIVE";
}
}
optin.created
Triggerado quando: Usuário envia mensagem contendo "optin <token>"
Payload:
{
event: "optin.created",
data: {
projectId: string;
environment: "TEST" | "LIVE";
whatsappInstanceName: string;
destinationNumber: string;
destinationHash: string;
fromName: string | null;
isFirstOptIn: boolean;
firstOptInAt: string;
lastSeenAt: string;
}
}
Ingestão Dual (Webhook + RabbitMQ)
A Pilot Status implementa um sistema de ingestão dual para garantir processamento confiável:
Webhook Primário:
- Endpoint:
POST /api/internal/webhook - Uso: Processamento imediato de webhooks Evolution
- Deduplicação: Redis (chave por evento)
RabbitMQ Secundário:
- Queue:
evolution_events - Uso: Consumidor processa eventos como backup/reconexão
- Deduplicação: Redis compartilhado
Dual Ingestion Manager:
- Coordenador
dual-ingestion.ts - Sistema de locks para evitar processamento duplo
- Finaliza ingestão ao término do processamento
Propriedades da Evolution Necessárias para Pilot Status
| Propriedade | Uso na Pilot Status | Obrigatório |
|------------|---------------------|-------------|
| event | Roteamento para handler correto | ✅ Sim |
| instance | Identificar instância no banco | ✅ Sim |
| date_time | Timestamp do evento | ❌ Não |
| data.key.id | Correlação com mensagens enviadas | ✅ Sim |
| data.key.fromMe | Diferenciar enviado vs recebido | ✅ Sim |
| data.key.remoteJid | Identificar contato | ✅ Sim |
| data.message | Conteúdo da mensagem | ✅ Sim |
| data.pushName | Nome do contato | ❌ Não |
| data.messageType | Tipo de mensagem | ❌ Não |
| data.status | Status da mensagem | ✅ Sim (messages.update) |
| data.state | Estado da conexão | ✅ Sim (connection.update) |
Headers Especiais
Verification (Opcional):
X-Evolution-Signature: sha256=<hmac>
Dual Ingestion Headers:
X-Ingestion-Source: WEBHOOK | RABBITMQ
X-Dedup-Key: <unique_key>
Common Types
EvolutionConnectionState
type EvolutionConnectionState =
| "open"
| "close"
| "connecting"
| "not_found"
| string;
InstancePresence
type InstancePresence =
| "available"
| "unavailable"
| "composing"
| "recording"
| "paused";
EvolutionCallOptions
interface EvolutionCallOptions {
apiKey?: string; // Override global apikey header (per-instance key)
signal?: AbortSignal; // Para cancelamento/timeout
fetchImpl?: typeof fetch; // Fetch injetado (tests)
baseUrl?: string; // Override base URL (tests)
}
Headers & Authentication
Todos os endpoints exigem o header de autenticação:
apikey: <EVOLUTION_API_KEY>
Autenticação por Instância
Alguns endpoints suportam override da API key por instância:
apiKey: opts.apiKey ?? getEvolutionApiKey();
Error Handling
EvolutionHttpError
Lançado em respostas não-2xx:
{
status: number;
bodyText: string;
url: string;
isInstanceNotFound?: boolean; // true quando status indica instância não encontrada
}
EvolutionInvalidJsonError
Lançado quando a API retorna JSON inválido ou vazio.
EvolutionNotConfiguredError
Lançado quando EVOLUTION_API_URL ou EVOLUTION_API_KEY não estão configurados.
URL Base
A URL base da API é configurada via:
- Variável de ambiente:
EVOLUTION_API_URL - Variável de ambiente:
EVOLUTION_API_KEY
Exemplo de URL completa:
https://api.evolution.com/instance/create
Observações Importantes
- Instance Name: O nome da instância deve ser URL-encoded nos endpoints.
- Proxies: O suporte a proxies é configurável via
proxyFieldsno create esetupProxy()no fetch. - Timeouts: Use
signal(AbortSignal) para controlar timeouts. - Retries: Implementar retries com backoff exponencial é recomendado.
- Error Signals: Alguns erros especiais como
[object Object]são tratados internamente.
Testes
Os testes unitários e de integração podem ser encontrados em:
packages/evolution/test/v2/packages/evolution/test/webhook/
Referências
- Código fonte:
packages/evolution/src/ - Tipos:
packages/evolution/src/types.ts - Provider:
packages/evolution/src/provider.ts - HTTP client:
packages/evolution/src/http.ts - Webhook types:
packages/evolution/src/webhook/events.ts - Webhook schema:
packages/evolution/src/webhook/schema.ts - Webhook handlers:
apps/fullstack/src/app/api/internal/webhook/handlers/ - Connection handler:
apps/fullstack/src/app/api/internal/webhook/handlers/connection.ts - Messages upsert handler:
apps/fullstack/src/app/api/internal/webhook/handlers/messages-upsert.ts - Messages update handler:
apps/fullstack/src/app/api/internal/webhook/handlers/messages-update.ts - Webhook route:
apps/fullstack/src/app/api/internal/webhook/route.ts - Dual ingestion:
apps/fullstack/src/app/api/internal/webhook/dual-ingestion.ts