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.

linkBase URLhttps://restrogrow.com/api/v1
smart_toyMCP serverhttps://restrogrow.com/mcp
data_objectOpenAPI/api/v1/openapi.json

Quick start

  1. The restaurant owner logs in to RestroGrow and opens API keys in the left menu.
  2. They name the key, tick the permissions it needs and press Create key. The key (rg_live_…) is shown once: copy it somewhere safe.
  3. 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:

OptionWhat it does
Valid untilNever, 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).
EditChange the name, permissions, valid-until date or allowed IPs. The key itself stays the same, so nothing breaks.
RotateGet 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 IPsOptional: the key works only from these IP addresses. Others get 403 ip_not_allowed.
Pause / ResumeStop a key for a while without losing it. Calls get 403 key_paused.
RevokeThe key stops working for good, at once. Do this if a key leaks.
DeleteRemove 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.

PermissionAllowsEndpoints
restaurant:readName, currency, timezone and menu sectionsGET /restaurant
menu:readDishes, prices, sizes, which are switched onGET /menu
menu:writeAdd dishes, edit them, switch them on or offPOST /menu/items, PATCH /menu/items/{id}, POST /menu/availability
orders:readOrders with dishes, customer name and phone, paymentGET /orders, GET /orders/{id}, GET /orders/number/{number}
orders:writeMove orders along: accept, prepare, ready, complete, cancel, rejectPOST /orders/{id}/status
reports:readSales and ready-made reportsGET /reports/sales, GET /reports/{report}
website:read / website:writeTheme and colours, logo, photo and offer banners, about, opening hours, order types, policy pages, SEO/website…
offers:read / offers:writeCoupons, combos, today's special, scratch card and wallet settings (never customer wallets)/offers…
loyalty:read / loyalty:writeLoyalty programme rules (points, cashback, stamps), rewards, tiers. No customer data/loyalty…
tables:read / tables:writeAreas, tables with live status, waiter calls/tables…
reservations:read / reservations:writeBookings: add, confirm, seat, complete, cancel/reservations…
staff:read / staff:writeStaff list, add, change role, pause, remove (never passwords; no Admin staff)/staff…
stock:read / stock:writeStock items, restock, wastage, counts/stock…
delivery:read / delivery:writeDelivery zones by pincode/delivery/zones…
catering:read / catering:writeCatering 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 toolPermission
get_restaurantrestaurant:read
list_menumenu:read
add_dish, update_dish, set_dish_availabilitymenu:write
list_orders, get_orderorders:read
update_order_statusorders:write
get_sales_summary, get_reportreports: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. …" } }
HTTPcodeMeaning
400bad_jsonThe body is not a JSON object
401missing_key, invalid_keyNo key, or it is wrong, revoked or expired
403missing_permissionThe key lacks the permission this endpoint needs
403key_paused, ip_not_allowedThe owner paused the key, or it doesn't work from your IP address
403account_blocked, api_off, forbiddenPlan expired, account switched off, or this feature is off for the restaurant
404not_foundNo such endpoint, dish or order (in this restaurant)
405method_not_allowedThe path exists, but not with this method
422invalid_requestThe values were refused, e.g. a negative price or a move the order can't make
429rate_limitedToo many calls: wait for Retry-After seconds
500 / 503server_error, unavailableOur 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 } ] } }

GET/menu menu:read

Dishes with id, section, type, price, sizes and whether they are switched on.

QueryType
searchstringPart of a dish name
sectionstringMenu section, e.g. Starters
only_switched_offbooleantrue = only dishes that are off
limit1–300Default 100
curl "https://restrogrow.com/api/v1/menu?search=paneer" -H "Authorization: Bearer rg_live_YOUR_KEY"
{ "success": true, "data": { "currency": "₹", "dishes": [
  { "item_id": 1289, "name": "Paneer Tikka", "section": "Starters", "type": "Veg", "price": 249.0, "sizes": [], "switched_on": true },
  { "item_id": 1291, "name": "Chilli Paneer", "section": "Starters", "type": "Veg", "price": 239.0,
    "sizes": [ { "name": "Dry", "price": 239.0 }, { "name": "Gravy", "price": 259.0 } ], "switched_on": true } ] } }

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.

BodyType
name *string2–150 characters
price *number0 – 1,000,000
section *stringe.g. Beverages
typestringVeg (default), Non Veg, Egg, Drink, Dessert, Other
descriptionstringUp to 1000 characters
prep_minutes0–180Kitchen time
availablebooleanDefault 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.

BodyType
namestringUp to 150 characters
descriptionstringUp to 1000 characters
pricenumberDishes without sizes
typestringAs in POST /menu/items
sizesarray[{"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.

QueryType
periodstringDefault today
statusstringactive (Pending, Accepted, Preparing, Ready), or one of Pending, Accepted, Preparing, Ready, Served, Completed, Cancelled, Rejected
limit1–50Default 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.

BodyType
status *stringAccepted, Preparing, Ready, Served, Completed, Cancelled, Rejected
reasonstringNeeded for Cancelled / Rejected
prep_minutes1–300When 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_dishesBest and least sold dishes
dishHow much one dish sold (?dish=Paneer Tikka)
peak_hoursBusiest hours and day
payments / channelsCash, UPI, card split / counter vs website vs WhatsApp
customers / lapsedNew vs returning / regulars who stopped coming
cancellations, today_so_far, adviceCancelled 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.