klaviyo-enterprise-rbac

Configure Klaviyo enterprise access control with API key scopes and OAuth. Use when implementing per-key scoping, configuring OAuth app authorization, or setting up organization-level access controls for Klaviyo. Trigger with phrases like "klaviyo scopes", "klaviyo RBAC", "klaviyo enterprise", "klaviyo permissions", "klaviyo OAuth", "klaviyo access control".

1,868 stars

Best use case

klaviyo-enterprise-rbac is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Configure Klaviyo enterprise access control with API key scopes and OAuth. Use when implementing per-key scoping, configuring OAuth app authorization, or setting up organization-level access controls for Klaviyo. Trigger with phrases like "klaviyo scopes", "klaviyo RBAC", "klaviyo enterprise", "klaviyo permissions", "klaviyo OAuth", "klaviyo access control".

Teams using klaviyo-enterprise-rbac should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/klaviyo-enterprise-rbac/SKILL.md --create-dirs "https://raw.githubusercontent.com/jeremylongshore/claude-code-plugins-plus-skills/main/plugins/saas-packs/klaviyo-pack/skills/klaviyo-enterprise-rbac/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/klaviyo-enterprise-rbac/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How klaviyo-enterprise-rbac Compares

Feature / Agentklaviyo-enterprise-rbacStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Configure Klaviyo enterprise access control with API key scopes and OAuth. Use when implementing per-key scoping, configuring OAuth app authorization, or setting up organization-level access controls for Klaviyo. Trigger with phrases like "klaviyo scopes", "klaviyo RBAC", "klaviyo enterprise", "klaviyo permissions", "klaviyo OAuth", "klaviyo access control".

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# Klaviyo Enterprise RBAC

## Overview

Enterprise access control for Klaviyo: API key scoping with granular read/write permissions, OAuth app authorization flows, and application-level RBAC built on top of Klaviyo's scope system.

## Prerequisites

- Klaviyo account with API key management access
- Understanding of OAuth 2.0 (for OAuth apps)
- Application requiring per-user or per-role Klaviyo access

## Klaviyo Access Control Model

Klaviyo uses **scoped API keys** and **OAuth** for access control. There are no built-in "roles" in Klaviyo's API -- you implement RBAC by creating multiple API keys with different scopes.

### API Key Scopes

| Scope | Read | Write | What It Controls |
|-------|------|-------|-----------------|
| `accounts` | Account info | N/A | Organization name, timezone |
| `campaigns` | List campaigns | Create/send campaigns | Email, SMS, push campaigns |
| `catalogs` | Browse items | CRUD catalog items | Product catalog management |
| `coupons` | List coupons | Create coupons | Coupon/discount codes |
| `data-privacy` | N/A | Delete profiles | GDPR/CCPA deletion requests |
| `events` | Query events | Track events | Server-side event tracking |
| `flows` | List flows | Create/update flows | Flow automation |
| `images` | List images | Upload images | Email template images |
| `lists` | List lists | CRUD lists/members | List management |
| `metrics` | Query metrics | N/A | Metric aggregations |
| `profiles` | Read profiles | Create/update profiles | Profile management |
| `segments` | Read segments | N/A | Segment queries |
| `tags` | Read tags | CRUD tags | Resource tagging |
| `templates` | Read templates | Create/update templates | Email templates |
| `webhooks` | List webhooks | CRUD webhooks | Webhook subscriptions |

## Instructions

### Step 1: Create Scoped API Keys

Create separate API keys per service/role in Klaviyo dashboard (**Settings > API Keys**):

```typescript
// Example: different keys for different services

// Profile Sync Service -- only needs profiles + lists
// Key scopes: profiles:read, profiles:write, lists:read, lists:write
const profileSyncSession = new ApiKeySession(process.env.KLAVIYO_KEY_PROFILE_SYNC!);

// Event Tracking Service -- only needs events + profiles
// Key scopes: events:write, profiles:read, profiles:write
const eventTrackingSession = new ApiKeySession(process.env.KLAVIYO_KEY_EVENT_TRACKER!);

// Reporting Dashboard -- read-only
// Key scopes: campaigns:read, metrics:read, segments:read, profiles:read
const reportingSession = new ApiKeySession(process.env.KLAVIYO_KEY_REPORTING!);

// Admin Service -- full access (use sparingly)
// Key scopes: all scopes
const adminSession = new ApiKeySession(process.env.KLAVIYO_KEY_ADMIN!);
```

