{"openapi":"3.1.0","info":{"title":"RestroGrow API","version":"1.0.0","description":"Read and change your RestroGrow restaurant: menu, orders and reports. Create a key in the RestroGrow dashboard › API keys. Docs: https://restrogrow.com/developers"},"servers":[{"url":"https://restrogrow.com/api/v1"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"Your API key: rg_live_…"}},"responses":{"Ok":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object"},"summary":{"type":"string"}}}}}},"Error":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}},"paths":{"/me":{"get":{"tags":["Key"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"me","summary":"This key","description":"The restaurant this key belongs to and its permissions. Needs no permission."}},"/restaurant":{"get":{"tags":["Restaurant"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"get_restaurant","summary":"Restaurant details","description":"Name, currency, timezone and menu sections of the connected restaurant. Call this first if you need the currency or the menu section names.\n\nPermission: `restaurant:read`.","x-permission":"restaurant:read"}},"/menu":{"get":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"list_menu","summary":"Menu","description":"Dishes on the menu with id, section, veg type, price, sizes (variations) and whether they are switched on. Use the ids with set_dish_availability and update_dish.\n\nPermission: `menu:read`.","x-permission":"menu:read","parameters":[{"name":"search","in":"query","required":false,"schema":{"type":"string","description":"Part of a dish name."}},{"name":"section","in":"query","required":false,"schema":{"type":"string","description":"Menu section name, e.g. Starters."}},{"name":"only_switched_off","in":"query","required":false,"schema":{"type":"boolean","default":false}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":300,"default":100}}]}},"/menu/items":{"post":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"},"201":{"$ref":"#/components/responses/Ok"}},"operationId":"add_dish","summary":"Add a dish","description":"Add a new dish to the menu. The section (e.g. Starters, Main Course) is created if it does not exist yet. Add a photo with set_dish_photo and sizes with set_dish_sizes.\n\nPermission: `menu:write`.","x-permission":"menu:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":150},"price":{"type":"number","minimum":0},"section":{"type":"string","minLength":2,"maxLength":80},"type":{"type":"string","enum":["Veg","Non Veg","Egg","Drink","Dessert","Other"],"default":"Veg"},"description":{"type":"string","maxLength":1000},"prep_minutes":{"type":"integer","minimum":0,"maximum":180},"available":{"type":"boolean","default":true}},"required":["name","price","section"]}}}}}},"/menu/items/{item_id}":{"patch":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"update_dish","summary":"Edit a dish","description":"Change a dish's name, description, price, veg type or the prices of its sizes. Only the fields you pass change. A dish with sizes has its prices in sizes (e.g. Half / Full), not in price.\n\nPermission: `menu:write`.","x-permission":"menu:write","parameters":[{"name":"item_id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":150},"description":{"type":"string","maxLength":1000},"price":{"type":"number","minimum":0},"type":{"type":"string","enum":["Veg","Non Veg","Egg","Drink","Dessert","Other"]},"sizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"price":{"type":"number","minimum":0}},"required":["name","price"]}}}}}}}}},"/menu/availability":{"post":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"set_dish_availability","summary":"Switch dishes on or off","description":"Switch one or more dishes on (available to order) or off (sold out / not today). Get the ids from list_menu.\n\nPermission: `menu:write`.","x-permission":"menu:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"item_ids":{"type":"array","items":{"type":"integer"},"minItems":1,"maxItems":50},"available":{"type":"boolean"}},"required":["item_ids","available"]}}}}}},"/orders":{"get":{"tags":["Orders"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"list_orders","summary":"List orders","description":"Orders in a period, newest first. status \"active\" = everything still open (Pending, Accepted, Preparing, Ready).\n\nPermission: `orders:read`.","x-permission":"orders:read","parameters":[{"name":"period","in":"query","required":false,"schema":{"type":"string","enum":["today","yesterday","this_week","last_week","last_7_days","this_month","last_month","last_30_days"],"description":"Time range, in the restaurant's own timezone.","default":"today"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","Pending","Accepted","Preparing","Ready","Served","Completed","Cancelled","Rejected"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}]}},"/orders/number/{order_number}":{"get":{"tags":["Orders"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"get_order_by_number","summary":"Order details","description":"One order with its dishes, customer, payment and the statuses it can move to next. Give order_id, or the order_number shown on the bill.\n\nPermission: `orders:read`.","x-permission":"orders:read","parameters":[{"name":"order_number","in":"path","required":true,"schema":{"type":"string"}}]}},"/orders/{order_id}":{"get":{"tags":["Orders"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"get_order","summary":"Order details","description":"One order with its dishes, customer, payment and the statuses it can move to next. Give order_id, or the order_number shown on the bill.\n\nPermission: `orders:read`.","x-permission":"orders:read","parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/orders/{order_id}/status":{"post":{"tags":["Orders"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"update_order_status","summary":"Update an order","description":"Move an order to its next status: Accepted, Preparing, Ready, Served, Completed, or Cancelled / Rejected (give a reason, the customer sees it). Only allowed moves work; get_order lists them. Cancelling or rejecting cannot be undone.\n\nPermission: `orders:write`.","x-permission":"orders:write","parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["Accepted","Preparing","Ready","Served","Completed","Cancelled","Rejected"]},"reason":{"type":"string","maxLength":200},"prep_minutes":{"type":"integer","minimum":1,"maximum":300,"description":"When accepting: how long the kitchen needs."}},"required":["status"]}}}}}},"/reports/sales":{"get":{"tags":["Reports"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"get_sales_summary","summary":"Sales summary","description":"Sales (money), number of orders, average bill and orders by channel (counter, website, WhatsApp) for a period, compared with the period before. Use for \"how much did I sell\", \"sales today\", \"is this week better than last week\".\n\nPermission: `reports:read`.","x-permission":"reports:read","parameters":[{"name":"period","in":"query","required":false,"schema":{"type":"string","enum":["today","yesterday","this_week","last_week","last_7_days","this_month","last_month","last_30_days"],"description":"Time range, in the restaurant's own timezone.","default":"today"}}]}},"/reports/{report}":{"get":{"tags":["Reports"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"get_report","summary":"Business report","description":"A ready-made report from the restaurant's own data: top_dishes (best sellers), slow_dishes (least sold), dish (how much one named dish sold; set dish), peak_hours (busiest hours and day), payments (cash / UPI / card split), channels (counter vs website vs WhatsApp), customers (new vs returning), cancellations, lapsed (regulars who stopped coming), today_so_far, advice (what to do next, from the numbers).\n\nPermission: `reports:read`.","x-permission":"reports:read","parameters":[{"name":"report","in":"path","required":true,"schema":{"type":"string","enum":["top_dishes","slow_dishes","dish","peak_hours","payments","channels","customers","cancellations","lapsed","today_so_far","advice"]}},{"name":"period","in":"query","required":false,"schema":{"type":"string","enum":["today","yesterday","this_week","last_week","last_7_days","this_month","last_month","last_30_days"],"description":"Time range, in the restaurant's own timezone.","default":"last_7_days"}},{"name":"dish","in":"query","required":false,"schema":{"type":"string","description":"Dish name, only for report=dish."}}]}},"/menu/items/{item_id}/photo":{"post":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"set_dish_photo","summary":"Set a dish photo","description":"Give a dish a new photo, or remove its photo with remove=true. A landscape picture about 5:4 looks best.\n\nPermission: `menu:write`.","x-permission":"menu:write","parameters":[{"name":"item_id","in":"path","required":true,"schema":{"type":"integer","description":"Dish id from list_menu."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"image":{"type":"string","description":"The picture: a data URL (data:image/jpeg;base64,…) or a public https link to a JPEG, PNG, GIF or WebP, at most 5 MB."},"remove":{"type":"boolean","default":false}}}}}}}},"/menu/items/{item_id}/delete":{"post":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_dish","summary":"Delete a dish","description":"Remove a dish from the menu. A dish that was ever ordered is hidden instead (it disappears everywhere, but its sales history stays; show_dish brings it back). A dish never ordered is deleted for good.\n\nPermission: `menu:write`.","x-permission":"menu:write","parameters":[{"name":"item_id","in":"path","required":true,"schema":{"type":"integer","description":"Dish id from list_menu."}}]}},"/menu/items/{item_id}/visibility":{"post":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"show_dish","summary":"Show or hide a dish","description":"Hide a dish from the menu everywhere (POS, waiter app, website) without deleting it, or show a hidden dish again. Different from switching it off: switched-off dishes still show as \"sold out\".\n\nPermission: `menu:write`.","x-permission":"menu:write","parameters":[{"name":"item_id","in":"path","required":true,"schema":{"type":"integer","description":"Dish id from list_menu."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"visible":{"type":"boolean"}},"required":["visible"]}}}}}},"/menu/items/{item_id}/sizes":{"post":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"set_dish_sizes","summary":"Set dish sizes","description":"Replace all sizes of a dish (e.g. Half / Full, Regular / Large) with this list, in this order. An empty list removes the sizes and the dish keeps one price (give price). The dish price shown becomes the cheapest size.\n\nPermission: `menu:write`.","x-permission":"menu:write","parameters":[{"name":"item_id","in":"path","required":true,"schema":{"type":"integer","description":"Dish id from list_menu."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sizes":{"type":"array","maxItems":12,"items":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"price":{"type":"number","minimum":0}},"required":["name","price"]}},"price":{"type":"number","minimum":0,"description":"Single price, when removing all sizes."}},"required":["sizes"]}}}}}},"/menu/items/{item_id}/move":{"post":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"move_dish","summary":"Move a dish to another section","description":"Move a dish to another menu section.\n\nPermission: `menu:write`.","x-permission":"menu:write","parameters":[{"name":"item_id","in":"path","required":true,"schema":{"type":"integer","description":"Dish id from list_menu."}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"section_id":{"type":"integer","description":"Section id from list_sections."}},"required":["section_id"]}}}}}},"/menu/items/order":{"post":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"reorder_dishes","summary":"Reorder dishes","description":"Set the order dishes appear in: give dish ids in the wanted order (usually all dishes of one section).\n\nPermission: `menu:write`.","x-permission":"menu:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"item_ids":{"type":"array","items":{"type":"integer"},"minItems":1,"maxItems":300}},"required":["item_ids"]}}}}}},"/menu/sections":{"get":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"list_sections","summary":"Menu sections","description":"Menu sections (categories) with id, name, position, number of dishes, and whether they are on.\n\nPermission: `menu:read`.","x-permission":"menu:read"},"post":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"add_section","summary":"Add a menu section","description":"Create a new menu section (e.g. Starters). It goes to the end of the menu.\n\nPermission: `menu:write`.","x-permission":"menu:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100}},"required":["name"]}}}}}},"/menu/sections/{section_id}":{"patch":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"update_section","summary":"Rename or switch a section","description":"Rename a menu section, or switch the whole section on or off.\n\nPermission: `menu:write`.","x-permission":"menu:write","parameters":[{"name":"section_id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100},"active":{"type":"boolean"}}}}}}}},"/menu/sections/order":{"post":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"reorder_sections","summary":"Reorder menu sections","description":"Set the order of the menu sections: give section ids in the wanted order.\n\nPermission: `menu:write`.","x-permission":"menu:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"section_ids":{"type":"array","items":{"type":"integer"},"minItems":1,"maxItems":100}},"required":["section_ids"]}}}}}},"/menu/sections/{section_id}/delete":{"post":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_section","summary":"Delete a menu section","description":"Delete an empty menu section. Move or delete its dishes first; a section with dishes is never deleted (that would delete the dishes and their sales history).\n\nPermission: `menu:write`.","x-permission":"menu:write","parameters":[{"name":"section_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/menu/addons":{"get":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"list_addons","summary":"Add-ons","description":"Add-ons (extras like Extra Cheese) with id, name, price and whether they are on. Add-ons apply to the whole menu.\n\nPermission: `menu:read`.","x-permission":"menu:read"},"post":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"save_addon","summary":"Add or edit an add-on","description":"Create an add-on (no addon_id) or change one (with addon_id): name, price, on/off.\n\nPermission: `menu:write`.","x-permission":"menu:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"addon_id":{"type":"integer"},"name":{"type":"string","minLength":1,"maxLength":255},"price":{"type":"number","minimum":0},"available":{"type":"boolean"}}}}}}}},"/menu/addons/{addon_id}/delete":{"post":{"tags":["Menu"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_addon","summary":"Delete an add-on","description":"Delete an add-on for good.\n\nPermission: `menu:write`.","x-permission":"menu:write","parameters":[{"name":"addon_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/offers/coupons":{"get":{"tags":["Offers"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"list_coupons","summary":"Coupons","description":"Coupon codes with discount, minimum order, uses, dates and whether they are on.\n\nPermission: `offers:read`.","x-permission":"offers:read"},"post":{"tags":["Offers"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"save_coupon","summary":"Create or edit a coupon","description":"Create a coupon (no coupon_id: code, type and value needed) or change one (coupon_id; only the fields you pass change). type percent or flat. A milestone coupon is applied automatically when the cart reaches min_order (needs min_order).\n\nPermission: `offers:write`.","x-permission":"offers:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"coupon_id":{"type":"integer"},"code":{"type":"string","pattern":"^[A-Za-z0-9_-]{2,30}$"},"type":{"type":"string","enum":["percent","flat"]},"value":{"type":"number","exclusiveMinimum":0},"min_order":{"type":"number","minimum":0},"max_uses":{"type":"integer","minimum":0,"description":"0 = unlimited"},"valid_from":{"type":"string","description":"YYYY-MM-DD, empty for no limit."},"valid_until":{"type":"string","description":"YYYY-MM-DD, empty for no limit."},"description":{"type":"string","maxLength":255},"milestone":{"type":"boolean"},"active":{"type":"boolean"}}}}}}}},"/offers/coupons/{coupon_id}/delete":{"post":{"tags":["Offers"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_coupon","summary":"Delete a coupon","description":"Delete a coupon for good. To stop it for now, save it with active=false instead.\n\nPermission: `offers:write`.","x-permission":"offers:write","parameters":[{"name":"coupon_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/offers/combos":{"get":{"tags":["Offers"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"list_combos","summary":"Combos","description":"Combo deals with price, parts (dishes to pick from), days, times, dates and whether they are on.\n\nPermission: `offers:read`.","x-permission":"offers:read"},"post":{"tags":["Offers"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"save_combo","summary":"Create or edit a combo","description":"Create a combo (no combo_id) or replace one (combo_id; send the whole combo). Each part is a slot the customer fills with qty dishes from its choices.\n\nPermission: `offers:write`.","x-permission":"offers:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"combo_id":{"type":"integer"},"name":{"type":"string","maxLength":120},"price":{"type":"number","exclusiveMinimum":0},"parts":{"type":"array","minItems":1,"maxItems":12,"items":{"type":"object","properties":{"title":{"type":"string","maxLength":80,"description":"e.g. \"Pick a main\". Default: Included / Pick one."},"qty":{"type":"integer","minimum":1,"maximum":20,"default":1},"choices":{"type":"array","minItems":1,"maxItems":30,"items":{"type":"object","properties":{"menu_item_id":{"type":"integer"},"size":{"type":"string","description":"Size name for dishes with sizes."},"extra_price":{"type":"number","minimum":0}},"required":["menu_item_id"]}}},"required":["choices"]}},"description":{"type":"string","maxLength":300},"badge":{"type":"string","maxLength":40},"active":{"type":"boolean","default":true},"valid_from":{"type":"string","description":"YYYY-MM-DD, empty for no limit."},"valid_until":{"type":"string","description":"YYYY-MM-DD, empty for no limit."},"days":{"type":"string","description":"Weekdays it runs: digits 1-7, Monday = 1 (default 1234567, every day)."},"time_from":{"type":"string","description":"HH:MM, with time_to, e.g. lunch only."},"time_to":{"type":"string"}},"required":["name","price","parts"]}}}}}},"/offers/combos/{combo_id}/active":{"post":{"tags":["Offers"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"set_combo_active","summary":"Switch a combo on or off","description":"Switch a combo on or off.\n\nPermission: `offers:write`.","x-permission":"offers:write","parameters":[{"name":"combo_id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"active":{"type":"boolean"}},"required":["active"]}}}}}},"/offers/combos/{combo_id}/delete":{"post":{"tags":["Offers"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_combo","summary":"Delete a combo","description":"Delete a combo for good.\n\nPermission: `offers:write`.","x-permission":"offers:write","parameters":[{"name":"combo_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/offers/todays-special":{"get":{"tags":["Offers"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"get_todays_special","summary":"Today's special","description":"The dishes set as today's special, per weekday (0 = Sunday … 6 = Saturday, 7 = every day), with notes and daily limits.\n\nPermission: `offers:read`.","x-permission":"offers:read"},"post":{"tags":["Offers"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"set_todays_special","summary":"Set today's special","description":"Replace the whole special list. Each entry: weekday (0 = Sunday … 6 = Saturday, 7 = every day), menu_item_id, optional note and daily_limit. At most 6 dishes per day. An empty list clears it.\n\nPermission: `offers:write`.","x-permission":"offers:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"specials":{"type":"array","maxItems":60,"items":{"type":"object","properties":{"weekday":{"type":"integer","minimum":0,"maximum":7},"menu_item_id":{"type":"integer"},"note":{"type":"string","maxLength":160},"daily_limit":{"type":"integer","minimum":1,"maximum":9999}},"required":["weekday","menu_item_id"]}}},"required":["specials"]}}}}}},"/offers/scratch-card":{"get":{"tags":["Offers"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"get_scratch_card","summary":"Scratch card settings","description":"Scratch card (prize after an order) settings and prizes.\n\nPermission: `offers:read`.","x-permission":"offers:read"},"post":{"tags":["Offers"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"set_scratch_card","summary":"Change the scratch card","description":"Change scratch card settings; only the fields you pass change. prizes (if given) replaces all prizes: type flat (money off), percent or none (try again), value, weight (chance, 1-1000), optional min_order. Up to 8 prizes; switching it on needs at least one.\n\nPermission: `offers:write`.","x-permission":"offers:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"title":{"type":"string","maxLength":60},"min_order":{"type":"number","minimum":0,"description":"Order total that earns a card."},"next_min_order":{"type":"number","minimum":0,"description":"Minimum next order to use the prize."},"valid_days":{"type":"integer","minimum":1,"maximum":90},"monthly_budget":{"type":"number","minimum":0,"description":"0 = no limit."},"prizes":{"type":"array","maxItems":8,"items":{"type":"object","properties":{"type":{"type":"string","enum":["flat","percent","none"]},"value":{"type":"number","minimum":0},"weight":{"type":"integer","minimum":1,"maximum":1000},"min_order":{"type":"number","minimum":0}},"required":["type","weight"]}}}}}}}}},"/offers/wallet":{"get":{"tags":["Offers"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"get_wallet_settings","summary":"Wallet settings","description":"Prepaid wallet settings: on/off, name, top-up limits, quick amounts, bonus tiers and cashback. No customer balances.\n\nPermission: `offers:read`.","x-permission":"offers:read"},"post":{"tags":["Offers"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"set_wallet_settings","summary":"Change wallet settings","description":"Change prepaid wallet settings; only the fields you pass change. bonus_tiers: [{amount, bonus}] (top up amount, get bonus extra; bonus below amount). quick_amounts: up to 6 top-up buttons.\n\nPermission: `offers:write`.","x-permission":"offers:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"name":{"type":"string","maxLength":40},"min_topup":{"type":"number","minimum":1},"max_topup":{"type":"number","minimum":1},"max_balance":{"type":"number","minimum":1},"quick_amounts":{"type":"array","maxItems":6,"items":{"type":"integer","minimum":1}},"bonus_tiers":{"type":"array","maxItems":6,"items":{"type":"object","properties":{"amount":{"type":"number"},"bonus":{"type":"number"}},"required":["amount","bonus"]}},"cashback_pct":{"type":"number","minimum":0,"maximum":50},"cashback_max":{"type":"number","minimum":0}}}}}}}},"/website":{"get":{"tags":["Website"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"get_website","summary":"Website settings","description":"Everything the restaurant website shows: theme and colours, public profile (about, phone, address, opening hours, social links, order types, minimum order), photo banners, offer banners, which policy pages are customised, and SEO.\n\nPermission: `website:read`.","x-permission":"website:read"}},"/website/theme":{"post":{"tags":["Website"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"update_theme","summary":"Change the website theme","description":"Change the website look; only the fields you pass change. preset applies a ready colour scheme.\n\nPermission: `website:write`.","x-permission":"website:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"primary_color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"dark_color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"accent_color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"checkout_color":{"type":"string","description":"#rrggbb, or empty to follow the primary colour."},"font":{"type":"string","enum":["Poppins","Playfair Display","Roboto","Montserrat","Nunito","Lora"]},"card_style":{"type":"string","enum":["rounded","sharp","pill"]},"layout_style":{"type":"string","enum":["grid","list","magazine"]},"header_style":{"type":"string","enum":["hero","minimal","glass","cover","card","brand","poster","split","arch","story","neon","paper","profile","aurora","stack"]},"menu_card_style":{"type":"string","enum":["classic","modern","minimal","photo","list","elegant","compact","midnight","showcase"]},"home_card_style":{"type":"string","enum":["classic","grid","big","compact","carousel","magazine","printed","tiles","delivery","dark"]},"nav_bar_style":{"type":"string","enum":["classic","floating","glass","dark","pill","bubble","line","fab","minimal"]},"menu_nav_position":{"type":"string","enum":["left","top"]},"preset":{"type":"string","enum":["classic","midnight","sunset","emerald","ocean"]},"site_name":{"type":"string","maxLength":191,"description":"Name shown on the site; empty = the restaurant name."}}}}}}}},"/website/profile":{"post":{"tags":["Website"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"update_profile","summary":"Change the public profile","description":"Change what the website shows about the restaurant; only the fields you pass change. opening_hours: any of monday … sunday, each {open, opening, closing} with times like \"09:00 AM\". At least one of delivery, takeaway or dine-in must stay on.\n\nPermission: `website:write`.","x-permission":"website:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"restaurant_name":{"type":"string","maxLength":190},"description":{"type":"string","maxLength":2000,"description":"About the restaurant."},"phone":{"type":"string"},"email":{"type":"string"},"address":{"type":"string","maxLength":2000},"google_maps_link":{"type":"string"},"opening_hours":{"type":"object","properties":{"monday":{"type":"object","properties":{"open":{"type":"boolean"},"opening":{"type":"string","description":"e.g. 09:00 AM"},"closing":{"type":"string","description":"e.g. 11:00 PM (after midnight is fine: 01:00 AM)"}}},"tuesday":{"type":"object","properties":{"open":{"type":"boolean"},"opening":{"type":"string","description":"e.g. 09:00 AM"},"closing":{"type":"string","description":"e.g. 11:00 PM (after midnight is fine: 01:00 AM)"}}},"wednesday":{"type":"object","properties":{"open":{"type":"boolean"},"opening":{"type":"string","description":"e.g. 09:00 AM"},"closing":{"type":"string","description":"e.g. 11:00 PM (after midnight is fine: 01:00 AM)"}}},"thursday":{"type":"object","properties":{"open":{"type":"boolean"},"opening":{"type":"string","description":"e.g. 09:00 AM"},"closing":{"type":"string","description":"e.g. 11:00 PM (after midnight is fine: 01:00 AM)"}}},"friday":{"type":"object","properties":{"open":{"type":"boolean"},"opening":{"type":"string","description":"e.g. 09:00 AM"},"closing":{"type":"string","description":"e.g. 11:00 PM (after midnight is fine: 01:00 AM)"}}},"saturday":{"type":"object","properties":{"open":{"type":"boolean"},"opening":{"type":"string","description":"e.g. 09:00 AM"},"closing":{"type":"string","description":"e.g. 11:00 PM (after midnight is fine: 01:00 AM)"}}},"sunday":{"type":"object","properties":{"open":{"type":"boolean"},"opening":{"type":"string","description":"e.g. 09:00 AM"},"closing":{"type":"string","description":"e.g. 11:00 PM (after midnight is fine: 01:00 AM)"}}}}},"enable_delivery":{"type":"boolean"},"enable_takeaway":{"type":"boolean"},"enable_dinein":{"type":"boolean"},"enable_reservations":{"type":"boolean"},"minimum_order_value":{"type":"number","minimum":0},"packaging_charge":{"type":"number","minimum":0},"call_waiter_enabled":{"type":"boolean"},"instagram_link":{"type":"string"},"facebook_link":{"type":"string"},"twitter_link":{"type":"string"},"youtube_link":{"type":"string"},"linkedin_link":{"type":"string"}}}}}}}},"/website/logo":{"post":{"tags":["Website"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"set_logo","summary":"Change the logo","description":"Set the restaurant logo (JPEG, PNG, GIF or WebP, at most 2 MB). A square picture works best.\n\nPermission: `website:write`.","x-permission":"website:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"image":{"type":"string","description":"The picture: a data URL (data:image/jpeg;base64,…) or a public https link."}},"required":["image"]}}}}}},"/website/banners":{"post":{"tags":["Website"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"add_banner","summary":"Add a photo banner","description":"Add a photo banner to the website (JPEG, PNG, GIF or WebP, at most 5 MB). placement: home_top (slider at the top of the home page), home_menu, menu_top, cart, or story (up to 10 photos).\n\nPermission: `website:write`.","x-permission":"website:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"image":{"type":"string","description":"The picture: a data URL (data:image/jpeg;base64,…) or a public https link."},"placement":{"type":"string","enum":["home_top","home_menu","menu_top","cart","story"],"default":"home_top"}},"required":["image"]}}}}}},"/website/banners/{banner_id}":{"patch":{"tags":["Website"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"update_banner","summary":"Move a photo banner","description":"Change where a photo banner shows (placement).\n\nPermission: `website:write`.","x-permission":"website:write","parameters":[{"name":"banner_id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"placement":{"type":"string","enum":["home_top","home_menu","menu_top","cart","story"]}},"required":["placement"]}}}}}},"/website/banners/order":{"post":{"tags":["Website"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"reorder_banners","summary":"Reorder photo banners","description":"Set the order of photo banners: give banner ids in the wanted order.\n\nPermission: `website:write`.","x-permission":"website:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"banner_ids":{"type":"array","items":{"type":"integer"},"minItems":1,"maxItems":100}},"required":["banner_ids"]}}}}}},"/website/banners/{banner_id}/delete":{"post":{"tags":["Website"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_banner","summary":"Delete a photo banner","description":"Delete a photo banner for good.\n\nPermission: `website:write`.","x-permission":"website:write","parameters":[{"name":"banner_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/website/offer-banners":{"post":{"tags":["Website"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"save_offer_banner","summary":"Create or edit an offer banner","description":"An animated text banner (no photo needed), e.g. \"50% OFF\" with a coupon code. No offer_banner_id = new. Only title is required for a new one.\n\nPermission: `website:write`.","x-permission":"website:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"offer_banner_id":{"type":"integer"},"title":{"type":"string","maxLength":40,"description":"Headline, e.g. 50% OFF"},"subtitle":{"type":"string","maxLength":90},"cta":{"type":"string","maxLength":24,"description":"Button text."},"code":{"type":"string","maxLength":30,"description":"Coupon code to show."},"template":{"type":"string","enum":["burst","ticket","neon","confetti","marquee","split","countdown","aurora","stamp","bubbles","stripes","spotlight","gift","tag","wave","orbit","typewriter","gold","pulse","bounce","polaroid","festive","flash","scratch","hearts","snow","sunrise","cinema"]},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"placement":{"type":"string","enum":["home_top","home_menu","menu_top","cart","story"]},"menu_item_id":{"type":"integer","description":"Dish the banner opens."},"active":{"type":"boolean","default":true},"ends_at":{"type":"string","description":"YYYY-MM-DD HH:MM: shows a countdown and hides after."}}}}}}}},"/website/offer-banners/{offer_banner_id}/delete":{"post":{"tags":["Website"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_offer_banner","summary":"Delete an offer banner","description":"Delete an offer banner for good.\n\nPermission: `website:write`.","x-permission":"website:write","parameters":[{"name":"offer_banner_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/website/policies/{policy}":{"get":{"tags":["Website"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"get_policy_page","summary":"Read a policy page","description":"The text of one policy page (privacy, terms, refund, shipping, cookie): the restaurant's own text, or the ready-made default if not customised.\n\nPermission: `website:read`.","x-permission":"website:read","parameters":[{"name":"policy","in":"path","required":true,"schema":{"type":"string","enum":["privacy","terms","refund","shipping","cookie"]}}]},"post":{"tags":["Website"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"set_policy_page","summary":"Change a policy page","description":"Replace the text of a policy page with your own (HTML allowed, no scripts). reset=true goes back to the ready-made default text.\n\nPermission: `website:write`.","x-permission":"website:write","parameters":[{"name":"policy","in":"path","required":true,"schema":{"type":"string","enum":["privacy","terms","refund","shipping","cookie"]}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","maxLength":100000},"reset":{"type":"boolean","default":false}}}}}}}},"/website/seo":{"post":{"tags":["Website"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"update_seo","summary":"Change SEO settings","description":"Change how the website shows on Google; only the fields you pass change. pages: any of home, menu, about, contact, each {title up to 90, description up to 300}.\n\nPermission: `website:write`.","x-permission":"website:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pages":{"type":"object","properties":{"home":{"type":"object","properties":{"title":{"type":"string","maxLength":90},"description":{"type":"string","maxLength":300}}},"menu":{"type":"object","properties":{"title":{"type":"string","maxLength":90},"description":{"type":"string","maxLength":300}}},"about":{"type":"object","properties":{"title":{"type":"string","maxLength":90},"description":{"type":"string","maxLength":300}}},"contact":{"type":"object","properties":{"title":{"type":"string","maxLength":90},"description":{"type":"string","maxLength":300}}}}},"keywords":{"type":"string","maxLength":300},"cuisine":{"type":"string","maxLength":120},"price_range":{"type":"string","enum":["","₹","₹₹","₹₹₹","₹₹₹₹"]},"google_verification":{"type":"string","description":"Search Console HTML tag code."},"ga_id":{"type":"string","description":"G-XXXXXXXXXX"},"meta_pixel_id":{"type":"string"},"hide_from_google":{"type":"boolean"}}}}}}}},"/loyalty":{"get":{"tags":["Loyalty"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"get_loyalty","summary":"Loyalty programme","description":"The loyalty programme: on/off, type (points, cashback or stamps) and its rules, referral rewards, rewards catalogue and tiers. No customer data.\n\nPermission: `loyalty:read`.","x-permission":"loyalty:read"},"post":{"tags":["Loyalty"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"update_loyalty","summary":"Change the loyalty programme","description":"Change programme settings; only the fields you pass change. program_type: points (earn points per amount spent, redeem for money off), cashback (a % back into the wallet) or stamps (one stamp per order, a reward when the card is full).\n\nPermission: `loyalty:write`.","x-permission":"loyalty:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"program_type":{"type":"string","enum":["points","cashback","stamps"]},"earn_points_per_amount":{"type":"integer","minimum":0,"description":"Points earned for every earn_amount_threshold spent."},"earn_amount_threshold":{"type":"number","minimum":0},"redeem_value_per_point":{"type":"number","minimum":0,"description":"Money one point is worth."},"min_redeem_points":{"type":"integer","minimum":0},"points_expiry_days":{"type":"integer","minimum":0,"description":"0 = never expire."},"cashback_pct":{"type":"number","minimum":0.5,"maximum":50},"cashback_max":{"type":"number","minimum":0,"description":"Most cashback per order, 0 = no limit."},"stamp_goal":{"type":"integer","minimum":2,"maximum":20},"stamp_min_order":{"type":"number","minimum":0},"stamp_reward_kind":{"type":"string","enum":["item","flat","percent"]},"stamp_reward_item_id":{"type":"integer","description":"Free dish when kind is item."},"stamp_reward_value":{"type":"number","minimum":0,"description":"Money or % off when kind is flat or percent."},"reward_valid_days":{"type":"integer","minimum":1,"maximum":365},"referral_enabled":{"type":"boolean"},"referrer_reward_points":{"type":"integer","minimum":0},"referred_reward_points":{"type":"integer","minimum":0}}}}}}}},"/loyalty/rewards":{"post":{"tags":["Loyalty"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"save_reward","summary":"Add or edit a reward","description":"Rewards customers buy with points. New: menu_item_id and points_cost. Edit (reward_id): points_cost and/or active.\n\nPermission: `loyalty:write`.","x-permission":"loyalty:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reward_id":{"type":"integer"},"menu_item_id":{"type":"integer"},"points_cost":{"type":"integer","minimum":1},"active":{"type":"boolean"}}}}}}}},"/loyalty/rewards/{reward_id}/delete":{"post":{"tags":["Loyalty"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_reward","summary":"Delete a reward","description":"Delete a reward from the catalogue.\n\nPermission: `loyalty:write`.","x-permission":"loyalty:write","parameters":[{"name":"reward_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/loyalty/tiers":{"post":{"tags":["Loyalty"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"save_tier","summary":"Add or edit a tier","description":"Customer tiers by total spend (e.g. Silver from 5,000, Gold from 15,000) with a points multiplier. No tier_id = new.\n\nPermission: `loyalty:write`.","x-permission":"loyalty:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tier_id":{"type":"integer"},"name":{"type":"string","maxLength":50},"min_total_spent":{"type":"number","minimum":0},"points_multiplier":{"type":"number","minimum":0.1,"maximum":9.99},"icon":{"type":"string","maxLength":30},"position":{"type":"integer","minimum":0}}}}}}}},"/loyalty/tiers/{tier_id}/delete":{"post":{"tags":["Loyalty"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_tier","summary":"Delete a tier","description":"Delete a customer tier.\n\nPermission: `loyalty:write`.","x-permission":"loyalty:write","parameters":[{"name":"tier_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/tables":{"get":{"tags":["Tables"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"list_tables","summary":"Tables","description":"Areas and their tables with seats and live status: busy (open order), reserved (confirmed booking today), free or off.\n\nPermission: `tables:read`.","x-permission":"tables:read"},"post":{"tags":["Tables"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"save_table","summary":"Add or edit a table","description":"Add a table (no table_id: number and area_id) or change one. Table names are unique in the restaurant; renaming a table makes its old QR code stop working.\n\nPermission: `tables:write`.","x-permission":"tables:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"table_id":{"type":"integer"},"number":{"type":"string","maxLength":50,"description":"Table name, e.g. T7"},"area_id":{"type":"integer"},"seats":{"type":"integer","minimum":1,"maximum":50},"available":{"type":"boolean","description":"false = off (its QR takes no orders)."}}}}}}}},"/tables/{table_id}/delete":{"post":{"tags":["Tables"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_table","summary":"Delete a table","description":"Delete a table for good. A table with an open order or a ticket in the kitchen is never deleted.\n\nPermission: `tables:write`.","x-permission":"tables:write","parameters":[{"name":"table_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/tables/areas":{"post":{"tags":["Tables"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"save_area","summary":"Add or edit an area","description":"Add an area (e.g. Rooftop, AC Hall) or rename one. color like #22c55e.\n\nPermission: `tables:write`.","x-permission":"tables:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"area_id":{"type":"integer"},"name":{"type":"string","maxLength":100},"color":{"type":"string"},"note":{"type":"string","maxLength":120}},"required":["name"]}}}}}},"/tables/areas/{area_id}/delete":{"post":{"tags":["Tables"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_area","summary":"Delete an area","description":"Delete an area. If it has tables, give move_to (another area id): its tables move there (clashing names get the old area's initial, e.g. R-T1).\n\nPermission: `tables:write`.","x-permission":"tables:write","parameters":[{"name":"area_id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"move_to":{"type":"integer"}}}}}}}},"/tables/waiter-calls":{"get":{"tags":["Tables"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"list_waiter_calls","summary":"Waiter calls","description":"Open waiter calls from tables (oldest first) and those answered today.\n\nPermission: `tables:read`.","x-permission":"tables:read"}},"/tables/waiter-calls/{call_id}/answer":{"post":{"tags":["Tables"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"answer_waiter_call","summary":"Mark a waiter call answered","description":"Mark a waiter call as attended.\n\nPermission: `tables:write`.","x-permission":"tables:write","parameters":[{"name":"call_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/reservations":{"get":{"tags":["Reservations"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"list_reservations","summary":"Reservations","description":"Table bookings for a day (default today) or a date range, optionally one status.\n\nPermission: `reservations:read`.","x-permission":"reservations:read","parameters":[{"name":"date","in":"query","required":false,"schema":{"type":"string","description":"YYYY-MM-DD"}},{"name":"from","in":"query","required":false,"schema":{"type":"string","description":"YYYY-MM-DD"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","description":"YYYY-MM-DD"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["Pending","Confirmed","Checked In","Completed","Cancelled","No Show"]}}]},"post":{"tags":["Reservations"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"add_reservation","summary":"Add a reservation","description":"Book a table. time_slot like \"07:30 PM\". A table already booked for that date and slot is refused. The guest gets an email if an email is given.\n\nPermission: `reservations:write`.","x-permission":"reservations:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string","description":"YYYY-MM-DD"},"time_slot":{"type":"string","maxLength":20},"name":{"type":"string","minLength":2,"maxLength":100},"phone":{"type":"string"},"email":{"type":"string"},"guests":{"type":"integer","minimum":1,"maximum":50},"table_id":{"type":"integer"},"meal_type":{"type":"string","maxLength":30,"default":"Dinner"},"note":{"type":"string","maxLength":500},"confirmed":{"type":"boolean","default":true}},"required":["date","time_slot","name","guests"]}}}}}},"/reservations/{reservation_id}/status":{"post":{"tags":["Reservations"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"update_reservation","summary":"Update a reservation","description":"Change a booking's status: Confirmed (approve), Checked In (seated), Completed, Cancelled (decline), No Show, or Pending. Confirming or cancelling emails the guest if they gave an email.\n\nPermission: `reservations:write`.","x-permission":"reservations:write","parameters":[{"name":"reservation_id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["Pending","Confirmed","Checked In","Completed","Cancelled","No Show"]}},"required":["status"]}}}}}},"/staff":{"get":{"tags":["Staff"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"list_staff","summary":"Staff","description":"Staff members with role, email, phone and whether they can log in. Never passwords.\n\nPermission: `staff:read`.","x-permission":"staff:read"},"post":{"tags":["Staff"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"add_staff","summary":"Add a staff member","description":"Add a staff login. role: Manager, Waiter, Chef, Cashier, Delivery (Admin only from the dashboard). They log in with email and the password given (6+ characters); tell them to change it.\n\nPermission: `staff:write`.","x-permission":"staff:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"email":{"type":"string"},"phone":{"type":"string","description":"With country code, e.g. +91-9876543210"},"role":{"type":"string","enum":["Manager","Waiter","Chef","Cashier","Delivery"]},"password":{"type":"string","minLength":6}},"required":["name","email","phone","role","password"]}}}}}},"/staff/{staff_id}":{"patch":{"tags":["Staff"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"update_staff","summary":"Change a staff member","description":"Change name, phone or role, or pause / resume their login (active). Passwords are changed only in the dashboard.\n\nPermission: `staff:write`.","x-permission":"staff:write","parameters":[{"name":"staff_id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"phone":{"type":"string"},"role":{"type":"string","enum":["Manager","Waiter","Chef","Cashier","Delivery"]},"active":{"type":"boolean"}}}}}}}},"/staff/{staff_id}/delete":{"post":{"tags":["Staff"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"remove_staff","summary":"Remove a staff member","description":"Delete a staff login for good (pausing with update_staff active=false keeps it).\n\nPermission: `staff:write`.","x-permission":"staff:write","parameters":[{"name":"staff_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/stock":{"get":{"tags":["Stock"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"list_stock","summary":"Stock","description":"Stock items with quantity, unit, low-stock level, cost and status (ok, low, out).\n\nPermission: `stock:read`.","x-permission":"stock:read","parameters":[{"name":"only_low","in":"query","required":false,"schema":{"type":"boolean","default":false}}]},"post":{"tags":["Stock"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"save_stock_item","summary":"Add or edit a stock item","description":"Add a stock item (no stock_id: name and unit; opening_stock counts what is on the shelf now) or change one. unit: kg, g, L, ml, pcs, dozen, box, packet, bottle, can, tray, bunch, unit.\n\nPermission: `stock:write`.","x-permission":"stock:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"stock_id":{"type":"integer"},"name":{"type":"string","maxLength":150},"unit":{"type":"string","enum":["kg","g","L","ml","pcs","dozen","box","packet","bottle","can","tray","bunch","unit"]},"category":{"type":"string","maxLength":100},"low_stock_level":{"type":"number","minimum":0},"par_level":{"type":"number","minimum":0},"cost_per_unit":{"type":"number","minimum":0},"opening_stock":{"type":"number","minimum":0}}}}}}}},"/stock/{stock_id}/restock":{"post":{"tags":["Stock"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"restock","summary":"Record stock coming in","description":"Add stock that came in (a purchase). The cost is recorded as an expense.\n\nPermission: `stock:write`.","x-permission":"stock:write","parameters":[{"name":"stock_id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"quantity":{"type":"number","exclusiveMinimum":0},"cost_per_unit":{"type":"number","minimum":0},"note":{"type":"string","maxLength":200}},"required":["quantity"]}}}}}},"/stock/{stock_id}/adjust":{"post":{"tags":["Stock"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"adjust_stock","summary":"Correct stock","description":"kind wastage: quantity thrown away (recorded as an expense); set: the quantity on hand now; adjustment: + or − correction.\n\nPermission: `stock:write`.","x-permission":"stock:write","parameters":[{"name":"stock_id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["wastage","set","adjustment"]},"quantity":{"type":"number"},"reason":{"type":"string","maxLength":200}},"required":["kind","quantity"]}}}}}},"/stock/{stock_id}/delete":{"post":{"tags":["Stock"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_stock_item","summary":"Remove a stock item","description":"Remove a stock item (its history stays in reports; it leaves any recipes).\n\nPermission: `stock:write`.","x-permission":"stock:write","parameters":[{"name":"stock_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/delivery/zones":{"get":{"tags":["Delivery"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"list_delivery_zones","summary":"Delivery zones","description":"Delivery areas by pincode with delivery charge, estimated minutes and on/off.\n\nPermission: `delivery:read`.","x-permission":"delivery:read"},"post":{"tags":["Delivery"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"save_delivery_zone","summary":"Add or edit a delivery zone","description":"Add a zone (no zone_id: pincode needed) or change one.\n\nPermission: `delivery:write`.","x-permission":"delivery:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"zone_id":{"type":"integer"},"pincode":{"type":"string","maxLength":10},"name":{"type":"string","maxLength":100},"charge":{"type":"number","minimum":0},"minutes":{"type":"integer","minimum":1,"maximum":300},"active":{"type":"boolean"}}}}}}}},"/delivery/zones/{zone_id}/delete":{"post":{"tags":["Delivery"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_delivery_zone","summary":"Delete a delivery zone","description":"Delete a delivery zone (orders from that pincode stop).\n\nPermission: `delivery:write`.","x-permission":"delivery:write","parameters":[{"name":"zone_id","in":"path","required":true,"schema":{"type":"integer"}}]}},"/catering":{"get":{"tags":["Catering"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"list_catering","summary":"Catering","description":"Catering requests (newest first, with contact, event date, guests, quote, status) and the price tiers.\n\nPermission: `catering:read`.","x-permission":"catering:read","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["new","contacted","confirmed","completed","cancelled"]}}]}},"/catering/requests/{request_id}":{"post":{"tags":["Catering"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"update_catering_request","summary":"Answer a catering request","description":"Move a request on: contacted, confirmed (approve), completed or cancelled (decline). Optionally set the quoted price and a note.\n\nPermission: `catering:write`.","x-permission":"catering:write","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["new","contacted","confirmed","completed","cancelled"]},"quoted_price":{"type":"number","minimum":0},"note":{"type":"string","maxLength":1000}},"required":["status"]}}}}}},"/catering/tiers":{"post":{"tags":["Catering"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"save_catering_tier","summary":"Add or edit a catering price tier","description":"A price per guest for a guest range, e.g. 20–50 guests at 450. No tier_id = new.\n\nPermission: `catering:write`.","x-permission":"catering:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tier_id":{"type":"integer"},"label":{"type":"string","maxLength":100},"min_guests":{"type":"integer","minimum":1},"max_guests":{"type":"integer","minimum":1},"price":{"type":"number","minimum":0},"active":{"type":"boolean"}}}}}}}},"/catering/tiers/{tier_id}/delete":{"post":{"tags":["Catering"],"security":[{"bearer":[]}],"responses":{"200":{"$ref":"#/components/responses/Ok"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}},"operationId":"delete_catering_tier","summary":"Delete a catering price tier","description":"Delete a catering price tier.\n\nPermission: `catering:write`.","x-permission":"catering:write","parameters":[{"name":"tier_id","in":"path","required":true,"schema":{"type":"integer"}}]}}}}