SyncroCentral de Ajuda
Nenhum resultado encontrado
Acessar Syncro

Webhooks de saída

Atualizado em 30 de abril de 2026

Webhooks de saída são o mecanismo reverso da API: ao invés de você chamar o Syncro pra buscar dados, o Syncro chama você quando algo acontece. Útil pra integração com n8n, Zapier custom, sistemas legados ou qualquer endpoint HTTP. Esse artigo cobre como criar subscription, eventos disponíveis, retry e segurança.

Pré-requisitos

  • API Key gerada. Veja Gerar API Key.
  • Endpoint HTTP público que recebe POST JSON.
  • HTTPS recomendado (não obrigatório).

Como funciona

1. Você cadastra subscription com URL + lista de eventos.
2. Algo acontece no Syncro (ex: lead criado).
3. Sistema dispara job assíncrono.
4. Job faz POST pro seu endpoint com payload + assinatura HMAC.
5. Seu sistema responde 2xx (sucesso) ou erro.
6. Erros disparam retry com backoff.

Criar subscription

Endpoint

POST https://app.syncro.chat/api/v1/webhooks

Payload

{
 "target_url": "https://meusistema.com/webhook/syncro",
 "events": [
 "lead.created",
 "lead.updated",
 "lead.won"
 ],
 "source": "api",
 "secret": "meu_secret_opcional"
}
Campo Obrigatório Descrição
target_url URL completa que recebe POST
events Array de eventos a inscrever
source api (default) ou n8n
secret Chave pra assinar HMAC. Se vazio, sistema gera 40 chars

Resposta (201)

{
 "success": true,
 "id": 42,
 "secret": "abc123def456...",
 "target_url": "https://meusistema.com/webhook/syncro",
 "events": ["lead.created", "lead.updated", "lead.won"],
 "is_active": true,
 "created_at": "2026-04-30T14:30:00Z"
}

⚠️ Atenção: secret aparece apenas na resposta da criação. Salve agora — é necessário pra validar assinatura HMAC.

Eventos disponíveis

Evento Quando dispara
lead.created Lead novo criado (manual, API, form, webhook)
lead.updated Qualquer campo do lead muda
lead.stage_changed Lead muda de etapa
lead.won Lead vai pra etapa won
lead.lost Lead vai pra etapa lost
lead.deleted Lead deletado
task.created Task nova criada
task.updated Task atualizada
task.completed Task marcada como completa
conversation.message_received Nova mensagem inbound (todos canais)

💡 Dica: você pode inscrever em múltiplos eventos numa mesma subscription. Sistema filtra por evento ao disparar.

Payload do webhook

Sistema envia POST com:

Headers

Content-Type: application/json
User-Agent: Syncro-CRM-Webhook/1.0
X-Syncro-Event: lead.created
X-Syncro-Delivery: unique_delivery_id
X-Syncro-Signature: sha256=<hmac>

Body JSON

{
 "event": "lead.created",
 "tenant_id": 123,
 "emitted_at": "2026-04-30T14:30:00Z",
 "data": {
 "id": 1234,
 "name": "João Silva",
 "phone": "+5511987654321",
 "email": "[email protected]",
 "company": "Acme Corp",
 "value": 5000,
 "source": "site-form",
 "status": "active",
 "pipeline_id": 1,
 "stage_id": 5,
 "assigned_to": 3,
 "tags": ["prospect"],
 "utm_source": "google",
 "utm_medium": "cpc",
 "utm_campaign": "summer_2026",
 "created_at": "2026-04-30T14:30:00Z",
 "updated_at": "2026-04-30T14:30:00Z"
 }
}

Eventos com contexto extra

lead.stage_changed:

{
 "event": "lead.stage_changed",
 "data": {
 "id": 1234,
 "name": "João Silva",
 "previous_stage_id": 5,
 "new_stage_id": 7,
 "new_stage_name": "Negociação",
...
 }
}

lead.won / lead.lost:

