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

# Customer Portal

> Customers can cancel and refund subscriptions by themselves.

## What is a Customer Portal?

After every successful payment, your customers will receive an email with a link to their Customer Portal. This portal allows them to manage their subscriptions, payment methods, and personal information.

This email contains a magic link, to a completely different authentication mechanism, in which they are able to access their account which allows them to execute the aforementioned actions.

<Info>
  If you're building with Next.js, the <a href="/code/sdks/nextjs">@creem\_io/nextjs adapter</a>{" "}
  ships a `   <CreemPortal />` component and `Portal` route helper so users can open the portal directly from
  your dashboard without touching the REST API.
</Info>

<AccordionGroup>
  <Accordion icon="receipt" title="Receipt Example">
    <img style={{ borderRadius: "0.5rem" }} src="https://nucn5fajkcc6sgrd.public.blob.vercel-storage.com/Screenshot%202024-12-17%20at%2023.26.24-zus6vfFFS6vdT5GSwjjXSbinB5KWZp.png" />
  </Accordion>

  <Accordion icon="right-to-bracket" title="Magic Link Login Example">
    <img style={{ borderRadius: "0.5rem" }} src="https://nucn5fajkcc6sgrd.public.blob.vercel-storage.com/magic-link-nq675ngtIqI95c6EeGiHPa8id6D1x1.png" />
  </Accordion>
</AccordionGroup>

## What can customers do in the Customer Portal?

### 1. Cancel a subscription

Upon entering the Customer Portal, customers can cancel their subscriptions by selecting an active subscription, and clicking on the **Manage Subscription** button.
This will open a details sheet on the right side of the screen, where a **Cancel Subscription** button is available.

This will immediately cancel their subscription and they will no longer be charged for it.

<img style={{ borderRadius: '0.5rem' }} src="https://nucn5fajkcc6sgrd.public.blob.vercel-storage.com/cancel-subscription-e7svTi3ym0foZze7gG8SOa6arqIj78.png" />

### 2. Request Invoice or Support

Customers using the customer portal, can copy all details of a specific payment, including order\_ID and request support from Creem team directly without contacting the merchant.

<img style={{ borderRadius: '0.5rem' }} src="https://nucn5fajkcc6sgrd.public.blob.vercel-storage.com/customer-portal-Klxod6wVtoF6JFJdeEDPOPPxDMJ31q.png" />

### 3. Generate Customer Portal Access Programmatically

You can generate a customer portal link for your users programmatically, allowing them to manage their subscriptions directly from your application.

<Tabs>
  <Tab title="Next.js">
    **Step 1: Create the Portal Route**

    ```typescript theme={null}
    // app/portal/route.ts
    import { Portal } from "@creem_io/nextjs";

    export const GET = Portal({
      apiKey: process.env.CREEM_API_KEY!,
      testMode: process.env.NODE_ENV !== "production",
    });
    ```

    **Step 2: Use the Component**

    ```tsx theme={null}
    // components/ManageSubscriptionButton.tsx
    "use client";

    import { CreemPortal } from "@creem_io/nextjs";

    export function ManageSubscriptionButton({ customerId }: { customerId: string }) {
      return (
        <CreemPortal customerId={customerId}>
          <button className="btn-primary">Manage Subscription</button>
        </CreemPortal>
      );
    }
    ```

    <Card title="Next.js Adapter Documentation" icon="react" href="/code/sdks/nextjs">
      Learn more about the Portal component and route helper.
    </Card>
  </Tab>

  <Tab title="TypeScript SDK">
    ```typescript theme={null}
    import { Creem } from "creem";

    const creem = new Creem({
      apiKey: process.env.CREEM_API_KEY!,
      server: process.env.NODE_ENV === "production" ? "prod" : "test",
    });

    // Create customer portal link
    const portal = await creem.customers.generateBillingLinks({
      customerId: "cust_abc123",
    });

    // Redirect user to portal
    console.log(portal.customerPortalLink);
    // Output: https://creem.io/my-orders/login/xxxxxxxxxx
    ```

    You can also retrieve the customer ID by email:

    ```typescript theme={null}
    // Get customer by email first
    const customer = await creem.customers.retrieve(undefined, "customer@example.com");

    // Then create portal link
    const portal = await creem.customers.generateBillingLinks({
      customerId: customer.id,
    });

    // Redirect to portal
    window.location.href = portal.customerPortalLink;
    ```

    <Card title="TypeScript SDK Documentation" icon="code" href="/code/sdks/typescript-core">
      View the complete customer management API reference.
    </Card>
  </Tab>

  <Tab title="Better Auth">
    **Client-Side Usage:**

    ```typescript theme={null}
    "use client";

    import { authClient } from "@/lib/auth-client";

    export function ManageSubscriptionButton() {
      const handlePortal = async () => {
        const { data, error } = await authClient.creem.createPortal();

        if (data?.url) {
          window.location.href = data.url;
        }

        if (error) {
          console.error("Failed to create portal:", error);
        }
      };

      return (
        <button onClick={handlePortal}>
          Manage Subscription
        </button>
      );
    }
    ```

    <Note>
      With Better Auth, the customer is automatically identified from the authenticated session—no need
      to pass a customer ID.
    </Note>

    <Card title="Better Auth Integration" icon="lock" href="/code/sdks/better-auth">
      Learn about automatic customer identification and session handling.
    </Card>
  </Tab>

  <Tab title="REST API">
    <Warning>
      If you're in test mode, use `https://test-api.creem.io` instead of `https://api.creem.io`. Learn
      more about [Test Mode](/getting-started/test-mode).
    </Warning>

    ```bash theme={null}
    curl -X POST https://api.creem.io/v1/customers/billing \
      -H "x-api-key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "customer_id": "cust_abc123"
      }'
    ```

    ### Response

    ```json theme={null}
    {
      "customer_portal_link": "https://creem.io/my-orders/login/xxxxxxxxxx"
    }
    ```

    ### JavaScript Example

    ```javascript theme={null}
    const response = await fetch("https://api.creem.io/v1/customers/billing", {
      method: "POST",
      headers: {
        "x-api-key": "YOUR_API_KEY",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        customer_id: "cust_abc123",
      }),
    });

    const data = await response.json();
    console.log(data.customer_portal_link);
    ```

    <Card title="API Reference" icon="book" href="/api-reference/endpoint/create-customer-billing">
      View the complete endpoint documentation.
    </Card>
  </Tab>
</Tabs>
