Menu
Use this endpoint to upload or update a client’s full menu (categories, products, variants, modifiers, and attributes) in one request.
This page mirrors the structure and tone of the existing Product documentation and fits into the same navigation under API Documentation.
Endpoint
PUT /v2/upload/client/products
Uploads a complete menu payload and performs upserts by identifiers:
integration_idfor categories, sub‑categories, and modifier groupspidfor products and product variants
If a record with the same identifier exists, it is updated; otherwise, it is created. Records not present in the payload are left unchanged unless replace mode is explicitly enabled.
Authentication
All requests require a valid Bearer token.
Authorization: Bearer <token>
Content-Type: application/jsonRequest Body
A single JSON document containing the client’s menu. Top‑level properties:
title
string
✓
Menu name for ease of identification
integration_id
string
Menu ID
branches
object array
Optional object list of branch number identifiers.
type
array
Identifies the type of menu, options are DELIVERY | COLLECTION | DINE-IN
menu_categories
array
✓
Hierarchy of categories and sub‑categories.
condiment_groups
array
✓
Typically this is a list of products that enhances the hero product
products
array
✓
Products with variants and references to categories and condiment groups.
attributes
array
Lookup catalogs (e.g., tax codes, preparation methods).
Category Model
{
"menu_categories": [
{
"integration_id": "0000-1",
"name": "Beverages",
"sub_categories": [
{
"integration_id": "0000-1-1",
"name": "Cold Beverages"
},
{
"integration_id": "0000-1-2",
"name": "Hot Beverages"
}
]
},
{
"integration_id": "0000-2",
"name": "Milk"
}
]
}Condiment Group Model
{
"condiment_groups": [
{
"integration_id": "00000-1",
"title": "Milk Alternatives",
"type": "Add On",
"required": true,
"multiple": false,
"minimum_quantity": 1,
"maximum_quantity": 1,
"product_list": [
{
"pid": "00000-1-1",
"sku": "00000-1-1",
"title": "Fresh Milk",
"price": 10,
"is_default": false,
"category_integration_id": [
"0000-2"
],
"status": "AVAILABLE",
"image_url": "https://...jpg",
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-1",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0002",
"lookup": true
}
]
}
]
}
]
}Product Model
{
"pid": "0000-2-0",
"sku": "0000-2-0",
"title": "Still Water",
"status": "AVAILABLE",
"image_url": "https://...jpg",
"variants": [
{
"pid": "0000-2-1",
"sku": "0000-2-1",
"title": "Still Water (500ml)",
"price": 30,
"is_default": false,
"category_integration_id": [
"0000-1-1"
],
"status": "AVAILABLE",
"image_url": "https://...jpg",
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-3",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0002",
"lookup": true
}
]
},
{
"pid": "0000-2-3",
"sku": "0000-2-3",
"title": "Still Water (1L)",
"price": 45,
"is_default": false,
"category_integration_id": [
"0000-1-1"
],
"status": "AVAILABLE",
"image_url": "https://...jpg",
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-4",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0002",
"lookup": true
}
]
}
],
"category_integration_id": [
"0000-1-1"
],
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-5",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0002",
"lookup": true
}
]
}Attributes Catalog
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-5",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0002",
"lookup": true
}
]Example — Minimal Payload
{
"title": "MY_MENU",
"integration_id": "MENU-0001",
"branches": [
{
"branch_number": "00000"
},
{
"branch_number": "00001"
}
],
"type": ["DELIVERY"],
"menu_categories": [
{
"integration_id": "0000-1",
"name": "Beverages",
"sub_categories": [
{
"integration_id": "0000-1-1",
"name": "Cold Beverages"
},
{
"integration_id": "0000-1-2",
"name": "Hot Beverages"
}
]
},
{
"integration_id": "0000-2",
"name": "Milk"
}
],
"condiment_groups": [
{
"integration_id": "00000-1",
"title": "Milk Alternatives",
"type": "Add On",
"required": true,
"multiple": false,
"minimum_quantity": 1,
"maximum_quantity": 1,
"product_list": [
{
"pid": "00000-1-1",
"sku": "00000-1-1",
"title": "Fresh Milk",
"price": 10,
"is_default": false,
"category_integration_id": [
"0000-2"
],
"status": "AVAILABLE",
"image_url": "https://...jpg",
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-1",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0002",
"lookup": true
}
]
},
{
"pid": "00000-1-2",
"sku": "00000-1-2",
"title": "Almond Milk",
"price": 10,
"is_default": false,
"category_integration_id": [
"0000-2"
],
"status": "AVAILABLE",
"image_url": "https://...jpg",
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-2",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0002",
"lookup": true
}
]
}
]
}
],
"products": [
{
"pid": "0000-2-0",
"sku": "0000-2-0",
"title": "Still Water",
"status": "AVAILABLE",
"image_url": "https://...jpg",
"variants": [
{
"pid": "0000-2-1",
"sku": "0000-2-1",
"title": "Still Water (500ml)",
"price": 30,
"is_default": false,
"category_integration_id": [
"0000-1-1"
],
"status": "AVAILABLE",
"image_url": "https://...jpg",
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-3",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0002",
"lookup": true
}
]
},
{
"pid": "0000-2-3",
"sku": "0000-2-3",
"title": "Still Water (1L)",
"price": 45,
"is_default": false,
"category_integration_id": [
"0000-1-1"
],
"status": "AVAILABLE",
"image_url": "https://...jpg",
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-4",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0002",
"lookup": true
}
]
}
],
"category_integration_id": [
"0000-1-1"
],
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-5",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0002",
"lookup": true
}
]
},
{
"pid": "0000-3-0",
"sku": "0000-3-0",
"title": "Sparkling Water",
"status": "AVAILABLE",
"image_url": "https://...jpg",
"variants": [
{
"pid": "0000-3-1",
"sku": "0000-3-1",
"title": "Sparkling Water (500ml)",
"price": 30,
"is_default": false,
"category_integration_id": [
"0000-1-1"
],
"status": "AVAILABLE",
"image_url": "https://...jpg",
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-6",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0001",
"lookup": true
}
]
},
{
"pid": "0000-3-2",
"sku": "0000-3-2",
"title": "Sparkling Water (1L)",
"price": 45,
"is_default": false,
"category_integration_id": [
"0000-1-1"
],
"status": "AVAILABLE",
"image_url": "https://...jpg",
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-7",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0001",
"lookup": true
}
]
}
],
"category_integration_id": [
"0000-1-1"
],
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-8",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0001",
"lookup": true
}
]
},
{
"pid": "0000-4-0",
"sku": "0000-4-0",
"title": "Cappuccino",
"status": "AVAILABLE",
"image_url": "https://...jpg",
"variants": [
{
"pid": "0000-4-1",
"sku": "0000-4-1",
"title": "Cappuccino Small",
"price": 40,
"is_default": false,
"category_integration_id": [
"0000-1-2"
],
"status": "AVAILABLE",
"image_url": "https://...jpg",
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-9",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0000",
"lookup": true
}
]
},
{
"pid": "0000-4-2",
"sku": "0000-4-2",
"title": "Cappuccino Large",
"price": 50,
"is_default": false,
"category_integration_id": [
"0000-1-2"
],
"status": "AVAILABLE",
"image_url": "https://...jpg",
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-10",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0000",
"lookup": true
}
]
}
],
"category_integration_id": [
"0000-1-2"
],
"attributes": [
{
"key": "pos_code",
"value": {
"name": "Pos Code",
"description": "Pos Code",
"default_value": "0000-11",
"options": null,
"type": "TEXT" /* | "NUMBER"| "DATE"| "BOOLEAN"| "LIST" */
},
"lookup": false
},
{
"key": "tax_code",
"lookup_id": "0",
"lookup": true
},
{
"key": "time_group",
"lookup_id": "0000",
"lookup": true
}
]
}
],
"attributes": [
{
"key": "tax_code",
"value": [
{
"lookup_id": "0",
"value": {
"name": "Default Tax",
"description": "Default Tax (15,00%)",
"default_value": 15.00,
"options": null,
"type": "NUMBER" /* | "TEXT"| "DATE"| "BOOLEAN"| "LIST" */
}
},
{
"lookup_id": "1",
"value": {
"name": "Exempt Tax",
"description": "Exempt Tax (0%)",
"default_value": 0,
"options": null,
"type": "NUMBER" /* | "TEXT"| "DATE"| "BOOLEAN"| "LIST" */
}
}
]
},
{
"key": "time_group",
"value": [
{
"lookup_id": "0000",
"value": {
"name": "Whole Day",
"description": "Whole Day",
"default_value": [
{
"day": "Monday",
"start": "00:00",
"end": "23:59"
},
{
"day": "Tuesday",
"start": "00:00",
"end": "23:59"
},
{
"day": "Wednesday",
"start": "00:00",
"end": "23:59"
},
{
"day": "Thursday",
"start": "00:00",
"end": "23:59"
},
{
"day": "Friday",
"start": "00:00",
"end": "23:59"
},
{
"day": "Saturday",
"start": "00:00",
"end": "23:59"
},
{
"day": "Sunday",
"start": "00:00",
"end": "23:59"
}
],
"options": null,
"type": "LIST" /* | "TEXT"| "DATE"| "BOOLEAN"| "NUMBER" */
}
},
{
"lookup_id": "0003",
"value": {
"name": "Afternoon Meal",
"description": "Afternoon Meal",
"default_value": [
{
"day": "Monday",
"start": "14:00",
"end": "23:59"
},
{
"day": "Tuesday",
"start": "14:00",
"end": "23:59"
},
{
"day": "Wednesday",
"start": "14:00",
"end": "23:59"
},
{
"day": "Thursday",
"start": "14:00",
"end": "23:59"
},
{
"day": "Friday",
"start": "14:00",
"end": "23:59"
},
{
"day": "Saturday",
"start": "14:00",
"end": "23:59"
},
{
"day": "Sunday",
"start": "14:00",
"end": "23:59"
}
],
"options": null,
"type": "LIST" /* | "TEXT"| "DATE"| "BOOLEAN"| "NUMBER" */
}
},
{
"lookup_id": "0004",
"value": {
"name": "Mid-Day Meal",
"description": "Mid-Day Meal",
"default_value": [
{
"day": "Monday",
"start": "11:00",
"end": "16:00"
},
{
"day": "Tuesday",
"start": "11:00",
"end": "16:00"
},
{
"day": "Wednesday",
"start": "11:00",
"end": "16:00"
},
{
"day": "Thursday",
"start": "11:00",
"end": "16:00"
},
{
"day": "Friday",
"start": "11:00",
"end": "16:00"
},
{
"day": "Saturday",
"start": "11:00",
"end": "16:00"
},
{
"day": "Sunday",
"start": "11:00",
"end": "16:00"
}
],
"options": null,
"type": "LIST" /* | "TEXT"| "DATE"| "BOOLEAN"| "NUMBER" */
}
}
]
}
]
}Responses
200 OK
OK422 Validation Error
{
"success": "false",
"message": "validation_failed",
"content": null
}Validation Rules
The menu
integration_idmust be unique per tenant.If branches are not provided, the menu applies across all branches.
If the menu type is not provided, the menu will be applied across all three types
DELIVERY|COLLECTION|DINE-INmenu_categoriesis a required array to group all productscondiment_groupsare optionalAll products are required to have the following:
A unique
skuA unique
pidA title.
A non negative price.
If provided,
image_urlmust be HTTPS.
Last updated