# Setup

This setup connects **Klaviyo** (segmentation, flows, campaigns) to **The Wallet Crew** (wallet execution and lifecycle signals).

Klaviyo needs two things:

* credentials so The Wallet Crew can send events and update Klaviyo profile properties
* a webhook flow so Klaviyo can request a back-population of `neostore.authenticationToken` for existing profiles

<details>

<summary><strong>Real-world examples</strong></summary>

* A Brand wants “installed vs not installed” segments to suppress reminder emails.
* A CRM team wants authenticated links in emails without changing existing templates.
* A partner wants subscription status updates driven by consent collected in a The Wallet Crew enrolment form.

</details>

### Prerequisites

Access is required on both sides.

* **The Wallet Crew**: access to the admin console and to advanced configuration files.
* **Klaviyo**: access to create API keys, segments, flows, and webhooks.
* A test profile exists in Klaviyo with a known email and/or phone number.
* Target environment is identified (staging vs production).

### The Wallet Crew configuration

The Wallet Crew uses the Klaviyo connector to send wallet lifecycle events into Klaviyo, maintain profile properties, and optionally manage list subscriptions based on consent collected in enrolment flows.

<details>

<summary><strong>Real-world examples</strong></summary>

* A loyalty enrolment form collects email + consent, then subscribes the customer to a newsletter list.
* A pass installation event becomes a Klaviyo metric used to trigger a welcome flow.

</details>

#### Configure the connector in The Wallet Crew

Open the Klaviyo integration settings in The Wallet Crew admin console.

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/integrations/klaviyo" class="button secondary" data-icon="chevrons-right">Open Klaviyo connector settings</a></p>

<div data-with-frame="true"><figure><img src="https://3566051324-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWLc8AHXW4tdrAXUBfrYF%2Fuploads%2F5xpNnkcqGMPDxCOJOFOS%2Fimage.png?alt=media&#x26;token=7049b0c4-9a1d-4e7f-8314-d07f842972a0" alt="The Wallet Crew Klaviyo connector: general configuration screen"><figcaption><p>General settings store the Klaviyo Site ID and the Klaviyo private API key.</p></figcaption></figure></div>

**Required Klaviyo values**

Klaviyo values are available at `https://www.klaviyo.com/settings/account/api-keys`.

* `siteId` maps to **Public API Key / Site ID**.
* `privateApiKey` is a **new** private key created for The Wallet Crew.

**Required permissions on the Klaviyo private key**

Minimum permissions depend on the enabled features.

* Always required
  * Events: **Full Access**
* Required when list subscription sync is enabled
  * Lists: **Full Access**
  * Profiles: **Full Access**
  * Subscriptions: **Full Access**

<div data-with-frame="true"><figure><img src="https://3566051324-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWLc8AHXW4tdrAXUBfrYF%2Fuploads%2F7esJQV498SFtEu7Eqed6%2Fimage.png?alt=media&#x26;token=b081b64a-a0cb-49c2-8282-db8f25094c53" alt="Klaviyo API keys screen showing permissions for a private key"><figcaption><p>Make sure the private key permissions match the expected capabilities.</p></figcaption></figure></div>

{% hint style="warning" %}
If events do not appear in Klaviyo, the first check is the Klaviyo private key permissions.
{% endhint %}

#### Enable the Klaviyo step in `server/flows.yml`

The connector sends events when a flow includes a `klaviyo` step.

{% hint style="info" %}
The `klaviyo` step can be added to any flow that should emit lifecycle events.
{% endhint %}

{% code title="server/flows.yml" %}

```yaml
flows:
  - type: userRegistration
    name: user
    steps:
      - type: shopify
      - type: pass
        passType: user
      - type: klaviyo
      - type: mail
        mailTemplate: downloadPass
```

{% endcode %}

{% hint style="warning" %}
If events do not show up in Klaviyo, confirm the `klaviyo` step is present in the executed flow.
{% endhint %}

#### Consent and list subscription configuration

Consent can be collected in The Wallet Crew enrolment form. The Klaviyo connector can turn this into list subscription updates.

**Single list configuration**

The `listId` value is available in Klaviyo list settings.

When a `listId` is configured in The Wallet Crew Klaviyo settings:

* when `email` is present, `consents_email` controls email subscription status
* when `phoneNumber` is present, `consents_sms` controls SMS subscription status

**Multiple lists (advanced)**

Multiple list routing can be implemented with scripting.

Create or edit `/server/script/klaviyo.js` and implement `GetSubscriptions`.

{% code title="/server/script/klaviyo.js" %}

