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

# Customer Portal After Purchases (Hosted Mode)

> Use UniBee Hosted Customer Portal to let your customers manage subscriptions, invoices, and billing information after purchases with minimal integration.

The **UniBee Hosted Customer Portal** is a secure, user-authenticated interface where your customers can **self-manage everything after purchases**, including:

* Viewing current subscriptions and plans
* Upgrading, downgrading, or cancelling subscriptions
* Updating payment methods and billing information
* Viewing invoices and payment history

Compared with the **Change Subscription After Purchases (Hosted Mode)** page—which focuses mainly on **subscription changes**—the Customer Portal is a **broader, all‑in‑one experience** for end users.

## When to Use the Customer Portal

Use the Customer Portal when you want to:

* Provide a **single entry point** for customers to manage all their billing and subscriptions
* Avoid building your own "My Account / Billing" UI
* Offer self-service experiences (change plan, update card, view invoices) after checkout
* Link to a hosted page from your app's **"Billing"** or **"Account"** menu

If you only need a focused subscription change flow for a single plan, you can still use:\
[Change Subscription After Purchases (Hosted Mode)](/documentation/business-integration/change-subscription-hosted-page-after-purchases).

## How It Works

The integration pattern is similar to the Subscription Update page:

1. Your backend calls a **Session API** to get a Customer Portal URL for a specific user.
2. Your frontend redirects the user to that URL.
3. The user completes actions in the hosted Customer Portal.
4. UniBee redirects the user back to your `returnUrl` or `cancelUrl`, and sends relevant Webhooks (e.g. subscription updated, invoice paid).

## Generate Customer Portal URL (Session API)

You generate the Customer Portal URL via the **Session API**:

**API Endpoint:** [Get Customer Portal URL](/api-reference/session/get-customer-portal-url)

```shell theme={null}
curl --location --request POST "$UniBee_API_Host/merchant/session/customer_portal_url" \
  --header "Authorization: Bearer $UNIBEE_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
    "email": "customer@example.com",
    "externalUserId": "your_user_id_123",
    "productId": 1001,
    "planId": 2001,
    "vatCountryCode": "DE",
    "returnUrl": "https://yourdomain.com/portal/success",
    "cancelUrl": "https://yourdomain.com/portal/cancel"
  }'
```

### Request Behavior

* **User identification**:
  * If `userId` is provided, UniBee uses it directly.
  * If `userId` is `0`, UniBee will try `externalUserId` first, then `email`.
  * If no user is found, the API returns `user not found`.

* **Subscription resolution**:
  * UniBee will try to find the most relevant subscription for this user (optionally filtered by `productId`):
    * Prefer the latest **active / incomplete / creating** subscription.
    * Fallback to the latest subscription record.
  * If a subscription is found, the portal URL will include `subscriptionId` so the portal can focus on that subscription.
  * If no subscription is found, the portal URL is still valid (without `subscriptionId`) and the user can start their first purchase from the portal.

* **Return URLs**:
  * `returnUrl`: where the user is redirected **after completing** actions in the portal.
  * `cancelUrl`: where the user is redirected if they **cancel or close** the portal without completing actions.

## Redirect the Customer

After calling the Session API from your backend, redirect the user to the returned URL:

```javascript theme={null}
// Example: from your backend API handler
const response = await fetch('https://api.unibee.dev/merchant/session/customer_portal_url', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.UNIBEE_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    email: customerEmail,
    productId: 1001,
    planId: 2001,
    returnUrl: 'https://yourdomain.com/portal/success',
    cancelUrl: 'https://yourdomain.com/portal/cancel',
  }),
});

const { data } = await response.json();
// In your frontend:
window.location.href = data.url; // Redirect to UniBee Customer Portal
```

## Handle Return Callback

After the customer finishes in the Customer Portal, UniBee redirects them back to your `returnUrl` (or `cancelUrl`).

You can handle the callback similarly to the checkout / subscription update flows:

```javascript theme={null}
// Example: handle return from Customer Portal
const urlParams = new URLSearchParams(window.location.search);
const success = urlParams.get('success') === 'true';

if (success) {
  // Refresh user subscriptions / invoices from your backend
  await refreshBillingData();
  showNotification('Billing information updated successfully!');
} else {
  // Optional: handle cancel case
  showNotification('Customer Portal was closed without changes.');
}
```

In addition, you should listen to corresponding [Webhooks](/documentation/webhooks/webhook-events.mdx) such as:

* `subscription.updated`
* `subscription.pending_update.success`
* `invoice.paid`

so your system can react to changes even if the frontend callback is interrupted.
