From klaviyo-pack
Deploys Klaviyo-powered apps to Vercel, Fly.io, and Cloud Run with secrets management, platform configs, webhook handlers, and health checks.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin klaviyo-packThis skill is limited to using the following tools:
Deploy Klaviyo-powered applications to Vercel, Fly.io, and Google Cloud Run with proper secrets management and health checks.
Executes Klaviyo production checklist for deploying integrations: verifies auth/secrets, API calls with klaviyo-api SDK, error resilience, webhook security, monitoring, and health checks.
Deploys Instantly.ai webhook receivers and API integrations to Vercel serverless, Google Cloud Run containers, or Fly.io for production HTTPS endpoints.
Deploys Customer.io integrations to GCP Cloud Run, Vercel, AWS Lambda, and Kubernetes with secrets management, health checks, and GitHub Actions pipelines.
Share bugs, ideas, or general feedback.
Deploy Klaviyo-powered applications to Vercel, Fly.io, and Google Cloud Run with proper secrets management and health checks.
pk_*)vercel, fly, or gcloud)klaviyo-api SDKklaviyo-prod-checklist completed# 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'
// 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.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
# 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)"
// 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 } },
};
}
}
| Issue | Cause | Solution |
|---|---|---|
| Secret not found at runtime | Missing env config | Verify secret binding in platform |
| Cold start timeout | Klaviyo API slow on first call | Set min_instances=1 |
| Webhook 401 | Wrong signing secret | Verify secret matches Klaviyo dashboard |
| Health check fails | Wrong API key per env | Separate keys for staging/prod |
For webhook handling, see klaviyo-webhooks-events.