Webhooks
Os webhooks permitem que sistemas externos recebam notificações em tempo real sempre que eventos importantes ocorrerem na plataforma SipPulse AI. Em vez de você precisar ficar consultando (“polling”) nossa API, enviamos automaticamente uma requisição HTTP ao seu servidor assim que algo acontece.
Por que usar webhooks?
- Resposta instantânea: receba dados de eventos no momento exato em que ocorrem.
- Escalabilidade: seu sistema só processa eventos quando necessário, economizando recursos.
- Automatização: acione fluxos internos (envio de e-mail, atualização de banco, alertas) sem intervenção manual.
Como funciona o fluxo
- Cadastro: você cria um webhook informando uma URL de destino, um segredo HMAC e quais eventos deseja receber.
- Disparo: sempre que um evento cadastrado ocorre, nossa plataforma gera um payload JSON e envia um
POST
para sua URL. - Validação: seu servidor valida a assinatura usando o segredo compartilhado.
- Confirmação: se sua API responder com HTTP 200, consideramos entregue; caso contrário, faremos até 3 tentativas automáticas.
- Logs: você pode acompanhar cada envio, status e resposta na interface de Logs de Eventos.
- Reenvio: caso o envio falhe, o sistema tentará reenviar o webhook até 3 vezes. É possível reenviar manualmente a partir da interface de logs.
Criar um webhook
- Abra o menu dropdown no canto superior direito e selecione Webhooks.
- Clique em Criar (canto superior direito).
- Preencha:
- URL: endpoint público (HTTPS recomendado) que receberá as requisições
POST
. - Segredo: uma string privada definida por você, usada para gerar a assinatura HMAC. Certifique-se de escolher um valor seguro e armazená-lo em um local protegido, pois ele será necessário para validar as assinaturas das requisições.
- Eventos: marque os eventos desejados (e.g.
thread.created
,thread.closed
,thread.removed
).
- Clique em Salvar. O status ficará Ativo e você começará a receber notificações imediatamente.
Payload enviado
Cada requisição tem:
- Headers
x-timestamp: <timestamp ISO 8601 da criação do evento>
x-signature: <HMAC-SHA256 de `${body}:${timestamp}`>
Content-Type: application/json
- Body (Exemplo)
{
"id": "c93e2b69-88c8-4c19-b85c-1a57d73f6ea7",
"event": "thread.closed",
"timestamp": "2025-04-30T12:34:56.789Z",
"payload": {
"id": "thr_01966dd65ad074f69cd4346ddcb7a582",
"title": "Saudação Inicial",
"history": [ /* ... */ ]
}
}
Como validar a assinatura
Para garantir que a requisição veio mesmo do SipPulse AI e não foi alterada:
- Recupere o
body
e otimestamp
do headerx-timestamp
. - Calcule localmente o HMAC-SHA256 de
${payload}:${timestamp}
usando seu segredo. - Compare de forma segura com o header
x-signature
. - (Opcional) Rejeite requisições com timestamp fora de uma janela — por exemplo ±5 min.
// Importação de bibliotecas necessárias
import express, { Request, Response } from 'express';
import { createHmac } from 'crypto';
const app = express();
app.use(express.json());
// Segredo compartilhado usado para validação
const WEBHOOK_SECRET: string = process.env.WEBHOOK_SECRET || '';
/**
* Função para validar a assinatura do webhook.
* @param payload - Corpo da requisição em formato string.
* @param timestamp - Timestamp enviado no header.
* @param signature - Assinatura enviada no header.
* @returns true se a assinatura for válida, false caso contrário.
*/
function isSignatureValid(payload: string, timestamp: string, signature: string): boolean {
const message = `${payload}:${timestamp}`;
const hmac = createHmac("sha256", WEBHOOK_SECRET)
.update(message)
.digest("hex");
return hmac === signature;
}
app.post('/webhook', (req: Request, res: Response) => {
const payload = JSON.stringify(req.body);
const timestamp = req.headers['x-timestamp'] as string;
const signature = req.headers['x-signature'] as string;
// Verifica se o timestamp está dentro de uma janela de 5 minutos
if (Math.abs(Date.now() - Date.parse(timestamp)) > 5 * 60 * 1000) {
return res.status(400).json({ error: 'Timestamp expired' });
}
// Valida a assinatura
if (!isSignatureValid(payload, timestamp, signature)) {
return res.status(400).json({ error: 'Invalid signature' });
}
// Processa o evento recebido
console.log('Evento recebido:', req.body);
res.status(200).json({ status: 'ok' });
});
app.listen(3000, () => {
console.log('Servidor rodando na porta 3000');
});
from fastapi import FastAPI, Request, HTTPException
import hmac
import hashlib
import os
import time
app = FastAPI()
# Segredo compartilhado usado para validação
WEBHOOK_SECRET = os.getenv('WEBHOOK_SECRET')
def is_signature_valid(payload: str, timestamp: str, signature: str) -> bool:
"""
Valida a assinatura do webhook.
:param payload: Corpo da requisição em formato string.
:param timestamp: Timestamp enviado no header.
:param signature: Assinatura enviada no header.
:return: True se a assinatura for válida, False caso contrário.
"""
message = f"{payload}:{timestamp}".encode()
hmac_obj = hmac.new(WEBHOOK_SECRET.encode(), message, hashlib.sha256)
expected_signature = hmac_obj.hexdigest()
return expected_signature == signature
@app.post("/webhook")
async def webhook(request: Request):
body = await request.body()
payload = body.decode()
timestamp = request.headers.get('x-timestamp')
signature = request.headers.get('x-signature')
# Verifica se o timestamp está dentro de uma janela de 5 minutos
if abs(time.time() - time.strptime(timestamp, "%Y-%m-%dT%H:%M:%S.%fZ").timestamp()) > 300:
raise HTTPException(status_code=400, detail="Timestamp expired")
# Valida a assinatura
if not is_signature_valid(payload, timestamp, signature):
raise HTTPException(status_code=400, detail="Invalid signature")
# Processa o evento recebido
print("Evento recebido:", payload)
return {"status": "ok"}
Importância da validação de assinatura
A verificação da assinatura HMAC é uma etapa crítica para a segurança da sua integração:
Riscos de não validar webhooks
- Ataques de falsificação: Qualquer pessoa que conheça seu endpoint pode enviar payloads falsos simulando eventos da SipPulse AI
- Injeção de dados maliciosos: Sem validação, atacantes podem injetar dados manipulados para comprometer seu sistema
- Replay attacks: Sem verificar o timestamp, requisições antigas podem ser capturadas e reenviadas repetidamente
- Ativação acidental de processos: Eventos falsos podem disparar operações indesejadas em seu sistema
Benefícios da validação
- Garantia de autenticidade: Confirmação de que a requisição realmente veio do SipPulse AI
- Integridade dos dados: Certeza de que o payload não foi alterado durante a transmissão
- Atualidade: Verificação do timestamp impede o reuso de requisições antigas
- Não-repúdio: Prova criptográfica da origem da mensagem
Sendo uma comunicação assíncrona e exposta à internet, webhooks sem validação representam um vetor de ataque significativo. O uso do HMAC-SHA256 com um segredo compartilhado é um método robusto e amplamente adotado para proteger esse canal de comunicação.
Atenção: Nunca armazene o segredo do webhook em código-fonte público ou em variáveis expostas ao front-end.
Teste local com ngrok
Para desenvolver e testar sem deploy:
- Instale o ngrok:
# Para macOS:
brew install ngrok
Para outros sistemas operacionais, consulte a documentação oficial do ngrok.
- Inicie um túnel apontando para sua porta local (ex: 3000):
ngrok http 3000
- Copie a URL HTTPS gerada (ex:
https://abc123.ngrok.io
) e use como URL no cadastro do webhook. - Execute sua aplicação local, receba os
POST /webhook
e observe o console. - Acesse Webhooks → [seu webhook] → Logs de Eventos para ver status, tentativas e resposta do seu servidor.