Os Webhooks permitem que você receba notificações automáticas quando eventos importantes acontecem no ConnectVets Notes, como quando uma transcrição é concluída ou falha.

Como Funcionam

1

Configuração

Nossa equipe configura os webhooks no seu sistema conforme suas necessidades
2

Eventos

Quando um evento ocorre (ex: transcrição concluída), enviamos uma requisição POST
3

Recebimento

Sua aplicação recebe a notificação e pode processar o evento imediatamente
4

Confirmação

Responda com status 200 para confirmar o recebimento

Eventos Disponíveis

note.transcription.completed

Disparado quando uma transcrição é finalizada com sucesso:
{
  "event": "note.transcription.completed",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Rex",
    "transcription_status": "completed",
    "external_id": "CLIENTE_123",
    "created_at": "2024-02-14T18:25:43Z",
    "completed_at": "2024-02-14T18:30:23Z"
  },
  "timestamp": "2024-02-14T18:30:24Z",
  "webhook_id": "wh_abc123def456"
}

note.transcription.failed

Disparado quando uma transcrição falha:
{
  "event": "note.transcription.failed",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Rex",
    "transcription_status": "failed",
    "error": {
      "code": "AUDIO_QUALITY_LOW",
      "message": "Áudio com qualidade insuficiente para transcrição"
    },
    "external_id": "CLIENTE_123",
    "created_at": "2024-02-14T18:25:43Z",
    "failed_at": "2024-02-14T18:28:15Z"
  },
  "timestamp": "2024-02-14T18:28:16Z",
  "webhook_id": "wh_abc123def456"
}

Implementação

Endpoint do Webhook

Sua aplicação deve ter um endpoint que aceite requisições POST:
app.post('/webhooks/connectvets', (req, res) => {
  const { event, data, timestamp } = req.body;
  
  console.log(`Evento recebido: ${event} em ${timestamp}`);
  
  switch (event) {
    case 'note.transcription.completed':
      handleTranscriptionCompleted(data);
      break;
      
    case 'note.transcription.failed':
      handleTranscriptionFailed(data);
      break;
      
    default:
      console.log(`Evento não tratado: ${event}`);
  }
  
  // Resposta de confirmação
  res.status(200).json({ received: true });
});

function handleTranscriptionCompleted(noteData) {
  // Lógica para processar transcrição concluída
  console.log(`Nota ${noteData.id} foi transcrita com sucesso`);
  
  // Exemplo: notificar o usuário
  notifyUser(noteData.external_id, 'Sua consulta foi transcrita!');
  
  // Exemplo: atualizar banco local
  updateLocalNote(noteData.id, { status: 'completed' });
}

function handleTranscriptionFailed(noteData) {
  // Lógica para processar falha na transcrição
  console.log(`Falha na transcrição da nota ${noteData.id}: ${noteData.error.message}`);
  
  // Exemplo: notificar erro
  notifyUser(noteData.external_id, 'Houve um problema na transcrição. Tente novamente.');
}

Segurança

Validação de Origem

Para garantir que o webhook vem do ConnectVets, valide o header de assinatura:
const crypto = require('crypto');

function validateWebhookSignature(payload, signature, secret) {
  const computedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
    
  const expectedSignature = `sha256=${computedSignature}`;
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

app.post('/webhooks/connectvets', (req, res) => {
  const signature = req.headers['x-connectvets-signature'];
  const payload = JSON.stringify(req.body);
  
  if (!validateWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  // Processar webhook...
});

HTTPS Obrigatório

  • Todos os webhooks devem usar HTTPS
  • Certificados SSL válidos são obrigatórios
  • URLs localhost não são aceitas em produção

Retry Logic

Como Funciona

Se seu endpoint não responder com status 2xx, reenviamos automaticamente:
TentativaDelay
Imediato
1 minuto
5 minutos
15 minutos
1 hora

Idempotência

Implemente verificação de duplicatas usando o webhook_id:
const processedWebhooks = new Set();

app.post('/webhooks/connectvets', (req, res) => {
  const webhookId = req.body.webhook_id;
  
  if (processedWebhooks.has(webhookId)) {
    // Já processado, apenas confirme
    return res.status(200).json({ received: true, duplicate: true });
  }
  
  processedWebhooks.add(webhookId);
  
  // Processar webhook...
});

Monitoramento

Logs Importantes

Monitore estes aspectos:
  • Latência de resposta: Tempo para processar webhook
  • Taxa de erro: Percentual de falhas no processamento
  • Timeouts: Requisições que demoram muito
  • Duplicatas: Webhooks reprocessados

Exemplo de Logging

const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'webhooks.log' })
  ]
});

