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

# Customer Portal

> A self-service billing portal where your customers view their account and settle what they owe

The Customer Portal is a hosted, self-service interface that gives your customers access to their own billing data and payment actions. Customers view subscriptions, invoices, wallet balances and usage, pay outstanding invoices, top up credits, save a card and turn on automatic top-ups, without going through your support or sales team.

The portal authenticates with a short-lived session token that you generate from your backend. You control which sections a customer sees, and the portal renders under your brand colours and logo.

**Benefits:**

* **Fewer billing tickets** - Customers answer their own questions about balances, invoices and usage
* **Faster collection** - An unpaid invoice carries a Pay now button instead of a support thread
* **Uninterrupted service** - Automatic top-ups refill a wallet before the balance runs out
* **No card data on your side** - Cards are collected and stored by the payment provider's hosted page, never by Flexprice or by you
* **Tenant-controlled surface** - Each section is switched on or off per environment

<Frame>
  <img src="https://mintcdn.com/flexprice/LrvjqfDBsdgv3HTB/images/docs/customers/customer-portal/customer-portal-overview.png?fit=max&auto=format&n=LrvjqfDBsdgv3HTB&q=85&s=680f907cfb2e4ca811b5a90c30ae5579" alt="Customer Portal Overview showing the wallet balance, saved payment methods and active subscriptions" width="3024" height="1964" data-path="images/docs/customers/customer-portal/customer-portal-overview.png" />
</Frame>

## What customers can do

The portal is organised into sections shown as tabs across the top. Which sections appear is [configurable](/docs/customers/customer-portal/configuration); the defaults are below.

| Section      | Contents                                                                         |
| ------------ | -------------------------------------------------------------------------------- |
| **Overview** | Wallet balance with top-up actions, saved payment methods, active subscriptions  |
| **Usage**    | Account summary, metric cards, usage trend chart, usage breakdown, current usage |
| **Credits**  | Wallet balance, auto top-up settings, full transaction history                   |
| **Invoices** | Invoice list with status, detail drawer, PDF download, Pay now                   |

Actions available to a customer:

* **View and download invoices** with their status and line-item breakdown
* **Pay an outstanding invoice** through a hosted checkout page
* **Top up a wallet** by card, or by raising an invoice to settle later
* **Configure auto top-up** with a threshold, an amount and an optional cooloff
* **Add, remove and set a default card** through the provider's hosted card form
* **Track usage and cost** per feature over a chosen date range

Payment actions depend on a payment provider being connected for the environment. See [Portal payments](/docs/customers/customer-portal/payments) for the provider capability matrix and the full flow of each action.

<Info>
  **Session tokens expire after 1 hour**

  The portal reads a session token from the URL. Generate a fresh session each time a customer needs access rather than storing the token.
</Info>

## Generating a portal session

To give a customer access, generate a session token from your backend using your API key. The token names one customer and carries the tenant and environment, so it grants access to that customer's data only.

**Endpoint:** `GET /v1/customers/portal/{external_id}`

**Authentication:** your Flexprice API key in the `x-api-key` header

**Path parameters:**

| Parameter     | Type   | Required | Description                |
| ------------- | ------ | -------- | -------------------------- |
| `external_id` | string | Yes      | The customer's external ID |

### Example request

<CodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url https://api.cloud.flexprice.io/v1/customers/portal/cust_123 \
    --header 'x-api-key: <your_api_key>'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    "https://api.cloud.flexprice.io/v1/customers/portal/cust_123",
    {
      method: "GET",
      headers: {
        "x-api-key": process.env.FLEXPRICE_API_KEY,
      },
    }
  );

  const session = await response.json();
  console.log("Token:", session.token);
  console.log("Expires at:", session.expires_at);
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.get(
      'https://api.cloud.flexprice.io/v1/customers/portal/cust_123',
      headers={
          'x-api-key': os.environ['FLEXPRICE_API_KEY']
      }
  )

  session = response.json()
  print(f"Token: {session['token']}")
  print(f"Expires at: {session['expires_at']}")
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "url": "https://portal.yourapp.com?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_at": "2025-01-06T17:27:17Z"
}
```

| Field        | Type   | Description                                         |
| ------------ | ------ | --------------------------------------------------- |
| `token`      | string | JWT used to authenticate customer portal requests   |
| `url`        | string | Portal URL with the token already attached          |
| `expires_at` | string | ISO 8601 timestamp at which the token stops working |

### Redirecting a customer

Send the customer to the `url` field. The portal reads the token from the query string and authenticates on load.

```javascript theme={null}
const session = await response.json();
window.location.href = session.url;
```

<Warning>
  **Do not put the portal URL in a shared or logged location**

  The URL carries the session token. Anyone holding it can act as that customer until it expires. Generate the link at the moment the customer clicks through to it, and do not email a raw portal URL to a shared inbox.
</Warning>

### Handling expiry

Read `expires_at` and generate a new session when the token has passed it:

```javascript theme={null}
const session = await response.json();

