Managing Store Menus

API Reference

The Rappi API enables you to manage the menus of your stores.

You can create and update menus in the platform, retrieve the items of the menus, and review the approval status of your requests to create or update menus.

The main properties of the menus and the items created through the Rappi API consist of the following items:

  • storeId: The store identifier
  • items: The items in the menu
    • category: The category of the items in the menu
      • id: The SKU (Stock-Keeping Unit) the ally gives to this category
      • maxQty: The maximum number of items that can be ordered in this category
      • minQty: The minimum quantity of elements that can be ordered in this category (In toppings, if it's 0 it means that it's not mandatory)
      • name: Category name
      • sortingPosition: If it's a product category, it's the position of the category in the menu. In case of being a Topping category, it's the position of the category within the product
    • children: Subitems nested in a category
    • name: The name of the item in the menu
    • description: The description of the item in the menu
    • imageUrl: The url of the image of the item in the menu
    • price: The price of the item in the menu
    • rappiIds: The identifier Rappi gives to this item
    • sku: The SKU (Stock-Keeping Unit) the ally gives to this item
    • sortingPosition: The position of the item in its category
    • type: The type of the item
    • maxLimit: Maximum indicator of the item, it's required only if the type is topping
    • combo: Indicates if the element belongs to a combo. (if it is true it means that it belongs to a combo)

Important

When a menu is sent, full prices should be sent instead of prices with discounts applied

Some of these properties are subdivided into more objects. For a detailed view and a deeper explanation of these items, consult the Menus API resource on the Rappi API Reference.

Types of mapping

  • No mapping: The ally loads their menu from the partners portal, without placing the SKUs of the menu items. Upon receiving an order, the json of the order will have the Rappi ids of the items but their SKUs will be null, so the ally is in charge of downloading their menu and encoding their SKUs.
  • Self mapping: The ally loads their menu from the partners portal and can enter the SKU of the menu item from there. This sku information is taken to obtain the association between the SKU and the rappi id of the item, to send it as part of the order information to the ally's POS.
  • Automatic mapping: The ally must send their menu consuming the POST menu endpoint, where SKUs must be received for each item that is sent in the menu. The mapping is generated by sending the json from the menu, generating a new mapping version that is available in such a way that when generating an order, the system takes the information registered in the automatic mapping database, and sends the information translated from the order to the ally's POS.

Improvements with automatic menu

  • We will reproduce the order of your products in the Rappi app as you send it from the POS.
  • We will keep the promotion settings when you update the menus from the POS.
  • Menu validation will be immediate, avoiding any delay in loading, and you will receive feedback instantly ("accepted", "rejected", or with "error").
  • We will keep the history of customers favorites in the Rappi app, as we will keep your SKUs history.

Creating a Menu for a Store

API Reference

Use the POST menu endpoint to create menus through API.

You can only send menus for parent stores. If you send a menu for a child store the endpoint will reject it.

To create a menu:

Make a POST request to the following URL, and add a JSON object to the body of the request with the following objects.

URL: https://{COUNTRY_DOMAIN}/api/v2/restaurants-integrations-public-api/menu

{COUNTRY_DOMAIN}: This is your Rappi Country Domain. See the list of Country Domains.

This is an example of the JSON object in the body of the request:

{ "storeId": "900103361", "items": [ { "name": "Grilled Chicken Burger", "description": "Grilled chicken burger description", "price": 14000, "sku": "10", "sortingPosition": 0, "type": "PRODUCT", "category": { "id": "2090019638", "maxQty": 0, "minQty": 0, "name": "Burgers", "sortingPosition": 0 }, "children": [ { "category": { "id": "211", "maxQty": 1, "minQty": 0, "name": "Do you want to add?", "sortingPosition": 0 }, "name": "French Fries", "description": "crunchy french fries", "price": 5000, "sku": "1", "maxLimit": 1, "sortingPosition": 1, "type": "TOPPING" }, { "category": { "id": "211", "maxQty": 1, "minQty": 0, "name": "Do you want to add?", "sortingPosition": 0 }, "name": "Potato Wedges", "price": 7000, "sku": "2", "maxLimit": 1, "sortingPosition": 1, "type": "TOPPING" } ] }, { "name": "Hawaiian Pizza", "description": "hawaiian pizza description", "price": 18000, "sku": "11", "sortingPosition": 1, "type": "PRODUCT", "category": { "id": "2090019639", "maxQty": 0, "minQty": 0, "name": "Pizzas", "sortingPosition": 1 }, "children": [] } ] }

Note

If then need to change product availability, can use availability module

Note

