---
title: "Customer portal link"
description: "Give a customer a link to read and download the invoices and credit notes they are followed up on."
canonical: https://developer.billabex.com/en/guides/customer-portal/
lang: en
alternate: https://developer.billabex.com/fr/guides/portail-client/
last-updated: 2026-09-27
---

# Customer portal link

> Give a customer a link to read and download the invoices and credit notes they are followed up on.

Source: https://developer.billabex.com/en/guides/customer-portal/
Language: English (en)
French version: https://developer.billabex.com/fr/guides/portail-client/

Every account can have a **customer portal link**: a page where the customer reads and downloads the
documents the account is currently followed up on, without an account or a password. The page lives
on the agent's domain (`https://portal.revoptim.com/...`), next to the address the reminders come
from.

## What the page shows

The page shows the **live** follow-up, recomputed on every visit, not a copy of an email:

- the invoices the reminders currently speak of: the overdue ones while something late is still
  owed, otherwise the ones to come. Invoices excluded from reminders and settled invoices never
  appear in this list;
- the credit notes that still have an amount left to use;
- the organization's bank details, except for an account paid by direct debit;
- a ZIP of all these documents, up to 200 files and 150 MB. Past that, each document stays
  downloadable on its own;
- a **history**: the invoices and credit notes settled (paid, allocated or refunded) issued in the last 12 months, up
  to 100, downloadable one by one for the customer's bookkeeping. An invoice excluded from reminders
  stays out of it, even settled. The history counts neither in the totals nor in the ZIP.

An invoice without a PDF is listed as unavailable. A document that leaves the follow-up or the
history is refused even through a download URL kept from an earlier visit.

## A permanent capability

The link names no person. **Anyone holding it** reads the account's current documents, including
future ones, until the link is **regenerated**. Disabling a contact does not take their copy back:
only a regeneration does, and it invalidates every copy at once, including the links in emails
already sent.

The secret part of the link follows the `#`. Browsers never send that part to a server, so it stays
out of access logs; store and transmit the full link as you would an API key.

## Endpoints

| Method | Path                                           | Scope                            | Behavior                                                               |
| ------ | ---------------------------------------------- | -------------------------------- | ---------------------------------------------------------------------- |
| `GET`  | `/accounts/{accountId}/portal-link`            | `accounts:read` / `accounts:all` | The current link, or `204` when none was created. Never creates one.   |
| `POST` | `/accounts/{accountId}/portal-link`            | `accounts:all`                   | The existing link, or a new one. Safe to retry: never replaces a link. |
| `POST` | `/accounts/{accountId}/portal-link/regenerate` | `accounts:all`                   | A new link. Every previous copy stops working. Not idempotent.         |

Each response carries `accountId`, `url`, `version` and `issuedAt`, and is sent with
`Cache-Control: no-store`. `POST /portal-link` adds `created`, false when the link already existed.
`version` increments on every regeneration and is not a secret: keep it to tell whether a link you
stored is still the current one.

```bash
curl -X POST https://app.billabex.com/api/public/v1/accounts/$ACCOUNT_ID/portal-link \
  -H "Authorization: Bearer $TOKEN"
```

```json
{
  "accountId": "123e4567-e89b-12d3-a456-426614174000",
  "url": "https://portal.revoptim.com/123e4567-e89b-12d3-a456-426614174000#k3Jd0vXw2b1qR8mZp6TsY4nLhF9cA7eGuBoIiKjW5xA",
  "version": 1,
  "issuedAt": "2026-09-27T09:30:00.000Z",
  "created": true
}
```

The link is never part of the account resource: `GET /accounts` and `GET /accounts/{accountId}` do
not return it.

## MCP

The same three operations are available as MCP tools: `get-account-portal-link` (`mcp:read`),
`ensure-account-portal-link` and `regenerate-account-portal-link` (`mcp:write`). The regeneration is
declared destructive and non idempotent.

---

Billabex developer portal. OpenAPI specification: https://developer.billabex.com/openapi.json.
Agent instructions: https://developer.billabex.com/llms.txt. Complete documentation: https://developer.billabex.com/llms-full.txt.
