> For the complete documentation index, see [llms.txt](https://docs.insurgrid.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.insurgrid.com/guides/form-structure-logic.md).

# Form structure & conditional logic

A form is an ordered list of **steps**, each holding an ordered list of **questions**. This is the shape you send when creating or updating a form, and the same shape `GET /v2/forms/{id}` returns — one model, both directions.

## The shape

```json
{
  "steps": [
    {
      "type": "custom",
      "name": "Applicant",
      "segment": "before",
      "position": 2,
      "questions": [
        { "type": "short_text", "label": "Full name", "required": true, "field_mapping": "FullName" }
      ]
    }
  ]
}
```

| Step field    | Description                                                                                           |
| ------------- | ----------------------------------------------------------------------------------------------------- |
| `type`        | `welcome`, `custom`, `carrier_select`, or `confirmation`.                                             |
| `name`        | Display name for the step.                                                                            |
| `segment`     | Where the step sits relative to the (optional) carrier-connect flow: `before`, `carrier`, or `after`. |
| `position`    | Order among the form's steps.                                                                         |
| `questions[]` | The ordered questions in this step — see below.                                                       |

## Question fields

| Field                  | Description                                                                                                                                |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `type`                 | `short_text`, `long_text`, `email`, `number`, `date`, `dropdown`, `single_choice`, `multi_choice`, `file_upload`, `address`, `data_table`. |
| `label`, `placeholder` | Display text.                                                                                                                              |
| `required`             | Whether an answer is mandatory.                                                                                                            |
| `options`              | Choices, for `dropdown` / `single_choice` / `multi_choice`.                                                                                |
| `field_mapping`        | Maps the answer to a known field InsurGrid recognizes: `FullName`, `Email`, `Phone`, `ServiceType`, `EventDate`.                           |
| `validation`           | Per-question validation: `{ "min": 1, "max": 100 }` or `{ "pattern": "^[0-9]{5}$" }`.                                                      |
| `column_schema`        | Column definitions, for a `data_table` question.                                                                                           |
| `rules`                | Conditional logic — see below.                                                                                                             |

> **New term — `field_mapping`:** tells InsurGrid a question's answer corresponds to a well-known field (like the respondent's email), independent of however you worded the question's label. Use it so downstream consumers — like ACORD generation — know which answer is "the email," even if you labeled the question "Best way to reach you."

## Conditional logic (`rules`)

Any question can carry `rules` that show, hide, require, skip, or end the form based on an earlier answer.

| Rule field                              | Description                                                                                                              |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `condition_mode`                        | `all` (AND) or `any` (OR) across the rule's `conditions`.                                                                |
| `conditions[]`                          | Each: `{ source_question_id, operator, value }`.                                                                         |
| `operator`                              | `equals`, `notEquals`, `contains`, `notContains`, `isEmpty`, `isNotEmpty`, `greaterThan`, `lessThan`, `before`, `after`. |
| `action`                                | `show`, `hide`, `require`, `skip_to_step`, `end_form`, `continue`.                                                       |
| `target_question_id` / `target_step_id` | Where the action applies — for example, which step to skip to.                                                           |

### Worked example: show a question only when an earlier answer equals a value

Say your form asks whether a policy is personal or commercial, and you only want to ask for a legal entity name when the answer is "Commercial":

```json
{
  "type": "custom",
  "name": "Applicant",
  "segment": "before",
  "position": 2,
  "questions": [
    {
      "id": "q-policy-kind",
      "type": "single_choice",
      "label": "Policy kind",
      "required": true,
      "options": ["Personal", "Commercial"]
    },
    {
      "id": "q-entity-name",
      "type": "short_text",
      "label": "Legal entity name",
      "initially_hidden": true,
      "rules": [
        {
          "condition_mode": "all",
          "conditions": [
            {
              "source_question_id": "q-policy-kind",
              "operator": "equals",
              "value": "Commercial"
            }
          ],
          "action": "show"
        }
      ]
    }
  ]
}
```

Walking through it:

1. "Policy kind" is a `single_choice` question with two options.
2. "Legal entity name" starts hidden (`initially_hidden: true`).
3. Its `rules` say: when question `q-policy-kind`'s answer `equals` `"Commercial"`, `show` this question.
4. Pick "Personal" and the field stays hidden. Pick "Commercial" and it appears.

Combine multiple `conditions` with `condition_mode: "any"` to show a question when *any one* of several earlier answers matches, or chain `skip_to_step` rules to route respondents down different step sequences entirely.

## Consistency across create, update, and read

The exact same `steps` / `questions` / `rules` shape is used in `POST /v2/forms`, `PATCH /v2/forms/{id}`, and the response from `GET /v2/forms/{id}`. Implement the model once — parse it, build a form from it, or render a preview — and it works in every direction.

## Related

* [Ownership model (agency vs agent)](/guides/ownership.md)
* Forms API reference
* Webhook events & payloads
* [Quickstart C — Build forms via the API](/intake-forms/c-build-forms-api.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.insurgrid.com/guides/form-structure-logic.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
