POS Product Configuration

Product types

When syncing products to Deliverect, you need to specify the relevant productType value, which is an integer that corresponds to it's intended function. These are defined in the table below;

Product TypeInteger ValueInteger Value
ProductA 'top level' item on a menu (can also be grouped within a modifier group or bundle)1
ModifierOptions selectable when ordering a product, typically modifications of the product2
Modifier GroupA grouping of modifiers (can also group products)3
BundleCan only contain products which are offered as part of a 'Meal Deal' and which Deliverect will set to zero value. Exception to this is where Overloads are set4

PLU

The PLU is typically something that's easier for the customer to use, and it should be the same across all locations for the same product. The PLU is what will be used for mapping orders coming from the channels to your integrated POS.

Price

Price is stored as an int with 2 decimal digits, for example, 5 euros is stored as 500.

Price Levels

All Product and Modifier items include a base "price" field. Optionally, additional prices can be defined using "priceLevels" in order to support different pricing for specific ordering channels and menu fulfilment type.

The "priceLevels" object for a product or modifier should include:

  • A price level property name which will be it's unique identifier.
  • An corresponding integer value defining the price to apply

The price level identifier set must also be defined in a "priceLevels" array, where each entry requires:

  • "posId" – this is the unique identifier referenced in product and modifier price levels.
  • "name" – a descriptive label which will be displayed in channel settings.

When configured as in below example, price levels can be mapped via channel link settings to a specified menu fulfilment type e.g. a 'First Party' channel can have a unique price level set for 'Delivery' , 'Pickup' and 'Eati-in' menus. The mapping process is described in the Price Level guide here. You can verify the configuration by previewing menus and switching between channels.

Example

In the example below, a product will be sold at different prices when correctly mapped on the ordering channel:

{
    "products": [
        {
            "name": "Ginger Beer",
            "productType": 1,
            "plu": "DRNK-03",
            "price": 350,
            "priceLevels": {
                "TA": 350,
                "DL": 400,
                "1PO": 300
            }
        }
    ],
    "priceLevels": [
        {
            "name": "Takeaway",
            "posId": "TA"
        },
        {
            "name": "Delivery",
            "posId": "DL"
        },
        {
            "name": "First Party",
            "posId": "1PO"
        }
    ]
}
⚠️

Ensure the same "posId" values are used across different locations in the same account

Tax

It is important to specify the sales tax rate which applies to any item. The sales tax which applies can be differentiated between the order types of;

  • Delivery (deliveryTax)
  • Takeaway (takeawayTax)
  • Eat-in (eatInTax)

Tax rates should be stored as an int with 3 decimal digits e.g. 5% would be 5000

It's acceptable to have a 0% tax

