How to Build Klaviyo VIP Segments from Stripe Lifetime Spend
Build a scheduled Spojit workflow that totals each customer's Stripe charges, writes a lifetime-value property onto their Klaviyo profile, and adds your highest spenders to a VIP list automatically.
What This Integration Does
Your most valuable customers deserve different marketing than first-time buyers, but lifetime spend lives in Stripe while your segments and flows live in Klaviyo. Copying totals across by hand does not scale, and a one-time export goes stale the moment the next charge lands. This workflow keeps the two systems aligned: it reads each customer's full charge history from Stripe, sums it into a lifetime-value figure, stamps that figure onto the matching Klaviyo profile, and adds anyone past your VIP threshold to a dedicated list. From there Klaviyo can drive VIP-only campaigns, early-access flows, and dynamic segments off a property that is always current.
The workflow runs on a Schedule trigger, so no external event is needed: on each scheduled tick it pages through your Stripe customers, and for every customer it totals their charges and updates Klaviyo. Nothing is deleted. Each run overwrites the lifetime-value property with the latest total and re-adds VIPs to the list (Klaviyo treats adding an existing member as a no-op), so the run is idempotent and safe to repeat. State left behind is purely in Klaviyo: an up-to-date stripe_lifetime_value property on every matched profile and an accurate VIP list membership. Re-running never double-counts spend because each run recomputes the total from scratch rather than incrementing.
Prerequisites
- A Stripe connection in Spojit (Connections -> Add connection -> Stripe) with read access to customers and charges.
- A Klaviyo connection with a private API key that can read and update profiles and manage list membership.
- A VIP list already created in Klaviyo. Copy its list ID (you can also confirm it with the
list-liststool during testing). - Customers that exist in both systems keyed by the same email address, so profiles can be matched reliably.
- A VIP spend threshold decided in advance (for example, 500.00 in your store currency).
Step 1: Add a Schedule trigger
Start a new workflow and set the Trigger node to type Schedule. A nightly cadence keeps lifetime values fresh without hammering either API. Use a 5-field Unix cron expression plus an IANA timezone, for example 0 2 * * * with Australia/Sydney to run at 2am local time. A single trigger can hold multiple schedules if you want more frequent updates during peak season. The trigger output is {{ scheduledAt }}, which you can reference downstream for logging or report subjects.
Step 2: Page through Stripe customers
Add a Connector node in Direct mode using the Stripe connector and the list-customers tool. Direct mode is right here because this is a predictable single-tool call with no AI cost. Set limit to 100 (the maximum per page). Stripe returns customers in pages, so to walk the full account use a Loop node in While mode (or repeat the list call) that passes the last customer ID into the starting_after cursor on each pass until no more pages remain. Hold the collected customers in a variable such as {{ customers }} for the next step.
Step 3: Loop over customers and total their charges
Add a Loop node in ForEach mode over {{ customers }}. Inside the loop body, add a Connector node in Direct mode using the Stripe connector and the list-charges tool, filtered to the current customer:
{
"customer": "{{ customer.id }}",
"limit": 100
}
If a customer can have more than 100 charges, page with the starting_after cursor exactly as in Step 2 until the list is exhausted. Then add a Connector node in Direct mode using the math connector and the sum tool over the charge amounts to produce a lifetime total. Stripe charge amounts are in the smallest currency unit (cents), so divide by 100 with the math connector's currency or round tool to get a human-readable value. Store the result as {{ lifetimeValue }}.
Step 4: Find the matching Klaviyo profile
Still inside the loop, add a Connector node in Direct mode using the Klaviyo connector and the list-profiles tool. Match on the Stripe customer's email with a JSON:API filter string:
{
"filter": "equals(email,\"{{ customer.email }}\")",
"pageSize": 1
}
Add a Condition node that checks whether a profile was returned. If the list is empty, branch to skip this customer (or create the profile first with the Klaviyo create-profile tool if you want to backfill). When a profile is found, read its ID into a variable such as {{ profileId }} for the update step.
Step 5: Write the lifetime-value property onto the profile
Add a Connector node in Direct mode using the Klaviyo connector and the update-profile tool. Pass the matched id and set a custom property under attributes.properties so Klaviyo can segment on it:
{
"id": "{{ profileId }}",
"attributes": {
"properties": {
"stripe_lifetime_value": {{ lifetimeValue }},
"stripe_ltv_updated_at": "{{ scheduledAt }}"
}
}
}
Custom properties live under properties so they do not collide with Klaviyo's standard fields. Each run overwrites these values, keeping the profile current without accumulating stale history.
Step 6: Add high spenders to the VIP list
Add a Condition node that checks {{ lifetimeValue }} against your VIP threshold (for example, greater than or equal to 500). On the true branch, add a Connector node in Direct mode using the Klaviyo connector and the add-profiles-to-list tool:
{
"listId": "YOUR_VIP_LIST_ID",
"profileIds": ["{{ profileId }}"]
}
Adding a profile that is already a member is a no-op, so this is safe to run every night. To avoid one call per profile, collect qualifying IDs across the loop and send them as a single batch in profileIds after the loop completes.
Step 7: Send yourself a run summary (optional)
After the loop, add a Send Email node so you get a record each run. Set Recipients to your address, a Subject such as Klaviyo VIP sync {{ scheduledAt }}, and a Body reporting how many profiles were updated and how many VIPs were added. Send Email uses Spojit's built-in mail service with no connection required, and only upstream variables resolve in the template. To send from your own domain instead, swap in the Resend or SMTP connector.
Tips
- Keep
limitat100onlist-customersandlist-chargesto minimise round trips, and always honour thestarting_aftercursor so you do not silently miss older records. - Batch your VIP additions: collect qualifying
{{ profileId }}values during the loop and pass them once toadd-profiles-to-listrather than calling it per customer. - Standardise the currency unit early. Convert Stripe's cents to a major-unit decimal once, before writing
stripe_lifetime_value, so Klaviyo segment conditions compare clean numbers. - Ask Miraxa, the intelligent layer across your automation, to scaffold the loop and condition for you with a prompt like "Add a Condition node that checks if
{{ lifetimeValue }}is over 500 and connect the true branch to a Klaviyo add-profiles-to-list node", then fine-tune fields in the properties panel.
Common Pitfalls
- Email mismatch: if a customer's Stripe email differs from their Klaviyo email,
list-profilesreturns nothing and the customer is skipped. Use the Condition node from Step 4 to catch and log these rather than failing the run. - Forgetting pagination: a customer with more than 100 charges will be undercounted if you read only the first page. Loop with
starting_afteruntil the charge list is empty. - Refunds and disputes:
list-chargesreturns charge amounts, not net revenue. If refunds matter for your VIP definition, decide whether to subtract them before summing, and document the choice. - Timezone drift: the schedule runs in the IANA timezone you set, not UTC. Pick the timezone that matches your reporting day so the nightly run lands when you expect.
Testing
Before enabling the schedule, run the workflow once with the Run button against a small slice: temporarily set list-customers limit to a handful, or hard-code a single known customer.id in Step 3. Confirm the Stripe total matches the customer's charges in the Stripe dashboard, open that customer's Klaviyo profile and verify stripe_lifetime_value appears with the right number, and check the VIP list membership only changed for profiles past your threshold. Once a single customer flows end to end, raise the limit, watch one full run in the execution history, then turn the schedule on.