Ringhum.

Desarrolladores

Webhooks

Recibe notificaciones HTTPS firmadas cuando terminan las llamadas, se toman mensajes, cambian las citas, pedidos y reservas, o termina una campaña, y verifica que cada una viene realmente de Ringhum.

6 min de lectura Actualizado el 24 septiembre 2026

En esta página

Un webhook envía una solicitud HTTPS a tu servidor en el momento en que algo ocurre en tu espacio de trabajo. Usa webhooks en lugar de consultar la API repetidamente: cuando termina una llamada, recibes el resumen, el resultado, los datos recopilados y la transcripción al instante. Cada entrega se firma con un secreto que solo conocéis tú y Ringhum, así que tu servidor puede rechazar cualquier cosa que no venga de Ringhum.

Añade un endpoint

Solo el Propietario y los Administradores del espacio de trabajo pueden añadir, probar y quitar endpoints.

  1. Abre Desarrolladores en el menú lateral.
  2. En la tarjeta Webhooks, haz clic en Añadir endpoint.
  3. Introduce la URL del endpoint. Debe empezar por https://.
  4. En Eventos, marca los que quieras. call.ended viene marcado por defecto.
  5. Haz clic en Añadir endpoint.
  6. Copia el secreto de firma del recuadro verde (empieza por whsec_) y guárdalo en tu servidor. Haz clic en Listo.

Importante: El secreto de firma se muestra solo una vez. Si lo pierdes, quita el endpoint y añádelo de nuevo para obtener uno nuevo.

Puedes añadir tantos endpoints como necesites. Los webhooks cubren todos los asistentes del espacio de trabajo. También puedes gestionar endpoints a través de la API, con POST /webhooks y una clave con el permiso de escritura.

Eventos

Evento Cuándo se envía
call.started Un asistente respondió una llamada
call.ended Una llamada terminó y se resumió (incluye transcripción y resumen)
call.transferred Una llamada se transfirió a una persona
message.taken El asistente tomó un mensaje
appointment.booked El asistente reservó una cita
appointment.rescheduled Una cita se movió a una nueva hora
appointment.cancelled Se canceló una cita
order.created Se hizo un pedido (por un asistente, a mano o a través de la API)
order.updated Un pedido pasó a un nuevo estado
order.cancelled Se canceló un pedido
reservation.created Se reservó una habitación (por un asistente, a mano o a través de la API)
reservation.updated Una reserva pasó a un nuevo estado (confirmada, entrada registrada, salida registrada, no presentado)
reservation.cancelled Se canceló una reserva
campaign.completed Una campaña saliente terminó de llamar a su lista
test.ping Hiciste clic en Enviar prueba

Cómo es una entrega

Cada entrega es un POST con un cuerpo JSON y estas cabeceras:

POST https://example.com/hooks/ringhum
Content-Type: application/json
User-Agent: Ringhum-Webhooks/1.0
X-Ringhum-Event: call.ended
X-Ringhum-Timestamp: 1789250000
X-Ringhum-Signature: v1=5f1a…

{
  "id": "evt_8f2k…",
  "type": "call.ended",
  "created_at": "2026-09-24T14:03:11+00:00",
  "data": {
    "call_id": 4812,
    "direction": "inbound",
    "from": "+14155550132",
    "to": "+14155550100",
    "assistant_id": 3,
    "status": "completed",
    "outcome": "message_taken",
    "sentiment": "neutral",
    "duration_seconds": 94,
    "summary": "Caller asked for a quote for a kitchen repair…",
    "extracted": { "name": "Dana Lee", "reason": "Quote" },
    "transcript": [
      { "role": "assistant", "content": "Hello, you've reached…" },
      { "role": "user", "content": "Hi, I'd like a quote…" }
    ]
  }
}

El objeto data depende del evento:

  • call.ended y message.taken: los campos de llamada anteriores.
  • call.started y call.transferred: call_id, direction, from, to, assistant_id, status y started_at.
  • appointment.*: appointment_id, title, status, starts_at, ends_at, timezone, customer (nombre, teléfono, correo), contact_id, service, staff, call_id y notes.
  • order.*: order_id, number, status, fulfillment, customer, address, items con opciones y precios, currency, subtotal, fee, total, source, call_id y, en las cancelaciones, cancel_reason.
  • reservation.*: reservation_id, number, status, room, check_in, check_out, nights, adults, children, guest, currency, nightly, total y source.
  • campaign.completed: campaign_id, name y los contadores de progreso de la campaña.

