API

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   │
└─────────────────────┘     └─────────────────────┘     └─────────────────────┘
  1. Um evento ocorre na plataforma (veículo cadastrado, negócio ganho, etc.)
  2. O Ecosys Auto envia um POST para a URL configurada
  3. Seu servidor processa o evento e responde com 200 OK
  4. 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

CampoTipoObrigatórioDescrição
urlstringSimURL que receberá as notificações (HTTPS)
eventsarraySimLista de eventos para escutar
descriptionstringNãoDescriçã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

EventoDescriçãoQuando é Disparado
vehicle.createdVeículo cadastradoNovo veículo via app ou API
vehicle.updatedVeículo atualizadoAlteração de dados/fase/preço
vehicle.soldVeículo vendidoStatus alterado para vendido
vehicle.phase_changedFase alteradaVeículo movido no kanban
vehicle.price_changedPreço alteradoAtualização de preço
vehicle.removedVeículo removidoVeículo removido do inventário

Eventos de Atividades

EventoDescriçãoQuando é Disparado
activity.createdAtividade criadaNova atividade/tarefa
activity.updatedAtividade atualizadaAlteração de dados
activity.completedAtividade concluídaStatus alterado para completed
activity.due_soonPrazo próximo24h antes do vencimento
activity.overdueAtividade atrasadaPrazo expirado

Eventos de Clientes

EventoDescriçãoQuando é Disparado
client.createdCliente criadoNovo cliente cadastrado
client.updatedCliente atualizadoAlteração de dados
client.deactivatedCliente desativadoStatus alterado para inactive

Eventos de Negócios

EventoDescriçãoQuando é Disparado
deal.createdNegócio criadoNovo negócio no pipeline
deal.updatedNegócio atualizadoAlteração de dados/fase
deal.phase_changedFase alteradaNegócio movido no pipeline
deal.wonNegócio ganhoMarcado como ganho (venda concretizada)
deal.lostNegócio perdidoMarcado como perdido

Eventos Financeiros

EventoDescriçãoQuando é Disparado
financial.createdRegistro criadoNovo registro financeiro
financial.paidPagamento confirmadoStatus alterado para paid
financial.overduePagamento atrasadoVencimento 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

HeaderDescrição
X-Ecosys-Auto-SignatureAssinatura HMAC-SHA256
X-Ecosys-Auto-TimestampTimestamp Unix do envio
X-Ecosys-Auto-Event-IdID do evento
Content-Typeapplication/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}), 200

Política de Retentativas

Se sua URL não responder com 2xx, tentaremos novamente:

TentativaIntervalo
1aImediato
2a5 minutos
3a30 minutos
4a2 horas
5a12 horas
6a24 horas

Após 6 tentativas falhas consecutivas, o webhook é desativado automaticamente. Você receberá um email de alerta.


Boas Práticas

Faça

  1. Responda rapidamente - Retorne 200 OK em até 5 segundos
  2. Processe assincronamente - Use filas para tarefas demoradas
  3. Implemente idempotência - O mesmo evento pode ser enviado mais de uma vez
  4. Verifique a assinatura - Sempre valide a autenticidade
  5. Use HTTPS - Obrigatório para receber webhooks
  6. Monitore entregas - Acompanhe a taxa de sucesso

Não Faça

  1. Processar no handler - Não execute lógica pesada síncrona
  2. Ignorar duplicados - Mesmo evento pode vir mais de uma vez
  3. Confiar cegamente - Sempre verifique a assinatura
  4. Usar HTTP - Apenas HTTPS é aceito
  5. Timeout longo - Não demore mais que 5 segundos

Erros Comuns

CódigoErroSolução
400Invalid URLUse URL HTTPS válida
400Invalid eventsVerifique lista de eventos
404Webhook not foundVerifique o ID
409URL already registeredURL já existe
422URL not reachableVerifique firewall/DNS

On this page