Introduction

The Menu API allows you to manage your Deliveroo menu from a third party system. This API consists of one webhook & a few endpoints.

๐Ÿ“˜

Available in Suites:

  • Partner Platform
  • Retail Platform

Glossary

The Deliveroo Menu API consists of the following components:

Item: An item is a single element that a user selects when browsing through one of your sites menus on Deliveroo. For example, an item could be a sandwich, a cheesecake, or a pizza.

Modifiers: Modifiers are a variant option for a particular item on the menu. Modifiers present the option to let users customize their orders based on their preferences. For example, a modifier for a sandwich can be 'Extra Cheese', 'Gluten free bread', 'Mustard'.

Category: A category represents a logical grouping of items that make is easier for users to navigate your menu. For example, categories in your menus could be 'Appetizers', 'Mains', 'Desserts'. If you are running a promotion, you could also include a category called 'Specials', or 'Deal of the Day' as a category.

Menu: A menu groups together one or more categories to present a single complete view of your offerings to your users.

๐Ÿ“˜

Menu Manager

Menu Manager lives in the Restaurant Hub which is a management tool for restaurants on Deliveroo platform. If your restaurant partner originally managed the menus through this tool you can pull this menu via the API instead of building the menu from scratch.

Why Connect?

Improve your customer experience by making your latest menu available instantly and impossible to order out-of-stock items.

  • A single view of inventory and Deliveroo menu management.
  • Automatically updates your Deliveroo menu to match your POS.
  • Reduces order errors and rejections - menu items always have the correct PLU/SKU.

Brand ID

Before you can use Menu API to manage menus, PLUs and item unavailabilities, you need to know the brand_id that needs to be passed as path parameter to the endpoints performing those operations. You can call Get Site Brand ID endpoint to get the correct brand id for each site.

Updating your menu

A partner can upload a menu to Deliveroo as well as get a recently uploaded menu.

  1. The partner submits a menu to be updated.
  2. Deliveroo accepts the menu payload, performs a validation and starts asynchronous menu processing.
  3. Once the menu is processed and published the webhook to notify a partner is called.
  4. If the menu has been successfully uploaded the partner can download it from Deliveroo by using Get menu endpoint.

See OAS specification for details.

๐Ÿ“˜

Unchanged menus

In the case of the menu details to be uploaded are the same as the existing menu details, then a successful response is returned with the additional information of the result. The result will contain the value MATCH_EXISTING_MENU.

{
    "result": "MATCH_EXISTING_MENU"
}

The Menu Event Webhook allows you to receive notifications about the result of menu uploading, particularly about image issues.

The webhook will be delivered after each successful Menu Upload request (excluding the case when the menu matches existing menu โ€“ย see "Unchanged menus" above), specifically after the asynchronous menu processing is finished โ€“ regardless of whether it's successful or not. For more details about the webhook see the OAS spec.

๐Ÿ“˜

Delivery failure and retries

A successful webhook callback occurs when the server responds with an HTTP 2xx success range; any other HTTP status or a timeout will result in a retry.

Our servers will retry failed webhook callbacks applying exponential back-off delays and circuit breaking when failures are successive in a short amount of time.

When the circuit breaker is tripped, the total number of requests per minute is significantly reduced until the endpoint appears healthy again.

For menu events, we "give up" and discard the event callback after 30 minutes.

๐Ÿšง

Note

Please notice that while every attempt is made to make callbacks in the order they occurred and in a timely manner, neither can be absolutely guaranteed. It is also possible to receive the same callback more than once.

๐Ÿ“˜

Configuring a menu update webhook

You can configure Menu Event webhook URL through the Change Integrator's Menu Webhook endpoint.

You can retrieve the currently configured URL any time through the Get Integrator's Menu Webhook.

Examples

