Skip to content

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 consultar ("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 email, atualização de banco, alertas) sem intervenção manual

Como Funciona o Fluxo

  1. Cadastro: Você cria um webhook informando uma URL de destino, um segredo HMAC e quais eventos deseja receber.
  2. Disparo: Sempre que um evento cadastrado ocorre, nossa plataforma gera um payload JSON e envia um POST para sua URL.
  3. Validação: Seu servidor valida a assinatura usando o segredo compartilhado.
  4. Confirmação: Se sua API responder com HTTP 200, consideramos entregue; caso contrário, faremos até 3 tentativas automáticas.
  5. Logs: Você pode acompanhar cada envio, status e resposta na interface de Logs de Eventos.
  6. Reenvio: Caso o envio falhe, o sistema tentará reenviar até 3 vezes. É possível reenviar manualmente a partir da interface de logs.

Criando um Webhook

  1. Navegue até Webhooks no menu lateral
  2. Clique no botão Criar
  3. Preencha a configuração:
    • 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. Escolha um valor seguro e armazene-o em local protegido — você precisará dele para validar as assinaturas
    • Eventos: Selecione os eventos para os quais deseja receber notificações
  4. Clique em Salvar. O status ficará Ativo e você começará a receber notificações imediatamente.

Contadores de Recursos

Se o seu plano tem um limite de webhooks, você verá um contador (ex: "2/5 Webhooks") no topo da página. Quando o limite é atingido, o botão Criar fica desabilitado.

Eventos Disponíveis

Eventos de Conversas (Threads)

EventoDescrição
thread.createdUma nova conversa foi iniciada
thread.closedUma conversa foi encerrada

Eventos de Voz

EventoDescrição
voice.start_callUma chamada de voz foi iniciada
voice.end_callUma chamada de voz foi encerrada

Eventos de WhatsApp

EventoDescrição
whatsapp.inboundUma mensagem de entrada foi recebida no WhatsApp
whatsapp.outboundUma mensagem de saída foi enviada pelo WhatsApp

Eventos de Modelos de IA

EventoDescrição
llm.completionUma resposta de LLM foi gerada
llm.streamStreaming de resposta de LLM em andamento
stt.transcriptionUma transcrição de fala para texto foi concluída
tts.synthesisUma síntese de texto para fala foi concluída

Eventos de Análise

EventoDescrição
structured_analysis.completedUma análise estruturada (análise pós-chamada) foi concluída

Formato do Payload

Cada requisição de webhook inclui:

Headers

text
x-timestamp: <timestamp ISO 8601 da criação do evento>
x-signature: <HMAC-SHA256 de `${body}:${timestamp}`>
Content-Type: application/json

Body (Exemplo)

json
{
  "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:

  1. Recupere o body e o timestamp do header x-timestamp.
  2. Calcule localmente o HMAC-SHA256 de ${payload}:${timestamp} usando seu segredo.
  3. Compare de forma segura com o header x-signature.
  4. (Opcional) Rejeite requisições com timestamp fora de uma janela — por exemplo ±5 minutos.
typescript
import express, { Request, Response } from 'express';
import { createHmac } from 'crypto';

const app = express();
app.use(express.json());

const WEBHOOK_SECRET: string = process.env.WEBHOOK_SECRET || '';

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');
});
python
from fastapi import FastAPI, Request, HTTPException
import hmac
import hashlib
import os
from datetime import datetime, timezone

app = FastAPI()

WEBHOOK_SECRET = os.getenv('WEBHOOK_SECRET')

def is_signature_valid(payload: str, timestamp: str, signature: str) -> bool:
    message = f"{payload}:{timestamp}".encode()
    hmac_obj = hmac.new(WEBHOOK_SECRET.encode(), message, hashlib.sha256)
    expected_signature = hmac_obj.hexdigest()
    return hmac.compare_digest(expected_signature, signature)

@app.post("/webhook")
async def webhook(request: Request):
    body = await request.body()
    payload = body.decode()
    timestamp_str = request.headers.get('x-timestamp')
    signature = request.headers.get('x-signature')

    # Verifica se o timestamp está dentro de uma janela de 5 minutos
    event_time = datetime.fromisoformat(timestamp_str.replace("Z", "+00:00"))
    if abs((datetime.now(timezone.utc) - event_time).total_seconds()) > 300:
        raise HTTPException(status_code=400, detail="Timestamp expired")

    # Valida a assinatura
    if not is_signature_valid(payload, timestamp_str, 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

  • Ataques de falsificação: Qualquer pessoa que conheça seu endpoint pode enviar payloads falsos simulando eventos do 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

DANGER

Nunca armazene o segredo do webhook em código-fonte público ou em variáveis expostas ao front-end.

Logs de Eventos

Cada webhook tem uma página de Logs de Eventos onde você pode monitorar o status das entregas:

  • Status: Se a entrega teve sucesso (200) ou falhou
  • Tentativas: Número de tentativas de entrega realizadas
  • Resposta: O corpo da resposta do seu servidor
  • Timestamp: Quando o evento foi disparado

Use os controles de paginação para navegar pelo histórico de logs. Você pode reenviar manualmente qualquer entrega que falhou a partir desta interface.

Teste Local com ngrok

Para desenvolver e testar sem deploy:

  1. Instale o ngrok:

    bash
    # Para macOS:
    brew install ngrok

    Para outros sistemas operacionais, consulte a documentação oficial do ngrok.

  2. Inicie um túnel apontando para sua porta local (ex: 3000):

    bash
    ngrok http 3000
  3. Copie a URL HTTPS gerada (ex: https://abc123.ngrok.io) e use como URL no cadastro do webhook.

  4. Execute sua aplicação local, receba os POST /webhook e observe o console.

  5. Acesse Webhooks → [seu webhook] → Logs de Eventos para ver status, tentativas e resposta do seu servidor.