Manage Nested Modifiers

Learn how to nest modifier lists under modifiers with the Catalog API to build multi-step customization flows, and how to read and search the modifier tree.

Applies to: Catalog API

Link to section

Overview

A flat modifier list presents every option at once. That works for a latte, but not for a burrito where choosing steak should lead to a sauce question, and choosing green salsa should lead to a spice level question. Nested modifiers let one selection reveal the next, so the buyer answers a sequence of questions instead of reading one long list.

Nesting is expressed on the modifier that triggers it. A CatalogModifier has a child_modifier_list_ids field holding references to the CatalogModifierList objects that should be presented when that modifier is selected. Nothing about the modifier lists themselves changes - a nested list is an ordinary modifier list that happens to be referenced by a modifier.

Important

Set the Square-Version header to 2026-08-19 or later. Earlier versions cannot write child_modifier_list_ids, and Square omits the field from their responses.

This page assumes you're familiar with the modifier data model. See Enable Item Customization with Modifiers for the basics.

Link to section

The child_modifier_list_ids field

Each entry in child_modifier_list_ids is the ID of a modifier list to present when the parent modifier is selected. The following rules govern the field:

RuleDetail
Up to 5 children per modifierA single modifier can reference at most 5 modifier lists.
Up to 3 levels of nestingCounted in modifier lists, not modifiers. See Nesting depth.
No duplicatesThe same modifier list ID cannot appear twice in one modifier's child_modifier_list_ids.
No cyclesA modifier cannot reference a modifier list that is already one of its own ancestors, including the list the modifier itself belongs to.
Order is preservedSquare stores the order you send and returns the entries in that order.

A modifier list can be referenced by more than one modifier, and a list that's nested under a modifier can also be attached directly to items. In the burrito example that follows, both Steak and Chicken reference the same Protein Amount list rather than each needing its own copy.

Link to section

Nesting depth

Depth counts modifier list levels along a chain of references. The list at the top of a chain is level 1, a list referenced by one of its modifiers is level 2, and a list referenced by one of those modifiers is level 3:

Protein (level 1) └── Steak ├── Sauce (level 2) │ └── Green Salsa │ └── Spice Level (level 3) └── Protein Amount (level 2)

A modifier in Spice Level cannot reference a further modifier list, because the resulting list would sit at level 4.

Attaching a modifier list to an item does not consume a level - the item is not part of the chain. Protein is level 1 whether it's attached to one item, many items, or none.

Two consequences are worth planning for:

  • Depth is evaluated over the whole tree as it exists in the catalog, not just the objects in your request. Adding a child to a modifier whose ancestors already exist in the catalog can fail even though your request contains a single object.
  • When a modifier list is reachable by more than one path, its deepest path determines its level. Referencing a shared list from a new, deeper location can push it past the limit and fail, even though your request didn't touch the branch that was already valid.

Requests that break the depth limit or introduce a cycle are rejected with a 400 response and an INVALID_VALUE error code.

Link to section

Build a nested modifier tree

The following BatchUpsertCatalogObjects request builds the burrito tree in a single call:

  • Spice Level, with Mild and Hot.
  • Sauce, whose Green Salsa modifier nests Spice Level.
  • Protein Amount, with Single and Double.
  • Protein, whose Steak modifier nests both Sauce and Protein Amount, and whose Chicken modifier nests only Protein Amount.
  • A Burrito item that attaches Protein. The three nested lists don't need to be attached to the item - they're reached through the tree.

Batch upsert catalog objects

Steak returns child_modifier_list_ids in the order it was sent - Sauce before Protein Amount.

Link to section

Update the children of a modifier

child_modifier_list_ids behaves like every other catalog field: the list you send replaces the stored list in full. To add or remove one child, read the parent modifier list, modify the array on the relevant modifier, and upsert the object with its current version. Omitting the field clears the modifier's children.

Link to section

Delete a nested modifier list

Deleting a modifier list that's nested under a modifier isn't blocked. Square removes the reference from every modifier that pointed to it, and, as with any modifier list, deletes the modifiers the list contained. Modifier lists that were nested one level deeper survive the delete and become the top of their own chain, so re-parent them if they should stay reachable.

Link to section

Read the modifier tree

A modifier tree is a graph of references, so reading it with BatchRetrieveCatalogObjects or SearchCatalogObjects alone means one round trip per level. The include_options request field collapses that into a single call. It takes an include array, and Square returns what you asked for in a new included_resources object alongside the usual objects.

include_options is supported on BatchRetrieveCatalogObjects, SearchCatalogObjects, and SearchCatalogItems, and accepts two values:

Include typeReturned inDescription
INCLUDE_NESTED_MODIFIERSincluded_resources.nested_modifiersThe modifier lists below the requested objects.
INCLUDE_ANCESTOR_MODIFIERSincluded_resources.ancestor_modifiersThe modifier lists above the requested modifier lists.

Included objects are complete CatalogObjects with modifier_list_data and their modifiers inlined, so each returned modifier carries its own child_modifier_list_ids and you can reconstruct the tree from a single response.

Link to section

Include nested modifier lists

What INCLUDE_NESTED_MODIFIERS returns depends on the type of each requested object:

Requested objectReturned in nested_modifiers
ITEMThe modifier lists attached to the item, plus every modifier list nested beneath them.
MODIFIER_LISTEvery modifier list nested beneath it. The requested list itself isn't repeated here.
MODIFIERThe modifier lists it references, plus every modifier list nested beneath those.

The following example retrieves only the Burrito item and gets its entire modifier tree back in one call:

Batch retrieve catalog objects

Link to section

Include ancestor modifier lists

INCLUDE_ANCESTOR_MODIFIERS walks the tree in the other direction. For each CatalogModifierList among the requested objects, Square returns the modifier lists above it, following parent references all the way to the top of the chain. Use it to answer "where does this list appear?" - for example, to warn a seller editing Spice Level that the change affects everything reached through Protein.

ancestor_modifiers contains CatalogModifierList objects. The parent modifier that does the nesting is returned inside its own list's modifier_list_data.modifiers, so to find the exact modifier that references your list, look for the one whose child_modifier_list_ids contains it.

Batch retrieve catalog objects

A modifier list with more than one parent returns all of them, along with each parent's own ancestors. A modifier list that isn't nested anywhere returns an empty ancestor_modifiers.

Link to section

Find the modifiers that nest a modifier list

INCLUDE_ANCESTOR_MODIFIERS gives you the ancestor lists of a list you're already retrieving. When you instead need the specific modifiers that reference a list - the ones a seller would have to edit to detach it - use the modifiers_for_child_list_query filter on SearchCatalogObjects. It takes child_modifier_list_ids and returns the CatalogModifier objects whose child_modifier_list_ids contain any of them.

The following example finds the modifiers that nest the Sauce list:

Search catalog objects

The filter returns direct parents only. To climb further, either run the query again against the modifier list each returned modifier belongs to (modifier_data.modifier_list_id), or retrieve that list with INCLUDE_ANCESTOR_MODIFIERS.

Link to section

See also