Vertichat
VERTICHAT FOR DEVELOPERS

Conecta conversaciones con tu producto.

Integra el chat web, recibe eventos de Vertichat y conecta n8n, Make, tu ERP o servicios propios con contratos claros y seguros.

Base URLhttps://vertichat.verticali.mx
webhook.receivedPOST /eventos

deal.stage_changed

Firma válida · 202 Accepted
Tu web
Vertichat
Tu API
01 · QUICKSTART

Instala el chat web en minutos.

Obtén la clave pública en Configuración → Canales → Chat web. Registra previamente los dominios permitidos y pega el snippet antes de cerrar </body>.

HTML
<script
  src="https://vertichat.verticali.mx/widget.js"
  data-nexo-key="TU_PUBLIC_KEY"
  data-color="#3157FF"
  async>
</script>
La clave pública puede aparecer en el navegador.

No concede acceso al workspace. Las sesiones solo se emiten para orígenes autorizados y tienen sus propios límites.

02 · AUTENTICACIÓN

Un mecanismo para cada superficie.

Clave pública

Identifica el canal web. Se combina con la lista de orígenes permitidos.

data-nexo-key

Bearer de widget

Autoriza mensajes, lectura y cargas de un visitante. No lo compartas entre usuarios.

Authorization: Bearer …

Firma webhook

Autentica el cuerpo crudo de cada evento saliente mediante HMAC-SHA256.

X-SipoChat-Signature

Sesión de aplicación

Las rutas internas del CRM y la bandeja requieren cookie y mismo origen; no son una API pública.

SameSite + Origin

No automatices las rutas internas /api/app, /api/crm o /api/outbound-webhooks desde un servidor externo. Hoy se administran desde la interfaz autenticada.

03 · API PÚBLICA DEL WIDGET

Crea una sesión y conversa.

El widget oficial ya implementa este circuito. Usa la API directamente solo si necesitas construir una interfaz propia.

1. Crear sesión

cURL
curl -X POST \
  'https://vertichat.verticali.mx/api/widget/TU_PUBLIC_KEY/session' \
  -H 'Origin: https://tuempresa.com' \
  -H 'Content-Type: application/json' \
  -d '{
    "anonymousId": "visitor_123",
    "pageUrl": "https://tuempresa.com/precios"
  }'
201 Created
{
  "data": {
    "token": "widget_session_token",
    "anonymousId": "visitor_123",
    "expiresAt": 1787328000000,
    "channel": {
      "name": "Ventas web",
      "greeting": "¡Hola! ¿En qué podemos ayudarte?",
      "color": "#3157FF"
    }
  }
}

2. Enviar texto

JavaScript
const response = await fetch(
  "https://vertichat.verticali.mx/api/widget/TU_PUBLIC_KEY/messages",
  {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${session.token}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      content: "Quiero una demostración para mi equipo"
    })
  }
);

if (!response.ok) throw await response.json();
const { data } = await response.json();

3. Enviar un archivo

JavaScript
const form = new FormData();
form.append("file", selectedFile);
form.append("caption", "Documento para la cotización");

const response = await fetch(
  "https://vertichat.verticali.mx/api/widget/TU_PUBLIC_KEY/uploads",
  {
    method: "POST",
    headers: { "Authorization": `Bearer ${session.token}` },
    body: form
  }
);
MétodoRutaAutorizaciónUso
GET/api/widget/{publicKey}/bootstrapPúblicaConfiguración visible del canal
POST/api/widget/{publicKey}/sessionOrigen permitidoCrea una sesión de visitante
GET/api/widget/{publicKey}/messages?after={cursor}Bearer widgetLista mensajes de la sesión
POST/api/widget/{publicKey}/messagesBearer widgetEnvía un mensaje de texto
POST/api/widget/{publicKey}/uploadsBearer widgetEnvía un archivo multipart
POST/api/widget/{publicKey}/readBearer widgetMarca la conversación como leída
GET/api/public/webhook-attachments/{id}?token=…URL firmadaDescarga temporal de un adjunto

Las cargas requieren Content-Length, usan multipart/form-data y aplican límites por sesión, visitante y canal.

04 · WEBHOOKS SALIENTES

Recibe eventos de chat y CRM.

En Vertichat abre Webhooks → Nuevo webhook, registra una URL HTTPS, selecciona eventos y copia el secreto. El secreto solo se muestra al crear o rotar.

VertichatCongela el evento
Firma HMACTimestamp + body
Tu endpointValida y responde
ReintentoBackoff si falla

Cabeceras de entrega

