klaviyo-common-errors
'Diagnose and fix common Klaviyo API errors and exceptions.
Allowed Tools
Provided by Plugin
klaviyo-pack
Claude Code skill pack for Klaviyo (24 skills)
Installation
This skill is included in the klaviyo-pack plugin:
/plugin install klaviyo-pack@claude-code-plugins-plus
Click to copy
Instructions
Klaviyo Common Errors
Overview
Quick reference for the most common Klaviyo API errors with real error payloads,
root causes, and solutions. Because Klaviyo returns JSON:API errors (a status
code plus a structured errors[] array), this skill walks you from a raw
exception to a targeted fix: extract the status code, match it against the
catalog, apply the documented remedy.
The full per-status-code catalog and the SDK-level failure table live in
references/ to keep this workflow scannable — drill in once you know which
status code you are chasing.
Prerequisites
klaviyo-apiSDK installed (npm install klaviyo-api— note: not@klaviyo/sdk)- A private API key (
pk*) exported asKLAVIYOPRIVATE_KEY - Access to the application logs where the failed request was recorded, so you
can Read the stack trace and Grep for the status code and error code
Instructions
Step 1: Identify the Error
Extract the status code and error detail from the caught exception. Read the
log line or wrap the call so the structured payload is visible:
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 }
}
If you only have raw logs, Grep for the status code (grep -E "40[0-9]|429|50[0-9]")
and the code field to isolate the failing request.
Step 2: Match and Fix
Map the status code to its root cause and remedy. Each row links into the full
catalog, which carries the actual response payload and the fix code block:
| Status | Meaning | Most common root cause |
|---|---|---|
| 400 | Bad Request | Missing field, non-E.164 phone, or snake_case instead of camelCase |
| 401 | Unauthorized | Missing KLAVIYOPRIVATEKEY, or a public key used as a private key |
| 403 | Forbidden | API key lacks the required scope (e.g. profiles:write) |
| 404 | Not Found | Wrong resource ID or a dead /api/v2/ path |
| 409 | Conflict | Duplicate — use createOrUpdateProfile upsert |
| 429 | Rate Limited | Exceeded burst (75/s) or steady (700/min); honor Retry-After |
| 500/503 | Server Error | Klaviyo-side — check status page, retry with backoff |
The most common one, 400, is almost always a casing mismatch (the SDK expects
camelCase):
// Wrong: snake_case // Right: camelCase (SDK convention)
{ first_name: 'Jane' } { firstName: 'Jane' }
See the full error catalog for every status
code's real payload, complete cause list, and fix. For client-side failures that
never reach the network (wrong import, response.data vs response.body.data,
bad filter syntax) plus copy-paste diagnostic commands, see
Output
Working through this skill produces a diagnosis and a fix, not a generated
artifact:
- The status code and error
codeidentifying the failure class - The root cause matched from the catalog
- A concrete code or config change (casing fix, scope grant, upsert, backoff)
- For 5xx: confirmation of whether the fault is Klaviyo-side (status page) or yours
Error Handling
- Status code is missing from the exception — the failure is client-side, not
an API response. Check the SDK-level errors table in
diagnostics (module-not-found, wrong constructor).
- 401 persists after setting the key — you are using a public key. Verify with
echo $KLAVIYOPRIVATEKEY | head -c 3 (must print pk_).
- 429 with no
RateLimit-Remainingheader — expected. On a 429 Klaviyo returns
only Retry-After; do not depend on the reset headers, honor Retry-After.
- Fix does not resolve the error — collect evidence with
klaviyo-debug-bundle,
check status.klaviyo.com, then open a support
ticket with the request IDs from the error responses.
Examples
Example — 403 permission_denied on profile create. The exception shows
status: 403, detail: "...required scope: profiles:write". Match to the 403 row:
the key lacks a scope. Fix: mint a new key with profiles:write at
Settings > API Keys. Full payload and the endpoint→scope table are in
the error catalog under the 403 section.
Example — intermittent 429 under load. Requests fail once traffic exceeds
700/min. Honor the Retry-After header and back off instead of tight-retrying:
if (error.status === 429) {
const retryAfter = parseInt(error.headers?.['retry-after'] || '10'); // seconds
await new Promise(r => setTimeout(r, retryAfter * 1000));
// then retry
}
More worked cases (400 casing, 404 stale ID, 409 upsert) are in
Resources
- Full error catalog — per-status-code payloads and fixes
- Diagnostics & SDK errors — client-side failures, diagnostic commands, escalation
- Rate Limits & Error Handling
- API Error Alerts
- Klaviyo Status Page
- For evidence collection see the
klaviyo-debug-bundleskill