Public Ticket Portal

The public portal lets external users create and reply to tickets from your page domain.

Public URLs

Common paths:

  • Create ticket for a project: /ticket/{project_id}
  • Open ticket thread: /ticket/thread/{token}
  • Unsubscribe from notifications: /ticket/unsubscribe/{token}

These links are generated on your workspace page domain.

Public ticket creation page

The public creation page supports:

  • Reporter email and optional reporter name
  • Optional Discord sign-in on Discord-backed workspaces
  • Title and description
  • Ticket type
  • Optional initial message
  • Attachments input
  • Small attachment previews before submit/reply
  • Template-driven custom fields
  • Error state actions (Back to form / Go back) when submission validation fails
  • A direct link to project public docs (/doc/{project_id}) so reporters can self-serve before submitting

Template behavior in public creation

  • Ticket-type-specific template bindings override the project-wide enforced template as soon as the reporter selects a type
  • If the project has a default ticket type, its matching enforced template is shown immediately on first load
  • If no template is bound for the current project/type combination, no template fields are shown
  • The public form only receives public-safe template metadata for the currently active project/type binding
  • Custom ticket types use the same binding logic as standard types
  • Hidden fields, read-only fields, and backend default values are not exposed to the browser
  • Backend still applies internal defaults and validates required fields server-side

Customer preselection

If the URL includes a valid customer_token, the customer is prefilled for the ticket.

Customer intake links are project-scoped and time-limited. They only allow ticket creation in the project that was baked into the generated link. If you need the same customer to open tickets in a different project later, generate a fresh link from that project's ticket settings.

Public ticket creation does not allow adding extra notification recipients. Only the reporter is enrolled on the unauthenticated create flow.

Reporter identity options

On Discord-backed workspaces, the public create page offers two reporter modes:

  • Email, which keeps the current email-based flow
  • Discord, which opens a Discord sign-in popup and uses your Discord identity as the reporter

Email remains available and stays the default option.

Discord sign-in on the public portal:

  • uses a secure API-hosted OAuth popup instead of redirecting the whole page
  • works on Codevase page domains and customer-managed custom domains
  • does not require an existing app account
  • expires after a short time; if the Discord session has expired, sign in again before creating the ticket

Knowledge suggestions

The form shows related public knowledge documents while users type. On desktop, suggestions appear in a right-side panel and the ticket form shifts smoothly to make space. If no suggestions are available, the form stays centered.

Suggested documents open in a new tab so users stay on the ticket form.

Attachment upload behavior

When you create a ticket with attachments, files are uploaded to ticket storage as part of the create flow. Attachment entries are not stored as metadata-only placeholders.

Public portal uploads use a stricter buffered ingress limit than the internal dashboard upload flow. Very large files are rejected before the public ticket form or thread tries to persist them.

Public ticket creation is also rate-limited server-side per client/workspace. This protects the portal from anonymous ticket spam even when the browser is bypassed.

Public ticket thread page

Thread pages allow reporters/notified recipients to:

  • Read the ticket conversation
  • Send public replies
  • Upload file attachments with replies
  • Open the public create page from the top "Create new ticket" button
  • See new conversation messages automatically without manual refresh (polls every 60 seconds while the tab is open/visible)
  • See the token-resolved recipient email in the reply form (read-only)
  • See the Discord reporter name instead of the synthetic fallback email when the ticket was created from Discord
  • For Discord-created tickets, the reply form does not show a second editable name field because the reporter identity is fixed by the secure link
  • Long message text (including long URLs/tokens) wraps inside the chat bubble

Each notified email receives its own unique thread token link.

Public thread links are recipient-scoped. The portal does not expose the internal ticket-wide public token back to the reporter, and public thread actions only accept the scoped thread link token. The public thread also does not show the internal ticket id anymore. Ticket ids are treated as internal workspace references, while the public portal is identified only by the scoped thread token.

Public thread replies and attachment uploads are rate-limited server-side per scoped thread token. Attachment uploads also use a basic per-token byte quota in addition to the normal per-request file-size limits.

Reopen behavior

If a ticket is already resolved/rejected and a reporter sends a new public reply, the ticket is reopened automatically.

Unsubscribe page

Email notifications include an unsubscribe action.

The unsubscribe URL opens the public unsubscribe page and immediately processes the unsubscribe token. If the request fails (for example because the token is invalid/expired), the page shows a retry action.