# FCC Robocall Mitigation Database Checker & Change Monitor (`automa-flow/fcc-rmd-provider-monitor`) Actor

Check U.S. voice providers against the official FCC Robocall Mitigation Database (RMD) by RMD number, FRN or exact business name. Monitor listing, provider role, STIR/SHAKEN implementation and recertification changes without turning source failures into false absences.

- **URL**: https://apify.com/automa-flow/fcc-rmd-provider-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

$20.00 / 1,000 resolved provider 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

## FCC Robocall Mitigation Database Checker & Change Monitor

Check and monitor FCC Robocall Mitigation Database status across a provider portfolio.

Give it a watchlist of U.S. voice, gateway and intermediate providers. Each run downloads one
validated snapshot of the official FCC RMD current list, matches every provider by RMD number,
FRN or exact business name, and returns one explicit row per input: listed or not, provider
roles, STIR/SHAKEN implementation, recertification date, and in monitor mode exactly what
changed since the last successful check.

Also searched as: RMD lookup, FCC RMD API, robocall mitigation database check, STIR/SHAKEN
provider status, FRN lookup, KYUP counterparty check.

### Use from AI agents with MCP

Connect the public Actor directly at
`https://mcp.apify.com?tools=automa-flow/fcc-rmd-provider-monitor`. Ask your agent
to verify a provider portfolio and preserve the Actor's explicit `SUCCESS`,
`NOT_FOUND`, `AMBIGUOUS`, `FAILED` and `INVALID_INPUT` states in downstream
decisions.

### Why providers run this

Downstream providers use the RMD to decide whether traffic from an upstream partner may be
carried at all, and FCC rules require RMD filings to stay accurate and to be recertified each
year. Filings do get removed: during a single afternoon of source research, five providers
disappeared from the current list in four minutes, all of them without a recertification date.

Checking one provider by hand is easy. Checking 300 interconnect partners every morning, and
noticing the one that vanished overnight, is not.

### Primary use cases

1. **Bulk FCC RMD provider lookup** - resolve hundreds of providers in one run.
2. **Verify upstream and interconnect providers** before accepting or continuing traffic.
3. **Monitor provider listing changes** - catch a partner that disappears from the current list.
4. **Detect STIR/SHAKEN implementation changes** - complete, partial, none or not applicable.
5. **Track RMD recertification updates** as filings are recertified through the annual cycle.
6. **Feed changes into telecom compliance workflows** by webhook, schedule or the Apify API.

### Input

```json
{
  "providers": [
    { "rmdNumber": "RMD0001410", "reference": "upstream-001" },
    { "frn": "0018570812", "reference": "interconnect-002" },
    { "businessName": "Infobip Voice, Inc.", "reference": "name-review" }
  ],
  "mode": "snapshot"
}
```

Each provider needs at least one of `rmdNumber`, `frn` or `businessName`. `reference` is your
own key and is echoed back unchanged. Up to 5,000 providers per run.

| Field | Default | Meaning |
| --- | --- | --- |
| `providers` | required | 1-5,000 watchlist entries |
| `mode` | `snapshot` | `monitor` also returns changes since the last successful check |
| `monitorId` | none | Required in monitor mode; names the stored baseline |
| `onlyChanges` | `false` | Blanks details of unchanged providers, still one row per input |
| `includeAliases` | `true` | Other FRNs, other and previous d/b/a names |
| `includeBusinessAddress` | `false` | The filed company address |

#### Matching

`rmdNumber` is tried first, then `frn`, then an exact normalized `businessName`. Nothing is
fuzzy-matched. In the live registry 18 FRNs and 96 business names belong to more than one
current filing; those return `AMBIGUOUS` with `candidate_rmd_numbers`, so you can re-run
against the exact filing rather than trusting a guess.

### Output

One row per input provider, always, including invalid, ambiguous and failed checks.

```json
{
  "source": "fcc_rmd",
  "source_id": "RMD0001410",
  "source_url": "https://fccprod.servicenowservices.com/rmd?id=rmd_form&table=x_g_fmc_rmd_robocall_mitigation_database&sys_id=...&view=sp",
  "scraped_at": "2026-09-03T19:22:00Z",
  "schema_version": 1,
  "fingerprint": "5c1f...",
  "reference": "upstream-001",
  "status": "SUCCESS",
  "matched_by": "RMD_NUMBER",
  "listed": true,
  "rmd_number": "RMD0001410",
  "frn": "0021441233",
  "business_name": "Piratel llc",
  "country": "United States of America",
  "foreign_provider": false,
  "provider_roles": ["VOICE_SERVICE_PROVIDER", "GATEWAY_PROVIDER", "INTERMEDIATE_PROVIDER"],
  "stir_shaken_implementation": "COMPLETE",
  "last_updated": "2026-02-17",
  "last_recertified": "2026-02-17",
  "changed": false,
  "changes": [],
  "alerts": []
}
```

