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.


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

FeatureDefaultDescription
enableTicketstrueAllow portal users to submit and track support tickets
enableAssetCheckouttrueAllow portal users to check out and return shared devices
enableSelfServicetrueAllow portal users to view organization devices
enablePasswordResettrueAllow portal users to reset their password via email
StatusMeaning
newTicket just submitted, not yet triaged
openTicket acknowledged and being worked on
pendingWaiting for additional information from the submitter
on_holdWork paused, awaiting external dependency
resolvedIssue fixed, awaiting confirmation
closedTicket fully closed
PriorityDescription
lowNon-urgent issue, can be addressed during normal operations
normalStandard priority (default for new tickets)
highImportant issue requiring prompt attention
urgentCritical issue requiring immediate response
StatusBehavior
activeUser can log in and access portal features
Any other valueLogin 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.

SettingValue
Session TTL24 hours (sliding)
Reset token TTL1 hour
Cookie namebreeze_portal_session
CSRF cookie namebreeze_portal_csrf_token
Auth methodsBearer token, session cookie

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

EndpointWindowMax AttemptsBlock Duration
Login5 minutes1015 minutes
Forgot password15 minutes530 minutes
Reset password15 minutes1030 minutes

Each organization can customize the portal appearance and contact information. Branding is resolved by custom domain — when a portal user visits their organization’s custom domain, Breeze serves the matching branding configuration.

FieldTypeDescription
logoUrlURLOrganization logo displayed in the portal header
faviconUrlURLBrowser tab icon
primaryColorCSS colorMain brand color
secondaryColorCSS colorSecondary accent color
accentColorCSS colorHighlight color for interactive elements
customDomainStringCustom domain for the portal (e.g., support.acme.com)
domainVerifiedBooleanWhether the custom domain has been verified
welcomeMessageTextWelcome text displayed on the portal login page
supportEmailEmailSupport contact email shown in the portal
supportPhonePhoneSupport phone number shown in the portal
footerTextTextCustom footer text
customCssCSSCustom CSS injected into the portal pages

Portal users can submit support tickets, track their status, and add comments to ongoing conversations.

  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 admin technicians can add comments to tickets. Portal users only see public comments (isPublic: true). Internal notes added by technicians with isPublic: false are hidden from 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.


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.
FieldRequiredDescription
expectedReturnAtNoISO 8601 datetime for expected return
checkoutNotesNoNotes about the checkout (max 2000 chars)
conditionNoCondition of the device at checkout (max 100 chars)
FieldRequiredDescription
checkinNotesNoNotes about the return (max 2000 chars)
conditionNoCondition 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:

FieldTypeDescription
nameString (1-255 chars)Display name
receiveNotificationsBooleanWhether to receive email notifications
passwordString (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.

MethodPathAuthDescription
POST/auth/loginNoLog in with email and password
POST/auth/forgot-passwordNoRequest a password reset email
POST/auth/reset-passwordNoReset password with a reset token
POST/auth/logoutYesLog out and invalidate the current session
MethodPathAuthDescription
GET/brandingNoGet branding for the current domain (resolved from Host header)
GET/branding/:domainNoGet branding for a specific domain
MethodPathAuthDescription
GET/devicesYesList devices in the portal user’s organization
MethodPathAuthDescription
GET/ticketsYesList tickets submitted by the current portal user
POST/ticketsYesCreate a new support ticket
GET/tickets/:idYesGet ticket details with public comments
POST/tickets/:id/commentsYesAdd a comment to a ticket
MethodPathAuthDescription
GET/assetsYesList available devices for checkout
POST/assets/:id/checkoutYesCheck out a device
POST/assets/:id/checkinYesCheck in a device
MethodPathAuthDescription
GET/profileYesGet current portal user profile
PATCH/profileYesUpdate profile (name, notifications, password)
POST/profile/passwordYesChange password (requires current password)

Portal API responses use HTTP cache headers for optimal performance.

Route TypeCache ScopeBrowser Max-AgeStale-While-Revalidate
Brandingpublic5 minutes24 hours
Devices, Tickets, Assetsprivate15 seconds90 seconds
Profileprivate15 seconds60 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.:

ActionTrigger
portal.ticket.createNew ticket submitted
portal.ticket.comment.createComment added to a ticket
portal.asset.checkoutDevice checked out
portal.asset.checkinDevice checked in
portal.profile.updateProfile updated
portal.profile.password.changePassword 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.