> For the complete documentation index, see [llms.txt](https://the-wishlist-documentation.gitbook.io/the-wishlist-documentation-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://the-wishlist-documentation.gitbook.io/the-wishlist-documentation-docs/integrations/customer-marketing-consent.md).

# Customer Marketing Consent

This guide explains how The Wishlist Company (TWC) records, interprets and exchanges customer marketing consent, including how consent received from commerce, POS and marketing platforms is handled.

For TWC's **pre-built integrations**, including platforms such as Shopify, Emarsys, Newstore, and AP21, the behaviours described in this document are handled automatically by the integration. Customers and implementation teams do not normally need to reproduce or manage this logic themselves.

This document is therefore primarily provided to:

* explain how TWC interprets and maintains consent across connected systems;
* assist teams reviewing consent flows and sources of truth across their technology stack; and
* provide implementation guidance for organisations integrating with TWC through our REST APIs or through third-party platforms for which a pre-built TWC integration is not available.

Where a custom integration is being developed, the principles and mappings described here should be followed to preserve the meaning and history of customer consent as it moves between systems.

It is intended for developers, solution architects and technical teams working with customer data and consent across TWC and connected platforms.

> **Note:** This document describes TWC's technical handling of customer consent. It is not legal advice. Retailers remain responsible for determining the appropriate consent requirements for their customers and jurisdictions.

***

### Consent channels

TWC records marketing consent independently for:

* **Email**
* **SMS**

Consent for one channel does not imply consent for another.

For example, a customer may be subscribed to email while being unsubscribed from SMS.

For each channel, TWC records the following information:

| Field               | Description                                           |
| ------------------- | ----------------------------------------------------- |
| `opt_in_active`     | The customer's current recorded consent decision      |
| `opted_in_at`       | When the customer originally opted into that channel  |
| `opt_in_updated_at` | When the recorded consent decision last changed       |
| `source`            | The system from which the consent decision originated |

Common source values include `SHOPIFY`, `EMARSYS` and `NEWSTORE`.

***

### Consent states

TWC uses a **three-state consent model**.

| Consent state        | Meaning                                        |
| -------------------- | ---------------------------------------------- |
| **Never subscribed** | No explicit consent decision has been recorded |
| **Subscribed**       | The customer has explicitly opted in           |
| **Unsubscribed**     | The customer has explicitly opted out          |

The distinction between **Never subscribed** and **Unsubscribed** is important.

A customer can exist in TWC without having made a marketing decision. For example, they may have:

* completed a purchase;
* created an account;
* been imported from another system; or
* provided contact details for another purpose.

Creating a customer record does not itself imply either consent or an unsubscribe decision.

#### Never subscribed

Where no consent decision has been recorded for a channel:

* there is no recorded consent-change timestamp; and
* the customer remains in the **Never subscribed** state.

This should not be interpreted as an explicit opt-out.

#### Subscribed

When a subscription decision is recorded:

```
opt_in_active = true
opt_in_updated_at = <decision timestamp>
opted_in_at = <subscription timestamp>
```

#### Unsubscribed

When an unsubscribe decision is recorded:

```
opt_in_active = false
opt_in_updated_at = <decision timestamp>
```

Where the customer previously subscribed, TWC retains the original `opted_in_at` value.

***

### Why three states matter

Some platforms represent consent using only a Boolean or two-state model:

```
Subscribed
Not subscribed
```

This creates an ambiguity because **Not subscribed** can represent either:

```
Never subscribed
```

or:

```
Explicitly unsubscribed
```

Those are not equivalent states.

Once they have been collapsed into a single value, another system may be unable to determine whether the customer actively withdrew consent or simply never provided it.

For integrations between systems, TWC therefore recommends preserving three-state consent wherever the destination platform supports it.

Where a destination supports only two states, the integration design should explicitly document how **Never subscribed** will be represented and what information will be lost.

***

### Shopify consent

TWC uses Shopify's email and SMS marketing consent information as the Shopify source of truth.

The legacy Shopify `accepts_marketing` field is **not used** for consent decisions.

#### Shopify → TWC

Shopify consent states are interpreted as follows:

| Shopify state    | TWC state                    | TWC action                       |
| ---------------- | ---------------------------- | -------------------------------- |
| `SUBSCRIBED`     | Subscribed                   | Record an opt-in decision        |
| `UNSUBSCRIBED`   | Unsubscribed                 | Record an opt-out decision       |
| `NOT_SUBSCRIBED` | Never subscribed             | Do not create a consent decision |
| `PENDING`        | Never subscribed / unchanged | Do not create a consent decision |
| `REDACTED`       | No decision                  | Do not create a consent decision |

#### `NOT_SUBSCRIBED`

This distinction is particularly important with Shopify.

Shopify can return `NOT_SUBSCRIBED` for a customer who has never made a marketing decision.

TWC therefore does **not** interpret `NOT_SUBSCRIBED` as an explicit unsubscribe.

Converting it directly to `false` would incorrectly make:

```
Never asked
```

indistinguishable from:

```
Explicitly opted out
```

#### `PENDING` and double opt-in

A `PENDING` Shopify state means that the customer has started a double opt-in process but has not yet completed it.

TWC does not treat this as consent.

The customer is only recorded as subscribed once Shopify reports `SUBSCRIBED`.

***

### Updating consent

TWC treats consent changes as explicit decisions rather than simply copying every consent value received from another platform.

A new decision updates:

```
opt_in_active
opt_in_updated_at
source
```

When the decision is an opt-in, TWC also records:

```
opted_in_at
```

Where possible, unchanged consent states are ignored rather than rewritten.

This reduces unnecessary updates and helps prevent consent synchronisation loops between platforms.

***

### Consent timestamps

TWC maintains two separate timestamps.

#### `opted_in_at`

This represents when the customer opted into the channel.

It is retained when the customer later unsubscribes so that the historical subscription date is not lost.

#### `opt_in_updated_at`

This represents when the customer's consent decision most recently changed.

It also indicates that TWC has actually recorded a consent decision.

Consequently:

```
opt_in_updated_at = null
```

generally indicates **Never subscribed**, rather than an explicit unsubscribe.

For integrations receiving consent from multiple systems, the update timestamp can also be used as part of determining which system holds the more recent decision.

***

### Consent source

TWC records the originating system for consent updates.

For example:

```
SHOPIFY
EMARSYS
NEWSTORE
```

The source identifies where TWC received the decision; it does not change the meaning of that decision.

A subscribed customer remains subscribed regardless of whether the decision originated from ecommerce, POS or a marketing platform.

***

### Integration considerations

When synchronising consent between multiple systems, the principal concern should be preserving the **meaning** of the consent state rather than simply mapping Boolean fields.

#### Three-state → three-state systems

Where both systems support:

```
Never subscribed
Subscribed
Unsubscribed
```

the states should normally map directly.

Klaviyo, for example, distinguishes:

```
NEVER_SUBSCRIBED
SUBSCRIBED
UNSUBSCRIBED
```

which maps naturally to TWC's consent model.

#### Three-state → two-state systems

Where another system supports only:

```
true / false
```

or:

```
subscribed / not subscribed
```

the integration must explicitly define how **Never subscribed** is handled.

It should not automatically be converted to `false` or `unsubscribed`, as this can incorrectly turn the absence of a consent decision into an explicit opt-out.

Where possible, TWC preserves the distinction by **not sending a consent value** when no decision has been recorded.

If a third-party integration instead collapses:

```
Never subscribed → false
Unsubscribed      → false
```

that conversion is lossy. The receiving system can no longer determine whether the customer explicitly opted out or simply never provided consent.

For example:

```
TWC Never subscribed → false
TWC Unsubscribed      → false
```

means that the receiving system can no longer distinguish the two states.

Where that system subsequently becomes a source of consent back into TWC, care must be taken not to turn the collapsed `false` value into an explicit unsubscribe unless that is genuinely what the value represents.

***

### Emarsys integration

TWC supports two-way consent synchronisation with Emarsys.

#### TWC → Emarsys

TWC sends an email or SMS consent update to Emarsys **only when the customer's recorded consent state changes**.

Unchanged consent is not re-sent.

The mapping for recorded consent decisions is:

| TWC state        | Emarsys value | Behaviour                 |
| ---------------- | ------------: | ------------------------- |
| Subscribed       |           `1` | Consent update sent       |
| Unsubscribed     |           `2` | Consent update sent       |
| Never subscribed |             — | **No consent value sent** |

The **Never subscribed** behaviour is deliberate.

A customer for whom TWC has never recorded a consent decision is not treated as unsubscribed. Because Emarsys does not provide an equivalent three-state value in this integration, TWC leaves the Emarsys consent value unchanged.

In particular, TWC does **not** convert:

```
Never subscribed → Emarsys 2
```

Doing so would incorrectly turn the absence of a consent decision into an explicit "not opted in" state.

#### Emarsys → TWC

TWC can also receive email and SMS consent changes from Emarsys via webhooks.

Where Emarsys supplies a consent value:

```
1 → Subscribed
2 → Unsubscribed
```

Where no consent value is supplied, TWC does not change the existing consent state.

Before applying an update, TWC compares the incoming state with the customer's current recorded state. If the consent state has not changed, no consent update is made.

This change detection also helps prevent unnecessary synchronisation loops between Emarsys and TWC.

***

#### Migrating between marketing platforms

Extra care should be taken when migrating consent from one marketing platform to another, particularly where the systems involved do not represent consent in the same way.

TWC preserves the distinction between:

* **Never subscribed**
* **Subscribed**
* **Unsubscribed**

However, some platforms represent consent using only two states. In those systems, a value such as `false`, `not subscribed` or equivalent may not make it clear whether the customer:

* explicitly unsubscribed; or
* has simply never provided consent.

For example, a two-state source system may contain:

```
false
```

without retaining enough information to determine whether that means:

```
Never subscribed
```

or:

```
Explicitly unsubscribed
```

This distinction should not be reconstructed by assumption during a migration.

Where possible, migration logic should use the system that retains the richest and most reliable consent history, including consent state, timestamps and source information, rather than relying solely on the outgoing platform's current Boolean consent value.

This is particularly important when migrating from a platform or ERP/POS system that does not distinguish between **Never subscribed** and **Unsubscribed**.

***

### Recommended integration principles

When building or reviewing consent integrations with TWC:

1. **Preserve three consent states wherever possible.**\
   Never subscribed and explicitly unsubscribed should remain distinct.
2. **Do not infer consent from customer existence.**\
   An email address, account or transaction does not itself constitute a marketing decision.
3. **Do not infer an unsubscribe from an unknown state.**\
   Missing consent information should normally mean "no decision", not `false`.
4. **Treat email and SMS independently.**
5. **Preserve consent timestamps where available.**\
   In particular, distinguish the original opt-in date from the date the consent state last changed.
6. **Retain the originating source where practical.**
7. **Avoid overwriting newer consent with older data.**\
   Where multiple systems can update consent, update timestamps should form part of the conflict-resolution strategy.
8. **Understand lossy integrations.**\
   If a platform supports only two states, explicitly document which three-state values are being combined.
9. **Avoid synchronisation loops.**\
   Do not emit a new consent update simply because the same state was received from another system.

***

### Klaviyo considerations

Klaviyo's consent model is broadly compatible with TWC's because Klaviyo distinguishes:

```
SUBSCRIBED
NEVER_SUBSCRIBED
UNSUBSCRIBED
```

A typical mapping is therefore:

| TWC              | Klaviyo            |
| ---------------- | ------------------ |
| Never subscribed | `NEVER_SUBSCRIBED` |
| Subscribed       | `SUBSCRIBED`       |
| Unsubscribed     | `UNSUBSCRIBED`     |

Klaviyo also treats subscription status separately by communication channel, which aligns with TWC's independent email and SMS consent records.

When migrating from another platform to Klaviyo, however, developers should first determine whether the source platform genuinely distinguishes **Never subscribed** from **Unsubscribed**.

If it does not, that distinction cannot safely be reconstructed solely from its current consent field.

Additional information such as TWC consent history, Shopify consent state, consent timestamps or historical subscription events may need to be considered.

***

### Example

Consider a customer who completes a Shopify checkout but leaves the email marketing checkbox unticked.

Shopify may report:

```
email marketing state = NOT_SUBSCRIBED
consent_updated_at = null
```

TWC records this as:

```
Never subscribed
```

rather than:

```
Unsubscribed
```

If the customer later explicitly subscribes:

```
TWC = Subscribed
opted_in_at = subscription time
opt_in_updated_at = subscription time
source = SHOPIFY
```

If they subsequently unsubscribe:

```
TWC = Unsubscribed
opted_in_at = original subscription time
opt_in_updated_at = unsubscribe time
source = SHOPIFY
```

The history therefore distinguishes all three situations:

```
No decision
        ↓
Subscribed
        ↓
Unsubscribed
```

rather than reducing the lifecycle to a Boolean value.

***

### Summary

TWC's consent model is based on a simple principle:

> **No consent decision is different from an explicit decision not to consent.**

TWC therefore distinguishes **Never subscribed**, **Subscribed** and **Unsubscribed** independently for email and SMS.

When integrating with TWC, systems should preserve that distinction wherever possible.

Where another platform supports only two consent states, developers should treat the integration as a lossy conversion and take care not to turn an unknown or never-subscribed state into evidence of an explicit customer opt-out.
