Webhooks
Receber notificações de eventos em tempo real via webhooks.
Webhooks
Em breve na API pública
O gerenciamento de webhooks via API (/api/v1/webhooks) ainda não está disponível. Por enquanto, webhooks podem ser configurados diretamente pelo painel do Ecosys Auto em Configurações → Webhooks.
Para dúvidas, entre em contato: suporte@ecosysauto.ai
Webhooks permitem que você receba notificações em tempo real sobre eventos importantes: novos veículos cadastrados, negócios ganhos/perdidos, atividades vencendo e muito mais.
Como Funciona
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ Evento Ocorre │────>│ Ecosys Auto │────>│ Seu Servidor │
│ (ex: negócio │ │ envia POST │ │ processa e │
│ ganho) │ │ para sua URL │ │ responde 200 OK │
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘- Um evento ocorre na plataforma (veículo cadastrado, negócio ganho, etc.)
- O Ecosys Auto envia um POST para a URL configurada
- Seu servidor processa o evento e responde com
200 OK - Se falhar, tentamos novamente com backoff exponencial
Eventos Disponíveis
Eventos de Veículos
| Evento | Quando é Disparado |
|---|---|
vehicle.created | Novo veículo cadastrado |
vehicle.updated | Dados/fase/preço alterados |
vehicle.sold | Status alterado para vendido |
vehicle.phase_changed | Veículo movido no kanban |
vehicle.price_changed | Preço atualizado |
vehicle.removed | Veículo arquivado |
Eventos de Negócios
| Evento | Quando é Disparado |
|---|---|
deal.created | Novo negócio criado |
deal.updated | Dados ou fase alterados |
deal.phase_changed | Negócio movido no pipeline |
deal.won | Marcado como ganho |
deal.lost | Marcado como perdido |
Eventos de Clientes
| Evento | Quando é Disparado |
|---|---|
client.created | Novo cliente cadastrado |
client.updated | Dados alterados |
client.deactivated | Cliente desativado |
Eventos de Vendas
| Evento | Quando é Disparado |
|---|---|
sale.delivered | Veículo entregue ao comprador (inclui prazos de garantia e transferência) |
sale.cancelled | Venda cancelada, inclusive depois da entrega |
Eventos de Pós-venda
| Evento | Quando é Disparado |
|---|---|
aftersale.ticket_opened | Ocorrência de pós-venda aberta para uma venda entregue (vício oculto, garantia, documentação etc.) |
aftersale.survey_answered | Pesquisa de satisfação (CSAT ou NPS) respondida pelo cliente. Dispara ao consolidar a resposta e de novo a cada edição consolidada |
Eventos de Atividades
| Evento | Quando é Disparado |
|---|---|
activity.created | Nova atividade criada |
activity.completed | Atividade concluída |
activity.due_soon | 24h antes do vencimento |
activity.overdue | Prazo expirado |
Eventos Financeiros
| Evento | Quando é Disparado |
|---|---|
financial.created | Novo registro financeiro |
financial.paid | Pagamento confirmado |
financial.overdue | Vencimento expirado |
Formato do Payload
Todas as notificações seguem este formato:
{
"id": "evt_abc123def456",
"type": "vehicle.created",
"api_version": "v1",
"created_at": "2026-02-04T14:30:00Z",
"data": {
"object": {
"id": "uuid-do-veiculo",
"title": "Honda Civic EXL 2.0 2024",
"brand": "Honda",
"model": "Civic",
"price": 142900.00,
"phase": "entrada",
"status": "ativo",
"created_at": "2026-02-04T14:30:00Z"
},
"previous_attributes": null
},
"team_id": "uuid-do-time",
"webhook_id": "uuid-do-webhook"
}Para eventos de atualização, previous_attributes contém os valores anteriores:
{
"id": "evt_update123",
"type": "vehicle.updated",
"data": {
"object": {
"id": "uuid-do-veiculo",
"phase": "em-vitrine",
"price": 139900.00
},
"previous_attributes": {
"phase": "entrada",
"price": 142900.00
}
}
}Exemplo: aftersale.ticket_opened
O objeto traz a ocorrência com o número da venda. O prazo cdc_due_at (30 dias a partir do recebimento do veículo, CDC art. 18 §1º) fica null até o veículo ser recebido pela loja.
{
"id": "evt_ticket123",
"type": "aftersale.ticket_opened",
"api_version": "v1",
"created_at": "2026-09-16T13:05:00Z",
"data": {
"object": {
"id": "uuid-da-ocorrencia",
"number": "OC-2026-0007",
"case_id": "uuid-do-acompanhamento",
"sale_id": "uuid-da-venda",
"sale_number": "VND-2026-0042",
"store_id": "uuid-da-loja",
"client_id": "uuid-do-cliente",
"vehicle_id": "uuid-do-veiculo",
"seller_user_id": "uuid-do-vendedor",
"owner_user_id": "uuid-do-responsavel",
"type": "vicio_oculto",
"status": "aberto",
"severity": "alta",
"coverage": "legal",
"source": "staff",
"title": "Barulho na suspensão dianteira",
"description": "Cliente relata ruído ao passar em lombadas",
"reported_at": "2026-09-16T13:05:00Z",
"defect_discovered_on": "2026-09-14",
"within_legal_warranty": true,
"vehicle_received_at": null,
"cdc_due_at": null,
"first_response_due_at": "2026-09-17T13:05:00Z",
"created_at": "2026-09-16T13:05:00Z"
}
},
"team_id": "uuid-do-time"
}| Campo | Valores |
|---|---|
type | vicio_oculto, garantia_legal, garantia_contratual, garantia_estendida, documentacao, transferencia, financeiro, atendimento, arrependimento, outro |
status | aberto, em_analise, aguardando_veiculo, em_reparo, aguardando_cliente, resolvido, recusado, cancelado |
severity | baixa, media, alta |
coverage | legal, contratual, estendida, cortesia, sem_cobertura ou null |
source | staff, survey, whatsapp, customer_portal |
Exemplo: aftersale.survey_answered
A resposta chega consolidada: a primeira nota vale, o cliente pode editar por até 10 minutos (no máximo 2 vezes) e cada edição consolidada dispara o evento de novo com edit_count maior. Use id + edit_count para saber se é a mesma resposta.
{
"id": "evt_survey123",
"type": "aftersale.survey_answered",
"api_version": "v1",
"created_at": "2026-09-20T18:12:00Z",
"data": {
"object": {
"id": "uuid-da-resposta",
"request_id": "uuid-do-pedido-de-pesquisa",
"case_id": "uuid-do-acompanhamento",
"sale_id": "uuid-da-venda",
"sale_number": "VND-2026-0042",
"store_id": "uuid-da-loja",
"client_id": "uuid-do-cliente",
"seller_user_id": "uuid-do-vendedor",
"type": "csat",
"score": 5,
"classification": "promoter",
"comment": "Entrega rápida e carro impecável",
"source": "web_link",
"respondent_verified": true,
"suspected_bot": false,
"answered_at": "2026-09-20T18:11:40Z",
"edit_count": 0
}
},
"team_id": "uuid-do-time"
}| Campo | Valores |
|---|---|
type | csat (nota de 1 a 5, sobre a entrega) ou nps (nota de 0 a 10, 30 dias depois) |
classification | detractor, passive ou promoter — calculada pela escala do type |
source | web_link e web_form (página da pesquisa), whatsapp_text (cliente digitou o número), whatsapp_button (tocou no botão) ou staff (alguém da loja registrou) |
respondent_verified | true quando houve interação confirmada do cliente (não é só a abertura do link) |
suspected_bot | true quando as regras de varredura acharam que a abertura foi de um scanner de link, não de uma pessoa |
edit_count | 0 na primeira resposta; aumenta a cada edição consolidada |
Verificando a Assinatura
Para garantir que a notificação veio do Ecosys Auto, verifique a assinatura no header X-Ecosys-Auto-Signature.
Headers Enviados
| Header | Descrição |
|---|---|
X-Ecosys-Auto-Signature | Assinatura HMAC-SHA256 |
X-Ecosys-Auto-Timestamp | Timestamp Unix do envio |
X-Ecosys-Auto-Event-Id | ID único do evento |
Content-Type | application/json |
Verificação em Node.js
import crypto from 'crypto';
import express from 'express';
const app = express();
const WEBHOOK_SECRET = process.env.ECOSYS_AUTO_WEBHOOK_SECRET;
app.use('/webhook', express.raw({ type: 'application/json' }));
app.post('/webhook', (req, res) => {
const signature = req.headers['x-ecosys-auto-signature'];
const timestamp = req.headers['x-ecosys-auto-timestamp'];
const payload = req.body.toString();
// Verificar timestamp (previne replay attacks — janela de 5 minutos)
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(timestamp)) > 300) {
return res.status(401).json({ error: 'Timestamp expirado' });
}
// Calcular assinatura esperada
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(signedPayload)
.digest('hex');
// Comparação segura (previne timing attacks)
if (!crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
)) {
return res.status(401).json({ error: 'Assinatura inválida' });
}
// Processar evento de forma assíncrona
const event = JSON.parse(payload);
switch (event.type) {
case 'vehicle.created':
// Publicar no portal de anúncios, enviar notificação, etc.
break;
case 'deal.won':
// Atualizar métricas, gerar contrato, etc.
break;
case 'activity.overdue':
// Enviar alerta, criar ticket, etc.
break;
}
// Responda RAPIDAMENTE com 200 OK
res.status(200).json({ received: true });
});Verificação em Python
import hmac
import hashlib
import time
import os
from flask import Flask, request, jsonify
app = Flask(__name__)
WEBHOOK_SECRET = os.environ['ECOSYS_AUTO_WEBHOOK_SECRET']
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-Ecosys-Auto-Signature')
timestamp = request.headers.get('X-Ecosys-Auto-Timestamp')
payload = request.get_data(as_text=True)
# Verificar timestamp
now = int(time.time())
if abs(now - int(timestamp)) > 300:
return jsonify({'error': 'Timestamp expirado'}), 401
# Calcular assinatura
signed_payload = f"{timestamp}.{payload}"
expected_signature = hmac.new(
WEBHOOK_SECRET.encode(),
signed_payload.encode(),
hashlib.sha256
).hexdigest()
# Comparação segura
if not hmac.compare_digest(signature, expected_signature):
return jsonify({'error': 'Assinatura inválida'}), 401
event = request.json
# Processar evento...
return jsonify({'received': True}), 200Política de Retentativas
Se sua URL não responder com 2xx, tentaremos novamente:
| Tentativa | Intervalo |
|---|---|
| 1a | Imediato |
| 2a | 5 minutos |
| 3a | 30 minutos |
| 4a | 2 horas |
| 5a | 12 horas |
| 6a | 24 horas |
Após 6 tentativas falhas consecutivas, o webhook é desativado automaticamente. Você receberá um email de alerta.
Boas Práticas
- Responda rapidamente — Retorne
200 OKem até 5 segundos - Processe assincronamente — Use filas (Bull, Celery, etc.) para tarefas demoradas
- Implemente idempotência — O mesmo evento pode ser entregue mais de uma vez (salve o
iddo evento) - Verifique a assinatura — Sempre valide a autenticidade antes de processar
- Use HTTPS — Obrigatório para receber webhooks
Roadmap
Planejamos disponibilizar os seguintes endpoints para gerenciar webhooks via API:
GET /api/v1/webhooks — Listar webhooks configurados
POST /api/v1/webhooks — Criar webhook
PUT /api/v1/webhooks/:id — Atualizar webhook
DELETE /api/v1/webhooks/:id — Remover webhook