flowglad-subscriptions

0
0
Source

Manage subscription lifecycle including cancellation, plan changes, reactivation, and status display. Use this skill when users need to upgrade, downgrade, cancel, or reactivate subscriptions.

Install

mkdir -p .claude/skills/flowglad-subscriptions && curl -L -o skill.zip "https://mcp.directory/api/skills/download/4641" && unzip -o skill.zip -d .claude/skills/flowglad-subscriptions && rm skill.zip

Installs to .claude/skills/flowglad-subscriptions

About this skill

<!-- @flowglad/skill sources_reviewed: 2026-01-21T12:00:00Z source_files: - platform/docs/features/subscriptions.mdx - platform/docs/sdks/subscription-management.mdx -->

Subscriptions Management

Abstract

This skill covers subscription lifecycle management including cancellation, plan changes, reactivation, trial handling, and status display. Proper subscription management ensures users can upgrade, downgrade, cancel, and reactivate subscriptions with correct billing behavior.


Table of Contents

  1. Reload After MutationsCRITICAL
  2. Cancel Timing OptionsHIGH
  3. Upgrade vs Downgrade BehaviorHIGH
  4. Reactivation with uncancelSubscriptionMEDIUM
  5. Trial Status DetectionMEDIUM
  6. Subscription Status DisplayMEDIUM

1. Reload After Mutations

Impact: CRITICAL

After any subscription mutation (cancel, upgrade, downgrade, reactivate), the local billing state is stale. Failing to reload causes UI to show outdated subscription information.

1.1 Client-Side State Sync

Impact: CRITICAL (users see incorrect subscription status)

When using useBilling() on the client, mutations update the server but the local state remains stale until explicitly reloaded.

Incorrect: assumes state updates automatically

function CancelButton() {
  const { cancelSubscription, currentSubscription } = useBilling()

  const handleCancel = async () => {
    await cancelSubscription({
      id: currentSubscription.id,
      cancellation: { timing: 'at_end_of_current_billing_period' },
    })
    // BUG: currentSubscription still shows old status!
    // UI will not reflect cancellation until page refresh
  }

  return (
    <div>
      <button onClick={handleCancel}>Cancel Subscription</button>
      {/* Shows incorrect status because we didn't reload */}
      <p>Status: {currentSubscription?.status}</p>
    </div>
  )
}

The UI continues showing the old subscription status because the local useBilling() state wasn't refreshed.

Correct: reload after mutation

function CancelButton() {
  const { cancelSubscription, currentSubscription, reload } = useBilling()
  const [isLoading, setIsLoading] = useState(false)

  const handleCancel = async () => {
    setIsLoading(true)
    try {
      await cancelSubscription({
        id: currentSubscription.id,
        cancellation: { timing: 'at_end_of_current_billing_period' },
      })
      // Refresh local state to reflect the cancellation
      await reload()
    } finally {
      setIsLoading(false)
    }
  }

  return (
    <div>
      <button onClick={handleCancel} disabled={isLoading}>
        {isLoading ? 'Canceling...' : 'Cancel Subscription'}
      </button>
      {/* Now shows correct status after reload */}
      <p>Status: {currentSubscription?.status}</p>
    </div>
  )
}

1.2 Server-Side Reload Pattern

Impact: CRITICAL (server actions may return stale data)

When performing mutations server-side and returning billing data to the client, you must fetch fresh data after the mutation.

Incorrect: returns stale billing data

// Server action
export async function upgradeSubscription(priceSlug: string) {
  const session = await auth()
  const billing = await flowglad(session.user.id).getBilling()

  await billing.adjustSubscription({ priceSlug })

  // BUG: billing object still has old data!
  return {
    success: true,
    subscription: billing.currentSubscription, // Stale!
  }
}

Correct: fetch fresh billing after mutation

// Server action
export async function upgradeSubscription(priceSlug: string) {
  const session = await auth()
  const billing = await flowglad(session.user.id).getBilling()

  await billing.adjustSubscription({ priceSlug })

  // Fetch fresh billing state after mutation
  const freshBilling = await flowglad(session.user.id).getBilling()

  return {
    success: true,
    subscription: freshBilling.currentSubscription, // Fresh!
  }
}

2. Cancel Timing Options

Impact: HIGH

Flowglad supports two cancellation timing modes. Using the wrong mode leads to billing disputes and poor user experience.

2.1 End of Period vs Immediate

Impact: HIGH (billing and access implications)

Most SaaS applications should cancel at the end of the billing period to let users keep access for time they've paid for.

Incorrect: immediately cancels without understanding impact