{
 "event": "lead.won",
 "data": {
...
 "value": 10000,
 "won_at": "2026-04-30T15:00:00Z"
 }
}

Como o seu endpoint deve responder

Sucesso (2xx)

Qualquer status 2xx é considerado sucesso. Sistema marca:

  • failure_count = 0.
  • last_success_at = now.

Mais comum: 200 OK com body vazio ou {"received": true}.

Erro 4xx (exceto 408/429)

Sistema considera erro permanente do receptor (request mal formada, endpoint não existe, etc):

  • Marca failure_count++.
  • NÃO retenta (é assumido que problema é do seu lado).

Erro 5xx, 408, 429, timeout

Sistema considera erro transitório:

  • Marca failure.
  • Retenta com backoff exponencial.

Retry exponencial

Se webhook falha, sistema retenta:

Tentativa Delay desde a anterior
imediato
10 segundos
1 minuto
5 minutos
15 minutos

Total: ~16 minutos pra desistir.

Auto-desativação

Se subscription falha 10+ vezes consecutivas:

  • Sistema marca is_active = false.
  • Para de tentar.
  • Aparece como Desativada na listagem.

Pra reativar:

PUT /api/v1/webhooks/{id}
{
 "is_active": true
}

Sistema reseta failure_count = 0.

SSRF protection

Sistema bloqueia webhooks pra:

  • IPs privados: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.
  • Loopback: 127.0.0.0/8.
  • Link-local: 169.254.0.0/16 (incluindo 169.254.169.254 — AWS metadata).
  • Multicast e IPv6 ULA.

Tentativas bloqueadas marcam falha com last_failure_reason: "ssrf_blocked". Não fazem POST.

💡 Dica: pra desenvolvimento local, use serviço tipo ngrok ou webhook.site pra ter URL público.

Listar subscriptions

curl "https://app.syncro.chat/api/v1/webhooks" \
 -H "X-API-Key: crm_..."

Resposta inclui métricas de saúde:

{
 "success": true,
 "data": [
 {
 "id": 42,
 "target_url": "https://meusistema.com/webhook/syncro",
 "events": ["lead.created"],
 "is_active": true,
 "failure_count": 0,
 "last_success_at": "2026-04-30T14:30:00Z",
 "last_failure_at": null,
 "last_failure_reason": null
 }
 ]
}

💡 Dica: monitore failure_count periodicamente. Spike = problema em produção.

Atualizar subscription

PUT /api/v1/webhooks/42
{
 "events": ["lead.created", "lead.updated", "lead.won", "lead.lost"],
 "is_active": true
}

Deletar subscription

DELETE /api/v1/webhooks/42

Imediato e irreversível. Subscription para de receber eventos.

Idempotência

Mesmo evento pode chegar 2x em casos raros:

  • Bug em retry.
  • Network split.
  • Sistema processou request mas sua resposta não chegou.

Como lidar

Use header X-Syncro-Delivery (único por tentativa) como dedup key:

// Pseudo-código
$deliveryId = $_SERVER['HTTP_X_SYNCRO_DELIVERY'];

// Se já processou esse delivery_id, retorna 200 sem processar de novo
if (cache_has("processed:$deliveryId")) {
 return response->json(['received' => true]);
}

// Processa
process_webhook($payload);

// Marca como processado por 24h
cache_put("processed:$deliveryId", true, 86400);

Múltiplas subscriptions pro mesmo evento

Sim, suportado. Cada uma recebe POST.

Útil pra:

  • Backup (se uma falha, outra recebe).
  • Splits (n8n recebe pra automação + sistema legado recebe pra log).

Exemplo — receptor em PHP

<?php
header('Content-Type: application/json');

// 1. Valida assinatura HMAC
$secret = 'seu_secret_aqui';
$signature = $_SERVER['HTTP_X_SYNCRO_SIGNATURE'] ?? '';
$body = file_get_contents('php://input');