Nota: Cuando el asistente reserva una cita durante una llamada, puedes recibir appointment.booked dos veces. Una se envía en el momento de la reserva, con los campos de la cita. La otra se envía después de resumir la llamada, con los campos de la llamada. Comprueba si data tiene appointment_id o call_id y usa el campo id para evitar procesar una entrega dos veces.

Verifica la firma

La firma es un HMAC-SHA256 de la marca de tiempo, un punto, y el cuerpo bruto de la solicitud, con clave tu secreto de firma del endpoint. Se envía como v1= seguido del resumen hexadecimal.

  1. Lee el cuerpo bruto exactamente como se recibió, antes de cualquier análisis JSON.
  2. Construye la cadena {X-Ringhum-Timestamp}.{cuerpo bruto}.
  3. Calcula el HMAC-SHA256 con tu secreto y anteponle v1=.
  4. Compáralo con X-Ringhum-Signature usando una comparación de tiempo constante.
  5. Rechaza la solicitud si la marca de tiempo tiene más de cinco minutos, para bloquear solicitudes repetidas.

Node.js:

const crypto = require('crypto');

function isValid(req, rawBody, secret) {
  const ts = req.header('X-Ringhum-Timestamp');
  const sig = req.header('X-Ringhum-Signature') || '';
  const expected = 'v1=' + crypto.createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  return fresh && sig.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}

PHP:

$ts = $_SERVER['HTTP_X_RINGHUM_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_RINGHUM_SIGNATURE'] ?? '';
$expected = 'v1=' . hash_hmac('sha256', $ts . '.' . file_get_contents('php://input'), $secret);
if (! hash_equals($expected, $sig) || abs(time() - (int) $ts) > 300) {
    http_response_code(400);
    exit;
}

Respuestas, tiempos de espera y reintentos

  • Responde con cualquier estado 2xx para confirmar la entrega. Haz el trabajo lento después de responder.
  • Ringhum espera hasta 10 segundos tu respuesta.
  • Si tu endpoint no responde con un 2xx, la entrega se intenta hasta 3 veces en total: de inmediato, otra vez unos 10 segundos después, y una última vez unos 60 segundos más tarde. Después de eso se descarta.
  • Las entregas pueden llegar desordenadas. Usa created_at y los ids en data para ordenarlas.

La tabla Webhooks muestra el último estado HTTP de cada endpoint y cuándo se envió. Un endpoint fallido sigue activo; Ringhum no lo desactiva por ti.

Prueba, pausa y elimina

  • Enviar prueba envía un evento test.ping al instante, y un mensaje muestra el estado HTTP que devolvió tu endpoint.
  • El interruptor Activo pausa un endpoint. Los eventos que ocurren mientras está desactivado no se envían después.
  • Quitar elimina el endpoint y su secreto.

Preguntas frecuentes

¿Cuál es la diferencia con las aplicaciones de Zapier, Make y n8n en Integraciones? Esas conexiones usan la página Integraciones y sus seis tipos de evento. Su cuerpo es {"event", "workspace", "sent_at", "data"}, y cuando configuras un secreto la cabecera de firma es X-Ringhum-Signature: sha256=…, un HMAC-SHA256 solo del cuerpo. Los webhooks de desarrollador, descritos aquí, cubren más eventos y usan la firma v1= con una marca de tiempo. Consulta Elegir qué se envía.

Mi endpoint devuelve 2xx pero mi código no ve nada. Comprueba que el evento esté marcado para ese endpoint, que el endpoint esté activo, y que tu cortafuegos permita solicitudes de internet.

¿Por qué falla la comprobación de la firma? Lo más habitual es que el cuerpo se analizara y volviera a codificar antes de calcular el hash. Calcula el hash de los bytes brutos exactamente como se recibieron.

¿Sigues con dudas?

Escribe a [email protected] o envíanos un mensaje. Los planes Team y Scale tienen soporte prioritario.

Contactar con soporte