Membership Downgrades

A downgrade takes effect at the end of the current billing cycle: the user requests it, the membership is marked pending, and the Subscription Service calls back to finalize it when the cycle ends. Error bodies are the ErrorResponse schema (error_code 9 for initiate, 10 for finalize, with an error_string) in the API Specification; the M… names below identify the branch that produced them.

Initiate

POST /{user_id}/user/membership/downgrade with downgrade_tier.

  1. Load the GrowthBook tier configuration (500 M2_CONFIG_FETCH_FAILED) and resolve the tier’s current version (400 M8_INVALID_TIER / M9_TIER_VERSION_NOT_FOUND).

  2. The user must exist (404 M3_USER_NOT_FOUND) and be ACTIVE (403 M4_USER_NOT_ACTIVE); a membership must exist (404 M5_MEMBERSHIP_NOT_FOUND).

  3. Schedule the downgrade in the Subscription Service with the tier and version; it returns the date the downgrade takes effect (500 M19_DOWNGRADE_FAILED on failure, a reply other than 201, or an unparseable date).

  4. Re-write the current membership with event MEMBERSHIP_DOWNGRADE, is_pending_downgrade true, downgrade_date and the caller-derived source (500 M18_MEMBERSHIP_RECORD_CREATE_FAILED).

  5. 201 with the membership. Its tier is still the current tier; the target tier is only known to the Subscription Service until finalization. Metric user.membership.downgrade with from_tier: and to_tier:.

Finalize

POST /{user_id}/user/membership/downgrade/finalize with downgrade_tier and downgrade_version, called by the Subscription Service at the end of the cycle. Internal only; it is not exposed to the mobile app.

  1. A membership must exist (404 M5_MEMBERSHIP_NOT_FOUND) and be pending a downgrade (403 M20_MEMBERSHIP_NOT_PENDING_DOWNGRADE).

  2. Write a new membership: <DOWNGRADE_TIER> / MONTHLY at downgrade_version, event MEMBERSHIP_DOWNGRADE_FINALIZED, caller-derived source (500 M18_MEMBERSHIP_RECORD_CREATE_FAILED).

  3. 201 with an empty body. Metric user.membership.finalize_downgrade.

Retraction

A pending downgrade is cancelled by upgrading back to the current tier, which costs nothing. A scheduled downgrade does not survive a pause: the pause record (self-service or admin) is written without is_pending_downgrade and downgrade_date, so the flag is cleared and a later finalize call is answered 403 M20_MEMBERSHIP_NOT_PENDING_DOWNGRADE. Unpause carries forward whatever the paused record holds.