{
  "openapi": "3.0.1",
  "info": {
    "title": "OpenTable Restaurant Scraper – Reviews, Ratings & Phone Numbers",
    "description": "Scrape OpenTable restaurants in any city, by area, address or lat-lng, with an optional cuisine keyword. Each row: name, profile URL, cuisines, price band, rating, review count, neighbourhood, address, coordinates. Opt in for phone, website, hours, menu, popular dishes and diner reviews.",
    "version": "0.0",
    "x-build-id": "Qd21OCEUYAs6Z6W2v"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/rl1987~opentable-api-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-rl1987-opentable-api-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/rl1987~opentable-api-scraper/runs": {
      "post": {
        "operationId": "runs-sync-rl1987-opentable-api-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/rl1987~opentable-api-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-rl1987-opentable-api-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "mode": {
            "title": "What this run does",
            "enum": [
              "search",
              "restaurants",
              "menus",
              "reviews",
              "availability"
            ],
            "type": "string",
            "description": "Start with <b>Search</b> to find restaurants by area. The other four modes each fetch <i>one</i> kind of data for a list of restaurants you supply below — so a scheduled run tracking menu changes doesn't pay for reviews it didn't ask for. In Search mode the <b>Include…</b> toggles add the same data per restaurant.",
            "default": "search"
          },
          "location": {
            "title": "Location",
            "type": "string",
            "description": "City, area, or address to search around (e.g. \"New York, NY\", \"San Francisco\"). Resolved to coordinates at run time."
          },
          "lat": {
            "title": "Latitude (advanced)",
            "type": "number",
            "description": "Optional latitude override; skips the location lookup."
          },
          "lon": {
            "title": "Longitude (advanced)",
            "type": "number",
            "description": "Optional longitude override; skips the location lookup."
          },
          "q": {
            "title": "Search term",
            "type": "string",
            "description": "Optional cuisine or keyword (e.g. \"sushi\", \"Indian\")."
          },
          "includeDetails": {
            "title": "Include restaurant details (phone, hours, website)",
            "type": "boolean",
            "description": "Fetch each restaurant's full profile: <b>phone number</b>, website, opening hours, dining style, dress code, parking, payment options, menu link and popular dishes. One extra request per restaurant, billed as a separate detail-row event. <b>Requires a US proxy</b> — this route is geo-gated and simply hangs from non-US IPs.",
            "default": false
          },
          "includeMenu": {
            "title": "Include full menu",
            "type": "boolean",
            "description": "Fetch the complete OpenTable-hosted menu for each restaurant - every menu, section, item, description, price and size variation. Adds one API call per restaurant. <b>Separate from <code>menuUrl</code></b>, which is the menu on the restaurant's own website: that field comes from the profile, so it needs <b>includeDetails</b>. A restaurant can have either source, both or neither, so enable both options to capture both.",
            "default": false
          },
          "includeReviews": {
            "title": "Include diner reviews",
            "type": "boolean",
            "description": "Fetch diner reviews per restaurant — text, author, dates and the per-category ratings (food, service, ambience, value, noise). Billed as a separate reviews-row event.",
            "default": false
          },
          "includeAvailability": {
            "title": "Include reservation availability",
            "type": "boolean",
            "description": "Fetch bookable reservation slots per restaurant for the <b>date</b>, <b>time</b> and <b>party size</b> below: slot times, seating type, dining area, loyalty points, and whether a credit card is required (hold vs deposit). Adds one API call per restaurant. <b>Needs a US proxy</b> — like the property profile route, this one hangs from non-US IPs rather than returning an error.",
            "default": false
          },
          "sort": {
            "title": "Sort order",
            "enum": [
              "",
              "best",
              "rating",
              "distance",
              "newestArrivals"
            ],
            "type": "string",
            "description": "Order of the search results. The full set from the app's own SortType enum; all four verified to change the ordering.",
            "default": ""
          },
          "cuisines": {
            "title": "Cuisines",
            "type": "array",
            "description": "Filter by cuisine, applied by OpenTable rather than after the fact, so you do not pay for rows you did not want. Use display names (<code>Italian</code>, <code>Steakhouse</code>, <code>Seafood</code>) and they are resolved to OpenTable's ids automatically; raw cuisine UUIDs also work. A name not offered for your search area is reported and ignored.",
            "items": {
              "type": "string"
            }
          },
          "neighborhoods": {
            "title": "Neighbourhoods",
            "type": "array",
            "description": "Filter by neighbourhood, e.g. <code>Chelsea</code>, <code>Astoria</code>. Names are resolved to OpenTable's ids (<code>n_hood:195</code>, <code>c_hood:292</code>), which you may also pass directly.",
            "items": {
              "type": "string"
            }
          },
          "priceBands": {
            "title": "Price bands",
            "type": "array",
            "description": "OpenTable price bands. Verified values and their labels: <code>2</code> = $30 and under, <code>3</code> = $31 to $50, <code>4</code> = $50 and over. (<code>1</code> returns nothing - the app's own PriceBand enum only has 2, 3 and 4.) On a 637-match New York search these left 260, 244 and 133 respectively.",
            "items": {
              "type": "string"
            }
          },
          "awardTags": {
            "title": "Award tags",
            "type": "array",
            "description": "Filter to award holders, e.g. <code>MICHELIN</code>, <code>MICHELIN;1 Star</code>, or a year like <code>2025</code>. The exact values available are listed in each search response's own facets.",
            "items": {
              "type": "string"
            }
          },
          "contextualPrompts": {
            "title": "Occasion / vibe prompts",
            "type": "array",
            "description": "OpenTable's own occasion prompts, e.g. <code>ROMANTIC</code>, <code>BRUNCH</code>, <code>FUN</code>, <code>PIZZA</code>.",
            "items": {
              "type": "string"
            }
          },
          "wheelchairAccessible": {
            "title": "Wheelchair accessible only",
            "type": "boolean",
            "description": "Only restaurants OpenTable flags as wheelchair accessible.",
            "default": false
          },
          "searchRadiusMiles": {
            "title": "Search radius (miles)",
            "minimum": 1,
            "type": "integer",
            "description": "Radius around the search location, in miles. OpenTable's own app offers 2, 10, 25 and 50. <b>This widens as well as narrows:</b> in a dense city the default radius is tighter than 2 miles, so a New York search went from 637 matches to 985 at a 2-mile radius and down to 63 at half a mile. Leave empty for OpenTable's default. <b>Ignored when a search term (<code>q</code>) is set</b> - a term search runs nationwide, which is OpenTable's behaviour."
          },
          "restaurantUrls": {
            "title": "Restaurant URLs or IDs",
            "type": "array",
            "description": "Scrape these restaurants directly instead of searching. Accepts a bare numeric ID (<code>42265</code>), a profile URL (<code>https://www.opentable.com/restaurant/profile/42265</code>) and any ordinary opentable.com restaurant URL (<code>https://www.opentable.com/del-friscos-double-eagle-steak-house-new-york-city</code>) - slug URLs are resolved automatically. Matching is exact, so a stale or truncated slug is skipped with a message rather than guessed at. When set, <b>location</b>/<b>q</b> are ignored.",
            "items": {
              "type": "string"
            }
          },
          "restaurantNames": {
            "title": "Restaurants by name and city",
            "type": "array",
            "description": "Resolve restaurants by name instead of URL, one per line as <code>Name, City</code> — e.g. <code>Brooklyn Chop House Times Square, New York</code>. Resolution is a name match within that city: <b>an ambiguous name is reported with the near-misses rather than guessed</b>, so two restaurants of the same name in one city will not resolve — pass the ID or profile URL for those. Costs two requests per entry.",
            "items": {
              "type": "string"
            }
          },
          "reviewsPerRestaurant": {
            "title": "Reviews per restaurant",
            "type": "integer",
            "description": "How many reviews to fetch for each restaurant (paged automatically). Only used when reviews are enabled.",
            "default": 20
          },
          "reviewsSort": {
            "title": "Review sort order",
            "enum": [
              "newestReview",
              "highestRating",
              "lowestRating",
              "recommended"
            ],
            "type": "string",
            "description": "Which reviews come first.",
            "default": "newestReview"
          },
          "date": {
            "title": "Reservation date",
            "type": "string",
            "description": "Date to check availability for, <code>YYYY-MM-DD</code>. Defaults to tomorrow. Each restaurant has its own booking horizon (<code>maxDaysInAdvance</code>; 90 and 365 days on two live samples) — beyond it you get no slots and <code>noTimesReasons: [\"TooFarInAdvance\"]</code> rather than a silent empty list."
          },
          "daysAhead": {
            "title": "Days ahead",
            "minimum": 0,
            "type": "integer",
            "description": "Check availability this many days from the day the run starts - <code>0</code> today, <code>1</code> tomorrow, <code>7</code> a week out. Use this instead of <b>date</b> for scheduled monitoring: a relative target stays correct every run, where a fixed date goes stale. Setting both <b>date</b> and <b>daysAhead</b> is rejected. Past a restaurant's own booking horizon you get <code>noTimesReasons: [\"TooFarInAdvance\"]</code> rather than a silent empty list."
          },
          "time": {
            "title": "Reservation time",
            "type": "string",
            "description": "Time of day, <code>HH:MM</code> (24-hour). Defaults to <code>19:00</code>.",
            "default": "19:00"
          },
          "partySize": {
            "title": "Party size",
            "minimum": 1,
            "type": "integer",
            "description": "Number of diners. Defaults to 2. Above a restaurant's <code>maxPartySize</code> you get no slots and <code>noTimesReasons: [\"AboveMaxPartySize\"]</code>.",
            "default": 2
          },
          "maxItems": {
            "title": "Max items",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum number of restaurants to return (0 = all pages).",
            "default": 100
          },
          "detailConcurrency": {
            "title": "Detail fetch concurrency",
            "type": "integer",
            "description": "How many restaurants to enrich in parallel (1-20). Raise for speed, lower to be gentler on the API and your proxy.",
            "default": 8
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Route requests through Apify Proxy. Defaults to <b>RESIDENTIAL, country US</b>, which is what the restaurant-details option needs: that route is geo-gated and hangs (rather than erroring) from non-US IPs — measured 5/5 phone numbers in 24s on residential US vs 3/5 in 133s on datacenter. Search and reviews are not gated, so for a search-only run you can switch to datacenter to go faster and spare your residential GB quota.",
            "default": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ],
              "apifyProxyCountry": "US"
            }
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}