> ## Documentation Index
> Fetch the complete documentation index at: https://firespark.cloud/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Modifier display types

> How RADIO, CHECKBOX, and QUANTITY map to modifier group and modifier quantity limits in menu sync payloads.

Set `display_type` on each `pricing.modifiers` entry for a modifier product. Fire spark validates that the value matches the group and modifier minimum and maximum quantities when you upsert a menu.

<Card title="Menu sync overview" icon="book-open" href="/docs/integrations-api/guides/menu-sync">
  Read the menu sync guide for payload structure, modifier groups, and nested
  modifiers.
</Card>

## Where the field lives

`display_type` is **not** set on the modifier group. Groups use `display_type` for layout only (`LIST` or `GRID`).

Per-modifier UI control lives on the **modifier product** under `pricing.modifiers`, one object per `modifier_group_id` where that product appears as an option:

```json theme={null}
{
  "id": "mod-ranch",
  "pricing": {
    "modifiers": [
      {
        "modifier_group_id": "mg-dipping-sauce",
        "minimum_quantity": 0,
        "maximum_quantity": 2,
        "display_type": "QUANTITY",
        "price": 0.5,
        "is_tax_inclusive": true,
        "tax_rate": 0.15
      }
    ]
  }
}
```

If you omit `display_type`, Fire spark infers the control from group and modifier quantity limits using the table below. Inference is deterministic when those bounds are present.

<Note>
  When the group max is greater than 1 and you omit `maximum_quantity` on the
  modifier entry, Fire spark treats the modifier as quantity-capable and infers
  `QUANTITY`. For checkbox-style options in a multi-select group, set
  `maximum_quantity: 1`. An explicit `display_type` is optional in that case —
  it documents intent for API consumers but must match the quantity bounds when
  you send it.
</Note>

## Expected display type by quantity limits

Use the **group** bounds from `modifier_groups[].minimum_quantity` and `modifier_groups[].maximum_quantity`, and the **modifier** bounds from the matching `pricing.modifiers` entry on the modifier product.

| Group min | Group max | Modifier min | Modifier max     | Expected `display_type` | Customer UI                                                               |
| --------- | --------- | ------------ | ---------------- | ----------------------- | ------------------------------------------------------------------------- |
| `1`       | `1`       | any          | `1` (or omitted) | `RADIO`                 | Pick exactly one option                                                   |
| `0`       | `1`       | any          | `1` (or omitted) | `CHECKBOX`              | Pick at most one optional option                                          |
| any       | `> 1`     | any          | `1`              | `CHECKBOX`              | Toggle each option on or off                                              |
| any       | `> 1`     | any          | omitted          | `QUANTITY`              | Stepper per option; omitted modifier max is treated as **greater than 1** |
| any       | `> 1`     | any          | `> 1`            | `QUANTITY`              | Stepper per option                                                        |

<Note>
  When the group max is greater than 1 and you omit `maximum_quantity` on the
  modifier entry, validation treats the modifier as quantity-capable (`QUANTITY`).
  Set `maximum_quantity: 1` explicitly when the option should behave as a
  checkbox inside a multi-select group.
</Note>

### Examples

| Scenario                                  | Group min / max | Modifier max | `display_type` |
| ----------------------------------------- | --------------- | ------------ | -------------- |
| Required drink on a combo                 | `1` / `1`       | `1`          | `RADIO`        |
| Optional size upgrade                     | `0` / `1`       | `1`          | `CHECKBOX`     |
| Up to three toppings                      | `0` / `3`       | `1`          | `CHECKBOX`     |
| Up to two sauce cups of the same flavor   | `0` / `2`       | `2`          | `QUANTITY`     |
| Extra portions without a per-modifier cap | `0` / `5`       | omitted      | `QUANTITY`     |

## Validation errors

Menu sync runs these checks on `style: "DEFAULT"` payloads.

### Modifier group breaks the rule

| Condition                                                                    | What went wrong                                                      |
| ---------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `group.minimum_quantity > group.maximum_quantity`                            | The group bounds are invalid.                                        |
| Group min `1`, max `1`, but a modifier has `maximum_quantity` other than `1` | Required single-select groups only allow one unit per option.        |
| Group min `0`, max `1`, but a modifier has `maximum_quantity` other than `1` | Optional single-select groups only allow one unit per option.        |
| Group max `> 1` and a modifier uses `display_type: "RADIO"`                  | `RADIO` is only valid when **both** group min and group max are `1`. |

### Modifier breaks the rule

| Condition                                                             | What went wrong                                                                                          |
| --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `modifier.minimum_quantity > modifier.maximum_quantity`               | The modifier bounds are invalid.                                                                         |
| `modifier.maximum_quantity > group.maximum_quantity`                  | One option cannot exceed the group total cap.                                                            |
| `display_type` does not match the expected value from the table above | For example, `QUANTITY` with modifier max `1` in a multi-select group, or `RADIO` when group min is `0`. |

Example rejection:

```text theme={null}
Modifier "mod-cheese" in group "mg-toppings" has display_type "RADIO" but must be "CHECKBOX": CHECKBOX because the group allows multiple selections (group min 0, max 3) and this modifier is capped at one unit (modifier min 0, max 1).
```

## Decision flow

```mermaid theme={null}
flowchart TD
  START["Read group min / max"] --> RADIO{"min = 1 and max = 1?"}
  RADIO -->|yes| DT_RADIO["display_type = RADIO"]
  RADIO -->|no| OPT{"min = 0 and max = 1?"}
  OPT -->|yes| DT_CHECKBOX["display_type = CHECKBOX"]
  OPT -->|no| MULTI{"modifier max = 1?"}
  MULTI -->|yes| DT_CHECKBOX_MULTI["display_type = CHECKBOX"]
  MULTI -->|no| DT_QTY["display_type = QUANTITY\n(modifier max omitted counts as > 1)"]
```

## Related fields

| Field                                  | Scope    | Purpose                                                  |
| -------------------------------------- | -------- | -------------------------------------------------------- |
| `modifier_groups[].minimum_quantity`   | Group    | Minimum total selections across all options in the group |
| `modifier_groups[].maximum_quantity`   | Group    | Maximum total selections across all options in the group |
| `pricing.modifiers[].minimum_quantity` | Modifier | Minimum units for this option                            |
| `pricing.modifiers[].maximum_quantity` | Modifier | Maximum units for this option                            |
| `pricing.modifiers[].display_type`     | Modifier | UI control: `RADIO`, `CHECKBOX`, or `QUANTITY`           |

See [Upsert menus](/docs/integrations-api/menus/put) for the full `pricing.modifiers` schema.
