FL

flowglad-subscriptions

Utility for handling subscription management workflows including upgrades, cancellations, and status checks.

Install

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

Installs to .claude/skills/flowglad-subscriptions

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Manage subscription lifecycle including cancellation, plan changes, reactivation, and status display. Use this skill when users need to upgrade, downgrade, cancel, or reactivate subscriptions.
192 chars✓ has a “when” trigger
Intermediate

Key capabilities

  • Synchronizes client-side state after billing mutations
  • Implements server-side reload patterns
  • Configures cancellation timing logic (immediate vs end-of-period)
  • Handles trial status expiration checks
  • Maps internal subscription status to display labels

How it works

It provides logic hooks and utility functions that force a data refresh and state validation after a subscription change is initiated.

Inputs & outputs

You give it
Subscription mutation request (upgrade, cancel, etc)
You get back
Updated subscription state

When to use flowglad-subscriptions

  • Handle a user subscription cancellation
  • Implement a plan upgrade/downgrade
  • Check user trial status

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.*

When not to use it

  • When building a custom billing engine from scratch
  • When subscription state does not require client-server synchronization

Prerequisites

Flowglad SDK installed

Limitations

  • Depends on network-synced state updates
  • Limited by the API's subscription lifecycle rules

How it compares

It enforces synchronization standards, whereas manual implementations often forget to update UI state after server-side mutations.

Compared to similar skills

flowglad-subscriptions side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
flowglad-subscriptions (this skill)16moNo flagsIntermediate
zendesk153moReviewIntermediate
zapier-workflows118moReviewBeginner
controlling-spotify73moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

Search skills

Search the agent skills registry