> ## 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.

# Win-back lapsed customers with a multi-channel fallback journey

> Build a segment-triggered reactivation journey: email on day 1, SMS on day 3, WhatsApp fallback on day 7, a unique incentive code per recipient, re-entry guards, holdout lift measurement, and a compliance pre-flight.

# Win-back lapsed customers with a multi-channel fallback journey

A win-back journey reactivates customers who have gone quiet. This guide builds one from a CDP segment, sends a timed sequence across email, SMS, and WhatsApp, attaches a unique incentive code, guards against duplicate enrollment, and measures whether the journey actually caused conversions.

For segment mechanics see [CDP audiences](/guides/cdp-segments). For journey nodes and validation see [Build a campaign journey](/guides/campaign-journey-builder). For the fallback engine behind the channel chain see [Fallback chains](/guides/fallback-chains) and [Smart-send fallback chains](/guides/smart-send-fallback-chains).

## 1. Define the win-back segment in CDP

Create a segment under **Contacts → Segments** or with the Segments API. The win-back gate is behavioral: the contact was a customer but has had no meaningful activity recently.

Example filter — customers with no event or purchase in the last 90 days:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/contacts/segments" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Lapsed customers — 90 days",
    "description": "Customers with no purchase or session event in the last 90 days",
    "filters": {
      "and": [
        { "field": "lifecycle_stage", "op": "equals", "value": "customer" },
        {
          "field": "event.Order Completed",
          "op": "did_not_perform_event",
          "value": { "within": "90d" }
        },
        {
          "field": "event.Session Started",
          "op": "did_not_perform_event",
          "value": { "within": "90d" }
        }
      ]
    },
    "auto_refresh": true,
    "auto_refresh_interval_minutes": 1440
  }'
```

Key choices:

* **Auto-refresh must be on.** A segment trigger only fires when the segment re-evaluates; without auto-refresh the journey never gains new enrollments.
* **Use a 24-hour refresh or longer.** Daily re-evaluation is the right cadence for lifecycle segments. A shorter interval buys little and increases compute.
* **Preview the count.** `POST /api/v1/contacts/segments/preview` returns the match count before you persist the segment.

If you already use [churn-risk scoring](/guides/churn-risk-scoring), you can combine the inactivity rule with `churn_risk > 0.7` for a higher-propensity cohort.

## 2. Pick the trigger type

Two trigger patterns are common for win-back:

| Pattern | Trigger type | When to use |
| - | - | - |
| **Active buyers leaving** | Segment exit from an "active buyers" segment | The segment already exists; lapsed customers are the ones who fell out. |
| **Churn risk entering** | Segment entry into a churn-risk segment | You do not have an active-buyers segment; the churn model already surfaces at-risk contacts. |

Both patterns use the same journey node. In the dashboard under **Campaigns → Journey builder**, add a **Journey Trigger** node and set **Trigger Type** to **Segment entry** or **Segment exit**. Pick the segment from section 1.

If you use the API, the `journeyTrigger` node carries `triggerType: "segment"` and a `segment_id`. The campaign's `audience_type` can be `"all"` because the trigger itself decides enrollment.

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/campaigns" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Win-back — 90 day lapsed customers",
    "type": "journey",
    "audience_type": "all",
    "message_template": "Win-back journey for lapsed customers"
  }'
```

## 3. Compose the three-touch fallback chain

The journey sends one message per channel, spaced apart, so the next channel only reaches people who did not convert on the previous touch.

1. **Email on day 1** — the richest format for explaining the offer.
2. **SMS on day 3** — a short reminder with a tracked link to the incentive.
3. **WhatsApp on day 7** — the final fallback, useful where WhatsApp is the primary channel.

Wired as a `journeyDefinition` graph:

