Claude-code-plugins-plus-skills klaviyo-hello-world
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-hello-world" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-klaviyo-hello-world && rm -rf "$T"
manifest:
plugins/saas-packs/klaviyo-pack/skills/klaviyo-hello-world/SKILL.mdsource content
Klaviyo Hello World
Overview
Minimal working example: create a profile, track an event, and query the result using the
klaviyo-api Node.js SDK against a.klaviyo.com/api/*.
Prerequisites
- Completed
setupklaviyo-install-auth
set in environmentKLAVIYO_PRIVATE_KEY
package installedklaviyo-api
Instructions
Step 1: Create a Profile
// hello-klaviyo.ts import { ApiKeySession, ProfilesApi, EventsApi, ProfileCreateQuery, ProfileEnum, EventCreateQueryV2, EventEnum, } from 'klaviyo-api'; const session = new ApiKeySession(process.env.KLAVIYO_PRIVATE_KEY!); const profilesApi = new ProfilesApi(session); const eventsApi = new EventsApi(session); // Create or update a profile // NOTE: SDK uses camelCase (firstName, not first_name) const profilePayload: ProfileCreateQuery = { data: { type: ProfileEnum.Profile, attributes: { email: 'hello@example.com', firstName: 'Hello', lastName: 'World', properties: { source: 'hello-world-script', signupDate: new Date().toISOString(), }, }, }, }; const profile = await profilesApi.createProfile(profilePayload); console.log('Profile created:', profile.body.data.id);
Step 2: Track an Event
// Track a custom event tied to the profile const eventPayload: EventCreateQueryV2 = { data: { type: EventEnum.Event, attributes: { // The metric name -- creates the metric if it doesn't exist metric: { data: { type: 'metric', attributes: { name: 'Hello World Test', }, }, }, // Link to the profile by email profile: { data: { type: ProfileEnum.Profile, attributes: { email: 'hello@example.com', }, }, }, properties: { message: 'First event from API!', timestamp: new Date().toISOString(), }, time: new Date().toISOString(), value: 0, }, }, }; await eventsApi.createEvent(eventPayload); console.log('Event tracked: Hello World Test');
Step 3: Retrieve the Profile
// Fetch profiles filtered by email const profiles = await profilesApi.getProfiles({ filter: 'equals(email,"hello@example.com")', }); const p = profiles.body.data[0]; console.log(`Found: ${p.attributes.firstName} ${p.attributes.lastName}`); console.log(`ID: ${p.id}`); console.log(`Created: ${p.attributes.created}`);
Step 4: Complete Script
// hello-klaviyo.ts -- full runnable script import { ApiKeySession, ProfilesApi, EventsApi, ProfileEnum, } from 'klaviyo-api'; async function main() { const session = new ApiKeySession(process.env.KLAVIYO_PRIVATE_KEY!); const profilesApi = new ProfilesApi(session); const eventsApi = new EventsApi(session); // 1. Create profile const profile = await profilesApi.createProfile({ data: { type: ProfileEnum.Profile, attributes: { email: 'hello@example.com', firstName: 'Hello', lastName: 'World', }, }, }); console.log(`Profile created: ${profile.body.data.id}`); // 2. Track event await eventsApi.createEvent({ data: { type: 'event', attributes: { metric: { data: { type: 'metric', attributes: { name: 'Hello World Test' } } }, profile: { data: { type: 'profile', attributes: { email: 'hello@example.com' } } }, properties: { source: 'hello-world' }, time: new Date().toISOString(), }, }, }); console.log('Event tracked successfully'); // 3. Query profile back const result = await profilesApi.getProfiles({ filter: 'equals(email,"hello@example.com")', }); console.log(`Verified: ${result.body.data[0]?.attributes.firstName}`); } main().catch(console.error);
Run it:
npx tsx hello-klaviyo.ts
Output
Profile created: 01JXXXXXXXXXXXXXXXXXXXXXX Event tracked successfully Verified: Hello
Error Handling
| Error | Status | Cause | Solution |
|---|---|---|---|
| 409 | Email already exists | Use instead |
| 400 | Malformed email | Validate email before sending |
| 400 | Empty metric object | Always include |
| 401 | Bad API key | Check env var |
Key SDK Conventions
- camelCase properties: The SDK uses
,firstName
,phoneNumber
(not snake_case)lastName - JSON:API format: All payloads use
structure{ data: { type, attributes } } - Response body: Access via
(notresponse.body.data
)response.data - Profile identifiers: Use
,email
, orphoneNumber
to identify profilesexternalId
Resources
Next Steps
Proceed to
klaviyo-local-dev-loop for development workflow setup, or klaviyo-core-workflow-a for profile and list management.