{
  "productType": 1,
  "plu": "GB-02",
  "name": "Ginger Beer",
...
  "deliveryTax": 5000,
  "takeawayTax": 5000,
  "eatInTax": 0,

Bag Fee

In certain regions, ordering platforms are required to process a specific payment for a bag fee. Deliverect will by default included this fee within the serviceCharge. It is also an option for the POS to sync a bag fee product with a unique PLU, this would need manually set per channel but will ensure the POS receives the bag fee as seperate item in the orders payload.

See guide on setting a bag fee PLU here

Ingredient Groups & Modifier Deltas

An attribute can be set on a modifier group to identify it as an 'Ingredient Group' "isIngredientGroup": true, to indicate that it includes options which will be included by default. When this in place, the order payload will pass only the delta, whereby if a customer removes or adds an option from this group, an attribute "modifierAction" will specify "NO"/"ADD"

This typically applies to Pizza ordering, where kitchen teams will want to review only what differs from the standard toppings included by default in the item.

Default Selection via Scopes

To mark an item as selected by default when offered on specific items only, an attribute "overloads" allows for a defined list of "scopes" . Below, the "Mozzarella" and "Pizza Sauce" are set with a specific combination of product and modidifer group PLUs e.g. "BYOP-00-->>BYOP-TOP"meaning that the only within this combination will the "defaultQuantity":1 apply.

ℹ️

Ingredients without pricing only

It is only possible to define items with zero price within modifier groups with the flag "isIngredientGroup": true

{
    "products": [
        {
            "name": "Build your own Large Pizza",
            "productType": 1,
            "plu": "BYOP-00",
            "subProducts": [
                "TOP",
                "EXTRAS"
            ]
        },
        {
            "name": "Toppings",
            "plu": "TOP",
            "isIngredientGroup": true,
            "min": 0,
            "max": 3,
            "multiMax": 1,
            "productType": 3,
            "subProducts": [
                "SAUCE",
                "MOZ",
                "CH_F"
            ]
        },
        {
            "name": "Mozzarella",
            "deliveryTax": 1200,
            "plu": "MOZ",
            "price": 0,
            "productType": 2,
            "overloads": [
                {
                    "scopes": [
                        "BYOP-00-->>BYOP-TOP"
                    ],
                    "defaultQuantity": 1
                }
            ]
        },
        {
            "name": "Pizza Sauce",
            "deliveryTax": 1200,
            "plu": "SAU",
            "price": 0,
            "productType": 2,
            "overloads": [
                {
                    "scopes": [
                        "BYOP-00-->>BYOP-TOP"
                    ],
                    "defaultQuantity": 1
                }
            ]
        }
    ]
}

Modifier Delta

When a customer has removed a default topping from an order, the order payload will indicate this as in snippet below "modifierAction": "NO" similarly, if an optional item from the ingredient group is included it will show "modifierAction": "ADD"

{
  "items": [
    {
      "name": "Build your own Large Pizza",
      "subItems": [
        {
          "plu": "E-Mz-O1-",
          "name": "Mozzarella",
          "modifierAction": "NO"
        }
      ]
    }
  ]
}
{
  "items": [
    {
      "name": "Build your own Large Pizza",
      "subItems": [
        {
          "plu": "CH_F",
          "name": "Chili Flakes",
          "modifierAction": "ADD"
        }
      ]
    }
  ]
}
⚠️

Only for Default Ingredients

For any mandatory modifier groups e.g. for Pizza, the "Size" and "Crust" or other single-select groups, these should not be set as isIngredientGroup": true as these selections need to pass through on the order webhook and no delta logic needs applied.

Overloads

Specific item attributes can be overridden depending on the item or grouping it is offered within.

It's primary purpose is to set context-specific pricing e.g. surcharges applied to combo products to alter the base price normally applied. The same structure can also be applied for other attributes to alter the base values in place.

An overload consists of:

  • A "scopes" array containing one or more PLU identifiers.
  • One or more override properties e.g. "price" or "bundlePrice"
{
  "overloads": [
    {
      "scopes": ["PLU-123"],
      "<property>": "<override value>"
    }
  ]
}

Supported Overload Values

PropertyDescription
priceStandard price override
bundlePriceBundle group specific price override productType:4
defaultQuantityA default quantity of greater or equal to 1 is a "pre-selected" item
minMinimum selection quantity allowed
maxMaximum selection quantity allowed
multiMaxMaximum quantity of multiple selections of the same item
nameDisplay name
descriptionDescription text
nameTranslationsLocalized names
descriptionTranslationsLocalized descriptions
imageUrlProduct image
visibleVisibility flag (enabled/disabled)

Overloads Pricing Rules

The pricing property for overloads depends on the type of group in which the product is being used:

Group TypeOverride Property
Modifier Group (type: 3)price
Bundle Group (type: 4)bundlePrice

the example below and also in samples 4 and 5 in the Insert/update products page, you can see both a product and modifier price being set this way.

The "overloads" array contains "scopes" which specify the group(s) in which either a"bundlePrice"(if a bundle group) or "price"(if not a bundle group) can be set differently.

In the first example below, an Avocado with base price 50, can be set to 0 if included in a group "FREE-TOP" and set to 100 if set in a group "XTRA-TOP"

The second example shows the same format for an Ice Cream with a base price 500, which can be set to 0 if included in a group "FREE-DESS" and 450 if set in a group "ADD-ON"it used the bundlePrice attribute as the group is not a modifier group (productType:3) but bundle (productType:4)

Overloads Examples - Price Overrides

The modifier in the first example has a base price of 50, but when chosen within the modifier group FREE-TOP, it's price will be set at 0 and when chosen within a product with PLU: BRGR it's price is 450

Similarly, in the second example, the base price of the Ice Cream, 500 becomes 0 when chosen in a bundle group with PLU "FREE-DESS" and 450 when chosen within a combo product with PLU: BRGR_COMBO

Overloads Examples - Default Quantity

In the third example, the Chicken Tenders is set with "defaultQuantity": 1 and will pre-selected only when displayed within a modifier group with PLU: CHK_MEAL

{
    "productType": 2,
    "plu": "AVO",
    "price": 50,
    "name": "Avocado",
    "overloads": [
        {
            "scopes": [
               "FREE-TOP"
            ],
            "price": 0
        },
        {
            "scopes": [
               BRGR"
            ],
            "price": 100
        }
    ]
}
{
    "productType": 1,
    "plu": "IC",
    "price": 500,
    "name": "Ice Cream",
    "overloads": [
        {
            "scopes": [
               "FREE-DESS"
            ],
            "bundlePrice": 0
        },
        {
            "scopes": [
               "BRGR_COMBO"
            ],
            "price": 450
        }
    ]
}
{
    "productType": 1,
    "plu": "PROD-1",
    "price": 500,
    "name": "Chicken Tenders",
    "overloads": [
        {
            "scopes": [
               "CHK_MEAL"
            ],
            "defaultQuantity": 1
        }
    ]
}

Images

The image URL you provide here is cached and put behind a CDN. Images are cached on access for 24 hours. Channels will download the images and also cache them. Depending on the channel, images can/will be resized. Deliverect supports images of up to 16.8 megapixels in size.

Categories

A category is a way to organise products into a section to be referenced when building a menu. Products can be in one or more categories denoted by an array of posCategoryIds. It's important to have at least one category per product.

Overrides

Customers are able to overwrite certain details of products within the menu builder in Deliverect, including;

  • Names
  • Descriptions
  • Prices
  • Images

*Everything that is not overwritten in Deliverect can be updated via this endpoint

Modifier Groups

The first example below represents a simple Product (productType:1) with three modifier groups attached (productType:3) where each modifier group contains an amount of modifiers (productType:2)

Typical use case: This structure would support standard modifications to a product e.g. required modifiers of 'Rare', 'Medium' or 'Well Done' would be applied to a Steak product.


{ 
 
  "products": [
    {
      "productType": 1,
      "plu": "STK-01",
      "price": 1500,
      "name": "Delicious Steak Frites",
      "deliveryTax": 9000,
      "takeawayTax": 9000,
      "eatInTax": 9000,
      "posCategoryIds": [
        "STK"
      ],

      "description": "Delicious Steak Frites",
      "subProducts": [    
        "MOD"
   
      ]
    },
    
    {
      "productType": 3,
      "plu": "MOD",
      "name": "Add a side",
      "imageUrl": "",
      "description": "Pizza made for cheese fanatics",
    
      "subProducts": [
        "SI-01",
        "SI-02",
        "SI-03"
      ],
      "min": 0,
      "max": 0,
      "multiMax": 3
    },
  
    {
      "productType": 2,
      "plu": "SI-01",
      "price": 0,
      "name": "Fries",
      "posCategoryIds": [
        "SD"
      ],
      "imageUrl": "",
      "description": "Fries",
      "deliveryTax": 9000,
      "takeawayTax": 9000,
      "eatInTax": 9000
    },
    {
      "productType": 2,
      "plu": "SI-02",
      "price": 200,
      "name": "Salad",
      "kitchenName": "",
      "posCategoryIds": [
        "SD"
      ],
      "imageUrl": "",
      "description": "Salad",
 
      "deliveryTax": 9000,
      "takeawayTax": 9000,
      "eatInTax": 9000
    },
    {
      "productType": 2,
      "plu": "SI-03",
      "price": 100,
      "name": "Mashed Potato",
      "kitchenName": "Mash",
      "posProductId": "POS-ID-014",
      "posCategoryIds": [
        "SD"
      ],
      "imageUrl": "",
      "description": "Mashed Potato",
     
      "deliveryTax": 9000,
      "takeawayTax": 9000,
      "eatInTax": 9000
    }
  ],
  "categories": [
    {
      "name": "Steaks",
      "posCategoryId": "STK"
    },
    {
      "name": "Sides",
      "posCategoryId": "SD"
    }
  ]
}

This same structure can also be applied to group together products (productType:1) within modifier groups (productType:3)

Typical use case: This structure is often applied as an "Upsell" where additional optional priced items are offered alongside a product.

    {
      "productType": 1,
      "plu": "STK-01",
      "price": 1500,
      "name": "Delicious Steak Frites",
      "deliveryTax": 9000,
      "takeawayTax": 9000,
      "eatInTax": 9000,
      "posCategoryIds": [
        "STK"
      ],

      "description": "Delicious Steak Frites",
      "subProducts": [    
        "Drink"
   
      ]
    },
    
    {
      "productType": 3,
      "plu": "Drink",
      "name": "Add a Drink",
      "imageUrl": "",
      "description": "Select a drink with your meal",
    
      "subProducts": [
        "DR-01",
        "DR-02",
        "DR-03"
      ],
      "min": 0,
      "max": 0,
      "multiMax": 3
    },
  
    {
      "productType": 1,
      "plu": "DR-01",
      "price": 0,
      "name": "Coke",
      "posCategoryIds": [
        "DR"
      ],
      "imageUrl": "",
      "description": "Fries",
      "deliveryTax": 9000,
      "takeawayTax": 9000,
      "eatInTax": 9000
    },
    {
      "productType": 1,
      "plu": "DR-02",
      "price": 200,
      "name": "Ginger Beer",

      "posCategoryIds": [
        "DR"
      ],
      "imageUrl": "",
      "description": "Salad",
 
      "deliveryTax": 9000,
      "takeawayTax": 9000,
      "eatInTax": 9000
    },
    {
      "productType": 1,
      "plu": "DR-03",
      "price": 100,
      "name": "Fanta",
     
      "posProductId": "POS-ID-014",
      "posCategoryIds": [
        "DR"
      ],
      "imageUrl": "",
      "description": "Fanta ",
     
      "deliveryTax": 9000,
      "takeawayTax": 9000,
      "eatInTax": 9000
    }
  ],
  "categories": [
    {
      "name": "Steaks",
      "posCategoryId": "STK"
    },
    {
      "name": "Drinks",
      "posCategoryId": "DR"
    }
  ]
}