$expected = 'sha256='. hash_hmac('sha256', $body, $secret);

if (!hash_equals($expected, $signature)) {
 http_response_code(401);
 echo json_encode(['error' => 'Invalid signature']);
 exit;
}

// 2. Parse payload
$payload = json_decode($body, true);
$event = $payload['event'];
$data = $payload['data'];

// 3. Processa
switch ($event) {
 case 'lead.created':
 my_db_create_lead($data);
 break;
 case 'lead.won':
 my_email_send_thank_you($data);
 break;
 //...
}

// 4. Responde sucesso
http_response_code(200);
echo json_encode(['received' => true]);

Veja Assinatura HMAC pra detalhes da validação.

Exemplo — receptor em Express (Node.js)

const express = require('express');
const crypto = require('crypto');

const app = express;
app.use(express.raw({ type: 'application/json' })); // raw body pra HMAC

const SECRET = 'seu_secret_aqui';

app.post('/webhook', (req, res) => {
 const signature = req.headers['x-syncro-signature'] || '';
 const body = req.body.toString('utf8');

 const expected = 'sha256=' + crypto
.createHmac('sha256', SECRET)
.update(body)
.digest('hex');

 if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
 return res.status(401).json({ error: 'Invalid signature' });
 }

 const payload = JSON.parse(body);
 console.log(`Event: ${payload.event}`, payload.data);

 res.status(200).json({ received: true });
});

app.listen(3000);

Boas práticas

1. Responda rápido (<5s)

Endpoint deve retornar 2xx em menos de 5 segundos. Se processamento demora, enfileire internamente:

// Recebe → marca como recebido → responde 200 → processa em background
queue_push(['event' => $event, 'data' => $data]);
http_response_code(200);

2. Idempotência sempre

Use X-Syncro-Delivery como dedup. Mesmo evento processado 2x não é problema.

3. Valide HMAC sempre

Sem validação, qualquer pessoa que descobriu sua URL pode mandar payloads falsos.

4. Use HTTPS

HTTP em texto puro expõe payload + headers (incluindo informação sensível de leads).

5. Monitore subscription

Crie alerta interno se failure_count > 5 — algo quebrou no seu lado.

6. Teste antes de produção

Use webhook.site ou ngrok local pra testar payloads antes de apontar pro endpoint final.

Limites

  • Sem limite oficial de subscriptions por tenant.
  • Sem limite de eventos por subscription.
  • Rate de envio: depende do volume de eventos. Sistema não throttle outbound — pode mandar 1000 webhooks numa hora se 1000 leads foram criados.

Casos práticos

Sync com Google Sheets

Subscription lead.created → endpoint Apps Script → adiciona linha em planilha. Histórico permanente.

Notificação Slack

Subscription lead.won → endpoint Slack webhook → notifica canal #vendas com toast 🎉.

Atualizar ERP

Subscription lead.created, lead.won → endpoint ERP custom → cria cliente no ERP automaticamente.

Análise externa

Subscription lead.updated, lead.stage_changed → endpoint que envia evento pro Mixpanel, Amplitude, Looker etc.

Erros comuns

"Subscription criada mas eventos não chegam"

  • Verifique is_active=true em GET /webhooks.
  • Confirme eventos certos (case-sensitive: lead.createdLead.Created).
  • Verifique logs do seu endpoint — chegou request 4xx/5xx?
  • Failure count crescendo → endpoint retorna erro.

"401 Invalid signature do meu lado"

Implementação HMAC errada. Veja Assinatura HMAC.

"Webhook desativado automaticamente"

Atingiu 10 falhas consecutivas. Investigue endpoint, corrija, reative com PUT /webhooks/{id} {"is_active": true}.

"SSRF blocked"

URL aponta pra IP privado. Use URL pública.

"Mesmo evento chega 5x"

Idempotência mal implementada no seu lado. Use X-Syncro-Delivery como dedup.

Próximos passos

Artigos relacionados