Webhooks
Receber notificações de eventos em tempo real via webhooks.
Webhooks
Receba notificações em tempo real sobre eventos importantes no Ecosys Auto: novos veículos, prazos vencendo, atividades concluídas e mais.
Por que usar Webhooks?
Webhooks permitem que você seja notificado automaticamente quando eventos ocorrem, eliminando a necessidade de polling na API. Ideal para integrações com CRMs, portais de anúncios e automações.
Como Funciona
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ Evento Ocorre │────>│ Ecosys Auto │────>│ Seu Servidor │
│ (ex: veículo │ │ envia POST │ │ processa e │
│ vendido) │ │ 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
GET /v1/webhooks
Lista todos os webhooks configurados.
Request
curl -X GET https://api.shopcar.com.br/v1/webhooks \
-H "Authorization: Bearer ea_live_sua_chave_aqui"Response
{
"success": true,
"data": [
{
"id": "wh_abc123def456",
"url": "https://seu-app.com/api/webhooks/ecosys-auto",
"events": [
"vehicle.created",
"vehicle.updated",
"activity.due_soon",
"activity.overdue"
],
"active": true,
"created_at": "2026-01-10T10:00:00Z",
"last_triggered_at": "2026-02-04T14:30:00Z",
"success_rate": 98.5,
"total_deliveries": 127,
"failed_deliveries": 2
}
]
}POST /v1/webhooks
Cria um novo webhook.
Request Body
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
url | string | Sim | URL que receberá as notificações (HTTPS) |
events | array | Sim | Lista de eventos para escutar |
description | string | Não | Descrição do webhook |
Requisitos da URL
- Deve usar HTTPS (HTTP não é aceito)
- Deve ser acessível publicamente
- Deve responder em menos de 5 segundos
- Deve retornar status 2xx para confirmar recebimento
Request
curl -X POST https://api.shopcar.com.br/v1/webhooks \
-H "Authorization: Bearer ea_live_sua_chave_aqui" \
-H "Content-Type: application/json" \
-d '{
"url": "https://seu-app.com/api/webhooks/ecosys-auto",
"events": [
"vehicle.created",
"vehicle.updated",
"vehicle.sold",
"activity.created",
"activity.completed",
"activity.due_soon",
"activity.overdue",
"client.created",
"deal.won",
"deal.lost"
],
"description": "Integração com portal de anúncios"
}'Response
{
"success": true,
"data": {
"id": "wh_new123abc456",
"url": "https://seu-app.com/api/webhooks/ecosys-auto",
"events": ["vehicle.created", "vehicle.updated", "..."],
"active": true,
"secret": "whsec_AbCdEfGhIjKlMnOpQrStUvWxYz123456789",
"created_at": "2026-02-04T10:30:00Z"
}
}Guarde o Secret!
O secret é exibido apenas uma vez. Use-o para verificar a autenticidade das notificações recebidas.
PUT /v1/webhooks/:id
Atualiza um webhook.
Request
curl -X PUT https://api.shopcar.com.br/v1/webhooks/wh_abc123def456 \
-H "Authorization: Bearer ea_live_sua_chave_aqui" \
-H "Content-Type: application/json" \
-d '{
"events": ["vehicle.created", "vehicle.updated"],
"active": true
}'Response
{
"success": true,
"data": {
"id": "wh_abc123def456",
"events": ["vehicle.created", "vehicle.updated"],
"active": true,
"updated_at": "2026-02-04T15:00:00Z"
}
}DELETE /v1/webhooks/:id
Remove um webhook.
Request
curl -X DELETE https://api.shopcar.com.br/v1/webhooks/wh_abc123def456 \
-H "Authorization: Bearer ea_live_sua_chave_aqui"Response
{
"success": true,
"data": {
"id": "wh_abc123def456",
"deleted": true
}
}Eventos Disponíveis
Eventos de Veículos
| Evento | Descrição | Quando é Disparado |
|---|---|---|
vehicle.created | Veículo cadastrado | Novo veículo via app ou API |
vehicle.updated | Veículo atualizado | Alteração de dados/fase/preço |
vehicle.sold | Veículo vendido | Status alterado para vendido |
vehicle.phase_changed | Fase alterada | Veículo movido no kanban |
vehicle.price_changed | Preço alterado | Atualização de preço |
vehicle.removed | Veículo removido | Veículo removido do inventário |
Eventos de Atividades
| Evento | Descrição | Quando é Disparado |
|---|---|---|
activity.created | Atividade criada | Nova atividade/tarefa |
activity.updated | Atividade atualizada | Alteração de dados |
activity.completed | Atividade concluída | Status alterado para completed |
activity.due_soon | Prazo próximo | 24h antes do vencimento |
activity.overdue | Atividade atrasada | Prazo expirado |
Eventos de Clientes
| Evento | Descrição | Quando é Disparado |
|---|---|---|
client.created | Cliente criado | Novo cliente cadastrado |
client.updated | Cliente atualizado | Alteração de dados |
client.deactivated | Cliente desativado | Status alterado para inactive |
Eventos de Negócios
| Evento | Descrição | Quando é Disparado |
|---|---|---|
deal.created | Negócio criado | Novo negócio no pipeline |
deal.updated | Negócio atualizado | Alteração de dados/fase |
deal.phase_changed | Fase alterada | Negócio movido no pipeline |
deal.won | Negócio ganho | Marcado como ganho (venda concretizada) |
deal.lost | Negócio perdido | Marcado como perdido |
Eventos Financeiros
| Evento | Descrição | Quando é Disparado |
|---|---|---|
financial.created | Registro criado | Novo registro financeiro |
financial.paid | Pagamento confirmado | Status alterado para paid |
financial.overdue | Pagamento atrasado | 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": "veh_xyz789",
"title": "Honda Civic EXL 2.0 2024",
"brand": "Honda",
"model": "Civic",
"price": 142900.00,
"phase": "recebido",
"status": "disponivel",
"client": {
"id": "cli_abc123",
"name": "João da Silva"
},
"created_at": "2026-02-04T14:30:00Z"
},
"previous_attributes": null
},
"team_id": "team_xyz789",
"webhook_id": "wh_abc123def456"
}Para eventos de atualização
{
"id": "evt_update123",
"type": "vehicle.updated",
"data": {
"object": {
"id": "veh_xyz789",
"phase": "em-vitrine",
"price": 139900.00
},
"previous_attributes": {
"phase": "recebido",
"price": 142900.00
}
}
}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 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)
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(timestamp)) > 300) {
return res.status(401).json({ error: 'Timestamp too old' });
}
// Calcular assinatura esperada
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(signedPayload)
.digest('hex');
// Comparação segura
if (!crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Processar evento
const event = JSON.parse(payload);
console.log(`Evento recebido: ${event.type}`);
switch (event.type) {
case 'vehicle.created':
handleVehicleCreated(event.data.object);
break;
case 'activity.overdue':
handleActivityOverdue(event.data.object);
break;
case 'deal.won':
handleDealWon(event.data.object);
break;
}
res.status(200).json({ received: true });
});
function handleVehicleCreated(vehicleData) {
console.log(`Novo veículo: ${vehicleData.title}`);
// Publicar no portal de anúncios, enviar notificação, etc.
}
function handleActivityOverdue(activity) {
console.log(`Atividade atrasada: ${activity.title}`);
// Enviar alerta, criar ticket, etc.
}
function handleDealWon(deal) {
console.log(`Venda concretizada: ${deal.title} - R$ ${deal.value}`);
// Atualizar métricas, gerar contrato, etc.
}Verificação em Python
import hmac
import hashlib
import time
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 too old'}), 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': 'Invalid signature'}), 401
# Processar evento
event = request.json
print(f"Evento recebido: {event['type']}")
if event['type'] == 'vehicle.created':
handle_vehicle_created(event['data']['object'])
elif event['type'] == 'activity.overdue':
handle_activity_overdue(event['data']['object'])
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
Faça
- Responda rapidamente - Retorne
200 OKem até 5 segundos - Processe assincronamente - Use filas para tarefas demoradas
- Implemente idempotência - O mesmo evento pode ser enviado mais de uma vez
- Verifique a assinatura - Sempre valide a autenticidade
- Use HTTPS - Obrigatório para receber webhooks
- Monitore entregas - Acompanhe a taxa de sucesso
Não Faça
- Processar no handler - Não execute lógica pesada síncrona
- Ignorar duplicados - Mesmo evento pode vir mais de uma vez
- Confiar cegamente - Sempre verifique a assinatura
- Usar HTTP - Apenas HTTPS é aceito
- Timeout longo - Não demore mais que 5 segundos
Erros Comuns
| Código | Erro | Solução |
|---|---|---|
400 | Invalid URL | Use URL HTTPS válida |
400 | Invalid events | Verifique lista de eventos |
404 | Webhook not found | Verifique o ID |
409 | URL already registered | URL já existe |
422 | URL not reachable | Verifique firewall/DNS |