FDA Drug Establishment Registration & Supplier Change Monitor
Pricing
$10.00 / 1,000 resolved supplier checks
FDA Drug Establishment Registration & Supplier Change Monitor
Bulk-check drug manufacturing suppliers against FDA DECRS current and excluded registration files. Match exact FEI, DUNS or normalized firm names; monitor disappearance, reappearance, annual expiration, operation, name and address changes without turning source failures into false absences.
Pricing
$10.00 / 1,000 resolved supplier checks
Rating
0.0
(0)
Developer
Vadim Bezrukov
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Monitor FDA drug establishment registration status across your supplier portfolio.
Bulk-check up to 5,000 pharmaceutical manufacturing establishments against the official FDA Drug Establishments Current Registration Site (DECRS), then rerun the same watchlist to detect registration disappearance, reappearance, annual expiration, business-operation, firm-name and address changes. One official bulk snapshot serves the whole batch: no FDA login, browser, proxy or one-request-per-supplier loop.
This Actor checks an administrative establishment-registration publication. It is not an FDA approval checker and does not prove product approval, GMP compliance, import admissibility, inspection outcome, safety, quality or FDA endorsement.
Use from AI agents with MCP
With access to this Actor, connect it directly at
https://mcp.apify.com?tools=automa-flow/fda-drug-establishment-monitor. Ask your
agent to check a supplier portfolio and report CURRENT, EXCLUDED, NOT_FOUND, or
source failure without converting an unverified response into a compliance
claim.
Primary workflows
- Verify drug manufacturing suppliers in bulk.
- Monitor supplier registration daily or weekly.
- Detect facilities disappearing from the current DECRS publication.
- Watch annual registration expiration.
- Detect business-operation, name and address changes.
- Feed supplier observations and changes into webhooks, ERP, procurement or compliance systems.
Quick start
{"establishments": [{"fei": "0000000360","duns": "271408412","name": "DSP","reference": "supplier-fr-001"},{"duns": "039106281","reference": "supplier-us-001"},{"name": "EUROAPI FRANCE","reference": "manual-name-review"}],"mode": "snapshot","dueSoonDays": 90,"includeAddress": true}
The Dataset always contains one reconciliation row per input. In this example the exact name
EUROAPI FRANCE is intentionally useful: FDA currently publishes two exact normalized matches,
so that row is AMBIGUOUS; the Actor never silently picks one.
Exact matching rules
The priority is:
FEI exact -> DUNS exact -> normalized firm-name exact
- FEI spaces, hyphens and leading zeroes are normalized for lookup.
- DUNS must resolve to exactly nine digits.
- Firm names normalize Unicode, case, punctuation and repeated whitespace. Accents remain significant; no fuzzy, phonetic or AI match is performed.
- If FEI returns multiple records and the input also provides DUNS, DUNS may disambiguate that FEI
group. Otherwise the result is
AMBIGUOUS. - If exact identifiers conflict, the Actor returns
AMBIGUOUSinstead of trusting one silently.
Live source research on 2026-09-02 found 281 duplicated FEI values in the current file and one FEI
reused between unrelated current and excluded rows. DUNS was unique within the live current file.
For that reason a resolved row uses fei:<FEI>|duns:<DUNS> as its stable source_id when both are
published. FEI remains the primary identity component without being falsely presented as globally
unique.
Truthful status semantics
match_status | registration_status | Meaning |
|---|---|---|
MATCHED | CURRENT | One exact supplier record is positively present in the successfully validated current DECRS file. |
MATCHED | EXCLUDED | One exact record is positively present in FDA's excluded file. FDA publishes no reason field, so the Actor asserts no cause. |
NOT_FOUND | NOT_CURRENT | Neither validated file contains an exact match. This does not mean enforcement, non-compliance or a ban. |
AMBIGUOUS | UNKNOWN | Multiple exact plausible records or conflicting identifiers; no fuzzy selection was made. |
FAILED | UNKNOWN | Required source or processing state was not verified. This is never converted to absence. |
INVALID_INPUT | UNKNOWN | This input item is invalid; other items continue. |
FDA says current establishments can disappear because a registration is inactivated for a compliance/enforcement case, expires, is deregistered or is otherwise dropped from submission. The bulk files do not provide a reliable reason. A disappearance event therefore says only that a previously current exact observation is no longer current in the latest successful snapshot.
If the current ZIP fails download, CRC, schema, size or suspicious-row-drop validation, all valid
inputs receive FAILED/UNKNOWN and the Actor run fails. A corrupted file can never manufacture
thousands of NOT_FOUND or disappearance events. If only the excluded file fails, exact current
matches can still succeed, but unmatched inputs are FAILED/UNKNOWN because excluded membership
was not verified. RUN_SUMMARY.sourceState is SOURCE_FAILED whenever either snapshot fails,
while the Actor run itself fails globally only when the current registry is unusable.
Input
| Field | Default | Description |
|---|---|---|
establishments | required | 1-5,000 objects. Each requires at least one of fei, duns, name; optional reference is echoed unchanged and is limited to 128 characters. |
mode | snapshot | snapshot returns the present observation; monitor compares with the last successful state. |
monitorId | — | Required in monitor mode. Reuse the same 1-64 character key for the same watchlist. |
onlyChanges | false | In monitor mode, unchanged inputs still emit status rows but omit repeated profile details. |
dueSoonDays | 90 | 1-365 day EXPIRATION_DUE_SOON threshold. |
includeAddress | true | Include the official formatted address and conservative components. |
No concurrency, retry, proxy, browser or parser settings are exposed. Retries are bounded and limited to network errors, 408, 429 and selected 5xx responses.
Output
Every row carries the history-ready contract:
source, stablesource_id, officialsource_url- UTC
scraped_at, additiveschema_version, semanticfingerprint reference,query_fei,query_duns,query_name- explicit
match_status,matched_by,registration_status - published FEI, DUNS, firm name, operations, expiration and facility address when verified
changed,change_type, exactchanges, thresholdalerts- a safe machine-readable
errorfor unverified outcomes
The fingerprint covers normalized semantic source fields only. It excludes timestamps, run IDs,
HTTP metadata, reference, days_until_expiration and source-download facts, so the same FDA
state produces the same hash on repeat runs. Business-operation order and irrelevant case changes
do not create false changes.
FDA supplies one formatted global address rather than reliable worldwide street/city/region
columns. The output preserves that value in facility_address.formatted, always extracts the FDA
country marker when present, and parses US street/city/state/postal components conservatively.
Other global subfields remain null instead of being invented.
Raw files also contain establishment contacts, emails, agents and registrant contacts. The Actor does not retain, log, index, store or emit any of those fields.
Monitor mode
{"establishments": [{"fei": "0000000360", "duns": "271408412", "reference": "supplier-fr-001"},{"duns": "039106281", "reference": "supplier-us-001"}],"mode": "monitor","monitorId": "weekly-pharma-suppliers","onlyChanges": true,"dueSoonDays": 120,"includeAddress": true}
The first successful verified observation is BASELINE with changed=false. Later successful
runs may emit:
REGISTRATION_APPEARED,REGISTRATION_DISAPPEARED,REGISTRATION_REAPPEAREDEXCLUDED_STATUS_CHANGEDEXPIRATION_DATE_CHANGED,EXPIRATION_DUE_SOONBUSINESS_OPERATION_ADDED,BUSINESS_OPERATION_REMOVEDFIRM_NAME_CHANGED,ADDRESS_CHANGEDFEI_CHANGED,DUNS_CHANGED
State lives only in an Apify KVS. The key namespace is monitorId plus normalized input identity:
FEI first, with DUNS included when the input supplies it so reused FEIs cannot collide. The value is
the last successful normalized observation. FAILED, AMBIGUOUS and invalid rows never overwrite
it. Source row-count/schema metadata is likewise updated only after a valid snapshot.
onlyChanges=true preserves one-input/one-row reconciliation. An unchanged row keeps status,
identity metadata, fingerprint and UNCHANGED, sets details_omitted=true, and omits repeated
supplier profile fields. Use the Dataset changes view for flattened event consumption.
API example
Keep the API token in a secret or environment variable, never in a URL, file or log:
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~fda-drug-establishment-monitor/runs?maxTotalChargeUsd=1" \-H "Authorization: Bearer $APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"establishments": [{"fei":"0000000360","duns":"271408412","reference":"supplier-fr-001"},{"duns":"039106281","reference":"supplier-us-001"}],"mode":"snapshot","dueSoonDays":90,"includeAddress":true}'
Poll the returned run, then read its defaultDatasetId. RUN_SUMMARY in the default KVS records
source ETags/Last-Modified values, compressed/uncompressed bytes, row counts, schema fingerprint,
retry/validation counters, Dataset/KVS operations and change totals.
Daily/weekly schedule
First save and test one stable monitor input as an Apify Task. Then create a non-overlapping daily schedule in Console, or call the official schedule API (replace placeholders):
curl -X POST "https://api.apify.com/v2/schedules" \-H "Authorization: Bearer $APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"name": "Daily FDA drug supplier registration watchlist","isEnabled": true,"isExclusive": true,"cronExpression": "0 8 * * *","timezone": "UTC","actions": [{"type":"RUN_ACTOR_TASK","actorTaskId":"YOUR_TASK_ID"}]}'
For a Monday weekly review use 0 8 * * 1. Keep the same monitorId. FDA says DECRS is updated
each business day, so running more frequently than daily usually adds fixed download cost without
new official source state.
Webhook example
Attach a persistent successful-run webhook to the saved Task. The receiver reads the run's default
Dataset and handles rows whose change_type == "CHANGED" or whose alerts are non-empty:
curl -X POST "https://api.apify.com/v2/webhooks" \-H "Authorization: Bearer $APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"requestUrl": "https://procurement.example/webhooks/fda-supplier-change","eventTypes": ["ACTOR.RUN.SUCCEEDED"],"condition": {"actorTaskId":"YOUR_TASK_ID"},"payloadTemplate": "{\"run_id\":\"{{resource.id}}\",\"dataset_id\":\"{{resource.defaultDatasetId}}\"}","shouldInterpolateStrings": true,"description": "FDA supplier registration changes"}'
Also subscribe operational alerting to ACTOR.RUN.FAILED: failure means the current FDA snapshot
was not verified, not that every supplier disappeared.
Source freshness and validation
Runtime data comes from the official drls_reg.zip and drls_excluded.zip files on
accessdata.fda.gov. Live research found tab-delimited text inside both ZIPs; current text uses
Windows-1252, and the source includes a leading space in its first header plus a harmless trailing
empty field on each row.
Before matching, the Actor validates HTTP status/content type, download length, ZIP member count,
uncompressed-size bound, CRC, exactly one text member, required columns, encoding, every retained
business field, exclusion flags and non-trivial volume. The current snapshot must have at least
5,000 rows and 500 KiB of TSV data, and cannot fall below 50% of the last successful row count.
The excluded snapshot must have at least five rows; both snapshots reject a row-count drop below
50% of their last successful snapshot. These conservative guards can also reject a legitimate
large contraction, which requires source verification before changing the safety thresholds.
A safe single renamed .txt member is accepted with a warning; missing or ambiguous files fail.
Research and reproducible live facts are in experiments/fda-decrs/. No raw contact data or cookies
are committed.
Pricing
$0.01 per resolved supplier check. Platform usage is included. The same price applies across Apify plans; there is no subscription or run-start fee.
The PPE event is supplier_checked: one event for an input exactly matched to one
CURRENT or EXCLUDED FDA record, or for an authoritative NOT_FOUND after both official files
validate. Both are successfully resolved supplier checks. There is no charge for ambiguous or
invalid inputs, retries, source failures, internal file downloads, Dataset writes or KVS work.
UNCHANGED checks in monitor mode are charged: the value is a fresh, verified observation,
not a guaranteed change. onlyChanges reduces repeated details, not the number of checks or
their price. Duplicate entries are separate requested checks and are charged individually;
deduplicate your watchlist if you want one check per supplier.
| Resolved checks per run | Maximum event charge |
|---|---|
| 1 | $0.01 |
| 10 | $0.10 |
| 100 | $1.00 |
| 1,000 | $10.00 |
| 5,000 | $50.00 |
For example, 100 suppliers checked on four weekly runs cost at most $4; checked on
30 daily runs, at most $30. Failed, invalid and ambiguous checks reduce those totals.
The saved Console maximum total charge is $1 (up to 100 resolved checks).
API callers must set maxTotalChargeUsd explicitly, as in the example above:
the run API does not inherit that saved Console ceiling. Increase it deliberately
for a larger watchlist. Apify can lower the requested ceiling to
your account's available budget. Inputs beyond the effective ceiling receive a free
FAILED/UNKNOWN row with MAX_TOTAL_CHARGE_REACHED; their monitor state is not advanced.
Apify may mark a budget-exhausted run ABORTED, so inspect its Dataset and summary too.
An abrupt platform termination can interrupt delivery before all reconciliation rows persist.
Successful hosted tests on 2026-09-05 verified snapshot and repeat-monitor behavior at 256 MiB,
without a browser or proxy. Final per-run compute and platform usage costs settle after the
Actor finishes: read them from GET /v2/actor-runs/{runId}. The in-run RUN_SUMMARY leaves
computeUnits and platformCostUsd null rather than guessing those final values.
Interrupted runs
Do not resurrect a partially delivered run to obtain the remaining suppliers. A delivery
checkpoint prevents replaying potentially charged output: a completed run keeps its existing
results, and an interrupted delivery reports DELIVERY_UNCERTAIN without repeating charges.
Inspect the existing Dataset, then start a new run for the unresolved inputs. Keep the same
monitorId to retain the last successfully saved state. Never overlap runs for one watchlist.
Support
Use the Actor's Issues tab for support. Include the run ID, a public supplier identifier and the relevant error code. Do not post API tokens, private supplier lists or contact details.
Limitations and legal/privacy note
- DECRS does not include every FDA-related facility category. FDA specifically notes exclusions for human-drug compounding outsourcing facilities unless registered under another operation, and for wholesale distributors/third-party logistics providers reported under a different program.
- FDA says submitted registration/listing data is not product approval and may not have been verified by FDA.
- The excluded file proves only published excluded membership; it contains no reliable cause.
- Exact company-name matching can be ambiguous and is deliberately not fuzzy-resolved.
- Historical state is last-successful KVS state, not a historical database.
Legal/privacy risk is classified LOW: this is a public US government dataset, requires no login or access-control bypass, and the Actor minimizes output to establishment-registration fields. Users remain responsible for interpreting the signal correctly and for any downstream regulatory, procurement or import decision.