```javascript
function getSubscriptions(account) {
  var subscriptions = [];

  var newsletterSubscription;
  if (account["email"] && account["consents_email"] !== undefined) {
    newsletterSubscription = newsletterSubscription || { ListId: "WnP7MK" };
    newsletterSubscription.Email = !!account["consents_email"];
  }

  if (account["phoneNumber"] && account["consents_sms"] !== undefined) {
    newsletterSubscription = newsletterSubscription || { ListId: "WnP7MK" };
    newsletterSubscription.Sms = !!account["consents_sms"];
  }

  if (newsletterSubscription) {
    subscriptions.push(newsletterSubscription);
  }

  return subscriptions;
}

export default function (context) {
  context.register("extensions.klaviyo.subscriptions.provider", {
    GetSubscriptions: getSubscriptions,
  });
}
```

{% endcode %}

{% hint style="warning" %}
If subscription updates do not work, confirm **Lists** and **Subscriptions** permissions are granted to the Klaviyo private key.
{% endhint %}

### Klaviyo configuration

`neostore.authenticationToken` is the identity cornerstone for authenticated links.

When this property exists on a Klaviyo profile, emails and SMS can include links that open the correct wallet page for that customer.

<details>

<summary><strong>Real-world examples</strong></summary>

* A reactivation email opens the pass page without asking for login.
* A reminder email opens the registration form when a pass is not installed.

</details>

#### Create the “TWC unsynced profiles” segment

This segment targets profiles missing the token.

1. Go to `https://www.klaviyo.com/lists/create` and select **Segment**.
2. Name: `TWC unsynced profiles`.
3. Definition:
   * `Properties about someone`
   * `neostore.authenticationToken`
   * `is not set`

{% hint style="warning" %}
A typo in this rule prevents back-population. This is the most common setup mistake.
{% endhint %}

#### Create the profile sync flow

This flow calls The Wallet Crew webhook to sync the token for profiles entering the segment.

{% stepper %}
{% step %}
**Create a flow**

* Go to `https://www.klaviyo.com/flows/create`.
* Create from scratch.
* Name: `sync TWC unsynced profiles`.
* Trigger: “When someone joins TWC unsynced profiles”.
  {% endstep %}

{% step %}
**Add a webhook action**

Klaviyo requires a **2FA-compliant** account to enable webhooks.

Set the webhook destination URL:

`https://app.neostore.cloud/api/<tenantId>/webhooks/listeners/klaviyo/profiles/sync`

`<tenantId>` is the The Wallet Crew tenant identifier.

{% hint style="info" %}
`<tenantId>` is the same identifier used in The Wallet Crew URLs and API routes for a given tenant.
{% endhint %}

Add one header:

* Key: `X-API-KEY`
* Value: a The Wallet Crew API key that includes `tenant.klaviyo.listener` write permission

Body (JSON):

```json
{
  "email": "{{ person.email }}",
  "phone_number": "{{ person.phone_number }}"
}
```

{% endstep %}

{% step %}
**Enable, then back-populate past profiles**

* Enable the flow.
* In the flow menu, use **Add past profiles**.
* Select “from beginning”.
* Run back-population.

This forces existing profiles to be evaluated and synced.
{% endstep %}
{% endstepper %}

#### Troubleshooting: token still missing after back-populate

* Confirm the segment is correct: `neostore.authenticationToken` **is not set**.
* Confirm the flow is **enabled**.
* Confirm the webhook action shows successful executions in Klaviyo flow history.
* Confirm the webhook header uses `X-API-KEY`.
* Confirm the The Wallet Crew API key has `tenant.klaviyo.listener` write permission.
* Confirm the destination URL uses the correct `<tenantId>`.

### Common setup errors

These issues explain most “it’s configured but nothing happens” situations.

* The Klaviyo private key misses required permissions (events only vs events + profiles + subscriptions).
* The webhook URL uses the wrong tenant identifier.
* The Wallet Crew API key used by the webhook lacks `tenant.klaviyo.listener` write permission.
* The Klaviyo segment rule has a typo, often around `neostore.authenticationToken` “is not set”.
* The executed wallet flow misses the `klaviyo` step, so no events are sent.
* Webhooks are not enabled in Klaviyo because the account is not 2FA-compliant.
* The Klaviyo sync flow is disabled, so back-population never runs.

### FAQ

<details>

<summary><strong>Which environment should be set up first?</strong></summary>

Staging is usually set up first.

This makes it easier to validate events, profile sync, and subscription behavior before production.

</details>

<details>

<summary><strong>Which teams typically own Setup?</strong></summary>

Connector settings and API keys are typically handled by IT or an implementation partner.

Segments, flows, and campaigns are typically handled by CRM or marketing operations.

</details>

<details>

<summary><strong>Does The Wallet Crew need Klaviyo access to manage campaigns?</strong></summary>

No. Klaviyo keeps ownership of flows, campaigns, and templates.

The Wallet Crew only syncs wallet signals and profile properties.

</details>

<details>

<summary><strong>Is email required to sync <code>neostore.authenticationToken</code>?</strong></summary>

Email is the most common identifier. Phone can also be provided.

The webhook accepts both fields. Matching rules depend on tenant configuration.

</details>