The values from this JSON are not real data. Ensure to replace them with your data when making API requests. You can add more items to the menu by adding more objects under items, separated by a comma.

The system retrieves the confirmation message Menu updated and ready to be validated.

Note

It's not possible to process more than 1 menu at a time, therefore, if there is already a menu in the approval process, all incoming menus from the same store will be ignored

Your menu is now under approval. You can consult the status of your menu by making a GET request to the menu endpoint. For more information, go to the Obtaining Menu Information section of this chapter.

Validations on the Received menu

When Rappi receives a menu through the POST menu endpoint, the catalog service runs a set of validations before accepting it. If any validation fails, the menu is rejected and the response includes the detail of each error.

The service applies a set of validations grouped into three families:

  1. Structural: shape of the menu and consistency between products, toppings and aisles.
  2. Content: quality and format of texts, images and prices.
  3. Limits: configurable maximum sizes.

How errors are reported

When a menu is rejected, the response is always HTTP 400. The body comes in one of two shapes, depending on which validation failed.

Simple format

When the service rejects the request early (for example: the same SKU used with different data, or a menu that is too deep), the body looks like:

{ "type": "<error_type>", "message": "..." }

Where <error_type> can be item_data_conflict, invalid_item_depth, among others.

Note

Even though some type values contain the word "conflict", the HTTP status is always 400 Bad Request, never 409.

Detailed format

When the full menu structure was evaluated, the body includes:

  • A boolean for each validation (true if it passed, false if it failed).
  • item_level_depth: the depth of the validated path.
  • path: the route inside the menu where the problem was detected (aisle → product → topping category → topping…).
  • path_item_details: a list of details with the following format:
[Error]: <validation_name>, [Details]: <description>, [Location]: store_id=…, item_id=…, item_sku=…

Shortened response example:

{ "duplicated_items_complies": false, "item_level_depth": 3, "path": [ { "id": 50, "item_type": "CATEGORY", "sku": "burgers" }, { "id": 200, "item_type": "ITEM", "sku": "hamburger" } ], "path_item_details": [ "[Error]: duplicated_items_complies, [Details]: duplicated item in category, [Location]: store_id=123, category_id=50, item_id=200, item_sku=fries" ] }

Note

The technical names in parentheses (in snake_case) are the identifiers that appear literally in path_item_details. Error messages remain in English because that is how the service returns them.

Structural validations

  • Maximum menu depth (invalid_item_depth): the menu supports up to 2 levels of hierarchy: a product at the first level and its toppings inside children. Nesting more children inside a topping is not allowed. The service rejects the request using the simple format with message: item with SKU '<sku>' exceeds maximum menu depth of 2 levels in menu integration V1.

  • Consistent data for the same SKU (item_data_conflict): if a SKU is repeated in different contexts of the menu, all of its attributes must match in every occurrence (name, description, price, image, quantities, list of children). If any differ, the menu is rejected using the simple format with a body of type item_data_conflict.

    For example, if you send the topping with SKU topping-tomate at two different prices under the same topping category 211, you receive:

    { "type": "item_data_conflict", "message": "item with sku 'topping-tomate' has two different price values under topping category '211': $2500 and $3000" }

    Six kinds of divergence are detected. In every message, <parentType> is one of corridor (aisle), product, or topping category —the type of container that holds the conflicting item— and <parentSKU> is the identifier of that container:

    • Title: item with sku '<sku>' has two different title values under <parentType> '<parentSKU>': '<t1>' and '<t2>'.
    • Description: item with sku '<sku>' has two different description values under <parentType> '<parentSKU>': '<d1>' and '<d2>'.
    • Price: item with sku '<sku>' has two different price values under <parentType> '<parentSKU>': $<p1> and $<p2>.
    • Image: item with sku '<sku>' has two different image values under <parentType> '<parentSKU>': '<url1>' and '<url2>'.
    • Quantity (applies to topping categories — maxQty, minQty, modifier type): item with sku '<sku>' has two different quantity values under <parentType> '<parentSKU>': min <m1>, max <M1>, type <t1> and min <m2>, max <M2>, type <t2>.
    • Children: item with sku '<sku>' has conflicting child items under <parentType> '<parentSKU>'.

    Note

    If your menu comes from a POS where the same product or topping appears in multiple contexts (for example, the same "Tomato" topping is offered in several burgers), make sure the SKU is identical and that all attributes match in every occurrence. If you need a variation to have different attributes (for example, "Tomato" with a different price in another burger), give it its own SKU: each variation of the product must have a unique SKU.

  • No duplicate aisles (duplicated_categories_complies): inside the same menu, two aisles cannot exist with the same id or the same SKU. Message: [Error]: duplicated_categories_complies, [Details]: duplicated category in menu, [Location]: ….

  • No duplicate products or toppings (duplicated_items_complies): inside an aisle, two products cannot have the same id or SKU. The same applies inside a topping category for its toppings. Message: [Error]: duplicated_items_complies, [Details]: duplicated item in category, [Location]: ….

  • Valid product ↔ topping category relation (item_relation_complies): along any path inside the menu, two consecutive nodes of the same type are not allowed. A product must contain topping categories, and a topping category must contain toppings; never product → product nor topping category → topping category. Message: [Error]: item_relation_complies, [Details]: invalid relation between items and modifier groups found in path, [Location]: ….

  • No cycles (item_relation_without_cyclic_complies): the same SKU cannot appear twice in the same menu path, regardless of the element type. For example, if a product has SKU abc-123 and somewhere inside its topping tree another element shows up with the same SKU abc-123 (another product, a topping or a topping category), the validation fails. Message: [Error]: item_relation_without_cyclic_complies, [Details]: cyclic relation between items found in path, [Location]: item with id <n> and sku <sku> is duplicated in path.

  • Path starts and ends with a product/topping (start_and_ends_with_item): every menu path begins and ends with a product or topping, never with a topping category. Message: [Error]: start_and_ends_with_item, [Details]: path does not start and end with item, [Location]: ….

  • At least one aisle (minimum_categories_complies): the store must send at least one aisle. Message: [Error]: minimum_categories_complies, [Details]: no categories found in store menu, [Location]: store_id=….

  • At least one product (minimum_items_complies): the store must send at least one product. Message: [Error]: minimum_items_complies, [Details]: no items found in store menu, [Location]: store_id=….

