协作头脑风暴
brainstorming
在实现前澄清需求、探索设计选择,并形成清晰的开发方向。
klaviyo-webhooks-events【开发与工程】Implement Klaviyo webhooks with HMAC-SHA256 signature verification and event handling. Use when setting up webhook endpoints, handling Klaviyo event notifications, or creating event-driven integrations with Klaviyo. Trigger with phrases like "klaviyo webhook", "klaviyo events", "klaviyo webhook signature", "handle klaviyo events", "klaviyo notificati…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
name: klaviyo-webhooks-events description: 'Implement Klaviyo webhooks with HMAC-SHA256 signature verification and event handling.
Use when setting up webhook endpoints, handling Klaviyo event notifications,
or creating event-driven integrations with Klaviyo.
Trigger with phrases like "klaviyo webhook", "klaviyo events",
"klaviyo webhook signature", "handle klaviyo events", "klaviyo notifications".
' allowed-tools: Read, Write, Edit, Bash(curl:), Bash(npm:) version: 1.7.0 license: MIT author: Jeremy Longshore jeremy@intentsolutions.io tags:
Set up Klaviyo webhooks with HMAC-SHA256 signature verification, event routing, idempotency handling, and the Webhooks API for programmatic subscription management.
This skill covers the full endpoint lifecycle in six steps: create a webhook subscription via the API, verify each request's signature, receive events in an Express handler, route them to per-topic handlers, deduplicate with Redis, and manage subscriptions. The high-level flow and the security-critical signature check live here; the complete step-by-step source is in references/implementation.md and worked scenarios are in references/examples.md.
webhooks:read, webhooks:writeKlaviyo webhooks fire when specific topics occur in your account. Each webhook is signed with a secret key using HMAC-SHA256, sent in the webhook-signature header.
| Topic Category | Example Topics |
|---|---|
| Profile | profile.created, profile.updated, profile.deleted |
| List | list.member.added, list.member.removed |
| Segment | segment.member.added, segment.member.removed |
| Campaign | campaign.sent, campaign.delivered |
| Flow | flow.triggered, flow.message.sent |
| Event | Custom metric events |
Follow these six steps in order. Each is fully sourced in references/implementation.md; the security-critical signature check is inlined below because getting it wrong is the most common failure.
webhooksApi.createWebhook with the target endpointUrl and webhookTopics, then save the signing secret from the response as KLAVIYO_WEBHOOK_SIGNING_SECRET.express.raw({ type: 'application/json' }) so the raw body survives for verification; reject on a bad signature, then parse.event.type to a per-topic handler map (profile.created, campaign.sent, ...).The signature-verification helper is the load-bearing piece — copy it exactly:
// src/klaviyo/webhook-verify.ts
import crypto from 'crypto';
export function verifyWebhookSignature(
rawBody: Buffer | string,
signature: string,
secret: string
): boolean {
if (!signature || !secret) return false;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(typeof rawBody === 'string' ? rawBody : rawBody.toString())
.digest('base64');
try {
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
} catch {
return false;
}
}
For the Express handler, event router, Redis idempotency layer, and subscription-management calls, see references/implementation.md.
A working integration produces:
createWebhook returns a webhook ID and a signing secret; store the secret as KLAVIYO_WEBHOOK_SIGNING_SECRET.200 { received: true } on success, 200 { status: 'already_processed' } on a replayed event, 401 { error: 'Invalid signature' } on a bad signature, and 500 { error: 'Processing failed' } when a handler throws.profile.created event upserts a row into your users table; a campaign.sent event emits an analytics track call.klaviyo:webhook:<eventId> entries with a 7-day TTL that prevent duplicate processing.| Issue | Cause | Solution |
|---|---|---|
| Invalid signature | Wrong signing secret | Verify secret matches webhook creation response |
| Duplicate events | No idempotency | Track event IDs in Redis/DB |
| Webhook timeout | Slow processing | Return 200 immediately, process async |
| Missing events | Wrong topics subscribed | Check webhook topic subscriptions |
| Body parse error | Using JSON body parser | Must use express.raw() for signature verification |
Two worked scenarios and the local-testing loop are in references/examples.md:
profile.created / profile.updated and upsert each profile into your users table.campaign.sent and forward each send to your analytics pipeline, with retries short-circuited by the idempotency layer.Minimal local-testing loop:
npm run dev # start your app on localhost:3000
ngrok http 3000 # expose it publicly
# register the ngrok URL as the webhook endpoint in Klaviyo,
# trigger an event, and watch your logs
klaviyo-performance-tuning skill.