Features
Customer request forms
On this page
Request forms collect the details your team needs alongside a customer's subject and message. Publish several forms, such as Order problem, Refund and Technical, using the same custom ticket fields your team uses in the inbox.
Build and publish a form
- Define the custom fields in Settings → Tickets. Supported types are text, whole number, decimal, date, dropdown, multi-select, checkbox and pattern-validated text. Choose bounds, choices and validation there.
- Open Settings → Request forms and choose New request form. Enter the Form name, Description, Default language code and Submit button label.
- Under Fields & conditions, add ticket fields in the order customers should complete them. Subject and Message are always required. Choose Require for any additional field the customer must complete. A field required by its ticket definition remains required on the form.
- To ask a follow-up question only for certain answers, select Show only when a condition matches. Choose an earlier field and a comparison: Equals, Does not equal, Includes for a multi-select, or Has a value. For example, show a required Order number only when Request type equals Order problem. A required conditional field is required only while it is shown.
- Under Languages, edit the customer labels, help text and choice labels. Choose Add language to add translations of those labels, the form name, description and submit button. Empty translations use the default wording; translating a choice label preserves its stored value.
- Select Publish this form, then Create form or Save changes. Leave it unpublished to keep a draft. Deleting a form removes it from customer use; requests already submitted remain in the inbox.
Only owners and admins manage forms. A public form can use only fields available to every role; fields with restricted read or write roles cannot be added. If a field becomes restricted later, its form is no longer offered publicly.
Send a request
Customers open /help/:project/requests, choose a published form and language,
and complete its questions. Signed-in customers can also start at
/portal/:project/requests/new. The widget's request-form link opens the same
customer flow. See Customer portal for sign-in and replies.
Visitors first verify their email through the portal sign-in link. A bot check is
required for anonymous submissions. A verified customer session lets a signed-in
customer submit without Turnstile, even when the installation has no Turnstile
keys. Anonymous submissions need both FORMS_TURNSTILE_SITE_KEY and the private
FORMS_TURNSTILE_SECRET_KEY, as well as working outbound email. Without either
Turnstile key, or when verification cannot be completed, anonymous requests are
refused; there is no bypass. Request and message rate limits also apply.
The server validates the selected form, field types, required answers, bounds, patterns and conditions. A refused submission identifies the failing field. Sending an unknown field or an answer to a hidden conditional question is also refused. Accepted custom answers are stored as typed ticket values for the inbox and the existing ticket-field filters and rules. Changing a form does not rewrite values on earlier requests.
Route requests and apply service commitments
Workflow conditions can match form_id and field:<ticket-field-id> together,
so two forms with the same answer can route to different teams. The form ID is
read from the admitted submission, rather than supplied as a ticket attribute.
The SLA policy API at /api/dashboard/projects/:projectId/sla-policies accepts
conditions.form_ids (any listed form) and conditions.fields (all listed typed
answers). For example, fields: {"priority-field-id": "urgent"} matches that
exact stored answer. Numbers and booleans retain their types; multi-select lists
match their complete stored list in order. Empty conditions match any value.
References must belong to the workspace, field values must pass the field's
validation, and restricted fields cannot be used. If a field becomes restricted,
its values no longer select that SLA. Existing policies without these conditions
keep their behavior. The settings screen displays these conditions and preserves
them when editing a policy; configure these two conditions through the API.
API reference
Public form definitions are available through GET /api/forms/:projectId and
GET /api/forms/:projectId/:formId. Use ?locale=es, for example, to request an
available translation. Responses include the localized labels, stable field and
choice values, required flags, conditions, validation and available locales.
Submit with POST /api/forms/:projectId/:formId/submissions. The request has
subject, message, fields keyed by ticket-field ID, and a unique localId.
An optional cc array admits up to 50 unique email addresses already independently
proven to this workspace by signed customer identity or authenticated customer mail.
Valid unknown, ambiguous, unavailable, unproven or other-workspace addresses are
silently omitted. The public response never reports which CCs qualified. Malformed
addresses still return a 422 validation error. A normalized duplicate of the
requester is skipped. Typing an address creates no contact and proves no identity.
The CC set is part of the immutable command. The requester and admitted CCs receive
one separately addressed acknowledgment, including when the same command is
replayed after a restart. No recipient sees another recipient’s address.
Anonymous requests supply turnstileToken from the bot check, but a successful
bot check alone does not create a request: the customer must still verify their
email. Signed-in submissions use the portal cookie established by email
verification and do not require turnstileToken. Without that verified session,
the API returns email_verification_required after a successful bot check; it
does not accept an email address as proof.
The customer's identity comes from the portal session, rather than a contact ID
supplied in the body.
Workspace management uses /api/forms/projects/:projectId/forms: GET lists
forms and eligible ticket fields, POST creates a form, and PUT, PATCH or DELETE
on /:formId changes or deletes it. Updates include the last read updatedAt;
a stale form or changed field definition is refused. These routes require the native workspace
session and current permissions. A form definition contains title,
description, submitLabel, locale, enabled, fields and translations.
Each field references fieldId and required, with an optional condition
containing fieldId, operator and, except for present, value. Translations
are keyed by locale; their fields entries are keyed by field ID, including
subject and message, and contain label, description and choice options.
Owners and admins with settings permission can inspect the latest 100 saved
versions with GET /api/forms/projects/:projectId/forms/:formId/versions.
History also respects the current read permissions of its referenced fields.
Each version records its save time, actor, previous version, form configuration
and the referenced field definitions, in the same transaction as the save.
Updates that lose a permission or stale-definition check create no version.
The history uses the existing portable audit store and its custody rules; it
starts with saves made after this capability was installed. Deleted forms retain
their recorded history. To reuse a prior configuration, read the current form,
copy the saved config into an ordinary update and supply the current
updatedAt; this makes a new version and still validates current fields.
Existing tickets retain their original typed values when forms change.
The corresponding ticket-field definitions have a history API at
GET /api/management/projects/:projectId/ticket-fields/:id/versions, with the same
settings authority and the field's read permissions. Accepted edits retain their
prior definitions and must validate every existing value. A field with stored
ticket values cannot be deleted; make it optional or edit it instead. This keeps
old ticket values from disappearing when a lead changes their forms.
Order/account lookup fields and a form version-history management screen are not available. Form fields reuse the current ticket-field permissions and validation; they do not introduce a separate field catalogue or grant access to company requests.