# UK MHRA New Manufacturing & Wholesale Licences Feed (`rastriq/uk-mhra-new-licences-feed`) Actor

- **URL**: https://apify.com/rastriq/uk-mhra-new-licences-feed.md
- **Developed by:** [Rastriq — Structured data from the world](https://apify.com/rastriq) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $14.00 / 1,000 licence returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 MHRA New Manufacturing & Wholesale Licences Feed

**UK MHRA New Licences Feed** returns every new **medicines manufacturing and wholesale dealer licence** granted by the UK MHRA - WDA(H), WDA(V), MIA, MIA(IMP), MS ("specials") and more - as clean, structured rows: MHRA company number, licence type, company, address, postcode district and month of grant. Schedule it monthly and get only the **new licences** since your last run, plus a growing **history** that the official rolling 12-month list does not keep.

### Why use it

The MHRA publishes the new licences of the last ~12 months as a single CSV on gov.uk, replaced every month. Older licences silently drop off, the file link changes each month, and there is no change feed. This Actor:

| | |
|---|---|
| 🆕 **New-licence alert** | `delta` mode returns only licences that appeared since your previous run. |
| 🗄️ **History** | Licences that leave the 12-month window are kept and marked `in_current_list = false` (`aged_out`). Turn on **Include archived licences** to get them back. |
| 🧹 **Clean data** | Normalised licence types with labels, validated UK postcodes, postcode district and area, `YYYY-MM` month. |
| ⚡ **Cheap and fast** | Two HTTP requests, runs in seconds on 128 MB. When the file did not change, the run ends free. |
| 🔒 **No personal data** | Licences held in a personal name are kept, but name, street and full postcode are removed. |

#### Snapshot vs delta: what each mode returns and charges

| Mode | Kind | What you get | What is charged |
|---|---|---|---|
| **Snapshot** | full list | The current list (about 120 licences) on every run; with *Include archived licences* also those that already left the list | `licence-record` per row |
| **Delta** | changes only | 1st run: the current list as `baseline`. Later runs: only `new`, `changed`, `reappeared` and (optionally) `aged_out` licences | 1st run: `licence-record` per row. Later runs: `licence-change` per changed row only. **Unchanged licences are never charged**; a run on an unchanged file costs only the start fee |

### Use cases

1. **Sales prospecting for pharma services** - pharma 3PL and cold-chain logistics, GDP/QP consultancies, serialisation and ERP vendors: every new WDA(H) holder is a company that just started distributing medicines in the UK.
2. **Competitive intelligence** - pharma wholesalers and CDMOs: who is entering UK wholesale or manufacturing, by region and month.
3. **Supplier and customer onboarding** - check that a new UK trading partner has recently obtained its licence (`company_no`, `licence_type`).
4. **Market research** - count new licences by type, region (`postcode_area`) and month.
5. **Data enrichment** - join with your CRM by company name and postcode, or with EU registers such as EudraGMDP.

### How to use

1. Keep the pre-filled values (**Snapshot**, **Max rows = 1**) and click **Start**: you get one licence in seconds for about $0.03. Set **Max rows** to 0 to get the whole current list.
2. For alerts, switch **Mode** to **Delta** and add a monthly schedule (the MHRA updates the list in the first days of each month; a weekly schedule also works and costs nothing when the file did not change).
3. Optional: filter by **licence type** or **postcode prefix**.

### Input

| Field | Type | Description |
|---|---|---|
| `mode` | enum | `delta` (default when empty) or `snapshot` |
| `licenceTypes` | array | `WDA(H)`, `WDA(V)`, `MIA`, `MIA(IMP)`, `MS`, `MANSA`, `MANA` |
| `postcodePrefixes` | array | e.g. `LS`, `M`, `DE65` |
| `includeArchive` | boolean | Snapshot: also return licences that left the 12-month list |
| `includeAgedOut` | boolean | Delta: report licences leaving the list (default on) |
| `maxItems` | integer | Row limit and spending cap (pre-filled 1; 0 = none) |
| `stateKey` | string | Name of an independent change-tracking stream |

```json
{ "mode": "delta", "licenceTypes": ["WDA(H)", "MIA"] }
```

### Output example

Real row from a snapshot run:

```json
{
  "licence_key": "62335|WDA(H)|DE65",
  "company_no": "62335",
  "licence_type": "WDA(H)",
  "licence_type_label": "Wholesale dealer's licence (human medicines)",
  "company_name": "BIONICAL CTS LIMITED",
  "address_line_1": "3RD FLOOR, THE PIAZZA MERCIA MARINA",
  "address_line_2": "FINDERN LANE, WILLINGTON",
  "city": "DERBY",
  "postcode": "DE65 6DW",
  "postcode_outward": "DE65",
  "postcode_area": "DE",
  "published_month": "2026-09",
  "is_natural_person_redacted": false,
  "quality_flags": [],
  "in_current_list": true,
  "source": "gov.uk MHRA new licences (OGL v3)",
  "source_url": "https://assets.publishing.service.gov.uk/media/6ac65fc6f1ba855cc196a8ba/New_Manufacturing_and_Wholesale_Dealer_Licences_-_October_2026.csv",
  "source_page": "https://www.gov.uk/government/publications/medicines-new-manufacturing-and-wholesale-dealer-licences",
  "source_file_title": "Title: Medicines: new manufacturing and wholesale dealer licences - October 2026",
  "source_updated_at": "2026-10-07T16:17:32+01:00",
  "first_seen_at": "2026-10-24T20:20:42Z",
  "last_seen_at": "2026-10-24T20:20:42Z",
  "detected_at": "2026-10-24T20:20:42Z",
  "change_type": "baseline",
  "changed_fields": [],
  "previous_values": null
}
```

### What data you get

| Field | Description |
|---|---|
| `company_no` | MHRA company number ("Company No" in the source). **Not** a Companies House number. |
| `licence_type`, `licence_type_label` | Normalised licence type and its meaning |
| `company_name`, `address_line_1/2`, `city`, `postcode` | As published (null when the holder is a person, see below) |
| `postcode_outward`, `postcode_area` | Postcode district (`DE65`) and area (`DE`) |
| `published_month` | Month the licence appeared in the list, `YYYY-MM` |
| `in_current_list` | `false` once the licence has left the rolling 12-month list |
| `change_type` | `baseline`, `new`, `changed`, `aged_out`, `reappeared`, `unchanged` |
| `changed_fields`, `previous_values` | What changed and the old values (`changed`) |
| `licence_key`, `source_url`, `source_updated_at`, `first_seen_at`, `last_seen_at`, `detected_at` | Stable key, the gov.uk CSV used, and run / tracking timestamps |
| `quality_flags` | `invalid_postcode`, `unknown_licence_type`, `possible_natural_person_redacted`, `missing_address`... Rows are flagged, never dropped |

### Personal data

Some licences are held by individuals (for example a GP practice listed by the doctors' names). A holder is treated as an organisation only if the name contains an organisation word (LIMITED, LTD, PLC, LLP, SURGERY, PHARMACY, NHS, TRUST, CLINIC...) and no personal title (DR, MR, MRS...). Otherwise the row is kept with `company_name`, street lines and full postcode set to `null` (city and postcode district stay), flagged `possible_natural_person_redacted`. Redacted values are not stored by the Actor.

### Pricing

Pay per event. Tier discounts: Silver -15 %, Gold and above -30 % (Free plan +15 %).

| Event | Price (Bronze) |
|---|---|
| `licence-record` - one licence in a snapshot or baseline | $20.00 / 1,000 ($0.02 each) |
| `licence-change` - one new / changed / aged-out licence in delta | $30.00 / 1,000 ($0.03 each) |
| Actor start | $0.01 per run |

The pre-filled example (1 licence) costs about $0.03. The whole current list (~120 licences) costs about $2.41. A monthly delta usually returns 5-20 new licences ($0.15-0.60). Only result rows are billed; runs on an unchanged file cost only the start fee. **Max rows** caps what a run can bill.

### Source, licence and limits

- Source: MHRA, *Medicines: new manufacturing and wholesale dealer licences*, [gov.uk](https://www.gov.uk/government/publications/medicines-new-manufacturing-and-wholesale-dealer-licences). Contains public sector information licensed under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/).
- The list covers **new** licences only (about 12 months). It is not the full register of all licence holders, and it does not report suspensions or revocations. `aged_out` is not a revocation.
- History builds up from your first run: the Actor cannot recover licences that dropped off the list before you started.
- Not affiliated with or endorsed by the MHRA. Not legal or regulatory advice.

### FAQ

**How often does the source change?** Once a month, usually in the first week.

**Is this the full MHRA register?** No. It is the official list of new licences. The full GMDP register is not covered.

**Is it legal to use this data?** Yes: the list is published by the MHRA under the Open Government Licence v3.0, which allows commercial reuse with attribution (see *Source, licence and limits*). Personal-name holders are redacted.

**Do I need proxies or an account?** No. The Actor makes two plain HTTP requests to gov.uk.

**Where is the history kept?** In a named key-value store (`uk-mhra-licences-state`) in your own Apify account. It is what lets delta mode and *Include archived licences* work; delete it to start over.

**Why is a company name empty?** The holder looks like a person; see *Personal data*.

Built by **Rastriq** - reliable data from official registers. Questions or feature requests: use the Actor's Issues tab.

# Changelog

This Actor's version history is a separate document: https://apify.com/rastriq/uk-mhra-new-licences-feed/changelog.md

# Actor input Schema

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

<b>Delta</b> (default when empty): only new, changed and aged-out licences since your last run; the first run returns everything as <code>baseline</code>.<br><b>Snapshot</b>: the current list on every run.

## `licenceTypes` (type: `array`):

Keep only these licence types. Empty = all.

## `postcodePrefixes` (type: `array`):

Keep only licences whose postcode starts with these letters or districts, e.g. <code>LS</code>, <code>M</code>, <code>DE65</code>. Empty = whole UK.

## `includeArchive` (type: `boolean`):

gov.uk only shows the last ~12 months. With this on, a snapshot also returns every licence this Actor has seen in earlier months and that has since dropped out of the list (<code>in_current_list = false</code>). Builds up over time from your first run.

## `includeAgedOut` (type: `boolean`):

In delta mode, also return licences that dropped out of the rolling 12-month list (<code>aged_out</code>). This is <b>not</b> a revocation: it only means the licence is older than the window.

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

Stop after this many rows (0 = no limit). Each row is billed, so this is also your spending cap. Pre-filled with 1 so the first test costs about 3 cents; set 0 to get the whole list.

## `stateKey` (type: `string`):

Optional name of the change-tracking stream (e.g. <code>pharma-uk</code>). Use a different key to keep independent histories. Mainly for delta mode.

## Actor input object example

```json
{
  "mode": "snapshot",
  "includeArchive": false,
  "includeAgedOut": true,
  "maxItems": 1
}
```

# Actor output Schema

## `licences` (type: `string`):

No description

## `runSummary` (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 = {
    "mode": "snapshot",
    "maxItems": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("rastriq/uk-mhra-new-licences-feed").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 = {
    "mode": "snapshot",
    "maxItems": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("rastriq/uk-mhra-new-licences-feed").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 '{
  "mode": "snapshot",
  "maxItems": 1
}' |
apify call rastriq/uk-mhra-new-licences-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rastriq/uk-mhra-new-licences-feed"
        }
    }
}
```

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/c9T8BgF7UBclBPZac/builds/j9rkI53d6H9F4BDap/openapi.json
