Skip to content

Customer Portal ​

The Customer Portal is the self-service site customers and reseller sub-accounts use to manage their own account, separate from the operator-facing admin app. It typically runs at portal.<domain> (for example portal.telecloud.co.za or portal.boxseats.tv) and lets a signed-in customer see their account balance, invoices, subscriptions and call/airtime usage, download statements and invoice PDFs, request or cancel services, and get help — all scoped strictly to the organisation(s) their login is linked to.

Resellers get an extra layer on top: a reseller login can also manage its own end-users ("My Customers") and log into the portal as one of them for support purposes.

What you can do ​

  • Account Overview — a summary dashboard showing account name, current balance, currency, active/suspended service counts by type, recent invoices, and (for voice customers) live airtime/wallet balance or unlimited-plan usage pulled straight from the PBX.
  • My Invoices — a read-only list of the account's sales invoices (number, customer, date, amount).
  • My Balance — the account's current balance-forward figure and currency.
  • Statement — a full Statement of Account: invoices, payments, credit notes, refunds and journal entries merged into one dated ledger with a running balance, matching the same figure the balance card shows. Each line can open the underlying invoice or payment PDF, and the whole statement can be downloaded as a branded PDF.
  • My Subscriptions — every active/suspended/cancelled service the account has, plus any "Pending Activation" orders not yet provisioned. From here a customer can open a service's management panel (hosting control panel SSO, PBX call-flow editor for phone numbers, IPTV/SMS/newsletter panels), resend the service's setup email, or self-cancel/reduce a subscription.
  • Activations — the account's own order/activation history (any status), with a self-service "Process" action to complete a still-pending order.
  • Voice usage & airtime recommendation — call volume/minutes/spend by month for the account's PBX domain(s), current airtime wallet or unlimited-plan status, and a recommended monthly airtime top-up based on recent call spend.
  • Make a Payment — a one-click link to the most recent payable invoice's public "Pay Now" page.
  • Visit Webstore — a link (with single sign-on) to the public website that fronts the account's books site.
  • Contact Us — a support form that emails the central helpdesk inbox, tagged with the customer's name, org and originating site.
  • My Customers (resellers only) — a reseller's own end-user/sub-account list, with the ability to create a new end-user, edit one, or log into the portal as them.

Common tasks ​

  1. Check what you owe — open the Overview to see the current account balance at a glance, or open My Balance / Statement for the exact figure and how it was arrived at.
  2. View or download a Statement of Account — go to Statement, review the dated list of charges and payments with running balance, then use View PDF in the toolbar to get the branded PDF version.
  3. Pay an outstanding invoice — use the Make a Payment button (Overview / account menu); it jumps straight to the newest invoice that is actually payable right now.
  4. See or manage a service — open My Subscriptions, find the row, and use Manage Service to open that service's control panel (e.g. hosting SiteWorx, PBX phone-number/call-flow editor) in a new tab or modal.
  5. Cancel or reduce a subscription — from My Subscriptions, use the row's Cancel Subscription action; cancellation is scheduled for the end of the current billing month (or, for quantity-based services like airtime blocks, you can reduce the quantity instead of cancelling the whole line).
  6. Finish a pending order — open Activations, find the row with status "Pending", and use Process to complete provisioning.

Data model ​

The portal identity layer and the commercial ("books") data live in different places and are joined at read time:

  • Tenant — the portal login's organisation record (name, id); resolved from the signed-in session / org switcher.
  • AccCustomer — the billing-side customer record on the books site; linked to a portal login via portal_tenant_id, and to a PBX domain via portal_domain_uuid. One portal login can be linked to more than one AccCustomer.
  • ResellerUser (legacy) / reseller end-user AccCustomer rows (customer_group="Reseller User") — a reseller's own sub-accounts, linked to their own tenant via portal_tenant_id and to their subscriptions via reseller_user_id.
  • Subscription — a billable service line (product, service_type, provision_type, domain/reference, qty, status); the source for My Subscriptions, service counts, phone-number listings and airtime quantities.
  • Activation — an order that hasn't yet been provisioned into a Subscription; surfaces as "Pending Activation" until processed.
  • AccSalesInvoice — sales invoices/credit notes; source for My Invoices and the Statement.
  • AccPaymentEntry — payments/refunds; source for the Statement.
  • GLEntry — general-ledger movements against the customer's receivable account; the single source of truth the Statement and the account balance are built from.
  • Balance — the account's aggregated balance-forward row (My Balance card).
  • Website — the books site's public webstore record (domain), used for the "Visit Webstore" link.