### Step 2: Application-Level RBAC

```typescript
// src/klaviyo/rbac.ts

enum AppRole {
  Admin = 'admin',
  Marketer = 'marketer',
  Developer = 'developer',
  Viewer = 'viewer',
  Service = 'service',
}

interface KlaviyoPermissions {
  canReadProfiles: boolean;
  canWriteProfiles: boolean;
  canDeleteProfiles: boolean;
  canSendCampaigns: boolean;
  canManageLists: boolean;
  canTrackEvents: boolean;
  canViewReports: boolean;
  canManageWebhooks: boolean;
}

const ROLE_PERMISSIONS: Record<AppRole, KlaviyoPermissions> = {
  admin: {
    canReadProfiles: true, canWriteProfiles: true, canDeleteProfiles: true,
    canSendCampaigns: true, canManageLists: true, canTrackEvents: true,
    canViewReports: true, canManageWebhooks: true,
  },
  marketer: {
    canReadProfiles: true, canWriteProfiles: false, canDeleteProfiles: false,
    canSendCampaigns: true, canManageLists: true, canTrackEvents: false,
    canViewReports: true, canManageWebhooks: false,
  },
  developer: {
    canReadProfiles: true, canWriteProfiles: true, canDeleteProfiles: false,
    canSendCampaigns: false, canManageLists: true, canTrackEvents: true,
    canViewReports: true, canManageWebhooks: true,
  },
  viewer: {
    canReadProfiles: true, canWriteProfiles: false, canDeleteProfiles: false,
    canSendCampaigns: false, canManageLists: false, canTrackEvents: false,
    canViewReports: true, canManageWebhooks: false,
  },
  service: {
    canReadProfiles: true, canWriteProfiles: true, canDeleteProfiles: false,
    canSendCampaigns: false, canManageLists: false, canTrackEvents: true,
    canViewReports: false, canManageWebhooks: false,
  },
};

export function checkPermission(role: AppRole, permission: keyof KlaviyoPermissions): boolean {
  return ROLE_PERMISSIONS[role][permission];
}

// Map roles to API keys with appropriate scopes
const ROLE_API_KEYS: Record<AppRole, string> = {
  admin: process.env.KLAVIYO_KEY_ADMIN!,
  marketer: process.env.KLAVIYO_KEY_MARKETER!,
  developer: process.env.KLAVIYO_KEY_DEVELOPER!,
  viewer: process.env.KLAVIYO_KEY_VIEWER!,
  service: process.env.KLAVIYO_KEY_SERVICE!,
};

export function getSessionForRole(role: AppRole): ApiKeySession {
  const key = ROLE_API_KEYS[role];
  if (!key) throw new Error(`No API key configured for role: ${role}`);
  return new ApiKeySession(key);
}
```

### Step 3: Permission Middleware

```typescript
// src/middleware/klaviyo-auth.ts
import { checkPermission, AppRole, KlaviyoPermissions } from '../klaviyo/rbac';

export function requireKlaviyoPermission(permission: keyof KlaviyoPermissions) {
  return (req: any, res: any, next: any) => {
    const userRole = req.user?.klaviyoRole as AppRole;
    if (!userRole) return res.status(401).json({ error: 'No Klaviyo role assigned' });

    if (!checkPermission(userRole, permission)) {
      return res.status(403).json({
        error: 'Forbidden',
        message: `Role '${userRole}' does not have permission: ${permission}`,
      });
    }

    next();
  };
}

// Usage in routes
app.get('/api/klaviyo/profiles',
  requireKlaviyoPermission('canReadProfiles'),
  profilesHandler
);

app.post('/api/klaviyo/campaigns/send',
  requireKlaviyoPermission('canSendCampaigns'),
  campaignSendHandler
);

app.delete('/api/klaviyo/profiles/:id',
  requireKlaviyoPermission('canDeleteProfiles'),
  profileDeleteHandler
);
```

### Step 4: OAuth App Flow (for third-party integrations)