{
  "name": "site-234 menu",
  "menu": {
    "categories": [
      {
        "description": {
          "en": "Freshly made porridge"
        },
        "id": "porridge",
        "item_ids": [
          "porridge_blueberries",
          "porridge_banana"
        ],
        "name": {
          "en": "Porridge ๐Ÿฅฃ"
        }
      },
      {
        "description": {},
        "id": "drinks",
        "item_ids": [
          "tea",
          "coffee",
          "orange_juice"
        ],
        "name": {
          "en": "Drinks โ˜•๏ธ"
        }
      },
      {
        "description": {},
        "id": "breakfast-bundle",
        "item_ids": [
          "breakfast-bundle"
        ],
        "name": {
          "en": "Breakfast bundle ๐Ÿ“ฆ"
        }
      }
    ],
    "items": [
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {},
        "diets": [],
        "external_data": "",
        "highlights": [],
        "barcodes": ["725272730706", "9780201379624", "4605664000050"],
        "id": "orange_juice",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": null,
        "modifier_ids": [],
        "name": {
          "en": "Orange juice"
        },
        "nutritional_info": {},
        "operational_name": "orange-juice",
        "plu": "orange_juice_$69",
        "price_info": {
          "overrides": [
            {
              "id": "breakfast-bundle",
              "price": 0,
              "type": "ITEM"
            }
          ],
          "price": 250
        },
        "tax_rate": "20",
        "type": "ITEM"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": "Porridge with a drink of your choice."
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "barcodes": ["5012345678900", "3014260115531"],
        "id": "breakfast-bundle",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": null,
        "modifier_ids": [
          "choose_your_porridge",
          "choose_your_drink"
        ],
        "name": {
          "en": "Breakfast bundle"
        },
        "nutritional_info": {},
        "operational_name": "Breakfast bundle",
        "plu": "breakfast_bundle123",
        "price_info": {
          "overrides": [],
          "price": 450
        },
        "tax_rate": "20",
        "type": "ITEM"
      },
      {
        "allergies": [
          "milk"
        ],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": "Porridge with blueberries and cinnamon"
        },
        "diets": [],
        "external_data": "",
        "highlights": [
          "in_store_price"
        ],
        "barcodes": ["50123452"],
        "id": "porridge_blueberries",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": 2,
        "modifier_ids": [
          "extra_toppings"
        ],
        "name": {
          "en": "Porridge with blueberries"
        },
        "nutritional_info": {
          "energy_kcal": {
            "high": 456,
            "low": 123
          },
          "hfss": false
        },
        "operational_name": "Porridge with blueberries",
        "plu": "porridge_blueberries123",
        "price_info": {
          "overrides": [
            {
              "id": "breakfast-bundle",
              "price": 0,
              "type": "ITEM"
            }
          ],
          "price": 350
        },
        "tax_rate": "20",
        "type": "ITEM"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": ""
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "barcodes": ["799439112766"],
        "id": "whole_milk",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": null,
        "modifier_ids": [],
        "name": {
          "en": "Whole milk"
        },
        "nutritional_info": {},
        "operational_name": "whole-milk",
        "plu": "whole_milk_$39",
        "price_info": {
          "overrides": [],
          "price": 0
        },
        "tax_rate": "20",
        "type": "CHOICE"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {},
        "diets": [],
        "external_data": "",
        "highlights": [],
        "barcodes": ["5024121099847"],
        "id": "coffee",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": 2,
        "modifier_ids": [
          "choose_milk"
        ],
        "name": {
          "en": "Coffee"
        },
        "nutritional_info": {},
        "operational_name": "coffee",
        "plu": "coffee_$78",
        "price_info": {
          "overrides": [
            {
              "id": "breakfast-bundle",
              "price": 0,
              "type": "ITEM"
            }
          ],
          "price": 250
        },
        "tax_rate": "20",
        "type": "ITEM"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {},
        "diets": [],
        "external_data": "",
        "highlights": [],
        "barcodes": ["0799439112766"],
        "id": "tea",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": 4,
        "modifier_ids": [
          "choose_milk"
        ],
        "name": {
          "en": "Tea"
        },
        "nutritional_info": {},
        "operational_name": "tea",
        "plu": "tea_$23",
        "price_info": {
          "overrides": [
            {
              "id": "breakfast-bundle",
              "price": 0,
              "type": "ITEM"
            }
          ],
          "price": 150
        },
        "tax_rate": "20",
        "type": "ITEM"
      },
      {
        "allergies": [
          "peanuts"
        ],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": "Crunchy peanut butter"
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "barcodes": ["5024121519116"],
        "id": "peanut_butter",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": false,
        "max_quantity": 2,
        "modifier_ids": [],
        "name": {
          "en": "Peanut butter"
        },
        "nutritional_info": {},
        "operational_name": "peanut-butter",
        "plu": "peanut_butter_123",
        "price_info": {
          "overrides": [],
          "price": 100
        },
        "tax_rate": "20",
        "type": "CHOICE"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": "Granola"
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "barcodes": ["1234567890128"],
        "id": "granola",
        "image": {},
        "is_eligible_as_replacement": false,
        "is_eligible_for_substitution": false,
        "max_quantity": 2,
        "modifier_ids": [],
        "name": {
          "en": "Granola"
        },
        "nutritional_info": {},
        "operational_name": "granola",
        "plu": "granola_123",
        "price_info": {
          "overrides": [],
          "price": 100
        },
        "tax_rate": "20",
        "type": "CHOICE"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": ""
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "barcodes": ["5060040253731"],
        "id": "no_milk",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": 2,
        "modifier_ids": [],
        "name": {
          "en": "No milk"
        },
        "nutritional_info": {},
        "operational_name": "no-milk",
        "plu": "no_milk_$49",
        "price_info": {
          "overrides": [],
          "price": 0
        },
        "tax_rate": "20",
        "type": "CHOICE"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": "Honey"
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "barcodes": ["3560070323067"],
        "id": "honey",
        "image": {},
        "is_eligible_as_replacement": false,
        "is_eligible_for_substitution": true,
        "max_quantity": null,
        "modifier_ids": [],
        "name": {
          "en": "Honey"
        },
        "nutritional_info": {},
        "operational_name": "honey",
        "plu": "honey_123",
        "price_info": {
          "overrides": [],
          "price": 0
        },
        "tax_rate": "20",
        "type": "CHOICE"
      },
      {
        "allergies": [
          "milk"
        ],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": "Porridge with bananas and cinnamon"
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "barcodes": ["5000168036755"],
        "id": "porridge_banana",
        "image": {},
        "is_eligible_as_replacement": false,
        "is_eligible_for_substitution": true,
        "max_quantity": 2,
        "modifier_ids": [
          "extra_toppings"
        ],
        "name": {
          "en": "Porridge with bananas"
        },
        "nutritional_info": {},
        "operational_name": "porridge-ban",
        "plu": "porridge_banana123",
        "price_info": {
          "overrides": [
            {
              "id": "breakfast-bundle",
              "price": 0,
              "type": "ITEM"
            }
          ],
          "price": 350
        },
        "tax_rate": "20",
        "type": "ITEM"
      }
    ],
    "mealtimes": [
      {
        "category_ids": [
          "breakfast-bundle",
          "porridge",
          "drinks"
        ],
        "description": {
          "en": "Best breakfast menu in town! Everything on the menu is freshly made at the start of the day."
        },
        "id": "breakfast-menu",
        "image": {
          "url": "https://.../image-url-with-unknown-format.jpg"
        },
        "name": {
          "en": "Breakfast menu"
        },
        "schedule": [
          {
            "day_of_week": 0,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          },
          {
            "day_of_week": 1,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          },
          {
            "day_of_week": 2,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          },
          {
            "day_of_week": 3,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          },
          {
            "day_of_week": 4,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          },
          {
            "day_of_week": 5,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          },
          {
            "day_of_week": 6,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          }
        ],
        "seo_description": null
      }
    ],
    "modifiers": [
      {
        "description": {
          "en": ""
        },
        "id": "choose_milk",
        "item_ids": [
          "no_milk",
          "whole_milk"
        ],
        "max_selection": 1,
        "min_selection": 0,
        "name": {
          "en": "Choose milk"
        },
        "repeatable": true
      },
      {
        "description": {
          "en": ""
        },
        "id": "choose_your_porridge",
        "item_ids": [
          "porridge_blueberries",
          "porridge_banana"
        ],
        "max_selection": 1,
        "min_selection": 0,
        "name": {
          "en": "Choose your porridge"
        },
        "repeatable": true
      },
      {
        "description": {
          "en": ""
        },
        "id": "choose_your_drink",
        "item_ids": [
          "tea",
          "coffee",
          "orange_juice"
        ],
        "max_selection": 1,
        "min_selection": 0,
        "name": {
          "en": "Choose your drink"
        },
        "repeatable": true
      },
      {
        "description": {
          "en": ""
        },
        "id": "extra_toppings",
        "item_ids": [
          "honey",
          "peanut_butter",
          "granola"
        ],
        "max_selection": 3,
        "min_selection": 0,
        "name": {
          "en": "Choice of extra toppings ๐Ÿฏ"
        },
        "repeatable": false
      }
    ]
  },
  "site_ids": [
    "site-234",
    "site-456"
  ]
}
{
  "event": "menu.upload_result",
  "body": {
    "menu_upload_result": {
      "http_status": 200,
      "brand_id": "brand-external-id",
      "menu_id": "site-234 menu",
      "site_ids": [
        "site-234",
        "site-456"
      ],
      "errors": {
        "processing": "",
        "images": [
          {
            "url": "https://.../image-url-with-unknown-format.jpg",
            "message": "cannot decode image to assess size requirements: image: unknown format"
          }
        ],
        "barcodes": [
          {
            "barcode": "3835112311342",
            "message": "invalid checksum"
          }
        ]
      }
    }
  }
}

