Applies to: Catalog API
Learn how to build a simple product catalog for a cafe that serves coffee in small and large sizes, with skim or whole milk.
To build this catalog, you call the UpsertCatalogObject endpoint to create the following catalog objects to represent the for-sale item (Coffee
). You include two variations (Small Coffee
and Large Coffee
) of the sale item, a CatalogTax object as taxes applied to the coffee item, and two optional modifications (with Skim Milk
and Whole Milk
).
The following steps are generally applicable to creating catalog objects of other types, except for uploading an image object. For information about how to upload an image to a catalog and attach it to an item, item variation, or category, see Work with Images.
1. Add a coffee item to a catalog
Important
When creating an item, you must also specify at least one variation. Otherwise, you get an INVALID_REQUEST
error.
To add a coffee item to a catalog as a product offering of a seller, call the UpsertCatalogObject endpoint to create a CatalogItem object in the catalog. This is shown in the following REST API example:
In this example, the Coffee
item has two variations (Small
and Large
).
The #coffee
ID is a temporary ID, serving as a placeholder for the permanent ID that the Square API generates and returns in the response. In the same request payload where the temporary ID is defined, you can use the temporary ID value to reference this to-be-created object. The two variations in this example use #coffee
to identify its parent item. If these variations were created in a separate request, you must use their Square-generated permanent ID values to reference them.
Because the UpsertCatalogObject
endpoint is used to create other catalog objects, the data object you specify must match the specified type
property value. In this example, you must set the item_data
property to an appropriate CatalogItem object to match the ITEM
type and set the item_variation_data
property to an appropriate CatalogItemVariation object to match the ITEM_VARIATION
type. Similarly, to set up a discount to be applied to an order, you must specify an appropriate CatalogDiscount object on the discount_data
field while setting the type
value to DISCOUNT
. In summary, the type
property must match the {object_type}_data
property.
When the request is successful, you get a 200 OK
response with a payload similar to the following:
{
"catalog_object": {
"type": "ITEM",
"id": "FX3LTXC2CCFCGHLGMSFLBSDO",
"updated_at": "2021-06-15T18:48:16.262Z",
"version": 1623782896262,
"is_deleted": false,
"present_at_all_locations": true,
"item_data": {
"name": "Coffee",
"description": "Coffee Drink",
"abbreviation": "Co",
"variations": [
{
"type": "ITEM_VARIATION",
"id": "OXRR3XANRU5TEQ3FQMDW5IJK",
"updated_at": "2021-06-15T18:48:16.262Z",
"version": 1623782896262,
"is_deleted": false,
"present_at_all_locations": true,
"item_variation_data": {
"item_id": "FX3LTXC2CCFCGHLGMSFLBSDO",
"name": "Small",
"ordinal": 0,
"pricing_type": "FIXED_PRICING",
"price_money": {
"amount": 300,
"currency": "USD"
},
"stockable": true
}
},
{
"type": "ITEM_VARIATION",
"id": "3EFNOI25E4NUK53CU4KMUHXX",
"updated_at": "2021-06-15T18:48:16.262Z",
"version": 1623782896262,
"is_deleted": false,
"present_at_all_locations": true,
"item_variation_data": {
"item_id": "FX3LTXC2CCFCGHLGMSFLBSDO",
"name": "Large",
"ordinal": 1,
"pricing_type": "FIXED_PRICING",
"price_money": {
"amount": 350,
"currency": "USD"
},
"stockable": true
}
}
],
"product_type": "REGULAR"
}
},
"id_mappings": [
{
"client_object_id": "#coffee",
"object_id": "FX3LTXC2CCFCGHLGMSFLBSDO"
},
{
"client_object_id": "#small_coffee",
"object_id": "OXRR3XANRU5TEQ3FQMDW5IJK"
},
{
"client_object_id": "#large_coffee",
"object_id": "3EFNOI25E4NUK53CU4KMUHXX"
}
]
}
Note that the response returns the ID mapping between the temporary ID (id_mappings.client_object_id
) value and the Square-generated ID (object_id
) value. From now on, you must reference these objects by their respective object_id
values.
In this example, the coffee item's product_type
is unspecified in the request. This is equivalent to setting product_type
to REGULAR
.
Create the coffee item as a food and beverage item explicitly
You can set product_type
to FOOD_AND_BEV
to create the coffee or another food and beverage item explicitly. This is useful if you want to include the food and beverage details (such as the calorie count, ingredients, or dietary preferences) in the resulting item.
For example, the following request recreates the coffee item with an explicit product_type
of FOOD_AND_BEV
to contain information about the calorie count and dietary preference:
The additional food and beverage details are returned in the successful response:
{
"catalog_object": {
"type": "ITEM",
"id": "H2Y6VVVMYKHOUTVFQIPMSQ67",
"updated_at": "2023-12-13T22:20:16.697Z",
"created_at": "2023-12-13T22:20:16.697Z",
"version": 1702506016697,
"is_deleted": false,
"present_at_all_locations": true,
"item_data": {
"name": "Coffee",
"description": "Coffee Drink",
"abbreviation": "Co",
"is_taxable": true,
"variations": [
{
"type": "ITEM_VARIATION",
"id": "A2ZOF5UEXL6V6X2JATH7K2Q7",
"updated_at": "2023-12-13T22:20:16.697Z",
"created_at": "2023-12-13T22:20:16.697Z",
"version": 1702506016697,
"is_deleted": false,
"present_at_all_locations": true,
"item_variation_data": {
"item_id": "H2Y6VVVMYKHOUTVFQIPMSQ67",
"name": "Small",
"ordinal": 0,
"pricing_type": "FIXED_PRICING",
"price_money": {
"amount": 300,
"currency": "USD"
},
"sellable": true,
"stockable": true
}
},
{
"type": "ITEM_VARIATION",
"id": "U7UEUIFP6GCAWUMD7TV2CO7R",
"updated_at": "2023-12-13T22:20:16.697Z",
"created_at": "2023-12-13T22:20:16.697Z",
"version": 1702506016697,
"is_deleted": false,
"present_at_all_locations": true,
"item_variation_data": {
"item_id": "H2Y6VVVMYKHOUTVFQIPMSQ67",
"name": "Large",
"ordinal": 1,
"pricing_type": "FIXED_PRICING",
"price_money": {
"amount": 350,
"currency": "USD"
},
"sellable": true,
"stockable": true
}
}
],
"product_type": "FOOD_AND_BEV",
"description_html": "<p>Coffee Drink</p>",
"description_plaintext": "Coffee Drink",
"is_archived": false,
"food_and_beverage_details": {
"calorie_count": 10,
"dietary_preferences": [
{
"type": "STANDARD",
"standard_name": "GLUTEN_FREE"
}
]
}
}
},
"id_mappings": [
{
"client_object_id": "#coffee",
"object_id": "H2Y6VVVMYKHOUTVFQIPMSQ67"
},
{
"client_object_id": "#small_coffee",
"object_id": "A2ZOF5UEXL6V6X2JATH7K2Q7"
},
{
"client_object_id": "#large_coffee",
"object_id": "U7UEUIFP6GCAWUMD7TV2CO7R"
}
]
}
If you create the coffee or another food or beverage as a REGULAR
item and include the food and beverage details in the request, the specified food and beverage details are ignored and not returned in the response.
2. Create a CatalogTax object for the coffee drink
In most locales, a sales tax must be levied on a sold product. To support taking taxes on an order, you must first create a CatalogTax object to set up the tax to be applied when the payment is made on the order.
The following code example shows how to create a tax object and add it to the catalog:
In this example, the drink tax is 7.5% of the pretax subtotal of an order and it applies to catalog item-based and ad-hoc order line items. If you don't specify the property, the new tax is created with "applies_to_custom_amounts": true
.
When successful, the request returns a 200 OK
response with the payload similar to the following:
{
"catalog_object": {
"type": "TAX",
"id": "TEROS7KLG76NDY4J7TYFZVGA",
"updated_at": "2021-06-15T19:12:49.613Z",
"version": 1623784369613,
"is_deleted": false,
"present_at_all_locations": true,
"tax_data": {
"name": "Drink Tax",
"calculation_phase": "TAX_SUBTOTAL_PHASE",
"inclusion_type": "ADDITIVE",
"percentage": "7.5",
"applies_to_custom_amounts": false,
"enabled": true
}
},
"id_mappings": [
{
"client_object_id": "#sales_tax",
"object_id": "TEROS7KLG76NDY4J7TYFZVGA"
}
]
}
Alternatively, you can combine the calls to create the Coffee
item with the Small
and Large
variations and the Drink Tax
object into a single call to the BatchUpsertCatalogObjects endpoint, as shown:
In the previous example, note that the catalog item item_data
property includes the tax_ids
sub-property:
"tax_ids": [
"#sales_tax"
]
This property connects the new CatalogTax
to the CatalogItem
created in the batch request. In an Orders API CreateOrder request, that tax is auto-applied to the coffee if the CreateOrder
request includes the pricing_options
property as in the following example:
"pricing_options": {
"auto_apply_discounts": false,
"auto_apply_taxes": true
}
3. Create a modifier list to contain two modifiers
To enable sellers to offer the choices of adding skim milk and whole milk to the coffee drink, you can create two catalog modifiers to apply to the Coffee
item. One way to add the modifiers is to create a modifier list containing individual modifiers as its entries.
The following example shows how to call the UpsertCatalogObject endpoint to create the CatalogModifierList object with two CatalogModifier objects for Skim Milk
and Whole Milk
:
The successful operation returns a 200 OK
response with a payload similar to the following:
{
"catalog_object": {
"type": "MODIFIER_LIST",
"id": "ZVSGY6U63IGCZQL4IOPZAKYW",
"updated_at": "2020-06-15T20:01:39.58Z",
"version": 1623784369656,
"is_deleted": false,
"present_at_all_locations": true,
"modifier_list_data": {
"name": "Milk Options",
"modifiers": [
{
"type": "MODIFIER",
"id": "MNXLZRO2PIBULOX2RX56DG25",
"updated_at": "2020-06-15T20:01:39.58Z",
"version": 1623784369656,
"is_deleted": false,
"present_at_all_locations": true,
"modifier_data": {
"name": "Whole Milk",
"price_money": {
"amount": 125,
"currency": "USD"
},
"ordinal": 0,
"modifier_list_id": "ZVSGY6U63IGCZQL4IOPZAKYW"
}
},
{
"type": "MODIFIER",
"id": "Q6R5X5VMSZTYVKM37QRHNZWM",
"updated_at": "2020-06-15T20:01:39.58Z",
"version": 1623784369656,
"is_deleted": false,
"present_at_all_locations": true,
"modifier_data": {
"name": "Skim Milk",
"price_money": {
"amount": 130,
"currency": "USD"
},
"ordinal": 1,
"modifier_list_id": "ZVSGY6U63IGCZQL4IOPZAKYW"
}
}
]
}
},
"id_mappings": [
{
"client_object_id": "#modifier_list",
"object_id": "ZVSGY6U63IGCZQL4IOPZAKYW"
},
{
"client_object_id": "#whole_milk",
"object_id": "MNXLZRO2PIBULOX2RX56DG25"
},
{
"client_object_id": "#skim_milk",
"object_id": "Q6R5X5VMSZTYVKM37QRHNZWM"
}
]
}
For the modifiers in the modifier list to be applied to the Coffee
item, you must have the resultant modifier list applied to the Coffee
item, as explained in step 4.
4. Apply the modifier list to the coffee item
To apply the modifier list created in step 3, call the UpdateItemModifierLists
endpoint as shown in the following example:
If successful, the operation returns a 200 OK
response with a payload similar to the following:
{
"updated_at": "2020-06-15T18:36:39.58Z"
}
Alternatively, you can call the BatchUpsertCatalogObjects endpoint to create a modifier list with appropriate modifier entries and add the modifier list to the Coffee
item, together with the required item variations, in a single call to create all related CatalogObject instances at once.
5. Verify the catalog you just built
After building your catalog, you can view and verify it by calling the ListCatalog endpoint to inspect the catalog items. The following request shows an example:
In response, the payload contains the catalog objects:
{
"objects": [
{
"type": "ITEM",
"id": "FX3LTXC2CCFCGHLGMSFLBSDO",
"updated_at": "2021-06-15T18:48:16.262Z",
"version": 1623782896262,
"is_deleted": false,
"present_at_all_locations": true,
"item_data": {
"name": "Coffee",
"description": "Coffee Drink",
"abbreviation": "Co",
"modifier_list_info": [
{
"modifier_list_id": "ZVSGY6U63IGCZQL4IOPZAKYW",
"enabled": true
}
],
"variations": [
{
"type": "ITEM_VARIATION",
"id": "3EFNOI25E4NUK53CU4KMUHXX",
"updated_at": "2021-06-15T18:48:16.262Z",
"version": 1623782896262,
"is_deleted": false,
"present_at_all_locations": true,
"item_variation_data": {
"item_id": "FX3LTXC2CCFCGHLGMSFLBSDO",
"name": "Large",
"pricing_type": "FIXED_PRICING",
"price_money": {
"amount": 350,
"currency": "USD"
}
}
},
{
"type": "ITEM_VARIATION",
"id": "OXRR3XANRU5TEQ3FQMDW5IJK",
"updated_at": "2021-06-15T18:48:16.262Z",
"version": 1623782896262,
"is_deleted": false,
"present_at_all_locations": true,
"item_variation_data": {
"item_id": "FX3LTXC2CCFCGHLGMSFLBSDO",
"name": "Small",
"pricing_type": "FIXED_PRICING",
"price_money": {
"amount": 300,
"currency": "USD"
}
}
}
],
"product_type": "REGULAR"
}
},
{
"type": "TAX",
"id": "TEROS7KLG76NDY4J7TYFZVGA",
"updated_at": "2021-06-15T19:12:49.613Z",
"version": 1623784369613,
"is_deleted": false,
"present_at_all_locations": true,
"tax_data": {
"name": "Drink Tax",
"calculation_phase": "TAX_SUBTOTAL_PHASE",
"inclusion_type": "ADDITIVE",
"percentage": "7.5",
"applies_to_custom_amounts": true,
"enabled": true
}
},
{
"type": "MODIFIER_LIST",
"id": "ZVSGY6U63IGCZQL4IOPZAKYW",
"updated_at": "2020-06-15T20:01:39.58Z",
"version": 1623784369656,
"is_deleted": false,
"present_at_all_locations": true,
"modifier_list_data": {
"name": "Milk Options",
"modifiers": [
{
"type": "MODIFIER",
"id": "MNXLZRO2PIBULOX2RX56DG25",
"updated_at": "2020-06-15T20:01:39.58Z",
"version": 1623784369656,
"is_deleted": false,
"present_at_all_locations": true,
"modifier_data": {
"name": "Whole Milk",
"price_money": {
"amount": 125,
"currency": "USD"
},
"ordinal": 0,
"modifier_list_id": "ZVSGY6U63IGCZQL4IOPZAKYW"
}
},
{
"type": "MODIFIER",
"id": "Q6R5X5VMSZTYVKM37QRHNZWM",
"updated_at": "2020-06-15T20:01:39.58Z",
"version": 1623784369656,
"is_deleted": false,
"present_at_all_locations": true,
"modifier_data": {
"name": "Skim Milk",
"price_money": {
"amount": 130,
"currency": "USD"
},
"ordinal": 1,
"modifier_list_id": "ZVSGY6U63IGCZQL4IOPZAKYW"
}
}
]
}
}
]
}