Webhooks
Los webhooks te permiten recibir notificaciones en tiempo real cuando ocurren eventos en VOCALS. Úsalos para sincronizar datos de llamadas con tu CRM, activar flujos de trabajo, actualizar bases de datos o alertar a tu equipo.
Configurar un Endpoint de Webhook
- Navega a API > Webhooks en el panel de control.
- Haz clic en Añadir Endpoint.
- Introduce la URL de tu receptor de webhook (debe ser HTTPS).
- Selecciona qué tipos de evento quieres recibir.
- Opcionalmente establece un signing secret para verificar la autenticidad del webhook.
- Haz clic en Guardar.
VOCALS enviará un ping de prueba a tu endpoint para verificar que es accesible. El endpoint debe responder con un código de estado 2xx en 5 segundos.
Tipos de Evento
call.started
Se dispara cuando una llamada se conecta y el pipeline de voz comienza.
{
"event": "call.started",
"timestamp": "2026-03-02T14:30:00.000Z",
"data": {
"call_id": "call_abc123",
"direction": "inbound",
"from": "+15559876543",
"to": "+15551234567",
"agent_id": "agent_xyz789",
"agent_name": "Inbound Sales",
"phone_number_id": "pn_456"
}
}
call.ended
Se dispara cuando una llamada termina, independientemente del motivo.
{
"event": "call.ended",
"timestamp": "2026-03-02T14:35:22.000Z",
"data": {
"call_id": "call_abc123",
"direction": "inbound",
"from": "+15559876543",
"to": "+15551234567",
"agent_id": "agent_xyz789",
"agent_name": "Inbound Sales",
"status": "completed",
"duration_seconds": 322,
"turns": 12,
"cost": {
"stt": 0.0048,
"llm": 0.0135,
"tts": 0.0210,
"telephony": 0.0180,
"total": 0.0573
},
"recording_url": "https://your-vocals-domain.com/api/v1/recordings/rec_abc123",
"metadata": {}
}
}
call.failed
Se dispara cuando una llamada falla debido a un error técnico. No se dispara para escenarios normales de no-respuesta.
{
"event": "call.failed",
"timestamp": "2026-03-02T14:30:05.000Z",
"data": {
"call_id": "call_def456",
"direction": "outbound",
"from": "+15551234567",
"to": "+15559876543",
"agent_id": "agent_xyz789",
"error": {
"code": "provider_timeout",
"message": "STT provider (Deepgram) did not respond within 10 seconds",
"provider": "deepgram",
"stage": "stt"
}
}
}
transcript.ready
Se dispara cuando la transcripción completa de la llamada ha sido procesada y está disponible. Este evento se envía después de call.ended, normalmente en unos pocos segundos.
{
"event": "transcript.ready",
"timestamp": "2026-03-02T14:35:30.000Z",
"data": {
"call_id": "call_abc123",
"transcript": [
{
"speaker": "agent",
"text": "Hello, thank you for calling Acme Corp. How can I help you today?",
"timestamp": "2026-03-02T14:30:01.000Z"
},
{
"speaker": "caller",
"text": "Hi, I'd like to check the status of my order.",
"timestamp": "2026-03-02T14:30:05.500Z"
},
{
"speaker": "agent",
"text": "Of course! Could you give me your order number?",
"timestamp": "2026-03-02T14:30:07.200Z"
}
],
"summary": "Customer called to check order status. Agent provided tracking information. Customer confirmed receipt.",
"duration_seconds": 322,
"turns": 12
}
}
Verificar Firmas de Webhook
Si estableces un signing secret, VOCALS incluye una firma en el header X-Vocals-Signature de cada solicitud de webhook. Usa esto para verificar que la solicitud proviene de VOCALS y no fue manipulada.
La firma se calcula como un HMAC-SHA256 del cuerpo crudo de la solicitud usando tu signing secret:
import hmac
import hashlib
def verify_signature(payload_body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
payload_body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)
const crypto = require("crypto");
function verifySignature(payloadBody, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(payloadBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(`sha256=${expected}`),
Buffer.from(signature)
);
}
Política de Reintentos
Si tu endpoint no responde con un código de estado 2xx en 5 segundos, VOCALS reintenta la entrega con backoff exponencial:
| Intento | Espera |
|---|---|
| 1er reintento | 10 segundos |
| 2do reintento | 1 minuto |
| 3er reintento | 10 minutos |
| 4to reintento | 1 hora |
| 5to reintento | 4 horas |
Después de 5 reintentos fallidos, la entrega del webhook se marca como fallida y no se realizan más intentos para ese evento.
Si tu endpoint está temporalmente caído, puedes reproducir las entregas fallidas desde los registros de webhook una vez que esté de vuelta.
Registros de Entrega
Cada entrega de webhook se registra en Configuración > Webhooks > Registros de Entrega. Cada entrada del registro muestra:
- Tipo de evento y marca de tiempo.
- Payload de la solicitud enviado a tu endpoint.
- Código de estado de respuesta y cuerpo de respuesta de tu endpoint.
- Estado de entrega:
delivered,retryingofailed. - Latencia: cuánto tiempo tardó tu endpoint en responder.
Usa los registros de entrega para depurar problemas de integración. Puedes filtrar por tipo de evento, estado de entrega y rango de fechas.
Reproducir Entregas
Para reproducir una entrega fallida o perdida:
- Ve a Configuración > Webhooks > Registros de Entrega.
- Busca la entrega que quieres reproducir.
- Haz clic en Reproducir.
- VOCALS re-enviará exactamente el mismo payload a la URL actual de tu endpoint.
Esto es útil después de corregir un bug en tu receptor de webhook o recuperarte de un tiempo de inactividad.
Mejores Prácticas
- Responde rápidamente. Devuelve un
200 OKtan pronto como recibas el webhook. Procesa el payload de forma asíncrona. Si tu handler tarda demasiado, se tratará como un fallo y se reintentará. - Implementa idempotencia. Usa los campos
call_idyeventpara deduplicar entregas. El mismo evento puede entregarse más de una vez debido a reintentos. - Valida firmas. Siempre verifica el header
X-Vocals-Signatureen producción para prevenir solicitudes falsificadas. - Usa HTTPS. Los endpoints de webhook deben usar HTTPS. Los endpoints HTTP en texto plano son rechazados.
- Monitorea los registros de entrega. Revisa tus registros de entrega regularmente para detectar fallos de integración temprano. Configura alertas para fallos de entrega sostenidos.