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

# End-to-end migration flow

> What happens when a subscriber migrates — from email send to web checkout to entitlement sync. The execution flow that ties the integration pages together.

The migration flow is the choreography across Recurr's integration mechanisms: a subscriber clicks an email link, lands at branded checkout, completes payment, and the app starts seeing them as a web subscriber. This page traces the full sequence so a CTO can map "if X breaks, which page do I check."

## The sequence

<Steps>
  <Step title="Migration email lands">
    Email sends from the customer's domain via Resend (Recurr's transactional email rail). Subject and body are co-authored with the customer during pilot scoping; the rendered email points subscribers at the customer's branded checkout URL with an identity-binding token.

    Failure modes: bounce, spam-folder, delete-without-opening. Recurr's CX layer monitors deliverability; bounce rates above baseline trigger investigation before the next wave.
  </Step>

  <Step title="Subscriber clicks link → branded checkout loads">
    Subscriber arrives at `subscribe.{customer-domain}.com` (or whichever subdomain is configured). The page is Recurr-hosted but serves on the customer's DNS, with the customer's branding.

    See: [Branded checkout](/integration/branded-checkout).
  </Step>

  <Step title="Identity bridge matches subscriber to app account">
    The identity-binding token in the URL matches the subscriber's web checkout session to their existing app-store account. Sign in with Apple, Sign in with Google, or custom OAuth — depending on the customer's authentication setup — completes the bridge.

    For \~99% of subscribers, this resolves automatically. The small remainder fall back to the customer's support flow (see [risk register → identity bridge](/trust/risk-register#identity-bridge--subscriber-doesnt-complete-verification)).

    See: [Identity continuity](/integration/identity-continuity).
  </Step>

  <Step title="Stripe Connect processes the charge">
    Subscriber enters payment method. Stripe Checkout runs in the customer's Stripe Connect account. The customer is Merchant of Record — Recurr never sits in the legal payment chain. Recurr's platform fee (3.5%) and migration performance fee (2.5%) accrue as `application_fee` line items on the charge.

    See: [Stripe Connect](/integration/stripe-connect).
  </Step>

  <Step title="Entitlement sync writes new web subscription state">
    Before the app-store cancellation lands, Recurr writes the new web subscription state to the customer's entitlement system (RevenueCat, Adapty, or custom backend). The app's runtime entitlement check is preserved — same `is_subscribed` boolean, same `plan_id`, just sourced from web now.

    See: [Entitlements sync](/integration/entitlements-sync).
  </Step>

  <Step title="App-store cancellation triggers">
    Recurr cancels the subscriber's existing app-store subscription via the Apple/Google billing rails. The cancellation propagates to App Store / Google Play as a standard subscription end-of-term event.

    The subscriber sees no in-app prompt — the cancellation is silent from their perspective. They paid on web; their app subscription transferred. The whole transaction looks like a billing-rail switch, not a cancel-and-resubscribe.
  </Step>

  <Step title="App sees active web subscription on next check">
    Next time the subscriber opens the app, the runtime entitlement check returns the same active subscription it always did — just sourced from web now. No SDK changes required on the app side, because the customer's entitlement system is the integration surface, not Recurr's.

    See: [No SDK](/integration/no-sdk).
  </Step>

  <Step title="Webhook events fire to downstream destinations">
    `subscription.activated` and (for the migration case specifically) `subscription.migrated` events fire to the customer's registered destinations — warehouse, product analytics, CDP, MMP, internal pipelines. Conversion attribution lands server-side.

    See: [API reference → events](/api-reference/events).
  </Step>
</Steps>

## What can break + where to look

| Symptom                                   | Likely surface                        | Doc to check                                                                                                     |
| ----------------------------------------- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Migration email not delivered             | Resend → customer's domain reputation | [Data handling → subscriber data](/trust/data-handling)                                                          |
| Branded checkout 404 or theme broken      | DNS CNAME + theme config              | [Branded checkout](/integration/branded-checkout)                                                                |
| Identity bridge fails to match subscriber | OAuth config or token expiry          | [Identity continuity](/integration/identity-continuity)                                                          |
| Payment fails                             | Stripe Connect account state          | [Stripe Connect](/integration/stripe-connect)                                                                    |
| Web sub paid but app still says expired   | Entitlement sync race condition       | [Entitlements sync](/integration/entitlements-sync)                                                              |
| Apple receipt + web sub both active       | App-store cancellation lag            | [Risk register → double billing](/trust/risk-register#double-billing)                                            |
| Conversion event not in warehouse         | Webhook delivery + retry              | [API reference → retry policy](/api-reference/overview#retry-policy)                                             |
| Subscriber stuck mid-flow                 | Identity bridge incompletion          | [Risk register → identity bridge](/trust/risk-register#identity-bridge--subscriber-doesnt-complete-verification) |

## The integration surface as a whole

The migration flow runs across 5 integration mechanisms, but the customer's engineering team touches only 4 surfaces during integration:

* **Auth provider** (RevenueCat / Adapty / custom) — for the identity bridge + entitlement sync
* **Stripe Connect** — for the payment rail (Connect account setup)
* **DNS** — for the branded subdomain CNAME
* **Webhook endpoint(s)** — for events flowing to downstream destinations

Total engineering investment in a typical pilot integration: 2-4 hours across these surfaces. Specific runbook by provider lands in the pilot kickoff pack.

## Cross-references

* [No SDK](/integration/no-sdk) — why this works without an app release
* [Stripe Connect](/integration/stripe-connect) — payment rail mechanics
* [Entitlements sync](/integration/entitlements-sync) — write path to RC / Adapty / custom backend
* [Identity continuity](/integration/identity-continuity) — OAuth and identity bridge
* [Branded checkout](/integration/branded-checkout) — subdomain + theme
* [API reference overview](/api-reference/overview) — webhook delivery + retry
* [Risk register](/trust/risk-register) — failure modes by exposure
* [Reliability](/trust/reliability) — operational error modes + incident response
