Skip to content

Customer Portal

The Customer Portal gives end-users in your managed organizations a self-service interface for common IT tasks. Portal users can view their organization’s devices, submit and track support tickets, check out and return shared assets, and manage their own profile – all without needing access to the full Breeze admin dashboard.

Each organization gets its own portal instance with customizable branding, a dedicated user directory, and granular feature toggles. Portal users authenticate with their own credentials, separate from admin accounts, and sessions are scoped to their organization.


The portal is served under the /portal path on your Breeze domain — for example, if your dashboard is at https://breeze.example.com, portal users sign in at https://breeze.example.com/portal/login. No separate hostname or DNS record is required. Share this link (or the per-quote/invoice links Breeze emails, which already point at /portal) with your end-users.

Each organization can enable or disable portal features independently through the branding configuration.

Feature Default Description
enableTickets true Allow portal users to submit and track support tickets
enableAssetCheckout true Allow portal users to check out and return shared devices
enableSelfService true Allow portal users to view organization devices
enablePasswordReset true Allow portal users to reset their password via email
Status Meaning
new Ticket just submitted, not yet triaged
open Ticket acknowledged and being worked on
pending Waiting for additional information from the submitter
on_hold Work paused, awaiting external dependency
resolved Issue fixed, awaiting confirmation
closed Ticket fully closed
Priority Description
low Non-urgent issue, can be addressed during normal operations
normal Standard priority (default for new tickets)
high Important issue requiring prompt attention
urgent Critical issue requiring immediate response
Status Behavior
active User can log in and access portal features
Any other value Login is blocked with a 403 response

Portal authentication is separate from the main Breeze admin auth system. Portal users have their own credentials stored in the portal_users table and sessions are managed through either Redis (production) or in-memory storage (development).

Sessions use 48-character tokens generated by nanoid. Each authenticated request slides the session expiry forward, keeping active users logged in.

Setting Value
Session TTL 24 hours (sliding)
Reset token TTL 1 hour
Cookie name breeze_portal_session
CSRF cookie name breeze_portal_csrf_token
Auth methods Bearer token, session cookie

The portal applies per-IP and per-account rate limiting to authentication endpoints to prevent brute-force attacks.

Endpoint Window Max Attempts Block Duration
Login 5 minutes 10 15 minutes
Forgot password 15 minutes 5 30 minutes
Reset password 15 minutes 10 30 minutes

Each organization can customize the portal appearance and contact information. Branding is resolved by domain — when a portal user visits a configured custom domain, Breeze serves that organization’s matching branding. Because custom-domain serving is not enabled yet, the shared /portal portal currently shows the default branding at the login screen; configured branding still applies to the organization elsewhere.

Field Type Description
logoUrl URL Organization logo displayed in the portal header
faviconUrl URL Browser tab icon
primaryColor CSS color Main brand color
secondaryColor CSS color Secondary accent color
accentColor CSS color Highlight color for interactive elements
customDomain String Custom domain for the portal (e.g., support.acme.com)
domainVerified Boolean Whether the custom domain has been verified
welcomeMessage Text Welcome text displayed on the portal login page
supportEmail Email Support contact email shown in the portal
supportPhone Phone Support phone number shown in the portal
footerText Text Custom footer text
customCss CSS Custom CSS injected into the portal pages

Portal users can submit support tickets, track their status, and add comments to ongoing conversations. Tickets submitted through the portal land directly in the technician Tickets queue in the Breeze dashboard, where technicians triage, assign, and respond to them.

  1. Log in to the customer portal.
  2. Navigate to the Tickets section.
  3. Click New Ticket and fill in the subject, description, and priority.
  4. Submit the ticket. A unique ticket number is auto-generated.

Tickets are automatically associated with the submitter’s portal user account and organization. Each ticket receives a unique alphanumeric ticket number for easy reference.

Both portal users and technicians can add comments to tickets. When a technician sends a public reply from the Tickets queue, it appears in the portal user’s ticket conversation. Portal users only see public comments (isPublic: true). Internal notes added by technicians with isPublic: false are never shown in the portal view.

Tickets support linking to external ticketing systems through the externalTicketId and externalTicketUrl fields, enabling integration with tools like ConnectWise, Autotask, or Zendesk.


Portal users can view their organization’s issued invoices, download the PDF, and – when you’ve connected Stripe – pay any invoice with an outstanding balance by card online.

  1. Log in to the customer portal and open Invoices.
  2. Select an invoice to see its line items, total, and balance due.
  3. Click Pay now to open a secure Stripe Checkout page and pay by card.
  4. Once payment succeeds, the invoice’s balance and status update automatically.

