Recibe eventos de woku en tu sistema en tiempo real, con firma HMAC para verificar la autenticidad y reintentos automáticos
Los webhooks te permiten recibir notificaciones HTTP en tu propio
servidor cada vez que ocurre un evento relevante en woku: una nueva
reseña woku, un NPS, un CSAT, un CES, la respuesta de un
formulario o un ticket de soporte generado por IA. woku hace un
POST con un cuerpo JSON a la URL que configures.
Los webhooks se administran desde la aplicación administrativa, no por
API pública.
1
Abre la configuración de integraciones
En el panel, entra a Empresa → Integraciones → Webhooks.
2
Crea un webhook
Pulsa Nuevo webhook e ingresa la URL de tu endpoint, los
eventos a los que te suscribes y, opcionalmente, headers
personalizados y la política de reintentos.
3
Guarda el secret
Al crear el webhook, woku muestra el secret una sola vez. Cópialo y
guárdalo de forma segura: lo necesitarás para verificar la firma de
cada evento.
El secret se muestra una única vez al crear o rotar el webhook. woku
lo guarda cifrado y no puede volver a mostrártelo. Si lo pierdes, rótalo
desde el panel para generar uno nuevo.
Los payloads no incluyen datos de contacto del cliente, con una
excepción: ticket.created, cuyo caso incluye la identidad del cliente
para que el equipo de soporte pueda contactarlo.
Cuando la IA de woku detecta riesgo de perder a un cliente por una mala
experiencia, crea un ticket de soporte. Puedes recibirlo de dos
formas, y usar ambas a la vez:
Conectores directos (recomendado, sin código): en Soporte →
Configurar conectas woku a tu plataforma de soporte (Zendesk,
Salesforce, Slack o un endpoint personalizado). woku crea el ticket
directamente en la plataforma; el ruteo por trackers y el formato de
cada plataforma se resuelven en el servidor de woku, sin que expongas
ningún servicio propio.
Webhook (para integraciones a medida): suscribe un webhook al
evento ticket.created y recibe el caso completo en formato
canónico, listo para crearlo en tu plataforma con tu propio código.
A diferencia del resto de los eventos, el payload de ticket.created
lleva la identidad del cliente para que soporte pueda contactarlo.
En Soporte → Configurar agregas uno o más destinos. Cada destino
representa una unidad de tu SAC (por ejemplo “SAC Chile” y “SAC
México”): apunta a una plataforma (zendesk, salesforce, slack o
personalizado), guarda sus credenciales de forma cifrada e identifica el
equipo que recibe el ticket dentro de la plataforma, nunca un agente
suelto:
Zendesk: el grupo de agentes (group_id).
Salesforce: la cola de casos (OwnerId, un id 00G...).
Slack: el canal (queda definido por la URL del webhook entrante).
Cada destino define además sus condiciones de ruteo sobre los valores
de los trackers: el ticket llega al destino cuando se cumplen todas sus
condiciones (y cada condición se cumple con cualquiera de sus valores).
Por ejemplo, “SAC Chile” recibe los tickets con País = Chile. Si un
ticket no cumple las condiciones de ningún destino, va al destino por
defecto. El formato del cuerpo lo resuelve woku según la plataforma; para
el destino personalizado defines tú el template con placeholders sobre el
payload canónico (por ejemplo {{case.subject}}).
Un webhook suscrito a ticket.created recibe siempre el payload
canónico completo (los webhooks no transforman el cuerpo ni participan
del ruteo: todo webhook suscrito recibe todos los tickets). El campo
routing.matched indica si el ticket se ruteó a un destino directo
(route), al destino por defecto (default) o a ninguno (null):
Cada entrega incluye el header X-Woku-Signature con una firma
HMAC-SHA256 del cuerpo JSON crudo, usando tu secret como llave:
X-Woku-Signature: sha256=<hex>
Calcula la firma sobre el cuerpo crudo de la solicitud (los bytes
exactos recibidos), antes de parsearlo como JSON. Re-serializar el
objeto puede cambiar el orden de las llaves o el espaciado y producir una
firma distinta.
Compara siempre con una función de tiempo constante para evitar
ataques de temporización. Si la firma no coincide, descarta la solicitud.
import crypto from 'node:crypto';function verifyWokuSignature(rawBody, signatureHeader, secret) { // signatureHeader: "sha256=<hex>" const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex'); const a = Buffer.from(signatureHeader); const b = Buffer.from(expected); return a.length === b.length && crypto.timingSafeEqual(a, b);}// Ejemplo con Express. Usa el cuerpo crudo, no el JSON parseado.import express from 'express';const app = express();app.post( '/webhooks/woku', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.header('X-Woku-Signature') ?? ''; if (!verifyWokuSignature(req.body, signature, process.env.WOKU_WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); } const event = JSON.parse(req.body.toString('utf8')); // ... procesa el evento res.status(200).json({ received: true }); },);
import hashlibimport hmacdef verify_woku_signature(raw_body: bytes, signature_header: str, secret: str) -> bool: # signature_header: "sha256=<hex>" expected = "sha256=" + hmac.new( secret.encode("utf-8"), raw_body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, signature_header)# Ejemplo con Flask. request.data es el cuerpo crudo.from flask import Flask, request, abort, jsonifyimport osapp = Flask(__name__)@app.post("/webhooks/woku")def woku_webhook(): signature = request.headers.get("X-Woku-Signature", "") if not verify_woku_signature(request.data, signature, os.environ["WOKU_WEBHOOK_SECRET"]): abort(401) event = request.get_json() # ... procesa el evento return jsonify(received=True), 200
Tu endpoint debe responder con un código HTTP 2xx (idealmente 200)
lo antes posible. woku considera exitosa la entrega ante cualquier 2xx.
Procesa el evento de forma asíncrona: responde 200 de inmediato y
encola el trabajo pesado. woku usa un timeout de 30 segundos por
intento; si tu endpoint tarda más, la entrega se cuenta como fallida.
Si tu endpoint no responde con 2xx (o no responde dentro del timeout),
woku reintenta con backoff exponencial:
Intento
Espera antes del intento
1
inmediato
2
~1 s
3
~2 s
Tras agotar los 3 intentos, la entrega pasa a estado dead-letter:
no se vuelve a intentar automáticamente. Puedes revisar el historial de
entregas y reintentar manualmente las que quedaron en dead-letter
desde Empresa → Integraciones → Webhooks, en el detalle del webhook.
Como un evento puede entregarse más de una vez (por un reintento sobre una
entrega que sí llegó pero respondió tarde), diseña tu endpoint para que
sea idempotente: usa el identificador del recurso en data para
descartar duplicados.