RestroGrow API · v1
RestroGrow API
Read and change a RestroGrow restaurant from your own code, Claude Code, Cursor or any AI agent: menu, orders, reports, website, offers, loyalty, tables, reservations, staff, stock, delivery zones and catering. Each API key has only the permissions the restaurant owner chose.
https://restrogrow.com/api/v1https://restrogrow.com/mcp/api/v1/openapi.jsonQuick start
- The restaurant owner logs in to RestroGrow and opens API keys in the left menu.
- They name the key, tick the permissions it needs and press Create key. The key (
rg_live_…) is shown once: copy it somewhere safe. - Call the API with the key:
curl https://restrogrow.com/api/v1/me \
-H "Authorization: Bearer rg_live_YOUR_KEY"
{
"success": true,
"data": {
"restaurant_id": "RESSGI002",
"restaurant": "Spice Garden Indiranagar",
"key": { "id": 7, "name": "Stock sync", "permissions": ["menu:read", "menu:write"], "valid_until": "2026-12-31 23:59:59" },
"rate_limit_per_minute": 120
},
"summary": "Key \"Stock sync\" can: menu:read, menu:write"
}
Authentication
Send the key on every request, in either header:
Authorization: Bearer rg_live_YOUR_KEY
X-API-Key: rg_live_YOUR_KEY
- A key works for one restaurant: the one whose owner created it. Ids from other restaurants answer
404. - Keep keys on your server. Never put a key in a public web page, a mobile app or a public Git repository.
- Bodies are JSON: send
Content-Type: application/json. Money is in the restaurant's currency (see GET /restaurant); times are in the restaurant's timezone.
Managing keys
The owner manages every key in the dashboard › API keys:
| Option | What it does |
|---|---|
| Valid until | Never, 7 days, 30 days, 90 days, 1 year or a date you pick (works through the end of that day). GET /me returns it as valid_until (null = never). |
| Edit | Change the name, permissions, valid-until date or allowed IPs. The key itself stays the same, so nothing breaks. |
| Rotate | Get a new secret with the same settings. The old key stops right away, in 1 hour or in 24 hours, so you can swap it in your code without downtime. |
| Allowed IPs | Optional: the key works only from these IP addresses. Others get 403 ip_not_allowed. |
| Pause / Resume | Stop a key for a while without losing it. Calls get 403 key_paused. |
| Revoke | The key stops working for good, at once. Do this if a key leaks. |
| Delete | Remove a revoked or expired key from the list. |
The page also shows when each key was last used and how many calls it made. A restaurant can have up to 20 working keys.
Permissions
Each endpoint needs one permission. A key without it gets 403 missing_permission. Menu permissions also cover photos, sizes, sections, add-ons and hiding or deleting dishes. Payments and customer details are not part of the API.
| Permission | Allows | Endpoints |
|---|---|---|
restaurant:read | Name, currency, timezone and menu sections | GET /restaurant |
menu:read | Dishes, prices, sizes, which are switched on | GET /menu |
menu:write | Add dishes, edit them, switch them on or off | POST /menu/items, PATCH /menu/items/{id}, POST /menu/availability |
orders:read | Orders with dishes, customer name and phone, payment | GET /orders, GET /orders/{id}, GET /orders/number/{number} |
orders:write | Move orders along: accept, prepare, ready, complete, cancel, reject | POST /orders/{id}/status |
reports:read | Sales and ready-made reports | GET /reports/sales, GET /reports/{report} |
website:read / website:write | Theme and colours, logo, photo and offer banners, about, opening hours, order types, policy pages, SEO | /website… |
offers:read / offers:write | Coupons, combos, today's special, scratch card and wallet settings (never customer wallets) | /offers… |
loyalty:read / loyalty:write | Loyalty programme rules (points, cashback, stamps), rewards, tiers. No customer data | /loyalty… |
tables:read / tables:write | Areas, tables with live status, waiter calls | /tables… |
reservations:read / reservations:write | Bookings: add, confirm, seat, complete, cancel | /reservations… |
staff:read / staff:write | Staff list, add, change role, pause, remove (never passwords; no Admin staff) | /staff… |
stock:read / stock:write | Stock items, restock, wastage, counts | /stock… |
delivery:read / delivery:write | Delivery zones by pincode | /delivery/zones… |
catering:read / catering:write | Catering requests and price tiers | /catering… |
GET /me works with any key.
AI agents (MCP)
The same key works on RestroGrow's MCP server, so AI agents can use RestroGrow as tools. The agent sees only the tools the key's permissions allow.
Claude Code
claude mcp add --transport http restrogrow https://restrogrow.com/mcp \
--header "Authorization: Bearer rg_live_YOUR_KEY"
Then ask: “what sold best this week?”, “switch off Paneer Tikka, we ran out”, “add Mango Lassi for 129 to Beverages”.
Cursor, Windsurf, VS Code and other MCP apps
{
"mcpServers": {
"restrogrow": {
"url": "https://restrogrow.com/mcp",
"headers": { "Authorization": "Bearer rg_live_YOUR_KEY" }
}
}
}
| MCP tool | Permission |
|---|---|
get_restaurant | restaurant:read |
list_menu | menu:read |
add_dish, update_dish, set_dish_availability | menu:write |
list_orders, get_order | orders:read |
update_order_status | orders:write |
get_sales_summary, get_report | reports:read |
| …and one tool for every endpoint in All endpoints (website, offers, loyalty, tables, reservations, staff, stock, delivery, catering) | that endpoint's permission |
ChatGPT and claude.ai users don't need a key: they connect with the owner's login from Growth › ChatGPT & Claude in the dashboard.
Responses & errors
Every answer is JSON. A success has data plus a one-line summary for people:
{ "success": true, "data": { … }, "summary": "✅ Paneer Tikka updated: price ₹249 → ₹269." }
A refusal has an error with a stable code and a message you can show:
{ "success": false, "error": { "code": "missing_permission", "message": "This key has no \"menu:write\" permission. …" } }
| HTTP | code | Meaning |
|---|---|---|
| 400 | bad_json | The body is not a JSON object |
| 401 | missing_key, invalid_key | No key, or it is wrong, revoked or expired |
| 403 | missing_permission | The key lacks the permission this endpoint needs |
| 403 | key_paused, ip_not_allowed | The owner paused the key, or it doesn't work from your IP address |
| 403 | account_blocked, api_off, forbidden | Plan expired, account switched off, or this feature is off for the restaurant |
| 404 | not_found | No such endpoint, dish or order (in this restaurant) |
| 405 | method_not_allowed | The path exists, but not with this method |
| 422 | invalid_request | The values were refused, e.g. a negative price or a move the order can't make |
| 429 | rate_limited | Too many calls: wait for Retry-After seconds |
| 500 / 503 | server_error, unavailable | Our side: try again shortly |
Rate limits
120 calls a minute per restaurant, shared by all its keys and AI connections. Over that you get 429 with a Retry-After header.
Endpoints
Paths are relative to https://restrogrow.com/api/v1. period is one of today, yesterday, this_week, last_week, last_7_days, this_month, last_month, last_30_days.
GET/me
The restaurant this key belongs to and its permissions. Any key.
GET/restaurant restaurant:read
Name, currency, timezone and menu sections with their dish counts.
{ "success": true, "data": { "restaurant": "Spice Garden Indiranagar", "currency": "₹", "timezone": "Asia/Kolkata",
"menu_sections": [ { "id": 239, "name": "Starters", "dishes": 10 } ] } }
POST/menu/items menu:write
Add a dish. A new section is created if it doesn't exist. Answers 201. Photos and sizes are added from the dashboard.
| Body | Type | |
|---|---|---|
name * | string | 2–150 characters |
price * | number | 0 – 1,000,000 |
section * | string | e.g. Beverages |
type | string | Veg (default), Non Veg, Egg, Drink, Dessert, Other |
description | string | Up to 1000 characters |
prep_minutes | 0–180 | Kitchen time |
available | boolean | Default true |
curl -X POST https://restrogrow.com/api/v1/menu/items \
-H "Authorization: Bearer rg_live_YOUR_KEY" -H "Content-Type: application/json" \
-d '{"name":"Mango Lassi","price":129,"section":"Beverages","type":"Drink"}'
{ "success": true, "data": { "item_id": 1341, "section": "Beverages", "new_section": false },
"summary": "✅ Added Mango Lassi (Drink, ₹129) to Beverages. …" }
PATCH/menu/items/{item_id} menu:write
Change only the fields you send. A dish with sizes keeps its prices in sizes, not price. POST works too, for clients without PATCH.
| Body | Type | |
|---|---|---|
name | string | Up to 150 characters |
description | string | Up to 1000 characters |
price | number | Dishes without sizes |
type | string | As in POST /menu/items |
sizes | array | [{"name":"Half","price":180},{"name":"Full","price":320}]: existing size names |
curl -X PATCH https://restrogrow.com/api/v1/menu/items/1289 \
-H "Authorization: Bearer rg_live_YOUR_KEY" -H "Content-Type: application/json" \
-d '{"price":269}'
{ "success": true, "data": { "item_id": 1289, "changes": ["price ₹249 → ₹269"] }, "summary": "✅ Paneer Tikka updated: price ₹249 → ₹269." }
POST/menu/availability menu:write
Switch 1–50 dishes on (orderable) or off (sold out). Ids not on this menu come back in not_found.
curl -X POST https://restrogrow.com/api/v1/menu/availability \
-H "Authorization: Bearer rg_live_YOUR_KEY" -H "Content-Type: application/json" \
-d '{"item_ids":[1289,1291],"available":false}'
{ "success": true, "data": { "switched_on": false, "dishes": { "1289": "Paneer Tikka", "1291": "Chilli Paneer" }, "not_found": [] } }
GET/orders orders:read
Orders in a period, newest first.
| Query | Type | |
|---|---|---|
period | string | Default today |
status | string | active (Pending, Accepted, Preparing, Ready), or one of Pending, Accepted, Preparing, Ready, Served, Completed, Cancelled, Rejected |
limit | 1–50 | Default 20 |
{ "success": true, "data": { "period": "today", "currency": "₹", "orders": [
{ "order_id": 26619, "order_number": "ORD-20261024-9723", "customer": "Rohan Iyer", "type": "Delivery", "source": "website",
"total": 540.0, "status": "Pending", "payment": "Paid", "payment_method": "UPI", "time": "2026-10-24 13:55:19" } ] } }
GET/orders/{order_id} orders:read
One order with its dishes, customer, payment and can_move_to: the statuses it can move to next. To look an order up by the number on the bill, use GET /orders/number/{order_number}.
{ "success": true, "data": { "order_id": 26619, "order_number": "ORD-20261024-9723", "status": "Pending",
"can_move_to": ["Preparing", "Cancelled", "Accepted", "Rejected"], "customer": "Rohan Iyer", "phone": "9876543210",
"total": 540.0, "items": [ { "dish": "Paneer Tikka", "qty": 2, "amount": 498.0 } ] } }
POST/orders/{order_id}/status orders:write
Move an order to its next status, with the same rules as the dashboard. Cancelling or rejecting needs a reason (the customer sees it) and can't be undone.
| Body | Type | |
|---|---|---|
status * | string | Accepted, Preparing, Ready, Served, Completed, Cancelled, Rejected |
reason | string | Needed for Cancelled / Rejected |
prep_minutes | 1–300 | When accepting: kitchen time |
curl -X POST https://restrogrow.com/api/v1/orders/26619/status \
-H "Authorization: Bearer rg_live_YOUR_KEY" -H "Content-Type: application/json" \
-d '{"status":"Accepted","prep_minutes":20}'
{ "success": true, "data": { "order_id": 26619, "order_number": "ORD-20261024-9723", "status": "Accepted" },
"summary": "✅ Order #ORD-20261024-9723 is now Accepted (ready in about 20 minutes)." }
GET/reports/sales reports:read
Sales, orders, average bill and orders by channel for a period (default today), compared with the period before.
{ "success": true, "data": { "period": "this month", "currency": "₹", "sales": 454546.33, "orders": 673, "average_bill": 675.0,
"counter_orders": 377, "website_orders": 288, "whatsapp_orders": 0,
"compared_with": { "period": "same days last month", "sales": 237623.94, "orders": 334 }, "change_percent": 91 } }
GET/reports/{report} reports:read
A ready-made report as text in data.text. Query: period (default last_7_days); dish for the dish report.
| report | |
|---|---|
top_dishes / slow_dishes | Best and least sold dishes |
dish | How much one dish sold (?dish=Paneer Tikka) |
peak_hours | Busiest hours and day |
payments / channels | Cash, UPI, card split / counter vs website vs WhatsApp |
customers / lapsed | New vs returning / regulars who stopped coming |
cancellations, today_so_far, advice | Cancelled orders, today's snapshot, what to do next |
All endpoints
Every endpoint, read live from the OpenAPI spec, so this list is always up to date. Paths are relative to https://restrogrow.com/api/v1. GET endpoints take their fields as query parameters; the others take a JSON body. A {…} part of the path is filled in with that value.
Loading the endpoint list…
OpenAPI spec
The full machine-readable description is at https://restrogrow.com/api/v1/openapi.json (OpenAPI 3.1). Import it into Postman, Insomnia or a code generator, or give it to an AI agent.
Security
- Keys are stored only as a SHA-256 hash; RestroGrow can't show a key again after it's created.
- Every change made with a key shows in the owner's Activity log with the key's name.
- Only the restaurant owner can create, edit, rotate, pause or revoke keys. A key stops working when it's revoked, expired or paused, used from an IP that isn't allowed, or when the owner account is switched off.
- Found a security problem? Email support@restrogrow.com.