Broadleaf Microservices
  • v1.0.0-latest-prod

Subscription Management

Subscription Modifications

Broadleaf provides an extensible, robust framework for handling modifications to existing subscriptions, such as editing, upgrading, downgrading, cancelling, and changing auto-renewal settings.

The foundation for these modifications is the ability to fetch a customer’s subscriptions via the CustomerSubscriptionOperationEndpoint and dynamically determine which actions are currently available. When requesting a customer’s subscriptions, you can specify that you want the available actions included in the response (via the getActions parameter). This triggers the backend to identify and attach the allowed modification actions for each subscription. For a guide on how to render this in a storefront, see Displaying a User’s Subscriptions.

How Available Actions are Identified

DefaultSubscriptionOperationService#populateSubscriptionActions identifies available modification types (e.g., DefaultSubscriptionActionType) for each subscription by:

  • First checking the current status of the subscription against the broadleaf.subscriptionoperation.service.allowed-actions-by-subscription-status properties map to see if the action is generically allowed (for example, a CANCELLED subscription cannot enter an EDIT flow).

  • If allowed by status, it then delegates to specific business rules to verify if the action makes sense contextually (e.g., verifying if the subscription product actually has upgrade options defined before allowing an UPGRADE action).

  • If all rules pass, a SubscriptionAction is added to the availableActions list on the subscription. If a rule fails, the reason is recorded so the UI can know why an action is disabled.

Initiating a Modification

To initiate a modification, the UI calls CustomerSubscriptionOperationEndpoint#modifySubscription (or the Account equivalent), passing a ModifySubscriptionRequest representing the chosen action. For examples of how this is implemented in a storefront, see:

Behind the scenes, the DefaultSubscriptionOperationService delegates this to a specific ModifySubscriptionHandler implementation. The handler validates the request and business rules, fetches the subscription, and (for complex flows like editing or upgrading) generates a new Cart pre-populated with the subscription items and details like the subscription action flow and ExistingSubscriptionDetails. This cart is then used to coordinate the modification with the user, typically directing them to a Product Details Page (PDP) equivalent or a checkout flow to finalize the changes.

Checkout & Validation

Checkout for a modification behaves similarly to the initial purchase:

  • A user must be logged in.

  • A saved payment method must be available.

  • CartSubscriptionLockActivity locks the subscription to ensure thread safety during checkout processing.

Fulfillment Workflow Activities & Handler Patterns

When a modification cart is submitted, it engages a workflow to fulfill the modification. The broadleaf-subscription-operation-services-workflow and broadleaf-order-operation-services-workflow dependencies make the following fulfillment, subscription, & billing event workflow activities available for registration. We expect subscription-modification-focused workflows to match this general structure, mixing in your own custom activities in the sequence as needed.

Sample Configuration for an Edit Workflow:

broadleaf:
  workflow:
    client:
      flows:
        fulfillmentTypeAEditWorkflow:
          description: Subscription Edit Workflow for Type-A Subscriptions
          historical-reset-enabled: true
          retry-enabled: true
      steps:
        fulfillmentTypeAEditWorkflow:
          prepareSubscriptionFulfillmentActivity:
            admin-selectable: true
            decisions:
              ok: subscriptionModificationActivity
          subscriptionModificationActivity:
            admin-selectable: true
            decisions:
              ok: subscriptionBillingEventGenerationActivity
          subscriptionBillingEventGenerationActivity:
            admin-selectable: true
            decisions:
              ok: myCustomProvisioningActivityForFulfillmentTypeA
          myCustomProvisioningActivityForFulfillmentTypeA:
            admin-selectable: true
            decisions:
              ok: releaseSubscriptionLockActivity
          releaseSubscriptionLockActivity:
            admin-selectable: true
            decisions:
              ok: fulfillmentStatusFinalizationActivity
          fulfillmentStatusFinalizationActivity:
            admin-selectable: true

Workflow Activity Descriptions:

  1. prepareSubscriptionFulfillmentActivity (broadleaf-subscription-operation-services-workflow) - Updates the subscription status to indicate it is actively being fulfilled.

  2. subscriptionModificationActivity (broadleaf-subscription-operation-services-workflow) - The primary activity for executing the requested subscription change. It evaluates the subscriptionActionFlow (e.g., EDIT, CANCEL) and delegates to a specific SubscriptionModificationHandler implementation that "can handle" the flow. This handler performs the core logic, such as modifying the subscription in the sandbox, updating items, and updating the subscription’s status.

  3. subscriptionBillingEventGenerationActivity (broadleaf-subscription-operation-services-workflow) - Responsible for aligning the subscription’s billing schedule with the new changes. It establishes a BillingEventGenerationContext and passes it to the DefaultBillingEventGenerationService. The service then delegates to a specific BillingEventGenerationHandler implementation based on the action flow to generate or negate BillingEvent records.

  4. myCustomProvisioningActivityForFulfillmentTypeA - An example of a custom workflow activity that might be executed for a specific fulfillment type to provision or de-provision a service.

  5. releaseSubscriptionLockActivity (broadleaf-subscription-operation-services-workflow) - Closes out the transaction, releasing the subscription lock and firing the LockPurgedEvent to commit the sandboxed changes to production.

  6. fulfillmentStatusFinalizationActivity (broadleaf-order-operation-services-workflow) - Updates the OrderFulfillment status to indicate that fulfillment has completed (e.g., setting it to FULFILLED).

Modification Types

For details on each specific modification action, including how the UI surfaces them, their respective ModifySubscriptionHandler implementations, and the workflow triggered upon checkout submission, see the following:

My Subscriptions User Interface

For a comprehensive guide on how a frontend storefront might consume the Subscription APIs to render a "My Subscriptions" portal — including fetching the list of subscriptions, displaying details, and wiring up buttons for each modification action — refer to the My Subscriptions UI Walkthrough.

Safe Modifications: Locking & Sandboxing

Because subscriptions involve recurring revenue and fulfillment, modifications must be handled safely to prevent race conditions or inconsistent states.

Whenever a subscription modification checkout is initiated (e.g., editing the subscription), the framework secures the subscription by acquiring a lock. This lock prevents any other concurrent modifications (like another checkout or a background billing job) from interfering.

Furthermore, modifications are not applied directly to the live subscription data. Instead, they are made within a sandboxed state (a temporary change container). When the fulfillment workflow successfully completes and releases the lock, an event is fired, causing the system to promote these sandboxed changes to the live production state. If the workflow fails, the lock is reverted, and the uncommitted sandbox changes are discarded.

For an in-depth look at this architecture, see Managing Subscription Locks & Sandbox Changes.

Prepaid Subscriptions & Delayed Actions

When managing prepaid subscriptions, mid-period modifications like downgrades, item removals, or quantity decreases present a challenge: the customer has already paid for that period’s access. Applying the change immediately would necessitate complex prorated refunds.

To solve this, Broadleaf introduced the concept of Delayed Actions. Instead of modifying the subscription instantly, these downgrades and removals are scheduled as a delayed action to be applied at the next billing cycle. When the current billing period naturally ends, the subscription billing job executes the delayed action, adjusting the subscription tier or removing the items just before generating the next BillingEvent. This ensures the customer retains the access they paid for through the end of the billing period.

Auditing Changes

As subscriptions evolve over time (status changes, edits, price changes), maintaining an audit trail is critical for customer service and compliance. The Broadleaf framework leverages its high-performance Audit Service to track these mutations.

To see how audit records are captured for trackable entities and how you can implement custom audit events, review the Audit Usage documentation.