Getting your menu

The Get Menu API allows you to retrieve the menu currently live. There 2 versions of the endpoint available to retrieve the menu: a by menu ID specified during API integration and b by the site to which the menu is assigned.

You can't GET a menu from the API without updating it first, but you can get the menu from Menu Manager first.

Examples

{
  "name": "site-234 menu",
  "menu": {
    "categories": [
      {
        "description": {
          "en": "Freshly made porridge"
        },
        "id": "porridge",
        "item_ids": [
          "porridge_blueberries",
          "porridge_banana"
        ],
        "name": {
          "en": "Porridge ๐Ÿฅฃ"
        }
      },
      {
        "description": {},
        "id": "drinks",
        "item_ids": [
          "tea",
          "coffee",
          "orange_juice"
        ],
        "name": {
          "en": "Drinks โ˜•๏ธ"
        }
      },
      {
        "description": {},
        "id": "breakfast-bundle",
        "item_ids": [
          "breakfast-bundle"
        ],
        "name": {
          "en": "Breakfast bundle ๐Ÿ“ฆ"
        }
      }
    ],
    "items": [
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {},
        "diets": [],
        "external_data": "",
        "highlights": [],
        "ian": "725272730706",
        "barcodes": ["725272730706", "9780201379624", "4605664000050"],
        "id": "orange_juice",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": null,
        "modifier_ids": [],
        "name": {
          "en": "Orange juice"
        },
        "nutritional_info": {},
        "operational_name": "orange-juice",
        "plu": "orange_juice_$69",
        "price_info": {
          "overrides": [
            {
              "id": "breakfast-bundle",
              "price": 0,
              "type": "ITEM"
            }
          ],
          "price": 250
        },
        "tax_rate": "20",
        "type": "ITEM"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": "Porridge with a drink of your choice."
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "ian": "5012345678900",
        "barcodes": ["5012345678900", "3014260115531"],
        "id": "breakfast-bundle",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": null,
        "modifier_ids": [
          "choose_your_porridge",
          "choose_your_drink"
        ],
        "name": {
          "en": "Breakfast bundle"
        },
        "nutritional_info": {},
        "operational_name": "Breakfast bundle",
        "plu": "breakfast_bundle123",
        "price_info": {
          "overrides": [],
          "price": 450
        },
        "tax_rate": "20",
        "type": "ITEM"
      },
      {
        "allergies": [
          "milk"
        ],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": "Porridge with blueberries and cinnamon"
        },
        "diets": [],
        "external_data": "",
        "highlights": [
          "in_store_price"
        ],
        "ian": "50123452",
        "barcodes": ["50123452"],
        "id": "porridge_blueberries",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": 2,
        "modifier_ids": [
          "extra_toppings"
        ],
        "name": {
          "en": "Porridge with blueberries"
        },
        "nutritional_info": {
          "energy_kcal": {
            "high": 456,
            "low": 123
          },
          "hfss": false
        },
        "operational_name": "Porridge with blueberries",
        "plu": "porridge_blueberries123",
        "price_info": {
          "overrides": [
            {
              "id": "breakfast-bundle",
              "price": 0,
              "type": "ITEM"
            }
          ],
          "price": 350
        },
        "tax_rate": "20",
        "type": "ITEM"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": ""
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "ian": "799439112766",
        "barcodes": ["799439112766"],
        "id": "whole_milk",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": null,
        "modifier_ids": [],
        "name": {
          "en": "Whole milk"
        },
        "nutritional_info": {},
        "operational_name": "whole-milk",
        "plu": "whole_milk_$39",
        "price_info": {
          "overrides": [],
          "price": 0
        },
        "tax_rate": "20",
        "type": "CHOICE"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {},
        "diets": [],
        "external_data": "",
        "highlights": [],
        "ian": "5024121099847",
        "barcodes": ["5024121099847"],
        "id": "coffee",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": 2,
        "modifier_ids": [
          "choose_milk"
        ],
        "name": {
          "en": "Coffee"
        },
        "nutritional_info": {},
        "operational_name": "coffee",
        "plu": "coffee_$78",
        "price_info": {
          "overrides": [
            {
              "id": "breakfast-bundle",
              "price": 0,
              "type": "ITEM"
            }
          ],
          "price": 250
        },
        "tax_rate": "20",
        "type": "ITEM"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {},
        "diets": [],
        "external_data": "",
        "highlights": [],
        "ian": "0799439112766",
        "barcodes": ["0799439112766"],
        "id": "tea",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": 4,
        "modifier_ids": [
          "choose_milk"
        ],
        "name": {
          "en": "Tea"
        },
        "nutritional_info": {},
        "operational_name": "tea",
        "plu": "tea_$23",
        "price_info": {
          "overrides": [
            {
              "id": "breakfast-bundle",
              "price": 0,
              "type": "ITEM"
            }
          ],
          "price": 150
        },
        "tax_rate": "20",
        "type": "ITEM"
      },
      {
        "allergies": [
          "peanuts"
        ],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": "Crunchy peanut butter"
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "ian": "5024121519116",
        "barcodes": ["5024121519116"],
        "id": "peanut_butter",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": false,
        "max_quantity": 2,
        "modifier_ids": [],
        "name": {
          "en": "Peanut butter"
        },
        "nutritional_info": {},
        "operational_name": "peanut-butter",
        "plu": "peanut_butter_123",
        "price_info": {
          "overrides": [],
          "price": 100
        },
        "tax_rate": "20",
        "type": "CHOICE"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": "Granola"
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "ian": "1234567890128",
        "barcodes": ["1234567890128"],
        "id": "granola",
        "image": {},
        "is_eligible_as_replacement": false,
        "is_eligible_for_substitution": false,
        "max_quantity": 2,
        "modifier_ids": [],
        "name": {
          "en": "Granola"
        },
        "nutritional_info": {},
        "operational_name": "granola",
        "plu": "granola_123",
        "price_info": {
          "overrides": [],
          "price": 100
        },
        "tax_rate": "20",
        "type": "CHOICE"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": ""
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "ian": "5060040253731",
        "barcodes": ["5060040253731"],
        "id": "no_milk",
        "image": {},
        "is_eligible_as_replacement": true,
        "is_eligible_for_substitution": true,
        "max_quantity": 2,
        "modifier_ids": [],
        "name": {
          "en": "No milk"
        },
        "nutritional_info": {},
        "operational_name": "no-milk",
        "plu": "no_milk_$49",
        "price_info": {
          "overrides": [],
          "price": 0
        },
        "tax_rate": "20",
        "type": "CHOICE"
      },
      {
        "allergies": [],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": "Honey"
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "ian": "3560070323067",
        "barcodes": ["3560070323067"],
        "id": "honey",
        "image": {},
        "is_eligible_as_replacement": false,
        "is_eligible_for_substitution": true,
        "max_quantity": null,
        "modifier_ids": [],
        "name": {
          "en": "Honey"
        },
        "nutritional_info": {},
        "operational_name": "honey",
        "plu": "honey_123",
        "price_info": {
          "overrides": [],
          "price": 0
        },
        "tax_rate": "20",
        "type": "CHOICE"
      },
      {
        "allergies": [
          "milk"
        ],
        "classifications": [],
        "contains_alcohol": false,
        "description": {
          "en": "Porridge with bananas and cinnamon"
        },
        "diets": [],
        "external_data": "",
        "highlights": [],
        "ian": "5000168036755",
        "barcodes": ["5000168036755"],
        "id": "porridge_banana",
        "image": {},
        "is_eligible_as_replacement": false,
        "is_eligible_for_substitution": true,
        "max_quantity": 2,
        "modifier_ids": [
          "extra_toppings"
        ],
        "name": {
          "en": "Porridge with bananas"
        },
        "nutritional_info": {},
        "operational_name": "porridge-ban",
        "plu": "porridge_banana123",
        "price_info": {
          "overrides": [
            {
              "id": "breakfast-bundle",
              "price": 0,
              "type": "ITEM"
            }
          ],
          "price": 350
        },
        "tax_rate": "20",
        "type": "ITEM"
      }
    ],
    "mealtimes": [
      {
        "category_ids": [
          "breakfast-bundle",
          "porridge",
          "drinks"
        ],
        "description": {
          "en": "Best breakfast menu in town! Everything on the menu is freshly made at the start of the day."
        },
        "id": "breakfast-menu",
        "image": {
          "url": ""
        },
        "name": {
          "en": "Breakfast menu"
        },
        "schedule": [
          {
            "day_of_week": 0,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          },
          {
            "day_of_week": 1,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          },
          {
            "day_of_week": 2,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          },
          {
            "day_of_week": 3,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          },
          {
            "day_of_week": 4,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          },
          {
            "day_of_week": 5,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          },
          {
            "day_of_week": 6,
            "time_periods": [
              {
                "start": "00:00:00",
                "end": "10:29:00"
              }
            ]
          }
        ],
        "seo_description": null
      }
    ],
    "modifiers": [
      {
        "description": {
          "en": ""
        },
        "id": "choose_milk",
        "item_ids": [
          "no_milk",
          "whole_milk"
        ],
        "max_selection": 1,
        "min_selection": 0,
        "name": {
          "en": "Choose milk"
        },
        "repeatable": true
      },
      {
        "description": {
          "en": ""
        },
        "id": "choose_your_porridge",
        "item_ids": [
          "porridge_blueberries",
          "porridge_banana"
        ],
        "max_selection": 1,
        "min_selection": 0,
        "name": {
          "en": "Choose your porridge"
        },
        "repeatable": true
      },
      {
        "description": {
          "en": ""
        },
        "id": "choose_your_drink",
        "item_ids": [
          "tea",
          "coffee",
          "orange_juice"
        ],
        "max_selection": 1,
        "min_selection": 0,
        "name": {
          "en": "Choose your drink"
        },
        "repeatable": true
      },
      {
        "description": {
          "en": ""
        },
        "id": "extra_toppings",
        "item_ids": [
          "honey",
          "peanut_butter",
          "granola"
        ],
        "max_selection": 3,
        "min_selection": 0,
        "name": {
          "en": "Choice of extra toppings ๐Ÿฏ"
        },
        "repeatable": false
      }
    ]
  },
  "site_ids": [
    "site-234",
    "site-456"
  ]
}