Item Rules

Individual items can have rules set against them to control how they can be ordered online

RulePurposeType
multiMaxTo restrict the number of products that can be sold within one order e.g. pharmaceuticals. You can achieve this by adding the attribute "multiMax" e.g. "multiMax": 1, prevents more than one of the items being added to the basket.Integer
defaultQuantityThis attribute makes a modifier preselected by default, where a value of 1 is equivalent to a pre-selected item. Most channels can handle a pre-selection, but not with a pre-selected quantity of more than 1Integer

Item Group Rules

Both Modifier Groups and Bundles allow certain ordering "rules" to be applied as follows;

RulePurposeType
minSetting a minimum value to a group of options e.g. 0would be equivalent to 'optional'and1or more would be 'required'Integer
maxSetting a maximum value limits how many items in a group can be orderedInteger
multiMax

Setting the attribute multiMax allows control over the maximum quantity of any single item in a group.

A value of '2' for example, means that each item in a group can be selected at most 2 times. The selection of a single item will still be limited by the overall max value allowed in a group

Integer

Meal Deals

In the payload examples on this page, shown on the right hand side, various product structures are depicted including combos and meal deals.

These examples use the structure below, where products are linked together using the subProducts field.

Meal Deal / Combo Structure

A meal deal or combo will typically have a set price, where a grouping of a 'Bundle' can contain products which normally have a price, but as part of a bundle will be zero-priced.

