Claude-code-plugins klaviyo-deploy-integration

install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/klaviyo-pack/skills/klaviyo-deploy-integration" ~/.claude/skills/jeremylongshore-claude-code-plugins-klaviyo-deploy-integration && rm -rf "$T"
manifest: plugins/saas-packs/klaviyo-pack/skills/klaviyo-deploy-integration/SKILL.md
source content

Klaviyo Deploy Integration

Overview

Deploy Klaviyo-powered applications to Vercel, Fly.io, and Google Cloud Run with proper secrets management and health checks.

Prerequisites

  • Klaviyo production API key (
    pk_*
    )
  • Platform CLI installed (
    vercel
    ,
    fly
    , or
    gcloud
    )
  • Application tested with
    klaviyo-api
    SDK
  • klaviyo-prod-checklist
    completed

Instructions

Vercel Deployment

# 1. Add secrets to Vercel project
vercel env add KLAVIYO_PRIVATE_KEY production
# Paste your pk_*** key when prompted

vercel env add KLAVIYO_WEBHOOK_SIGNING_SECRET production
# Paste your whsec_*** secret

# 2. Configure vercel.json
{
  "env": {
    "KLAVIYO_PRIVATE_KEY": "@klaviyo_private_key"
  },
  "functions": {
    "api/**/*.ts": {
      "maxDuration": 30
    }
  },
  "rewrites": [
    { "source": "/webhooks/klaviyo", "destination": "/api/webhooks/klaviyo" }
  ]
}
# 3. Deploy
vercel --prod

# 4. Verify health
curl -s https://your-app.vercel.app/api/health | jq '.services.klaviyo'

Vercel Webhook Handler (Edge-compatible)

// api/webhooks/klaviyo.ts (Vercel serverless function)
import crypto from 'crypto';

export const config = { api: { bodyParser: false } };

export default async function handler(req: any, res: any) {
  if (req.method !== 'POST') return res.status(405).end();

  const chunks: Buffer[] = [];
  for await (const chunk of req) chunks.push(chunk);
  const body = Buffer.concat(chunks);

  // Verify HMAC-SHA256 signature
  const signature = req.headers['klaviyo-webhook-signature'];
  const expected = crypto
    .createHmac('sha256', process.env.KLAVIYO_WEBHOOK_SIGNING_SECRET!)
    .update(body)
    .digest('base64');

  if (!crypto.timingSafeEqual(Buffer.from(signature || ''), Buffer.from(expected))) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const event = JSON.parse(body.toString());
  // Process event...
  console.log('Klaviyo webhook:', event.type);

  res.status(200).json({ received: true });
}

Fly.io Deployment

# fly.toml
app = "my-klaviyo-app"
primary_region = "iad"

[env]
  NODE_ENV = "production"

[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = "stop"
  auto_start_machines = true
  min_machines_running = 1

[[services.http_checks]]
  interval = 30000
  timeout = 5000
  path = "/health"
  method = "GET"
# 1. Set secrets
fly secrets set KLAVIYO_PRIVATE_KEY=pk_***
fly secrets set KLAVIYO_WEBHOOK_SIGNING_SECRET=whsec_***

# 2. Deploy
fly deploy

# 3. Verify
fly status
curl -s https://my-klaviyo-app.fly.dev/health | jq

Google Cloud Run Deployment

# Dockerfile
FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json .
EXPOSE 3000
CMD ["node", "dist/index.js"]
# 1. Store secret in GCP Secret Manager
echo -n "pk_***" | gcloud secrets create klaviyo-private-key --data-file=-
echo -n "whsec_***" | gcloud secrets create klaviyo-webhook-secret --data-file=-

# 2. Grant Cloud Run access to secrets
gcloud secrets add-iam-policy-binding klaviyo-private-key \
  --member="serviceAccount:YOUR_SA@PROJECT.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

# 3. Deploy to Cloud Run
gcloud run deploy klaviyo-service \
  --source . \
  --region us-central1 \
  --allow-unauthenticated \
  --set-secrets=KLAVIYO_PRIVATE_KEY=klaviyo-private-key:latest,KLAVIYO_WEBHOOK_SIGNING_SECRET=klaviyo-webhook-secret:latest \
  --min-instances=1 \
  --max-instances=10

# 4. Verify
gcloud run services describe klaviyo-service --region=us-central1 --format="value(status.url)"

Universal Health Check

// src/health.ts -- works on all platforms
import { ApiKeySession, AccountsApi } from 'klaviyo-api';

export async function healthCheck(): Promise<{
  status: string;
  services: { klaviyo: { connected: boolean; latencyMs: number } };
}> {
  const start = Date.now();
  try {
    const session = new ApiKeySession(process.env.KLAVIYO_PRIVATE_KEY!);
    const api = new AccountsApi(session);
    await api.getAccounts();
    return {
      status: 'healthy',
      services: { klaviyo: { connected: true, latencyMs: Date.now() - start } },
    };
  } catch {
    return {
      status: 'degraded',
      services: { klaviyo: { connected: false, latencyMs: Date.now() - start } },
    };
  }
}

Output

  • Application deployed with Klaviyo secrets configured
  • Health check endpoint verifying Klaviyo connectivity
  • Webhook endpoint with HMAC signature verification
  • Platform-specific best practices applied

Error Handling

IssueCauseSolution
Secret not found at runtimeMissing env configVerify secret binding in platform
Cold start timeoutKlaviyo API slow on first callSet
min_instances=1
Webhook 401Wrong signing secretVerify secret matches Klaviyo dashboard
Health check failsWrong API key per envSeparate keys for staging/prod

Resources

Next Steps

For webhook handling, see

klaviyo-webhooks-events
.