Configuring the Workflow Trigger Input Schema

Viktor Ristic
Viktor Ristic
  • Updated

Overview

The trigger input schema defines what data a workflow expects when it starts, and what happens when that data doesn't match. For manual triggers, it controls the form your team fills out at launch. For event, webhook, and schedule triggers, it validates incoming payloads before any nodes run.

In this article, we'll be covering what the input schema is, how to configure it, the supported field types, and how validation works at execution time.

 

Understanding what the input schema does

The input schema is a JSON Schema object attached to a workflow's trigger. It serves two purposes depending on the trigger type:

  • Validate the workflow input  — for webhook and manual triggers, the schema validates the incoming payload or input before the workflow is executed. If the input doesn't match, the execution is rejected and no workflow run is created.
  • Generate a user-friendly input form — if the workflow uses a manual trigger and the trigger has an object, the schema generates the launch form your team sees when they start the workflow from a record. Each field in the schema becomes an input in that form. Required fields must be filled in before the workflow can be launched; optional fields show (optional) next to their label.

 

Finding and editing the input schema

The input schema can be configured on the trigger node in the workflow builder.

  1. Open the workflow and click the trigger node at the top of the graph.
  2. In the configuration panel, locate the Input JSON schema section.
  3. Click the edit icon to open the JSON editor.
  4. Edit the schema and save.

Changes to the input schema take effect immediately for all new executions. If you add a required field to a workflow already in use, anyone launching the workflow — from the UI, via the API, or through the Start Workflow node — must provide that field or the launch will fail.

 

Writing the schema

The input schema follows standard JSON Schema structure. The top-level object must have type: "object" and a properties map defining each input field. Fields listed in the required array must be provided at launch.

Each field supports the following properties:

  • type — the field's data type (see field types below)
  • title — the label shown above the field in the manual trigger launch form; defaults to the field key if omitted

 

Choosing the right field type

The supported standard types are:

  • string — a plain text value
  • integer — a whole number
  • number — an integer or decimal
  • boolean — true or false
  • object — a JSON object; renders as a section label in the launch form with no editable input
  • array — a JSON array; can define items to type the array's contents

 

Setting length and format rules for text fields

For type: string fields, you can enforce how long a value must be, or require it to match a specific pattern:

  • minLength — the minimum number of characters allowed
  • maxLength — the maximum number of characters allowed
  • pattern — a regular expression (regex) the value must match
{
  "referenceCode": {
    "type": "string",
    "title": "Reference code",
    "minLength": 3,
    "maxLength": 20,
    "pattern": "^[A-Z]{3}-[0-9]{4}$"
  }
}

 

In the manual trigger launch form, these rules are validated on form submission, with a message shown below the field if the value doesn't yet satisfy the rule. For all trigger types, they're also enforced when the payload is validated at execution time.

 

Custom validation messages

By default, a failed check shows a generic, technical message — for example, Must match ^[A-Z]{3}-[0-9]{4}$ for a pattern rule, or Test is required for a missing required field. These aren't always meaningful to someone filling out the launch form.

Use errorMessage on a field to replace one or more of these default messages with your own wording. It supports four checks:

  • minLength — shown when the value is too short
  • maxLength — shown when the value is too long
  • pattern — shown when the value doesn't match the expected format
  • required — shown when the field is missing
{
  "phoneNumber": {
    "type": "string",
    "title": "Phone number",
    "pattern": "^\\+?[0-9]{7,15}$",
    "errorMessage": {
      "pattern": "Enter a valid phone number, digits only"
    }
  }
}

You can combine several at once, including alongside required:

{
  "username": {
    "type": "string",
    "title": "Username",
    "minLength": 3,
    "maxLength": 15,
    "pattern": "^[a-z0-9_]+$",
    "errorMessage": {
      "minLength": "Username must be at least 3 characters",
      "maxLength": "Username can't be longer than 15 characters",
      "pattern": "Use only lowercase letters, numbers, and underscores"
    }
  }
}

