Guides
Customer portal
A branded self-service portal where your customers sign in with an emailed code to manage subscriptions, invoices, payments and their details.
On this page
- Overview
- Enabling the portal
- Portal settings
- The portal URL
- How customers sign in
- Code and rate limits
- Customers sharing an email address
- Sending sign-in links
- What customers can do
- Subscription actions
- Invoices, receipts and statements
- Payment methods and profile
- Sessions and security
- Emails
- API: email a portal link
Overview#
The customer portal is a page on CentraPoint, carrying your branding, where your customers sign in with their email address and a one-time code. There they can see their subscriptions, invoices, payments, statement and payment methods, download PDFs, pay open invoices and, if you allow it, cancel, pause or change their subscriptions and update their contact details. There are no passwords for customers to manage.
The portal is available on plans that include the Customer portal feature (featCustomerPortal). On other plans Settings → Customer portal shows an upgrade notice, and a portal URL shows an "unavailable" page.
Enabling the portal#
The portal is off by default. Open Settings → Customer portal, tick Enable the customer portal and save. You need the settings:write permission to change the settings; users with settings:read can view them. The portal is only open to customers when all of these hold:
- your plan includes the Customer portal feature;
- the portal is enabled in the settings;
- your account is not suspended.
When it is not open, customers see "Customer portal unavailable" with your company email and phone, the portal sign-in API refuses requests, and emails leave out their portal button.
Portal settings#
| Setting | Default | Effect |
|---|---|---|
| Enable the customer portal | Off | Opens the portal to customers. When off, the portal shows an unavailable page and emails omit the portal button. |
| Cancel subscriptions (and undo a scheduled cancellation) | On | Shows the Cancel subscription and Keep my subscription actions. |
| Pause and resume subscriptions | Off | Shows the Pause subscription and Resume subscription actions. |
| Change plan within the same package (upgrade / downgrade) | On | Lets customers move to another plan in the same package. |
| Update their name, phone, company, billing email and address | On | Makes the Profile page editable. When off it is read-only. |
| When a customer cancels | At the end of the current period | At the end of the current period stops renewal and the customer keeps access until the paid period (or trial) ends. Immediately ends the subscription straight away. |
| Support message | Empty | Up to 1000 characters, shown at the bottom of every portal page (for example how to reach your support team). |
The settings page also shows the number of customer sign-ins in the last 30 days. The portal uses your Settings → Branding logo, primary colour and icon, and your company name, email and phone.
The portal URL#
Each account has one portal address, built from your account slug:
https://app.centrapoint.co.za/portal/{your-account-slug}Settings → Customer portal shows the exact URL with a Copy URL button (and Open portal while it is live). Link to it from your website, or send it to customers as described below. Portal pages are marked noindex so search engines do not list them.
How customers sign in#
- The customer opens the portal URL and enters their email address.
- If the address belongs to an active customer of yours, CentraPoint emails a 6-digit code using the
portal_otptemplate. The response is the same whether or not the address is known ("If that email is registered with us, a sign-in code is on its way."), so the portal never reveals who your customers are. - The customer types the code. Spaces and dashes are ignored. A correct code starts a session and opens the overview.
Customers sign in with the customer record's email field (matched case-insensitively). The separate billing email is not used for sign-in. Inactive customers cannot sign in.
Code and rate limits#
| Rule | Value |
|---|---|
| Code format | 6 digits, uniformly random (leading zeros kept) |
| Code lifetime | 10 minutes |
| Wrong guesses per code | 5, then the code is locked and a new one must be requested |
| New code requested | Every earlier unused code for that customer stops working |
| Code requests per IP address | 10 per 15 minutes |
| Code requests per email address | 3 per 15 minutes |
| Code checks per IP address | 30 per 15 minutes |
Going over a request limit returns "Too many code requests. Please wait a few minutes and try again.". Only a keyed hash of each code is stored, never the code itself.
Customers sharing an email address#
Customer email addresses are not unique, so several active customers can have the same one. When that happens, the portal signs the person in as one customer: the active customer with that email whose record was most recently updated (latest updatedAt). If two records have the same update time, the most recently created one wins. The customer sees only that record's subscriptions, invoices and payments.
Sending sign-in links#
You can email a customer the portal address from their page in the dashboard: Customers → customer → Customer portal → Email portal link (needs customers:write). The same card shows the customer's last portal sign-in and a Copy portal URL button. From your own system, use the portal link endpoint.
The email uses the portal_link template. The link is the plain portal URL, not a one-click login: the customer still signs in with an emailed code. It is not sent when the portal is not open, the customer is inactive, the template is disabled, or email delivery fails.
What customers can do#
| Page | Contents |
|---|---|
| Overview | Account code, number of active subscriptions, outstanding balance (per currency), next payment, and a list of unpaid invoices and upcoming subscription charges. |
| Subscriptions | Every subscription with plan, price, status, dates, payment method and plan features, plus the actions you allow. |
| Invoices | All issued invoices (drafts are never shown) with status, total and balance, a PDF download and Pay now for open invoices. |
| Payments | Completed, refunded, pending and failed payments, with a Receipt PDF for completed and refunded ones. |
| Statement | Account statement for a chosen period (default the last 90 days, at most 5 years), with a PDF download. |
| Payment methods | Read-only list of debit order mandates and stored cards. |
| Profile | Contact and billing details, editable if you allow it. |
Subscription actions#
| Action | Needs setting | When offered |
|---|---|---|
| Cancel subscription | Cancel subscriptions | The subscription has not ended and is not already set to end. The customer can give an optional reason, recorded on the subscription. Whether it ends now or at period end follows When a customer cancels. |
| Keep my subscription | Cancel subscriptions | The subscription is set to end at period end; this undoes the scheduled cancellation. |
| Pause subscription | Pause and resume | Status is active or past due, and it is not set to end. |
| Resume subscription | Pause and resume | Status is paused. |
| Change plan | Change plan | Status is active or trialling and it is not set to end. Only enabled plans in the same (enabled) package and currency are offered, excluding contact-us plans. Options are labelled Upgrade or Downgrade by price per day. The new price applies from the next billing date. |
These actions use the same logic as the dashboard (see Packages, plans & subscriptions), so the usual subscription emails and webhooks follow. When a setting is off, the action is hidden and the portal tells the customer to contact you.
Invoices, receipts and statements#
Customers can download their own invoice, receipt and statement PDFs, the same branded documents you get in the dashboard (see Tax & PDF documents). Pay now on a sent or overdue invoice with a balance opens the invoice's payment page. Every download and action is limited to the signed-in customer's own records.
Payment methods and profile#
Payment methods is read-only. It lists debit order mandates that are not cancelled (masked account number, bank, amount, debit day, next debit date and status) and cards stored with a gateway (the card details stay with the gateway). Customers are asked to contact you to change bank or card details.
With Update their name, phone, company, billing email and address on, customers can edit first name (required), last name, phone, company, billing email and address. The sign-in email cannot be changed in the portal. Changes are recorded in your audit log with source portal.
Sessions and security#
- A session lasts 24 hours and slides forward while the customer uses the portal (an open portal tab keeps it alive every 10 minutes while visible). When it ends the customer is sent back to sign-in.
- The session is a random token in an
HttpOnly,SameSite=Laxcookie (Securein production) namedcp_portal_<slug>, scoped to your portal pages and the portal API. Only a hash of the token is stored. - Sign out ends the session immediately. Deactivating a customer signs them out of every session.
- Expired codes and sessions are deleted by a daily job (01:00 South African time). Each successful sign-in is written to the audit log.
Emails#
| Template slug | Used for |
|---|---|
portal_otp | The sign-in code (placeholders include {{code}} and {{minutes}}). |
portal_link | The portal link sent by staff or the API ({{portalUrl}}). |
welcome | New customers created at checkout; includes an Open customer portal button while the portal is open. |
subscription_* | Subscription emails that use {{portalUrl}} (activated, trial ending, renewing soon, expiring, expired) show their portal button only while the portal is open. |
Edit or disable them under Settings → Email → Templates. See Email & templates. Disabling portal_otp stops customers from signing in.
API: email a portal link#
/api/v1/customers/{id}/portal-linkEmails the customer the portal sign-in link (the portal_link template) and returns the URL. Send no body (or an empty JSON object; any other field is rejected with 400). Requires a plan with the REST API. The request is not idempotent: each call sends another email, and an Idempotency-Key header is ignored.
curl -X POST "https://app.centrapoint.co.za/api/v1/customers/cmg2c0s7t0003cust0001abcd/portal-link" \
-H "Authorization: Bearer $CENTRAPOINT_API_KEY"{
"object": "portal_link",
"customerId": "cmg2c0s7t0003cust0001abcd",
"url": "https://app.centrapoint.co.za/portal/acme-hosting",
"sent": true
}| Status | error | Meaning |
|---|---|---|
200 | - | Email sent. Body: object, customerId, url, sent: true. |
404 | not_found | No customer with this ID in your account. |
409 | portal_disabled | The portal is not open (not enabled, not on your plan, or account suspended). |
422 | not_sent | The email was not sent: the customer is inactive, the portal_link template is disabled, or delivery failed. The body includes url so you can share it another way. |
Other errors follow the usual error format. The customer must still sign in with an emailed code, so the returned URL is safe to show in your own app.