```json theme={null}
{
  "nodes": [
    {
      "id": "n_trigger",
      "type": "journeyTrigger",
      "data": {
        "label": "Lapsed 90 days",
        "triggerType": "segment",
        "segment_id": "seg_lapsed_90d"
      }
    },
    {
      "id": "n_email",
      "type": "sendMessage",
      "data": {
        "label": "Day 1 — win-back email",
        "channel": "email",
        "subject": "We miss you — here's 20% off",
        "body": "Hi {{first_name}}, it's been a while. Use code {{winback_code}} for 20% off your next order. Unsubscribe: {{unsubscribe_url}}"
      }
    },
    {
      "id": "n_wait_sms",
      "type": "waitDelay",
      "data": { "label": "Wait 2 days", "delayMinutes": 2, "delayUnit": "days" }
    },
    {
      "id": "n_sms",
      "type": "sendMessage",
      "data": {
        "label": "Day 3 — SMS reminder",
        "channel": "sms",
        "body": "Hi {{first_name}}, your 20% off code {{winback_code}} is waiting: {{short_link}}. Reply STOP to opt out."
      }
    },
    {
      "id": "n_wait_whatsapp",
      "type": "waitDelay",
      "data": { "label": "Wait 4 days", "delayMinutes": 4, "delayUnit": "days" }
    },
    {
      "id": "n_whatsapp",
      "type": "sendMessage",
      "data": {
        "label": "Day 7 — WhatsApp fallback",
        "channel": "whatsapp",
        "body": "Hi {{first_name}}, one last reminder: code {{winback_code}} for 20% off expires soon. Reply STOP to opt out."
      }
    },
    {
      "id": "n_end",
      "type": "journeyEnd",
      "data": { "label": "End" }
    }
  ],
  "edges": [
    { "source": "n_trigger", "target": "n_email" },
    { "source": "n_email", "target": "n_wait_sms" },
    { "source": "n_wait_sms", "target": "n_sms" },
    { "source": "n_sms", "target": "n_wait_whatsapp" },
    { "source": "n_wait_whatsapp", "target": "n_whatsapp" },
    { "source": "n_whatsapp", "target": "n_end" }
  ],
  "exit_criteria": [
    {
      "field": "event.Order Completed",
      "operator": "is_set"
    }
  ],
  "re_entry_policy": "after_cooldown_days",
  "re_entry_cooldown_days": 90
}
```

Save the graph on the campaign:

```bash theme={null}
curl -X PATCH "https://api.orbit.devotel.io/api/v1/campaigns/cmp_winback01" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "variables": {
      "journeyDefinition": {
        "nodes": [ ... ],
        "edges": [ ... ],
        "exit_criteria": [
          { "field": "event.Order Completed", "operator": "is_set" }
        ],
        "re_entry_policy": "after_cooldown_days",
        "re_entry_cooldown_days": 90
      }
    }
  }'
```

The `exit_criteria` here means a contact who purchases after the first email leaves the journey before the SMS or WhatsApp steps fire.

## 4. Attach a unique win-back incentive code

Use the [incentives ledger](/guides/incentives-ledger) to mint a unique code per recipient. A `discount_code` reward returns a `code` you can splice into the message template.

For a campaign-level variable, issue one code per recipient before launch or use the journey's `{{coupon_code}}` merge-tag, which derives a deterministic unique value from the recipient identity. To issue programmatically:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/incentives/issue" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: winback-2026q4-{{contact_id}}" \
  -d '{
    "reward_type": "discount_code",
    "source_ref": "winback-campaign-2026q4",
    "recipient": { "contact_id": "ct_01H..." },
    "amount": 20,
    "currency": "USD"
  }'
```

Response:

```json theme={null}
{
  "data": {
    "id": "ipo_7xk2q",
    "status": "issued",
    "reward_type": "discount_code",
    "code": "WINBACK-7XK2Q-20",
    "amount": 20,
    "currency": "USD",
    "issued_at": "2026-10-05T09:00:00.000Z"
  }
}
```

Pass the code into the campaign's personalization context, or read it from `GET /api/v1/incentives/issued?source_ref=winback-campaign-2026q4` before launching and load it into `variables.per_contact_codes`.

If you prefer loyalty points instead of a discount, route the reward through the [loyalty program](/guides/loyalty-program) redemption endpoint; the issued record still lands in the same incentives ledger.

## 5. Re-entry guard and suppression

Set two limits so the same customer is not repeatedly enrolled:

1. **Re-entry cooldown.** The graph above uses `"re_entry_policy": "after_cooldown_days"` with `"re_entry_cooldown_days": 90`. A contact can re-enter only after 90 days outside the segment.
2. **Global enrollment cap.** Add a campaign-level variable to cap total enrollments per contact. The recommended default for win-back is **3 lifetime enrollments**:

```bash theme={null}
curl -X PATCH "https://api.orbit.devotel.io/api/v1/campaigns/cmp_winback01" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "variables": {
      "max_enrollments_per_contact": 3
    }
  }'