Only issued invoices appear in the portal – drafts are never shown. The Pay now button appears only on invoices with a balance due, and only when the partner has connected Stripe. Payments collected here settle directly into the MSP’s own Stripe account; see Online Payments for how to connect Stripe and send payment links.


The asset checkout system lets portal users borrow shared devices from their organization’s inventory and return them when finished.

  1. Navigate to Assets in the portal.
  2. Browse the list of available devices (devices not currently checked out).
  3. Select a device and click Check Out.
  4. Optionally provide an expected return date, condition notes, and checkout notes.
  5. Confirm the checkout.
  1. Navigate to Assets in the portal.
  2. Find your checked-out asset and click Check In.
  3. Optionally provide return condition notes and check-in notes.
  4. Confirm the check-in.
Field Required Description
expectedReturnAt No ISO 8601 datetime for expected return
checkoutNotes No Notes about the checkout (max 2000 chars)
condition No Condition of the device at checkout (max 100 chars)
Field Required Description
checkinNotes No Notes about the return (max 2000 chars)
condition No Condition of the device at return (max 100 chars)

Portal users can view and update their profile, change their password, and manage notification preferences.

Send a PATCH to the profile endpoint with any combination of:

Field Type Description
name String (1-255 chars) Display name
receiveNotifications Boolean Whether to receive email notifications
password String (min 8 chars) New password (replaces current)

The dedicated password change endpoint requires the current password for verification before accepting a new password. After a successful password change, all existing sessions for the user are invalidated.


All portal endpoints are mounted under /api/v1/portal. Public routes (branding, auth) do not require authentication. Protected routes require a valid portal session token.

Method Path Auth Description
POST /auth/login No Log in with email and password
POST /auth/forgot-password No Request a password reset email
POST /auth/reset-password No Reset password with a reset token
POST /auth/logout Yes Log out and invalidate the current session
Method Path Auth Description
GET /branding No Get branding for the current domain (resolved from Host header)
GET /branding/:domain No Get branding for a specific domain
Method Path Auth Description
GET /devices Yes List devices in the portal user’s organization
Method Path Auth Description
GET /tickets Yes List tickets submitted by the current portal user
POST /tickets Yes Create a new support ticket
GET /tickets/:id Yes Get ticket details with public comments
POST /tickets/:id/comments Yes Add a comment to a ticket
Method Path Auth Description
GET /invoices Yes List the organization’s issued invoices
GET /invoices/:id Yes Get invoice detail with customer-visible lines
GET /invoices/:id/pdf Yes Download the invoice PDF
POST /invoices/:id/pay Yes Start a Stripe Checkout session to pay the balance
Method Path Auth Description
GET /assets Yes List available devices for checkout
POST /assets/:id/checkout Yes Check out a device
POST /assets/:id/checkin Yes Check in a device
Method Path Auth Description
GET /profile Yes Get current portal user profile
PATCH /profile Yes Update profile (name, notifications, password)
POST /profile/password Yes Change password (requires current password)

Portal API responses use HTTP cache headers for optimal performance.

Route Type Cache Scope Browser Max-Age Stale-While-Revalidate
Branding public 5 minutes 24 hours
Devices, Tickets, Assets private 15 seconds 90 seconds
Profile private 15 seconds 60 seconds

All authenticated endpoints also return ETag headers. Clients that send If-None-Match receive a 304 Not Modified response when the data has not changed, saving bandwidth.


All mutating portal actions are recorded in the audit log with an actorType of user and actions prefixed with portal.:

Action Trigger
portal.ticket.create New ticket submitted
portal.ticket.comment.create Comment added to a ticket
portal.asset.checkout Device checked out
portal.asset.checkin Device checked in
portal.profile.update Profile updated
portal.profile.password.change Password changed

Portal login returns “Multiple portal accounts found”

Section titled “Portal login returns “Multiple portal accounts found””

This error occurs when the same email address exists in multiple organizations and no orgId was provided in the login request. The portal frontend should prompt the user to select their organization or include the orgId field in the login payload.

Verify that the domainVerified field is set to true for the organization’s branding record. Branding is only served for verified domains.

When using cookie-based authentication, ensure your frontend reads the breeze_portal_csrf_token cookie and sends its value in the x-breeze-csrf request header on every POST, PATCH, and DELETE request.

“Service temporarily unavailable” (503) on login

Section titled ““Service temporarily unavailable” (503) on login”

In production mode, portal sessions require Redis. If Redis is unreachable, the portal returns 503. Verify your Redis connection is healthy and the PORTAL_STATE_BACKEND environment variable is set correctly.

Rate limits apply per IP address and per account. After being blocked, wait for the duration specified in the Retry-After response header. Rate limit state is automatically cleared on successful login.