Membership Downgrades
Overview
A membership downgrade is a two-phase process. When a user requests a downgrade, the change is scheduled for the end of the current billing cycle rather than applied immediately. The Subscription Service finalizes the downgrade by calling back into the User Service once the billing cycle ends.
User requests downgrade
│
▼
Phase 1: Initiate (IsPendingDowngrade = true)
│
... billing cycle ends ...
│
▼
Phase 2: Finalize (Subscription Service callback)
│
▼
New membership record at lower tier
Phase 1: Initiate Downgrade
POST /{user_id}/user/membership/downgrade
Flow
Decode request
Fetch tier config from Growthbook ──fail──► 500 M2_CONFIG_FETCH_FAILED
│
▼
Validate tier exists in config ──fail──► 400 M8_INVALID_TIER / M9_TIER_VERSION_NOT_FOUND
│
▼
User exists and is ACTIVE? ──No──► 404 M3_USER_NOT_FOUND / 403 M4_USER_NOT_ACTIVE
│ Yes
▼
Membership record exists? ──No──► 404 M5_MEMBERSHIP_NOT_FOUND
│ Yes
▼
Downgrade subscription (Subscription Service)
Returns: downgrade_date (RFC3339)
Error? ──► 500 M19_DOWNGRADE_FAILED
│
▼
Update existing membership record:
event_type: MEMBERSHIP_DOWNGRADE
is_pending_downgrade: true
downgrade_date: <date from Subscription Service>
event_source: <caller identity>
│
▼
Write membership record (DynamoDB) ──fail──► 500 M18_MEMBERSHIP_RECORD_CREATE_FAILED
│
▼
Return 201 Created
Response 201 Created
{
"membership": {
"user_id": "user_123",
"tier": "PLUS",
"term": "MONTHLY",
"status": "",
"is_pending_downgrade": true,
"downgrade_date": "2024-02-15T00:00:00Z",
"tier_version": "v1"
}
}
Note that tier in the response reflects the current tier, not the target. The user remains on their current tier until the billing cycle ends.
Phase 2: Finalize Downgrade
Called by the Subscription Service at the end of the billing cycle. This endpoint is internal-only and must not be exposed to the mobile app.
POST /{user_id}/user/membership/downgrade/finalize
Flow
Decode request
│
▼
Membership record exists? ──No──► 404 M5_MEMBERSHIP_NOT_FOUND
│ Yes
▼
IsPendingDowngrade == true? ──No──► 403 M20_MEMBERSHIP_NOT_PENDING_DOWNGRADE
│ Yes
▼
Write new membership record:
tier: downgrade_tier (uppercased)
term: MONTHLY
version: downgrade_version
event_type: MEMBERSHIP_DOWNGRADE_FINALIZED
event_source: <caller identity>
│
▼
Return 201 Created
Error Reference
Downgrade errors use error_code: 9. Finalize downgrade errors use error_code: 10.
| Error String | Status | Description |
|---|---|---|
|
400 |
Malformed JSON in the request body |
|
500 |
Growthbook tier configuration unavailable |
|
404 |
User does not exist |
|
403 |
User must be in |
|
404 |
No membership record exists for this user |
|
400 |
Requested tier not found in Growthbook configuration |
|
400 |
Version not found within the tier config |
|
500 |
DynamoDB write failed |
|
500 |
Subscription Service failed to schedule the downgrade |
|
403 |
Finalize was called but membership is not in a pending downgrade state |
Related Pages
-
Membership Upgrades — Upgrade flow and proration
-
Membership Pause — Pause and unpause flows
-
Users & Data Model — Membership event types and DynamoDB schema
-
Event-Driven Flows —
MEMBERSHIP_DOWNGRADEandMEMBERSHIP_DOWNGRADE_FINALIZEDevents on the outbound Kinesis stream