```typescript
// OAuth flow for Klaviyo apps (marketplace integrations)
// Reference: https://developers.klaviyo.com/en/docs/set_up_oauth

const OAUTH_CONFIG = {
  clientId: process.env.KLAVIYO_OAUTH_CLIENT_ID!,
  clientSecret: process.env.KLAVIYO_OAUTH_CLIENT_SECRET!,
  redirectUri: 'https://your-app.com/auth/klaviyo/callback',
  authorizationUrl: 'https://www.klaviyo.com/oauth/authorize',
  tokenUrl: 'https://a.klaviyo.com/oauth/token',
  // Only request scopes your app needs
  scopes: ['profiles:read', 'profiles:write', 'events:write', 'lists:read'],
};

// Step 1: Redirect user to Klaviyo authorization
function getAuthorizationUrl(state: string): string {
  const params = new URLSearchParams({
    response_type: 'code',
    client_id: OAUTH_CONFIG.clientId,
    redirect_uri: OAUTH_CONFIG.redirectUri,
    scope: OAUTH_CONFIG.scopes.join(' '),
    state,
  });
  return `${OAUTH_CONFIG.authorizationUrl}?${params}`;
}

// Step 2: Exchange code for access token
async function exchangeCodeForToken(code: string): Promise<{
  accessToken: string;
  refreshToken: string;
  expiresIn: number;
}> {
  const response = await fetch(OAUTH_CONFIG.tokenUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code,
      client_id: OAUTH_CONFIG.clientId,
      client_secret: OAUTH_CONFIG.clientSecret,
      redirect_uri: OAUTH_CONFIG.redirectUri,
    }),
  });

  const data = await response.json();
  return {
    accessToken: data.access_token,
    refreshToken: data.refresh_token,
    expiresIn: data.expires_in,
  };
}
```

### Step 5: Audit Trail

```typescript
// src/klaviyo/audit.ts

interface KlaviyoAuditEntry {
  timestamp: Date;
  userId: string;
  role: AppRole;
  action: string;
  resource: string;
  success: boolean;
  klaviyoEndpoint: string;
  ipAddress?: string;
}

async function logKlaviyoAccess(entry: KlaviyoAuditEntry): Promise<void> {
  // Store in audit database
  await db.auditLog.create({ data: entry });

  // Alert on suspicious activity
  if (entry.action === 'DELETE' && entry.resource.includes('profile')) {
    await alertSecurityTeam(`Profile deletion by ${entry.userId} (${entry.role})`);
  }
}
```

## Environment Variable Layout

```bash
# Per-role API keys (create in Klaviyo dashboard with specific scopes)
KLAVIYO_KEY_ADMIN=pk_admin_***         # All scopes
KLAVIYO_KEY_MARKETER=pk_marketer_***   # campaigns:*, lists:*, profiles:read, segments:read
KLAVIYO_KEY_DEVELOPER=pk_dev_***       # profiles:*, events:*, lists:*, webhooks:*, templates:*
KLAVIYO_KEY_VIEWER=pk_viewer_***       # *:read only
KLAVIYO_KEY_SERVICE=pk_service_***     # events:write, profiles:read/write

# OAuth (for marketplace apps)
KLAVIYO_OAUTH_CLIENT_ID=your_client_id
KLAVIYO_OAUTH_CLIENT_SECRET=your_client_secret
```

## Error Handling

| Error | Status | Cause | Solution |
|-------|--------|-------|----------|
| `permission_denied` | 403 | API key missing required scope | Create new key with correct scopes |
| OAuth code expired | 400 | User took too long to authorize | Retry authorization flow |
| Token refresh failed | 401 | Refresh token revoked | Re-authorize the app |
| Role not assigned | 401 | User missing `klaviyoRole` | Assign role in your user management |

## Resources