`status` is one of `SUCCESS`, `NOT_FOUND`, `AMBIGUOUS`, `FAILED` or `INVALID_INPUT`. These mean
different things and never collapse into each other:

- **`NOT_FOUND` with `listed: false`** is a verified absence: the snapshot downloaded, validated
  and did not contain that identifier.
- **`FAILED`** means the source could not be verified. It says nothing at all about whether the
  provider is listed, and it never overwrites a stored baseline.

Every row carries `scraped_at`, `schema_version` and a `fingerprint` over the regulatory fields
only, so rows are append-only observations you can diff, deduplicate and keep as history.

### Monitor mode

```json
{
  "providers": [{ "rmdNumber": "RMD0001410" }, { "frn": "0018570812" }],
  "mode": "monitor",
  "monitorId": "carrier-portfolio",
  "onlyChanges": true
}
```

The first run stores a baseline and reports `change_type: "BASELINE"` with `changed: false`.
Later runs compare against the last **successful** observation and emit deterministic events:

| Event | Meaning |
| --- | --- |
| `PROVIDER_NO_LONGER_LISTED` | Was in the current list, now absent |
| `PROVIDER_LISTED` / `PROVIDER_RELISTED` | First appearance, or a return after an absence |
| `ROLE_ADDED` / `ROLE_REMOVED` | Voice, gateway or intermediate role change |
| `IMPLEMENTATION_CHANGED` | STIR/SHAKEN implementation moved |
| `NEW_RECERTIFICATION_OBSERVED` | A recertification date appeared for the first time |
| `RECERTIFICATION_DATE_CHANGED` | The recertification date moved |
| `FILING_UPDATED` | The filing's last-updated date moved |
| `BUSINESS_NAME_CHANGED`, `FRN_CHANGED`, `COUNTRY_CHANGED`, `FOREIGN_PROVIDER_CHANGED` | Identity and jurisdiction |
| `ALIAS_ADDED` / `ALIAS_REMOVED`, `PREVIOUS_NAME_ADDED` / `PREVIOUS_NAME_REMOVED`, `OTHER_FRN_ADDED` / `OTHER_FRN_REMOVED` | d/b/a and related-FRN changes |
| `ADDRESS_CHANGED` | The filed company address changed |

A failed or ambiguous check never becomes a change event and never replaces the baseline, so a
bad source day cannot invent a wave of removals.

#### Schedule it

Create the run once, then schedule it in the Apify console:

- **Daily at 07:00 UTC** - `0 7 * * *`, `mode: "monitor"`, `onlyChanges: true`.
- **Weekly on Monday** - `0 7 * * 1` for a slower-moving portfolio.

The FCC publishes changes continuously, so daily is the useful cadence for interconnect
partners and weekly is usually enough for a vendor list.

#### Webhook on changes

Add an Actor webhook for `ACTOR.RUN.SUCCEEDED` pointing at your endpoint, then read the
change-only view:

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

Each unwound row is one change event with its provider, ready to post into a ticket, a Slack
channel or a compliance queue.

#### Call it from the API

```bash
curl -X POST "https://api.apify.com/v2/acts/<username>~fcc-rmd-provider-monitor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
        "providers": [{"rmdNumber": "RMD0001410"}, {"frn": "0018570812"}],
        "mode": "monitor",
        "monitorId": "carrier-portfolio"
      }'
```

Other useful views: `?view=alerts&clean=true` for `PROVIDER_NOT_LISTED` and
`IDENTIFIER_MISMATCH`, and `?view=diagnostics&clean=true` for status and error triage. The run
summary, including snapshot row count and validation warnings, is written to `RUN_SUMMARY` in
the run's key-value store.

### Pricing

Pay per event: **`provider_checked`, $0.02 per resolved provider**, about $20 per 1,000
providers.

A provider is charged at most once per run, and only when the run produced a verified answer
from a fully validated snapshot: a matched filing, or a confirmed absence from the current
list. A confirmed absence is charged because it is the answer carriers act on, and it takes the
same validated snapshot to establish.

Never charged: ambiguous identifiers, invalid input, retries, source failures, the snapshot
download itself, Dataset writes and Key-Value Store operations.

Platform usage is included in the event price. There is no run-start charge and no charge for
an Actor run that cannot produce a verified provider answer. A $2 maximum total charge funds
up to 100 resolved checks; the actual bill can be lower when an identifier is invalid or
ambiguous, or when the source fails.

