> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hexclave.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Subscriptions

> Switch plans with automatic proration, and cancel subscriptions

When products belong to the same [product line](https://docs.hexclave.com/guides/apps/payments/products-and-pricing.md#product-lines), customers can move between them, and Hexclave handles the proration and timing for you.

## Switching plans

For example, upgrading from Pro to Enterprise:

```typescript title="app/components/upgrade-button.tsx" theme={null}
"use client";
import { useUser } from "@hexclave/next";  // replace `next` with the correct framework SDK package

export default function UpgradeButton() {
  const user = useUser({ or: 'redirect' });

  return (
    <button onClick={async () => {
      await user.switchSubscription({
        fromProductId: "prod_pro",
        toProductId: "prod_enterprise",
        // optional: priceId, quantity (quantity > 1 requires a stackable product)
      });
    }}>
      Upgrade to Enterprise
    </button>
  );
}
```

> [!NOTE]
>
> Switching plans requires the customer to have a default payment method saved (see [Billing & Invoices](https://docs.hexclave.com/guides/apps/payments/billing-and-invoices.md)). The switch happens immediately and the charge is prorated automatically. You cannot switch to an add-on, and a [free trial](https://docs.hexclave.com/guides/apps/payments/products-and-pricing.md#free-trials) on the destination product is not applied.

## Canceling a subscription

`cancelSubscription` is called on the app instance rather than the user object:

> [tab] Client Component
>
> ```typescript theme={null}
> "use client";
> import { useHexclaveApp } from "@hexclave/next";  // replace `next` with the correct framework SDK package
>
> export default function CancelButton({ productId }: { productId: string }) {
>   const app = useHexclaveApp();
>   return (
>     <button onClick={async () => {
>       await app.cancelSubscription({ productId });
>     }}>
>       Cancel Subscription
>     </button>
>   );
> }
> ```

> [tab] Server
>
> ```typescript theme={null}
> import { hexclaveServerApp } from "@/hexclave/server";
>
> // Cancel for the current user
> await hexclaveServerApp.cancelSubscription({ productId: "prod_pro" });
>
> // Cancel for a team
> await hexclaveServerApp.cancelSubscription({
>   productId: "prod_team_plan",
>   teamId: "team-id",
> });
> ```

`cancelSubscription` is **immediate** for live, processor-backed subscriptions — access ends now. Subscriptions created in **test mode** or via [grantProduct](https://docs.hexclave.com/guides/apps/payments/granting-products.md) (no processor subscription) are marked to end at the current period end, so access continues until then.

Pass `subscriptionId` when canceling an [inline product](https://docs.hexclave.com/guides/apps/payments/granting-products.md#inline-products) that has no catalog `productId`. One-time purchases cannot be canceled; [refund](https://docs.hexclave.com/guides/apps/payments/refunds.md) them instead.

## Reading subscription state

Each subscription product returned by [`useProducts` / `listProducts`](./checkout#checking-what-a-customer-owns) carries a `subscription` field with the current period end and cancellation state, plus `switchOptions` listing the other products in the same product line the customer can switch to.

## Related

* [Checkout & Purchases](https://docs.hexclave.com/guides/apps/payments/checkout.md) - start a subscription
* [Billing & Invoices](https://docs.hexclave.com/guides/apps/payments/billing-and-invoices.md) - payment methods and billing history
* [Refunds](https://docs.hexclave.com/guides/apps/payments/refunds.md) - reverse a charge and optionally end the subscription
