Saltar al contenido
CorekChat Ayuda Guías para clientes

Ayuda · Integraciones y API

Cómo configurar webhooks para recibir avisos en tu sistema

Un webhook es un aviso que CorekChat le manda a tu sistema en el momento en que algo pasa: entra un pedido, cambia de estado, se crea o se cancela una reserva, se abre o se cierra una mesa. Así tu facturación, tu contabilidad o tu tablero se enteran solos, sin tener que preguntar cada rato. La primera parte es para quien administra la cuenta; la segunda, para quien programa el receptor.

#Paso 1: abre la pestaña Webhooks

Abre Configuraciones y elige Webhooks, en el grupo Desarrolladores. Ahí están las direcciones que reciben avisos (se llaman endpoints) y, abajo, el historial de las últimas entregas.

Captura del sistema, sólo para clientesConfiguraciones → Webhooks: los endpoints arriba y las últimas entregas abajoVerla con tu cuenta

#Paso 2: crea el endpoint

Pulsa Nuevo endpoint y completa:

  • Dirección (HTTPS): la que te da quien programa el receptor. Tiene que empezar con https:// y estar publicada en internet; no se aceptan direcciones de una red interna.
  • Descripción: para reconocerlo después («Sistema de facturación»).
  • Eventos: marca sólo los que ese sistema usa.

Pulsa Guardar. Puedes tener hasta diez endpoints.

Captura del sistema, sólo para clientesNuevo endpoint: la dirección HTTPS, una descripción y los eventos que ese sistema necesitaVerla con tu cuenta

#Paso 3: guarda el secreto

Al guardar aparece el secreto del endpoint, una sola vez. Cópialo y pásaselo a quien programa el receptor: con él comprueba que cada aviso salió de CorekChat y no de un tercero. Si se pierde, usa Rotar secreto: se genera uno nuevo y el anterior deja de servir apenas termina la rotación, así que hay que cargar el nuevo en el receptor enseguida.

Captura del sistema, sólo para clientesEl secreto se ve una única vez: al crear el endpoint o al rotarloVerla con tu cuenta

#Revisar las entregas

En Últimas entregas ves cada aviso, a qué endpoint fue, si llegó y qué respondió el receptor. Una entrega Entregada es la que el receptor aceptó; una Falló agotó sus intentos y se puede mandar de nuevo con Reintentar.

Si un endpoint falla cinco entregas seguidas, se desactiva solo y te llega un correo: así un receptor caído no se queda acumulando avisos. Cuando se corrija, pulsa Reactivar. Desactivar hace lo mismo a mano, por ejemplo durante un cambio de proveedor.

#Para quien programa: qué llega

Cada aviso es un POST a la dirección del endpoint, con un cuerpo JSON así:

{
  "id": "5d0e3c1a-…",
  "event": "order.created",
  "createdAt": "2026-09-27T13:05:12.000Z",
  "data": {
    "orderId": "8f1c…",
    "branchId": "3a2e…",
    "channel": "whatsapp",
    "status": "pending",
    "total": 42000,
    "itemCount": 2,
    "createdAt": "2026-09-27T13:05:12.000Z"
  }
}

Y con estos encabezados:

Encabezado Qué trae
X-Corek-Event El nombre del evento, igual que event
X-Corek-Delivery El id de la entrega, igual que id
X-Corek-Signature La firma: t=<segundos>,v1=<firma>

#Los eventos

Evento Cuándo Qué trae en data
order.created Entra un pedido orderId, branchId, channel, status, total, itemCount, createdAt
order.status_changed Un pedido cambia de estado orderId, branchId, previousStatus, status, total, changedAt
reservation.created Se crea una reserva reservationId, branchId, status, partySize, scheduledAt, createdAt
reservation.cancelled Se cancela una reserva reservationId, branchId, partySize, scheduledAt, cancelledBy (customer o staff), cancelledAt
conversation.escalated El asistente pasa una conversación a una persona conversationId, channel, reason, escalatedAt
table.session_opened Se abre una mesa en el salón sessionId, tableId, tableLabel, branchId, partySize, openedAt
table.session_closed Se cierra una mesa sessionId, tableId, tableLabel, branchId, openedAt, closedAt, total, orderCount
order.updated Tu equipo modifica un pedido desde el panel (productos, cantidades, dirección, pago, nota o datos del cliente) orderId, branchId, status, total, itemCount, changes, updatedAt

