guaba·commerceWebhooks · guía técnica

Avisos a otras apps · versión 1

Enterate en tu sistema de lo que pasa en Guaba

Cuando entra un pedido, cambia su estado o una conversación pasa a una persona, Guaba hace un POST con JSON a la dirección que vos configurés en Configuración → Avisos a otras apps. Sirve tal cual para Zapier, Make, n8n, tu propio servidor o una hoja de cálculo. Está incluido en los planes Crece y Negocio.

1 · Configurá el destino

En Configuración agregá un destino con su URL https://. Guaba genera un secreto de firma (empieza con whsec_) y te lo muestra una sola vez: guardalo. Con «Probar envío» mandamos un evento prueba.ping.

  • Solo https, puerto 443 u 8443. No se aceptan direcciones IP ni redes internas (se revisa al guardar y en cada envío).
  • No seguimos redirecciones: poné la URL final.
  • Tu servidor tiene 8 segundos para responder. Cualquier 2xx cuenta como recibido.
  • Hasta 5 destinos por negocio.

2 · El evento

Todos los eventos tienen el mismo sobre: id (único por evento), tipo, version, creado_en, negocio_id y datos.

tipocuándo
pedido.creadoSe creó un pedido (por el bot, el agente o el panel).
pedido.estado_cambiadoEl pedido cambió de estado. Trae estado_anterior y estado_nuevo junto a pedido.
conversacion.escaladaUna conversación pasó de Guaba a una persona. datos.conversacion trae id, cliente y último mensaje.
prueba.pingEl botón «Probar envío».

Ejemplo de pedido.creado:

{
  "id": "4b0d2c0e-6d54-4f0e-9a52-3c7a8d2f1b10",
  "tipo": "pedido.creado",
  "version": 1,
  "creado_en": "2026-10-07T15:04:05.000Z",
  "negocio_id": "0b8c…",
  "datos": {
    "pedido": {
      "id": "7f3a…",
      "estado": "nuevo",
      "total": 12500,
      "moneda": "CRC",
      "notas": null,
      "creado_en": "2026-10-07T15:03:51.000Z",
      "cliente": { "nombre": "Ana", "telefono": "50688887777" },
      "items": [
        { "nombre": "Café molido", "opcion": "500 g", "cantidad": 2, "precio_unitario": 6250 }
      ]
    }
  }
}

Los datos del pedido son los del momento del envío (el estado puede haber avanzado desde que ocurrió el evento). Los estados son nuevo, confirmado, preparando, entregado y cancelado.

3 · Encabezados y firma

EncabezadoQué es
X-Guaba-Signaturesha256= + HMAC-SHA256 en hexadecimal de <timestamp>.<cuerpo>, con tu secreto.
X-Guaba-TimestampSegundos desde 1970 (UTC) del envío. Cambia en cada reintento.
X-Guaba-Event-IdEl mismo id del cuerpo. Es igual en todos los reintentos: usalo para no procesar dos veces.
X-Guaba-EventEl tipo del evento.

Verificación en Node.js (Express):

import crypto from "node:crypto";
import express from "express";

const app = express();
const SECRETO = process.env.GUABA_SECRETO; // el whsec_… que te mostró Guaba

// OJO: hay que leer el cuerpo CRUDO (sin parsear), es lo que se firma.
app.post("/guaba", express.raw({ type: "application/json" }), (req, res) => {
  const timestamp = req.header("X-Guaba-Timestamp");
  const firma = req.header("X-Guaba-Signature") ?? "";
  const cuerpo = req.body.toString("utf8");

  // 1) Rechazá mensajes viejos (anti-replay): tolerá 5 minutos.
  const ts = Number(timestamp);
  if (!Number.isFinite(ts) || Math.abs(Date.now() / 1000 - ts) > 300) {
    return res.sendStatus(400);
  }

  // 2) Recalculá la firma: HMAC-SHA256 de "<timestamp>.<cuerpo>".
  const esperada =
    "sha256=" +
    crypto.createHmac("sha256", SECRETO).update(`${timestamp}.${cuerpo}`).digest("hex");
  const a = Buffer.from(firma);
  const b = Buffer.from(esperada);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.sendStatus(401);
  }

  // 3) Idempotencia (obligatoria): el mismo evento puede llegar dos veces.
  //    Guardá el id (o X-Guaba-Event-Id) y no lo proceses de nuevo.
  const evento = JSON.parse(cuerpo);
  if (yaProcesado(evento.id)) return res.sendStatus(200);

  procesar(evento); // tu lógica
  res.sendStatus(200); // cualquier 2xx = recibido
});

4 · Reintentos

Si tu servidor no responde 2xx, Guaba reintenta con espera exponencial: 1 min, 4 min, 16 min, ~1 h y ~4 h (6 intentos en total). Se reintenta ante errores 5xx, 408, 425, 429, tiempo agotado y fallas de red; un 4xx (salvo esos) o una redirección se toman como error de configuración y no se reintentan. Lo que falla del todo queda en Últimos avisos con el botón «Reintentar». Guardamos 30 días de historial.

Los eventos pueden llegar repetidos o fuera de orden: usá id (igual a X-Guaba-Event-Id) para deduplicar y el estado del pedido que viene en el cuerpo, no el orden de llegada. Tu receptor tiene que ser idempotente: un mismo evento puede llegar dos veces (por ejemplo, si tu respuesta se pierde).

5 · Zapier, Make, n8n y hojas de cálculo

  • Zapier: trigger «Webhooks by Zapier → Catch Hook», pegá su URL como destino. Cada campo del JSON queda disponible en tus pasos.
  • Make: módulo «Webhooks → Custom webhook». Activá «Get request headers» si querés verificar la firma.
  • n8n: nodo «Webhook» (POST) y, para verificar la firma, un nodo «Code» con el ejemplo de arriba.
  • Google Sheets (Apps Script): publicá un script como «Aplicación web» con una función doPost(e) que haga JSON.parse(e.postData.contents) y agregue una fila. Apps Script no deja leer los encabezados, así que no puede verificar la firma: agregale a la URL un parámetro secreto largo (…/exec?clave=…) y comprobalo en el script.

¿Integrás tu propia tienda? Mirá también la guía de Guaba Connect.