Klaviyo SDK Patterns

SkillDev tools

'Apply production-ready Klaviyo SDK patterns for the klaviyo-api package.

Use Klaviyo SDK Patterns in Claude, ChatGPT or Ahel Desktop

Free. Sign in, add Klaviyo SDK Patterns and connect your AI. About a minute.

Also: Claude Code · Cursor · Codex

Then ask your AI: use the Klaviyo SDK Patterns skill

Details

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

Add Ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Klaviyo SDK PatternsStart free

What this skill tells your AI

The instructions your AI receives, as published by jeremylongshore/tons-of-skills-marketplace in skills/.curated/klaviyo-sdk-patterns/SKILL.md and read by Ahel’s review.

Overview

Production-ready patterns for the klaviyo-api Node.js SDK: singleton sessions, type-safe wrappers, retry logic, cursor pagination, and multi-tenant support. Read the target project's Klaviyo files, then Write or Edit the src/klaviyo/ modules below into place so every call goes through one consistent, retry-aware layer instead of ad-hoc new ApiKeySession(...) calls scattered across the codebase.

The six patterns are summarized here with the essential skeleton; the full, copy-paste implementation for all of them lives in references/implementation.md, and combined worked examples with expected output are in references/examples.md.

Prerequisites

  • klaviyo-api package installed in the target project.
  • The klaviyo-install-auth setup completed, so KLAVIYO_PRIVATE_KEY is available in the environment.
  • A TypeScript project with strict mode enabled — every pattern is typed.

Instructions

Step 1: Singleton session (the foundation)

Create one lazily-initialized ApiKeySession and reuse it everywhere. Read the key from the environment, fail fast if it is missing, and expose a reset hook for tests.

// src/klaviyo/session.ts
import { ApiKeySession } from 'klaviyo-api';

let _session: ApiKeySession | null = null;

export function getSession(apiKey?: string): ApiKeySession {
  if (!_session) {
    const key = apiKey || process.env.KLAVIYO_PRIVATE_KEY;
    if (!key) throw new Error('KLAVIYO_PRIVATE_KEY is required');
    _session = new ApiKeySession(key);
  }
  return _session;
}
export function resetSession(): void { _session = null; }

Steps 2-6: the rest of the layer

Each builds on the session singleton. Write the corresponding file from references/implementation.md:

  • Step 2 — Type-safe API wrapper (api.ts): lazy getters for all 11 API clients (Profiles, Events, Lists, …) so unused clients are never constructed.
  • Step 3 — Error wrapper (errors.ts): parseKlaviyoError normalizes the raw error and safeCall returns { data, error } instead of throwing.
  • Step 4 — Retry (retry.ts): withRetry retries only on 429/5xx, honoring Klaviyo's Retry-After header, else exponential backoff with jitter.
  • Step 5 — Pagination (pagination.ts): paginate turns any cursor-based list endpoint into an AsyncGenerator, extracting page[cursor] for you.
  • Step 6 — Multi-tenant factory (multi-tenant.ts): getApisForTenant caches one client set per tenant id, isolating each customer's API key.

Output

Applying this skill produces a src/klaviyo/ module set:

FileExportsPurpose
session.tsgetSession, resetSessionOne shared authenticated session
api.tsdefault apisLazy, type-safe access to every API client
errors.tsparseKlaviyoError, safeCallNon-throwing typed error results
retry.tswithRetryRate-limit/5xx retry honoring Retry-After
pagination.tspaginateAsync iteration over cursor pages
multi-tenant.tsgetApisForTenantPer-tenant client isolation

Callers then read as const { data, error } = await safeCall(() => apis.profiles.getProfiles(...)) instead of managing sessions and try/catch by hand.

SDK Conventions

ConventionExample
Property casingfirstName (not first_name)
Response accessresponse.body.data (not response.data)
Payload structure{ data: { type: 'profile', attributes: { ... } } }
Filter syntaxequals(email,"user@example.com")
Sort syntax'-datetime' (descending), 'datetime' (ascending)
Include relations{ include: ['lists'] }

Error Handling

ErrorStatusRetryableSolution
Invalid API key401NoCheck KLAVIYO_PRIVATE_KEY
Missing scope403NoAdd required scope to API key
Validation error400NoFix request payload
Rate limited429YesHonor Retry-After header
Server error500/503YesRetry with backoff
Conflict409NoResource already exists; use update

Examples

A quick taste — wrap any call so a failure returns a typed error instead of throwing:

import apis from './klaviyo/api';
import { safeCall } from './klaviyo/errors';

const { data, error } = await safeCall(
  () => apis.profiles.getProfiles({ pageSize: 20 }),
  'list profiles',
);
if (error) console.error(`Failed (${error.status}):`, error.errors[0].detail);
else console.log(`Fetched ${data!.body.data.length} profiles`);

Full worked examples — retrying a rate-limited write, paginating every profile, and serving two tenants from one process, each with expected output — are in references/examples.md.

Resources

Next Steps

Once the src/klaviyo/ layer is in place, apply the patterns in klaviyo-core-workflow-a for profile and list management — those workflows assume apis, safeCall, withRetry, and paginate already exist.

Signals

GitHub stars
3k
Forks
415
Last commit
Oct 2026
Advanced
Item type
skill
Key
klaviyo-sdk-patterns
Source
github.com/jeremylongshore/tons-of-skills-marketplace