Eviworx
Docs

Custom Forms API

The Custom Forms API manages configurable forms (CustomForm) that back ticket creation with dynamic fields. Forms are used when creating and editing tickets (web and mobile). A form consists of a JSON formSchema with fields, optional assignment (assignedTo) and multilingual labels. Base path: /api/forms.

📝
Features
✓ Active, deactivated, archived (isActive, isArchived)
✓ At most one global default form (isDefault)
✓ 1–50 fields per form (formSchema)
✓ Choice fields (options)
✓ Field visibility by role (visibleToRoles)
✓ Assignment to roles or users (assignedTo)
✓ Multilingual names and field labels
✓ Only released forms per user (/available)
✓ Start dialog for workflows (triggerSchema)
✓ Data collection steps (DATA_COLLECTION)

🔐 Auth: User login only, API keys are not accepted. All management endpoints (list, detail, create, update) require settings.editGeneral; /available requires tickets.create. See RBAC →.

Endpoints

Method Endpoint Description Permission
GET/api/formsAdmin list (filters, full fields)settings.editGeneral
GET/api/forms/availableForms for ticket creation (without management data, filtered by assignedTo and field visibility)tickets.create
GET/api/forms/:idSingle formsettings.editGeneral
POST/api/formsCreate (201)settings.editGeneral
PATCH/api/forms/:idUpdate (deactivate = isActive:false, archive = isArchived:true)settings.editGeneral

Admin list vs. /available

GET /api/forms is the admin endpoint (settings.editGeneral, all fields). GET /api/forms/available is the endpoint for ticket creation (tickets.create): the server filters by assignedTo (allRoles/roles/users), returns the forms without management data and removes fields according to visibleToRoles / hiddenForEndUsers. hiddenForEndUsers applies to users WITHOUT tickets.viewAll/editAll (so custom end-user roles count too).

List Filters (GET /api/forms)

ParameterValues
isActivetrue | false | all
isArchivedtrue | false | all
includeWorkflowTemplatestrue | false (default false)

Create Form

POST /api/forms
{
  "name": "Hardware Request",
  "description": "Form for new hardware tickets",
  "isActive": true,
  "isDefault": false,
  "formSchema": {
    "fields": [
      {
        "id": "subject",
        "type": "subject",
        "label": "Subject",
        "order": 0,
        "required": true,
        "labels": { "de": "Betreff", "en": "Subject" }
      },
      {
        "id": "device",
        "type": "text",
        "label": "Device",
        "order": 1,
        "required": true,
        "maxLength": 100,
        "visibleToRoles": ["AGENT", "ADMIN"],
        "hiddenForEndUsers": false
      }
    ],
    "assignedTo": { "allRoles": false, "roles": ["clx-role-enduser"], "users": [] },
    "names": { "de": "Hardware-Anfrage", "en": "Hardware Request" }
  }
}

Fields: name (3–100, unique), description? (max 500), formSchema (required), isActive (default true), isDefault (default false; there is at most one default form, a new one automatically replaces the previous one). formSchema.fields: 1–50 entries; assignedTo = { allRoles, roles (role IDs), users (user IDs) }. Unknown fields are rejected with 400.

Field Structure (formSchema.fields[])

FeldDescription
id, type, label, orderRequired. type is free-form (subject, category, description, text, number, email, …)
requiredMandatory field (default false) — applies in the masks AND in the API; cannot be set on an attachment field
placeholder, description, defaultValueOptional UI helpers
minLength, maxLength, validationValidation bounds (validation = free object)
visibleToRolesOnly these roles see the field (empty = all)
hiddenForEndUsersHide field for end users (default false)
labels, placeholders, descriptions, optionLabelsMultilingual variants (Record<lang, …>)

Where the requirement applies: The field rule applies in the input masks AND in the ticket API: anyone creating with formId or changing custom fields is validated server-side — required, minimum and maximum length, email, URL and phone format, plus membership in the option list. Violations are 400 FORM_SUBMISSION_INVALID; details.issues names fieldId, fieldType and a code per field (REQUIRED, MIN_LENGTH, MAX_LENGTH, INVALID_EMAIL, INVALID_URL, INVALID_PHONE, INVALID_OPTION). Only what the caller may see is checked. Values for invisible fields and unknown keys are discarded without an error.

Attachment fields do NOT take part in the validation — files are uploaded only after creation, so at creation time the requirement is not checkable. That is also why an attachment field cannot be saved as mandatory (400). Default values apply as long as nothing is entered: they appear in the response and are stored; a field with a default cannot be set to empty.

Relation to Workflows

A CustomForm can be assigned to one or more workflow templates (workflowTemplates relation). The WorkflowTemplate holds the rendered FormSchema as triggerSchema; submitted values land in the WorkflowInstance under data.trigger.*. DATA_COLLECTION steps use the same field structure and write to data.stepOutputs[stepName]. So the form supplies the FIELDS — a workflow is started through the catalog (user) or the API trigger (API key); submitting a form does not by itself start a workflow.

⚙️ Trigger types, step types and the instance data model: Workflows API →.

Related Pages
Workflows API →

start dialog (triggerSchema), DATA_COLLECTION steps

Tickets API →

Ticket creation uses /forms/available

Settings API →

settings.editGeneral grants form management

RBAC →

Permission matrix