Managing unavailabilities

A partner can manage stock unavailability through the API.

There are three possible statuses of an item:

  • available (default) - the item is visible in the menu for the customers,
  • unavailable - the item is "greyed out", "striked-through" and marked as "sold out" on our platform. It will be made available during the next morning stock reset (see below),
  • hidden - the item is not visible in the menu for the customers. It will not be affected by the morning stock reset (see below).

  1. The partner retrieves unavailable items.
  2. The partner sets unavailable or hidden items (multiple items can be used at once), either by using Replace All Unavailabilities endpoint or Update Individual Unavailabilities endpoint.

Endpoints

There are two sets of API endpoints available.

In most cases the v1 endpoints are the ones you need to use.

In a situation when the menu is managed by the partners via Menu Manager graphical interface, but they want to manipulate item unavailabilities using the API, use the v2 endpoints.

v1 (recommended, requires menu ID)v2 (compatible with Menu Manager menus, requires site ID)
Get Item UnavailabilitiesGet Item Unavailabilities v1Get Item Unavailabilities v2
Replace All Unavailabilities (PUT)Replace All Item Unavailabilities v1Replace All Item Unavailabilities v2
Update Individual Unavailabilities (POST)Update Individual Item Unavailabilities v1Update Individual Item Unavailabilities v2