```

For suppression rules and how they interact with consent, see [Choose your suppression entry point](/guides/suppression-three-entry-points). All opt-outs — CSV import, Consent API, or Preference Center — write into the same ledger that send gates read.

## 6. Measure uplift with a holdout

Reserve a control group so the conversion rate you see is causal, not just a count of people who would have come back anyway.

Set a campaign-wide holdout before launch:

```bash theme={null}
curl -X PATCH "https://api.orbit.devotel.io/api/v1/campaigns/cmp_winback01" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "variables": {
      "campaign_holdout_percent": 10
    }
  }'
```

After the journey has run, read lift:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/campaigns/cmp_winback01/journey/holdout-lift" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

The response reports treatment versus control, absolute lift, relative lift, and a confidence interval. Treat the effect as unproven until `is_significant` is true. For the full interpretation see [Holdouts and uplift measurement](/guides/campaign-holdout-uplift-measurement).

## 7. Compliance pre-flight

Run these checks before launch:

* **Quiet hours.** The platform applies tenant-configured quiet-hours windows at send time. Review your window under **Compliance → Quiet hours** and check the [quiet-hours configuration guide](/guides/quiet-hours-configuration).
* **Marketing opt-out.** Every marketing message must carry a clear opt-out. Email needs an unsubscribe link; SMS and WhatsApp need "Reply STOP to opt out" or a localized equivalent.
* **Unsubscribe footer.** The email template in section 3 includes `{{unsubscribe_url}}`. Verify the link resolves to your hosted preference center or a working unsubscribe handler.
* **Country rules.** If your audience spans markets, review the [country rules directory](/compliance/country-rules-directory). Country-specific consent, sender-ID, and marketing-hour rules are tenant-owned controls; configure them per market rather than relying on a platform default.

<Note>
  Compliance controls other than the US TCPA federal voice dialing-window guard are tenant-owned and default open. You decide what qualifies as consent, opt-out, and lawful sending; the platform enforces the gates you configure. This guide is not legal advice.
</Note>

## 8. Launch the journey

Launch from the dashboard under **Outbound → Campaigns** or from **Campaigns → Journey builder**, or call the send endpoint:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/campaigns/cmp_winback01/send" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

After launch, monitor enrollments and conversions:

* `GET /api/v1/campaigns/cmp_winback01/journey-analytics` — aggregate funnel.
* `GET /api/v1/campaigns/cmp_winback01/journey/node-analytics` — per-node send, delivery, and exit counts.
* `GET /api/v1/campaigns/cmp_winback01/journey/goal/analytics` — conversion rollup.
* `GET /api/v1/campaigns/cmp_winback01/journey/holdout-lift` — causal lift versus the control group.

## See also

* [Build, simulate, and launch a campaign journey](/guides/campaign-journey-builder)
* [Segment-triggered journeys](/guides/segment-triggered-journeys)
* [Fallback chains](/guides/fallback-chains)
* [Smart-send fallback chains](/guides/smart-send-fallback-chains)
* [Incentives ledger](/guides/incentives-ledger)
* [Loyalty program](/guides/loyalty-program)
* [Holdouts and uplift measurement](/guides/campaign-holdout-uplift-measurement)
* [Choose your suppression entry point](/guides/suppression-three-entry-points)
* [Churn-risk scoring](/guides/churn-risk-scoring)
* [Campaigns API reference](/api-reference/endpoints/campaigns)


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