Applies to: Catalog API
Learn how to enable product customization with list-based and text-based modifiers.
When selling certain products, a seller might want to give the buyer choices to add selected modifications. For example, when ordering a cheeseburger, the buyer can choose to add a specialty cheese of gorgonzola or pecorino for an additional cost. In this case, the specialty cheese is modeled by CatalogModifier in the Square catalog. Another example of product customization is selling T-shirts with custom printing of buyer-selected text.
The Square catalog supports two types of modifiers: list-based modifiers and text-based modifiers.
The list-based modifier is also referred to as non-text-based modifiers. The specialty cheese example describes non-text-based modifiers, which are represented by a list of CatalogModifier objects contained in a CatalogModifierList object. The data model of list-based modifiers is of the following format:
{ "type": "MODIFIER_LIST", "id": "{{Square-generated ID of this modifier list}}", ..., "modifier_list_data": { "name": "Name of the modifier list", "selection_type": "{{One (SINGLE) or more (MULTIPLE) modifiers selectable from this modifier list}}", "internal_name": "{{Notes for the seller about this transaction}}", "modifiers": [ { "type": "MODIFIER", "id": "{{Square-generated ID of this modifier}}", ..., "modifier_data": { "name": "Name of this modifier", "price_money": { "amount": {{Integer price of this modifier}}, "currency": "USD | ..." }, "ordinal": {{Position of this modifier in the list}}, "modifier_list_id": "{{ID of the containing modifier list}}" } }, ... ] } }
With list-based modifiers, the CatalogModifierList
object contains a non-empty list of CatalogModifier
objects.
An example of a text-based modifier is buyer-selected text printed on a T-shirt, when a seller sells T-shirts with custom printing. However, it's represented directly by a CatalogModifierList
object. The data model of the text-based modifier is of the following form:
{ "type": "MODIFIER_LIST", "id": "{{Square-generated unique string}}", ... "modifier_list_data": { "name": "{{The modifier's name}}", "selection_type": "SINGLE", "modifier_type": "TEXT", "max_length": {{Maximum unicode points of the modifier's text}}, "text_required": {{Whether the modifier's text can be empty (false) or not (true}} "internal_name": "{{Notes for the seller about this transaction}}" } }
Unlike list-based modifiers, a text-based modifier is represented by the CatalogModifierList
object itself and doesn't incur any extra cost. The selection_type
is always SINGLE
. Any attempt to set the other selection type is ignored.
To better appreciate the differences between list-based modifiers and a text-based modifier, it might be helpful to view the CatalogModifierList
object for a text-based modifier as containing a single modifier as described by properties specific to text-based modifiers. The CatalogModifierList
object for list-based modifiers, on the other hand, contains a list of CatalogModifier
instances each of which is a non-text-based modifier.
To enable customization to a product offering, supported modifiers must be created and then added to the associated product item in the catalog. When enabled, the modifiers can be presented for the buyer to choose when the product item is ordered.
Creating modifiers and adding them to an item involves calling the Catalog API. Presenting product modifications to the buyer is part of the ordering process and built into buyer-facing client applications, such as Square Point of Sale or third-party applications, that are integrated with the Orders API.
In this topic, you learn how to enable list-based and text-based modifiers on items.
To enable list-based modifiers, call the UpsertCatalogObject or BatchUpsertCatalogObjects endpoint to do the following:
- Create a
CatalogModifierList
object with themodifier_type
attribute set toLIST
. Assign a non-empty list ofCatalogModifier
objects on the modifiers property. - Create a
CatalogItem
object (if it doesn't exist already), reference the modifier list, and specify within themodifier_list_info
attribute of the item how the modifier can be selected at the time of sale.
When multiple catalog objects are created, UpsertCatalogObject
must be invoked one object at a time, while BatchUpsertCatalogObjects
can be invoked for all the required catalog objects in one call.
Request: Add two cheese modifiers to a cheeseburger
The following example invokes BatchUpsertCatalogObjects
to perform the following tasks:
- Create a
CatalogModifierList
object containing a list of twoCatalogModifier
objects for the gorgonzola cheese and pecorino cheese modifiers. - Create a
CatalogItem
object for a cheeseburger item with the two cheese modifiers included as optional add-ons for the buyer to choose from.
Batch upsert catalog objects
The modifiers have their own pricing. In this example, each costs an additional 1 US dollar, namely 100 cents. The MULTIPLE
selection type declared within the CatalogModifierList
object means that this cheeseburger can have more than one type of cheese added to it. If the selection type is SINGLE
, the cheeseburger can have gorgonzola or pecorino cheese added to it, but not both.
The number of cheeses a buyer can choose when ordering the cheeseburger is specified by the min_selected_modifiers
and max_selected_modifiers
values within the modifier_list_info
property of the CatalogItem
object. In this example, because min_selected_modifiers=0
and max_selected_modifiers=2
, the buyer can choose 0, 1, or 2 cheeses when ordering the cheeseburger and be charged $7, $8, or $9, respectively. For a $9 cheeseburger, it can have one of the following cheese options:
- One gorgonzola and one pecorino
- Two portions of gorgonzola
- Two portions of pecorino
If the quantity is unspecified, min_selected_modifiers
or max_selected_modifiers
defaults to -1. This indicates that the selections are unlimited.
Note
The actual quantity of modifiers selected by a buyer is order-specific and not recorded in the catalog.
Response: Add two cheese modifiers to a cheeseburger
The successful response returns a payload similar to the following:
{
"objects": [
{
"type": "MODIFIER_LIST",
"id": "CXNV4SOM4QCPLH5MGZN5DWYR",
"updated_at": "2024-02-22T19:55:59.86Z",
"created_at": "2024-02-22T19:55:59.86Z",
"version": 1706644559860,
"is_deleted": false,
"present_at_all_locations": true,
"modifier_list_data": {
"name": "Cheese add-ons",
"selection_type": "MULTIPLE",
"modifiers": [
{
"type": "MODIFIER",
"id": "DSTNWJ5F5VC6C7R3NXJ5WHBO",
"updated_at": "2024-02-22T19:55:59.86Z",
"created_at": "2024-02-22T19:55:59.86Z",
"version": 1706644559860,
"is_deleted": false,
"present_at_all_locations": true,
"modifier_data": {
"name": "Gorgonzola cheese",
"price_money": {
"amount": 100,
"currency": "USD"
},
"ordinal": 0,
"modifier_list_id": "CXNV4SOM4QCPLH5MGZN5DWYR"
}
},
{
"type": "MODIFIER",
"id": "F7MH4ASVZXGW2BPUNMLMFKHO",
"updated_at": "2024-02-22T19:55:59.86Z",
"created_at": "2024-02-22T19:55:59.86Z",
"version": 1706644559860,
"is_deleted": false,
"present_at_all_locations": true,
"modifier_data": {
"name": "Pecorino cheese",
"price_money": {
"amount": 100,
"currency": "USD"
},
"ordinal": 1,
"modifier_list_id": "CXNV4SOM4QCPLH5MGZN5DWYR"
}
}
]
}
},
{
"type": "ITEM",
"id": "SVNCMZI3KBU2MX5W4A2DRQ6B",
"updated_at": "2024-02-22T19:55:59.86Z",
"created_at": "2024-02-22T19:55:59.86Z",
"version": 1706644559860,
"is_deleted": false,
"present_at_all_locations": true,
"item_data": {
"name": "Cheeseburger",
"is_taxable": true,
"modifier_list_info": [
{
"modifier_list_id": "CXNV4SOM4QCPLH5MGZN5DWYR",
"min_selected_modifiers": 0,
"max_selected_modifiers": 2,
"enabled": true
}
],
"variations": [
{
"type": "ITEM_VARIATION",
"id": "N74APPZ5SZVDXDLY54KTBTFX",
"updated_at": "2024-02-22T19:55:59.86Z",
"created_at": "2024-02-22T19:55:59.86Z",
"version": 1706644559860,
"is_deleted": false,
"present_at_all_locations": true,
"item_variation_data": {
"item_id": "SVNCMZI3KBU2MX5W4A2DRQ6B",
"name": "Fancy cheese burger",
"ordinal": 0,
"pricing_type": "FIXED_PRICING",
"price_money": {
"amount": 700,
"currency": "USD"
},
"sellable": true,
"stockable": true
}
}
],
"product_type": "REGULAR",
"is_archived": false
}
}
],
"id_mappings": [
{
"client_object_id": "#modifier_list",
"object_id": "CXNV4SOM4QCPLH5MGZN5DWYR"
},
{
"client_object_id": "#item_cheeseburger",
"object_id": "SVNCMZI3KBU2MX5W4A2DRQ6B"
},
{
"client_object_id": "#modifier_cheese_gorgonzola",
"object_id": "DSTNWJ5F5VC6C7R3NXJ5WHBO"
},
{
"client_object_id": "#modifier_cheese_pecorino",
"object_id": "F7MH4ASVZXGW2BPUNMLMFKHO"
},
{
"client_object_id": "#var_cheeseburger",
"object_id": "N74APPZ5SZVDXDLY54KTBTFX"
}
]
}
To enable text-based modifiers on an item, call the UpsertCatalogObject
or BatchUpsertCatalogObjects
endpoint to perform the following tasks:
- Create a
CatalogModifierList
object with themodifier_type
attribute set toTEXT
. Don't set the modifiers list property. - Create a
CatalogItem object
, if it doesn't exist already, while referencing the modifier list within themodifier_list_info
attribute of the item.
When multiple catalog objects are created, UpsertCatalogObject
must be invoked for one object at a time, while BatchUpsertCatalogObjects
can be invoked for all the required catalog objects in one call.
For a text-based modifier, there's no need to specify min_selected_modifiers
and max_selected_modifiers
to define the selectable quantity because they don't apply to any text-based modifier.
Request: Enable a text-based modifier on an item
The following example invokes BatchUpsertCatalogObjects
to perform the following tasks:
- Create a text-based modifier as presented by a
CatalogModifierList
object with properties specific text-based modifiers. - Create a
CatalogItem
object for a custom-print T-shirt item with buyer-supplied text printed on the front of the T-shirt.
Batch upsert catalog objects
In the specification of the text-based modifier (namely, the CatalogModifierList
object), the modifier_list_data
contains two properties specific to text-based modifiers. This is in addition to certain properties that also apply to the CatalogModifierList
object containing a list of CatalogModifier
objects each of which is a non-text-based modifier.
max_length
- Sets the limit of the buyer-supplied text, with 150 unicode points as the default value.text_required
- Determines whether buyer-supplied text can be empty (false
) or not (true
). The default value isfalse
. When an empty text is allowed, the seller might opt to skip printing the text or use pre-selected text, according to the business plan.
It's more likely to expect that the internal_name
attribute is also used to specify internal instructions or supplemental descriptions for how custom printing should be done.
If the custom-print T-shirt can have two texts printed on the front or back of a T-shirt, a Back Print
catalog object of the MODIFIER_LIST
type can be inserted after the Front Print
text-based modifier.
{ "id": "#modifier_list_back", "type": "MODIFIER_LIST", "modifier_list_data": { "modifier_type": "TEXT", "name": "Back Print", "max_length": 150, "text_required": false, "internal_name": "Use purple color" } },
In turn, the modifier_list_info
list under item_data
needs to be updated to the following:
"modifier_list_info": [ { "modifier_list_id": "#modifier_list_front", "enabled": true }, { "modifier_list_id": "#modifier_list_back", "enabled": true } ],
With this addition, the buyer must provide text for the front when ordering the T-shirt, but might choose to add or not add text for the back.
Response: Enable a test-based modifier on an item
The successful response contains a payload similar to the following:
{
"objects": [
{
"type": "MODIFIER_LIST",
"id": "3GNDKIXMPF4P4CKA5VTUNHK6",
"updated_at": "2024-02-22T22:32:57.149Z",
"created_at": "2024-02-22T22:32:57.149Z",
"version": 1706653977149,
"is_deleted": false,
"present_at_all_locations": true,
"modifier_list_data": {
"name": "Front Print",
"selection_type": "SINGLE",
"modifier_type": "TEXT",
"max_length": 150,
"internal_name": "Italic face in blue color"
}
},
{
"type": "ITEM",
"id": "CIWKQBQYIRRJUOFSZ5JJB3OO",
"updated_at": "2024-02-22T22:32:57.149Z",
"created_at": "2024-02-22T22:32:57.149Z",
"version": 1706653977149,
"is_deleted": false,
"present_at_all_locations": true,
"item_data": {
"name": "T-shirt with custom print",
"is_taxable": true,
"modifier_list_info": [
{
"modifier_list_id": "3GNDKIXMPF4P4CKA5VTUNHK6",
"enabled": true
}
],
"variations": [
{
"type": "ITEM_VARIATION",
"id": "FGLUTQGTCXUHFICMM7N5DCOY",
"updated_at": "2024-02-22T22:32:57.149Z",
"created_at": "2024-02-22T22:32:57.149Z",
"version": 1706653977149,
"is_deleted": false,
"present_at_all_locations": true,
"item_variation_data": {
"item_id": "CIWKQBQYIRRJUOFSZ5JJB3OO",
"name": "T-shirt with custom print",
"ordinal": 0,
"pricing_type": "FIXED_PRICING",
"price_money": {
"amount": 1700,
"currency": "USD"
},
"sellable": true,
"stockable": true
}
}
],
"product_type": "REGULAR",
"is_archived": false
}
}
],
"id_mappings": [
{
"client_object_id": "#modifier_list_front",
"object_id": "3GNDKIXMPF4P4CKA5VTUNHK6"
},
{
"client_object_id": "#item_t_shirt",
"object_id": "CIWKQBQYIRRJUOFSZ5JJB3OO"
},
{
"client_object_id": "#var_t_shirt",
"object_id": "FGLUTQGTCXUHFICMM7N5DCOY"
}
]
}