Agent Skills: Klaviyo Common Errors

|

UncategorizedID: jeremylongshore/claude-code-plugins-plus-skills/klaviyo-common-errors

Install this agent skill to your local

pnpm dlx add-skill https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/HEAD/plugins/saas-packs/klaviyo-pack/skills/klaviyo-common-errors

Skill Files

Browse the full folder contents for klaviyo-common-errors.

Download Skill

Loading file tree…

plugins/saas-packs/klaviyo-pack/skills/klaviyo-common-errors/SKILL.md

Skill Metadata

Name
klaviyo-common-errors
Description
'Diagnose and fix common Klaviyo API errors and exceptions.

Klaviyo Common Errors

Overview

Quick reference for the most common Klaviyo API errors with real error payloads, root causes, and solutions.

Prerequisites

  • klaviyo-api SDK installed
  • API credentials configured
  • Access to application logs

Instructions

Step 1: Identify the Error

Klaviyo returns JSON:API error responses. Extract the status code and error detail:

try {
  await profilesApi.createProfile(payload);
} catch (error: any) {
  console.error('Status:', error.status);
  console.error('Errors:', JSON.stringify(error.body?.errors, null, 2));
  // error.body.errors[] has: { id, code, title, detail, source }
}

Step 2: Match and Fix


400 -- Bad Request (Validation Error)

Actual Klaviyo response:

{
  "errors": [{
    "id": "abc-123",
    "code": "invalid",
    "title": "Invalid input.",
    "detail": "The email field is required.",
    "source": { "pointer": "/data/attributes/email" }
  }]
}

Common causes:

  • Missing required field (email, metric name, list name)
  • Invalid phone number format (must be E.164: +15551234567)
  • Invalid filter syntax in query params
  • Wrong type value in JSON:API payload
  • Sending snake_case instead of camelCase (SDK uses camelCase)

Fix:

// Wrong: snake_case
{ first_name: 'Jane', phone_number: '+155...' }

// Right: camelCase (SDK convention)
{ firstName: 'Jane', phoneNumber: '+15551234567' }

401 -- Unauthorized

Actual response:

{
  "errors": [{
    "code": "not_authenticated",
    "title": "Authentication credentials were not provided.",
    "detail": "Missing or invalid Authorization header."
  }]
}

Root causes:

  1. Missing KLAVIYO_PRIVATE_KEY environment variable
  2. Using a public key (6 chars) instead of private key (pk_*)
  3. API key was revoked or rotated

Fix:

# Verify key is set and starts with pk_
echo $KLAVIYO_PRIVATE_KEY | head -c 3
# Should print: pk_

# Test with cURL
curl -s -w "%{http_code}" -o /dev/null \
  -H "Authorization: Klaviyo-API-Key $KLAVIYO_PRIVATE_KEY" \
  -H "revision: 2024-10-15" \
  "https://a.klaviyo.com/api/accounts/"

403 -- Forbidden (Missing Scope)

Actual response:

{
  "errors": [{
    "code": "permission_denied",
    "title": "You do not have permission to perform this action.",
    "detail": "The API key does not have the required scope: profiles:write"
  }]
}

Fix: Generate a new API key with the required scope at Settings > API Keys > Create Private API Key.

| Endpoint | Required Scope | |----------|---------------| | POST /api/profiles/ | profiles:write | | GET /api/segments/ | segments:read | | POST /api/events/ | events:write | | POST /api/campaigns/ | campaigns:write | | POST /api/data-privacy-deletion-jobs/ | data-privacy:write |


404 -- Not Found

Typical causes:

  • Wrong resource ID (profile, list, segment, campaign)
  • Using v1/v2 URL paths instead of new API (/api/v2/ is dead, use /api/)
  • Resource was deleted

Fix:

// Verify the resource exists first
const lists = await listsApi.getLists();
const targetList = lists.body.data.find(l => l.attributes.name === 'Newsletter');
if (!targetList) throw new Error('List not found');

409 -- Conflict (Duplicate)

Actual response:

{
  "errors": [{
    "code": "duplicate",
    "title": "Conflict.",
    "detail": "A profile already exists with the email customer@example.com"
  }]
}

Fix: Use createOrUpdateProfile (upsert) instead of createProfile:

// This handles both create and update
await profilesApi.createOrUpdateProfile({
  data: {
    type: 'profile' as any,
    attributes: { email: 'customer@example.com', firstName: 'Updated' },
  },
});

429 -- Rate Limited

Headers on 429 response:

Retry-After: 10

Klaviyo rate limits (per-account, fixed window):

| Window | Limit | |--------|-------| | Burst (1 second) | 75 requests | | Steady (1 minute) | 700 requests |

Note: When rate limited, RateLimit-Remaining and RateLimit-Reset headers are NOT returned. Only Retry-After (integer seconds) is present.

Fix: Honor Retry-After header:

catch (error: any) {
  if (error.status === 429) {
    const retryAfter = parseInt(error.headers?.['retry-after'] || '10');
    console.log(`Rate limited. Waiting ${retryAfter}s...`);
    await new Promise(r => setTimeout(r, retryAfter * 1000));
    // Retry the request
  }
}

500/503 -- Klaviyo Server Error

Fix:

  1. Check Klaviyo Status Page
  2. Retry with exponential backoff (see klaviyo-rate-limits)
  3. If persistent, check Klaviyo's changelog for known issues

Common SDK-Level Errors

| Error | Cause | Fix | |-------|-------|-----| | Cannot find module 'klaviyo-api' | Wrong package | npm install klaviyo-api (not @klaviyo/sdk) | | TypeError: ... is not a constructor | Wrong import | Use new ProfilesApi(session) not new KlaviyoClient() | | response.data is undefined | Wrong access pattern | Use response.body.data (not response.data) | | filter is not valid | Bad filter syntax | Use equals(field,"value") not field = value |

Quick Diagnostic Commands

# Check Klaviyo API health
curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Klaviyo-API-Key $KLAVIYO_PRIVATE_KEY" \
  -H "revision: 2024-10-15" \
  "https://a.klaviyo.com/api/accounts/"

# Check Klaviyo status page
curl -s https://status.klaviyo.com/api/v2/status.json | python3 -m json.tool

# Verify local env
env | grep KLAVIYO
npm list klaviyo-api

Escalation Path

  1. Collect evidence with klaviyo-debug-bundle
  2. Check status.klaviyo.com
  3. Open ticket at Klaviyo Support with request IDs from error responses

Resources

Next Steps

For comprehensive debugging, see klaviyo-debug-bundle.