Because one snapshot serves the whole watchlist, a run costs the same to the platform whether
it checks 1 provider or 5,000. Larger batches are dramatically better value per provider.

### Source and freshness

The Actor reads the FCC's public current-list CSV, the same file the RMD portal offers for
download. No login, no API key, no CAPTCHA, no browser and no proxy. One request per run,
requested compressed, roughly 1.2 MB on the wire for about 11,400 current filings.

Before a single provider is classified, the snapshot must pass validation: a complete
compressed stream verified against its CRC and length, the expected columns and known field
vocabulary, zero structurally unreadable rows, a minimum row count, and a comparison against
the previous run's row count. Invalid FRNs and unknown role, implementation, foreign-provider
or date values fail the run instead of being converted into a false regulatory change. A
row-count collapse
also fails rather than reporting that half the database was removed; additive schema drift and
smaller unusual row-count drops are reported as warnings in the run summary.

### Limits worth knowing

- This is an independent service and is **not affiliated with the FCC**. Data comes from the
  public FCC Robocall Mitigation Database.
- Being listed is not a compliance opinion, and absence from the current list is not proof of
  enforcement removal, voluntary withdrawal or wrongdoing. The Actor reports source facts and
  nothing beyond them. Output is informational and is **not legal advice**.
- Two thirds of current filings publish no recertification date, so the Actor exposes
  `last_recertified` and reports when it changes, but never infers an "overdue" verdict.
- Filing contact names, titles, departments, phone numbers, extensions, contact addresses and
  contact countries are published by the source but are **never** collected, returned or
  stored. The company address is available only if you switch `includeBusinessAddress` on.
- Robocall mitigation plan documents are not downloaded or analyzed.
- The RMD covers current filings only. This Actor does not submit or amend filings, and does
  not enrich from Form 499, enforcement dockets or the covered list.

# Actor input Schema

## `providers` (type: `array`):

One row per provider. The RMD number is tried first, then the FRN, then the exact normalized business name. Several matching filings are returned as AMBIGUOUS with candidate RMD numbers, never fuzzy-matched.

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

snapshot returns the current status of every provider. monitor also compares each provider with its last successful observation and returns deterministic change events.

## `monitorId` (type: `string`):

Required in monitor mode. Names the stored baseline so several watchlists can be monitored independently. 1-64 letters, digits, dots, underscores or hyphens.

## `onlyChanges` (type: `boolean`):

Monitor mode only. Unchanged providers still return one row each, with the descriptive fields blanked and details\_omitted set to true, so the batch stays one row per input.

## `includeAliases` (type: `boolean`):

Adds other\_frns, other\_dba\_names and previous\_dba\_names. The source stores these as free text, so names are split only on line breaks and semicolons; a comma-separated group stays one entry rather than being invented into several.

## `includeBusinessAddress` (type: `boolean`):

Off by default for data minimization. The company address helps tell apart providers that share a business name. Filing contact names, phone numbers and personal addresses are never returned in any mode.

## Actor input object example

```json
{
  "providers": [
    {
      "rmdNumber": "RMD0001410",
      "reference": "upstream-001"
    },
    {
      "frn": "0018570812",
      "reference": "interconnect-002"
    },
    {
      "businessName": "Infobip Voice, Inc.",
      "reference": "name-review"
    }
  ],
  "mode": "snapshot",
  "onlyChanges": false,
  "includeAliases": true,
  "includeBusinessAddress": false
}
```

# Actor output Schema

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

Exactly one row per input, including invalid, ambiguous and failed checks.

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

Flattened deterministic monitor changes, ready for webhook consumers.

## `alerts` (type: `string`):

Flattened PROVIDER\_NOT\_LISTED and IDENTIFIER\_MISMATCH alerts.

## `diagnostics` (type: `string`):

Failure-focused projection; filter status client-side.

## `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 = {
    "providers": [
        {
            "rmdNumber": "RMD0001410",
            "reference": "upstream-001"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("automa-flow/fcc-rmd-provider-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 = { "providers": [{
            "rmdNumber": "RMD0001410",
            "reference": "upstream-001",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("automa-flow/fcc-rmd-provider-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 '{
  "providers": [
    {
      "rmdNumber": "RMD0001410",
      "reference": "upstream-001"
    }
  ]
}' |
apify call automa-flow/fcc-rmd-provider-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automa-flow/fcc-rmd-provider-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/uXXtoWwtoc18RvcrU/builds/4Xsl4Odhb3CDUtAR7/openapi.json