Configuration & integrations ​

  • A site is turned into a customer portal by setting is_customer_portal_site: true in its site_config.json. This blocks it from installing operator-only apps (accounting, debtors, buying, CRM) and only allows the portal app.
  • A federated portal site declares parent_site (e.g. portal → tc, bs_portal → bs) — its own database holds only identity (tenants, users, memberships), and every commercial read (app.core.instance.books_site_for) is made cross-database against the parent's books site. A self-contained customer-facing site (e.g. bs) is its own books site.
  • The portal grids are registered on sites = {"portal", "bs", "bs_portal"}; a site must be in this set (both the portal-facing site and the site whose database backs it) or its /g/portal-* menu entries disappear.
  • FusionPBX — resolved via erp_credentials.resolve_provider(db, "fusionpbx"); used for live voice wallet/unlimited-plan balances (GET /api/v1/balance/summary) and call-history stats (GET /api/v1/call-history). Best-effort — an unconfigured or unreachable PBX simply blanks the airtime/usage sections rather than breaking the page.
  • Axxess — used to fetch live data-usage summaries for lte_account subscriptions on My Subscriptions.
  • Mailer — the Contact Us form and subscription setup-email resend go through app.services.mailer / app.services.portal_org_smtp; Contact Us always targets a fixed helpdesk inbox (helpdesk@telecloud.co.za), not the site's own support email.
  • Impersonation — a reseller's "Log into Service Portal" action mints a single-use login via app.services.impersonation, provisioning the end-user's portal login on first use.

Account scoping ​

Every portal endpoint and grid scopes to the signed-in login's active organisation, resolved as a dashless tenant UUID from the X-Tenant-ID org-switcher header (falling back to the session's own tenant_uuid). A superuser who selects "All organizations" (X-Tenant-ID: all, or none) is the one exception: they see a platform-wide Operations Center view instead of any single customer's data, so a real customer's numbers are never presented under a "Superadmin" heading. A reseller end-user with no AccCustomer of its own is scoped by ResellerUser.portal_tenant_id instead, and only ever sees its own subscriptions/activations — never its parent reseller's full book.

API reference ​

Portal-specific endpoints live under /portal (app/api/portal.py):

Method & pathPurpose
GET /portal/summaryAccount Overview aggregate: balance, currency, service counts, unlocked service-portal apps, recent invoices, phone numbers, and live airtime/unlimited-plan state. Returns a platform-wide view for a superadmin on "All organizations".
GET /portal/voice-usageMonthly call-history stats and airtime wallet/unlimited status for the account's PBX domain(s), plus a recommended monthly airtime spend based on recent usage.
GET /portal/webstoreThe public website URL for the account's books site (for "Visit Webstore" / SSO order links), or null if none is published.
GET /portal/pay-linkThe "Make a Payment" link — the public pay page for the most recent invoice that's actually payable, or null.
GET /portal/document-pdf/{voucher_type}/{voucher_id}Returns a base64 PDF for one invoice (acc_sales_invoice) or payment (acc_payment_entry) belonging to the caller's own linked customer(s).
POST /portal/contactSubmits the Contact Us form; emails the central helpdesk inbox.

Everything else (invoices, balances, statement, subscriptions, activations, reseller end-users) is served through the generic grid CRUD engine at /g/{slug} (app/grids/portal.py), all self-scoping to the signed-in login's linked account(s) and read-only except for a small set of guarded row actions:

Grid slugDataNotable actions
portal-invoicesMy Invoices—
portal-balancesMy Balance—
portal-statementStatement of AccountView PDF (branded Statement PDF)
portal-subscriptionsMy Subscriptions (+ pending activations)Manage Service, Email Setup Instructions, Cancel Subscription
portal-activationsMy Activations (own orders)Process
portal-reseller-usersMy Customers (reseller end-users)New, Edit, Log into Service Portal

All grid providers and row actions independently re-verify that the row belongs to the caller's own tenant/customer before returning data, since these grids bypass the normal staff permission checks (customer_safe).

Lubb One Documentation