The diagram below shows that it is possible to contain the zero-priced 'Bundle' options as well as 'Modifier Groups' containing priced items.

❗️

Important Attribute for Combos/Meal Deals

Please ensure the attribute "isCombo": true is set on the main product "productType": 1 and linked to a Bundle groups"productType": 4, as certain channels need this flag and Bundle groups to display these options correctly

Bundles cannot be nested under a sub-product and must be at the top level of options.

The structure to form bundles could be as follows:

  • Combo product Type:1
  • Bundle Type:4
    • Product Type:1
      • Modifier group Type:3
        • Modifier Type:2

Nested Modifiers

A product configuration can include a sub-group of options to be selected. These options themselves can also contain their own sub-groups, this is reffered to as 'Nested Modifiers'.

Meal Deal with 'Upsell'

In the Meal Deal with upsell (example 3) we have a modifier group in addition to the bundles. This allows for Fries to be ordered which are not included as part of the deal and the customer will be charged accordingly. This is referred to as an 'upsell', which can be modifier groups containing products or modifiers.

It is also possible to construct combo products as follows:

  • Combo product Type:1
  • Modifier group Type:3
    • Modifier Type:2
      • Modifier group Type:3
        • Modifier Type:2

Click here to see examples of how orders with these meal deal examples are sent to your POS in an order.

