# Zomato API — live Indian restaurant data scraper: search a city's restaurants by cuisine, locality or collection, and get the full record with address, coordinates, opening hours, cost-for-two, the dish catalogue and review text — with Zomato's dining and delivery star ratings returned as SEPARATE fields, never blended

> List a city's restaurants, optionally narrowed to one cuisine, locality or curated collection, or to the restaurants that deliver. Returns up to 9 rows — that is the source's own ceiling per listing and it does not page, so breadth comes from varying city/cuisine/locality/collection rather than from a page number. Every row carries `is_promoted`, because on a plain city listing all 9 rows are paid placements.
> ReefAPI engine `zomato` · 5 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/zomato/v1/<action>` with a JSON body.
- **Auth:** header `x-api-key: <YOUR_REEFAPI_KEY>` — create one free (1,000 credits, no card): https://reefapi.com/signup
- **Response (every call):** `{ ok: boolean, data: ..., meta: { record_count, credits, ... }, error: { code, message } }` — branch on `ok`. Failed calls are free except verified SHEIN NOT_FOUND on product/detail and price (4 credits).
- **One key + one shared credit pool** across every ReefAPI API. Per-call credits are listed on each endpoint below.
- **Use it from an AI agent (MCP):** connect `https://api.reefapi.com/mcp` (remote streamable-http, `Authorization: Bearer <key>`) and your assistant can call these actions directly.

## Endpoints

### POST /zomato/v1/search — 2 credits
List a city's restaurants, optionally narrowed to one cuisine, locality or curated collection, or to the restaurants that deliver. Returns up to 9 rows — that is the source's own ceiling per listing and it does not page, so breadth comes from varying city/cuisine/locality/collection rather than from a page number. Every row carries `is_promoted`, because on a plain city listing all 9 rows are paid placements.

**Parameters:**
- `city` (string, required) — The Zomato city slug, as it appears in the site's own URLs: 'ncr' (Delhi NCR), 'mumbai', 'bangalore', 'hyderabad', 'chennai', 'kolkata', 'pune', 'jaipur'. Inventory is strictly per city — eight cities measured shared zero restaurants with each other.
- `cuisine` (string, optional) — Narrow the city to one cuisine, using Zomato's own cuisine slug. Measured to bite: Delhi NCR 25,603 listed → 12,847 north-indian, 9,994 chinese, 4,379 pizza, and every returned row really carried that cuisine (9/9 on each). Common slugs: north-indian, south-indian, chinese, pizza, burger, biryani, desserts, cafe, fast-food, italian, continental, mughlai.
- `locality` (string, optional) — Narrow the city to one neighbourhood, using Zomato's locality slug ('saket', 'connaught-place-delhi', 'koramangala'). This changes which restaurants come back (measured: 9 of 9 rows different, and the rows really sat in that area) but the source's own `source_total_results` counter does NOT move for it and stays city-wide.
- `collection` (string, optional) — One of Zomato's curated city collections ('best-cafes', 'breakfast', 'insta-worthy'). These are the cleanest rows on the site: /ncr/best-cafes returned 0 paid placements out of 9, where the plain city listing returned 9 out of 9.
- `mode` (enum, optional, default "dining") — Which side of Zomato to list. 'delivery' genuinely narrows the city (Delhi NCR 25,603 → 2,107 and every row different). 'dining' is the site's default view — it is accepted for clarity but does not narrow anything, which is why it is the default. [one of: dining, delivery]

**Returns:** restaurants[]{res_id, name, url, slug, rating_dining, rating_dining_count, rating_delivery, rating_delivery_count, price_for_two_text, price_for_two_inr, price_for_one_text, locality, address, cuisines[], distance, timing, image, is_promoted, is_disabled, rating_count_approximate}, count, promoted_count, organic_count, dropped_tiles, source_total_results, city, listing_url, stop_reason

**Example request body:**
```json
{
  "city": "ncr"
}
```

### POST /zomato/v1/restaurant/detail — 2 credits
One full restaurant record by id: address and coordinates, city and postcode, the business phone numbers the page prints, cuisines, opening hours per day, cost-for-two, popular dishes, facility highlights, and the dining and delivery ratings as separate named fields.

**Parameters:**
- `res_id` (string, required) — The numeric Zomato restaurant id, as `search` returns it in `res_id`. A zomato.com URL containing the id is also accepted.

**Returns:** restaurant{res_id, name, url, rating_dining, rating_dining_count, rating_delivery, rating_delivery_count, rating_count_approximate, price_for_two_text, price_for_two_inr, cost_notes[], cuisines[], address, locality, city, zipcode, latitude, longitude, phone, phones[], status_text, is_open_now, timing_text, opening_hours[], is_delivery_only, is_permanently_closed, is_temporarily_closed, highlights[], popular_dishes, known_for, payment_accepted, image_menus[], chain_url}

**Example request body:**
```json
{
  "res_id": 311057
}
```

### POST /zomato/v1/restaurant/menu — 3 credits
The restaurant's dish catalogue: every menu, its categories and the dishes in them with name, description and veg/vegan tags. 🔴 Dish PRICES are not returned, because Zomato does not publish them to a logged-out reader — the page sets its own `price_login_blocker` flag and the dish records carry no price key at all (verified from four different exits, including one inside India). `price_inr` is therefore null on every dish and `prices_published` is false, rather than a guessed number.

**Parameters:**
- `res_id` (string, required) — The numeric Zomato restaurant id, as `search` returns it in `res_id`. A zomato.com URL containing the id is also accepted.

**Returns:** categories[]{menu, category, items[]{item_id, name, description, price_inr, is_veg, is_vegan, dietary_tags[], is_delivery_enabled, image}}, item_count, menu_count, prices_published, priced_item_count, price_note, res_id

**Example request body:**
```json
{
  "res_id": 311057
}
```

### POST /zomato/v1/restaurant/reviews — 3 credits
Review text for one restaurant, newest first, 5 per page. Returns at most 25 reviews: page 6 is where Zomato answers 'Please login', measured identically on three restaurants. Each review carries its text, star rating, age, like and comment counts, and the reviewer name and profile link exactly as the public page prints them.

**Parameters:**
- `res_id` (string, required) — The numeric Zomato restaurant id, as `search` returns it in `res_id`. A zomato.com URL containing the id is also accepted.
- `max_pages` (integer, optional, default 5) — How many review pages to walk, 5 reviews each. Capped at 5 because page 6 is where Zomato returns 'Please login' — measured identically on three restaurants, so 25 reviews is the logged-out ceiling.

**Returns:** reviews[]{review_id, text, rating, timestamp, like_count, comment_count, photo_count, review_url, user_name, user_profile_url, user_id, user_review_count, user_follower_count, rating_type, rating_label, tags[]}, count, pages_fetched, reviews_truncated, source_number_of_pages, stop_reason, res_id

**Example request body:**
```json
{
  "res_id": 311057,
  "max_pages": 2
}
```

### POST /zomato/v1/locations/search — 1 credit
Turn a place name into the localities Zomato knows, with coordinates — the lookup that tells you what to pass as `locality`.

**Parameters:**
- `query` (string, required) — A place name to resolve — a neighbourhood, a landmark or a city.

**Returns:** locations[]{title, subtitle, name, entity_id, entity_type, location_type, latitude, longitude}, count

## More
- Try it live, no code: https://reefapi.com/playground?engine=zomato
- Human docs page: https://reefapi.com/docs/zomato
- Overview page: https://reefapi.com/zomato-api
- Every ReefAPI API in one file (for your AI): https://reefapi.com/llms-full.txt
