# FDA Drug Establishments (DECRS) - Daily Changes & Removals (`rastriq/fda-drug-establishments-delta`) Actor

Every drug establishment registered with the US FDA (about 10,500 firms: API makers, manufacturers, labs, packagers) with country, operations and expiry, plus what the FDA does not keep: daily new registrations, renewals, changes and removals.

- **URL**: https://apify.com/rastriq/fda-drug-establishments-delta.md
- **Developed by:** [Rastriq — Structured data from the world](https://apify.com/rastriq) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 establishment 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

## FDA Drug Establishments - daily new, renewed, changed and removed firms

Every firm registered with the **US FDA** to make, test, pack or label human drugs - about **10,500 establishments** worldwide (API makers, finished-dose plants, contract labs, packagers, repackagers, PET drug sites) - as clean **FDA establishment registration data** rows keyed by **FEI** and **DUNS**.

The FDA publishes only today's list. **It does not tell you who joined, who renewed, what changed or who disappeared.** This Actor keeps that history for you: schedule it once a day in *delta* mode and get exactly the changes, including the **removals** (firms that dropped off the registry), which the FDA does not keep anywhere.

### Use cases: what can you do with FDA establishment registration data?

**1. Supplier qualification and CMO / CDMO due diligence** - *QA, procurement and sourcing teams.*
Before you approve a contract manufacturer or an API source, you need proof that it is registered, for which operations and until when. Run `snapshot` with `countries` set to the supplier's country and look the firm up by `fei_number` or `duns_number`. Check `operations` (for example `API MANUFACTURE` vs `MANUFACTURE`), `expiration_date` and the flags `expiration_past` and `agent_missing_foreign`. You get a dated qualification record: `source_updated_at` shows which FDA file it came from.

**2. Alerts when a supplier drops off the registry** - *supply-chain risk and vendor management.*
The FDA keeps no history, so a lapsed or withdrawn registration just vanishes. Schedule `delta` once a day with the countries you source from and filter the dataset on `change_type = removed`; `last_seen_at` is the last run that still saw the firm. You get an early warning for a supplier that is no longer registered, before a shipment or an audit finds out.

**3. Monitor new API manufacturing sites in India or China** - *market intelligence and sourcing.*
Use `delta` with `countries: ["IND","CHN"]` and `operations: ["API MANUFACTURE"]`, then read the `new` rows: `firm_name`, `address_raw`, `agent_name`, `registrant_name`. You get a running list of new Asian API entrants into the US supply chain (recipe below).

**4. Regulatory intelligence and competitor radar** - *regulatory affairs, strategy and analyst teams.*
Follow how a set of firms changes: in `delta` mode, rows with `change_type = changed` list `changed_fields` (for example `operations`, `address_raw`, `agent_name`, `registrant_duns`) and `previous_values` with the old values. You see that a competitor added `STERILIZE` or moved to a new site without reading the whole list every month.

**5. Lead generation for US Agent and registration services** - *regulatory consultancies and US-agent providers.*
Foreign establishments need a US agent and a yearly renewal. Pick `new` and `renewed` rows with `countries` outside the US, and use `agent_name`, `agent_duns` and the flag `agent_missing_foreign` to find firms with no US agent listed, or `expiration_date` to time your outreach. You get a prospect list of companies (contacts and personal data are never output), refreshed daily.

**6. Enrich a supplier master by FEI or DUNS** - *data and master-data teams.*
Join your vendor table to the registry on `duns_number` (always 9 digits) or on `fei_number` + `duns_number`, which is the unique key. `fei_zero_padded` and `shared_fei` tell you where an ID needed repair or is shared by several rows. You add registration status, operations, country and agent to every vendor, and a stable key to join with inspection, import-alert or EU GMP data.

**7. Track the yearly renewal campaign (October to December)** - *compliance and account managers.*
Most registrations expire on 31 December and are renewed in the last quarter. Keep `includeRenewals: true` and read the `renewed` rows (`previous_values.expiration_date` holds the old date) to see who has renewed; in a `snapshot`, firms still showing the old `expiration_date` have not. Or switch `includeRenewals` off to receive only real changes.

#### Recipe 1: daily monitor of API manufacturers in India and China

Schedule once a day. The first run returns the full list in scope as `baseline`; later runs return only `new`, `renewed`, `changed` and `removed` firms.

```json
{
  "mode": "delta",
  "countries": ["IND", "CHN"],
  "operations": ["API MANUFACTURE"],
  "includeExcluded": false,
  "includeRenewals": true,
  "maxItems": 0
}
```

#### Recipe 2: supplier shortlist for contract manufacturers in Spain, Italy and Germany

One full snapshot of firms that manufacture or analyse, ready to join with your vendor list.

```json
{
  "mode": "snapshot",
  "countries": ["ESP", "ITA", "DEU"],
  "operations": ["MANUFACTURE", "ANALYSIS"],
  "includeExcluded": false,
  "maxItems": 0
}
```

### How to run it

1. **Fastest way to try:** click **Start** with the pre-filled input (snapshot, Spain, 100 rows).
2. **Daily monitoring:** set `mode` to `delta`, add filters if you want (countries, operations) and schedule it once a day (see the recipes above). The first run returns the full list as `baseline`; every later run returns only changes, and finishes in seconds with no per-row charge when the FDA file has not changed (the small Actor start fee still applies).

#### Example output

```json
{
  "fei_number": "1000242648",
  "fei_raw": "1000242648",
  "duns_number": "512780529",
  "firm_name": "Example Pharma Ltd",
  "address_raw": "Plot 4, Industrial Area, Hyderabad, Telangana 500001, India (IND)",
  "country_iso3": "IND",
  "operations": ["API MANUFACTURE", "ANALYSIS"],
  "operations_raw": "ANALYSIS; API MANUFACTURE",
  "expiration_date": "2027-12-31",
  "registrant_name": "Example Pharma Ltd",
  "registrant_duns": "512780529",
  "agent_duns": "116937572",
  "agent_name": "Example US Agent Inc.",
  "exclusion_flag": "N",
  "is_excluded": false,
  "source": "fda-decrs",
  "source_file": "drls_reg",
  "source_url": "https://www.accessdata.fda.gov/cder/drls_reg.zip",
  "source_updated_at": "2026-10-09T03:00:50Z",
  "first_seen_at": "2026-10-12T09:00:04Z",
  "last_seen_at": "2026-10-13T09:00:03Z",
  "detected_at": "2026-10-13T09:00:03Z",
  "change_type": "renewed",
  "changed_fields": ["expiration_date"],
  "previous_values": { "expiration_date": "2026-12-31" },
  "quality_flags": []
}
```

### FDA Drug Establishments Actor input parameters

All parameters are optional. With the pre-filled input the Actor returns 100 Spanish establishments in `snapshot` mode.

| Parameter | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `delta` when empty (pre-filled: `snapshot`) | `snapshot`, `delta` or `preloaded`; see the modes table below. |
| `countries` | array of ISO3 codes | empty = all countries (pre-filled: `["ESP"]`) | Keep only establishments in these countries, read from the address (for example `ESP`, `IND`, `CHN`). You can type any other 3-letter code. |
| `operations` | array of strings | empty = all | Keep establishments that perform at least one of these operations (exact match on the normalised name), for example `API MANUFACTURE`. |
| `includeExcluded` | boolean | `false` | Also load the FDA list of establishments excluded from the registry (23 firms, flag `E`). They have no operations or expiry date. |
| `includeRenewals` | boolean | `true` | Delta mode only. Switch off to skip renewals: they are neither returned nor billed, and your stored state still moves forward. |
| `maxItems` | integer (min 0) | 0 or empty = no limit (pre-filled: `100`) | Stop after this many rows. Rows not delivered stay pending and arrive in your next delta run. |
| `stateKey` | string | empty | Name of your delta stream. Runs with the same key (or the same filters, if empty) are compared with each other. |

Pre-filled input (the fastest way to try the FDA Drug Establishments Actor):

```json
{"mode": "snapshot", "countries": ["ESP"], "maxItems": 100}
```

### FDA establishment data modes: delta, snapshot and preloaded

| Mode | What you get | Billed as |
|---|---|---|
| `delta` (default) | Only `new`, `renewed`, `changed` and `removed` establishments since your last run. **First run:** the full list as `baseline`. Source unchanged: 0 rows, no per-row charge. | `establishment-change` (`establishment` for the baseline rows) |
| `snapshot` | The full list in scope on every run, each row tagged `new`, `renewed`, `changed`, `unchanged` (or `baseline` on the first run), plus removals. | `establishment` |
| `preloaded` | The latest full list already prepared by Rastriq, served instantly and at a lower price per row; no change tracking. At launch, if that snapshot is not published yet, the run falls back to *snapshot* (live) mode and is billed as `establishment`. | `establishment-preloaded` |

**Filters only decide which rows you receive.** The Actor always compares the complete list, so a removal is never missed or invented because of a filter. Each combination of filters (or each `stateKey`) keeps its own change history.

#### Change types

| `change_type` | Meaning |
|---|---|
| `new` | Establishment appeared since the previous run. |
| `renewed` | **Only** the expiry date changed, and it moved forward - the yearly registration renewal. |
| `changed` | Any other field changed (name, address, operations, agent, registrant, exclusion, or an expiry date that moved for another reason). `changed_fields` and `previous_values` tell you what and from what. |
| `removed` | Establishment is no longer in the FDA list. `last_seen_at` is the last run that saw it. |
| `unchanged` | Same as before (snapshot mode only). |
| `baseline` | First run for this filter set / `stateKey`: starting point, not a real change. |

Expect heavy `renewed` traffic between October and December, when most registrations are renewed for the next year. In delta mode you can switch **Include renewals** off: renewals are then neither returned nor billed (your state still advances, so they do not come back later).

**Truncated first run:** if your first run stops early (`maxItems` or a spending limit), no state is saved and the next run starts the baseline again, so you are never billed change prices for what is really baseline data.

### FDA drug establishment output fields

| Field | Description |
|---|---|
| `fei_number` | FDA Establishment Identifier, 10 digits (older 7-digit IDs are zero-padded). `null` for about 2% of firms that have none. |
| `fei_raw` | FEI exactly as published. |
| `duns_number` | D-U-N-S number of the establishment (9 digits). |
| `firm_name` | Name under which the establishment is registered. In a few cases it is a sole trader (an individual) and so may be a person's name; filter on `quality_flags` and your own rules if that matters to you. |
| `address_raw` | Address exactly as published, including the country. |
| `country_iso3` | ISO 3166 alpha-3 country code read from the address (e.g. `ESP`, `IND`). |
| `operations` | Normalised, sorted list: `API MANUFACTURE`, `MANUFACTURE`, `ANALYSIS`, `PACK`, `REPACK`, `LABEL`, `RELABEL`, `STERILIZE`, `TRANSFILL`... |
| `operations_raw` | Operations as published. |
| `expiration_date` | Registration expiry, ISO date. |
| `registrant_name`, `registrant_duns` | Company that holds the registration. `registrant_name` is `null` when it is the name of an individual (flag `registrant_name_person_removed`). |
| `agent_name`, `agent_duns` | US agent (a company) for foreign establishments. `agent_name` is `null` when the published agent is an individual (flag `agent_name_person_removed`); `agent_duns` is kept. |
| `exclusion_flag`, `is_excluded` | `E` / `true` for firms on the FDA exclusion list (only with `includeExcluded`). |
| `source`, `source_file`, `source_url`, `source_updated_at` | Where the row comes from and when the FDA generated that file (UTC). |
| `first_seen_at`, `last_seen_at`, `detected_at` | First and last run that saw the row; timestamp of this run. |
| `change_type`, `changed_fields`, `previous_values` | The change, see above. |
| `quality_flags` | Data-quality notes. Rows are **flagged, never dropped** - full list below. |

#### Quality flags

| Flag | Meaning |
|---|---|
| `fei_zero_padded` | FEI was published with fewer than 10 digits and was left-padded with zeros (`fei_raw` has the original). |
| `fei_missing` | No FEI published (`fei_number` is `null`). |
| `fei_format` | FEI is not numeric. |
| `shared_fei` | Other rows share this FEI (different D-U-N-S or address). |
| `duns_missing`, `duns_format` | D-U-N-S absent or not 9 digits. |
| `registrant_duns_format` | Registrant D-U-N-S not 9 digits. |
| `country_missing` | No `(XXX)` country code at the end of the address. |
| `expiration_invalid` | Expiry date missing or not a valid date. |
| `expiration_past` | Expiry date is before the run date. |
| `expiration_far` | Expiry date is later than the end of next year. |
| `operations_missing` | No operations listed (non-excluded firms). |
| `agent_missing_foreign` | Non-US establishment with no US agent listed. |
| `agent_details_nonstandard` | Agent field did not follow the usual pattern and was parsed best-effort. |
| `agent_name_partial` | Part of the agent text looked like a person and was discarded. |
| `agent_name_unavailable` | Agent name could not be determined (e.g. only an email was published). |
| `agent_name_person_removed` | Agent name looked like an individual and was removed. |
| `registrant_name_person_removed` | Registrant name was an individual and was removed. |

**About the key.** One FEI can appear on several rows (about 6% of rows, e.g. an establishment registered under two D-U-N-S numbers or two address variants). Use `fei_number` + `duns_number` as the unique key; rows sharing a FEI carry the `shared_fei` flag.

### Personal data is removed

The FDA file includes contact people's names and emails. **This Actor never outputs or stores them**: establishment contacts, registrant contacts, and the email address and phone number inside the US agent field are all discarded. Registrant and agent names that are individuals (recognised by comparing with the contact names in the file and by name shape) are set to `null` and flagged. Recognition is best-effort and conservative: a company with a person-like name may occasionally lose its name. Rows are about companies and sites, not people.

The FDA CDN occasionally serves an older copy of the file; the Actor detects it (the file is older than your stored state), retries, and skips the run instead of reporting false reversals.

### How much does it cost to use this FDA establishment registration data Actor?

Pay per event. Prices per 1,000 events on the BRONZE tier:

| Event | Price |
|---|---|
| Actor start | $0.01 per run (512 MB) |
| `establishment` (snapshot / baseline row) | $1.00 per 1,000 rows |
| `establishment-change` (delta row: new / renewed / changed / removed) | $5.00 per 1,000 rows |
| `establishment-preloaded` (row of the ready-made snapshot) | $0.50 per 1,000 rows |

Apify plan discounts apply to these prices: Free plan +15 %, Silver -15 %, Gold / Platinum / Diamond -30 %.

**Real-cost examples**

- **Full snapshot:** about 10,450 rows is roughly **$10.45** (about $5.23 as `preloaded`).
- **Typical daily monitor:** about 50 changes a day is roughly **$0.26 per day** ($0.01 start + 50 x $0.005).
- **Renewal season:** between 9 and 12 October 2026 the delta returned 421 changes, 381 of them `renewed`. With `includeRenewals: false` it would have been 40.
- **Nothing changed at the FDA:** the run finishes in seconds and there is **no per-row charge**, only the Actor start fee.

**Test run:** the pre-filled input (100 snapshot rows) on the BRONZE tier is 100 x $0.001 = $0.10, plus the Actor start fee.

Set a maximum charge per run in the Apify run options, or use `maxItems`: rows not delivered stay pending and arrive in your next delta run.

### Data source, frequency and licence

- Source: FDA Drug Establishments Current Registration Site (DECRS) - `drls_reg.zip` and `drls_excluded.zip` on accessdata.fda.gov.
- The FDA refreshes the list every business day; schedule this Actor daily.
- The data is a work of the US government and in the public domain (FDA Website Policies). Attribution to the U.S. Food and Drug Administration is appreciated. This Actor is not affiliated with or endorsed by the FDA.
- Registration with the FDA is not an approval or certification of the establishment.

### FAQ: FDA drug establishment registration data

**How much does a test run cost?** With the pre-filled input (snapshot, Spain, 100 rows) on the BRONZE tier: 100 x $0.001 = $0.10 plus the Actor start fee. `maxItems` and the maximum charge per run in the Apify run options cap your spend.

**How often should I run it?** The FDA refreshes the list every business day, so a daily schedule in `delta` mode is enough. If the FDA file did not change, the run finishes in seconds with no per-row charge.

**What does `removed` mean?** The establishment is no longer in the FDA list. `last_seen_at` is the last run that still saw it. The Actor does not tell you why it left the list.

**Do filters hide removals?** No. The Actor always compares the complete list, so `countries` and `operations` only decide which rows you receive.

**Does it return people's names or emails?** No. Contact names, emails and agent phone numbers are discarded. Registrant and agent names that look like individuals are set to `null` and flagged (see the personal data section).

**Why is `fei_number` sometimes `null`?** About 2% of firms have no FEI in the FDA file. Use `duns_number`, or `fei_number` + `duns_number` as the unique key where both exist.

**Something looks wrong or a field is missing?** Open an issue from the Actor page and include the `fei_number` and `duns_number` of the row.

### Related Rastriq actors

- [EudraGMDP Pharma Registry (EMA)](https://apify.com/rastriq/eudragmdp-pharma-registry) - EU licences (WDA, MIA) and GMP/GDP certificates, one row per document.
- [EU Pharma Sites Graph](https://apify.com/rastriq/eu-pharma-sites-graph) - EU/EEA pharma sites from EudraGMDP with their licences grouped, one row per site.
- [Europages Scraper](https://apify.com/rastriq/europages-scraper) - European B2B company directory.

***

Built by **Rastriq** - reliable data from official registries. Questions or a field you need? Open an issue from the Actor page.

# Changelog

This Actor's version history is a separate document: https://apify.com/rastriq/fda-drug-establishments-delta/changelog.md

# Actor input Schema

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

<b>Delta</b> (default when empty): only new, changed, renewed and removed establishments since your last run; the first run returns everything as <code>baseline</code>.<br><b>Snapshot</b>: the full list in scope on every run, each row tagged with its change type.<br><b>Preloaded</b>: a pre-built copy of the full list at a lower price per row (no change tracking).

## `countries` (type: `array`):

Keep only establishments located in these countries, 3-letter ISO codes read from the address (e.g. <code>ESP</code>, <code>IND</code>, <code>CHN</code>). Empty = all countries. You can type any other code and press Enter.

## `operations` (type: `array`):

Keep establishments that perform at least one of these operations (exact match on the normalised operation name). Empty = all. Example: <code>API MANUFACTURE</code> for active-ingredient makers.

## `includeExcluded` (type: `boolean`):

Also load the FDA list of establishments <b>excluded</b> from the registry (23 firms, flag <code>E</code>). They have no operations or expiry date.

## `includeRenewals` (type: `boolean`):

<b>Delta mode only.</b> A renewal is an establishment whose only change is a later expiry date (the yearly registration renewal). Most registrations expire on 31 December, so between October and December <b>thousands of renewals</b> are billed at the change price. Untick to skip them: they are not returned or billed, but your stored state still moves forward, so they will not reappear.

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

Stop after this many rows (0 or empty = no limit). Rows not delivered stay pending and are delivered in your next delta run. Also a handy cost cap.

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

Name of your delta stream. Runs with the same key (or the same filters, if empty) compare against each other. Use a different key to keep separate change histories.

## Actor input object example

```json
{
  "mode": "snapshot",
  "countries": [
    "ESP"
  ],
  "includeExcluded": false,
  "includeRenewals": true,
  "maxItems": 100
}
```

# Actor output Schema

## `establishments` (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",
    "countries": [
        "ESP"
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("rastriq/fda-drug-establishments-delta").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",
    "countries": ["ESP"],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("rastriq/fda-drug-establishments-delta").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",
  "countries": [
    "ESP"
  ],
  "maxItems": 100
}' |
apify call rastriq/fda-drug-establishments-delta --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rastriq/fda-drug-establishments-delta"
        }
    }
}
```

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/ufe8bAXUtbf8mny15/builds/NOXVf5NXtfYwNbWfF/openapi.json