async function handleCancel() {
  await billing.cancelSubscription({
    id: billing.currentSubscription.id,
    // This immediately ends access!
    // User loses features they already paid for
    cancellation: { timing: 'immediately' },
  })
}

Immediate cancellation removes access right away, even if the user paid for the full month. This often leads to support tickets and refund requests.

Correct: cancel at end of period (default for most cases)

async function handleCancel() {
  await billing.cancelSubscription({
    id: billing.currentSubscription.id,
    // User keeps access until their paid period ends
    cancellation: { timing: 'at_end_of_current_billing_period' },
  })
  await billing.reload()
}

Use immediately only for specific cases like fraud prevention, user request for immediate refund, or account deletion.

2.2 User Communication

Impact: HIGH (user confusion)

When showing cancellation options, clearly communicate what each timing option means.

Incorrect: vague cancellation UI

function CancelModal() {
  return (
    <div>
      <h2>Cancel Subscription</h2>
      <button onClick={() => handleCancel('immediately')}>
        Cancel Now
      </button>
      <button onClick={() => handleCancel('at_end_of_current_billing_period')}>
        Cancel Later
      </button>
    </div>
  )
}

"Cancel Now" and "Cancel Later" don't explain the billing implications.

Correct: clear communication of timing

function CancelModal() {
  const { currentSubscription } = useBilling()
  const endDate = currentSubscription?.currentPeriodEnd

  return (
    <div>
      <h2>Cancel Subscription</h2>
      <div>
        <button onClick={() => handleCancel('at_end_of_current_billing_period')}>
          Cancel at End of Billing Period
        </button>
        <p>
          You'll keep access until {formatDate(endDate)}.
          No further charges will occur.
        </p>
      </div>
      <div>
        <button onClick={() => handleCancel('immediately')}>
          Cancel Immediately
        </button>
        <p>
          Access ends now. You may be eligible for a prorated refund.
        </p>
      </div>
    </div>
  )
}

3. Upgrade vs Downgrade Behavior

Impact: HIGH

Upgrades and downgrades have different default behaviors. Not understanding this leads to incorrect UI and user confusion.

3.1 Immediate Upgrades

Impact: HIGH (billing timing)

By default, upgrades apply immediately with prorated billing. Users get instant access to the new plan.

Incorrect: suggests upgrade happens later

function UpgradeButton({ targetPriceSlug }: { targetPriceSlug: string }) {
  const { adjustSubscription, reload } = useBilling()

  return (
    <button onClick={async () => {
      await adjustSubscription({ priceSlug: targetPriceSlug })
      await reload()
    }}>
      {/* Misleading: upgrade happens immediately, not next month */}
      Upgrade Starting Next Month
    </button>
  )
}

Correct: communicate immediate effect

function UpgradeButton({ targetPriceSlug }: { targetPriceSlug: string }) {
  const { adjustSubscription, reload, getPrice } = useBilling()
  const price = getPrice(targetPriceSlug)

  return (
    <div>
      <button onClick={async () => {
        await adjustSubscription({ priceSlug: targetPriceSlug })
        await reload()
      }}>
        Upgrade Now to {price?.product.name}
      </button>
      <p>
        Your new plan starts immediately.
        You'll be charged a prorated amount for the remainder of this billing period.
      </p>
    </div>
  )
}

3.2 Deferred Downgrades

Impact: HIGH (user expectation mismatch)

Downgrades typically apply at the end of the current billing period. Users keep their current plan until then.

Incorrect: implies immediate downgrade

function DowngradeButton({ targetPriceSlug }: { targetPriceSlug: string }) {
  const { adjustSubscription, reload } = useBilling()

  return (
    <button onClick={async () => {
      await adjustSubscription({ priceSlug: targetPriceSlug })
      await reload()
    }}>
      {/* Misleading: downgrade doesn't happen immediately */}
      Switch to Basic Now
    </button>
  )
}

Correct: communicate deferred effect

function DowngradeButton({ targetPriceSlug }: { targetPriceSlug: string }) {
  const { adjustSubscription, currentSubscription, reload, getPrice } = useBilling()
  const price = getPrice(targetPriceSlug)
  const endDate = currentSubscription?.currentPeriodEnd

  return (
    <div>
      <button onC

---

*Content truncated.*

You might also like

flutter-development

aj-geddes

Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.

644969

drawio-diagrams-enhanced

jgtolentino

Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.

593705

ui-ux-pro-max

nextlevelbuilder

"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."

319400

godot

bfollington

This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.

341398

nano-banana-pro

garg-aayush

Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.

454339

fastapi-templates

wshobson

Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.

304231

Stay ahead of the MCP ecosystem

Get weekly updates on new skills and servers.