Skip to content
Proud to collaborate with Microsoft for Startups

subscription.plan_change ​

Handles subscription upgrades and downgrades with Stripe proration

Subscription plan changes (upgrades / downgrades) with Stripe proration.

Uses context.session (SQLAlchemy session injected by the engine, ADR-011) to load subscription/plan records and to sync the plan change to the database after Stripe is updated.

States: initiated → validating → calculating_proration → awaiting_confirmation → updating_stripe → syncing → completed OR → updating_stripe (skip confirmation) canceled | failed (terminal)

Overview ​

PropertyValue
Workflow typeLinear
LibraryApp-subscription
Version2.0

Triggers ​

SourceEndpoint / EventDescription
APIPOST /api/subscriptions/{id}/change-planUser requests plan change

Input Schema ​

FieldTypeRequiredDefaultDescription
subscription_uuiduuidYes—OrganizationSubscription UUID
organization_uuiduuidYes—Organization UUID
current_plan_uuiduuidYes—Current plan UUID
new_plan_uuiduuidYes—New plan UUID
user_uuiduuidNo—User requesting the change
proration_behaviorstringNo—Stripe proration behavior (create_prorations
require_confirmationbooleanNo—Whether to require user confirmation before updating Stripe (default: True)

Output Schema ​

FieldTypeRequiredDefaultDescription
subscription_uuiduuidNo—OrganizationSubscription UUID
organization_uuiduuidNo——
new_plan_uuiduuidNo—New plan UUID applied to the subscription
current_plan_uuiduuidNo—Plan UUID at workflow start (pre-change)
user_uuiduuidNo——
proration_behaviorstringNo——
require_confirmationbooleanNo——
stripe_subscription_refstringNo——
current_plan_namestringNo——
current_stripe_product_refstringNo——
new_plan_namestringNo——
new_stripe_product_refstringNo——
app_uuiduuidNo——
initiated_atstringNo——
initiated_bystringNo——
validated_atstringNo——
new_stripe_price_refstringNo——
current_stripe_item_refstringNo——
proration_amountintegerNo—Stripe-computed proration amount in minor units
proration_detailsjsonNo—Stripe upcoming-invoice preview
proration_calculated_atstringNo——
confirmation_requested_atstringNo——
confirmation_skippedbooleanNo——
confirmedbooleanNo——
confirmed_atstringNo——
confirmed_bystringNo——
stripe_updated_atstringNo——
new_stripe_statusstringNo—Stripe subscription status after the modify call
completed_atstringNo——
canceled_atstringNo——
cancel_reasonstringNo——
failed_atstringNo——
failure_reasonstringNo——
failure_typestringNo——
failed_actionstringNo——
failed_at_statestringNo——
failed_stepstringNo——
failed_layerstringNo——
errorstringNo——
error_typestringNo——

States ​

StateInitialTerminalSuccessAuto-advanceDescription
initiatedYesNo—validate_changePlan change request received
awaiting_confirmationNoNo——Waiting for user to confirm the proration amount
calculating_prorationNoNo——Calculating proration amount from Stripe
syncingNoNo—completeSyncing updated plan to the database
updating_stripeNoNo—update_stripeUpdating subscription in Stripe
validatingNoNo—calculate_prorationValidating subscription and plan
canceledNoYesNo—User canceled plan change
completedNoYesYes—Plan change completed
failedNoYesNo—Plan change failed

State Diagram ​

Transitions ​

FromActionToDescription
initiatedvalidate_changevalidatingValidate inputs and load subscription/plan data
validatingcalculate_prorationcalculating_prorationCalculate proration via Stripe
calculating_prorationrequest_confirmationawaiting_confirmationRequest user confirmation of proration
calculating_prorationskip_confirmationupdating_stripeSkip confirmation, go directly to Stripe update
awaiting_confirmationconfirmupdating_stripeUser confirmed — proceed with Stripe update
awaiting_confirmationcancelcanceledUser canceled the plan change
updating_stripeupdate_stripesyncingUpdate Stripe subscription, then sync DB
syncingcompletecompletedSync plan to DB and mark complete
* (any state)failfailedCatch-all failure handler

Outcomes ​

OutcomeTypeDescriptionState Data Keys
completedSUCCESSPlan change completed successfullynew_plan_uuid, proration_amount, completed_at
canceledFAILUREUser canceled the plan changecanceled_at, cancel_reason
failedFAILUREPlan change failed — see failure_reasonfailed_at, failure_reason

Business Errors ​

CodeMessage Template
ORGANIZATION_NOT_FOUNDOrganization {organization_uuid} not found
SUBSCRIPTION_NOT_FOUNDSubscription {subscription_uuid} not found
SUBSCRIPTION_NOT_ACTIVESubscription is not active (status={status})
NO_STRIPE_SUBSCRIPTIONSubscription has no Stripe subscription reference
PLAN_NOT_FOUNDPlan {plan_uuid} not found or inactive
SAME_PLANNew plan is the same as current plan
DIFFERENT_APPCannot change to a plan from a different app
NO_PRICE_FOUNDNo active price found for product reference
BILLING_AUTHORIZATION_REQUIRED

State Timeouts ​

StateTimeoutAction
awaiting_confirmation1440 minfail

Alarms ​

NameTypeStateSeverityDescription
plan_change_failedstate_enteredfailedwarningSubscription plan change failed
confirmation_pendingstate_timeoutawaiting_confirmationinfoPlan change awaiting confirmation for over 1 hour

API Usage ​

bash
POST /api/workflows/start
Content-Type: application/json

{
  "workflow_type": "subscription.plan_change",
  "initial_data": {
    "subscription_uuid": "value",
    "organization_uuid": "value",
    "current_plan_uuid": "value",
    "new_plan_uuid": "value"
  }
}