> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Activate Klaviyo as a CDP destination

> Connect Klaviyo through Nango once, map a segment onto Klaviyo's profile object with email as the upsert key, run an on-demand sync, and read the run history.

# Activate Klaviyo as a CDP destination

Klaviyo is one of the six CRM/martech destinations Orbit's CDP can activate a segment into as **native object writes**. This guide walks the Klaviyo leg end to end: connect the integration, configure the profile mapping, run an on-demand sync, and read the run history.

If you are moving off Klaviyo instead, that path lives in [Migrate from Klaviyo to Orbit](/guides/migration-from-klaviyo). This page is the destination-integration walkthrough — it keeps Klaviyo in your stack and pushes Orbit segments into it.

## 1. Klaviyo among the six CDP destinations

The object-sync surface accepts six destination slugs, each with a closed list of native object types — for Klaviyo the list resolves to a single object type, `profile`:

| Destination | Object types | Default upsert identifier |
| - | - | - |
| `salesforce` | `Contact`, `Lead`, `Account` | `Email` |
| `hubspot` | `contact`, `company` | `email` |
| `braze` | `user` | `external_id` |
| `iterable` | `user` | `email` |
| `customer_io` | `person` | `id` |
| `klaviyo` | `profile` | `email` |

Klaviyo accepts one object type — `profile` — and defaults its upsert key to `email`. The full destination matrix and the field-map rules that apply to all six slugs live in [CDP to CRM object sync](/guides/cdp-crm-object-sync); the Braze/Iterable/Customer.io walkthrough on [Activate segments into Braze, Iterable, and Customer.io](/guides/cdp-martech-destinations-braze-iterable-customerio) covers the same walk for the other martech slugs.

## 2. Connect Klaviyo via Nango Connect

The connected Nango integration that powers per-event contact upsert powers the batch object sync — one connection, both paths. If your organization already wired Klaviyo on the [destinations](/guides/cdp-source-and-destinations) page, object sync can run against it with **no new auth**. The upstream OAuth token lives only inside that connection, never in a sync config.

<Info>
  A run against a destination with no connected account is still recorded — every batch reports as skipped dispatch — so you can validate the mapping end to end before you wire the integration.
</Info>

## 3. Choose the target Klaviyo object

Klaviyo's object list has a single entry: `profile`. A PATCH that names any other object type fails at config time with the whitelist error — the config can never drift into a shape the Klaviyo Nango action does not know how to upsert.

Pick the segment to activate in [CDP segments](/guides/cdp-segments). The segment's membership is the consent filter: only profiles whose definition you wrote reach Klaviyo.

## 4. Configure the Klaviyo mapping

Read every destination's current mapping with `GET /api/v1/cdp/crm-sync/config`. Then PATCH Klaviyo with only the keys you want to change — the merge is scoped to that one destination:

```bash theme={null}
curl -X PATCH "https://api.orbit.devotel.io/api/v1/cdp/crm-sync/config/klaviyo" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "object_type": "profile",
    "segment_id": "seg_high_value_clickers",
    "identifier_field": "email",
    "field_map": {
      "email": "email",
      "first_name": "first_name",
      "last_name": "last_name",
      "lifecycle_stage": "lifecycle_stage"
    },
    "schedule_minutes": 60
  }'
```

Field-map rules specific to this walk:

* **Flattened trait paths.** Each `field_map` key is a source trait path — a flat key or a dotted path like `traits.email`, up to 5 segments. Path segments named `__proto__`, `prototype`, or `constructor` are rejected outright as a prototype-pollution guard, so a polluted key can never reach the per-record projector.
* **The identifier must be a mapped value.** `email` must appear as one of your `field_map` destination values (here, from the `email` trait), or the config is rejected — without a mapped upsert key every record would be a blind-inserted duplicate.
* **No duplicate destination fields.** Two source traits writing the same Klaviyo attribute would silently clobber one another, so the mapping rejects it.

`identifier_field` defaults to `email` when you omit it; set it only to override Klaviyo's canonical external identity field.

## 5. Run the on-demand sync and read the history

Trigger a run with `POST /api/v1/cdp/crm-sync/run/klaviyo`:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/cdp/crm-sync/run/klaviyo" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "segment_id": "seg_high_value_clickers",
    "profiles": [
      { "email": "ana@example.com", "first_name": "Ana" },
      { "email": "ben@example.com", "first_name": "Ben" }
    ]
  }'
```

Profiles (1–5000 per request) are projected through the stored field map and chunked into upsert batches of 100. A profile whose mapped record is missing the identifier value is skipped — counted in `skipped`, never blind-inserted. The response is the recorded run object:

```json theme={null}
{
  "id": "9c3d...",
  "destination": "klaviyo",
  "object_type": "profile",
  "segment_id": "seg_high_value_clickers",
  "requested": 2,
  "matched": 2,
  "skipped": 0,
  "batches": 1,
  "dispatched": 1,
  "status": "ok"
}
```

Read the run history with `GET /api/v1/cdp/crm-sync/runs`:

```json theme={null}
{
  "runs": [
    {
      "id": "9c3d...",
      "destination": "klaviyo",
      "object_type": "profile",
      "segment_id": "seg_high_value_clickers",
      "requested": 5000,
      "matched": 4987,
      "skipped": 13,
      "rows": { "attempted": 4987, "delivered": 4985, "rejected": 0, "failed": 2 },
      "status": "partial"
    }
  ]
}
```

The history is capped at the last 50 runs per organization, newest first. The [sync run log](/guides/cdp-sync-run-log) guide walks the full reading loop — check `skipped` (profiles missing the upsert key) and `rows.failed` (per-batch provider errors, with record counts only) to find the leg that needs a fix.

## 6. When object sync is the wrong shape

Object sync exists for the **segment-level batch** case. If the unit of work is "this event, into Klaviyo" — a new sign-up, a single contact-update event — use the per-event destination dispatch on the [destinations panel](/guides/cdp-source-and-destinations) instead. The connected Nango integration you authorized once powers both paths, so choosing per-event over batch is a surface choice, not an auth choice.

## Related

* [CDP to CRM object sync (all six destinations)](/guides/cdp-crm-object-sync)
* [Destinations (per-event dispatch)](/guides/cdp-destinations)
* [Build the source segment](/guides/cdp-segments)
* [Migrate from Klaviyo to Orbit](/guides/migration-from-klaviyo)
* [Decode CRM connection and dispatch errors](/troubleshooting/crm-integration-errors)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.