# UK FSA First-Seen Food Business Leads (`afkdigital/newapi20-uk-food-business-first-seen`) Actor

Find current UK FSA FHRS food businesses and detect FHRS IDs first observed after an honest baseline. Official API v2, local authority and rating filters; no false claims of newly opened companies.

- **URL**: https://apify.com/afkdigital/newapi20-uk-food-business-first-seen.md
- **Developed by:** [AFK Digital](https://apify.com/afkdigital) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.50 / 1,000 unique fsa food business results

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

## UK FSA Newly Observed Food Business Leads

**Actor:** NEWAPI20 / newapi20-uk-food-business-first-seen\
**Version:** 1.0.0 (Apify source version 1.0)\
**Source:** Official UK Food Standards Agency Food Hygiene Rating Scheme (FHRS) API v2

Find current food business records in a UK local authority, or monitor for **FHRS IDs first observed by this Actor after its initial complete baseline scan**. Source records cover participating FHRS/FHIS local authorities in England, Wales, Northern Ireland and Scotland.

> **Important:** "First seen" is the UTC time **this Actor's persistent state first observed the FHRS ID**. It is NOT the date a business started trading, opened, registered, incorporated, entered the FSA database, obtained an inspection, or received its first rating. The initial snapshot is **not** a collection of new businesses.

### How to use

1. Choose a local authority ID from https://api.ratings.food.gov.uk/Authorities/basic (request header: x-api-version: 2). Example: **277 = Adur**.
2. Select **current** to list the presently published businesses, filtered as needed. The Actor always scans the entire authority first to maintain an accurate full-ID baseline.
3. Select **first_seen** to monitor newly observed FHRS IDs. On the **very first successful complete scan** of a given authority, it creates a persistent baseline and emits **zero** paid first-seen records.
4. Run the same authority again at a later time. Only previously unseen FHRS IDs identified in a successful complete later snapshot are queued as potential first-seen leads. If nothing is new, the Dataset is empty and **no results are charged**.
5. Export the default Dataset as JSON or CSV from Apify. The default Key-Value Store contains RUN_SUMMARY and the separate named Key-Value Store holds persistent monitoring state.

#### Example: current records (fast default, typically under five minutes)

{
"localAuthorityId": 277,
"mode": "current",
"maxResults": 20,
"maxCostUsd": 0.09,
"ratingValues": \[]
}

#### Example: first seen only

{
"localAuthorityId": 277,
"mode": "first_seen",
"maxResults": 100,
"maxCostUsd": 0.45,
"businessTypeId": 1,
"ratingValues": \["5", "4"]
}

### Inputs

| Input | Description |
| --- | --- |
| localAuthorityId | Official FSA local authority ID; required, example Adur 277 |
| businessTypeId | Optional numeric ID from official /BusinessTypes lookup; 1 = Restaurant/Cafe/Canteen |
| businessType | Optional exact official business type name; validated against /BusinessTypes; if ID is also set they must agree |
| ratingValues | Optional list of rating/status values from official /Ratings lookup: e.g. 0–5, Pass, Improvement Required, Awaiting Inspection, Exempt |
| mode | current (current matching records) or first_seen (post-baseline unseen identities only) |
| maxResults | Maximum unique FHRS IDs emitted in this run; NOT a truncated baseline |
| maxCostUsd | Limit on result event spending in USD. 0 makes this an observation-only scan. The Actor also respects Apify's run-level charge limit |

**Defaults:** Adur 277, current, 20 results, $0.09 cap, all ratings/types.

### Output: Default Dataset, JSON / CSV

Each row contains exactly:

- fhrs_id (stable FSA identifier, used for deduplication)
- business_name
- business_type
- address_line
- postcode
- rating_value (text; e.g. "5", "Pass", "Awaiting Inspection")
- rating_date (FSA inspection/rating date; not opening date)
- local_authority_name
- first_seen_at (UTC first observation recorded in this Actor's named store)
- source_url (official FSA public business page)
- observed_at (UTC time of the completed scan)

The default KV RUN_SUMMARY includes first baseline time, authority name, scanned count, IDs seeded in the initial baseline, genuinely new identities detected **after** baseline, returned count, pending queue size, reappeared IDs, disappearance count and maximum event charges. Baseline-seeded IDs are never first-seen leads.

### Identity and persistence guarantees

- **Full-authority baseline:** All pages are fetched before first-seen comparisons. Filtering, maxResults, and cost caps are applied **after** the unfiltered full-ID scan.
- **No first-run false positives:** A first completed scan per local authority (in either mode) records the baseline but emits no "first seen" leads.
- **Persistent state:** Named Apify Key-Value Store `newapi20-fhrs-observations-v1`, key `STATE_V1`. Contains a global first-observation map keyed by FHRS ID plus per-authority baselineAt, last scan, active FHRS ID inventory, and pending first-seen IDs. **Do not delete or rename this store** or historical continuity will be lost.
- **Global ID reuse:** If the same FHRS ID appears in another monitored authority, its existing first_seen_at remains unchanged. A rating or address update for an existing ID is not a new business.
- **Disappear and reappear:** Disappearing IDs are removed only from the *active* list, not from the ever-observed global ID map. Reappearance cannot become a fresh first-seen lead.
- **Pending records:** If the max result count, cost ceiling or filter prevents emission, discovered first-seen IDs remain pending and are eligible for later runs once visible and matching. The original first_seen_at is preserved.
- **Incomplete scans:** If any page, timeout, throttling error, duplicate FHRS ID, or total-count mismatch prevents a complete scan, no snapshot state or partial results are committed. The error is reported and the next run can retry.
- **Same-store concurrency:** Avoid overlapping runs with the same named storage owner, since Apify Key-Value Store does not provide cross-run compare-and-swap transactions. Prefer scheduling one complete scan at a time per owner to avoid races.

**Definition caution:** A change in FHRS ID (e.g. an FSA re-keying or replacement) is a new *identity* to the Actor, not proof of a newly opened business. FSA delays, data corrections and non-continuous monitoring also prevent any guaranteed inference about when the real-world business appeared.

### Pricing: $0.0045 per distinct emitted Dataset item

**Configured Apify Store model: Pay per event (PPE)**, with exactly one configured synthetic event:

- `apify-default-dataset-item` — **$0.0045 / row**.
- **No Actor-start fee; no separate custom-result event** (to avoid double billing).
- **current:** One charge per distinct FHRS ID in the Dataset *in that run*, even if it was returned on an earlier run. 1,000 returned current records = **$4.50**.
- **first_seen:** One charge per distinct first-seen FHRS ID *actually emitted*, and only after baseline; 1,000 genuinely newly observed IDs emitted = **$4.50**. Initial baseline and zero-result repeat runs = **$0.00** for result events.
- `maxResults` and `maxCostUsd` provide strict Actor-side result ceilings (floor(maxCostUsd / $0.0045)), in addition to any Apify run maximum charge.
- Platform usage may be charged separately only if the published Actor's pricing explicitly opts into pay-per-event + usage; verify its visible pricing panel. This project is designed for plain PPE, with platform usage included in event revenue.

No event is charged for a request, an FSA record filtered out, a page scan, a rating change, or a baseline-only scan. There is no promise that the FSA supplies a "newly registered" date.

### FSA API source and reuse

Source: **Food Standards Agency, Food Hygiene Rating Scheme/Food Hygiene Information Scheme data**. Contains public sector information licensed under the **Open Government Licence v3.0**.

- API documentation: https://api.ratings.food.gov.uk/help
- FSA open-data catalogue and licence: https://data.food.gov.uk/catalog/datasets/38dd8d6a-5ab1-4f50-b753-ab33288e3200
- FSA terms: https://ratings.food.gov.uk/terms-and-conditions
- Official business page (record-specific): https://ratings.food.gov.uk/business/1746824
- Licencing details: https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/

Official FHRS API v2 requests include `x-api-version: 2` and `Accept: application/json`, use `Authorities/{id}`, `BusinessTypes`, `Ratings`, and paginated `Establishments?localAuthorityId=...&pageNumber=...&pageSize=1000`.

**No FSA logo, rating badges, rating images or other protected graphics are bundled or used as this Actor's branding.** The product is independent and **not endorsed by the FSA**. Ratings are subject to change; check the current official record and inspection date before relying on an item.

### Reliability and limits

Requests are sequential with short delays. Timeouts are 12 s per request and approximately 270 s per run. Throttling (403/429) and temporary server errors have bounded exponential backoff and optional Retry-After. Incomplete full scans fail closed. At most 50,000 records or 100 API pages per authority can be scanned per run; exceeding a safety limit fails rather than silently truncating the baseline. High-volume authorities may need more time and should be used cautiously to respect FSA rate limits.

**Runtime:** Node.js 22, Apify SDK 3, no proxy or API key. Test with `npm ci && npm test`; local run with `node src/main.js`. Use isolated Apify local storage for tests, never reset the production named store.

**Monitoring cadence:** Run at sensible intervals. Repeated back-to-back checks should normally show zero first-seen leads; they do not imply that no businesses have been created in the real world.

# Actor input Schema

## `localAuthorityId` (type: `integer`):

FSA LocalAuthorityId; default 277 (Adur). Browse IDs at the official FSA Authorities endpoint.

## `businessTypeId` (type: `integer`):

Optional FSA BusinessTypeId; use 1 for Restaurant/Cafe/Canteen. Leave blank for all.

## `businessType` (type: `string`):

Optional exact FSA business type name such as Restaurant/Cafe/Canteen. Cannot conflict with businessTypeId.

## `ratingValues` (type: `array`):

Optional FSA rating labels, such as 5, 4, Pass, Exempt, Awaiting Inspection or Improvement Required. Empty selects all.

## `mode` (type: `string`):

current = current matching records; first_seen = only new FHRS IDs detected after a full initial baseline.

## `maxResults` (type: `integer`):

Output ceiling; the first-seen baseline still scans all IDs in the authority.

## `maxCostUsd` (type: `number`):

Hard maximum of $0.0045 times records emitted. Does not cover external platform charges (if independently enabled). A $0 limit performs observation only.

## Actor input object example

```json
{
  "localAuthorityId": 277,
  "ratingValues": [],
  "mode": "current",
  "maxResults": 20,
  "maxCostUsd": 0.09
}
```

# Actor output Schema

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

No description

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

No description

# 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 = {
    "localAuthorityId": 277,
    "ratingValues": [],
    "mode": "current",
    "maxResults": 20,
    "maxCostUsd": 0.09
};

// Run the Actor and wait for it to finish
const run = await client.actor("afkdigital/newapi20-uk-food-business-first-seen").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 = {
    "localAuthorityId": 277,
    "ratingValues": [],
    "mode": "current",
    "maxResults": 20,
    "maxCostUsd": 0.09,
}

# Run the Actor and wait for it to finish
run = client.actor("afkdigital/newapi20-uk-food-business-first-seen").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 '{
  "localAuthorityId": 277,
  "ratingValues": [],
  "mode": "current",
  "maxResults": 20,
  "maxCostUsd": 0.09
}' |
apify call afkdigital/newapi20-uk-food-business-first-seen --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,afkdigital/newapi20-uk-food-business-first-seen"
        }
    }
}
```

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/7l1xGsggBit0xUq2J/builds/tHcPtLtS0zsEk02Yp/openapi.json
