Skip to main content

Create and maintain menu products

This guide covers creating a product with its variants, attaching modifier categories, and the updates you'll make afterward — visibility, stock, and price.

The flow at a glance​

Step 1 — categories and kitchens​

A product belongs to a category and a kitchen; resolve both ids first:

GET /v1/menu/categories
GET /v1/menu/kitchens

Required scope: menu:read. A category holds at most 50 products — creating one past that limit is rejected with catalog_limit_reached_products_per_category.

Step 2 — create the product​

POST /v1/menu/products

Required scope: menu:write. Prices are decimals, not minor units, as in every menu endpoint. Accepts application/json (no image) or multipart/form-data (field product = the same JSON as a string, field image = a jpeg/jpg/png/webp file up to 5 MB).

curl -X POST https://public-api.olaclick.app/v1/menu/products \
-H "Authorization: Bearer olk_live_..." \
-H "Content-Type: application/json" \
-d '{
"category_id": "6b2f1a04-1c7e-4a2b-9f11-2d8e0b3c4d55",
"kitchen_id": "9c4f4203-9e2c-403d-88cc-7c0ce9e0f572",
"name": "Classic Burger",
"description": "Beef patty, cheddar, lettuce, tomato",
"variants": [
{
"name": "Regular",
"price": 8.5,
"original_price": 10,
"sku": "BURGER-REG"
}
]
}'
FieldRequiredNotes
category_id, kitchen_idYesMust belong to your company; an unknown kitchen_id is rejected with 422, an unknown category_id with 404.
nameYes1–191 characters.
descriptionNoUp to 550 characters.
visibleNoDefaults to true.
variantsYes1–30 items. Each needs name, price, original_price (list price) and sku (at most 20 characters); price must not exceed original_price. cost and packaging_price are write-only (accepted, never returned).
modifier_category_idsNoUp to 100 distinct UUIDs, in display order. Omit for a product with no modifiers.

The response is the created product with its variants and modifier categories — see the REST API Reference for the full shape.

Step 3 — add or update variants​

A product can get more variants (sizes, presentations) after creation:

POST /v1/menu/products/{id}/variants
{ "name": "Large", "price": 10.5, "original_price": 12, "sku": "BURGER-LRG" }

Required scope: menu:write. Same required fields as a variant in the create body: name, original_price, price, sku.

To change an existing variant — including its price, stock or stock_threshold — use:

PATCH /v1/menu/products/{id}/variants/{variantId}
{ "stock": 40, "stock_threshold": 5 }

All fields are optional, but at least one is required; price still cannot exceed original_price when both are present in the request.

Step 4 — sync modifier categories​

List what's available, then replace the product's association in one call:

GET /v1/menu/modifier-categories
PUT /v1/menu/products/{id}/modifier-categories
{ "modifier_category_ids": ["8e2b4d6f-9a0c-4e1b-85d7-9f2a4c6e8b10"] }

This replaces the product's modifier categories entirely, in the order given — it is not an add/remove diff. Every id must be distinct; an empty array detaches every modifier category.

Required scope: menu:write.

Step 5 — updates (visibility, stock, price)​

  • Visibility, stock tracking, customer-facing message: PATCH /v1/menu/products/{id} — name, description, visible, stock_enabled, messages_for_customers. At least one field is required; the response does not include variants (call GET /v1/menu/products/{id} for the full product).
  • Stock and price per variant: PATCH /v1/menu/products/{id}/variants/{variantId}, as above.

Common validation errors​

StatusCodeWhen
422validation_failed (kitchen_not_found)kitchen_id doesn't belong to your company.
404not foundcategory_id doesn't exist or belongs to another company (on create); the product (and, for variant endpoints, the variant) doesn't exist.
422catalog_limit_reached_products_per_categoryThe category already has 50 products.
422catalog_limit_reached_variants_per_productThe product already has the maximum number of variants allowed.
422validation_failedA variant's price exceeds its original_price; an update body has no fields; modifier_category_ids has duplicates.
422modifier_category_not_foundA modifier_category_ids entry doesn't exist or belongs to another company.
403insufficient_scopeThe API key is missing menu:read or menu:write.

Doing it through the MCP server​

ToolWhat it does
list_categories / list_kitchensResolve category_id / kitchen_id
create_productCreate a product with its variants (JSON only, no image)
create_product_variantAdd a variant to an existing product
update_product_variantUpdate a variant (price, stock, etc.)
list_modifier_categoriesFind valid modifier_category_ids
sync_product_modifier_categoriesReplace a product's modifier categories
list_products / get_productBrowse the catalog

Needed scopes: menu:read, menu:write.

Note: changing a product's own visibility/stock-tracking flag (PATCH /v1/menu/products/{id}) is REST-only — there is no MCP tool for it yet.

Example prompts:

"Create a product called Classic Burger in category 6b2f1a04-1c7e-4a2b-9f11-2d8e0b3c4d55, kitchen 9c4f4203-9e2c-403d-88cc-7c0ce9e0f572, with one variant priced at 8.5"

"Set stock to 40 for variant ... on product ..."

See the MCP Server page for every tool's full parameters.