X-SipoChat-EventX-SipoChat-DeliveryX-SipoChat-TimestampX-SipoChat-AttemptX-SipoChat-SignatureX-SipoChat-Spec-Version: 1.0

Payload Vertichat v1

application/json
{
  "specversion": "1.0",
  "id": "evt_8f9c...",
  "type": "deal.stage_changed",
  "version": "2026-07-01",
  "source": "https://vertichat.verticali.mx",
  "workspace_id": "wsp_123",
  "subject": "deal/deal_456",
  "time": "2026-07-21T16:10:00.000Z",
  "actor": { "type": "user", "id": "usr_789" },
  "context": { "conversation_id": "cnv_234" },
  "data": { "id": "deal_456", "title": "Plan Empresa" },
  "changes": {
    "stage_id": { "previous": "stage_new", "current": "stage_demo" }
  },
  "private": false
}

Verificar la firma

Node.js
import crypto from "node:crypto";

export function verifySipoChatWebhook(rawBody, headers, secret) {
  const timestamp = headers["x-sipochat-timestamp"];
  const received = headers["x-sipochat-signature"];
  if (!timestamp || !received?.startsWith("v1=")) return false;

  const ageMs = Math.abs(Date.now() - Number(timestamp) * 1000);
  if (ageMs > 5 * 60 * 1000) return false;

  const expected = crypto
    .createHmac("sha256", secret)
    .update(timestamp + "." + rawBody)
    .digest("hex");

  const actual = received.slice(3);
  if (actual.length !== expected.length) return false;
  return crypto.timingSafeEqual(
    Buffer.from(actual, "hex"),
    Buffer.from(expected, "hex")
  );
}
Usa el body crudo, antes de parsear JSON.
Compara la firma en tiempo constante.
Rechaza timestamps con más de 5 minutos.
Deduplica cada evento por su campo id.
Responde 2xx solo al persistir el evento.
Procesa en cola y mantén tu handler rápido.

La entrega es al menos una vez. Vertichat reintenta fallos transitorios con backoff; tu consumidor debe ser idempotente.

05 · EVENTOS

Suscríbete solo a lo que necesitas.

Las notas internas se excluyen por defecto. Para recibir note.created, un administrador debe activar explícitamente la inclusión de eventos privados.

Conversaciones

message.creatednote.createdattachment.createdconversation.createdconversation.updatedconversation.status_changed

Contactos

contact.createdcontact.updatedcompany.createdcompany.updated

CRM

deal.createddeal.updateddeal.stage_changeddeal.wondeal.lostactivity.created

Tareas

task.createdtask.updatedtask.completedtask.cancelledtask.reopened

Cotizaciones

quote.createdquote.sentquote.acceptedquote.rejected

Operación

webhook.test
¿Migras desde Chatwoot?

Selecciona chatwoot_compat_v1. Vertichat convierte el nombre del evento y los atributos modificados a una estructura compatible para facilitar la transición.

06 · WEBHOOKS DE CANAL

Callbacks que configura Vertichat.

Estas rutas reciben mensajes desde los proveedores. No son endpoints para emitir mensajes desde tu integración; el asistente de Canales las configura y protege.

WhatsApp Cloud API

GET/POST /api/webhooks/whatsapp

GET valida el verify token. POST exige X-Hub-Signature-256 de Meta.

Vertichat Connect

POST /api/webhooks/evolution/{channelId}

Ruta interna del conector. Exige X-Nexo-Evolution-Secret, valida la instancia y responde 202 al encolar.

07 · ERRORES, LÍMITES Y OPERACIÓN

Integra pensando en fallos.

Error estándar
{
  "error": {
    "code": "widget_session_rate_limited",
    "message": "Se iniciaron demasiadas sesiones para este visitante.",
    "details": { "retryAfterSeconds": 60 }
  }
}
400JSON o campos inválidos
401Token o firma incorrecta
403Origen no permitido
404Recurso oculto o inexistente
413Carga demasiado grande
429Límite temporal alcanzado
5xxReintenta con backoff y jitter

Checklist antes de producción

Usa HTTPS y conserva secretos fuera del código. Permite únicamente los orígenes reales del widget. Registra IDs de evento, no cuerpos con datos sensibles. Simula reintentos, duplicados, timeouts y firmas inválidas. Monitorea entregas fallidas y rota secretos periódicamente.
CONTRATO VERSIONADO

Explora la especificación completa.

Descarga el archivo OpenAPI para Postman, Insomnia, Swagger UI o generación de clientes.

OpenAPI JSONVer manual de usuario