# Global Patent & IP Enforcement Actions Monitor (`stefano_seggio/actor-21-patent-ip-enforcement-monitor`) Actor

Extracts USPTO PTAB patent-dispute proceedings (IPR/PGR/CBM/Derivation), plus an optional EPO Open Patent Services opposition-watch module. Both sources are BYOK via free registration. PatentsView (down) and WIPO (paid-only) are out of scope - see README.md.

- **URL**: https://apify.com/stefano\_seggio/actor-21-patent-ip-enforcement-monitor.md
- **Developed by:** [Stefano Seggio](https://apify.com/stefano_seggio) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 patent enforcement proceedings

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

## Global Patent & IP Enforcement Actions Monitor — Apify Store Overview

**Actor:** `stefano_seggio/actor-21-patent-ip-enforcement-monitor` (ID: `fTvz8lwj3F1FrPQfM`)
**Store URL:** https://apify.com/stefano\_seggio/actor-21-patent-ip-enforcement-monitor
**Version:** 1.1

***

### Executive Summary & Business Use Case

The Global Patent & IP Enforcement Actions Monitor extracts adversarial patent-dispute proceedings from the **USPTO Patent Trial and Appeal Board (PTAB)**, via the USPTO Open Data Portal's PTAB Trials search endpoint (`api.uspto.gov/api/v1/patent/trials/proceedings/search`), and can optionally enrich or extend that with a **EPO Open Patent Services (OPS)** opposition-family legal-status watch for a caller-supplied list of European patent publication numbers. The USPTO source returns real Inter Partes Review, Post-Grant Review, Covered Business Method, and Derivation proceedings — the actual mechanism by which one party challenges the validity of another party's granted patent before a U.S. administrative tribunal — newest-filed-first, with petition/institution/decision dates, the challenged patent and application numbers, and the identities of the patent owner, the petitioner, and their counsel. The EPO source is watchlist-driven by design: OPS has no bulk "recent oppositions" search, only a per-publication-number legal-status lookup, so a caller supplies the EP publication numbers they care about (`epWatchlist`) and the actor reports any legal event recorded against them. Both sources are bring-your-own-key: a free USPTO.gov account with mandatory MFA for the ODP key, and a free `developers.epo.org` account with a registered App for the OPS OAuth2 client credentials — the actor never attempts to create either account on the operator's behalf.

Three concrete, domain-grounded use cases follow directly from what this data actually contains. First, **in-house or outside patent litigation counsel** representing a patent owner can run the actor on a schedule with `onlyNew` enabled to catch the moment a new IPR/PGR petition is filed against one of their patents — `recipient_or_defendant_name` carries the patent owner's name, `entity_identifier_native` the challenged patent number, and `institutionDecisionDate` (mapped to `effective_date_iso`) is the real signal that PTAB formally instituted the trial rather than merely received a petition. Second, a **petitioner-side IP strategy or competitive-intelligence team** can filter `trialTypeCodes` to just `IPR` and `dateRange` to a recent window to track newly filed challenges against a competitor's patent portfolio by technology center (`technologyCenterNumber`), building a live view of where validity challenges are concentrating. Third, **patent prosecution counsel or an in-house European IP team** managing a portfolio of EP publications can populate `epWatchlist` with the numbers they're responsible for and get alerted the instant OPS records a new opposition-related legal event against any of them, without manually polling the EPO's own systems.

What this actor deliberately does not claim is equally grounded in the real data: neither PTAB proceedings nor EPO legal-status events carry a monetary amount, so `value_native`, `value_currency`, and `value_usd_normalized` are always `null` rather than fabricated — an IPR/PGR/CBM/DER dispute's real stakes are a patent's validity, not a dollar figure, and this actor's documentation says so explicitly instead of forcing a fine/penalty framing onto a domain that has none.

### Technical Features & V2 Architecture Highlights

This actor ships with **named key-value-store cross-run delta persistence**. Per its own `input_schema.json`, the `onlyNew` flag (default `false`) "persists seen record ids and a status fingerprint between runs (in this actor's own key-value store) and skips records whose status is unchanged since the prior run." In practice, that means a `uspto_ptab` trial is tracked by its `trialNumber` and an `epo_opposition` event by a composed `publicationNumber:eventCode:eventDate` key, so re-running the actor on a schedule only surfaces genuinely new or changed activity instead of re-delivering everything every time.

The **real `event_type` values this actor emits are `SANCTION`, `UPDATED`, `TERMINATED`, and `SNAPSHOT_NO_DIFF`** — confirmed identically in both `dataset_schema.json` and `README.md` — which is a deliberately different vocabulary from the generic `NEW_LISTING`/`UPDATED`/`CLOSED` pattern used elsewhere in this actor fleet:

- **`SANCTION`** — first time this proceeding (PTAB) or legal event (EPO) has ever been seen.
- **`UPDATED`** — a previously-seen record's status, latest decision date, or (for EPO) event code/date changed since it was last seen.
- **`TERMINATED`** — PTAB-only, and more specific than a generic `UPDATED`: this trial's `terminationDate` transitioned from unset to set since it was last seen, i.e. the trial genuinely concluded between runs. A trial that is already terminated the very first time it's observed is reported as `SANCTION`, not `TERMINATED`, because there is nothing to transition from on a first sighting.
- **`SNAPSHOT_NO_DIFF`** — identical to the prior run; only re-emitted when `onlyNew` is `false`, and skipped from delivery entirely when `onlyNew` is `true`.

There is no `CLOSED` event anywhere in this actor, and EPO opposition events carry no equivalent terminal signal at all — per the README, "a new `eventCode` on a watched publication IS itself the point of that record, not a status field to diff against," so `TERMINATED` is intentionally scoped to `uspto_ptab` only.

The `onlyNew` boolean is the actor's delta-mode switch, and its own schema description is explicit about the billing-relevant behavior: when enabled, it "skips records whose status is unchanged since the prior run" — an unchanged record is never pushed to the dataset at all, not pushed as a `SNAPSHOT_NO_DIFF` record for $0.

On the **output schema itself**: the normalized envelope (`src/schemas.ts#UnifiedRecordSchema`) is confirmed to be exactly an **18-field Unified Master Schema (UMS)** — `record_id`, `event_type`, `scraped_at`, `is_new`, `source_url`, `recipient_or_defendant_name`, `entity_identifier_native`, `value_native`, `value_currency`, `value_usd_normalized`, `effective_date_iso`, `publish_date_iso`, `category_or_type`, `status_or_estado`, `awarding_or_regulating_agency`, `jurisdiction`, `source_document_url`, `reference_number` — every source-agnostic field null-honest per record (e.g. `value_usd_normalized` is always `null`, since neither PTAB nor EPO carries a monetary figure to normalize). `dataset_schema.json` documents this UMS envelope alongside a `source` discriminator and the full set of raw, source-specific fields preserved from each origin (18 raw PTAB fields such as `trialNumber`, `trialStatusCategory`, `patentOwnerName`; 5 raw EPO fields such as `publicationNumber`, `eventCode`) — so a `uspto_ptab` record carries all 18 PTAB-specific fields populated and all 5 EPO-specific fields `null`, and vice versa for `epo_opposition`.

Two more source-specific engineering facts worth surfacing: the USPTO PTAB search endpoint is confirmed live with real rate limits (burst = 1, 4–15 req/s, 5,000,000 calls/week shared across all ODP metadata-retrieval endpoints), and `src/sources/usptoPtab.ts` flattens the raw proceeding response via `flattenProceeding()`. And a competing source, **USPTO PatentsView**, was live-checked and confirmed down/mid-migration as of 2026-09-07 with no committed relaunch date — and per the README it "never covered disputes/enforcement anyway, only grants/applications," so it would not have served this actor's brief even if live. **WIPO PATENTSCOPE** was likewise confirmed live but excluded because its programmatic/bulk access is a paid, CHF-priced commercial product, not an open API. Neither omission is a gap in coverage; both are documented, verified decisions.

A standalone MCP tool manifest also ships in this package (`mcp/searchPatentEnforcement.ts`) — a JSON-RPC tool declaration with a zod `inputSchema`, a `jsonSchema` derived via `zodToJsonSchema`, and a `handler`, not wired into any external registry but ready to register. And per the README's compliance note, there is no CAPTCHA-solving, fingerprint spoofing, or WAF/OAuth-gate bypass anywhere in the codebase — both live sources require registered, publisher-sanctioned API access (a USPTO ODP account with MFA; EPO OAuth2 client credentials), which is exactly why both are BYOK inputs rather than an embedded operator key.

### Input Schema & JSON Configuration Example

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `sources` | array (enum, select) | `["uspto_ptab"]` | uspto\_ptab = real USPTO PTAB Trial proceedings (IPR/PGR/CBM/DER), newest-filed-first, via the USPTO Open Data Portal. epo\_opposition = EPO Open Patent Services opposition-family legal-status watch for a caller-supplied list of EP publication numbers (epWatchlist). Both require the matching credential fields below (BYOK) -- see this actor's README/src/http.ts for the live-verified access requirements of each. |
| `usptoOdpApiKey` | string (secret) | — | Required when sources includes uspto\_ptab. Bring-your-own-key: obtain a free key from a USPTO.gov account (MFA required) at https://data.uspto.gov/myodp -- this actor never attempts to create that account on your behalf. Never logged or persisted beyond this run. |
| `epoOpsConsumerKey` | string (secret) | — | Required when sources includes epo\_opposition. From a free developers.epo.org account + registered App (OAuth2 client-credentials flow). Never logged or persisted beyond this run. |
| `epoOpsConsumerSecret` | string (secret) | — | Paired with epoOpsConsumerKey. Never logged or persisted beyond this run. |
| `epWatchlist` | array (string list) | `[]` | Required when sources includes epo\_opposition -- EPO OPS has no bulk 'recent oppositions' search, only a per-publication-number legal-status lookup, so this actor is watchlist-driven for that source. Example: "EP3000000". |
| `trialTypeCodes` | array (enum, select) | `[]` | Filters uspto\_ptab results by trialMetaData.trialTypeCode. Leave empty for all four: Inter Partes Review (IPR), Post-Grant Review (PGR), Covered Business Method (CBM), Derivation (DER). |
| `dateRange` | string (enum, select) | — | Optionally restricts uspto\_ptab results to proceedings whose petitionFilingDate falls within this window (applied server-side as an ODP rangeFilter). Does not affect epo\_opposition, which is watchlist-driven. Allowed values: `24h`, `7d`, `30d`, `90d`. |
| `maxItemsPerSource` | integer | `100` | Hard cap on how many records to return per selected source this run (applied independently to uspto\_ptab and epo\_opposition). |
| `onlyNew` | boolean | `false` | When enabled, persists seen record ids and a status fingerprint between runs (in this actor's own key-value store) and skips records whose status is unchanged since the prior run. A first-seen record is emitted as event\_type SANCTION; a previously-seen record whose status/decision fields changed is emitted as UPDATED; a uspto\_ptab record whose terminationDate newly became set since it was last seen is emitted as the more specific TERMINATED instead. Recommended for recurring monitoring. |

```json
{
  "sources": ["uspto_ptab", "epo_opposition"],
  "usptoOdpApiKey": "YOUR_USPTO_ODP_API_KEY",
  "epoOpsConsumerKey": "YOUR_EPO_OPS_CONSUMER_KEY",
  "epoOpsConsumerSecret": "YOUR_EPO_OPS_CONSUMER_SECRET",
  "epWatchlist": ["EP3000000", "EP3500000"],
  "trialTypeCodes": ["IPR", "PGR"],
  "dateRange": "30d",
  "maxItemsPerSource": 50,
  "onlyNew": true
}
```

### Output Dataset Sample & Data Dictionary

**Unified Master Schema (UMS) fields — present on every record, `source`-agnostic:**

| Field | Type | Description |
| --- | --- | --- |
| `source` | string | uspto\_ptab or epo\_opposition — which of the two sources produced this record. |
| `record_id` | string | trialNumber (uspto\_ptab) or a composed publicationNumber:eventCode:eventDate key (epo\_opposition) - stable across runs. |
| `event_type` | string | SANCTION (first seen), UPDATED (status/decision changed since last run), TERMINATED (uspto\_ptab only - the trial's terminationDate transitioned from unset to set since it was last seen, a more specific signal than a generic UPDATED), or SNAPSHOT\_NO\_DIFF (unchanged, re-emitted because onlyNew=false). |
| `scraped_at` | string | ISO-8601 timestamp of this extraction. |
| `is_new` | boolean | true if not seen in a prior run (delta mode). |
| `source_url` | string | null | Public case-viewer URL for this record; null for both sources in this actor (no verified per-record public page URL for either uspto\_ptab or epo\_opposition — an honest null rather than a fabricated link). |
| `recipient_or_defendant_name` | string | null | Patent Owner / Defendant — for uspto\_ptab, the patent owner under adversarial challenge; always null for epo\_opposition (OPS legal-status data doesn't carry the owner's name in this actor's scope). |
| `entity_identifier_native` | string | null | Native Entity Identifier — the challenged patentNumber (uspto\_ptab) or the watched publicationNumber (epo\_opposition). |
| `value_native` | string | null | Value (native) — always null; neither source carries a monetary amount. |
| `value_currency` | string | null | Value Currency — always null; neither source carries a monetary amount. |
| `value_usd_normalized` | number | null | Value (USD) — always null; neither source carries a monetary amount to normalize. |
| `effective_date_iso` | string | null | Effective Date — institutionDecisionDate (falling back to accordedFilingDate) for uspto\_ptab; eventDate for epo\_opposition. |
| `publish_date_iso` | string | null | Publish Date — petitionFilingDate for uspto\_ptab; eventDate for epo\_opposition. |
| `category_or_type` | string | null | Category / Type — trialTypeCode (IPR/PGR/CBM/DER) for uspto\_ptab; eventCode for epo\_opposition. |
| `status_or_estado` | string | null | Status — trialStatusCategory for uspto\_ptab; eventDescription for epo\_opposition. |
| `awarding_or_regulating_agency` | string | null | Regulating Agency — constant "USPTO Patent Trial and Appeal Board (PTAB)" or "European Patent Office (EPO) -- Legal/Opposition Division". |
| `jurisdiction` | string | US or EP. |
| `source_document_url` | string | null | Source Document URL — fileDownloadURI for uspto\_ptab; always null for epo\_opposition (OPS is a data API, not a public document store). |
| `reference_number` | string | null | Reference Number — trialNumber for uspto\_ptab; publicationNumber for epo\_opposition. |

**USPTO PTAB fields — populated only when `source` = `uspto_ptab`, null otherwise:**

| Field | Type | Description |
| --- | --- | --- |
| `trialNumber` | string | null | PTAB Trial Number, e.g. IPR2024-00123. |
| `trialTypeCode` | string | null | Trial Type: IPR / PGR / CBM / DER. |
| `trialStatusCategory` | string | null | Trial Status. |
| `petitionFilingDate` | string | null | Petition Filing Date. |
| `accordedFilingDate` | string | null | Accorded Filing Date. |
| `institutionDecisionDate` | string | null | Institution Decision Date. |
| `latestDecisionDate` | string | null | Latest Decision Date. |
| `terminationDate` | string | null | Termination Date. |
| `trialLastModifiedDateTime` | string | null | Trial Last Modified. |
| `fileDownloadURI` | string | null | Document Download URI. |
| `patentNumber` | string | null | Challenged Patent Number. |
| `applicationNumberText` | string | null | Application Number. |
| `patentOwnerName` | string | null | Patent Owner Name. |
| `patentOwnerRealPartyInInterestName` | string | null | Patent Owner Real Party in Interest. |
| `petitionerRealPartyInInterestName` | string | null | Petitioner Real Party in Interest. |
| `petitionerCounselName` | string | null | Petitioner Counsel. |
| `inventorName` | string | null | Inventor Name. |
| `technologyCenterNumber` | string | null | Technology Center. |

**EPO OPS fields — populated only when `source` = `epo_opposition`, null otherwise:**

| Field | Type | Description |
| --- | --- | --- |
| `publicationNumber` | string | null | EP Publication Number. |
| `eventCode` | string | null | Legal Event Code. |
| `eventDescription` | string | null | Legal Event Description. |
| `eventDate` | string | null | Legal Event Date. |
| `eventCountry` | string | null | Legal Event Country. |

Sample record (`uspto_ptab`, a first-seen IPR proceeding under delta mode):

```json
{
  "source": "uspto_ptab",
  "trialNumber": "IPR2026-00842",
  "trialTypeCode": "IPR",
  "trialStatusCategory": "Instituted",
  "petitionFilingDate": "2026-03-14",
  "accordedFilingDate": "2026-03-14",
  "institutionDecisionDate": "2026-09-02",
  "latestDecisionDate": "2026-09-02",
  "terminationDate": null,
  "trialLastModifiedDateTime": "2026-09-02T00:00:00Z",
  "fileDownloadURI": "https://api.uspto.gov/api/v1/patent/trials/proceedings/IPR2026-00842/documents/1120345/download",
  "patentNumber": "10,987,654",
  "applicationNumberText": "16/123,456",
  "patentOwnerName": "Meridian Semiconductor Corp.",
  "patentOwnerRealPartyInInterestName": "Meridian Semiconductor Corp.",
  "petitionerRealPartyInInterestName": "Northgate Devices Inc.",
  "petitionerCounselName": "Harlow & Voss LLP",
  "inventorName": "Chen, Wei-Ming",
  "technologyCenterNumber": "2800",
  "publicationNumber": null,
  "eventCode": null,
  "eventDescription": null,
  "eventDate": null,
  "eventCountry": null,
  "record_id": "IPR2026-00842",
  "event_type": "SANCTION",
  "scraped_at": "2026-09-08T14:22:07.481Z",
  "is_new": true,
  "source_url": null,
  "recipient_or_defendant_name": "Meridian Semiconductor Corp.",
  "entity_identifier_native": "10,987,654",
  "value_native": null,
  "value_currency": null,
  "value_usd_normalized": null,
  "effective_date_iso": "2026-09-02",
  "publish_date_iso": "2026-03-14",
  "category_or_type": "IPR",
  "status_or_estado": "Instituted",
  "awarding_or_regulating_agency": "USPTO Patent Trial and Appeal Board (PTAB)",
  "jurisdiction": "US",
  "source_document_url": "https://api.uspto.gov/api/v1/patent/trials/proceedings/IPR2026-00842/documents/1120345/download",
  "reference_number": "IPR2026-00842"
}
```

### Multi-language Integration Snippets

#### cURL

```bash
curl "https://api.apify.com/v2/acts/stefano_seggio~actor-21-patent-ip-enforcement-monitor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "sources": ["uspto_ptab"],
    "usptoOdpApiKey": "YOUR_USPTO_ODP_API_KEY",
    "trialTypeCodes": ["IPR", "PGR"],
    "dateRange": "30d",
    "maxItemsPerSource": 50,
    "onlyNew": true
  }'
```

#### Python (apify-client)

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")

run_input = {
    "sources": ["uspto_ptab"],
    "usptoOdpApiKey": "YOUR_USPTO_ODP_API_KEY",
    "trialTypeCodes": ["IPR", "PGR"],
    "dateRange": "30d",
    "maxItemsPerSource": 50,
    "onlyNew": True,
}

run = client.actor("stefano_seggio/actor-21-patent-ip-enforcement-monitor").call(run_input=run_input)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"[{item['event_type']}] {item['trialNumber']} - {item['recipient_or_defendant_name']}")
```

#### Node.js (apify-client)

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const runInput = {
    sources: ['uspto_ptab'],
    usptoOdpApiKey: 'YOUR_USPTO_ODP_API_KEY',
    trialTypeCodes: ['IPR', 'PGR'],
    dateRange: '30d',
    maxItemsPerSource: 50,
    onlyNew: true,
};

const run = await client.actor('stefano_seggio/actor-21-patent-ip-enforcement-monitor').call(runInput);

const { items } = await client.dataset(run.defaultDatasetId).listItems();

for (const item of items) {
    console.log(`[${item.event_type}] ${item.trialNumber} - ${item.recipient_or_defendant_name}`);
}
```

### Pricing Model Explanation

This actor is pay-per-event, with platform usage included:

| Event | Price | What it means here |
| --- | --- | --- |
| `result` | $0.002 / record | Charged once per dataset item pushed. There is no second, cheaper tier for this actor — the USPTO PTAB Trials search endpoint returns full proceeding metadata (dates, patent/application numbers, patent-owner and petitioner party data) in a single call, and the EPO OPS legal-status lookup likewise returns the full legal event for a watched publication number in one call. Neither source has a "listing-only" response that this actor later has to fetch details for, so there is no lighter-weight/heavier-weight split to price differently — every record that reaches the dataset, from either source, costs the same. |
| `apify-actor-start` | $0.00005 / run | Charged once per run, regardless of how many sources are selected or how many records are returned. |

**Delta mode and billing:** when `onlyNew` is set to `true`, the actor persists a status fingerprint per record in its own named key-value store and only pushes dataset items for records it classifies as `SANCTION` (first seen), `UPDATED` (status/decision changed), or `TERMINATED` (a PTAB trial's `terminationDate` newly became set). A record that is already known and unchanged is never delivered at all — it is not pushed as a `SNAPSHOT_NO_DIFF` record and then charged at $0, it is simply never created as a dataset item in the first place, so it is never a chargeable `result` event. That is what makes scheduling this actor for recurring monitoring economical: re-running it against the same PTAB search or the same EP watchlist on a schedule only bills for genuinely new petitions, status changes, or terminations — not for reconfirming proceedings that haven't moved.

***

*Sources for this overview: `.actor/actor.json`, `.actor/input_schema.json`, `.actor/dataset_schema.json`, `README.md`, `src/schemas.ts`, and `src/umsNormalizer.ts` from the actor's real repository at `C:\Users\Stef\apify-portfolio\actor-21-patent-ip-enforcement-monitor`. No `CHANGELOG.md` exists at this actor's root (only inside `node_modules` dependencies, which are third-party and not this actor's own); V2/UMS architecture detail came from `README.md`'s "Unified Master Schema (UMS)" and "Delta mode" sections plus `src/schemas.ts`/`src/umsNormalizer.ts` directly instead.*

# Actor input Schema

## `sources` (type: `array`):

uspto\_ptab = real USPTO PTAB Trial proceedings (IPR/PGR/CBM/DER), newest-filed-first, via the USPTO Open Data Portal. epo\_opposition = EPO Open Patent Services opposition-family legal-status watch for a caller-supplied list of EP publication numbers (epWatchlist). Both require the matching credential fields below (BYOK) -- see this actor's README/src/http.ts for the live-verified access requirements of each.

## `usptoOdpApiKey` (type: `string`):

Required when sources includes uspto\_ptab. Bring-your-own-key: obtain a free key from a USPTO.gov account (MFA required) at https://data.uspto.gov/myodp -- this actor never attempts to create that account on your behalf. Never logged or persisted beyond this run.

## `epoOpsConsumerKey` (type: `string`):

Required when sources includes epo\_opposition. From a free developers.epo.org account + registered App (OAuth2 client-credentials flow). Never logged or persisted beyond this run.

## `epoOpsConsumerSecret` (type: `string`):

Paired with epoOpsConsumerKey. Never logged or persisted beyond this run.

## `epWatchlist` (type: `array`):

Required when sources includes epo\_opposition -- EPO OPS has no bulk 'recent oppositions' search, only a per-publication-number legal-status lookup, so this actor is watchlist-driven for that source. Example: "EP3000000".

## `trialTypeCodes` (type: `array`):

Filters uspto\_ptab results by trialMetaData.trialTypeCode. Leave empty for all four: Inter Partes Review (IPR), Post-Grant Review (PGR), Covered Business Method (CBM), Derivation (DER).

## `dateRange` (type: `string`):

Optionally restricts uspto\_ptab results to proceedings whose petitionFilingDate falls within this window (applied server-side as an ODP rangeFilter). Does not affect epo\_opposition, which is watchlist-driven.

## `maxItemsPerSource` (type: `integer`):

Hard cap on how many records to return per selected source this run (applied independently to uspto\_ptab and epo\_opposition).

## `onlyNew` (type: `boolean`):

When enabled, persists seen record ids and a status fingerprint between runs (in this actor's own key-value store) and skips records whose status is unchanged since the prior run. A first-seen record is emitted as event\_type SANCTION; a previously-seen record whose status/decision fields changed is emitted as UPDATED; a uspto\_ptab record whose terminationDate newly became set since it was last seen is emitted as the more specific TERMINATED instead. Recommended for recurring monitoring.

## Actor input object example

```json
{
  "sources": [
    "uspto_ptab"
  ],
  "epWatchlist": [],
  "trialTypeCodes": [],
  "maxItemsPerSource": 100,
  "onlyNew": false
}
```

# Actor output Schema

## `results` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("stefano_seggio/actor-21-patent-ip-enforcement-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("stefano_seggio/actor-21-patent-ip-enforcement-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 '{}' |
apify call stefano_seggio/actor-21-patent-ip-enforcement-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,stefano_seggio/actor-21-patent-ip-enforcement-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/fTvz8lwj3F1FrPQfM/builds/7CrOpqNdnZmZ0Gbne/openapi.json
