Claude-code-plugins-plus klaviyo-core-workflow-a
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-core-workflow-a" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-klaviyo-core-workflow-a && rm -rf "$T"
manifest:
plugins/saas-packs/klaviyo-pack/skills/klaviyo-core-workflow-a/SKILL.mdsource content
Klaviyo Core Workflow A -- Profiles, Lists & Subscriptions
Overview
Primary money-path workflow: create/update profiles, manage lists, and subscribe contacts for email and SMS marketing via the
klaviyo-api SDK.
Prerequisites
- Completed
setupklaviyo-install-auth - API key with scopes:
,profiles:read
,profiles:write
,lists:readlists:write
Instructions
Step 1: Create or Update a Profile
import { ApiKeySession, ProfilesApi, ProfileEnum } from 'klaviyo-api'; const session = new ApiKeySession(process.env.KLAVIYO_PRIVATE_KEY!); const profilesApi = new ProfilesApi(session); // Create a new profile (409 if email already exists) const newProfile = await profilesApi.createProfile({ data: { type: ProfileEnum.Profile, attributes: { email: 'customer@example.com', firstName: 'Jane', lastName: 'Doe', phoneNumber: '+15551234567', location: { city: 'Atlanta', region: 'GA', country: 'US', zip: '30309', }, properties: { plan: 'pro', signupSource: 'website', lifetime_value: 250.00, }, }, }, }); console.log('Profile ID:', newProfile.body.data.id); // Create OR update (upsert) -- preferred for syncing const upserted = await profilesApi.createOrUpdateProfile({ data: { type: ProfileEnum.Profile, attributes: { email: 'customer@example.com', firstName: 'Jane', lastName: 'Doe-Smith', // Updated last name properties: { plan: 'enterprise', // Updated plan lastLogin: new Date().toISOString(), }, }, }, }); console.log('Upserted profile:', upserted.body.data.id);
Step 2: Create a List
import { ListsApi, ListEnum } from 'klaviyo-api'; const listsApi = new ListsApi(session); // Create a new list const list = await listsApi.createList({ data: { type: ListEnum.List, attributes: { name: 'Newsletter Subscribers', }, }, }); const listId = list.body.data.id; console.log('List created:', listId); // Get all lists const allLists = await listsApi.getLists(); for (const l of allLists.body.data) { console.log(`${l.attributes.name} (${l.id})`); }
Step 3: Add Profiles to a List
// Add existing profiles to a list (does NOT change subscription status) await listsApi.createListRelationships({ id: listId, relationshipType: 'profiles' as any, body: { data: [ { type: ProfileEnum.Profile, id: 'PROFILE_ID_1' }, { type: ProfileEnum.Profile, id: 'PROFILE_ID_2' }, ], }, });
Step 4: Subscribe Profiles (Email + SMS Consent)
// Subscribe profiles to a list WITH marketing consent // This is the correct way to add subscribers (not just list members) await profilesApi.subscribeProfiles({ data: { type: 'profile-subscription-bulk-create-job', attributes: { profiles: { data: [ { type: ProfileEnum.Profile, attributes: { email: 'subscriber@example.com', phoneNumber: '+15559876543', subscriptions: { email: { marketing: { consent: 'SUBSCRIBED', consentTimestamp: new Date().toISOString(), }, }, sms: { marketing: { consent: 'SUBSCRIBED', consentTimestamp: new Date().toISOString(), }, }, }, }, }, ], }, }, relationships: { list: { data: { type: ListEnum.List, id: listId, }, }, }, }, }); console.log('Profile subscribed to email + SMS');
Step 5: Query Profiles with Filters
// Filter profiles by custom property const proUsers = await profilesApi.getProfiles({ filter: 'equals(properties.plan,"pro")', sort: '-created', // Newest first }); // Filter by date range const recentProfiles = await profilesApi.getProfiles({ filter: 'greater-than(created,2024-01-01T00:00:00Z)', }); // Filter by email domain const gmailUsers = await profilesApi.getProfiles({ filter: 'contains(email,"@gmail.com")', }); // Get profiles for a specific list const listMembers = await listsApi.getListProfiles({ id: listId }); for (const member of listMembers.body.data) { console.log(member.attributes.email); }
Step 6: Bulk Profile Import
// Batch create/update up to 100 profiles at a time const profiles = customers.map(c => ({ type: ProfileEnum.Profile as const, attributes: { email: c.email, firstName: c.firstName, lastName: c.lastName, properties: { source: 'bulk-import', importedAt: new Date().toISOString() }, }, })); // Process in batches of 100 for (let i = 0; i < profiles.length; i += 100) { const batch = profiles.slice(i, i + 100); await Promise.all( batch.map(p => profilesApi.createOrUpdateProfile({ data: p })) ); console.log(`Imported ${Math.min(i + 100, profiles.length)}/${profiles.length}`); }
Output
- Profiles created/updated in Klaviyo
- Lists created and populated
- Subscribers opted in with consent timestamps
- Queryable customer data for segmentation
Error Handling
| Error | Status | Cause | Solution |
|---|---|---|---|
| Duplicate profile | 409 | Email exists | Use (upsert) |
| Invalid phone | 400 | Wrong format | Use E.164 format: |
| List not found | 404 | Wrong list ID | Verify list ID via |
| Missing consent | 400 | No consent timestamp | Always include |
| Rate limited | 429 | >75 req/s burst | See |
Resources
Next Steps
For event tracking and campaign triggers, see
klaviyo-core-workflow-b.