# NYC Restaurant Inspection Results Scraper (`knotty_mistveil/nyc-restaurant-inspection-results`) Actor

Restaurant inspection violations in New York City from NYC Open Data (DOHMH): name, address, violation, grade and inspection date, filtered by date and borough.

- **URL**: https://apify.com/knotty_mistveil/nyc-restaurant-inspection-results.md
- **Developed by:** [Jason](https://apify.com/knotty_mistveil) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 1,000 inspection row returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## NYC Restaurant Inspection Results Scraper

Pulls New York City's restaurant health inspection results **as the city publishes them**, straight from **NYC Open Data** (DOHMH, the Department of Health and Mental Hygiene) through its public Socrata SODA API. No API key, no login, no browser automation. **One flat JSON record per violation row** — the dataset's own grain, not per restaurant and not per inspection (see [What you get](#what-you-get) for exactly what that means and why it matters for counting). Filter by inspection-date window, borough, restaurant-name/cuisine keyword, letter grade and whether the violation is flagged critical. Citywide volume runs **roughly 300–600 violation rows per weekday** (measured 21–25 September 2026) and is close to zero on weekends — see [Limits and freshness](#limits-and-freshness) before sizing `maxItems`.

### What you get

**Row grain, read this first.** The source dataset is "every sustained or not-yet-adjudicated violation citation from every inspection," not one row per restaurant or one row per inspection:

- A single inspection that cites, say, five violations produces **five rows**, one per `violationCode`, all sharing the same restaurant, date and inspection type.
- An inspection that finds **no violations** produces **one row** with `violationCode: null` and `action` reading *"No violations were recorded at the time of this inspection."*
- A restaurant that has applied for a permit but **has not yet been inspected** gets **one placeholder row** with `inspectionDate: "1900-01-01"` (the source's own placeholder) and every inspection/violation field `null`.
- Measured on a full working week (21–25 September 2026, 2,332 rows): **696 distinct inspections** from **646 distinct restaurants**, averaging **3.35 violation rows per inspection** (median 3, max 13 in that week). **Do not report row counts as restaurant counts or inspection counts** — divide by `camis` or by `inspectionDate`+`inspectionType` first.

| Field | Description |
| --- | --- |
| `id` | `<camis>:<inspectionDate>:<inspectionType-slug>:<violationCode>`, e.g. `40546082:2023-08-15:Cycle-Inspection-Initial-Inspection:02B`. The dataset has no single-column primary key for a violation row. CAMIS + date + violation code alone is *usually* unique but measurably is not always: a live sample (488 rows, one day, one restaurant) showed 4 collisions where the same restaurant had both an Initial and a Re-inspection on the same calendar date citing the same code. Adding inspection type removed every observed collision. The Actor also de-duplicates defensively at run time and reports any further collision as `filteredOut.duplicate` in `SUMMARY`. |
| `source` | Always `nyc-restaurant-inspections`. |
| `url` | A Socrata data-explorer link pre-filtered to this exact CAMIS + inspection date + inspection type + violation code. **This dataset has no public per-row permalink of its own** (no restaurant detail page, no inspection id in a URL) — this is the closest public link to the one row; for the "not yet inspected" placeholder row it links to the restaurant's CAMIS alone. |
| `camis` | NYC's own unique restaurant/establishment id, stable across every inspection of that restaurant. |
| `dba` | The restaurant's "doing business as" name, as filed. |
| `cuisineDescription` | The source's own cuisine category (`Pizza`, `Coffee/Tea`, `Hamburgers`, …). Not published on the not-yet-inspected placeholder row. |
| `borough`, `building`, `street`, `address`, `zipcode` | Location. `address` joins `building` + `street` with the borough and ZIP. The source's own `boro` value `"0"` (not geocoded to a borough) is reported as `borough: null`, not the literal string `"0"`. |
| `phone` | The restaurant's phone number on file, digits only, as published. |
| `latitude`, `longitude` | Property coordinates where geocoded. |
| `inspectionDate` | ISO `YYYY-MM-DD`. **This, not `recordDate`, is the freshness field this Actor filters on** — see the box below. |
| `pendingFirstInspection` | `true` only for the `1900-01-01` placeholder row described above. |
| `inspectionType` | The inspection cycle and stage, e.g. `Cycle Inspection / Initial Inspection`, `Cycle Inspection / Re-inspection`, `Pre-permit (Operational) / Initial Inspection`. |
| `action` | The source's own one-line outcome of the inspection (violations cited, none recorded, establishment closed/re-opened/re-closed). |
| `hasViolation` | `true` when `violationCode` is set; a convenience flag equivalent to `violationCode !== null`. |
| `violationCode`, `violationDescription` | The cited code and its text, e.g. `02B` / "Hot TCS food item not held at or above 140 °F." `null` on a no-violation or not-yet-inspected row. |
| `criticalFlag` | `Critical`, `Not Critical` or `Not Applicable` (no violation on this row). These are the three values the live API returns (verified 2026-10-05); there is no "Critical Violation" synonym. |
| `score` | The inspection's numeric point score (lower is better); repeated on every violation row of the same inspection. |
| `grade` | One of `A`, `B`, `C`, `N` (Not Yet Graded), `P` (Grade Pending, issued on reopening), `Z` (Grade Pending), or `null`. **About half of all rows carry no grade at all** (51% in the dataset total, measured 2026-10-05) — many inspection types (Smoke-Free Air Act, Trans Fat, Calorie Posting, Administrative Miscellaneous, …) do not produce a letter grade. |
| `gradeDate` | ISO date the grade was assigned; `null` alongside `grade: null`. |
| `recordDate` | Full ISO timestamp of the nightly batch that last pulled this row into the published dataset — **not** when the inspection happened. See the box below; it is informational only, not filterable by this Actor. |
| `extra` | `communityBoard`, `councilDistrict`, `censusTract`, `bin`, `bbl`, `nta` (Neighborhood Tabulation Area), plus any column NYC adds later that this Actor has not mapped by hand. |
| `fetchedAt` | ISO timestamp of the run that produced the record. |

**Why `inspectionDate`, not `recordDate`, is the freshness filter.** `recordDate` is the timestamp of NYC's nightly data-pull batch, not the inspection date: querying the live API (2026-10-05) showed `recordDate` clustered within seconds of the batch run **for every row regardless of age** — a 2017 inspection and a 2026 inspection pulled in the same nightly batch both carry essentially the same `recordDate`. It tells you when the *extract* was refreshed, not which rows are new. `inspectionDate` is the actual event date and is what every input filter in this Actor (`daysBack`, `dateFrom`/`dateTo`) is applied to.

### Input

| Input | Type | Default | Description |
| --- | --- | --- | --- |
| `daysBack` | integer | `7` | Look-back window on `inspectionDate`, counted back from the run. Ignored when `dateFrom`/`dateTo` are set. |
| `dateFrom` | string | – | Earliest inspection date, `YYYY-MM-DD`, inclusive. Overrides `daysBack`. |
| `dateTo` | string | today | Latest inspection date, `YYYY-MM-DD`, inclusive. |
| `boroughs` | string\[] | all | `Manhattan`, `Brooklyn`, `Queens`, `Bronx`, `Staten Island`. Empty keeps every borough, including the small number of rows the source could not geocode to one. |
| `keywords` | string\[] | none | Case-insensitive substrings OR-matched against `dba` and `cuisineDescription`. |
| `grades` | string\[] | all | `A`, `B`, `C`, `N`, `P`, `Z`. Setting this excludes every ungraded row (about half of the total), since a `null` grade never matches a non-empty filter. |
| `onlyCritical` | boolean | `false` | Keep only rows whose `criticalFlag` is `Critical`. Also excludes every no-violation row. |
| `socrataAppToken` | string (secret) | – | Optional free Socrata app token, sent as `X-App-Token`. Not required; it only lifts the shared per-IP throttle. Register at <https://evergreen.data.socrata.com/profile/app_tokens>. |
| `maxItems` | integer | `500` | Stop after this many rows. You are charged per row delivered, so this is also the cost cap. Rows come newest-first by inspection date, so a value below the window's volume drops the **oldest** rows. Citywide volume is roughly 300–600 rows/weekday (measured 21–25 September 2026) and near zero on weekends, so a gap-free 7-day window needs about 3,000. |

Every default is chosen so "Try it" with zero edits returns a small, fast, cheap result: the last 7 days, every borough, 500-row cap.

New critical violations in Brooklyn and Queens this week:

```json
{ "daysBack": 7, "boroughs": ["Brooklyn", "Queens"], "onlyCritical": true, "maxItems": 500 }
```

C grades and below, citywide, for a compliance watch-list:

```json
{ "daysBack": 30, "grades": ["C"], "maxItems": 2000 }
```

An unknown borough, an unknown grade, a malformed date or a reversed date range fails fast: the run stops with the validation message as its status before a single request is made. A keyword that matches nothing returns zero rows and charges nothing.

### Output example

A real record from a live run on 2026-10-05 (`daysBack: 10`, no other filters):

```json
{
  "id": "50122004:2026-10-01:Cycle-Inspection-Reopening-Inspection:10F",
  "source": "nyc-restaurant-inspections",
  "url": "https://data.cityofnewyork.us/d/43nn-pn8j/explore/query/SELECT%20*%20WHERE%20camis%20%3D%20'50122004'%20AND%20inspection_date%20%3D%20'2026-10-01T00%3A00%3A00.000'%20AND%20inspection_type%20%3D%20'Cycle%20Inspection%20%2F%20Reopening%20Inspection'%20AND%20violation_code%20%3D%20'10F'/page/filter",
  "camis": "50122004",
  "dba": "EL PERRO",
  "cuisineDescription": "Latin American",
  "borough": "Queens",
  "building": "80-26",
  "street": "NORTHERN BLVD",
  "address": "80-26 NORTHERN BLVD, Queens, NY 11372",
  "zipcode": "11372",
  "phone": "7184240763",
  "latitude": 40.755380766968,
  "longitude": -73.886911697316,
  "inspectionDate": "2026-10-01",
  "pendingFirstInspection": false,
  "inspectionType": "Cycle Inspection / Reopening Inspection",
  "action": "Establishment re-opened by DOHMH.",
  "hasViolation": true,
  "violationCode": "10F",
  "violationDescription": "Non-food contact surface or equipment made of unacceptable material, not kept clean, or not properly sealed, raised, spaced or movable to allow accessibility for cleaning on all sides, above and underneath the unit.",
  "criticalFlag": "Not Critical",
  "score": 2,
  "grade": "Z",
  "gradeDate": "2026-10-01",
  "recordDate": "2026-10-02T06:00:16.000Z",
  "extra": {
    "communityBoard": "403",
    "councilDistrict": "25",
    "censusTract": "028500",
    "bin": "4028773",
    "bbl": "4012530001",
    "nta": "QN28"
  },
  "fetchedAt": "2026-10-05T02:57:01.814Z"
}
```

A not-yet-inspected restaurant looks like this (fields the source never publishes for it simply stay `null`):

```json
{
  "id": "50180010:1900-01-01:noinspection:noviolation",
  "source": "nyc-restaurant-inspections",
  "camis": "50180010",
  "dba": "NEFIS LLC",
  "borough": "Manhattan",
  "address": "956 1 AVENUE, Manhattan, NY 10022",
  "inspectionDate": "1900-01-01",
  "pendingFirstInspection": true,
  "inspectionType": null,
  "violationCode": null,
  "hasViolation": false,
  "grade": null,
  "criticalFlag": "Not Applicable"
}
```

The run also writes a `SUMMARY` record to the key-value store with rows scanned and kept, the newest inspection date reached, how many rows each filter removed, and a `windowExhausted` completeness flag (`true` only when the whole date window was read, nothing on the last page was left unread, and every kept row was actually delivered).

### Pricing

Pay per result: **US$0.0015 per row delivered** (US$1.50 per 1,000 rows) — priced as a bulk government compliance register, in line with this repo's other bulk-register Actors (comparable to the FDIC and NZBN company registers). You are charged only for rows pushed to the dataset; a run that returns nothing costs nothing. A gap-free 7-day citywide pull (about 3,000 rows, see [Limits and freshness](#limits-and-freshness)) costs roughly US$4.50. Runs on the Apify free plan are limited by the platform's free-tier usage allowance.

### Data source and licence

**DOHMH New York City Restaurant Inspection Results**, NYC Department of Health and Mental Hygiene: `GET https://data.cityofnewyork.us/resource/43nn-pn8j.json`. Dataset page: <https://data.cityofnewyork.us/d/43nn-pn8j>. Read live on 2026-10-05.

This dataset's own Socrata metadata (`https://data.cityofnewyork.us/api/views/43nn-pn8j.json`, read 2026-10-05) carries **no separate `license` or `licenseId` field** (both are empty) and sets `attribution` to *"Department of Health and Mental Hygiene (DOHMH)"*. Like every dataset on the portal, it is still published under **NYC Open Data**, whose enabling law (New York City Local Law 11 of 2012, Admin. Code § 23-502(d)) requires city datasets to be available "without registration requirement, license requirement, or usage restrictions." Terms of use: <https://www.nyc.gov/home/terms-of-use.page>. Commercial reuse is permitted; the City warrants nothing about completeness or accuracy. Attribute to DOHMH via NYC Open Data.

Socrata app tokens — optional, free, and only relevant to rate limits: <https://dev.socrata.com/docs/app-tokens.html>.

#### Personal data

Every record in this feed is a **public health-inspection record about a business**, not about an individual. It carries a restaurant's trading name, address and phone number, and (per [What you get](#what-you-get)) the dataset publishes no individual owner or officer at all — just the establishment. That still does not make downstream use of the phone number automatic:

- `phone` is the restaurant's own published business line. If you use it for outbound sales or marketing calls, US telemarketing law still applies to the call itself: the **TCPA** (47 U.S.C. § 227) and FCC rules on autodialled/pre-recorded calls and texts, and the National Do Not Call Registry, regardless of whose name is on the account.
- Commercial email built from this data is covered by **CAN-SPAM** (15 U.S.C. § 7701 et seq.): accurate headers, a physical postal address, and a working opt-out honoured within ten business days.
- A poor inspection grade is a sensitive fact about a small business. Using this feed to contact a restaurant about its violations (pest control, compliance consulting, insurance) is a legitimate, common use of the data; publishing it as a standalone "worst restaurants" shaming list is a different use with its own reputational and legal exposure, and is **your** responsibility, not NYC's or this Actor's.
- `score` and `grade` are the city's official determination; this Actor does not reinterpret, rank or editorialise them.

### Limits and freshness

**Volumes, measured live.** The full dataset held **296,175 rows** on 2026-10-05 (`$select=count(*)`), going back to **2007-08-10** (excluding the `1900-01-01` not-yet-inspected placeholder rows, of which there were 3,865). A full working week, **21–25 September 2026, returned 2,332 rows**: 471, 523, 501, 608 and 229 rows Monday through Friday. The weekend of 20–21 September returned 12 rows total. The seven days ending 2026-10-05 (28 Sep – 1 Oct, the most recent inspections available at measurement time) returned **1,396 rows** over 4 active days. **Budget roughly 300–600 rows per weekday citywide and near-zero on weekends and public holidays.**

**Freshness and publication lag, measured 2026-10-05.** The newest `inspectionDate` available was **2026-10-01**, while the dataset's own metadata (`rowsUpdatedAt`) showed the last nightly refresh at **2026-10-02 06:00 UTC** — a lag of about **one business day** between an inspection happening and it appearing in the API, consistent with the metadata's own stated `Update Frequency: Daily`. The most recent day's row count is typically a small fraction of a full day's (1 row for 2026-10-01 at measurement time) because that day's inspections were still being entered when the nightly extract ran; the preceding days (09-28 through 09-30: 423, 484, 488 rows) are representative of a complete day. **A `daysBack` of 1 can legitimately return very few or zero rows** — that is the source's own entry lag, not a defect in the Actor.

**Row grain and double counting.** See [What you get](#what-you-get) above. Do not sum `score`, average `grade`, or count rows as restaurants/inspections without first grouping by `camis` (restaurants) or by `camis` + `inspectionDate` + `inspectionType` (inspections).

**Grade coverage, measured 2026-10-05 (dataset total, 296,175 rows).** `A` 97,941 (33%), `B` 18,067 (6%), `C` 12,982 (4%), `N` 10,079 (3%), `Z` 5,124 (2%), `P` 724 (0.2%), and **151,258 rows (51%) carry no grade at all** — the inspection types that never produce a letter grade (Smoke-Free Air Act, Trans Fat, Calorie Posting, Sodium Warning, most Administrative Miscellaneous inspections) make up a large share of all rows. Setting the `grades` filter necessarily excludes that 51%.

**Rate limits and paging.** The SODA API is read in pages of 1,000 rows ordered `inspection_date DESC, :id`, with a 400ms pause between pages and a ceiling of 500 pages (500,000 rows) per run. Without an app token Socrata throttles by shared IP pool and can answer `503`/`429`; `fetchWithRetry` backs off exponentially and honours `Retry-After`. A default 7-day run needs only one to a few requests, so the throttle is rarely reached in normal use; supply `socrataAppToken` if pulling months of history on a tight schedule.

**Duplicate rows.** CAMIS + inspection date + violation code alone is not always unique (see the `id` row in [What you get](#what-you-get)); adding inspection type removed every collision observed in live testing. The Actor still de-duplicates on the full `id` at run time, reporting the count as `filteredOut.duplicate` in `SUMMARY`.

**Scope.** This Actor reads restaurant and college-cafeteria inspections only — the one dataset DOHMH publishes under this id. It does not cover other NYC food-safety datasets (mobile food vendors, farmers markets) or other cities. Only establishments in an "active" status as of the source's own data pull are included, per the dataset's own description; a restaurant that has closed permanently eventually drops out of the feed entirely rather than appearing with a "closed" status.

### Use cases

- **Compliance and pest-control lead generation.** A daily feed of restaurants that just failed an inspection, by borough or cuisine, for pest control, cleaning, HACCP consulting or legal compliance outreach.
- **Food-safety and public-health research.** Track violation codes, critical-flag rates and grade distribution by borough, cuisine or time, using the full `extra` geography (community board, council district, census tract) for neighbourhood-level analysis.
- **Insurance and real-estate due diligence.** Attach a restaurant tenant's recent inspection and grade history (via `camis`) to an underwriting or leasing decision, or screen a commercial property's food-service tenants for compliance risk.

### Support

Open an issue on the Actor's Issues tab on Apify Store. Replies within 14 days. Bug reports that name the run id and the input used are fixed fastest.

# Actor input Schema

## `daysBack` (type: `integer`):

Look-back window on the INSPECTION date, counted back from the run. Because inspection dates are calendar dates, 7 means today plus the seven previous days. Ignored when Date from / Date to are set. The source publishes about 1 business day behind (measured 2026-10-05), so a 1-day window can occasionally return nothing.

## `dateFrom` (type: `string`):

Earliest inspection date, YYYY-MM-DD (inclusive). Overrides Days back.

## `dateTo` (type: `string`):

Latest inspection date, YYYY-MM-DD (inclusive). Defaults to the day the run starts.

## `boroughs` (type: `array`):

Keep only these NYC boroughs. Empty = every borough, including the small number of rows the source could not geocode to one (borough is null there). Case-sensitive, exact match.

## `keywords` (type: `array`):

Case-insensitive substrings matched against the restaurant name (dba) and cuisine description; a row is kept when any term matches. Examples: "pizza", "starbucks", "bakery". Empty = no keyword filter.

## `grades` (type: `array`):

Keep only rows whose inspection grade is one of these. A = A, B = B, C = C, N = Not Yet Graded, Z = Grade Pending, P = Grade Pending (issued on reopening). About half of all rows carry no grade at all (the inspection type does not produce one); those are excluded whenever this filter is non-empty. Empty = every grade, including ungraded rows.

## `onlyCritical` (type: `boolean`):

Keep only rows whose violation is flagged Critical (a violation type the NYC Health Code treats as more likely to contribute to foodborne illness). Rows with no violation at all (critical_flag = "Not Applicable") are excluded when this is on.

## `socrataAppToken` (type: `string`):

Optional free Socrata application token, sent as the X-App-Token header. Not required: the Actor works without one. A token lifts the shared per-IP throttle, which matters only for very large windows. Register at https://evergreen.data.socrata.com/profile/app_tokens.

## `maxItems` (type: `integer`):

Stop after this many rows. You are charged per row delivered, so this is also the cost cap. Rows come newest-first by inspection date, so a value below the window's volume drops the OLDEST rows. The source produces roughly 300-600 violation rows per weekday citywide (measured 2026-09-21..25) and almost none on weekends, so a gap-free 7-day window needs about 3000.

## Actor input object example

```json
{
  "daysBack": 7,
  "boroughs": [],
  "keywords": [],
  "grades": [],
  "onlyCritical": false,
  "maxItems": 500
}
```

# Actor output Schema

## `results` (type: `string`):

All inspection violation rows returned by the run, one JSON object each. Append ?format=csv or ?format=xlsx to download a spreadsheet.

## `summary` (type: `string`):

Rows scanned and kept, the newest inspection date reached, the resolved date window, and how many rows each filter removed, written at the end of the run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "daysBack": 7,
    "boroughs": [],
    "keywords": [],
    "grades": [],
    "maxItems": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("knotty_mistveil/nyc-restaurant-inspection-results").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "daysBack": 7,
    "boroughs": [],
    "keywords": [],
    "grades": [],
    "maxItems": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("knotty_mistveil/nyc-restaurant-inspection-results").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "daysBack": 7,
  "boroughs": [],
  "keywords": [],
  "grades": [],
  "maxItems": 500
}' |
apify call knotty_mistveil/nyc-restaurant-inspection-results --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,knotty_mistveil/nyc-restaurant-inspection-results"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/fXCI63axFUXVrMcRP/builds/dkbKfd2i8IF2azyGW/openapi.json
