# FDA Wholesale Drug Distributor & 3PL Reporting Monitor (`automa-flow/fda-wdd-3pl-reporting-monitor`) Actor

Look up FDA wholesale drug distributor (WDD) and 3PL annual reporting records by license or facility name. Monitor reported expiration dates, DBAs and reporting changes across supplier lists. DSCSA reporting data only; verify state licensure separately.

- **URL**: https://apify.com/automa-flow/fda-wdd-3pl-reporting-monitor.md
- **Developed by:** [Vadim Bezrukov](https://apify.com/automa-flow) (community)
- **Categories:** Business, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 resolved target checks

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## FDA Wholesale Drug Distributor & 3PL Reporting Monitor

Screen and monitor wholesale drug distributors (WDD) and third-party logistics
providers (3PL) against FDA's official DSCSA annual-reporting database. Give it a
watchlist of licence numbers or facility names, and it tells you what FDA reports
today and exactly what changed since your last check.

> **This is federal reporting data, not an Authorized Trading Partner check.**
> This Actor monitors public FDA WDD/3PL annual-reporting records. Presence in, or
> absence from, this database is not by itself proof of current state licensure,
> FDA approval, regulatory compliance, or complete DSCSA Authorized Trading
> Partner status. FDA recommends checking applicable state licensure separately.
> Read [Limitations](#limitations) before you use this in an onboarding decision.

### What problem this solves

Under DSCSA, wholesale drug distributors and third-party logistics providers must
meet applicable licensure and reporting requirements, and FDA republishes their
annual reporting database **every business day**. If you buy, store or move
prescription drugs, you need to know when a facility you depend on stops
appearing, reports a different licence expiration, changes its trading name, or
files under a new reporting year.

Doing that by hand means re-searching FDA's web form facility by facility and
eyeballing the difference. This Actor turns that into a scheduled job: one
watchlist in, typed changes out.

Built for pharmaceutical manufacturers and repackagers, wholesale distributors,
3PLs, pharmacies and dispensers, procurement and supplier-onboarding teams, and
DSCSA compliance vendors and data teams.

### What the FDA WDD/3PL reporting database is

FDA's Drug Supply Chain Security Act annual-reporting database holds what
wholesale drug distributors and third-party logistics providers report to FDA
each year. Each row is **one licence for one facility for one reporting year**, so
a single facility commonly appears many times: once per state licence, and again
when it files for a new year.

- Official search page: <https://www.accessdata.fda.gov/scripts/cder/wdd3plreporting/>
- About the programme: <https://www.fda.gov/drugs/drug-supply-chain-security-act-dscsa/annual-reporting-prescription-drug-wholesale-distributors-and-third-party-logistics-providers>
- FDA guidance on checking licensure: <https://www.fda.gov/drugs/drug-supply-chain-integrity/check-licensure-wholesale-drug-distributors-and-third-party-logistics-providers>

The Actor reads FDA's own published bulk file, so it sees exactly what the search
page sees, all 38,000-odd rows at once, in one request.

### Use from AI agents with MCP

With access to this Actor, connect it directly at
`https://mcp.apify.com?tools=automa-flow/fda-wdd-3pl-reporting-monitor`. Ask your
agent to screen a supplier list and report MATCHED, NOT\_FOUND, AMBIGUOUS or a
source failure. The output is worded so an agent cannot turn a reporting record
into a licensure or compliance claim: nothing in it says "approved", "licensed"
or "compliant".

Execution requires the caller's own Apify OAuth or token. Authenticated MCP tool
discovery and direct API execution with limited permissions were verified on
2026-09-07. Execution through agentic payment providers is not separately tested.

### Quickstart

Watch two facilities, one by licence and one by name:

```json
{
  "targets": [
    {"licenseState": "US-OH", "licenseNumber": "WHO.0008724", "reference": "supplier-001"},
    {"facilityName": "AdiraMedica LLC", "facilityState": "PA", "reference": "supplier-002"}
  ],
  "monitorKey": "pharma-suppliers-prod"
}
```

The first run stores a baseline and publishes what FDA reports today. Every later
run with the same `monitorKey` publishes only what changed.

The Console demo preselects `snapshotAndChanges`, so repeated demo runs still
show current records. Select `changesOnly` for a scheduled watchlist. API calls
that omit `mode` default to `changesOnly`.

### Sample output

A matched licence, on a first run:

```json
{
  "record_type": "BASELINE",
  "status": "SUCCESS",
  "reference": "supplier-3pl-001",
  "target_key": "LICENSE|US-IN|94000227A|*",
  "target_type": "LICENSE",
  "match_status": "MATCHED",
  "record_key": "0f1c...",
  "facility_name": "AdiraMedica LLC",
  "dba_names": [],
  "facility_type": "3PL",
  "license_number": "94000227A",
  "license_state": "US-IN",
  "license_expiration_date": "2026-09-30",
  "license_expired": false,
  "days_until_license_expiration": 24,
  "reporting_year": 2026,
  "facility_street": "585 Turner Industrial Way",
  "facility_city": "Aston",
  "facility_state": "PA",
  "change_types": [],
  "changes": null,
  "source": "fda_wdd_3pl_reporting",
  "source_snapshot_date": "2026-09-04",
  "scraped_at": "2026-09-06T20:27:13Z",
  "schema_version": 1,
  "fingerprint": "8a3f..."
}
```

A licence renewal on a later run:

```json
{
  "record_type": "CHANGE",
  "status": "SUCCESS",
  "reference": "supplier-3pl-001",
  "change_types": ["LICENSE_EXPIRATION_CHANGED"],
  "changes": {
    "licenseExpirationDate": {"previous": "2026-09-30", "current": "2027-09-30"}
  },
  "license_expiration_date": "2027-09-30",
  "source_snapshot_date": "2026-09-11"
}
```

`examples/sample_input.json` and `examples/sample_output.json` hold a complete run
covering every outcome, including not-found, ambiguous and invalid targets.

### Watching exact licences

The precise way to watch a supplier. `licenseState` accepts `US-OH` or `OH`;
`licenseNumber` must be exactly as FDA publishes it.

```json
{
  "targets": [
    {"licenseState": "US-OH", "licenseNumber": "WHO.0008724", "reference": "ohio"},
    {"licenseState": "US-CO", "licenseNumber": "TPLP.0000067", "reference": "colorado"}
  ],
  "monitorKey": "pharma-suppliers-prod"
}
```

Case and surrounding whitespace are normalized. Punctuation is **not** stripped,
because `WHO.0008724` and `WHO0008724` are different licences.

One thing the live data will surprise you with: a licence number is not globally
unique. 182 `(state, number)` pairs in the current file are reported under more
than one facility name, and 227 span both WDD and 3PL. A licence target returns
**all** of its rows and tells you how many distinct facilities that is, in
`matched_facility_count`. It never picks one for you.

### Watching facility names

Use this when you have a name but no licence number.

```json
{
  "targets": [
    {"facilityName": "AdiraMedica LLC", "reference": "adira"},
    {"facilityName": "Frontier Scientific Solutions, LLC", "facilityState": "NC", "reference": "frontier"}
  ],
  "monitorKey": "pharma-suppliers-prod"
}
```

Names match exactly after Unicode, case, punctuation and whitespace
normalization. There is no fuzzy matching and no entity resolution, so
`AdiraMedical LLC` will not match `AdiraMedica LLC`; it returns `NOT_FOUND`.

If one name is reported by several distinct facilities, the result is
`AMBIGUOUS`, not a guess. The row lists the candidate addresses so you can pick
one, and **ambiguous targets are never charged**. In the current file, 1,281 of
1,463 distinct names resolve to exactly one facility; `facilityState` narrows most
of the rest.

A facility with many state licences is *not* ambiguous. It returns one row per
licence and is charged once.

### Change monitoring

Reuse the same `monitorKey` on a schedule. Each run compares against the last
**successful** observation for that key.

```json
{
  "targets": [{"licenseState": "US-OH", "licenseNumber": "WHO.0008724", "reference": "supplier-001"}],
  "monitorKey": "pharma-suppliers-prod",
  "mode": "changesOnly",
  "firstRunBehavior": "emitCurrent"
}
```

| Change type | Means |
| --- | --- |
| `REPORTING_RECORD_ADDED` | A reporting row appeared that was not in the previous validated snapshot |
| `REPORTING_RECORD_REMOVED` | A reporting row that was in the previous validated snapshot is absent from the current one |
| `LICENSE_EXPIRATION_CHANGED` | The reported expiration date on an existing row changed |
| `DBA_CHANGED` | The reported doing-business-as names changed |
| `REPORTED_LICENSE_EXPIRATION_REACHED` | A reported expiration date moved into the past since your last run |
| `REPORTING_YEAR_CHANGED` | The latest reporting year for this target advanced |
| `FACILITY_NAME_CHANGED` | The facility name reported under this target changed |
| `FACILITY_ADDRESS_CHANGED` | The reported facility address changed |
| `FACILITY_TYPE_CHANGED` | The facility is now reported under a different type |
| `BECAME_FOUND` / `BECAME_NOT_FOUND` | The target appeared in, or disappeared from, the reporting database |

**Read `REPORTING_RECORD_REMOVED` literally.** It means the row was in the
previous successful FDA snapshot and is not in the current successfully validated
one. It does **not** mean the licence was revoked, that the facility is
unlicensed or non-compliant, or that it is no longer an Authorized Trading
Partner. Likewise `REPORTED_LICENSE_EXPIRATION_REACHED` is arithmetic on a date
the facility reported to FDA; it does not replace a state-board licence check.

There is **no** disciplinary-action change type, because FDA publishes no
disciplinary-action field in this database, in either the bulk file or the search
UI. The Actor does not invent one.

### Schedules, webhooks, API and MCP

**Schedule.** Create an Apify schedule with cron `0 6 * * 1-5` (weekdays 06:00
UTC) so it runs shortly after FDA's business-day update, on a Task holding your
watchlist and `monitorKey`. In `changesOnly` mode a quiet day writes no rows,
which is a successful run, not a failure.

**Webhook.** Point a `ACTOR.RUN.SUCCEEDED` webhook at your endpoint and read the
`changes` view; every row is already an alert payload with stable ids, previous
and current values, and the snapshot date it came from.

```text
https://api.apify.com/v2/datasets/{datasetId}/items?view=changes&clean=true
```

**API.** Run it synchronously and read the Dataset:

```bash
curl -X POST "https://api.apify.com/v2/acts/automa-flow~fda-wdd-3pl-reporting-monitor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "targets": [{"licenseState": "US-OH", "licenseNumber": "WHO.0008724", "reference": "supplier-001"}],
    "monitorKey": "pharma-suppliers-prod",
    "mode": "snapshotAndChanges"
  }'
```

**MCP.** `https://mcp.apify.com?tools=automa-flow/fda-wdd-3pl-reporting-monitor`

### Pricing

Pay per event:

| Event | Price | When |
| --- | --- | --- |
| `monitor-run` | $0.025 | Once per run, after the FDA bulk file downloads and passes validation |
| `target-checked` | $0.010 | Once per unique target resolved conclusively: `MATCHED` or `NOT_FOUND` |

You are charged for the **check**, not for the row. A target that matches 40
state licences costs the same as one that matches one, and an unchanged recheck
that publishes nothing is still one completed check.

Never charged: ambiguous names, invalid targets, duplicate targets, retries,
source failures, rejected snapshots, and targets beyond the run's charge limit.

| Watchlist | Weekly | Monthly |
| --- | --- | --- |
| 100 suppliers | $1.025 | ~$4.10 |
| 1,000 suppliers | $10.025 | ~$40.10 |
| 10,000 suppliers | $100.025 | ~$400.10 |

Measured locally on 2026-09-07 by replaying a saved full snapshot (38,030 rows):
1.79 s to parse and 0.44 s to match 10,000 targets, with 33.1 MB of peak traced
Python allocations. This is not total process memory. Replay makes no HTTP
requests; normal execution downloads the FDA file once. See
`examples/benchmark.json`. These measurements exclude Actor boot, storage and
monitor-lock API calls. Five hosted checks on 2026-09-07 completed in 5.69–17.74 seconds. Platform usage
was $0.00054 for one target and $0.00210 for 100 targets. These are measured
validation workloads, not guarantees for every input; final usage settles after
a run and should be read from the Apify run API.

### Source freshness

Every row carries `source_snapshot_date`, taken from the bulk file's
`Last-Modified` header, so you always know which FDA publication an observation
came from. FDA updates the file every business day. The run summary warns with
`SNAPSHOT_STALE` if the file is more than seven days old, without treating age
alone as a withdrawal. A publication older
than the last accepted `Last-Modified` is rejected with
`SNAPSHOT_DATE_REGRESSED`, including regressions within the same day. A missing
or invalid timestamp cannot replace a previously dated snapshot.

#### Comparison scope and overlapping runs

Each `monitorKey` and normalized `facilityTypes` selection has its own baseline.
Omitting `facilityTypes` or passing `[]` selects both types. Changing a filter
starts that filter's baseline; returning to a previously used filter resumes its
history. Configuration changes therefore do not produce supplier removals.

The corrected version uses a new state namespace because earlier state did not
record the matching filter. The first run after upgrading creates a baseline
according to `firstRunBehavior`; old state is retained but is not compared.

Runs sharing a comparison scope execute exclusively. A concurrent attempt
returns `MONITOR_BUSY` without reading shared state, downloading FDA data or
charging events. Retry after the active run finishes. In Apify, this uses one
unhandled semaphore request in a named request queue and the platform's atomic
[request lock](https://docs.apify.com/api/v2/request-queue-head-lock-post).
The semaphore URL is never fetched. Local runs use an OS file lock in their
configured storage directory.

Work inside the lock has a 15-minute deadline, inside a one-hour cloud lease.
Normal completion releases the lock; after a crash or a failed unlock, another
run may need to wait until the lease expires. Do not manually clear a lock while
its owner is running. Lock API failure aborts execution without an unlocked
fallback. Interrupted delivery keeps the existing checkpoint safeguards.
Cloud coordination adds four unbilled queue API calls per completed run; these
are separate from the one FDA download and are excluded from the local benchmark.

### Failure semantics

**`NOT_FOUND` is never `SOURCE_FAILED`.** A target is reported `NOT_FOUND` only
when the FDA file downloaded, decoded, matched the expected 13-column schema,
cleared the row-count and licence-coverage floors, ended with a complete line
terminator, and was matched in full.

Anything else is a `FAILED` row with a machine-readable reason and a failed run:
timeouts, 429/5xx after the retry budget, an HTML page served instead of data, a
truncated download, missing or renamed required columns, an implausible row-count
collapse, an unknown facility type, conflicting values for one record identity,
an older publication, or a row the schema cannot interpret. Identical semantic
duplicate rows are collapsed before matching; conflicting duplicates are rejected
regardless of their order in the file.

When the source fails:

- no target is reported as absent;
- no change event is produced;
- the last good state for every target is left untouched;
- nothing is charged.

A truncated or collapsed snapshot therefore cannot produce thousands of false
`REPORTING_RECORD_REMOVED` events. That is the guarantee this Actor is built
around, and it is covered by tests.

### Privacy and the fields you get

FDA publishes a facility contact **name, phone number and email** on every row.
This Actor does not need them to answer "did this supplier's reported licensing
information change", so they are **dropped at parse time**: never stored, never
published, never logged, and replaced with placeholders in the test fixtures.

You get: facility name, DBA names, facility type, licence number, licence state,
reported licence expiration, reporting year, and the facility's public business
address. Street is null for about 9% of live rows, where FDA publishes none.

### Limitations

- **Not an ATP verifier.** FDA tells you to check both applicable state licensure
  *and* this reporting database. This Actor does one of those two. It does not
  join state-board licence sources, and it does not handle ATP digital
  credentials.
- **Reported, not verified.** Every value is what the facility reported to FDA. A
  reported expiration date is not a state board's current licence status, and the
  source contains placeholder dates such as 1901-01-01 and 2049-12-31.
- **A submission log, not a registry.** Rows are per reporting year, so a facility
  that filed in 2025 and again in 2026 has rows for both.
- **Exact matching only.** No fuzzy matching, no entity resolution, no aliases
  beyond FDA's own DBA field. A misspelled name returns `NOT_FOUND`.
- **US only**, and only the two facility types FDA publishes here: WDD and 3PL.
- **Watchlist size.** Up to 10,000 targets per run. Monitoring state is stored per
  `monitorKey`; a watchlist whose stored state grows beyond the per-key limit
  fails loudly with `STATE_TOO_LARGE` rather than silently losing history. Split
  it across several `monitorKey` values if you hit that.
- Old targets you stop watching keep their stored state under that `monitorKey`.
  Use a fresh key to start clean.

### Technical source details

| | |
| --- | --- |
| Source file | `https://www.accessdata.fda.gov/cder/wdd_3pl_facilities_report.txt` |
| Format | Tab-separated, CRLF, Windows-1252, 13 columns, no quoting |
| Size | 6.2 MB raw, 536 KB gzipped, 38,030 rows (2026-09-06) |
| Requests per run | 1 |
| Authentication | None |
| Proxy | None |
| Browser | None |
| Update cadence | Every business day |

Record identity is a SHA-256 over facility type, licence state, licence number,
facility name, street, city, facility state and reporting year. Those eight
fields were verified unique across all 38,030 live rows; the three-field identity
that looks natural (licence state, licence number, type) collides on 290 keys.
Row position is never used as identity.

Every row is an append-only observation with `scraped_at`, `schema_version` and a
`fingerprint` over the normalized reported fields only, so rows captured months
apart stay comparable.

### Support

Open an issue on the Actor's Apify page. For a source-caused bug, include the
`RUN_SUMMARY` record from the run's key-value store: it carries the snapshot
date, row count, schema signature, file hash and any warnings.

### Saved workflow examples

- [Look up a WDD by license](https://apify.com/automa-flow/fda-wdd-3pl-reporting-monitor/examples/fda-wholesale-distributor-license-lookup): replace the sample state and license number.
- [Look up a 3PL by facility name](https://apify.com/automa-flow/fda-wdd-3pl-reporting-monitor/examples/fda-3pl-facility-name-lookup): replace the exact reported facility name.
- [Monitor supplier reporting changes](https://apify.com/automa-flow/fda-wdd-3pl-reporting-monitor/examples/monitor-fda-wdd-3pl-supplier-reporting-changes): replace the watchlist and reuse its monitor key.

Each example has a $0.10 event-charge cap, 512 MB memory and a five-minute timeout.
They create no schedule automatically. Lookup examples publish current records
on repeat runs; the monitor emits the first baseline and later changes or
unresolved targets. A verified unchanged monitor can have an empty Dataset;
check RUN\_SUMMARY for completed and charged checks.

# Actor input Schema

## `targets` (type: `array`):

One entry per facility or licence you want screened. A licence target needs licenseState and licenseNumber; a name target needs facilityName and matches exactly after case, punctuation and whitespace normalization. Identical targets are de-duplicated and charged once.

## `monitorKey` (type: `string`):

Names the stored comparison state. Reuse the same key on every scheduled run so changes are detected against that watchlist's own history. 1-80 letters, digits, underscores or hyphens.

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

changesOnly publishes only baselines, changes and unresolved targets, which is what a scheduled monitor wants. snapshotAndChanges also republishes the current reported records for every matched target on every run.

## `firstRunBehavior` (type: `string`):

emitCurrent publishes what FDA reports today, so the first run is immediately useful. baselineOnly stores the baseline silently and publishes nothing until something changes. Both are charged, because the screening happened either way.

## `facilityTypes` (type: `array`):

Restrict matching to wholesale drug distributors, third-party logistics providers, or both. These are the only two values FDA publishes. Leave empty for both.

## Actor input object example

```json
{
  "targets": [
    {
      "licenseState": "US-OH",
      "licenseNumber": "WHO.0008724",
      "reference": "supplier-001"
    },
    {
      "facilityName": "AdiraMedica LLC",
      "facilityState": "PA",
      "reference": "supplier-002"
    }
  ],
  "monitorKey": "default",
  "mode": "snapshotAndChanges",
  "firstRunBehavior": "emitCurrent",
  "facilityTypes": [
    "WDD",
    "3PL"
  ]
}
```

# Actor output Schema

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

Every row this run produced, including not-found, ambiguous, invalid and failed targets.

## `changes` (type: `string`):

Flattened semantic changes, ready to send to a webhook. Empty when nothing changed.

## `observations` (type: `string`):

Current reported records for every matched target.

## `unresolved` (type: `string`):

Targets that produced no reported record, with the reason for each.

## `expiring` (type: `string`):

Reported licence expiration dates and days remaining.

## `runSummary` (type: `string`):

Counts, snapshot date, row count, warnings and billing for this 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 = {
    "targets": [
        {
            "licenseState": "US-IN",
            "licenseNumber": "94000227A",
            "reference": "supplier-3pl-001"
        },
        {
            "facilityName": "AdiraMedica LLC",
            "reference": "supplier-name-001"
        }
    ],
    "mode": "snapshotAndChanges"
};

// Run the Actor and wait for it to finish
const run = await client.actor("automa-flow/fda-wdd-3pl-reporting-monitor").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 = {
    "targets": [
        {
            "licenseState": "US-IN",
            "licenseNumber": "94000227A",
            "reference": "supplier-3pl-001",
        },
        {
            "facilityName": "AdiraMedica LLC",
            "reference": "supplier-name-001",
        },
    ],
    "mode": "snapshotAndChanges",
}

# Run the Actor and wait for it to finish
run = client.actor("automa-flow/fda-wdd-3pl-reporting-monitor").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 '{
  "targets": [
    {
      "licenseState": "US-IN",
      "licenseNumber": "94000227A",
      "reference": "supplier-3pl-001"
    },
    {
      "facilityName": "AdiraMedica LLC",
      "reference": "supplier-name-001"
    }
  ],
  "mode": "snapshotAndChanges"
}' |
apify call automa-flow/fda-wdd-3pl-reporting-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automa-flow/fda-wdd-3pl-reporting-monitor"
        }
    }
}

```

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/4zqEoBYMjomoe3IGe/builds/eU8ghZkU4gEp0a25x/openapi.json
