界面已本地化;技能介绍与说明文档按所选语言由 AI 自动翻译,代码、命令、路径和专业术语保留原文,以原作者文档为准。
探索技能
开发与工程 · SKILL.md

klaviyo-webhooks-events

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 快照 · 自动分类 · 以原作者文档为准

技能说明

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:

  • saas
  • klaviyo
  • email-marketing
  • cdp compatibility: Designed for Claude Code

Klaviyo Webhooks & Events

Overview

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.

Prerequisites

  • Klaviyo account with webhooks enabled
  • HTTPS endpoint accessible from internet
  • API key with scopes: webhooks:read, webhooks:write
  • Redis or database for idempotency (recommended)

Klaviyo Webhook Architecture

Klaviyo 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 CategoryExample Topics
Profileprofile.created, profile.updated, profile.deleted
Listlist.member.added, list.member.removed
Segmentsegment.member.added, segment.member.removed
Campaigncampaign.sent, campaign.delivered
Flowflow.triggered, flow.message.sent
EventCustom metric events

Instructions

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.

  1. Create a webhook subscription — call webhooksApi.createWebhook with the target endpointUrl and webhookTopics, then save the signing secret from the response as KLAVIYO_WEBHOOK_SIGNING_SECRET.
  2. Verify the signature — recompute the HMAC-SHA256 over the raw request body and compare with a timing-safe check (skeleton below).
  3. Receive events — mount an Express route with express.raw({ type: 'application/json' }) so the raw body survives for verification; reject on a bad signature, then parse.
  4. Route by topic — dispatch event.type to a per-topic handler map (profile.created, campaign.sent, ...).
  5. Deduplicate — record each processed event ID in Redis with a TTL so Klaviyo retries are short-circuited.
  6. Manage subscriptions — list, inspect topics, and delete webhooks via the API.

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.

Output

A working integration produces:

  • A registered webhook — createWebhook returns a webhook ID and a signing secret; store the secret as KLAVIYO_WEBHOOK_SIGNING_SECRET.
  • HTTP responses from your endpoint — 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.
  • Side effects per topic — e.g. a profile.created event upserts a row into your users table; a campaign.sent event emits an analytics track call.
  • Idempotency keys in Redis — klaviyo:webhook:<eventId> entries with a 7-day TTL that prevent duplicate processing.

Error Handling

IssueCauseSolution
Invalid signatureWrong signing secretVerify secret matches webhook creation response
Duplicate eventsNo idempotencyTrack event IDs in Redis/DB
Webhook timeoutSlow processingReturn 200 immediately, process async
Missing eventsWrong topics subscribedCheck webhook topic subscriptions
Body parse errorUsing JSON body parserMust use express.raw() for signature verification

Examples

Two worked scenarios and the local-testing loop are in references/examples.md:

  • Sync new profiles into your own database — subscribe to profile.created / profile.updated and upsert each profile into your users table.
  • Track campaign sends into analytics — subscribe to 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

Resources

我的收藏