Keep in mind the two important differences between PUT and POST endpoints:

  • Replace All Unavailabilities (PUT) request makes available all the items from the menu that are not explicitly included in the payload. If some items present in the request don't exist on the menu, this doesn't prevent the request from succeeding.
  • Update Individual Unavailabilities (POST) changes only the availability of items explicitly included in it. If some items present in the request don't exist on the menu, the entire request will fail and will have no effect.

Morning stock reset

When a site opens, all unavailable items are made available again and all hidden items remain hidden.

Exception: the morning stock reset doesn't occur for given site on specific day if there was any change done to item unavailabilities (either through API, Deliveroo tablet or Restaurant Hub) between midnight (site's local time) and the time of opening of the site. If you want to take advantage of the morning stock reset, make sure you don't manipulate unavailabilities before the site opens.

Best practices for managing unavailabilities

  1. Use v1 endpoints if you're not interested in handling stock in menus managed by Menu Manager.
  2. Respect the rate limit. The specification of each endpoint mentions its rate limit. You can batch multiple items in a single request to avoid exceeding the limit.
  3. Remember that unavailabilities can be changed through multiple channels (API, Deliveroo tablet, Restaurant Hub). This means that using Replace All Unavailabilities (PUT) request without knowing the current state of the stock can reset availability of items that were made unavailable/hidden by other channels. Thus we recommend to GET the unavailabilities first, so that you're fully aware of state of the stock when preparing the PUT request.
  4. If you want to set item unavailabilities right after calling Upload Menu request, you need to adhere to the following rules:
    1. if the Upload Menu HTTP response has "result": "MATCH_EXISTING_MENU", you can update stock right away.
    2. otherwise, before updating stock, you must first wait to receive the Menu Upload Result Webhook. If you don't, the change of unavailabilities may be ineffective for newly created items.