required works on any field type, not just text fields — useful for giving a clearer prompt on a checkbox, dropdown, or date field than the generic default:

{
  "cancellationReason": {
    "type": "object",
    "title": "Cancellation reason",
    "customType": "enumFromWorkflow",
    "workflowId": "workflow_4ozbvMF9xs48gZtXCeobUc",
    "errorMessage": {
      "required": "Please select a reason before continuing"
    }
  }
}

You only need to set errorMessage for the checks you want to customize — anything you leave out still falls back to the default message. errorMessage applies everywhere the schema is validated: the manual trigger launch form, and the error returned for webhook, API, and Start Workflow node executions.
 

Using custom field types

Beyond standard JSON Schema types, gaiia supports two custom field types that control both validation and how the field renders in the manual trigger launch form.

Date fields

Use customType: "date" with type: "string" to validate that a value is a date in YYYY-MM-DD format. In the manual trigger form, this renders as a date picker.

{
    "activationDate": {
      "type": "string",
      "customType": "date",
      "title": "Activation Date",
    }
  }

Workflow-populated dropdowns

Use customType: "enumFromWorkflow" to populate a field's options from a workflow's output. In the manual trigger form, this renders as a dropdown whose options are fetched by running the referenced workflow at launch time. This lets you drive dynamic option lists — such as pending billing subscriptions, available product versions, or open work orders — directly from live gaiia data rather than hardcoding values in the schema.

Required properties

