Product graph
Availability & Cross-Selling
Manage product availability in real-time across different sales channels. This endpoint allows operations to instantly "86" (disable) an item that has run out of stock during service, without needing a full menu republication.
PUT/availability/{menuId}/{channelId}/product/{productId}Update Availability
Toggle the availability status of a specific product for a given menu and channel.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| menuId | integer | Yes | The unique identifier of the menu. |
| channelId | integer | Yes | The sales channel ID. Available values: 1 (Kiosk), 2 (Web), 9 (Uber Eats), 10 (Deliveroo). For marketplace channels (9, 10), the availability is pushed to the marketplace and the body must also contain the store reference and marketplace product ID (uberEatsStoreReference/uberEatsProductId or deliverooStoreReference/deliverooProductId). |
| productId | integer | Yes | The unique identifier of the product. |
Request Body
{
"actionId": 464462,
"availability": false,
"channel": 2,
"menuId": 106477
}Request Body Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| actionId | integer | 464462 | Identifier of the associated action. |
| availability | boolean | false | The availability value. |
| channel | integer | 2 | The channel value. |
| menuId | integer | 106477 | Identifier of the menu. |
Response
{
"status": 200,
"message": "OK"
}Response Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| status | integer | 200 | HTTP status code returned by the API. |
| message | string | "OK" | Human-readable result message. Do not use this value for program logic. |
Payload Fields
actionId: Must match theproductIdbeing updated.availability:trueto enable,falseto disable.channel: The channel ID (must match URL).menuId: The menu ID (must match URL).
PUT/availability/{menuId}/{channelId}/category/{categoryId}Update Category Availability
Toggle the availability of a whole category for a given menu and sales channel. Updates the category kioskAvailability (channelId 1) or webAvailability (channelId 2) flag, broadcasts a real-time CATEGORY_AVAILABILITY_UPDATED event to the brand front-ends and invalidates the menu cache.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| menuId | integer | Yes | The unique identifier of the menu. |
| channelId | integer | Yes | The sales channel ID. Only 1 (Kiosk) and 2 (Web) are accepted for categories - unlike the product variant, marketplace channels are not supported. Any other value returns 400 missing_parameters. |
| categoryId | integer | Yes | The unique identifier of the category. |
Request Body
{
"availability": false
}Request Body Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| availability | boolean | false | The availability value. |
Response
{
"status": 200,
"code": "category_availability_update_succeed",
"message": "The product category have been successfully updated",
"data": {
"categoryId": 30085,
"menuId": 106477,
"name": "Burgers",
"webAvailability": false,
"kioskAvailability": true
}
}Response Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "category_availability_update_succeed" | Machine-readable application code for the result. |
| message | string | "The product category have been successfully updated" | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.categoryId | integer | 30085 | Identifier of the category. |
| data.menuId | integer | 106477 | Identifier of the menu. |
| data.name | string | "Burgers" | The name value. |
| data.webAvailability | boolean | false | The web availability value. |
| data.kioskAvailability | boolean | true | The kiosk availability value. |
Good to Know
- The category is looked up by
categoryIdonly: the API does not verify that it belongs to the menu in the path (only your access to the menu is checked). Always pass a category of that menu. Returns404 data_not_foundif the category does not exist. availabilitymust be a boolean - the value is written as-is without type validation.- On all
PUT /availabilityroutes, a Restaurant role token is only accepted if the menu's restaurant has stock management V2 enabled; otherwise the request fails withpermission_denied.
💡 Integration Tips
1. Retrieving IDs
To perform this call, you need the menuId and productId.
- Find Menu ID: Call
GET /restaurants/{restaurantId}/menusto see which menus are attached to a specific restaurant. - Find Product ID: Call
GET /menus/{menuId}/productsto list all products in that menu.
2. Mapping from SKU
The API uses internal productId integers. If your external system uses SKUs (Stock Keeping Units):
- Fetch all products via
GET /menus/{menuId}/products. - Iterate through the response to find the product where
skuValuematches your system's SKU. - Use the found
productIdin the availability PUT request.
Cross-Selling
Get Runtime Suggestions
This anonymous endpoint is for the ordering flow. It returns enabled cross-selling pages after excluding products already present in the submitted carts. It only accepts the Web channel.
POST/cross-selling/enabled/with-productsGet Enabled Cross-Selling Products
Returns up to limit eligible products per enabled cross-selling page for the submitted Web-ordering carts. Authentication is not required.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| limit | integer | Yes | Maximum number of products returned for each cross-selling page. |
Request Body
{
"brandId": 3325,
"channelId": 2,
"consumptionMode": "MODE_TAKE_AWAY",
"restaurantCarts": [
{
"restaurantId": 6801,
"menuId": 106477,
"expectedAt": "2026-06-02T12:15:00.000Z",
"expectedAtEnd": "2026-06-02T12:30:00.000Z",
"cartId": "cart-8c0db2d8",
"cart": [
{
"productId": 464462,
"productCartId": "line-main",
"quantity": 1,
"steps": [
{
"stepId": 554,
"type": 1,
"products": [
{
"productId": 991,
"quantity": 1,
"steps": []
}
]
}
]
}
]
}
]
}Request Body Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Required | Example | Description |
|---|---|---|---|---|
| brandId | integer | Yes | 3325 | Brand whose enabled cross-selling pages are evaluated. |
| channelId | integer | Yes | 2 | Must be 2, the Web channel. |
| consumptionMode | string | Yes | "MODE_TAKE_AWAY" | One of MODE_DELIVERY, MODE_TAKE_AWAY, MODE_SIT_IN, or MODE_DRIVE. |
| restaurantCarts | array | Not specified | […] | List of restaurant carts entries. |
| restaurantCarts[] | object | Yes | {…} | One cart context per restaurant. |
| restaurantCarts[].restaurantId | integer | Yes | 6801 | Restaurant serving the cart. |
| restaurantCarts[].menuId | integer | Yes | 106477 | Menu used by the cart. |
| restaurantCarts[].expectedAt | datetime | No | "2026-06-02T12:15:00.000Z" | Optional ISO-8601 expected fulfillment time. |
| restaurantCarts[].expectedAtEnd | datetime | No | "2026-06-02T12:30:00.000Z" | Optional ISO-8601 end time; when supplied it must not precede expectedAt. |
| restaurantCarts[].cartId | string | No | "cart-8c0db2d8" | Optional caller cart reference. |
| restaurantCarts[].cart | array | Not specified | […] | List of cart entries. |
| restaurantCarts[].cart[] | object | Yes | {…} | Products already in the cart; they are excluded from suggestions. |
| restaurantCarts[].cart[].productId | integer|string | Yes | 464462 | Product identifier. |
| restaurantCarts[].cart[].productCartId | string | No | "line-main" | Optional client-side line identifier. |
| restaurantCarts[].cart[].quantity | number | Yes | 1 | Positive quantity, at most 10,000. |
| restaurantCarts[].cart[].steps | array | Not specified | […] | List of steps entries. |
| restaurantCarts[].cart[].steps[] | object | Yes | {…} | Selected customization or cross-selling step entries. An empty array is valid. |
| restaurantCarts[].cart[].steps[].stepId | integer | Yes | 554 | Selected step identifier. |
| restaurantCarts[].cart[].steps[].type | integer | No | 1 | Optional step type: 1 for customization or 2 for cross-selling. |
| restaurantCarts[].cart[].steps[].products | array | Not specified | […] | List of products entries. |
| restaurantCarts[].cart[].steps[].products[] | object | Yes | {…} | Selected products for that step; each recursively uses the same product-cart shape. |
| restaurantCarts[].cart[].steps[].products[].productId | integer | Not specified | 991 | Identifier of the product. |
| restaurantCarts[].cart[].steps[].products[].quantity | integer | Not specified | 1 | The quantity value. |
| restaurantCarts[].cart[].steps[].products[].steps | array | Not specified | [] | List of steps entries. |
| restaurantCarts[].cart[].imageUrl | string | No | Not provided | Optional client image URL. |
| restaurantCarts[].cart[].customPrice | number | No | Not provided | Optional client custom price. |
| restaurantCarts[].cart[].customLabel | string | No | Not provided | Optional client custom label. |
| restaurantCarts[].cart[].crossSelling | object | No | Not provided | Optional source pair with stepId and productId for a cross-selling selection. |
| restaurantCarts[].cart[].measuredQuantity | number | No | Not provided | Optional positive measured quantity, at most 100,000. |
| restaurantCarts[].cart[].measurementUnit | string | No | Not provided | Optional measurement unit for a weighted product. |
Response
{
"status": 200,
"code": "cross_selling_succeed",
"message": "Cross selling succeed.",
"data": [
{
"title": "Complete your meal",
"products": [
{
"position": 1,
"productId": 464500,
"menuId": 106477,
"image": "https://static.innovorder.fr/images/fries.jpg",
"price": 350,
"name": "French fries",
"restaurantId": 6801
}
]
}
]
}Response Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "cross_selling_succeed" | Machine-readable application code for the result. |
| message | string | "Cross selling succeed." | Human-readable result message. Do not use this value for program logic. |
| data | array | […] | Endpoint-specific response payload. |
| data[] | object | {…} | Endpoint-specific response payload. |
| data[].title | string | "Complete your meal" | The title value. |
| data[].products | array | […] | List of products entries. |
| data[].products[] | object | {…} | Object containing products fields. |
| data[].products[].position | integer | 1 | The position value. |
| data[].products[].productId | integer | 464500 | Identifier of the product. |
| data[].products[].menuId | integer | 106477 | Identifier of the menu. |
| data[].products[].image | string | "https://static.innovorder.fr/images/fries.jpg" | The image value. |
| data[].products[].price | integer | 350 | The price value. |
| data[].products[].name | string | "French fries" | The name value. |
| data[].products[].restaurantId | integer | 6801 | Identifier of the restaurant. |
List Rules
Retrieve all cross-selling rules for a brand or a specific restaurant. Cross-selling rules define product suggestions displayed to customers during the ordering flow.
GET/cross-sellingList Cross-Selling Rules
Returns all cross-selling rules. Requires either brandId or restaurantId (mutually exclusive).
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| brandId | integer | No | Brand identifier. Mutually exclusive with restaurantId. |
| restaurantId | integer | No | Restaurant identifier. Mutually exclusive with brandId. |
Response
{
"status": 200,
"code": "cross_selling_succeed",
"message": "Cross selling succeed.",
"data": [
{
"crossSellingId": 1,
"brandId": 22,
"restaurantId": null,
"name": "Dessert Upsell",
"status": "enabled"
}
]
}Response Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "cross_selling_succeed" | Machine-readable application code for the result. |
| message | string | "Cross selling succeed." | Human-readable result message. Do not use this value for program logic. |
| data | array | […] | Endpoint-specific response payload. |
| data[] | object | {…} | Endpoint-specific response payload. |
| data[].crossSellingId | integer | 1 | Identifier of the associated cross selling. |
| data[].brandId | integer | 22 | Identifier of the brand. |
| data[].restaurantId | null | null | Identifier of the restaurant. |
| data[].name | string | "Dessert Upsell" | The name value. |
| data[].status | string | "enabled" | HTTP status code returned by the API. |
Get Rule
Retrieve a single cross-selling rule by its ID, including its associated products.
GET/cross-selling/{crossSellingId}Get Cross-Selling Rule by ID
Returns the cross-selling rule identified by crossSellingId.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| crossSellingId | integer | Yes | ID of the cross-selling rule. |
Response
{
"status": 200,
"code": "cross_selling_succeed",
"message": "Cross selling succeed.",
"data": {
"crossSellingId": 1,
"brandId": 22,
"restaurantId": null,
"name": "Dessert Upsell",
"status": "enabled",
"crossSellingProducts": [
{
"productId": 101,
"position": 1
},
{
"productId": 102,
"position": 2
}
]
}
}Response Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "cross_selling_succeed" | Machine-readable application code for the result. |
| message | string | "Cross selling succeed." | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.crossSellingId | integer | 1 | Identifier of the associated cross selling. |
| data.brandId | integer | 22 | Identifier of the brand. |
| data.restaurantId | null | null | Identifier of the restaurant. |
| data.name | string | "Dessert Upsell" | The name value. |
| data.status | string | "enabled" | HTTP status code returned by the API. |
| data.crossSellingProducts | array | […] | List of cross selling products entries. |
| data.crossSellingProducts[] | object | {…} | Object containing cross selling products fields. |
| data.crossSellingProducts[].productId | integer | 101 | Identifier of the product. |
| data.crossSellingProducts[].position | integer | 1 | The position value. |
List Products
Retrieve all products available for cross-selling configuration within a brand. Useful for building the product picker when creating or editing a cross-selling rule.
GET/cross-selling/brands/{brandId}/productsList Products by Brand
Returns all products for the given brand that can be used in cross-selling rules.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| brandId | integer | Yes | Brand identifier. |
Response
{
"status": 200,
"code": "cross_selling_succeed",
"message": "Cross selling succeed.",
"data": [
{
"productId": 101,
"name": "Tiramisu",
"price": 650
},
{
"productId": 102,
"name": "Brownie",
"price": 450
}
]
}Response Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "cross_selling_succeed" | Machine-readable application code for the result. |
| message | string | "Cross selling succeed." | Human-readable result message. Do not use this value for program logic. |
| data | array | […] | Endpoint-specific response payload. |
| data[] | object | {…} | Endpoint-specific response payload. |
| data[].productId | integer | 101 | Identifier of the product. |
| data[].name | string | "Tiramisu" | The name value. |
| data[].price | integer | 650 | The price value. |
Create Rule
Create a new cross-selling rule. Each rule is associated with a brand (and optionally a restaurant) and contains an ordered list of products to suggest.
POST/cross-sellingCreate Cross-Selling Rule
Creates a cross-selling rule with its product associations.
Request Body
{
"brandId": 22,
"restaurantId": null,
"name": "Dessert Upsell",
"status": "enabled",
"crossSellingProducts": [
{
"productId": 101,
"position": 1
},
{
"productId": 102,
"position": 2
}
]
}Request Body Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| brandId | integer | 22 | Identifier of the brand. |
| restaurantId | null | null | Identifier of the restaurant. |
| name | string | "Dessert Upsell" | The name value. |
| status | string | "enabled" | HTTP status code returned by the API. |
| crossSellingProducts | array | […] | List of cross selling products entries. |
| crossSellingProducts[] | object | {…} | Object containing cross selling products fields. |
| crossSellingProducts[].productId | integer | 101 | Identifier of the product. |
| crossSellingProducts[].position | integer | 1 | The position value. |
Response
{
"status": 200,
"code": "cross_selling_succeed",
"message": "Cross selling succeed.",
"data": {
"crossSellingId": 1,
"brandId": 22,
"name": "Dessert Upsell",
"status": "enabled"
}
}Response Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "cross_selling_succeed" | Machine-readable application code for the result. |
| message | string | "Cross selling succeed." | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.crossSellingId | integer | 1 | Identifier of the associated cross selling. |
| data.brandId | integer | 22 | Identifier of the brand. |
| data.name | string | "Dessert Upsell" | The name value. |
| data.status | string | "enabled" | HTTP status code returned by the API. |
Field Reference
| Field | Type | Required | Description |
|---|---|---|---|
| brandId | Integer | Yes | The brand this rule belongs to. |
| restaurantId | Integer | No | Optionally restrict this rule to a specific restaurant. |
| name | String | Yes | Human-readable name for this cross-selling rule. |
| status | Enum | Yes | enabled or disabled. |
| crossSellingProducts | Array<Object> | Yes | Ordered list of products. Each object has productId (integer) and position (integer). |
Update Rule
Update an existing cross-selling rule. The full configuration including the product list must be provided. Requires either brandId or restaurantId (mutually exclusive).
PUT/cross-selling/{crossSellingId}Update Cross-Selling Rule
Replaces the cross-selling rule configuration identified by crossSellingId.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| crossSellingId | integer | Yes | ID of the cross-selling rule to update. |
Request Body
{
"brandId": 22,
"name": "Dessert Upsell V2",
"status": "enabled",
"crossSellingProducts": [
{
"productId": 101,
"position": 1
},
{
"productId": 103,
"position": 2
}
]
}Request Body Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| brandId | integer | 22 | Identifier of the brand. |
| name | string | "Dessert Upsell V2" | The name value. |
| status | string | "enabled" | HTTP status code returned by the API. |
| crossSellingProducts | array | […] | List of cross selling products entries. |
| crossSellingProducts[] | object | {…} | Object containing cross selling products fields. |
| crossSellingProducts[].productId | integer | 101 | Identifier of the product. |
| crossSellingProducts[].position | integer | 1 | The position value. |
Response
{
"status": 200,
"code": "cross_selling_succeed",
"message": "Cross selling succeed.",
"data": {
"crossSellingId": 1,
"brandId": 22,
"name": "Dessert Upsell V2",
"status": "enabled"
}
}Response Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "cross_selling_succeed" | Machine-readable application code for the result. |
| message | string | "Cross selling succeed." | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.crossSellingId | integer | 1 | Identifier of the associated cross selling. |
| data.brandId | integer | 22 | Identifier of the brand. |
| data.name | string | "Dessert Upsell V2" | The name value. |
| data.status | string | "enabled" | HTTP status code returned by the API. |
Delete Rule
Permanently delete a cross-selling rule and all its product associations.
DELETE/cross-selling/{crossSellingId}Delete Cross-Selling Rule
Deletes the cross-selling rule identified by crossSellingId.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| crossSellingId | integer | Yes | ID of the cross-selling rule to delete. |
Response
{
"status": 200,
"code": "cross_selling_succeed",
"message": "Cross selling succeed."
}Response Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "cross_selling_succeed" | Machine-readable application code for the result. |
| message | string | "Cross selling succeed." | Human-readable result message. Do not use this value for program logic. |
Duplicate Rule
Create a copy of an existing cross-selling rule with a new name. The duplicated rule inherits all product associations from the original.
POST/cross-selling/{crossSellingId}/duplicateDuplicate Cross-Selling Rule
Duplicates the cross-selling rule identified by crossSellingId with the provided name.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| crossSellingId | integer | Yes | ID of the cross-selling rule to duplicate. |
Request Body
{
"name": "Dessert Upsell (Copy)"
}Request Body Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| name | string | "Dessert Upsell (Copy)" | The name value. |
Response
{
"status": 200,
"code": "cross_selling_succeed",
"message": "Cross selling succeed.",
"data": {
"crossSellingId": 2,
"brandId": 22,
"name": "Dessert Upsell (Copy)",
"status": "enabled",
"crossSellingProducts": [
{
"productId": 101,
"position": 1
},
{
"productId": 102,
"position": 2
}
]
}
}Response Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "cross_selling_succeed" | Machine-readable application code for the result. |
| message | string | "Cross selling succeed." | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.crossSellingId | integer | 2 | Identifier of the associated cross selling. |
| data.brandId | integer | 22 | Identifier of the brand. |
| data.name | string | "Dessert Upsell (Copy)" | The name value. |
| data.status | string | "enabled" | HTTP status code returned by the API. |
| data.crossSellingProducts | array | […] | List of cross selling products entries. |
| data.crossSellingProducts[] | object | {…} | Object containing cross selling products fields. |
| data.crossSellingProducts[].productId | integer | 101 | Identifier of the product. |
| data.crossSellingProducts[].position | integer | 1 | The position value. |
Toggle Status
Toggle the status of a cross-selling rule between enabled and disabled. No request body is needed.
PUT/cross-selling/{crossSellingId}/statusToggle Cross-Selling Status
Toggles the enabled/disabled status of the cross-selling rule identified by crossSellingId.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| crossSellingId | integer | Yes | ID of the cross-selling rule. |
Response
{
"status": 200,
"code": "cross_selling_succeed",
"message": "Cross selling succeed.",
"data": {
"crossSellingId": 1,
"status": "disabled"
}
}Response Properties
Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.
| Property | Type | Example | Description |
|---|---|---|---|
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "cross_selling_succeed" | Machine-readable application code for the result. |
| message | string | "Cross selling succeed." | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.crossSellingId | integer | 1 | Identifier of the associated cross selling. |
| data.status | string | "disabled" | HTTP status code returned by the API. |