Reactivation

A PAUSED user returns to ACTIVE through one of two operations. Error bodies of the collect flow are the CollectOnReactivationError schema in the API Specification.

Flow Operation Summary

MX reactivation

POST /users/{user_id}/reactivate

Admin API only. Reactivates without collecting money and unblocks Auth0.

Collect-on-reactivation

POST /{user_id}/user/collect

App flow. Collects the outstanding float and the subscription payment, then reactivates.

MX Reactivation

  1. The user must exist (404) and be PAUSED (400).

  2. The current membership (or the BASE default) is re-written with an empty status, reactivation_date now, event REACTIVATE and an empty event source.

  3. The user becomes ACTIVE and the Auth0 account is unblocked.

  4. 200 with an empty body.

Collect-on-Reactivation

The body is optional; tier defaults to base and is resolved to its current version from the GrowthBook tier config (400 INVALID_TIER when unknown).

  1. Load the user (500); an INVESTIGATE user is 405 USER_UNDER_INVESTIGATION.

  2. Load the current membership (or the base default) and apply the cooldown (405 REACTIVATION_COOLDOWN).

  3. Find the user’s fee waiver: a settlement participant matched to the user who has not forfeited and whose 18 months have not ended (program settlement; one who has not started yet qualifies), otherwise an active win-back offer, an unarchived MEMBERSHIP_WAIVER_OFFER whose expires_at has not passed (see Tags used by this service). A read failure is 500 UNEXPECTED_ERROR, so a user holding a waiver is never charged by mistake. The settlement waiver applies on its own; a win-back offer only when the body asks for it with waiver_program: winback. A win-back request is refused with 409, before anything is collected, when there is no usable offer (WAIVER_OFFER_NOT_FOUND) or the user’s membership history has a reactivation waived under winback in the last 6 months (WAIVER_RECENTLY_USED; a history read failure is 500 UNEXPECTED_ERROR).

  4. Without a waiver, Float Service payback for reactivation: 404 means no outstanding float, 402 means a partial repayment and carries amount_remaining, any other failure is 500 FLOAT_REPAYMENT_FAILED. With one, the payback is skipped and an active float stays owed.

  5. Subscription Service reactivation with the tier and version, and the waiver to write when there is one, which the Subscription Service records without checking: a settlement waiver as program and ends_at, the end of the participant’s 18 months (18 months from the start of this hour for one starting now); a win-back as program, cycles (the offer’s offer_length) and cohort: 201 created the subscription, 200 means it was already active (no subscription receipt), anything else is 500 SUBSCRIPTION_PAYMENT_FAILED. After a waived 201, a win-back offer tag gets waiver_used_at and is archived, and a settlement participant who had not started the waiver gets started_at now (failures logged). One who already started keeps their started_at, so the 18 months stay anchored to it and a reactivation never restarts them.

  6. Write the new membership (<TIER> / MONTHLY at the resolved version, empty status, reactivation_date now, waiver_program set to the waiver’s program when waived and empty otherwise, event MANUAL_REACTIVATION, empty source) and set the user ACTIVE (500 UNEXPECTED_ERROR).

  7. Persist every active Plaid item in the Transactions Service (removes their expiry); failures are logged because the user has already been charged.

  8. Ask the Underwriting Service to recalculate (failure logged).

  9. Fire the first-debit-card event.

  10. Send the receipt when anything was collected and answer 201 (no float, or float fully repaid) or 206 (a float balance remains) with full_success, amount_collected (float plus subscription, dollars) and amount_remaining.

Metrics user.membership.reactivation (tag full_success:) and prod.manual.reactivations.

Cooldown

A membership whose reactivation_date plus REACTIVATION_LIMIT_DAYS (60 days in both environments) is still in the future cannot reactivate again.

Receipt

Segment event user-reactivation-receipt:

Field Value

frequency

Subscription period from the Subscription Service, Monthly when only a float was collected

amount

Float amount collected plus the subscription amount

float_amount, sub_amount

The two components (0.00 when absent)

reactivation_date

RFC3339 timestamp

payment_type

DEBIT

mask

Last digits of the card, from the float response or the subscription response

membership_tier

Requested tier, upper-cased

Source: pkg/api/reactivations.go