Who can use this: the customer portal is built for your customers — the people you sell to. They sign in with their own email and a password your organization invites them to set up. Inside Solabooks, the team members who manage portal links and customer accounts are Owner, Manager, and Accountant. URL / Route: two distinct entry points exist:
- Account-based portal at
/customer-portal/*(customer-portal.*routes) — dashboard, invoices, quotes, orders, payments, settings.- Token-based document links at
/i/{token}(portal.*routes) and the legacy alias/portal/{token}— single-document share links sent in document emails. A separate route/q/{token}(quote.customer.*) exists for the older standalone quote share. Plan / feature gate: none — customer-portal access is part of every plan. Permissions (internal): the portal does not consume Solabooks's role-permission system; customer-portal accounts are scoped to one customer in one organization. Internal staff don't need a special permission to send a portal link — sending an invoice/quote by email automatically issues a link.
Purpose
The customer portal is the read-only (mostly) view your customers see when you share a quote, invoice, sales order, or statement with them. Two flavours coexist:
- Token-based links are stateless one-document URLs you send by email — no signup required. Best for one-off quotes or invoices.
- Account-based portal is a real login with email + password, where a customer can browse all their open and historical documents at once.
Most organizations start with token-based links and turn on the account-based portal later when their customers ask for a single login.
Token-based document links — /i/{token} and /portal/{token}
Used automatically when you click Send by email on an invoice, quote, sales order, sales receipt, refund, credit note, or statement.
What the customer sees
Opening the link shows the document on a clean public page with:
- Download as PDF (
portal.pdf). - For quotes: Accept (
portal.quotes.accept) and Decline (portal.quotes.decline) buttons. - For invoices/statements: a "Pay now" path is reserved but not always wired up to a payment gateway in this build.
- A Settings link (
portal.settings) where the customer can set or change a password to access the account-based portal. - An End access action (
portal.end) that revokes the link from the customer's side.
Lifecycle and security
- The token is a hashed random string stored against
customer_portal_links. The raw token is in the email URL only. - Token lifespan: 24 hours. After that the link returns "Link expired" and the customer can request a fresh one (see below).
- The token is bound to the document, the customer, and the organization — Solabooks verifies all three before allowing access (defence in depth).
- The customer can ask for a new link via Request access (
portal.request-access) and Send again (portal.send-again), both rate-limited (throttle:portal-recovery). - Read endpoints are rate-limited too (
throttle:portal-public). - The legacy alias
/portal/{token}accepts the same tokens for older URLs already in customer inboxes.
When you send a document
On posted documents, the Send by email action:
- Generates a fresh
customer_portal_linksrow with a new 24-hour token. - Builds the email using your active PDF template (if
pdf_templates_enabledis on), with the token URL embedded. - Sends and logs the send on the document's activity tab.
Account-based portal — /customer-portal/*
This is a full login page set scoped to one customer in one organization.
Routes (17 total)
customer-portal.login(GET) andcustomer-portal.login.submit(POST, throttledcustomer-portal-login).customer-portal.logout.customer-portal.setupandcustomer-portal.setup.submit— first-time password setup.customer-portal.forgot-passwordandcustomer-portal.forgot-password.submit— password reset request.customer-portal.reset-password.show(GET, with token) andcustomer-portal.reset-password.submit(POST).customer-portal.dashboard— landing page with totals and the most recent activity.customer-portal.invoices— open + paid invoices.customer-portal.quotes— pending and historical quotes.customer-portal.orders— sales orders.customer-portal.payments— payments the customer made or had refunded.customer-portal.settingsandcustomer-portal.settings.update.customer-portal.settings.password.
Lifecycle
- Setup tokens (
customer_portal_setup_tokens) and password-reset tokens (customer_portal_password_reset_tokens) both expire after 60 minutes. Tokens are stored hashed and consumed transactionally so they cannot be reused. - A customer's password is local to their
customer_portal_accountsrecord — there is no cross-organization sign-in for customers. - All POST endpoints are rate-limited (
throttle:customer-portal-loginandthrottle:customer-portal-password).
Inviting a customer to the account portal
- Open the customer's record (
/finance/customers/{id}). - Click Invite to customer portal. Solabooks generates a 60-minute setup token and emails the customer a link.
- The customer follows the link, sets a password, and lands on
customer-portal.dashboard.
If the customer never finishes setup, you can re-issue an invitation from the same screen.
Quote-only public link — /q/{token}
A separate, narrower share URL exists at /q/{token} (quote.customer.show, accept, decline). It is used for older quote-share emails that pre-date the canonical /i/{token} routes. The throttle bucket is throttle:quotes-public.
Behaviour and rules
- Token-based links are per document. Sending the same document twice issues two tokens.
- Account-based portal is per customer. One account can see all documents of that one customer.
- A customer who has both a portal account and a token link will see the token-link page when they click an emailed link; the portal login is not required.
- Multitenancy: each portal is scoped to one organization. A customer who works with two of your orgs will have two separate portal accounts.
- The portal does not have its own permission keys in
finance_permissions.php; access is enforced by middleware (portal.token,customer-portal.tenant,customer-portal.auth,customer-portal.guest) and by the portal services (PortalLinkService,CustomerPortalTokenService).
Permissions / restrictions
- Customers authenticate against
customer_portal_accountsrows; they do not see Solabooks roles. - Internal staff do not need a separate permission to send portal links —
sales.invoices.send,quotes.send, etc. cover the act of sending the email.
Related
- Quotes — accept / decline from the customer side.
- Invoices, Sales orders, Sales receipts — what the customer can see.
- Credit notes, Refund receipts — credit balances and refunds visible to the customer.
- Customers — invite to the account-based portal.
- Timesheets — customer-side time-approval view.
- PDF templates — designs used by portal pages.
- Documents library — files the customer can download.
- Payments — customer can see their unallocated balance.
- Reports — Customer Statement, AR Aging.
- Settings — portal config and PDF templates.