- [Klaviyo API Scopes](https://developers.klaviyo.com/en/docs/authenticate_)
- [OAuth Setup Guide](https://developers.klaviyo.com/en/docs/set_up_oauth)
- [Update OAuth Scopes](https://developers.klaviyo.com/en/docs/update_your_oauth_scopes)

## Next Steps

For major migrations, see `klaviyo-migration-deep-dive`.

Related Skills

windsurf-enterprise-rbac

1868
from jeremylongshore/claude-code-plugins-plus-skills

Configure Windsurf enterprise SSO, RBAC, and organization-level controls. Use when implementing SSO/SAML, configuring role-based seat management, or setting up organization-wide Windsurf policies. Trigger with phrases like "windsurf SSO", "windsurf RBAC", "windsurf enterprise", "windsurf admin", "windsurf SAML", "windsurf team management".

webflow-enterprise-rbac

1868
from jeremylongshore/claude-code-plugins-plus-skills

Configure Webflow enterprise access control — OAuth 2.0 app authorization, scope-based RBAC, per-site token isolation, workspace member management, and audit logging for compliance. Trigger with phrases like "webflow RBAC", "webflow enterprise", "webflow roles", "webflow permissions", "webflow OAuth scopes", "webflow access control", "webflow workspace members".

vercel-enterprise-rbac

1868
from jeremylongshore/claude-code-plugins-plus-skills

Configure Vercel enterprise RBAC, access groups, SSO integration, and audit logging. Use when implementing team access control, configuring SAML SSO, or setting up role-based permissions for Vercel projects. Trigger with phrases like "vercel SSO", "vercel RBAC", "vercel enterprise", "vercel roles", "vercel permissions", "vercel access groups".

veeva-enterprise-rbac

1868
from jeremylongshore/claude-code-plugins-plus-skills

Veeva Vault enterprise rbac for enterprise operations. Use when implementing advanced Veeva Vault patterns. Trigger: "veeva enterprise rbac".

vastai-enterprise-rbac

1868
from jeremylongshore/claude-code-plugins-plus-skills

Implement team access control and spending governance for Vast.ai GPU cloud. Use when managing multi-team GPU access, implementing spending controls, or setting up API key separation for different teams. Trigger with phrases like "vastai team access", "vastai RBAC", "vastai enterprise", "vastai spending controls", "vastai permissions".

twinmind-enterprise-rbac

1868
from jeremylongshore/claude-code-plugins-plus-skills

Configure TwinMind Enterprise with on-premise deployment, custom AI models, SSO integration, and team-wide transcript sharing. Use when implementing enterprise rbac, or managing TwinMind meeting AI operations. Trigger with phrases like "twinmind enterprise rbac", "twinmind enterprise rbac".

supabase-enterprise-rbac

1868
from jeremylongshore/claude-code-plugins-plus-skills

Implement custom role-based access control via JWT claims in Supabase: app_metadata.role, RLS policies with auth.jwt() ->> 'role', organization-scoped access, and API key scoping. Use when implementing role-based permissions, configuring organization-level access, building admin/member/viewer hierarchies, or scoping API keys per role. Trigger: "supabase RBAC", "supabase roles", "supabase permissions", "supabase JWT claims", "supabase organization access", "supabase custom roles", "supabase app_metadata".

speak-enterprise-rbac

1868
from jeremylongshore/claude-code-plugins-plus-skills

Configure Speak for schools and organizations: SSO, teacher/student roles, class management, and usage reporting. Use when implementing enterprise rbac, or managing Speak language learning platform operations. Trigger with phrases like "speak enterprise rbac", "speak enterprise rbac".

snowflake-enterprise-rbac

1868
from jeremylongshore/claude-code-plugins-plus-skills

Configure Snowflake enterprise RBAC with system roles, custom role hierarchies, SSO/SCIM integration, and least-privilege access patterns. Use when implementing role-based access control, configuring SSO with SAML/OIDC, or setting up organization-level governance in Snowflake. Trigger with phrases like "snowflake RBAC", "snowflake roles", "snowflake SSO", "snowflake SCIM", "snowflake permissions", "snowflake access control".

windsurf-enterprise-sso

1868
from jeremylongshore/claude-code-plugins-plus-skills

Configure enterprise SSO integration for Windsurf. Activate when users mention "sso configuration", "single sign-on", "enterprise authentication", "saml setup", or "identity provider". Handles enterprise identity integration. Use when working with windsurf enterprise sso functionality. Trigger with phrases like "windsurf enterprise sso", "windsurf sso", "windsurf".

shopify-enterprise-rbac

1868
from jeremylongshore/claude-code-plugins-plus-skills

Implement Shopify Plus access control patterns with staff permissions, multi-location management, and Shopify Organization features. Trigger with phrases like "shopify permissions", "shopify staff", "shopify Plus organization", "shopify roles", "shopify multi-location".

sentry-enterprise-rbac

1868
from jeremylongshore/claude-code-plugins-plus-skills

Configure enterprise role-based access control, SSO/SAML2, and SCIM provisioning in Sentry. Use when setting up organization hierarchy, team permissions, identity provider integration, API token governance, or audit logging for compliance. Trigger: "sentry rbac", "sentry permissions", "sentry team access", "sentry sso setup", "sentry scim", "sentry audit log".