Los avisos llevan lo mínimo a propósito. Para el detalle de un pedido o de una reserva, consulta la API con el id que llegó. Los dos eventos de mesas sólo salen con el módulo POS.

changes de order.updated es la lista de lo que cambió, con estos nombres: items, total, deliveryAddress, paymentMethod, notes, customerName, customerPhone y deliveryFee (el valor del domicilio, cuando el cliente cambia la dirección de un pedido pendiente por el chat). Si un pedido vuelve a un estado anterior (por ejemplo, de «Enviado» a «En preparación»), lo que llega es order.status_changed, con el estado anterior en previousStatus.

#Verificar la firma

La firma es un HMAC-SHA256, con el secreto del endpoint, sobre el texto <t>.<cuerpo>: los segundos de t, un punto y el cuerpo exactamente como llegó, antes de convertirlo a JSON. Rechaza el aviso si la firma no coincide o si t tiene más de cinco minutos: así nadie puede reenviar un aviso viejo que haya capturado.

// Node.js — ejemplo con Express. Ojo: hay que leer el cuerpo CRUDO.
const crypto = require('crypto');
const express = require('express');
const app = express();

// El whsec_… del paso 3.
const SECRETO = process.env.COREK_WEBHOOK_SECRET;

const crudo = express.raw({ type: 'application/json' });

app.post('/webhooks/corekchat', crudo, (req, res) => {
  const cuerpo = req.body.toString('utf8');
  const encabezado = String(req.get('X-Corek-Signature') || '');
  const partes = Object.fromEntries(
    encabezado.split(',').map((p) => p.split('=')),
  );
  const t = Number(partes.t);
  const esperada = crypto
    .createHmac('sha256', SECRETO)
    .update(`${t}.${cuerpo}`)
    .digest('hex');

  const firmaOk =
    partes.v1 &&
    partes.v1.length === esperada.length &&
    crypto.timingSafeEqual(
      Buffer.from(partes.v1),
      Buffer.from(esperada),
    );
  const reciente = Math.abs(Date.now() / 1000 - t) <= 300;
  if (!firmaOk || !reciente) return res.status(400).end();

  const aviso = JSON.parse(cuerpo);
  // …procesa aviso.event y aviso.data…
  res.status(200).end();
});
# Python — la misma cuenta.
import hashlib, hmac, time

def firma_valida(secreto: str, encabezado: str, cuerpo: bytes) -> bool:
    partes = dict(p.split("=", 1) for p in encabezado.split(",") if "=" in p)
    t = int(partes.get("t", "0"))
    firmado = f"{t}.".encode() + cuerpo
    esperada = hmac.new(secreto.encode(), firmado, hashlib.sha256).hexdigest()
    reciente = abs(time.time() - t) <= 300
    return hmac.compare_digest(partes.get("v1", ""), esperada) and reciente

#Cómo responder y qué pasa si falla

  • Responde con un código 2xx en menos de 10 segundos. Si el trabajo es largo, guarda el aviso, responde y procésalo después.
  • Si el receptor no contesta o responde un error del servidor (5xx), el aviso se reintenta solo: hasta cinco intentos, a los 30 segundos, 2 minutos, 8 minutos y 32 minutos.
  • Un error del cliente (4xx) no se reintenta, porque repetir lo mismo daría el mismo error; salvo 408 y 429, que sí.
  • Un mismo aviso puede llegar más de una vez. Los reintentos automáticos conservan el mismo id; un Reintentar manual crea una entrega nueva con otro id. Para no procesar dos veces el mismo hecho, guíate por el dato del evento: por ejemplo, el orderId junto con el status.