Content validations

  • Valid image URL (image_url_complies): each image URL must be absolute (starting with http:// or https://), contain no whitespace and be parseable. It is validated against the pattern ^https?://[^\s]+(\?[^\s]*)?$. Message: [Error]: image_url_complies, [Details]: Invalid image URL <url>, Error: invalid image url format, [Location]: ….

  • Text format (text_format_complies): customer-visible texts (name, description, attributes, image paths) cannot contain emojis or blacklisted words. The SKU is only checked for emojis; blacklisted words inside a SKU produce a non-blocking warning (they do not reject the menu). The list of blacklisted words depends on the country (see below). Possible messages:

    • [Error]: text_format_complies, [Details]: item title contains emoji characters: <text>, [Location]: …
    • [Error]: text_format_complies, [Details]: item title '<text>' contains blacklisted words: '<word>', [Location]: …
  • Text field lengths (text_fields_length_complies): allowed lengths:

    FieldMinimumMaximum
    Product / topping SKU1500
    Product / topping name11000
    Product / topping description02000
    Aisle / topping category SKU0500
    Aisle / topping category name01000
    Aisle / topping category description02000

    Message: [Error]: text_fields_length_complies, [Details]: item title length out of bounds: <n> not between [<min> and <max>], [Location]: ….

  • Valid override types (override_type_complies): an override can only be applied at certain levels depending on the field it overrides:

    OverrideAllowed levels
    TitleSTORE, ITEM
    DescriptionSTORE, ITEM
    PriceSTORE, ITEM
    ItemsSTORE, ITEM
    QuantitySTORE, ITEM
    SchedulesSTORE, ITEM, CATEGORY
    SuspensionSTORE
    ImagesSTORE, ITEM

    Message: [Error]: override_type_complies, [Details]: item <field> override has unsupported type: <type>, [Location]: ….

    If you send an override at a level that is not allowed, the service may reject it early using the simple format (type: "item_data_conflict") with one of these messages:

    • item with SKU '<sku>' and title '<t>' and type '<type>' is not permitted for an override
    • item with SKU '<sku>' and description '<d>' and type '<type>' is not permitted for an override
    • item with SKU '<sku>' and price '<p>' and type '<type>' is not permitted for an override
    • item with SKU '<sku>' and image '<img>' and type 'CATEGORY' is not permitted for an override
    • item with SKU '<sku>' and quantity is not permitted in override of type <type>
  • Non-negative numbers (positive_numbers_complies): prices cannot be negative; min_permitted and max_permitted cannot be negative; inside a topping category max_permitted must be greater than 0. Messages:

    • [Error]: positive_numbers_complies, [Details]: item has negative price: <p>, [Location]: …
    • [Error]: positive_numbers_complies, [Details]: modifier_group item has zero max_permitted: 0, [Location]: …
  • Zero prices (zero_price_complies): a product without toppings must have a price greater than 0. A product with toppings may have price 0 as long as at least one of its toppings has a price greater than 0. Message: Product price must be greater than 0 if the product doesn't have any children. Otherwise at least one of its children must have price..

  • Valid min_permitted (min_permitted_complies): in standard products, min_permitted cannot be greater than 0. This restriction applies to the field on the product and on any override. Message: [Error]: min_permitted_complies, [Details]: item min_permitted greater than 0: <n>, [Location]: ….

Limit validations

  • Max children per product / topping category (max_item_childs_complies): maximum 50. Message: item with too many childs: <n> > 50.
  • Max images per product (max_item_images_complies): maximum 3. Message: item with too many images: <n> > 3.
  • Max products per aisle (max_items_category_complies): maximum 50. Message: category with too many items: <n> > 50.
  • Max time periods per schedule (max_time_periods_complies): maximum 6. Message: schedule <id> with too many time periods: <n> > 6.
  • max_permitted within the parent's limits (max_permitted_in_items_complies): a topping's max_permitted must respect the max_permitted (or maxQty) of its containing topping category, and a topping category's max_permitted cannot exceed that of its parent product. Message: [Error]: max_permitted_in_items_complies, [Details]: max_permitted exceeds parent max_permitted, [Location]: ….

Note

The numeric limits are configurable and may change over time. The values listed here are the ones in effect at the time this page was published.

Additional rules

On top of the validations above, the following rules are applied at the request level:

  • Empty product list: the body must include at least one product. Error: Items is required.
  • Valid item types: the first level must be PRODUCT and the children must be TOPPING. Error: All parent items must be product type and children must be topping type.
  • Image file formats: referenced files must be PNG, JPEG, JFIF, JPG, WEBP, TIFF or BMP and weigh up to 1 MB.

Blacklisted words by country

The text_format_complies validation rejects texts that contain words from the country's blacklist. The list varies by country (AR, BR, CL, CO, CR, EC, MX, PE and UY each have their own list). The words fall into three categories:

  1. Competing platforms. Delivery and commerce brands whose names cannot appear in the menu content. Some are common to several countries (for example uber, uber eats, ubereats, ifood, glovo, didi, pedidos ya, domicilios.com) and others are country-specific (BR: 99 food, aiqfome, alfred delivery, delivery much, delivery center, james delivery, ze delivery, cornershop; CO/AR/CR: merqueo; and others).
  2. Offensive or vulgar language. Insults, slurs, discriminatory language and profanity. The specific content varies by regional usage.
  3. Local political or topical references. Names of political figures, parties and movements in the country (varies by jurisdiction), as well as related terms such as huelga, protestar, corrupto, fraude, manifestación and similar.

Note

The complete per-country list (word by word) changes often and is maintained on Rappi's side. If your pipeline needs the current list to filter content before sending the menu, contact the support team that supports your integration.

Recommendation: sanitize customer-visible content (name and description of products, toppings and aisles; attribute names) before sending it. If the content comes from the partner's POS or from a marketing team, avoid references to competitors, offensive language and political topics local to the store's country.

Note

Automatic menu does not support reusing skus (ids) when you create new topping categories, products, and toppings.

Obtaining Menu Information

API Reference

After Rappi approves the content of the menu, you can retrieve the contents of your store menus using the GET menu endpoint.

To retrieve the contents of your store menus:

Make a GET request to the following URL.

URL: https://{COUNTRY_DOMAIN}/api/v2/restaurants-integrations-public-api/menu

{COUNTRY_DOMAIN}: This is your Rappi Country Domain. See the list of Country Domains.

The system retrieves a JSON object response with the information of your store menus.

Consulting the Approval Status of Your Menus

API Reference

After creating a menu using our API, the Rappi team validates the structure and the contents of your menu.

You can use the GET menu/approved/{storeId} endpoint to consult the approval status of your menus.

To consult the status of your menus:

Make a GET request to the following URL.

URL: https://{COUNTRY_DOMAIN}/api/v2/restaurants-integrations-public-api/menu/approved/{storeId}

{COUNTRY_DOMAIN}: This is your Rappi Country Domain. See the list of Country Domains.

The system retrieves a JSON object response with the approval status of your store menus.

Note

If the wait time for a menu approval exceeds the agreed SLA, the support team must be contacted to validate the status of the menu.

Retrieving Your Last Created Menu

API Reference

Use the GET menu/rappi/{storeId} endpoint to retrieve the information of the last menu created for a specific store.

To get the last created menu:

Make a GET request to the following URL:

URL: https://{COUNTRY_DOMAIN}/api/v2/restaurants-integrations-public-api/menu/rappi/{storeId}

The system retrieves a JSON response with the information of the last menu created for your store.