Guides · Setup
Connect the Klaviyo API to Outloop
Last updated:
In short
Outloop connects Klaviyo to your AI agents using a Private API Key stored in your Mac's Keychain.
Agents run real Klaviyo work — reporting, segments, list membership, campaign drafts and sends — while the key is injected host-side and redacted out of every response, audit line and log. Each client workspace is bound to exactly one Klaviyo account, derived from the key rather than typed by you.
The two one-way doors
Klaviyo's Private API Key is the credential, and two facts about it shape the entire setup. Both are Klaviyo's design, not Outloop's, and both are irreversible — which is why they come before anything else on this page rather than in a footnote after you have already created the key.
The second door is the one Outloop is built for. You paste the key once, it goes into the macOS Keychain, and from then on it is used without being seen — by you or by any agent.
What this connection gives you
Your agent works in Klaviyo — pulls reporting, builds segments, drafts and sends campaigns, manages list membership — and never sees the API key. Every request is bounded to one client account and written to a redacted audit line.
- ✓Reporting and audience reads — accounts, lists, list membership, profiles, metrics, events and campaigns.
- ✓Real campaign work — create a list, create a template, create a campaign, assign the template, and send.
- ✓List hygiene — add and remove profiles on a list without touching anyone's marketing consent.
- ✓One account per workspace — a request that reaches a different Klaviyo account is refused before the key is even read.
- ✓The key stays in the Keychain — injected host-side per request, redacted out of every response, audit line and log.
What you need
- →A Klaviyo account for the client, with permission to create a Private API Key.
- →Outloop installed on the Mac that will run the agents, with a workspace for this client.
- →Ten minutes, and the scope list below open in another tab before you click create.
1. Create the key with the right scopes
In Klaviyo, open Settings → API keys → Create Private API Key. Choose Custom key and grant the scopes below. A Full Access key also works if that suits your client's policy.
| Scope | What it is for | Grant |
|---|---|---|
accounts:read | Required. It is how Outloop identifies which account the key belongs to. | Always |
campaigns, flows | Draft, edit, schedule and send campaigns; read and edit flows, activate or pause them. | Read + write |
lists, segments, profiles, subscriptions | Audience and consent work. | Read + write |
templates, tags, images, events | Content and event writes. | Read + write |
metrics:read, forms:read | Reporting. | Read |
catalogs, coupons, coupon-codes, web-feeds | Ecommerce catalog and coupon work. | Only if this client uses them |
data-privacy | Permanent erasure of a person and their event history. | Only if this workspace handles deletion requests |
Klaviyo can pre-tick the whole set for you. Open this link instead of ticking twenty-two boxes by hand, then name the key and create it:
https://www.klaviyo.com/create-private-api-key?scopes=accounts:read,campaigns:read,campaigns:write,flows:read,flows:write,lists:read,lists:write,profiles:read,profiles:write,segments:read,segments:write,subscriptions:read,subscriptions:write,templates:read,templates:write,tags:read,tags:write,images:read,images:write,events:read,events:write,metrics:read,forms:read
403 when the key is valid but lacks the scope for that endpoint. Outloop
passes that through as a real 403 carrying the provider's own status — it does not relabel it as an
authentication failure, and it will not send you off to replace a key that is working perfectly well.
2. What Outloop sends
Outloop calls https://a.klaviyo.com under /api/ only,
injecting Authorization: Klaviyo-API-Key … host-side, plus two companion
headers it sets automatically: revision (pinned) and
X-Klaviyo-Revision-Fall-Forward-Opt-Out.
The agent cannot choose the API revision. Those headers are injected after the agent's own, so a request can never silently move to a different version of Klaviyo's API — which is what would otherwise let a payload shape change under you without a single line of your configuration changing.
PATCH, not PUT.
Klaviyo's API is JSON:API-shaped, so the allowed methods on a full grant are
GET, POST, PATCH and
DELETE. An agent reaching for PUT is using the wrong
verb for this provider, not hitting a policy limit.
3. Add the key in Outloop
In Outloop open API Keys & Access, pick Klaviyo, and choose whether this key is dedicated to one workspace or shared across several. For a client's own Klaviyo account, dedicated is almost always right — the key reaches that client's account and nothing else, so sharing it buys you nothing and widens the blast radius.
Then paste the key and add it.
4. The account binds itself
You do not type an account id. Outloop calls
GET /api/accounts/, reads the one account the key belongs to, shows it to
you, and binds the workspace to it. You confirm rather than transcribe — which removes the single
most common setup error on connectors that ask for an identifier by hand.
That binding is the client boundary. A Private API Key reaches exactly one Klaviyo account, so the credential is the boundary — which is why the pin fails closed until it is bound, and why the only route reachable before binding is that one read-only account call.
The first safe proof
Start with a Grant Preflight, which answers from local policy
with no provider call and no credential read — expect PREFLIGHT_OK plus the
allowed methods and the resource pin. Then the real proof, which is the same read-only call the access
check runs and the one that binds the workspace:
GET /api/accounts/ decision: allow code: OK http_status: 200 secret_exposed: false account bound: data[0].id <- derived, never typed public_api_key: ***REDACTED***
It identifies the account and touches nothing. Note the last line: Klaviyo's own
public_api_key field comes back redacted, because Outloop redacts
credential-shaped values out of provider responses as well as out of its own.
The boundary is proven by the negative case, and this one costs nothing to run — asking for a data-privacy deletion while that capability is off:
POST /api/data-privacy-deletion-jobs/ decision: deny code: DATA_PRIVACY_ACTION_NOT_ENABLED http_status: null <- no Klaviyo call was made at all secret_exposed: false
http_status: null is the part that matters. The refusal happened
before the key was read and before Klaviyo was contacted, so
nothing was deleted and nothing was even asked.
Capabilities and write actions
- Verified Live verified through Outloop — actually run against a real
production Klaviyo account and passed. Reads: accounts, lists, list membership, profiles including
additional-fields, metrics, events and campaigns. Writes: create a list (201), create a template (201), create a campaign (201), assign a template (200), add profiles to a list (204), delete a list (204), a bulk subscribe consent change (202), and a real campaign send that executed exactly once and was observed delivering to one recipient. - Supported, not verified yet Flow activation, account-wide unsubscribe, suppression and un-suppression, and catalog, coupon and web-feed writes. Klaviyo allows them and Outloop's policy allows them; no proof has been run.
- Off by default Data-privacy deletion only. Everything else in the enabled capability set runs — see the next section, which is the one part of this page worth reading twice.
What runs unattended
Once you enable full API access, nothing waits for a person. Sends, flow activation and consent changes all execute and are audited. There is no approval queue and nothing is sitting in Outloop waiting for you to click something.
Exactly two switches can stop a request:
| Switch | Default | What it gates |
|---|---|---|
| Destructive actions (delete / archive) | ON | DELETE requests, and delete or archive semantics expressed through POST. |
| Data-privacy deletion | OFF | POST /api/data-privacy-deletion-jobs/ — permanently deletes a person and their entire event history. |
DELETE is part of this connector's declared baseline, so the add flow
writes it and the row reads Enabled immediately. If you do not want agents deleting
lists, turning it off is a deliberate act you have to perform — an operator who assumes deletion starts
off will be wrong.
Unsubscribe has two very different shapes
Klaviyo does not make the difference obvious, and it is the sharpest edge on this connector. An unsubscribe that names a list still globally unsubscribes anyone who is not on that list. An unsubscribe with no list is account-wide by definition.
So Outloop runs a bounded membership pre-read first, and one non-member refuses the entire request — it never strips the non-members and quietly sends the remainder, because a partial consent change is the kind of thing nobody discovers until a client asks why a customer stopped hearing from them. Batches are capped at 100 targets, or 6 when addressed by profile id.
DELETE /api/lists/{id}/relationships/profiles unlinks
a profile from a list without touching their marketing consent. Outloop deliberately does not classify
it as destructive — it is the most common list-hygiene write an agency performs, and gating it would
make the switch meaningless.
202 for job-shaped work such as a campaign send. Outloop reports that
honestly as accepted-but-unverified and never auto-resubmits. Poll the job if you need to know it
finished — and note that a send Klaviyo accepts can still be skipped by Klaviyo's own Smart Sending.
What is verified vs what is not claimed
Tested here: against a real production Klaviyo account on 2026-08-29, workspace-scoped, on a live account rather than a test one — secure key entry with zero leaks including broker stdout and stderr; account binding derived from the live account read; the read set and write set listed above; a campaign send executing exactly once with delivery observed and a replay refused; a data-privacy deletion denied before any provider call while the capability was off; and a permanent list delete executing unattended with the destructive capability on. Zero approval records were created, and the key never appeared in any result, audit line or log.
Not claimed. These are stated plainly because they are the guarantees customers most want, and they are proven only by offline suites rather than against the live provider:
- ✕That the list-membership guard has fired against live Klaviyo. It has not. It is the assertion this connector is shaped around, and it is offline-tested only.
- ✕That the wrong-account refusal has fired live.
KLAVIYO_ACCOUNT_MISMATCHhas never fired against the provider — no second Klaviyo account was available to prove it with. - ✕That cross-workspace denial has been run live. It has not.
- ✕That destructive-actions-off was exercised on a live grant. Offline suites only.
- ✕That the rate-limit header names Outloop captures are confirmed. They are declared from Klaviyo's documentation and have not been checked against a live response, and no natural
429was ever observed. - ✕That unattended execution was proven on the installed app. The unattended run was executed from a development build. The installed-app proof covered the reads, the writes and the delivered send.
- ✕That the official Klaviyo MCP server was tested here. It was not connected in this workspace.
Klaviyo through Outloop vs the Klaviyo MCP server
| Area | Klaviyo through Outloop | Official Klaviyo MCP server |
|---|---|---|
| Provenance | The Klaviyo connector in Outloop, verified here against product 1.29.6. | An official hosted MCP server published by Klaviyo at mcp.klaviyo.com, generally available. |
| Authentication | One Private API Key per client, held in the macOS Keychain and injected host-side. No person signs in. | OAuth with dynamic client registration. A person signs in, and the tools run as that signed-in session. |
| Who can use it | Any approved agent runtime in the workspace, bounded by the capabilities you enabled. | Klaviyo restricts it to users holding an Owner, Admin or Manager role. |
| Per-client scoping | Each workspace is bound to the one Klaviyo account its key answers for, before the credential is read. | Reach follows whoever authenticated. There is no per-workspace account boundary. |
| Credential handling | The key never reaches the agent, the chat, your project files or your logs. Responses carry secret_exposed: false. | Not applicable here — no key of yours is held by Outloop on this path. |
| Consent-changing writes | An unsubscribe naming a list runs a bounded membership pre-read first, and one non-member refuses the whole request. | Governed by the MCP server and the signed-in account, not by Outloop. |
| Audit trail | One redacted line per attempt: workspace, service, action class, the resource addressed, and the capability that authorized it. | Not applicable here. |
| Status here | Live verified through Outloop Real read, write and send proof against a production account, 2026-08-29. | Official MCP exists Not connected here; not verified in this guide. |
When something is refused
- →
CUSTOMER_RESOURCE_PIN_REQUIRED— the workspace was never bound to a Klaviyo account. Re-run the access check on the key row; the binding happens there. - →
KLAVIYO_ACCOUNT_MISMATCH— the key answers for a different Klaviyo account than this workspace is bound to, and nothing was sent. That is isolation working: the key most likely belongs to another client. - →
KLAVIYO_LIST_MEMBERSHIP_UNVERIFIED— one or more unsubscribe targets are not on the named list, or membership could not be proven. Nobody was partially unsubscribed. Re-read the list and unsubscribe only actual members. - →
KLAVIYO_TARGET_LIMIT_EXCEEDED— more than 100 targets, or more than 6 profile ids. Split it into smaller batches. - →
DESTRUCTIVE_ACTION_BLOCKED— destructive actions are switched off for this workspace. That is a setting, not a request for approval, and nothing is waiting for anyone. - →
DATA_PRIVACY_ACTION_NOT_ENABLED— data-privacy deletion is off, which is the default. Enable it only if this workspace handles deletion requests. - →
ACTION_RISK_UNCLASSIFIED— an ambiguous mutation that might be high-impact, so it is refused rather than silently allowed. Report the exact method and path; do not retry a variation of it. - →HTTP
403from Klaviyo — the key is valid but lacks that scope. Because scopes cannot be edited, the fix is a new key with the scope, then Rotate key on the Outloop key row. - →A
202that never seems to finish — 202 means accepted, not delivered. Poll the job. If the campaign shows as sent but a recipient got nothing, check Klaviyo's Smart Sending before suspecting the connector.
What keeps one client separate
- ✓The key never reaches the agent. It is not returned to the agent, written to project files, logs, policy or the audit trail. Every allowed response carries
secret_exposed: false, and Klaviyo's ownpublic_api_keyfield comes back redacted. - ✓Workspace pinning — identity is derived from the real folder path, never from the request body.
- ✓Account pinning — derived from the live account read rather than typed, so there is no identifier for anyone to get wrong.
- ✓The credential is the boundary — a Private API Key reaches exactly one Klaviyo account, so the pin fails closed until it is bound, and the only route reachable before binding is the read-only account call.
- ✓One approved host, HTTPS only —
a.klaviyo.comunder/api/. Nothing outside that prefix is reachable by an agent. - ✓The agent cannot pick the API revision — the revision headers are injected after the agent's own.
- ✓Audit trail — one redacted line per attempt with the workspace, service, action class, the resource addressed, and the capability that authorized it.
- ✓No unsafe replay — a send that was accepted once is not resubmitted, and a replay of the proven send was refused.
Replacing the key starts on Klaviyo's side, because scopes are immutable: create a new Private API Key with the scopes you want, then use Rotate key on the Outloop key row to enter it, and delete the old key in Klaviyo. The workspace binding, the access level and the capability switches are untouched. The broader mechanism is on the security model page.
Official documentation
- →How to create or clone a private API key
- →Authenticate API requests — the Klaviyo-API-Key and revision headers
- →API versioning and deprecation policy
- →Get Accounts — the read that derives the account binding
- →Rate limits and error handling
- →Klaviyo MCP server
Outloop is available with guided onboarding for agency teams. Outloop is an independent tool and is not affiliated with or endorsed by Klaviyo. See the security model for how credentials are stored and used, the Taboola Backstage guide and the Microsoft 365 Mail guide for the other connectors at this level of proof, or the rest of the connector setup guides.
One key in the Keychain. The right client account, every time.
Run Klaviyo campaigns, segments and list work across client workspaces without handing an agent the key.