if (new Date(session.expires_at) > new Date()) {
  window.location.href = session.url;
} else {
  // Request a new session and redirect again
}
```

### Embedding the portal

The portal renders inside an iframe:

```html theme={null}
<iframe
  src="https://portal.yourapp.com?token=<session_token>"
  width="100%"
  height="800px"
  frameborder="0"
>
</iframe>
```

<Note>
  Hosted checkout pages open in a new browser tab, not inside the iframe. Payment providers block being framed. The portal handles the hand-off and the return automatically, described in [Portal payments](/docs/customers/customer-portal/payments#returning-from-a-hosted-checkout).
</Note>

## Opening the portal from the dashboard

You can open a customer's portal from the Flexprice dashboard without writing any code.

### From the Customers page

1. Go to **Customers**
2. Find the customer in the table
3. Click the three-dot menu at the end of the row
4. Select **Open Customer Portal**

A session is generated and the portal opens in a new tab.

<Frame>
  <img src="https://mintcdn.com/flexprice/aQYG_jSalnKlR10I/images/docs/customers/customer-portal/open-customer-portal.png?fit=max&auto=format&n=aQYG_jSalnKlR10I&q=85&s=c20562541aba73d11fec419cadd0e7b5" alt="Customers Page with Portal Option" width="1932" height="632" data-path="images/docs/customers/customer-portal/open-customer-portal.png" />
</Frame>

### From the customer details page

1. Go to **Customers** and click a customer
2. Open the **Information** tab
3. In the Customer Details section, click the share icon to copy the portal link

<Frame>
  <img src="https://mintcdn.com/flexprice/aQYG_jSalnKlR10I/images/docs/customers/customer-portal/customer-details-page.png?fit=max&auto=format&n=aQYG_jSalnKlR10I&q=85&s=218ca5ff0f812ee41d27cdbd61603a5c" alt="Customer Details Page" width="1970" height="648" data-path="images/docs/customers/customer-portal/customer-details-page.png" />
</Frame>

<Tip>
  The copied link contains a session token that expires after 1 hour. Share it through a channel the customer controls, and generate a new one if they come back later.
</Tip>

## Section reference

### Overview

The default landing section. It answers three questions in one screen: what the balance is, how it gets paid, and what the customer is signed up to.

* **Wallet balance** with credits, monetary value, and Add credits and Pay now actions
* **Payment methods** listing saved cards, with Add card, Set as default and Remove
* **Subscriptions** showing plan name, status, current period and next billing date

<Frame>
  <img src="https://mintcdn.com/flexprice/LrvjqfDBsdgv3HTB/images/docs/customers/customer-portal/payment-methods.png?fit=max&auto=format&n=LrvjqfDBsdgv3HTB&q=85&s=2df720a543a3150c424b4e94b1ff24be" alt="Saved payment methods on Overview, with the default card marked and the row actions open" width="2252" height="604" data-path="images/docs/customers/customer-portal/payment-methods.png" />
</Frame>

### Usage

Feature-level consumption and cost over a date range. When features are assigned to [groups](/docs/product-catalogue/groups), the usage breakdown is grouped accordingly.

* **Account summary** with balance, amount due and next billing date
* **Metric cards** for revenue and any custom analytics metrics
* **Usage trend** chart, with a date preset selector and optional custom range
* **Usage breakdown** table of feature, total usage, events and total cost
* **Current usage** for the in-progress billing period

<Frame>
  <img src="https://mintcdn.com/flexprice/8GOxYJf7UE7fMqwf/images/docs/groups/customer-portal.png?fit=max&auto=format&n=8GOxYJf7UE7fMqwf&q=85&s=0174bdd2b39ba49e77d77022d40b2368" alt="Customer Portal Usage" width="3420" height="1958" data-path="images/docs/groups/customer-portal.png" />
</Frame>

<Warning>
  Cost and margin metric cards are switched off by default. They show your cost to serve the customer and your margin on them, which are not the customer's numbers to see. Turn them on only for an internal-facing portal.
</Warning>

### Credits

The prepaid wallet in full.

* **Wallet balance** in credits and monetary value, with the wallet status
* **Auto top-up** summary and settings
* **Transaction history** listing each credit and debit with date, expiry, priority and amount

<Frame>
  <img src="https://mintcdn.com/flexprice/aQYG_jSalnKlR10I/images/docs/customers/customer-portal/credits.png?fit=max&auto=format&n=aQYG_jSalnKlR10I&q=85&s=fdbf841fef7fcf56257eb7d125691e10" alt="Customer Portal Credits" width="2066" height="1678" data-path="images/docs/customers/customer-portal/credits.png" />
</Frame>

### Invoices

Every invoice raised against the customer.

* **Invoice table** with date, invoice number, status, amount and row actions
* **Detail drawer** showing amount due, billing period, issue and due dates, line items, subtotal, discount, tax and total
* **Download** as PDF, available once an invoice is finalized
* **Pay now**, shown when the invoice is awaiting payment and a provider is connected

Invoice rows show each invoice in its own currency, so a customer billed in more than one currency reads the correct symbol on every row.

<Frame>
  <img src="https://mintcdn.com/flexprice/LrvjqfDBsdgv3HTB/images/docs/customers/customer-portal/pay-now.png?fit=max&auto=format&n=LrvjqfDBsdgv3HTB&q=85&s=5d9c5cc342522d3c78d4dfba9e8131b4" alt="Customer Portal Invoices with per-row currency and the row action menu showing Pay now" width="2274" height="906" data-path="images/docs/customers/customer-portal/pay-now.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/flexprice/LrvjqfDBsdgv3HTB/images/docs/customers/customer-portal/invoice-details-drawer.png?fit=max&auto=format&n=LrvjqfDBsdgv3HTB&q=85&s=061d327c3bfdca03f000ed25c62892cd" alt="Invoice detail drawer showing amount due, billing period, line items, totals, and the Pay and Download actions" width="3024" height="1964" data-path="images/docs/customers/customer-portal/invoice-details-drawer.png" />
</Frame>

## Security model

| Control               | Behaviour                                                                                                                                                                 |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Session scope**     | The token names one customer. Every portal request is scoped to that customer, and to the tenant and environment the token was issued in                                  |
| **Token lifetime**    | 1 hour from issue                                                                                                                                                         |
| **Tenant suspension** | A suspended tenant's portal stops serving requests, the same as the rest of the API                                                                                       |
| **Card data**         | Collected and stored by the payment provider's hosted page. Card details never reach Flexprice or your servers                                                            |
| **Gateway identity**  | Provider names are shown only where the customer must choose between two connected providers                                                                              |
| **Return URLs**       | The session token is stripped from the URL handed to a payment provider, so it never enters the provider's logs, referrer chain or the customer's history at the provider |
| **Amount authority**  | Invoice payments take their amount from the invoice, so a customer cannot part-pay. Top-up credit reason, expiry and priority are pinned server-side                      |

## Related resources

<CardGroup cols={2}>
  <Card title="Portal payments" icon="credit-card" href="/docs/customers/customer-portal/payments">
    Invoice payment, top-ups, auto top-up and saved cards
  </Card>

  <Card title="Portal configuration" icon="sliders" href="/docs/customers/customer-portal/configuration">
    Control which sections appear and how the portal looks
  </Card>

  <Card title="Portal API reference" icon="code" href="/docs/customers/customer-portal/api-reference">
    Every endpoint under /v1/customer/portal
  </Card>

  <Card title="Wallet top-ups" icon="wallet" href="/docs/wallet/top-up">
    How wallet top-ups work outside the portal
  </Card>

  <Card title="Auto top-up" icon="rotate" href="/docs/wallet/auto-top-up">
    Threshold-based automatic top-ups
  </Card>

  <Card title="Checkout sessions" icon="cart-shopping" href="/docs/checkout/checkout-sessions">
    The checkout session model the portal builds on
  </Card>
</CardGroup>