Variants

A variant in a menu allows customers to choose from different versions of a product, such as pizza sizes or beverage flavors. The variant product displays the lowest price, then allows the customer to choose from a list of variations of the product by showing additional costs for selecting larger sizes, ensuring clear and transparent pricing for customization.

"products": [
    {
      "productType": 1,
      "plu": "VAR-PROD-1",
      "price": 0,
     ...
      "isVariant": true,
    ...
      "subProducts": [
        "MG-VAR-1"
      ]
    },
{
      "productType": 3,
      "plu": "MG-VAR-1",
      "name": "How many pieces?",
      "posProductId": "POS-002",
      "isVariantGroup": true,
      "subProducts": [
        "VAR-1",
        "VAR-2",
        "VAR-3"
      ]

Follow the "Example 6 - Variant products" on the insert/update products endpoint.

Chicken tenders: €8

3 pieces: + €0
6 pieces: + €3
9 pieces: + €5.50

For example, Chicken Tenders start at €8. If a customer selects 3 pieces, the price remains €8. If they choose 6 pieces, an additional €3 is added, making the total €11. For 9 pieces, an extra €5.50 is added, bringing the total to €13.50.


Auto Apply

There can be a use case where products ordered online should be received with a pre-defined set of sub products applied. This is not the same as items being pre-selected in the menu interface via defaultQuantity, but is a mechanism for specific items to be auto-applied (by Deliverect) following a completed order.

This is shown in the example below, where the Parsley Garnish and Melted Butter are within a modifier group 'Garnishes' which is set to apply these items automatically when the Steak Frites is ordered.

Note that "defaultQuantity": 3 is shown below and defines how many of the item should be auto-applied to the order. The "sortOrder" attribute allows a 'stepped' order of the auto-applied items to appear, where 0 is the first item to be listed.

'NB: Neither the channel platform or end-consumer will see the auto-applied items, and as such there can be no price associated with them. If de-selection of pre-set items or charging for them is a requirement,"defaultQuantity" can be used without "autoApply" (See 'Item Rules').

"autoApply": [
    {
        "plu": "PR1"
    },
    {
        "plu": "PR2"
    }
],
{
    "productType": 2,
    "plu": "PR1",
    "price": 0,
    "name": "Parsley",
    "posProductId": "PA_POS-0023",
    "posCategoryIds": "",
    "imageUrl": "",
    "description": "",
    "deliveryTax": 0,
    "takeawayTax": 0,
    "subProducts": [],
    "defaultQuantity": 3,
    "sortOrder": 1
}

Translations

Translations are supported for all product types and both the name and description can be set with a translated value. Additionally, category names and descriptions can be translated. can be provided in the JSON. A base name is always required but translations are optional.

See examples of the nested object for translations below, where the property key is the language tag and the value is the translation itself.

See all language tags supported via the link below;

▶ Language Tags

Translation Examples

{
    "productType": 1,
    "plu": "MEAT-02",
    "price": 200,
    "name": "Chicken",
    "nameTranslations": {
        "ar": "دجاج",
        "en": "Chicken",
        "es": "Pollo",
        "nl": "Kip"
    },  
    "description": "Grilled chicken",
    "descriptionTranslations": {
        "ar": "دجاج مشوي",
        "en": "Grilled chicken.",
        "es": "Pollo asado.",
        "nl": "Gegrilde kip."
    }
}
{
    "posCategoryId": "B2",
    "name": "Burgers",
    "nameTranslations": {
        "ar": "برجر",
        "pt": "Hambúrgueres",
        "es": "Hamburguesas",
        "zh": "汉堡"
    },
    "imageUrl": "https://storage.googleapis.com/ikona-bucket-production/images/5be9fe94c6489f0001b2fe57/174466-666abfd750c486d4c3a2d5a9.jpg",
    "description": "Our Burgers are made with 100% all-natural Angus beef, responsibly raised and cooked to order",
    "descriptionTranslations": {
        "ar": "برجراتنا مصنوعة من لحم أنجوس طبيعي 100%، تم تربيتها بمسؤولية ويتم طهيها حسب الطلب",
        "pt": "Nossos hambúrgueres são feitos com 100% de carne Angus totalmente natural, criada de forma responsável e cozida a pedido",
        "es": "Nuestras hamburguesas están hechas con carne Angus 100% natural, criada de manera responsable y cocinada a pedido",
        "zh": "我们的汉堡采用100%天然安格斯牛肉制作,经过负责任的养殖,并按订单烹制"
    }
}

Product visibility

A product can be marked as invisible (disabled) by setting visible property to false. After this action the product will be hidden all menus where it was used and will not be pushed to channels until it marked as visible again.

For more granularity on "visible" status, this can be applied at a channel level, see guide [here](status at a channel level,)

{
    "productType": 1,
    "plu": "SI-01",
    "price": 100,
    "name": "Fries",
    "visible": false
}

Product tags: consumable types and allergens

A product can have one or more product tags. These are are contained inside productTags

In below example snippet, 104 and 109 are values representing 'eggs' and 'peanuts'

{
  "productType": 1,
  "plu": "P-SATE",
  "price": 450,
  "name": "Chicken Sate",
...
  "productTags": [
    104,
    110
  ]
},

See link below for a complete list of tags available;

▶ Product Tags

Nutritional Information and Supplemental Info

A product can be set with nutritional and supplemental information e.g. packaging, additives etc and certain attributes shown in the link below will be legally required in some regions;

▶ Nutritional & Supplemental Info

Calories

Calories can be sent as in the example shown below;

ParameterMeaning
caloriesThis is the base calorie amount, where a maximum calories is set, this should be interpreted as the 'minimum'
caloriesRangeHighThe maximum calorie amount of an item
"products": [
          {
               "productType": 1,
               "plu": "PR03",
               "price": 900,
               "name": "Cheese Lovers Pizza",
               ...
               "calories": 500,
               "caloriesRangeHigh": 750
               },
               ...
               ]
          },