Webhooks
Receive real-time webhook notifications when Pique makes decisions about visitor sessions.
When Pique makes an actionable decision about a visitor session, it sends a webhook to your configured endpoints. Webhooks are delivered via Svix, which handles signing, retries, and delivery logging.
Payload format
Every webhook has the event type decision.made and the following JSON body:
{
"type": "decision.made",
"decision": {
"id": "a1b2c3d4-...",
"action": "cart_abandonment",
"reason": "Added \"Summer Dress\" to cart but left without purchasing.",
"llmReasoning": "This visitor spent 4 minutes browsing 3 products before adding..."
},
"session": {
"visitorId": "f8e7d6c5-...",
"email": "customer@example.com",
"eventCount": 12,
"durationSeconds": 245,
"productsViewed": 3,
"cartItems": ["Summer Dress"]
},
"timestamp": "2025-01-15T14:32:00.000Z"
}
Signature verification
Every webhook is signed by Svix using HMAC-SHA256. When you create an endpoint, you receive a signing secret (starting with whsec_). Verify incoming webhooks using the Svix SDK:
import { Webhook } from "svix";
const wh = new Webhook("whsec_your_signing_secret");
function handleWebhook(req, res) {
try {
const payload = wh.verify(req.body, {
"svix-id": req.headers["svix-id"],
"svix-timestamp": req.headers["svix-timestamp"],
"svix-signature": req.headers["svix-signature"],
});
// payload is verified — process it
console.log(payload);
res.status(200).json({ ok: true });
} catch (err) {
res.status(400).json({ error: "Invalid signature" });
}
}
Klaviyo integration
The most common integration is connecting Pique decisions to Klaviyo flows. Here's a step-by-step guide.
1. Create a Klaviyo API key
In your Klaviyo account, go to Settings → API Keys and create a private API key with write access to Events (Track API). Copy the key.
2. Set up a webhook relay
Deploy a small HTTP endpoint that receives Pique webhooks and forwards them to Klaviyo's Track API. Below is a complete example:
import express from "express";
import { Webhook } from "svix";
const app = express();
app.use(express.raw({ type: "application/json" }));
const SVIX_SECRET = process.env.SVIX_SECRET;
const KLAVIYO_API_KEY = process.env.KLAVIYO_API_KEY;
app.post("/webhook", async (req, res) => {
const wh = new Webhook(SVIX_SECRET);
let payload;
try {
payload = wh.verify(req.body, {
"svix-id": req.headers["svix-id"],
"svix-timestamp": req.headers["svix-timestamp"],
"svix-signature": req.headers["svix-signature"],
});
} catch {
return res.status(400).json({ error: "Invalid signature" });
}
if (!payload.session.email) {
return res.status(200).json({ skipped: "no email" });
}
const eventName = {
cart_abandonment: "Pique Cart Abandonment",
browse_abandonment: "Pique Browse Abandonment",
price_sensitive: "Pique Price Sensitive",
gentle_nudge: "Pique Gentle Nudge",
}[payload.decision.action] || `Pique ${payload.decision.action}`;
await fetch("https://a.klaviyo.com/api/events", {
method: "POST",
headers: {
Authorization: `Klaviyo-API-Key ${KLAVIYO_API_KEY}`,
"Content-Type": "application/json",
revision: "2024-10-15",
},
body: JSON.stringify({
data: {
type: "event",
attributes: {
metric: { data: { type: "metric", attributes: { name: eventName } } },
profile: {
data: {
type: "profile",
attributes: { email: payload.session.email },
},
},
properties: {
action: payload.decision.action,
reason: payload.decision.reason,
llmReasoning: payload.decision.llmReasoning,
productsViewed: payload.session.productsViewed,
cartItems: payload.session.cartItems,
durationSeconds: payload.session.durationSeconds,
},
time: payload.timestamp,
},
},
}),
});
res.status(200).json({ ok: true });
});
app.listen(3001, () => console.log("Relay listening on :3001"));
3. Map actions to Klaviyo flows
In Klaviyo, create flows triggered by the metric names above. For example:
- Pique Cart Abandonment → Send an abandoned cart email with the items from
cartItems - Pique Browse Abandonment → Send a product recommendation email
- Pique Price Sensitive → Send a discount or bundle offer
- Pique Gentle Nudge → Send a soft follow-up with the products they viewed
The llmReasoning field is available as a Klaviyo event property — you can use it in email templates for personalized copy or internal context.
Generic webhook
For any HTTP endpoint, the flow is:
- Add a webhook endpoint in Settings → Webhooks
- Copy the signing secret
- Verify the
svix-signatureheader on incoming requests - Parse the JSON body and route on
decision.action - Respond with 2xx within 15 seconds
Svix retries failed deliveries with exponential backoff. You can view delivery logs and manually retry from the Webhooks section in your dashboard.