Property Type Description
type "object" or "array" "object" for single-select, "array" for multi-select. No other types are supported.
customType "enumFromWorkflow" Marks this field as a workflow-resolved dropdown
workflowId string The Global ID of the resolver workflow (begins with workflow_, found in the URL when viewing the workflow's overview)
title string Label displayed above the dropdown

Optional properties

Property Type Description
refetchOnWorkflowInputsChange string[] An array of sibling field names. When any listed field's value changes, the resolver workflow is re-executed automatically to refresh the dropdown options.

Item schema

Each option returned by the resolver must conform to the { id, label, value } shape. For single-select (type: "object"), declare these properties directly on the field. For multi-select (type: "array"), declare them under items.

{
  "required": ["id", "value", "label"],
  "properties": {
    "id": { "type": "string" },
    "label": { "type": "string" },
    "value": { "type": "object" }
  }
}

 

Single-select example

{
  "cancellationReason": {
    "type": "object",
    "title": "Cancellation reason",
    "required": ["id", "value", "label"],
    "customType": "enumFromWorkflow",
    "properties": {
      "id": { "type": "string" },
      "label": { "type": "string" },
      "value": { "type": "object" }
    },
    "workflowId": "workflow_4ozbvMF9xs48gZtXCeobUc"
  }
}

Multi-select example

{
  "pendingBillingSubscriptions": {
    "type": "array",
    "customType": "enumFromWorkflow",
    "workflowId": "workflow_wXiEcAgypX6nHDLBHiwHyp",
    "title": "Pending billing subscriptions",
    "items": {
      "type": "object",
      "required": ["id", "value", "label"],
      "properties": {
        "id": { "type": "string" },
        "label": { "type": "string" },
        "value": { "type": "object" }
      }
    }
  }
}

 

Configuring the resolver workflow

The resolver workflow is a standard workflow with a Manual trigger. When the form loads, gaiia executes this workflow behind the scenes and uses its output to populate the dropdown. The resolver receives a fixed set of contextual inputs and must return options in a specific format.

Input received by the resolver workflow

The form automatically passes the following fields to the resolver workflow. You only need to declare the ones your workflow actually uses in its trigger inputJsonSchema — undeclared fields are simply not sent.

Field Type Description
searchText string The current text typed in the dropdown's search box (empty string on initial load)
currentWorkflowInput object All current field values from the parent workflow's form at the time of execution
objectId string The Global ID of the object the workflow is being launched from (e.g., the account record)
objectUuid string The object's UUID — provided for backward compatibility and usage with the V0 API

Example resolver workflow input schema declaring all available fields:

{
  "type": "object",
  "properties": {
    "objectId": { "type": "string" },
    "objectUuid": { "type": "string" },
    "searchText": { "type": "string" },
    "currentWorkflowInput": { "type": "object" }
  }
}

Only declare the fields your resolver actually needs. Each field also controls form behaviour — see below.

 

How each input field affects form behavior

  • searchText — when declared in the resolver's input schema, every keystroke in the dropdown's search box re-executes the resolver workflow with the updated text. This enables server-side filtering and disables client-side filtering. When searchText is not declared, the resolver is executed only once on mount and typing in the search box filters the loaded options client-side.
  • objectId — when declared, the form provides the Global ID of the object the workflow is launched from. When omitted, the object ID is not sent. This allows resolver workflows to also work for manual workflows that are not tied to a specific object type.
  • objectUuid — when declared, the form provides the object's UUID. Use this for backward compatibility or when working with the V0 API.
  • currentWorkflowInput — when declared, the form provides all current field values from the parent workflow's form. This lets the resolver make decisions based on what the user has already filled in. Access it in your output mapper via state.input.currentWorkflowInput.<fieldName>.

 

Output format

The resolver workflow's output mapper must return an array of objects with this shape:

[
  {
    "id": "unique_identifier",
    "label": "Display text shown in the dropdown",
    "value": { ... }
  }
]

If the output does not conform to this shape (missing id or label), the dropdown displays an error.

 

Search behavior

The dropdown always includes a search box. Its behavior depends on whether the resolver workflow declares searchText in its trigger input schema:

  • searchText declared — each keystroke re-executes the resolver workflow with the updated search text. This enables server-side filtering and is recommended for large datasets. Client-side filtering is disabled in this mode.
  • searchText not declared — the resolver workflow executes once when the dropdown first opens. Typing in the search box filters the already-loaded options client-side. This is simpler and works well for small option sets.

 

Reactive dropdowns with refetchOnWorkflowInputsChange

You can make a dropdown's options react to changes in other form fields by setting refetchOnWorkflowInputsChange on the parent workflow's field schema. This is an array of sibling field names — when any listed field's value changes, the resolver workflow is automatically re-executed and the dropdown refreshes.

Combine this with currentWorkflowInput in the resolver workflow to read the updated sibling values and return different options accordingly.

Example: product list filtered by a checkbox

A service modification workflow where available products change based on whether the user wants to see discontinued options:

{
  "type": "object",
  "required": ["productVersion", "modificationDate"],
  "properties": {
    "modificationDate": {
      "type": "string",
      "title": "Modification date",
      "customType": "date"
    },
    "productVersion": {
      "type": "object",
      "title": "Product",
      "required": ["id", "value", "label"],
      "customType": "enumFromWorkflow",
      "properties": {
        "id": { "type": "string" },
        "label": { "type": "string" },
        "value": { "type": "object" }
      },
      "workflowId": "workflow_vsqxTtR4TsVKg8BJycn1ic",
      "refetchOnWorkflowInputsChange": ["shouldDisplayNoLongerOfferedProducts"]
    },
    "shouldDisplayNoLongerOfferedProducts": {
      "type": "boolean",
      "title": "Include speed options no longer offered or not available to the customer"
    }
  }
}

When the user toggles the checkbox, the resolver workflow is re-executed. The resolver reads the checkbox value from state.input.currentWorkflowInput.shouldDisplayNoLongerOfferedProducts to decide which products to return.

 

Accessing the selected value in later steps

Once the user submits the form, the selected option is stored in state.input.<fieldName> with the full { id, label, value } shape.

  • Single-select — the value is an object:

    state.input.cancellationReason.id     // "cancellationReason_abc123"
    state.input.cancellationReason.label  // "Moving away"
    state.input.cancellationReason.value  // { ...full node data }
  • Multi-select — the value is an array:

    state.input.pendingBillingSubscriptions[0].id
    state.input.pendingBillingSubscriptions[0].label
    state.input.pendingBillingSubscriptions[0].value

 

Making fields conditional

Sometimes a field should only be required — and only shown on the launch form — when another field has a specific value. For example, a text field explaining "reason for express shipping" only makes sense once a "needs express shipping" checkbox is turned on.

Use if and then to make this happen:

{
  "type": "object",
  "properties": {
    "needsExpressShipping": {
      "type": "boolean",
      "title": "Needs express shipping"
    },
    "expressReason": {
      "type": "string",
      "title": "Reason for express shipping"
    }
  },
  "if": {
    "properties": {
      "needsExpressShipping": { "const": true }
    }
  },
  "then": {
    "required": ["expressReason"]
  }
}

With this schema, Reason for express shipping stays hidden on the launch form until Needs express shipping is checked. Once checked, the field appears and must be filled in before the workflow can be launched.

If can compare against any value — not just true/false. This also works with dropdowns, text fields, and workflow-populated dropdowns (see Workflow-populated dropdown above):

{
  "if": {
    "properties": {
      "contactMethod": { "const": "phone" }
    },
    "required": ["contactMethod"]
  },
  "then": {
    "required": ["phoneNumber"]
  }
}

Important: always list the condition field itself in the if block's own required array (as shown above), unless it's a checkbox. Without it, a workflow launched with that field left empty may still be rejected as if the condition were met, even though nothing was selected on the launch form. Checkboxes don't need this — they always start unchecked (false), so there's no "empty" state to worry about.

Combining several conditions

To make more than one field conditional in the same schema, use allOf with a separate if/then pair for each condition:

{
  "type": "object",
  "properties": {
    "hasBio": { "type": "boolean", "title": "Add a bio" },
    "bio": { "type": "string", "title": "Bio" },
    "contactMethod": { "type": "string", "enum": ["email", "phone"], "title": "Preferred contact method" },
    "phoneNumber": { "type": "string", "title": "Phone number" }
  },
  "allOf": [
    {
      "if": { "properties": { "hasBio": { "const": true } } },
      "then": { "required": ["bio"] }
    },
    {
      "if": { "properties": { "contactMethod": { "const": "phone" } }, "required": ["contactMethod"] },
      "then": { "required": ["phoneNumber"] }
    }
  ]
}

Each condition is independent — toggling Add a bio has no effect on the Preferred contact method condition, and vice versa.

 

Understanding validation behavior

The schema is validated before any nodes run. If validation fails, the execution is not created — no partial run, no node executions, no entry in execution history.

The error returned describes what failed:

  • Missing required field: must have required property 'fieldName'
  • Wrong type: must be integer
  • Invalid date format: must be a valid date in the YYYY-MM-DD format
  • Value too short or too long: Input must contain at least X characters / Input cannot exceed X characters (or your own custom message, if one is set)
  • Value doesn't match the required pattern: your custom message, if one is set, otherwise a generic must match pattern message
  • Missing a conditionally required field: The field fieldName is required
     

For manual triggers, the launch form enforces required fields before the workflow can be executed. For webhook and API-triggered executions, the caller receives an error response and should handle it accordingly.

 

Knowing when to define an input schema

Input schemas are optional, but they're worth defining when:

  • The workflow acts on data passed in at launch — formalizing the expected shape makes the workflow easier to call correctly, whether from the UI, the API, or the Start Workflow node
  • You want to prevent bad data from reaching your nodes — catching a missing or malformed field at the trigger is cleaner than handling it inside node logic
  • The workflow is called by another workflow via the Start Workflow node — a defined schema on the manual trigger documents the expected inputs and makes the contract between workflows explicit
  • The manual trigger form needs clear labels — a clear, meaningful title makes the launch form readable for team members who didn't build the workflow

Related to

Was this article helpful?

Have more questions? Submit a request