app.post('/webhooks/connectvets', (req, res) => {
  const startTime = Date.now();
  const { event, webhook_id } = req.body;
  
  try {
    // Processar webhook...
    
    const duration = Date.now() - startTime;
    logger.info('webhook_processed', {
      event,
      webhook_id,
      duration_ms: duration,
      status: 'success'
    });
    
    res.status(200).json({ received: true });
  } catch (error) {
    const duration = Date.now() - startTime;
    logger.error('webhook_failed', {
      event,
      webhook_id,
      duration_ms: duration,
      error: error.message,
      status: 'error'
    });
    
    res.status(500).json({ error: 'Processing failed' });
  }
});

Configuração

Importante: Webhooks não são gerenciados via API. A configuração é feita através de contato direto com nossa equipe.

Para Configurar Webhooks

  1. Contate nossa equipe via WhatsApp (+55 31 8883-5141)
  2. Forneça informações:
    • URL do seu endpoint (deve ser HTTPS)
    • Eventos que deseja receber
    • Método de autenticação preferido
    • Ambiente (produção/desenvolvimento)

Informações Necessárias

  • URL do Endpoint: https://seuapp.com/webhooks/connectvets
  • Eventos: ["note.transcription.completed", "note.transcription.failed"]
  • Headers Customizados (opcional): Para autenticação adicional
  • Secret para Validação: Para verificar autenticidade

Teste em Desenvolvimento

Nossa equipe pode configurar webhooks para ambiente de desenvolvimento usando:
  • ngrok para túneis locais
  • Webhook.site para testes rápidos
  • RequestBin para debug

Troubleshooting

Webhook Não Recebido

Possíveis causas:
  • Endpoint inacessível (timeout/erro)
  • Certificado SSL inválido
  • Firewall bloqueando nossa IP
Soluções:
  • Verificar se endpoint responde a GET/POST
  • Validar certificado SSL
  • Liberar IPs do ConnectVets no firewall

Erro 401/403

Possíveis causas:
  • Autenticação adicional no endpoint
  • Headers de validação incorretos
Soluções:
  • Revisar lógica de autenticação
  • Verificar headers x-connectvets-signature

Webhooks Duplicados

Possíveis causas:
  • Endpoint demorou para responder (timeout)
  • Resposta não 2xx
Soluções:
  • Implementar verificação de webhook_id
  • Otimizar tempo de processamento
  • Responder rapidamente (mover processamento pesado para background)

Exemplos de Uso

Integração com CRM

async function handleTranscriptionCompleted(noteData) {
  // Buscar informações da consulta no sistema local
  const appointment = await getAppointmentByExternalId(noteData.external_id);
  
  if (appointment) {
    // Atualizar status no CRM
    await updateCRMRecord(appointment.crm_id, {
      transcription_status: 'completed',
      transcription_url: `https://notes.connectvets.com.br/notes/${noteData.id}`,
      last_updated: new Date()
    });
    
    // Notificar veterinário
    await sendNotification(appointment.veterinarian_id, {
      type: 'transcription_ready',
      patient: noteData.name,
      note_id: noteData.id
    });
  }
}

Workflow de Aprovação

async function handleTranscriptionCompleted(noteData) {
  // Verificar se nota precisa de aprovação
  const needsApproval = await checkApprovalRules(noteData);
  
  if (needsApproval) {
    // Enviar para fila de aprovação
    await addToApprovalQueue(noteData.id, {
      priority: noteData.urgent ? 'high' : 'normal',
      assigned_to: await getReviewerForNote(noteData)
    });
    
    // Notificar revisor
    await notifyReviewer(noteData);
  } else {
    // Aprovação automática
    await autoApproveNote(noteData.id);
  }
}

Próximo passo: Veja exemplos práticos de webhooks ou explore os endpoints de Notes.