# FAA Aircraft Ownership & Registration Change Monitor (`automa-flow/faa-aircraft-registration-change-monitor`) Actor

Track known FAA aircraft by N-number and emit structured ownership, registration, certificate-expiration and deregistration changes from the official FAA releasable database.

- **URL**: https://apify.com/automa-flow/faa-aircraft-registration-change-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 $3.00 / 1,000 verified aircraft registration 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

## FAA Aircraft Ownership & Registration Change Monitor

Track the FAA aircraft you already know by **N-number**. Get the current public
registration, owner name, aircraft model and certificate expiry, then run the same
watchlist again to see verified changes with before-and-after values.

Use it for fleet registration reviews, ownership-record monitoring and certificate
expiry reminders. It reads the [official FAA aircraft registry download](https://www.faa.gov/licenses_certificates/aircraft_certification/aircraft_registry/releasable_aircraft_download).
It does not discover sales leads or search by owner name.

### Get your first results

1. Replace the sample N-numbers in **FAA aircraft watchlist** with your aircraft.
2. Give the list a **Monitor key**, such as `managed-fleet`. Keep this key for future checks.
3. Leave **Mode** as `snapshotAndChanges` and **Baseline mode** as `emitSnapshot`.
4. Use **512 MB**, a **300-second timeout** and a **$1 maximum charge** for this example. Two verified aircraft cost **$0.056**. Open **Observations and changes** when it finishes.

```json
{
  "monitorKey": "managed-fleet",
  "aircraft": [
    {"nNumber": "N12345", "externalId": "fleet-001"},
    {"nNumber": "N221DG", "externalId": "fleet-002"}
  ],
  "expiryWindowsDays": [365, 180, 90, 30],
  "mode": "snapshotAndChanges",
  "baselineMode": "emitSnapshot"
}
```

You can also enter a simple list: `["N12345", "N221DG"]`. The sample numbers are
public registry lookups, not aircraft endorsed by or affiliated with this Actor.

The first verified check returns a **BASELINE** for each aircraft. A later check
returns a **CHANGE** when facts or expiry thresholds change, or a **SNAPSHOT**
when the current observation is unchanged. Check `source_data_as_of` to see the
date of the FAA export; the result is not a live aircraft movement feed.

### Choose the right workflow

| Goal | Settings | What to expect |
| --- | --- | --- |
| Export current registrations | `snapshotAndChanges`, `emitSnapshot` | A current observation for every verified aircraft on each run |
| Receive changes for a stable fleet | `changesOnly`, `emitSnapshot` | Initial baselines, then changes and diagnostic rows |
| Start monitoring without initial alerts | `changesOnly`, `storeOnly` | Baselines saved silently; subsequent changes still appear |
| Review certificate expiry | `snapshotAndChanges`, thresholds such as `[90, 30]` | Expiry date and days remaining, plus threshold events |

A daily run with the same Monitor key is usually appropriate for this bulk
source. Add an Apify Schedule if you want automatic checks. The Actor does not
create schedules, send email or configure webhooks for you.

In `changesOnly` mode, an empty Dataset can be a successful check with no changes.
Open **Every input status** (`CHECKS`) and **Run summary** (`RUN_SUMMARY`) to confirm
what happened. Do not treat an empty Dataset as evidence that aircraft disappeared.

### Inputs

| Field | How to use it |
| --- | --- |
| `aircraft` | 1–2,000 N-number strings or objects with `nNumber` and optional `externalId`. Case, spaces and an omitted N-prefix normalize automatically. |
| `monitorKey` | A watchlist name using 1–80 letters, digits, underscores or hyphens. Use a different key for an independent comparison history. |
| `expiryWindowsDays` | 1–10 distinct integer thresholds from 1 to 1,825 days. Default: 365, 180, 90 and 30. |
| `mode` | `snapshotAndChanges` includes unchanged observations. `changesOnly` returns baselines, changes and diagnostics. The Console prefill uses the first; the API default is the second. |
| `baselineMode` | `emitSnapshot` returns the first observation. `storeOnly` saves it without a baseline row, including aircraft added later. |

Invalid entries receive their own error without blocking valid aircraft.
Duplicate N-numbers are compared once; `CHECKS` retains every submitted input,
its original index, duplicate reference and external ID. Dataset rows represent
the unique comparison, so use `CHECKS` to map duplicates back to your system.

Adding an aircraft creates its own baseline. Removing it from the list prunes its
stored comparison state after a verified source run. Adding it back later starts
a new baseline. Use one complete watchlist per key and avoid overlapping runs.

### Results and change events

The default Dataset contains N-number, manufacturer, model, serial number,
registered owner name, coarse mailing location, registration status, certificate
dates, days to expiry and observation metadata. Download results as JSON, CSV,
Excel or another supported format from Apify's export menu.

Use **Aircraft observations** for fleet exports, **Certificate expiry** for date
reviews, **Change events** for before-and-after values and **Verification details**
for errors. The Change events view expands event types; filter `record_type=CHANGE`
when your downstream workflow should receive change alerts only.

Events include owner and registration-status changes, certificate-date changes,
deregistration, N-number reassignment, expiry-window entry and certificate expiry.
Thresholds use the UTC observation date, so a date-based alert can occur even if
the FAA export itself is unchanged.

Example excerpt from **synthetic test data**, not actual ownership history:

```json
{
  "record_type": "CHANGE",
  "status": "SUCCESS",
  "source_id": "N221DG",
  "monitor_key": "synthetic-example",
  "change_types": ["OWNER_CHANGED"],
  "changes": {
    "owner_name": {
      "before": "PREVIOUS SYNTHETIC OWNER",
      "after": "SYNTHETIC AVIATION LLC"
    }
  }
}
```

Each observation includes a source URL, source date, observation time,
`schema_version`, `fingerprint` and `event_id`. An N-number can be reassigned to
a different aircraft. The Actor compares manufacturer code and serial number
and emits `N_NUMBER_REASSIGNED` without inventing a sale between different aircraft.

### Understand verification statuses

| Status | Meaning | Effect on comparison history |
| --- | --- | --- |
| `SUCCESS` | Public record and required comparison fields verified | Save the verified observation |
| `NOT_FOUND` | Number absent from validated public MASTER and DEREG files | Record public absence |
| `PARTIAL` | Selected information is ambiguous, malformed or unavailable | Keep the previous good observation |
| `SOURCE_FAILED` | Source download, freshness, schema or integrity could not be verified | Keep the previous good observation |
| `INVALID_INPUT` | Submitted entry is not a supported N-number input | No history update |
| `SKIPPED` in CHECKS | The run budget or pricing configuration prevented the check | No history update or Actor event fee |

`NOT_FOUND` does not prove deregistration or nonexistence. FAA allows owners to
withhold information from public dissemination. Missing owner information is
reported as `PARTIAL`, not an ownership change. A public record that reappears
gets a new verified baseline, not an unsupported re-registration claim.

Current MASTER records take priority over historic deregistrations. Stale archives
over seven days old, timestamp rollbacks and large record-count drops fail source
validation. A registry owner-name change is not proof of a sale, legal title,
beneficial ownership or airworthiness; verify consequential decisions with FAA.

### API and AI agent use

POST the input above with your Apify authorization header to:

```text
https://api.apify.com/v2/acts/automa-flow~faa-aircraft-registration-change-monitor/runs?timeout=300&memory=512&maxTotalChargeUsd=1
```

Use an asynchronous run and wait for completion. Then read the Dataset, `CHECKS`
and `RUN_SUMMARY` from its output links. For webhooks, handle both successful and
failed runs, and inspect the per-input statuses before changing your own records.
Deduplicate delivered observations by `event_id`.

For automatic daily checks, this [schedule API](https://docs.apify.com/api/v2/schedules-post)
body runs the example watchlist at 07:00 America/Chicago. Replace the watchlist
and key before creating it in your own account:

```json
{
  "name": "faa-managed-fleet-daily",
  "isEnabled": true,
  "isExclusive": true,
  "cronExpression": "0 7 * * *",
  "timezone": "America/Chicago",
  "actions": [{
    "type": "RUN_ACTOR",
    "actorId": "Nmi1L2VxdLWROcUQB",
    "runInput": {
      "body": "{\"monitorKey\":\"managed-fleet\",\"aircraft\":[\"N12345\",\"N221DG\"],\"mode\":\"changesOnly\",\"baselineMode\":\"emitSnapshot\",\"expiryWindowsDays\":[365,180,90,30]}",
      "contentType": "application/json; charset=utf-8"
    },
    "runOptions": {"build": "latest", "timeoutSecs": 300, "memoryMbytes": 512, "restartOnError": false}
  }]
}
```

Optional [webhook API](https://docs.apify.com/api/v2/webhooks-post) body for your
own receiver; replace the example URL:

```json
{
  "eventTypes": ["ACTOR.RUN.SUCCEEDED", "ACTOR.RUN.FAILED"],
  "condition": {"actorId": "Nmi1L2VxdLWROcUQB"},
  "requestUrl": "https://your-service.example/faa-run"
}
```

For an authenticated Apify MCP client, select this Actor with:

```text
https://mcp.apify.com?tools=automa-flow/faa-aircraft-registration-change-monitor
```

Example prompt: “Check N12345 and N221DG under managed-fleet. Report verified
registration changes and aircraft entering the 30-day expiry window.”

Private access requires the owning account or an authorized collaborator.
The Actor uses limited permissions for its own persistent storage.

### Runtime, limits and pricing

Every source check downloads and validates the complete FAA archive, even for one
N-number. Combine aircraft into a watchlist instead of starting one run per aircraft.
No browser or proxy is needed. Cloud validation at 512 MB includes the actual
two-aircraft Console example; allow several minutes for a full check.

**Pay per event: $0.05 per successful watchlist run + $0.003 per unique verified
N-number.** Platform usage is included in this price; there is no extra fee per
Dataset row. The Actor's Pricing tab shows the effective configuration.

| Unique verified aircraft | Maximum Actor event fees per run | 30 successful runs |
| ---: | ---: | ---: |
| 1 | $0.053 | $1.59 |
| 2 | $0.056 | $1.68 |
| 10 | $0.080 | $2.40 |
| 100 | $0.350 | $10.50 |
| 1,000 | $3.050 | $91.50 |
| 2,000 | $6.050 | $181.50 |

The `verified-aircraft-check` event includes a first baseline, an unchanged
observation and confirmed public absence (`NOT_FOUND`). You pay for a verified
check, even when `changesOnly` produces no Dataset rows. The
`verified-watchlist-run` fee applies only when at least one such check is saved
and available. If no checks can be verified, **both event fees are zero**.
Partial/failed checks, invalid inputs, duplicates and retries do not add fees.

Before downloading FAA data, the Actor checks the budget for every unique valid
number in the input. A smaller budget produces `BUDGET_EXCEEDED` and a `SKIPPED`
receipt for each valid input, with no source request, fee or history change.
A $1 limit supports up to 316 unique numbers. For 2,000 use at least $6.05;
$7 leaves a small allowance. The input limit bounds the event bill at $6.05 even
when no explicit charge limit is supplied. The actual bill is lower when some
checks are partial. A budget refusal does not claim the FAA source failed.

`RUN_SUMMARY` reports `billable_check_count`, `charged_event_counts`,
`charged_amount_usd` and `billing_status`. If a charge response is ambiguous,
the affected count and amount are `null`, not a false zero; inspect the original
run's Apify charge record. No recovery run retries that charge. If Apify accepts
only part of a charge, verified data remains available and unpaid work is not
billed again during recovery.

The input limit is 2,000 entries. Very large change histories can hit the 8 MiB
state-and-delivery limit earlier; split the watchlist if the Actor reports that
limit. Source download and parsing share a 240-second deadline. The work phase
has a 280-second limit, independent of a longer user timeout. Memory is fixed at
512 MB. Download, expanded-file and individual-record limits bound archive parsing.

### Privacy and interrupted runs

Only watched public records are retained. Street addresses are omitted, raw ZIP
files are temporary, and suppressed personal information is not reconstructed.
Owner and co-owner names plus coarse mailing location remain personal data in
some cases. Set appropriate Dataset retention and delete unused monitor state.

Comparison state lives in `faa-aircraft-registration-change-monitor-state` under
`FAA_MONITOR_STATE_V2_<hash-of-monitorKey>`. Output delivery uses a saved journal;
recovery can repeat an `event_id`, so consumers must deduplicate it. A recovery-only
run reports `recovery_only=true`; run again to check fresh source data.
Recovery-only delivery has **no additional Actor event fees**, including the run
fee. The original billing receipt is retained as `original_billing`. An unfinished
charge is never retried; unattempted charges for that delivery are waived.

A hard crash or timeout may leave a safety lock in
`faa-aircraft-registration-monitor-locks`. Before deleting the marker for the
affected Monitor key, stop every run using that key. Keep the baseline and pending
output in the key-value store. Restarting without clearing an uncertain lock fails
explicitly rather than allowing conflicting writers.

# Actor input Schema

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

Use one key per watchlist. The same key compares against its last verified state. Adding aircraft creates individual baselines; removing aircraft prunes their stored state.

## `aircraft` (type: `array`):

Watch 1–2,000 entries. Strings or {nNumber, externalId} objects. Invalid entries get their own status. Duplicate numbers are compared once; CHECKS retains a receipt for every original input.

## `expiryWindowsDays` (type: `array`):

Generate ENTERED\_<T>\_DAY\_EXPIRY\_WINDOW events when FAA days-to-expiry crosses one of these thresholds.

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

changesOnly emits baselines, changes and diagnostics. snapshotAndChanges also emits unchanged observations. CHECKS always contains every input status.

## `baselineMode` (type: `string`):

emitSnapshot returns an aircraft's first verified observation. storeOnly saves that baseline silently, including aircraft added later. It does not suppress subsequent snapshots or diagnostics.

## Actor input object example

```json
{
  "monitorKey": "faa-demo",
  "aircraft": [
    {
      "nNumber": "N12345",
      "externalId": "fleet-001"
    },
    {
      "nNumber": "N221DG",
      "externalId": "fleet-002"
    }
  ],
  "expiryWindowsDays": [
    365,
    180,
    90,
    30
  ],
  "mode": "snapshotAndChanges",
  "baselineMode": "emitSnapshot"
}
```

# Actor output Schema

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

No description

## `checks` (type: `string`):

Includes duplicates, invalid entries, unchanged aircraft and inputs skipped before source access.

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

Verification counts, accepted event charges, budget refusals and recovery status.

# 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 = {
    "monitorKey": "faa-demo",
    "aircraft": [
        {
            "nNumber": "N12345",
            "externalId": "fleet-001"
        },
        {
            "nNumber": "N221DG",
            "externalId": "fleet-002"
        }
    ],
    "mode": "snapshotAndChanges"
};

// Run the Actor and wait for it to finish
const run = await client.actor("automa-flow/faa-aircraft-registration-change-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 = {
    "monitorKey": "faa-demo",
    "aircraft": [
        {
            "nNumber": "N12345",
            "externalId": "fleet-001",
        },
        {
            "nNumber": "N221DG",
            "externalId": "fleet-002",
        },
    ],
    "mode": "snapshotAndChanges",
}

# Run the Actor and wait for it to finish
run = client.actor("automa-flow/faa-aircraft-registration-change-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 '{
  "monitorKey": "faa-demo",
  "aircraft": [
    {
      "nNumber": "N12345",
      "externalId": "fleet-001"
    },
    {
      "nNumber": "N221DG",
      "externalId": "fleet-002"
    }
  ],
  "mode": "snapshotAndChanges"
}' |
apify call automa-flow/faa-aircraft-registration-change-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automa-flow/faa-aircraft-registration-change-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/Nmi1L2VxdLWROcUQB/builds/wHkRv1EtAruWk8wIN/openapi.json