Examples

{
  "unavailable_ids": [
    "orange_juice",
    "granola"
  ],
  "hidden_ids": [
    "whole_milk"
  ]
}
{
  "unavailable_ids": [
    "orange_juice",
    "granola"
  ],
  "hidden_ids": [
    "whole_milk"
  ]
}
{
  "item_unavailabilities": [
    {
      "item_id": "orange_juice",
      "status": "unavailable"
    },
    {
      "item_id": "granola",
      "status": "available"
    },
    {
      "item_id": "whole_milk",
      "status": "hidden"
    }
  ]
}

PLU mapping

Menu items are stored in our platform and can be identified by their id, which is provided by the restaurant partner. When a restaurant is integrated with our POS APIs, an additional ID is used to identify the same item the customer is ordering on the restaurant partner POS systems. These IDs are sometimes referred as "sku", "external_id", or "plu": this - plu is what we call those identifiers that must find a match on the restaurant's POS system. Our menus APIs can be used to upload an entire menu, including their PLU codes. This API, however, is meant to be the way partners can provide and update that mapping between an item and its PLU code.

See OAS specification for details.

Examples

[
  {
    "item_id": "1234",
    "plu": "1234-plu"
  },
  {
    "item_id": "5678",
    "plu": "5678-plu"
  }
]