# USPTO Patent Ownership & Assignment Monitor (`automa-flow/uspto-patent-assignment-monitor`) Actor

Monitor patents, applications and companies for newly recorded USPTO assignment and ownership events. Compare official Assignment Center records with last successful state and emit typed conveyance alerts.

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

## Pricing

from $2.00 / 1,000 verified uspto assignment 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?

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

## USPTO Patent Ownership & Assignment Monitor

Monitor patents, applications and companies for newly recorded USPTO ownership
and assignment events. Get deterministic alerts for assignments, mergers,
security interests, name changes and other recorded conveyances. Each run checks
the public histories again and compares them with the last saved observations.
Changes-only output reduces repeated exports, not source requests.

Use it for patent-portfolio reviews, IP operations and competitor monitoring.
It saves the last verified state for each watchlist and reads public [USPTO Assignment Center](https://assignmentcenter.uspto.gov/search/patent)
JSON. A USPTO recordation is evidence of a recorded document; it does not prove
perfect legal title, and delayed or corrective filings exist.

### Get your first results

1. Keep or replace the sample patent number **10277785**.
2. Set a **Monitor key**, such as `portfolio`. Reuse it on every later run.
3. Leave **Mode** as `watchlist`, **Changes only** off for the demo, and **Baseline mode** as `emitSnapshot`.
4. Use **512 MB**, a **300-second timeout** and a **$1 maximum charge**. Open **Observations and changes** when it finishes.

```json
{
  "mode": "watchlist",
  "monitorKey": "portfolio",
  "patentNumbers": ["10277785"],
  "applicationNumbers": [],
  "publicationNumbers": [],
  "companies": [],
  "conveyanceTypes": [],
  "changesOnly": false,
  "baselineMode": "emitSnapshot",
  "lookbackDays": 90
}
```

The first verified check returns a **BASELINE** for each target, even when
`changesOnly` is true. After a complete baseline, a later check returns a **CHANGE** when a new reel/frame
appears or a stored assignment record is updated. The demo also returns
SNAPSHOT rows on unchanged runs. Turn `changesOnly` on for alert workflows;
unchanged runs can then have an empty Dataset; **Every input status** (`CHECKS`) still has one receipt per input.

If the initial history is `PARTIAL`, newly discovered records remain **BASELINE**
until the first complete check is saved. Filling a gap in old history is not a
new assignment alert and has no CHANGE fee. Updates to previously observed
records are still detected. `CHECKS.baseline_complete` reports whether that
initial history has been verified; a permanently truncated company search may
never complete it. Prefer patent or application numbers for complete coverage.

### Choose the right workflow

| Goal | Settings | What to expect |
| --- | --- | --- |
| Portfolio patents | patent numbers, `changesOnly` | Baseline, then new recorded assignments |
| Competitor names | companies with aliases, 90-day lookback | Exact-normalized assignee/assignor hits |
| Application docket | application numbers | Application-side recorded transfers |

Prepared examples cover a patent portfolio, competitor conveyances and a
single assignee. Company examples use Pacific Biosciences and a 365-day window;
replace that public sample with your own exact names. Task links become
available after the examples are published.

Add an Apify Schedule if you want automatic checks. The Actor does not create
schedules, send email or configure webhooks for you.

### Inputs

| Field | How to use it |
| --- | --- |
| `mode` | `watchlist` only. Daily bulk XML is not offered: USPTO PASDL now requires a login, so that mode would fail every run. |
| `monitorKey` | 1–80 letters, digits, `_` or `-`. One comparison history per key. |
| `patentNumbers` | Up to 1,000 granted patent numbers. A `US` prefix is stripped, including `USD…`, `USRE…` and `USPP…`. RE/PP numbers accept five digits, such as `RE45824` and `PP33095`. |
| `applicationNumbers` | Up to 1,000 application numbers. |
| `publicationNumbers` | Up to 1,000 publication numbers such as `US20180191929A1`. |
| `companies` | Up to 200 `{name, role, aliases, match}` objects. Default match is exact. |
| `conveyanceTypes` | Optional category filter. Empty keeps every recorded type, including `OTHER`. |
| `changesOnly` | Hide unchanged SNAPSHOT rows after the baseline. |
| `baselineMode` | `emitSnapshot` returns the first observation. `storeOnly` saves it silently. |
| `lookbackDays` | 1–366, default 90. Bounds **company** searches only. |

Malformed patent, application and publication strings get their own status.
Invalid global options or malformed company objects reject input before source access.
Duplicate normalized identifiers are compared once; `CHECKS` keeps every original
input. Company history is keyed by normalized name, role, match mode and aliases,
so an assignee watch and an assignor watch for the same company do not share
state. Company matching never equates IBM with International Business Machines
unless you add that alias. `contains` filters locally after an exact name search;
it does not discover similar company names. Add aliases for every spelling
you accept. Company lookback drops assignments without a recorded date.

**Company coverage is bounded.** USPTO may return an incomplete historical
window for large names before reaching recent records. The local recorded-date
filter cannot recover omitted pages. Such checks are `PARTIAL`; without any
matching observations they return `INCOMPLETE`, preserve history and incur no
custom check fee. Use known patent or application numbers when company coverage
is insufficient. Exact names and aliases do not imply subsidiary coverage.

### Results and change events

Each Dataset row is an observation of one assignment at `scraped_at`. Stable
identity is **reel/frame** (`assignment_id` such as `47086/0788`). Filter
`record_type=CHANGE` for alerts. First-run `BASELINE` rows are not a claim that
a transfer just happened.

```json
{
  "record_type": "CHANGE",
  "status": "SUCCESS",
  "change_types": ["NEW_ASSIGNMENT", "PATENT_TRANSFER_RECORDED"],
  "assignment_id": "99999/0001",
  "recorded_date": "2026-09-01",
  "conveyance": {
    "category": "ASSIGNMENT",
    "code": 23,
    "text": "ASSIGNMENT OF ASSIGNOR'S INTEREST"
  },
  "assignors": ["SYNTHETIC ASSIGNOR LLC"],
  "assignees": ["EXAMPLE TECHNOLOGY INC"],
  "patent_numbers": ["10277785"],
  "matched_targets": ["patent:10277785"]
}
```

The excerpt is **synthetic fixture data**, not a live inventor or owner history.
Default output keeps party **names** and omits street addresses, correspondent
details, inventors and attorney docket numbers.

Events include `NEW_ASSIGNMENT`, `NEW_ASSIGNEE`, `NEW_ASSIGNOR`,
`PATENT_TRANSFER_RECORDED`, `APPLICATION_TRANSFER_RECORDED`, `MERGER_RECORDED`,
`NAME_CHANGE_RECORDED`, `SECURITY_INTEREST_RECORDED`, `LIEN_RECORDED`,
`LICENSE_RECORDED`, `RELEASE_RECORDED`, `CORRECTIVE_ASSIGNMENT_RECORDED` and
`ASSIGNMENT_RECORD_UPDATED`. Unknown conveyance text stays `OTHER`.

### Understand verification statuses

| Status | Meaning | Effect on comparison history |
| --- | --- | --- |
| `SUCCESS` | Assignment Center returned a verified body | Save observed assignments |
| `NOT_FOUND` | Message `No assignments found` | Record verified absence |
| `PARTIAL` | Truncation, a missing page, the assignment cap, undated company records or a failed name search | Save matching observations only; preserve history if none were verified |
| `UNRESOLVED_TARGET` | Integrity answer for an identifier the index will not resolve, after a known control identifier still answers | No history update; the run stays `PARTIAL` and succeeds |
| `SOURCE_FAILED` | HTTP error, HTML body, invalid party structure, an integrity failure while the index itself is down, login wall, a PASDL page without dated zip files, or a vanishing history | Keep the last good state; the run fails only when every check is a source failure |
| `INVALID_INPUT` | Identifier or company name could not be normalized | No history update |
| `SKIPPED` | Budget, pricing configuration or the source time budget prevented verification | No history update or custom fee; a time-limited check may have started a request before stopping |

`NO_RESULTS` is never turned into `SOURCE_FAILED`, and a failed check never
overwrites good state. Absence of a previous assignee from a new document is not
an ownership reversal.

### API, schedules and AI agents

POST the input above with your Apify authorization header to:

```text
https://api.apify.com/v2/acts/automa-flow~uspto-patent-assignment-monitor/runs?timeout=300&memory=512&maxTotalChargeUsd=1
```

For automatic weekday checks, this [schedule API](https://docs.apify.com/api/v2/schedules-post)
body runs the sample patent at 07:00 America/New\_York. Replace the watchlist
before creating it in your own account:

```json
{
  "name": "uspto-portfolio-daily",
  "isEnabled": true,
  "isExclusive": true,
  "cronExpression": "0 7 * * 1-5",
  "timezone": "America/New_York",
  "actions": [{
    "type": "RUN_ACTOR",
    "actorId": "automa-flow/uspto-patent-assignment-monitor",
    "runInput": {
      "body": "{\"mode\":\"watchlist\",\"monitorKey\":\"portfolio\",\"patentNumbers\":[\"10277785\"],\"applicationNumbers\":[],\"publicationNumbers\":[],\"companies\":[],\"conveyanceTypes\":[],\"changesOnly\":true,\"baselineMode\":\"emitSnapshot\",\"lookbackDays\":90}",
      "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; replace
the example URL:

```json
{
  "eventTypes": ["ACTOR.RUN.SUCCEEDED", "ACTOR.RUN.FAILED"],
  "condition": {"actorId": "automa-flow/uspto-patent-assignment-monitor"},
  "requestUrl": "https://your-service.example/uspto-assignment-run"
}
```

Handle both successful and failed runs. Inspect per-input statuses before
changing your own records. Deduplicate by `event_id`.

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

```text
https://mcp.apify.com?tools=automa-flow/uspto-patent-assignment-monitor
```

Example prompt: “Watch patent 10277785 under monitor key portfolio and report
any newly recorded USPTO assignments since the last successful state.”

### Runtime, limits and pricing

Watchlist checks are sequential HTTP JSON calls. No browser or proxy is used.
The Actor normally stops source work after about 240 seconds, leaving 40 seconds
for delivery and state, plus time for shutdown before the 300-second default
timeout. A shorter configured cloud timeout reduces this window. Completed
observations are saved; unverified inputs get `SKIPPED / RUN_TIME_LIMIT`, and the
run summary is `PARTIAL`. For repeated time limits, split into smaller stable
watchlists with a distinct `monitorKey` for each; each new key creates a baseline.
Reusing an existing key with fewer targets removes the excluded targets' history.
Increasing the Console timeout does not extend the internal 280-second limit.
Company-name responses can exceed a megabyte; lookback and a 500-assignment cap
bound stored state. On a complete `SUCCESS` check, older IDs that USPTO no longer
returns may be dropped so a target stays within 500 stored assignments (`PARTIAL`).
Split a watchlist if state exceeds 8 MiB. `dailyFeed` XML is streamed with a
64 MiB cap; JSON search bodies stay at 8 MiB.

**Pay per event: $0.00005 per Actor start + $0.002 per unique verified target
check + $0.02 per unique CHANGE assignment ID. Platform usage is included.**

A baseline or quiet run for one patent costs $0.00205; 20 verified targets cost
$0.04005 without changes, or $0.08005 with two unique changed assignment IDs.
A daily 20-target watchlist without changes costs about $1.20 over 30 runs.
Confirmed `NOT_FOUND` and unchanged checks are billable. A `PARTIAL` check is
billable only when matching observations are retained.

Retries, source failures, unresolved identifiers, skipped inputs, invalid inputs, incomplete checks without matching
observations, duplicates and recovery delivery have no custom fees. Baseline
rows, including historical additions to an incomplete baseline, have no per-row
charge; the verified target check still costs $0.002.
Apify charges its start fee automatically, including failed and recovery runs.
RUN\_SUMMARY reports custom charges separately; the run Pricing receipt includes
the platform start fee. The Pricing tab shows the current rates.

A $1 limit is enough for the Console example. Before calling USPTO, the Actor
reserves the per-target fees and any start fee not already recorded by Apify. After the check, CHANGE
assignment events that would exceed `maxTotalChargeUsd` are omitted from Dataset
and state so a later successful check can emit them with a higher limit.
Company lookback and source truncation still apply; retry before records leave
the available window.

Daily bulk XML is not available through this Actor. Use the documented
Assignment Center watchlist inputs for public patent and company records.

### Privacy and interrupted runs

Only watched public assignment records are retained. Comparison state lives in
`uspto-patent-assignment-monitor-state` under
`USPTO_ASSIGNMENT_MONITOR_V1_<hash-of-monitorKey>`. Recovery can repeat an
`event_id`. A graceful source deadline saves completed observations and skips
unverified inputs. Cancellation stops new requests and waits for the worker to
exit before closing its HTTP client and releasing the monitor lock. Results are
journaled after source work stops; a forced process kill before that point still
requires a fresh check. A killed process may leave a marker in
`uspto-patent-assignment-monitor-locks`; stop every run for that Monitor key
before deleting only that marker.

# Actor input Schema

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

watchlist checks the patents, applications, publications and companies you supply. The daily bulk-XML mode is not offered because USPTO's PASDL portal no longer publishes an unattended daily file; it would fail every run.

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

Use one key per watchlist. The same key compares against its last verified state. Adding a target creates its own baseline; removing a target prunes its stored assignments.

## `patentNumbers` (type: `array`):

Granted USPTO patent numbers. Spaces, commas and a leading US prefix are ignored, including design (USD…), reissue (USRE45824) and plant (USPP33095) numbers. Each number is checked independently.

## `applicationNumbers` (type: `array`):

USPTO application numbers, digits only after punctuation is stripped.

## `publicationNumbers` (type: `array`):

Pre-grant publication numbers such as US20180191929A1. A missing US prefix is added.

## `companies` (type: `array`):

Exact assignee/assignor names; add aliases for accepted spellings. contains only filters the returned exact-name search. Large company histories can be truncated before recent records are reached; PARTIAL with no matching observations is not billed or stored. Use patent numbers when complete company coverage is unavailable.

## `conveyanceTypes` (type: `array`):

Keep only these conveyance categories. Leave empty to keep every recorded document type, including OTHER.

## `changesOnly` (type: `boolean`):

Show only CHANGE rows after the baseline when enabled. The Console demo keeps this off so an unchanged demo still returns current observations. Error and incomplete-check receipts remain visible.

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

emitSnapshot returns each target's first verified observation. If initial coverage is partial, unseen records remain BASELINE until a complete check is saved. storeOnly saves these silently. Updates to known records remain CHANGE events.

## `lookbackDays` (type: `integer`):

Filter company observations by recorded date over the last 1-366 days. This is a local filter, not a server-side date search or a guarantee of complete company coverage.

## Actor input object example

```json
{
  "mode": "watchlist",
  "monitorKey": "uspto-demo",
  "patentNumbers": [
    "10277785"
  ],
  "applicationNumbers": [],
  "publicationNumbers": [],
  "companies": [],
  "conveyanceTypes": [],
  "changesOnly": true,
  "baselineMode": "emitSnapshot",
  "lookbackDays": 90
}
```

# Actor output Schema

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

No description

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

Includes duplicates, invalid entries, unresolved identifiers, unchanged targets, baseline completeness and inputs skipped because of pricing, budget or runtime limits.

## `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 = {
    "mode": "watchlist",
    "monitorKey": "uspto-demo",
    "patentNumbers": [
        "10277785"
    ],
    "applicationNumbers": [],
    "publicationNumbers": [],
    "companies": [],
    "conveyanceTypes": [],
    "changesOnly": false,
    "baselineMode": "emitSnapshot",
    "lookbackDays": 90
};

// Run the Actor and wait for it to finish
const run = await client.actor("automa-flow/uspto-patent-assignment-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 = {
    "mode": "watchlist",
    "monitorKey": "uspto-demo",
    "patentNumbers": ["10277785"],
    "applicationNumbers": [],
    "publicationNumbers": [],
    "companies": [],
    "conveyanceTypes": [],
    "changesOnly": False,
    "baselineMode": "emitSnapshot",
    "lookbackDays": 90,
}

# Run the Actor and wait for it to finish
run = client.actor("automa-flow/uspto-patent-assignment-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 '{
  "mode": "watchlist",
  "monitorKey": "uspto-demo",
  "patentNumbers": [
    "10277785"
  ],
  "applicationNumbers": [],
  "publicationNumbers": [],
  "companies": [],
  "conveyanceTypes": [],
  "changesOnly": false,
  "baselineMode": "emitSnapshot",
  "lookbackDays": 90
}' |
apify call automa-flow/uspto-patent-assignment-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automa-flow/uspto-patent-assignment-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/TqWLxKES7t2CofKE4/builds/hQpgBFJkBHcYTkPvn/openapi.json
