Webhook

Ogni evento outbound è firmato con HMAC-SHA256 nell'header X-Lvbl-Signature. Verifica sempre la firma prima di processare il payload.

Mai fidarsi del payload senza verifica

Senza verifica della firma chiunque conosca l'URL può inviare eventi fake. Usa timingSafeEqual / hmac.compare_digest.

Verifica firma — Node.js

ts
import { createHmac, timingSafeEqual } from "crypto";
import express from "express";

const app = express();
app.use(express.raw({ type: "application/json" }));

app.post("/webhook/lvbl", (req, res) => {
  const signature = req.header("X-Lvbl-Signature") || "";
  const body = req.body.toString("utf8");

  const expected = createHmac("sha256", process.env.LVBL_WEBHOOK_SECRET!)
    .update(body)
    .digest("hex");

  if (
    signature.length !== expected.length ||
    !timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
  ) {
    return res.status(401).send("Invalid signature");
  }

  const event = JSON.parse(body);
  console.log(event.type, event.data);
  res.send("ok");
});

Verifica firma — Python

python
import hmac, hashlib, os
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = os.environ["LVBL_WEBHOOK_SECRET"].encode()

@app.post("/webhook/lvbl")
def hook():
    sig = request.headers.get("X-Lvbl-Signature", "")
    body = request.get_data()
    expected = hmac.new(SECRET, body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(sig, expected):
        abort(401)
    event = request.get_json()
    print(event["type"], event["data"])
    return "ok"

Esempio payload

json
{
  "type": "assignment",
  "experiment_id": "...",
  "data": {
    "user_id": "user-123",
    "variant_id": "...",
    "variant_name": "B"
  },
  "timestamp": "2026-05-31T12:00:00Z"
}

Eventi disponibili

A/B Testing

  • assignment — utente assegnato a una variante
  • conversion — goal raggiunto
  • winner — esperimento concluso con vincitore statistico
  • guardrail_violation — metrica guardrail oltre soglia
  • status_change — esperimento avviato / messo in pausa / terminato

Deadline Engine

  • subscribe — nuovo iscritto al countdown
  • expired — deadline scaduta per un iscritto
  • reminder_24h — promemoria 24h prima della scadenza
  • reminder_1h — promemoria 1h prima