← Volver a integraciones

Webhooks Artemiz

Recibí en tiempo real los eventos importantes de tu CRM (ventas, leads, ghosting) en cualquier servicio: Zapier, Make, n8n o tu propio backend.

🔐 Firma HMAC
Cada request lleva header X-Artemiz-Signature: sha256=HMAC(secret, body). Verificá esto antes de confiar en el payload.
📍 Headers
X-Artemiz-Event identifica el tipo. User-Agent: Artemiz-Webhook/1.0. Content-Type: application/json.
⏱ Timeout
Respondé con 2xx en menos de 10 segundos. No hay retry queue en V1 — un fallo se loguea pero no reintenta.

Estructura del payload

Todos los eventos llegan envueltos en este sobre:

{
  "event": "sale.paid",
  "tenant_id": "abc-123",
  "fired_at": "2026-05-04T15:30:01.234Z",
  "data": { /* contenido específico del evento */ }
}

Eventos disponibles

lead.first_inboundLead nuevo (primer inbound)

Cuando un número desconocido escribe por primera vez.

{
  "event": "lead.first_inbound",
  "tenant_id": "tu-tenant-uuid",
  "fired_at": "2026-05-04T15:30:01.234Z",
  "data": {
    "cliente_id": "demo-cli-001",
    "nombre": "María Pérez",
    "telefono": "+51999111222",
    "canal": "whatsapp",
    "primer_mensaje": "Hola, me interesa el modelo en oferta",
    "received_at": "2026-05-04T14:23:11.000Z"
  }
}
client.createdCliente creado

Cuando se crea un nuevo cliente en el CRM (mismo trigger que lead.first_inbound en su mayoría).

{
  "event": "client.created",
  "tenant_id": "tu-tenant-uuid",
  "fired_at": "2026-05-04T15:30:01.234Z",
  "data": {
    "cliente_id": "demo-cli-001",
    "nombre": "María Pérez",
    "telefono": "+51999111222",
    "fuente": "whatsapp_inbound",
    "created_at": "2026-05-04T14:23:11.000Z"
  }
}
lead.ghostedLead ghosteado

Cuando un lead deja de responder por más de 48h (cron kanban-automove).

{
  "event": "lead.ghosted",
  "tenant_id": "tu-tenant-uuid",
  "fired_at": "2026-05-04T15:30:01.234Z",
  "data": {
    "cliente_id": "demo-cli-002",
    "nombre": "Carlos Mendoza",
    "telefono": "+51988777666",
    "last_inbound_at": "2026-05-02T09:15:00.000Z",
    "horas_sin_responder": 48,
    "etapa_kanban": "calentando"
  }
}
solicitud.createdSolicitud creada

Cuando se crea una solicitud (carrito de compra) desde la extensión o panel.

{
  "event": "solicitud.created",
  "tenant_id": "tu-tenant-uuid",
  "fired_at": "2026-05-04T15:30:01.234Z",
  "data": {
    "solicitud_id": "demo-sol-101",
    "cliente_id": "demo-cli-001",
    "cliente_nombre": "María Pérez",
    "productos": [
      {
        "id": "demo-prod-1",
        "nombre": "Perfume Cosmos 100ml",
        "cantidad": 1,
        "precio_unitario": 189
      }
    ],
    "total": 189,
    "moneda": "PEN",
    "estado": "pendiente",
    "created_at": "2026-05-04T14:25:00.000Z"
  }
}
solicitud.cancelledSolicitud cancelada

Cuando una solicitud cambia de estado a cancelada.

{
  "event": "solicitud.cancelled",
  "tenant_id": "tu-tenant-uuid",
  "fired_at": "2026-05-04T15:30:01.234Z",
  "data": {
    "solicitud_id": "demo-sol-101",
    "cliente_id": "demo-cli-001",
    "motivo": "cliente_cambio_opinion",
    "cancelled_at": "2026-05-04T15:10:00.000Z"
  }
}
sale.createdVenta creada

Cuando se emite boleta. Estado inicial pendiente_pago.

{
  "event": "sale.created",
  "tenant_id": "tu-tenant-uuid",
  "fired_at": "2026-05-04T15:30:01.234Z",
  "data": {
    "venta_id": "demo-ven-201",
    "solicitud_id": "demo-sol-101",
    "cliente_id": "demo-cli-001",
    "cliente_nombre": "María Pérez",
    "productos": [
      {
        "id": "demo-prod-1",
        "nombre": "Perfume Cosmos 100ml",
        "cantidad": 1,
        "precio_unitario": 189
      }
    ],
    "total": 189,
    "moneda": "PEN",
    "estado": "pendiente_pago",
    "created_at": "2026-05-04T15:00:00.000Z"
  }
}
sale.paidVenta pagada

Cuando una venta se marca como pagada.

{
  "event": "sale.paid",
  "tenant_id": "tu-tenant-uuid",
  "fired_at": "2026-05-04T15:30:01.234Z",
  "data": {
    "venta_id": "demo-ven-201",
    "cliente_id": "demo-cli-001",
    "cliente_nombre": "María Pérez",
    "total": 189,
    "moneda": "PEN",
    "metodo_pago": "yape",
    "paid_at": "2026-05-04T15:30:00.000Z"
  }
}

Verificar la firma (Node.js)

import { createHmac, timingSafeEqual } from "crypto";

function verifyArtemizWebhook(rawBody: string, header: string, secret: string): boolean {
  const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
  if (header.length !== expected.length) return false;
  return timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}

// Express handler
app.post("/artemiz", express.raw({ type: "application/json" }), (req, res) => {
  const sig = req.header("X-Artemiz-Signature") || "";
  if (!verifyArtemizWebhook(req.body.toString(), sig, process.env.ARTEMIZ_SECRET!)) {
    return res.status(401).end();
  }
  const payload = JSON.parse(req.body.toString());
  console.log("Received", payload.event, payload.data);
  res.status(200).end();
});