# Patent Assignee Period Rollup (`zinin/patent-assignee-period-rollup`) Actor

Summarize patent datasets by observed assignee. Deduplicate patent records, separate date bases, surface conflicting metadata and report batch-scoped portfolio assessments with source evidence.

- **URL**: https://apify.com/zinin/patent-assignee-period-rollup.md
- **Developed by:** [Tim Zinin](https://apify.com/zinin) (community)
- **Categories:** Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $24.50 / 1,000 portfolio assessments

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Patent Assignee Period Rollup — turn a patent-record batch into one portfolio assessment per assignee

Feed this Actor a batch of patent rows from your own `zinin/patent-monitor` watch, a Google-Patents-shaped scraper run, or a hand-built inline list combining both, and it returns one deduplicated **portfolio assessment** per literal assignee name — distinct patent counts, five separate date-basis period counts with yearly buckets, co-observation disclosure, missing-metadata coverage, and exact record-conflict counts — so you can see, in minutes, which assignee's filings actually agree across your sources and which need a human to reconcile before anyone relies on the batch.

![Patent Assignee Period Rollup — buyer input, source evidence and decision outcome](https://raw.githubusercontent.com/TimmyZinin/apify-actor-assets/90de26a051f8149b0276682281c1eb0e7289f112/value-add-2-20260923/patent-assignee-period-rollup/readme-hero.webp)

### What you get

You give this Actor a dataset (or an inline list) of patent-record rows. It never scrapes, never calls a model, and never guesses — it reads exactly the rows you supply and reports, per literal assignee name, a **portfolio assessment**: a single deduplicated view of that assignee's patents inside the batch, with every count traceable back to the specific source row that produced it.

Concretely, for each assignee observed in your batch, you receive:

- **`distinctPatentCount`** — how many unique, syntactically valid `patentId` values this assignee's rows contained. Two rows for the same patent are one patent, not two. A row whose `patentId` doesn't match a real publication-number syntax (US, JP and other supported office prefixes) is excluded entirely and reported as a free `invalid_patent_id` diagnostic instead — it never becomes a paid portfolio member.
- **`coObservedPatentCount`** — of those patents, how many were *also* observed under a different assignee spelling elsewhere in the same batch. This is disclosure of a fact your batch actually contains, never a claim about fractional or joint legal ownership.
- **`datePeriodCounts`** — five *fully separate* date bases: `patentDate` (the single date field `zinin/patent-monitor` rows carry) and `filingDate`, `publicationDate`, `grantDate`, `priorityDate` (the four distinct legal milestones Google-Patents-shaped rows carry). Each basis reports `{ count, earliest, latest, yearlyBuckets }`, where `yearlyBuckets` is a `{ "YYYY": distinctPatentCount }` map deduping a patent to at most one count per calendar year it has a known value for in that basis. These five bases are never merged into one generic "date": a row supplying only `filingDate` never contributes to `patentDate`'s count.
- **`missingMetadataCounts`** — for `title`, `url`, `jurisdiction`, `recordStatus`, and each date basis, exactly how many distinct patents never carried a usable value for that field. Absence is stated explicitly; never silently treated as zero, never treated as a negative claim about the real patent.
- **`recordConflicts`** — a bounded list (cap 10, with an exact `recordConflictsOmitted` count) of cases where the *same* `patentId` under the *same* assignee was observed with more than one distinct non-empty value for its title or a given date basis across duplicate rows. This is disagreement your own supplied data actually contains, not an interpretation layered on top of it.
- **`evidence`** — a bounded list (cap 12, with an exact `evidenceOmitted` count) of sample patents backing the portfolio, each carrying its own retained source URL when the source row supplied one, and a `coObserved` flag.
- **`observedAt`** and **`sourceObservationWindow`** — the real latest (and earliest, for the window) strictly-valid `checkedAt`/`scrapedAt` capture timestamp across contributing rows, compared by its true normalized instant (UTC-offset aware, not lexical string order). A source *capture* time, never a patent event date, never fabricated as "now."

What this Actor deliberately does **not** do, so you never mistake a convenience rollup for a legal or market conclusion:

- It does **not** merge differently-spelled assignee names into one corporate family. `"Example Energy Systems Inc."` and `"Example Energy Systems, Inc."` are two separate portfolios, exactly as your source data spelled them — corporate-family resolution is a separate step you run before or after this Actor.
- It does **not** claim market share, filing velocity, growth, or an exhaustive view of any assignee's real-world patent holdings. Every count is scoped explicitly to "what this batch contained," never to "what this assignee owns."
- It does **not** treat a source row's own capture timestamp (`checkedAt` / `scrapedAt`) as a patent event date, and it never invents "now" as an observation time when no row actually carried one.
- It does **not** call any network, AI model, or system clock from inside its transform step. Every number in the output traces back to a field on a row you supplied.
- It does **not** launch `zinin/patent-monitor`, a Google Patents scraper, or any other upstream Actor on your behalf. It never starts new scraping work, and it never combines multiple dataset IDs automatically on a single run.

![Patent Assignee Period Rollup — schedule, API, MCP or webhook feeding the Actor into a CRM or operational review queue](https://raw.githubusercontent.com/TimmyZinin/apify-actor-assets/90de26a051f8149b0276682281c1eb0e7289f112/value-add-2-20260923/patent-assignee-period-rollup/readme-workflow.webp)

### Who uses it

- **IP paralegals and patent operations analysts** who already run `zinin/patent-monitor` or a Google Patents scraper on a watch list of assignees and need a fast, honest rollup before a status memo — without opening a spreadsheet and manually deduplicating rows by hand every week.
- **Competitive-intelligence and R\&D strategy teams** tracking a competitor's filings across quarters, who want distinct patent counts and yearly buckets per date basis rather than a raw row count that double-counts every patent scraped twice.
- **M\&A and diligence support staff** doing a first-pass sanity check on a target company's patent batch — surfacing missing metadata and duplicate-row conflicts *before* they get escalated to outside patent counsel, so counsel's time goes to genuine legal questions rather than data-hygiene ones.
- **Data engineers building an internal IP dashboard** who need a dependable, pure post-processing step between a scraper's raw output and a BI table — one that never silently drops a disagreement between two duplicate rows and always tells you exactly how many results were capped.
- **Search-term note for assignee/portfolio watch teams:** if your own search vocabulary uses terms like *"patent portfolio tracker"*, *"patent assignee report"*, *"patent filing rollup by company"*, *"US and JP publication number validation"*, or the Japanese publication-number families this Actor already validates (`JPS`, `JPH`, `JPWO` prefixes, e.g. `JPS639877A`, `JPWO2014203654A1`), this Actor's identity rules and date-basis separation apply directly to that batch without any extra configuration.

### How to run

1. Open the Apify Console and start a new run of **Patent Assignee Period Rollup**.
2. Choose a source, in order of precedence (an explicit dataset always wins over a run reference, which always wins over the inline example — a dataset/run source never merges with inline rows):
   - **Source Dataset** (`datasetId`) — point at an existing Dataset from a prior `zinin/patent-monitor` or Google-Patents-style scraper run. Read with your own run's granted permissions; no elevated access is used.
   - **Source run ID** (`runId`) — supply a run ID instead, if you have one but not its Dataset ID directly; its default Dataset is resolved automatically.
   - **Integration payload** (`payload.resource`) — set automatically by Apify's Integrations "Actor/task run" template when you chain this Actor after an upstream scraper; carries `{{resource.defaultDatasetId}}`/`{{resource.id}}`/`{{resource.actId}}` so no manual mapping is needed.
   - **Source records (inline)** — paste or edit rows directly, or leave the prefilled real public sample in place for a first test run: a curated projection of an actual public `zinin/patent-monitor` run plus two actual `khadinakbar/google-patents-scraper` rows.
3. Optionally set **Max source rows** (`maxInputRows`, default 100, up to 1000) and **Max results** (`maxResults`, default 2, up to 1000). The platform's own **Max total charge USD** run option is a separate, independent stop: whichever limit is hit first ends delivery.
4. Run it. Delivered rows land in the run's default Dataset, one per assignee, each carrying `sourceRowIndexes` back into your original batch so you can trace any figure to its source rows.
5. Read `partial` and the summary's `resultsCapped`/`sourcePartial` flags before treating a run as a complete picture of your batch — see **Evidence and boundaries** for exactly when those flags are set and why.

For a repeatable pipeline (e.g. a weekly assignee-watch refresh), save this configuration as an Apify Task and chain it after your `zinin/patent-monitor` or Google Patents scraper run via Apify's Integrations, or trigger it from your own system via the API — see **Integration recipes** below for both paths with the exact chaining fields.

### Pricing

This Actor bills on the Apify Pay-Per-Event model under a single primary event, **`result-found`** — described to buyers under the pricing noun **"portfolio assessment."** There is **no start fee** and no per-row or per-patent charge: only a delivered, useful portfolio assessment is billed. Free diagnostics (invalid rows, missing assignee, missing/invalid patent ID, source failures, budget stops, empty-batch outcomes) never request the paid event and are never charged.

| Tier | Price per portfolio assessment |
|---|---|
| Free | $0.0350 |
| Bronze | $0.0315 |
| Silver | $0.0280 |
| Gold | $0.0245 |
| Platinum | $0.0245 |
| Diamond | $0.0245 |

Bronze, Silver and Gold apply Apify's standard 10%/20%/30% volume discounts off the Free-tier price; Platinum and Diamond are held at the Gold rate. There is no owner-run revenue claim and no guarantee of any particular run volume in this pricing table — it states only the price actually configured on this Actor's `result-found` event, verified against the live Actor record at publication time.

A useful portfolio assessment is a real aggregate result — a deduplicated per-assignee rollup with at least one distinct patent and populated evidence — never a raw source row passed through unprocessed. A `partial: true` portfolio assessment (for example, one delivered while `maxInputRows` cut off part of your batch) is still a useful aggregate and is still billed; only genuinely empty, invalid, or source-failure outcomes are free. See **Evidence and boundaries** for the exact delivery-and-charging mechanics, including why a new run of this Actor against identical input can bill again.

### Input contract

This Actor's input schema is deliberately small: a source selector plus two bounds. There are no product-specific configuration fields beyond the shared source contract — the whole surface area is "which rows, how many of them, how many results."

```json
{
  "items": [
    {
      "recordType": "patent_evidence_record",
      "schemaVersion": "2.0.0",
      "found": true,
      "checkedAt": "2026-09-18T15:19:59.476Z",
      "patentId": "US12345678B2",
      "title": "Thermal management system for an energy storage assembly",
      "patentDate": "2026-07-14",
      "assignee": "Example Energy Systems Inc.",
      "url": "https://patents.google.com/patent/US12345678B2/en",
      "jurisdiction": "US",
      "recordStatus": "granted"
    },
    {
      "patentId": "US10000000B2",
      "googlePatentsUrl": "https://patents.google.com/patent/US10000000B2/en",
      "scrapedAt": "2026-09-23T06:42:42.482Z",
      "title": "Coherent LADAR using intra-pixel quadrature detection",
      "filingDate": "2015-03-10",
      "publicationDate": "2018-06-19",
      "grantDate": "2018-06-19",
      "priorityDate": "2015-03-10",
      "assignee": "Raytheon Co"
    }
  ],
  "maxInputRows": 100,
  "maxResults": 2
}
```

This example is a trimmed projection of the Actor's own real prefill (the full prefill also includes a `khadinakbar/google-patents-scraper` row for `US10000001B2` / LS Mtron Ltd, plus each row's `__source` provenance block and the scraper rows' full `cpc`/citation arrays, read but ignored by this Actor's transform — see the row-shape table below). Every `patentId`, `assignee`, and date in the prefill is a real value observed from a real upstream run, not synthetic fixture data.

| Field | Type | Notes |
|---|---|---|
| `items` | array, optional | Inline source rows. Ignored if `datasetId` or a resolvable `runId`/`payload.resource` is present. Bounded to 1000 rows / 4 MiB total / 64 KiB per row. |
| `datasetId` | string, optional | Reads an existing Dataset with your run's own granted permissions (`resourcePicker`, READ). Overrides inline `items`. For Integrations, map `{{resource.defaultDatasetId}}` here. |
| `runId` | string, optional | Reads a run's default Dataset when you have a run ID but not its Dataset ID directly. No elevated access — the run's own default Dataset is resolved and read exactly as `datasetId` would be. |
| `payload` | object, optional | Set automatically by Apify's Integrations "Actor/task run" template; carries `resource.id` / `resource.defaultDatasetId` / `resource.actId`. A raw webhook envelope alone does not grant private Dataset access — the resourcePicker's own READ grant does that. |
| `maxInputRows` | integer, default 100, max 1000 | Hard cap on source rows read for this run, independent of `maxResults`. |
| `maxResults` | integer, default 2, max 1000 | Hard cap on paid portfolio assessments delivered this run. Free diagnostics are never counted against this cap. |

#### Recognized row shapes

| Field | Which source carries it | Role in the rollup |
|---|---|---|
| `assignee` | both | Identity — literal text, whitespace-normalized (trim + collapse internal runs), the sole grouping key |
| `patentId` | both | Identity — validated against a real publication-number syntax; unrecognized forms are a free diagnostic |
| `title` | both | Display and title-conflict detection |
| `url` / `googlePatentsUrl` | both | Display — retained verbatim into `evidence[].url`, never re-derived |
| `jurisdiction` / `countryCode` | both | Display only, not identity |
| `recordStatus` / `status` | both | Display only, not identity |
| `patentDate` | `zinin/patent-monitor` | Date basis 1 of 5 |
| `filingDate` | Google-Patents-shaped | Date basis 2 of 5 |
| `publicationDate` | Google-Patents-shaped | Date basis 3 of 5 |
| `grantDate` | Google-Patents-shaped | Date basis 4 of 5 |
| `priorityDate` | Google-Patents-shaped | Date basis 5 of 5 |
| `checkedAt` / `scrapedAt` | either | Source capture timestamp, feeds `observedAt`/`sourceObservationWindow`, never an event date |

Any other field present on a row — `cpc`, `citationsBackward`, `citationsForward`, `abstractSnippet`, `decision`, `confidence`, `freshness`, and similar fields real `zinin/patent-monitor` or Google-Patents-shaped rows may carry — is read as part of the row but is never surfaced in the output and never used to infer anything: it is simply not part of this Actor's rollup contract.

### Output examples

Every delivered row and diagnostic below is copied verbatim from an actual private cloud canary run of this Actor's `value-add-candidate` build (build `0.1.1`), never hand-written. Field order and values match the real Dataset item exactly.

#### Happy path — a delivered portfolio assessment

Real run against the prefilled three-row public sample with `maxResults: 2` (so the run also produced a `max_results_reached` diagnostic after two portfolio assessments — the assignee row below is the first of those two):

```json
{
  "entityId": "assignee:Example Energy Systems Inc.",
  "found": true,
  "status": "assignee_portfolio_rollup",
  "action": "review_portfolio",
  "confidence": "high",
  "sourceRowCount": 1,
  "assignee": "Example Energy Systems Inc.",
  "distinctPatentCount": 1,
  "coObservedPatentCount": 0,
  "datePeriodCounts": {
    "patentDate": {
      "count": 1,
      "earliest": "2026-07-14",
      "latest": "2026-07-14",
      "yearlyBuckets": {
        "2026": 1
      }
    },
    "filingDate": {
      "count": 0,
      "earliest": null,
      "latest": null,
      "yearlyBuckets": {}
    },
    "publicationDate": {
      "count": 0,
      "earliest": null,
      "latest": null,
      "yearlyBuckets": {}
    },
    "grantDate": {
      "count": 0,
      "earliest": null,
      "latest": null,
      "yearlyBuckets": {}
    },
    "priorityDate": {
      "count": 0,
      "earliest": null,
      "latest": null,
      "yearlyBuckets": {}
    }
  },
  "missingMetadataCounts": {
    "title": 0,
    "url": 0,
    "jurisdiction": 0,
    "recordStatus": 0,
    "patentDate": 0,
    "filingDate": 1,
    "publicationDate": 1,
    "grantDate": 1,
    "priorityDate": 1
  },
  "evidenceOmitted": 0,
  "recordConflicts": [],
  "recordConflictCount": 0,
  "recordConflictsOmitted": 0,
  "observedAt": "2026-09-18T15:19:59.476Z",
  "sourceObservationWindow": {
    "earliest": "2026-09-18T15:19:59.476Z",
    "latest": "2026-09-18T15:19:59.476Z",
    "validCount": 1,
    "totalRowCount": 1
  },
  "evidence": [
    {
      "field": "patentId",
      "value": "US12345678B2",
      "title": "Thermal management system for an energy storage assembly",
      "url": "https://patents.google.com/patent/US12345678B2/en",
      "coObserved": false,
      "sourceRowIndex": 0
    }
  ],
  "businessPartial": false,
  "sourceRowIndexes": [
    0
  ],
  "partial": false,
  "sourceCoverage": {
    "complete": true,
    "reason": null,
    "droppedOversized": 0
  },
  "product": "patent-assignee-period-rollup",
  "schemaVersion": "1.0",
  "sourceDatasetId": null,
  "sourceRunId": null,
  "suppliedSourceRunId": null,
  "sourceRunIdVerified": null,
  "processedAt": "2026-09-23T07:50:47.078Z"
}
```

Notice `missingMetadataCounts.patentDate` is `0` (patent-monitor supplied it) while `filingDate`/`publicationDate`/`grantDate`/`priorityDate` are each `1` — this assignee's single patent simply never carried those Google-Patents-specific bases, and the Actor reports that absence explicitly rather than silently treating it as zero coverage. The run's summary for this exact call reported `"requested": 3, "usefulResults": 3, "delivered": 2, "paid": 2, "free": 1, "resultsCapped": true, "partialOverall": true"` — a real, honest example of `maxResults` capping a batch that had one more useful assignee than the run was configured to pay for.

#### Partial path — a real `maxInputRows` cutoff, with a genuinely delivered result

Real run against the same three-row batch with `maxInputRows: 1` (so only the batch's first row was read at all) and `maxResults: 2`:

```json
{
  "entityId": "assignee:Example Energy Systems Inc.",
  "found": true,
  "status": "assignee_portfolio_rollup",
  "action": "review_portfolio",
  "confidence": "high",
  "sourceRowCount": 1,
  "assignee": "Example Energy Systems Inc.",
  "distinctPatentCount": 1,
  "coObservedPatentCount": 0,
  "datePeriodCounts": {
    "patentDate": {
      "count": 1,
      "earliest": "2026-07-14",
      "latest": "2026-07-14",
      "yearlyBuckets": {
        "2026": 1
      }
    },
    "filingDate": {
      "count": 0,
      "earliest": null,
      "latest": null,
      "yearlyBuckets": {}
    },
    "publicationDate": {
      "count": 0,
      "earliest": null,
      "latest": null,
      "yearlyBuckets": {}
    },
    "grantDate": {
      "count": 0,
      "earliest": null,
      "latest": null,
      "yearlyBuckets": {}
    },
    "priorityDate": {
      "count": 0,
      "earliest": null,
      "latest": null,
      "yearlyBuckets": {}
    }
  },
  "missingMetadataCounts": {
    "title": 0,
    "url": 0,
    "jurisdiction": 0,
    "recordStatus": 0,
    "patentDate": 0,
    "filingDate": 1,
    "publicationDate": 1,
    "grantDate": 1,
    "priorityDate": 1
  },
  "evidenceOmitted": 0,
  "recordConflicts": [],
  "recordConflictCount": 0,
  "recordConflictsOmitted": 0,
  "observedAt": "2026-09-18T15:19:59.476Z",
  "sourceObservationWindow": {
    "earliest": "2026-09-18T15:19:59.476Z",
    "latest": "2026-09-18T15:19:59.476Z",
    "validCount": 1,
    "totalRowCount": 1
  },
  "evidence": [
    {
      "field": "patentId",
      "value": "US12345678B2",
      "title": "Thermal management system for an energy storage assembly",
      "url": "https://patents.google.com/patent/US12345678B2/en",
      "coObserved": false,
      "sourceRowIndex": 0
    }
  ],
  "businessPartial": false,
  "sourceRowIndexes": [
    0
  ],
  "partial": true,
  "sourceCoverage": {
    "complete": false,
    "reason": "max_input_rows_reached",
    "droppedOversized": 0
  },
  "product": "patent-assignee-period-rollup",
  "schemaVersion": "1.0",
  "sourceDatasetId": null,
  "sourceRunId": null,
  "suppliedSourceRunId": null,
  "sourceRunIdVerified": null,
  "processedAt": "2026-09-23T07:56:00.875Z"
}
```

This row is identical to the happy-path row above in every field except `partial` and `sourceCoverage`, because the one row this narrower run actually read was the same first row. Those two changed fields say explicitly that this Actor never read your batch's two remaining real rows (the two Google-Patents-shaped patents) this run — not deleted, corrupted, or degraded, simply outside the row window you configured. The run also emitted a separate free `partial_source` diagnostic (`"reason": "max_input_rows_reached"`) alongside this delivered row. If your batch legitimately has more than `maxInputRows` rows, raise the limit (up to 1000) rather than relying on this Actor to see rows it was never given.

#### Failure path — the platform's own charge limit stops delivery before any row is read

Real run with the platform's **Max total charge USD** run option set to `$0.005` — below the configured `$0.035` Free-tier price of a single portfolio assessment:

```json
{
  "product": "patent-assignee-period-rollup",
  "schemaVersion": "1.0",
  "status": "budget_stopped",
  "reason": "Run charge limit cannot cover any result; no source was read.",
  "found": false,
  "processedAt": "2026-09-23T07:51:45.448Z"
}
```

This diagnostic is free — `chargedEventCounts.result-found` was `0` on the real run terminal record. Critically, the Actor checks whether the run's own charge limit can cover even a single result *before* reading any source rows, so a misconfigured (too-low) `Max total charge USD` fails safely and instantly rather than partially reading your batch and then stalling mid-run.

#### Empty-source path — a batch with nothing usable in it

Real run with `items: []` (an explicitly empty inline batch):

```json
{
  "product": "patent-assignee-period-rollup",
  "schemaVersion": "1.0",
  "status": "no_results",
  "found": false,
  "reason": "no_usable_rows_in_batch",
  "sourceCoverage": {
    "complete": true,
    "reason": null,
    "droppedOversized": 0
  },
  "processedAt": "2026-09-23T07:51:35.972Z"
}
```

Also free. `sourceCoverage.complete: true` here means exactly what it says: the Actor read the entire (empty) batch you supplied — the emptiness is a fact about your input, not a read failure on the Actor's part.

### Field dictionary

| Field | Meaning |
|---|---|
| `entityId` | `assignee:<literal assignee text>` — a stable identity string for this delivered row. |
| `found` | `true` for a useful result eligible for the result-found event; every free diagnostic row has `found: false`. |
| `status` | `assignee_portfolio_rollup` for a delivered row; otherwise a diagnostic status listed under **Evidence and boundaries**. |
| `action` | `review_portfolio` on a delivered row — a routing hint, never an automated legal or business decision. |
| `confidence` | `high`, `medium`, or `low` — see **Decision routing** for the exact rule. |
| `sourceRowCount` | How many source rows contributed to this portfolio (may exceed `distinctPatentCount` when duplicate rows repeat the same patent). |
| `assignee` | The literal, whitespace-normalized assignee text — the grouping key, unchanged from your source spelling. |
| `distinctPatentCount` | Unique, syntactically valid `patentId` values for this assignee in the batch. Never a claim of the assignee's complete real-world portfolio. |
| `coObservedPatentCount` | Of those, how many were also observed under a different assignee spelling elsewhere in the batch. |
| `datePeriodCounts.{patentDate,filingDate,publicationDate,grantDate,priorityDate}` | `{ count, earliest, latest, yearlyBuckets }` per basis — five fully independent objects, never merged. `earliest`/`latest` are raw date strings, never re-derived. `yearlyBuckets` is `{ "YYYY": distinctPatentCount }`. |
| `missingMetadataCounts` | `{ title, url, jurisdiction, recordStatus, ...each date basis }` — how many distinct patents never carried a usable value for each field. |
| `recordConflicts` | Bounded list (cap 10) of `{ patentId, field, values, sourceRowIndexes }` — duplicate rows disagreeing on title or a date basis. |
| `recordConflictCount` | The exact total conflicts found, independent of the displayed list's 10-item cap. |
| `recordConflictsOmitted` | `recordConflictCount` minus `recordConflicts.length`. `0` when nothing was omitted. |
| `evidence` | Bounded list (cap 12) of `{ field: "patentId", value, title, url, coObserved, sourceRowIndex }` sample patents. |
| `evidenceOmitted` | `distinctPatentCount` minus `evidence.length`. `0` when nothing was omitted. |
| `observedAt` | The real latest strictly-valid capture timestamp (`checkedAt`/`scrapedAt`), compared by normalized instant. A capture time, never a patent event date, never "now." `null` when no row carried one. |
| `sourceObservationWindow` | `{ earliest, latest, validCount, totalRowCount }` across every accepted row — raw capture strings, never re-derived. |
| `businessPartial` | Product-level incompleteness: contributing source rows marked partial, capped evidence/conflicts, or capped source-row indexes. Runtime `partial` also includes source-reader limits. It is false in the displayed clean examples, not universally. |
| `sourceRowIndexes` | The specific offsets into your original batch that produced this row. |
| `partial` | `true` when evidence/conflicts were capped, a contributing row itself reported `partial: true`, or the configured row window wasn't fully read. |
| `sourceCoverage` | `{ complete, reason, droppedOversized }` — whether the reader established the end of the supplied source, including a bounded probe when a row limit was reached. |
| `product` / `schemaVersion` | Fixed identifiers (`"patent-assignee-period-rollup"` / `"1.0"`) for schema pinning. |
| `sourceDatasetId` / `sourceRunId` / `suppliedSourceRunId` / `sourceRunIdVerified` | Provenance for a dataset/run-sourced batch — `null` on an inline-items run. |
| `processedAt` | When this Actor processed the row — never a patent event date or source capture time. |

Diagnostics (never billed) share a smaller, honest shape: `{ product, schemaVersion, status, found: false, reason, sourceRowIndexes? }`, with `status` one of `invalid_row`, `source_row_failed`, `missing_assignee`, `missing_patent_id`, `invalid_patent_id`, `no_results`, `budget_stopped`, `partial_source`, or the run-level `max_results_reached` summary row.

### Evidence and boundaries

**What "found" actually means here.** A delivered portfolio assessment requires `found: true` with a nonempty `assignee`, at least one distinct valid `patentId`, and populated `evidence` — this Actor never fabricates a paid result from a batch that contained nothing usable for a given assignee.

**Diagnostics carry no result event.** Rejected rows produce statuses in the transform; delivery retains at most 200 diagnostic rows and reports truncation or oversized omissions in the summary. Typical statuses are: `invalid_row` (not an object), `source_row_failed` (the source itself reported `found: false`, `failed: true`, or a failure-shaped `status`/`error`), `missing_assignee` (no usable assignee text), `missing_patent_id` (no `patentId` at all), or `invalid_patent_id` (a `patentId` that doesn't match a supported real publication-number syntax). None of these can become a paid portfolio member.

**Why `maxInputRows`/`maxResults` caps and platform charge limits interact the way they do.** This Actor reads at most `maxInputRows` source rows and delivers at most `maxResults` paid portfolio assessments, independent of each other and both independent of the platform's own **Max total charge USD** run option — whichever bound is hit first ends delivery, and the delivered row(s) or diagnostic tell you exactly which one it was (`max_input_rows_reached`, `max_results_reached`, or `budget_stopped`). Before reading any source row, the Actor verifies the run's charge limit can cover at least one portfolio assessment at the confirmed live price; if it cannot, the run stops immediately with the free `budget_stopped` diagnostic shown above rather than reading part of your batch and then stalling.

**Delivery is a dataset write, then an explicit charge — never the reverse, and never guaranteed exactly-once.** Every delivered portfolio assessment is written to your run's Dataset *before* the corresponding `result-found` charge event is requested, and the two steps are not transactional. On any ambiguity about whether a write or a charge actually completed, this Actor fails closed rather than guessing — it never automatically retries a possibly-already-charged write, because a retry could double it. A run that fails partway through may still contain already-delivered, already-charged rows; that is expected behavior for a partial run, not a bug.

**Re-running is new processing, not deduplication.** This Actor's own-run guard only prevents an automatic *resurrection* of a run that already started paid work (for example, after a platform restart) — it is not a cross-run deduplication layer. Running this Actor again against the exact same input performs genuinely new processing and can bill again for the same assignees. If you need to avoid double-billing across scheduled refreshes, dedupe on your own side using `assignee` + `observedAt`, or only re-run against genuinely new upstream data.

**Source resolution precedence and permissions.** When both an explicit `datasetId`/`runId` and an Integrations `payload.resource` reference are present, they must agree — a mismatch is rejected outright. A `runId` (explicit or from `payload.resource.id`) is read with your own run's own granted permissions; no elevated access is used, and no upstream Actor is ever started. The **Source Dataset** field uses Apify's `resourcePicker` with an explicit READ-only grant — that grant, not the mere presence of a webhook payload, is what allows this Actor to read a private Dataset. A bare webhook envelope alone never grants private Dataset access on its own. Source resolution uses read-only GET requests against the fixed `https://api.apify.com` origin. Dataset output and billing use the Apify SDK and perform writes. Credentials belong in Authorization headers, never in URL query strings or inline source records.

**Bounded everything, always.** 1000 source rows / 4 MiB total input / 64 KiB per source row, per run. `evidence` is capped at 12 sample patents per assignee, `recordConflicts` at 10 — both with an exact omitted count and a `partial: true` flag when more exist than shown. `recordConflictCount`/`evidenceOmitted` are always an independent running total across your *entire* accepted batch, never approximated from the displayed list's length.

**What this Actor cannot verify.** It cannot confirm a real patent registry record exists behind a syntactically valid `patentId` — validation is against the *format* of real publication-number syntaxes, never a registry lookup. It cannot tell you whether two differently-spelled assignees are legally the same company, or whether a patent is valid, enforceable, or currently in force. None of these are claimed anywhere in this Actor's output.

### Decision routing

`confidence` is set by one deterministic rule, applied per assignee, after the full batch for that assignee has been aggregated:

1. **`low`** whenever `recordConflictCount > 0` for that assignee — i.e. at least one duplicate-row disagreement on a title or date-basis value was found anywhere in that assignee's patents. A conflict is a fact about your own data, and it always overrides the other two levels regardless of how much date coverage exists.
2. **`high`** when there are no conflicts and at least one of the five date bases has `count > 0` for that assignee — meaning at least one distinct patent carried a usable date value in some basis.
3. **`medium`** when there are no conflicts but *none* of the five date bases has any coverage at all — every distinct patent for this assignee is missing every date field this Actor recognizes.

Route accordingly:

- **`confidence: "low"`** → send to manual reconciliation before using any count from this assignee's portfolio in a report. Read `recordConflicts` (and request the full list via a follow-up run with a narrower batch if `recordConflictsOmitted > 0`) to find the exact `patentId`/field/rows that disagree, and resolve at the source before re-trusting the aggregate.
- **`confidence: "high"`** → safe to surface directly in an internal dashboard or status memo, with the usual caveat that `distinctPatentCount` describes the *batch*, not the assignee's real-world holdings.
- **`confidence: "medium"`** → treat as a coverage gap, not a data-quality problem: your source rows for this assignee simply never carried usable dates. Check `missingMetadataCounts` to see which specific date basis is absent, and consider re-scraping with a source that supplies it if date coverage matters for your use case.

`partial: true` is an orthogonal signal from `confidence` — it tells you the *displayed lists* (evidence, conflicts) were capped, or that your configured row window wasn't fully read this run, not that the underlying assessment is untrustworthy. A `high`-confidence, `partial: true` row may be shown only with its coverage warning: omitted or unread evidence can contain further conflicts, and high confidence does not certify completeness.

### Commercial playbooks

**Weekly assignee-watch digest.** Chain `zinin/patent-monitor` (or your Google Patents scraper) → this Actor, scheduled weekly via an Apify Task. Route `confidence: "low"` rows to a Slack/email digest tagged "needs review" and `confidence: "high"` rows straight into your internal filing tracker. Compare `datePeriodCounts.patentDate.yearlyBuckets` across successive weeks to see period coverage shift — the trend lives in your own comparison across runs, not inside this Actor.

**Pre-diligence patent-batch sanity check.** Before a target company's patent list goes to outside counsel for a real freedom-to-operate or portfolio-value opinion, run it through this Actor first. `recordConflicts` and `missingMetadataCounts` surface exactly the data-hygiene issues that would otherwise cost billable attorney hours to notice manually — resolve those first, then send the cleaned batch onward.

**Competitive filing-cadence snapshot.** Feed a competitor's known patent rows through this Actor quarterly. `datePeriodCounts.filingDate`/`publicationDate`/`grantDate` yearly buckets give an honest, source-scoped view of when their observed activity clustered — one input into a broader competitive-intelligence memo, never a standalone market-share claim.

**Internal IP-ops data-quality gate.** Insert this Actor as a validation step immediately after any patent scraper in your pipeline, before rows reach your BI warehouse. A `confidence: "low"` result blocks that assignee's batch from loading until a human resolves the conflict — a cheap, deterministic gate against the kind of duplicate-row disagreement that silently corrupts a downstream count table.

### Integration recipes

**Chained via Apify Integrations (recommended for scheduled pipelines).** In the Apify Console, open your `zinin/patent-monitor` (or Google Patents scraper) Task, add an "Actor/task run" integration pointed at this Actor, and map the upstream run's `{{resource.defaultDatasetId}}` into this Actor's **Source Dataset** field and keep any webhook envelope consistent with that explicit reference. The integration must actually supply the reference; the Actor does not invent or automatically populate a webhook envelope. A readable run record is checked for correspondence. If that metadata is unavailable but the explicit Dataset is readable, processing may continue with `sourceRunIdVerified: false`; it never claims the run link was verified.

**Direct API call.** Start a run via `POST https://api.apify.com/v2/acts/zinin~patent-assignee-period-rollup/runs?maxTotalChargeUsd=0.50` with your Authorization header, passing `{ "datasetId": "<upstream dataset id>", "maxInputRows": 200, "maxResults": 10 }` as the JSON body. Poll `GET /v2/actor-runs/<runId>` for `status: "SUCCEEDED"`, then read `GET /v2/datasets/<defaultDatasetId>/items` for the delivered rows.

**Webhook-notified pipeline.** Attach an Apify webhook to this Actor for `ACTOR.RUN.SUCCEEDED`, pointed at your own endpoint. The webhook payload itself never grants elevated access to the run's Dataset — treat it as a "go read the Dataset now" signal, and fetch rows via the Dataset API using your own stored token. Define the webhook with `doNotRetry: true` and never embed a customer credential in its configuration.

**MCP / agent tool use.** Pass the same `datasetId`/`runId`/`items` + `maxInputRows`/`maxResults` shape as any other caller. Surface `confidence`, `partial`, and `recordConflicts` directly to the end user rather than only the aggregate counts. They describe supplied evidence and route review; they do not certify real-world ownership or completeness.

The following webhook registration is a **template**, not a captured dispatch. Substitute your upstream Actor ID and configure the destination’s Dataset READ grant. A header placeholder is not a usable credential. The automatic mapping does not itself grant access.

```json
{
  "eventTypes": [
    "ACTOR.RUN.SUCCEEDED"
  ],
  "condition": {
    "actorId": "<YOUR_UPSTREAM_ACTOR_ID>"
  },
  "requestUrl": "https://api.apify.com/v2/acts/zinin~patent-assignee-period-rollup/runs?maxTotalChargeUsd=0.50",
  "headersTemplate": "{\"Authorization\":\"Bearer <YOUR_APIFY_TOKEN>\"}",
  "payloadTemplate": "{\"datasetId\":\"{{resource.defaultDatasetId}}\",\"payload\":{\"resource\":{{resource}}},\"maxInputRows\":100,\"maxResults\":2}",
  "doNotRetry": true
}
```

Finalization attempts to save `OUTPUT` and `SUMMARY`; storage failures can prevent either record from being saved. After an ambiguous write or charge, raw Dataset rows may exceed confirmed summary counters. Inspect the platform event counters before deciding to rerun.

### Operating guide

- **Start with the real prefill.** Run it once against the prefilled sample to confirm the delivered shape and confidence rule match your expectations — it costs the price of two portfolio assessments (or less, at your account's tier) and uses genuinely real, previously-observed public data.
- **Set `maxInputRows` to your batch's real size, not the default.** The default of 100 exists for a safe first test; a genuine assignee-watch batch may be larger. Under-setting this silently caps coverage (visible via `sourceCoverage.reason: "max_input_rows_reached"` and `partial: true`) — it does not fail the run, so watch for that flag rather than assuming a `SUCCEEDED` run read everything.
- **Set `maxResults` to your real number of distinct assignees, not the default of 2.** A real watch list with a dozen tracked assignees needs `maxResults` raised accordingly, or you will see `max_results_reached` and only get a partial set back.
- **Always set the platform's own Max total charge USD** for any run touching a batch you have not sized before — a cap below one result stops before source reads, while a cap covering only part of a batch can deliver that part and then stop. Inspect paid/free and budgetStopped counters.
- **Treat `recordConflicts` as a to-do list, not noise.** Every conflict is a real disagreement your own upstream source(s) produced — most commonly the same patent scraped twice with a title or date that changed between scrapes. Resolve at the source rather than silently trusting whichever value was observed first.
- **Do not rely on a single run for a moving batch.** Schedule this Actor to run on a cadence rather than treating one run's output as a permanent snapshot — `observedAt` and `sourceObservationWindow` on each row tell downstream consumers exactly how fresh that assessment was.
- **Keep an eye on `coObservedPatentCount`.** A nonzero value signals a spelling inconsistency or a genuine co-assignment worth a closer look; it will not resolve itself without a corporate-family-resolution step or a source-data fix.

### FAQ

**Does this Actor scrape any patent data itself?**
No. It is a pure post-processing rollup over rows you already have — from your own `zinin/patent-monitor`, a Google Patents scraper, or a hand-built list. It never launches an upstream Actor and never fetches anything from patents.google.com or any registry directly.

**Why are `patentDate` and `filingDate`/`publicationDate`/`grantDate`/`priorityDate` kept separate instead of one "date" field?**
Because they mean different, legally distinct things, and merging them would silently misrepresent your data. `zinin/patent-monitor` rows only ever carry `patentDate`; Google-Patents-shaped rows carry the other four as genuinely separate legal milestones. Reporting five independent bases, each honestly `0`-covered when a row didn't supply it, avoids fabricating a date basis a row never had.

**Why did my batch's assignee names come back as two separate portfolios when they're really the same company?**
Because this Actor's identity rule is deliberately literal: only whitespace trimming and internal-run collapsing are applied, never case-folding, fuzzy matching, or corporate-suffix stripping. `"Acme Inc."` and `"ACME, Inc."` are two rows in the output by design — corporate-family resolution requires business-entity knowledge this Actor deliberately does not embed.

**My `patentId` looks valid to me, but it came back as an `invalid_patent_id` diagnostic instead of a result. Why?**
The Actor validates against a specific, real publication-number grammar (country/office prefix, optional US `RE`/`D`/`PP` series or a `JPS`/`JPH`/`JPWO` Japanese-office prefix, digits, kind-code letter, optional trailing digits) defined by this Actor’s source contract. An ID that doesn't match this real grammar — a typo, a placeholder string, or an unsupported office format — is rejected rather than accepted as an opaque string, because accepting arbitrary text as a "patent identity" would let unrelated garbage strings masquerade as distinct patents.

**What happens if I supply both a `datasetId` and a `runId` that don't actually correspond to each other?**
When accessible run metadata proves the references disagree, the run returns `INVALID_INPUT` / `run_dataset_mismatch` before reading source rows. If the run metadata is unavailable but the explicit Dataset can be read, the Dataset remains the selected source and run provenance is explicitly unverified.

**Can I get more than 12 sample patents or 10 conflicts per assignee in one run's output?**
Not in a single delivered row — those caps keep each row's payload bounded and predictable. `evidenceOmitted`/`recordConflictsOmitted` always tell you the exact count beyond the cap; if you need further evidence, partition the source rows for that assignee into smaller batches and inspect omitted counts on each. A single-assignee filter alone does not remove per-assignee caps. Do not sum overlapping partitions without deduplicating patent identities.

**Will running this Actor again on the same dataset cost me twice?**
Yes, if the same assignees still qualify as useful portfolio assessments. This Actor has no cross-run deduplication, only a same-run resurrection guard. Build your own dedupe key (`assignee` + `observedAt`) on your side for a recurring schedule against overlapping data.

**Is a `high` confidence a claim that these patents are real, valid, or currently in force?**
No. `confidence` describes evidence coverage and internal consistency within your supplied batch only. It is never a claim about legal validity, enforceability, ownership, or any registry-verified fact.

### Sources and rights

This Actor processes only patent-record rows you supply — your own `zinin/patent-monitor` runs, a Google-Patents-shaped scraper's output (such as [`khadinakbar/google-patents-scraper`](https://apify.com/khadinakbar/google-patents-scraper)), or any hand-built inline list following the recognized row shapes above. It holds no scraping rights or licensing relationship of its own with any patent registry or database; you remain responsible for the terms under which your source data was originally obtained.

Related public Store Actors referenced or usable alongside this one, identified in the saved Apify Store research and public Actor metadata captured on 2026-09-23:

- [`zinin/patent-monitor`](https://apify.com/zinin/patent-monitor) — the primary own-ecosystem upstream source for this Actor's `patentDate`-basis rows.
- [`khadinakbar/google-patents-scraper`](https://apify.com/khadinakbar/google-patents-scraper) — Google Patents Scraper, the primary external source for this Actor's `filingDate`/`publicationDate`/`grantDate`/`priorityDate`-basis rows.

Public examples in this Actor's prefill and in this README are curated, provenance-tagged projections of actual public source runs, never synthetic fixtures — every value traces back to a real upstream Actor, run, and Dataset recorded in the row's own `__source` block. The saved public examples omit dates of birth, home addresses, nationality, and personal contact details. Fields supplied in your own records remain your responsibility, consistent with the business-record-only scope of the rows it processes.

- [`zinin/company-registry-enricher`](https://apify.com/zinin/company-registry-enricher) — separate corporate context for an analyst reviewing an assignee name; registry rows are not patent input and do not establish that similarly named assignees are the same legal entity.
- [`zinin/funding-round-tracker`](https://apify.com/zinin/funding-round-tracker) — separate filing context for company research; funding records are not patent input and neither imply patent ownership nor validate portfolio value.

# Actor input Schema

## `items` (type: `array`):

Use the saved real source example, paste compatible records, or select an existing Dataset/run. Public examples omit personal addresses, birth dates and nationality.

## `payload` (type: `object`):

Optional. Expected shape: { "resource": { "id": "<run id>", "defaultDatasetId": "<dataset id>", "actId": "<actor id>" } }. Ignored fields are harmless; a malformed resource.\* value is rejected, never silently ignored.

## `datasetId` (type: `string`):

Read an existing source Dataset with the permissions granted to this run. Overrides inline items. For Integrations, map {{resource.defaultDatasetId}} to this resourcePicker field. A webhook payload alone does not grant private Dataset access.

## `runId` (type: `string`):

Optional Actor run ID to read instead of Source Dataset. Its default Dataset is resolved with your run's own permissions — no elevated access is used, and no upstream Actor is started.

## `maxInputRows` (type: `integer`):

At most 1000 input rows, 4 MiB total and 64 KiB per source row. Coverage limits are reported; aggregate evidence is bounded separately.

## `maxResults` (type: `integer`):

Maximum useful portfolio assessment rows delivered; free diagnostics are separate. The platform Max total charge may stop delivery earlier.

## Actor input object example

```json
{
  "items": [
    {
      "recordType": "patent_evidence_record",
      "schemaVersion": "2.0.0",
      "found": true,
      "checkedAt": "2026-09-18T15:19:59.476Z",
      "observedAt": "2026-09-18T15:19:59.476Z",
      "patentId": "US12345678B2",
      "title": "Thermal management system for an energy storage assembly",
      "patentDate": "2026-07-14",
      "assignee": "Example Energy Systems Inc.",
      "url": "https://patents.google.com/patent/US12345678B2/en",
      "jurisdiction": "US",
      "recordStatus": "granted",
      "__source": {
        "actor": "zinin/patent-monitor",
        "actorId": "kcLdXz58zRI7SIml5",
        "runId": "mFJpsRFyQjfHh4zLK",
        "datasetId": "88yXMBVUNp8tNPliz",
        "sampleRowIndex": 0,
        "projection": "Public business-record fields only; observed values unchanged. Added __source is provenance, not upstream payload."
      }
    },
    {
      "patentId": "US10000000B2",
      "googlePatentsUrl": "https://patents.google.com/patent/US10000000B2/en",
      "scrapedAt": "2026-09-23T06:42:42.482Z",
      "mode": "details",
      "title": "Coherent LADAR using intra-pixel quadrature detection",
      "filingDate": "2015-03-10",
      "publicationDate": "2018-06-19",
      "grantDate": "2018-06-19",
      "priorityDate": "2015-03-10",
      "kindCode": "B2",
      "countryCode": "US",
      "type": "PATENT",
      "status": "GRANT",
      "assignee": "Raytheon Co",
      "cpc": [
        "G",
        "G01",
        "G01S",
        "G01S7/00",
        "G01S7/48",
        "G01S7/483",
        "G01S7/486",
        "G01S7/4861",
        "G01S7/4863",
        "G01S13/00",
        "G01S13/88",
        "G01S13/89",
        "G01S7/4865",
        "G01S7/491",
        "G01S7/4912",
        "G01S7/4913",
        "G01S7/4914",
        "G01S7/4917",
        "G01S17/00",
        "G01S17/88",
        "G01S17/89",
        "G01S17/894"
      ],
      "citationsBackward": [
        "US5093563A",
        "US5751830A",
        "US20030076485A1",
        "WO2005080928A1",
        "US20060227317A1",
        "JPS639877A",
        "US5565982A",
        "JP3332802B2",
        "JP3771777B2",
        "US6934034B2",
        "JP2005214927A",
        "US20060227316A1",
        "US7206062B2",
        "CN100578261C",
        "JP5514641B2",
        "US20130104661A1",
        "JP2013257302A",
        "JPWO2014203654A1",
        "US10000000B2"
      ],
      "citationsForward": [
        "US10845468B2",
        "US20180172806A1",
        "US11237252B2",
        "US20180156897A1",
        "US20220326355A1",
        "US12399278B1",
        "US12399279B1",
        "US12123950B2",
        "US12418719B2",
        "US10873738B2",
        "US12096121B2",
        "US11477363B2",
        "US11838626B2",
        "US11092690B1",
        "US11619718B2",
        "US11243296B2",
        "US10753736B2",
        "US11520021B2",
        "US11933967B2",
        "US12372318B2",
        "US12379185B2",
        "US12379177B2",
        "US10031215B1",
        "KR102373926B1",
        "EP3548840B1",
        "KR102254466B1",
        "US11624828B2",
        "KR102399757B1",
        "US10502618B2",
        "US9871339B1",
        "US10002986B1",
        "US10422880B2",
        "DE112018001060T5",
        "CN110832350B",
        "EP4246176A3",
        "CN113260873A",
        "US11822010B2",
        "US11415697B2",
        "CN110456366B",
        "IL321588A",
        "US11548433B2",
        "FR3112397B1",
        "CN111708024B",
        "EP4033270A4",
        "KR102628708B1",
        "US11740336B2",
        "US12216209B2",
        "US12153139B2",
        "US11567212B2",
        "CN113406664A",
        "WO2023191849A2",
        "US12130363B2",
        "US12366663B1",
        "US11592540B1",
        "US12571914B2"
      ],
      "citationsBackwardTotal": 19,
      "citationsForwardTotal": 55,
      "__source": {
        "actor": "khadinakbar/google-patents-scraper",
        "actorId": "9TNaptxQeIHf8bZNd",
        "runId": "xiAfEHKEl32fXSeJH",
        "datasetId": "DlbZZJT6kkyo0Utmq",
        "sampleRowIndex": 0,
        "projection": "Public business-record fields only; observed values unchanged. Added __source is provenance, not upstream payload."
      }
    },
    {
      "patentId": "US10000001B2",
      "googlePatentsUrl": "https://patents.google.com/patent/US10000001B2/en",
      "scrapedAt": "2026-09-23T06:42:46.090Z",
      "mode": "details",
      "title": "Injection molding machine and mold thickness control method",
      "filingDate": "2015-12-08",
      "publicationDate": "2018-06-19",
      "grantDate": "2018-06-19",
      "priorityDate": "2014-12-24",
      "kindCode": "B2",
      "countryCode": "US",
      "type": "PATENT",
      "status": "GRANT",
      "assignee": "LS Mtron Ltd",
      "cpc": [
        "B",
        "B29",
        "B29C",
        "B29C45/00",
        "B29C45/17",
        "B29C45/76",
        "B29C45/64",
        "B29C45/66",
        "B29C45/80",
        "B29C45/661",
        "G",
        "G05",
        "G05B",
        "G05B19/00",
        "G05B19/02",
        "G05B19/18",
        "G05B19/182",
        "G05B19/402",
        "B29C2945/00",
        "B29C2945/76",
        "B29C2945/76003",
        "B29C2945/76083",
        "B29C2945/76177",
        "B29C2945/76224",
        "B29C2945/76227",
        "B29C2945/76344",
        "B29C2945/76431",
        "B29C2945/76494",
        "B29C2945/76505",
        "B29C2945/76822",
        "B29C2945/76866",
        "B29C45/1751",
        "B29C45/7653",
        "G05B2219/00",
        "G05B2219/30",
        "G05B2219/45",
        "G05B2219/45244"
      ],
      "citationsBackward": [
        "JP3276727B2",
        "US20020022069A1",
        "US20030039719A1",
        "KR100512595B1",
        "US20050098912A1",
        "US20080211126A1",
        "US20090026644A1",
        "US7804268B2",
        "JP2009208412A",
        "US20120146260A1",
        "US9296144B2",
        "JP2013132796A",
        "US20140134284A1",
        "US9022767B2",
        "US9090016B2",
        "US9108352B2",
        "US9566732B2",
        "CN1428232A",
        "JP3962725B2",
        "JP4146381B2"
      ],
      "citationsForward": [
        "US12600071B2",
        "CN109414860B",
        "JP6444955B2",
        "JP6538763B2",
        "US11850782B2",
        "CN111703053B"
      ],
      "citationsBackwardTotal": 20,
      "citationsForwardTotal": 6,
      "__source": {
        "actor": "khadinakbar/google-patents-scraper",
        "actorId": "9TNaptxQeIHf8bZNd",
        "runId": "xiAfEHKEl32fXSeJH",
        "datasetId": "DlbZZJT6kkyo0Utmq",
        "sampleRowIndex": 1,
        "projection": "Public business-record fields only; observed values unchanged. Added __source is provenance, not upstream payload."
      }
    }
  ],
  "payload": {},
  "maxInputRows": 100,
  "maxResults": 2
}
```

# Actor output Schema

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

API URL for the default dataset items produced by this run.

## `summary` (type: `string`):

API URL for the OUTPUT record in the default key-value store.

# 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 = {
    "items": [
        {
            "recordType": "patent_evidence_record",
            "schemaVersion": "2.0.0",
            "found": true,
            "checkedAt": "2026-09-18T15:19:59.476Z",
            "observedAt": "2026-09-18T15:19:59.476Z",
            "patentId": "US12345678B2",
            "title": "Thermal management system for an energy storage assembly",
            "patentDate": "2026-07-14",
            "assignee": "Example Energy Systems Inc.",
            "url": "https://patents.google.com/patent/US12345678B2/en",
            "jurisdiction": "US",
            "recordStatus": "granted",
            "__source": {
                "actor": "zinin/patent-monitor",
                "actorId": "kcLdXz58zRI7SIml5",
                "runId": "mFJpsRFyQjfHh4zLK",
                "datasetId": "88yXMBVUNp8tNPliz",
                "sampleRowIndex": 0,
                "projection": "Public business-record fields only; observed values unchanged. Added __source is provenance, not upstream payload."
            }
        },
        {
            "patentId": "US10000000B2",
            "googlePatentsUrl": "https://patents.google.com/patent/US10000000B2/en",
            "scrapedAt": "2026-09-23T06:42:42.482Z",
            "mode": "details",
            "title": "Coherent LADAR using intra-pixel quadrature detection",
            "filingDate": "2015-03-10",
            "publicationDate": "2018-06-19",
            "grantDate": "2018-06-19",
            "priorityDate": "2015-03-10",
            "kindCode": "B2",
            "countryCode": "US",
            "type": "PATENT",
            "status": "GRANT",
            "assignee": "Raytheon Co",
            "cpc": [
                "G",
                "G01",
                "G01S",
                "G01S7/00",
                "G01S7/48",
                "G01S7/483",
                "G01S7/486",
                "G01S7/4861",
                "G01S7/4863",
                "G01S13/00",
                "G01S13/88",
                "G01S13/89",
                "G01S7/4865",
                "G01S7/491",
                "G01S7/4912",
                "G01S7/4913",
                "G01S7/4914",
                "G01S7/4917",
                "G01S17/00",
                "G01S17/88",
                "G01S17/89",
                "G01S17/894"
            ],
            "citationsBackward": [
                "US5093563A",
                "US5751830A",
                "US20030076485A1",
                "WO2005080928A1",
                "US20060227317A1",
                "JPS639877A",
                "US5565982A",
                "JP3332802B2",
                "JP3771777B2",
                "US6934034B2",
                "JP2005214927A",
                "US20060227316A1",
                "US7206062B2",
                "CN100578261C",
                "JP5514641B2",
                "US20130104661A1",
                "JP2013257302A",
                "JPWO2014203654A1",
                "US10000000B2"
            ],
            "citationsForward": [
                "US10845468B2",
                "US20180172806A1",
                "US11237252B2",
                "US20180156897A1",
                "US20220326355A1",
                "US12399278B1",
                "US12399279B1",
                "US12123950B2",
                "US12418719B2",
                "US10873738B2",
                "US12096121B2",
                "US11477363B2",
                "US11838626B2",
                "US11092690B1",
                "US11619718B2",
                "US11243296B2",
                "US10753736B2",
                "US11520021B2",
                "US11933967B2",
                "US12372318B2",
                "US12379185B2",
                "US12379177B2",
                "US10031215B1",
                "KR102373926B1",
                "EP3548840B1",
                "KR102254466B1",
                "US11624828B2",
                "KR102399757B1",
                "US10502618B2",
                "US9871339B1",
                "US10002986B1",
                "US10422880B2",
                "DE112018001060T5",
                "CN110832350B",
                "EP4246176A3",
                "CN113260873A",
                "US11822010B2",
                "US11415697B2",
                "CN110456366B",
                "IL321588A",
                "US11548433B2",
                "FR3112397B1",
                "CN111708024B",
                "EP4033270A4",
                "KR102628708B1",
                "US11740336B2",
                "US12216209B2",
                "US12153139B2",
                "US11567212B2",
                "CN113406664A",
                "WO2023191849A2",
                "US12130363B2",
                "US12366663B1",
                "US11592540B1",
                "US12571914B2"
            ],
            "citationsBackwardTotal": 19,
            "citationsForwardTotal": 55,
            "__source": {
                "actor": "khadinakbar/google-patents-scraper",
                "actorId": "9TNaptxQeIHf8bZNd",
                "runId": "xiAfEHKEl32fXSeJH",
                "datasetId": "DlbZZJT6kkyo0Utmq",
                "sampleRowIndex": 0,
                "projection": "Public business-record fields only; observed values unchanged. Added __source is provenance, not upstream payload."
            }
        },
        {
            "patentId": "US10000001B2",
            "googlePatentsUrl": "https://patents.google.com/patent/US10000001B2/en",
            "scrapedAt": "2026-09-23T06:42:46.090Z",
            "mode": "details",
            "title": "Injection molding machine and mold thickness control method",
            "filingDate": "2015-12-08",
            "publicationDate": "2018-06-19",
            "grantDate": "2018-06-19",
            "priorityDate": "2014-12-24",
            "kindCode": "B2",
            "countryCode": "US",
            "type": "PATENT",
            "status": "GRANT",
            "assignee": "LS Mtron Ltd",
            "cpc": [
                "B",
                "B29",
                "B29C",
                "B29C45/00",
                "B29C45/17",
                "B29C45/76",
                "B29C45/64",
                "B29C45/66",
                "B29C45/80",
                "B29C45/661",
                "G",
                "G05",
                "G05B",
                "G05B19/00",
                "G05B19/02",
                "G05B19/18",
                "G05B19/182",
                "G05B19/402",
                "B29C2945/00",
                "B29C2945/76",
                "B29C2945/76003",
                "B29C2945/76083",
                "B29C2945/76177",
                "B29C2945/76224",
                "B29C2945/76227",
                "B29C2945/76344",
                "B29C2945/76431",
                "B29C2945/76494",
                "B29C2945/76505",
                "B29C2945/76822",
                "B29C2945/76866",
                "B29C45/1751",
                "B29C45/7653",
                "G05B2219/00",
                "G05B2219/30",
                "G05B2219/45",
                "G05B2219/45244"
            ],
            "citationsBackward": [
                "JP3276727B2",
                "US20020022069A1",
                "US20030039719A1",
                "KR100512595B1",
                "US20050098912A1",
                "US20080211126A1",
                "US20090026644A1",
                "US7804268B2",
                "JP2009208412A",
                "US20120146260A1",
                "US9296144B2",
                "JP2013132796A",
                "US20140134284A1",
                "US9022767B2",
                "US9090016B2",
                "US9108352B2",
                "US9566732B2",
                "CN1428232A",
                "JP3962725B2",
                "JP4146381B2"
            ],
            "citationsForward": [
                "US12600071B2",
                "CN109414860B",
                "JP6444955B2",
                "JP6538763B2",
                "US11850782B2",
                "CN111703053B"
            ],
            "citationsBackwardTotal": 20,
            "citationsForwardTotal": 6,
            "__source": {
                "actor": "khadinakbar/google-patents-scraper",
                "actorId": "9TNaptxQeIHf8bZNd",
                "runId": "xiAfEHKEl32fXSeJH",
                "datasetId": "DlbZZJT6kkyo0Utmq",
                "sampleRowIndex": 1,
                "projection": "Public business-record fields only; observed values unchanged. Added __source is provenance, not upstream payload."
            }
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("zinin/patent-assignee-period-rollup").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 = { "items": [
        {
            "recordType": "patent_evidence_record",
            "schemaVersion": "2.0.0",
            "found": True,
            "checkedAt": "2026-09-18T15:19:59.476Z",
            "observedAt": "2026-09-18T15:19:59.476Z",
            "patentId": "US12345678B2",
            "title": "Thermal management system for an energy storage assembly",
            "patentDate": "2026-07-14",
            "assignee": "Example Energy Systems Inc.",
            "url": "https://patents.google.com/patent/US12345678B2/en",
            "jurisdiction": "US",
            "recordStatus": "granted",
            "__source": {
                "actor": "zinin/patent-monitor",
                "actorId": "kcLdXz58zRI7SIml5",
                "runId": "mFJpsRFyQjfHh4zLK",
                "datasetId": "88yXMBVUNp8tNPliz",
                "sampleRowIndex": 0,
                "projection": "Public business-record fields only; observed values unchanged. Added __source is provenance, not upstream payload.",
            },
        },
        {
            "patentId": "US10000000B2",
            "googlePatentsUrl": "https://patents.google.com/patent/US10000000B2/en",
            "scrapedAt": "2026-09-23T06:42:42.482Z",
            "mode": "details",
            "title": "Coherent LADAR using intra-pixel quadrature detection",
            "filingDate": "2015-03-10",
            "publicationDate": "2018-06-19",
            "grantDate": "2018-06-19",
            "priorityDate": "2015-03-10",
            "kindCode": "B2",
            "countryCode": "US",
            "type": "PATENT",
            "status": "GRANT",
            "assignee": "Raytheon Co",
            "cpc": [
                "G",
                "G01",
                "G01S",
                "G01S7/00",
                "G01S7/48",
                "G01S7/483",
                "G01S7/486",
                "G01S7/4861",
                "G01S7/4863",
                "G01S13/00",
                "G01S13/88",
                "G01S13/89",
                "G01S7/4865",
                "G01S7/491",
                "G01S7/4912",
                "G01S7/4913",
                "G01S7/4914",
                "G01S7/4917",
                "G01S17/00",
                "G01S17/88",
                "G01S17/89",
                "G01S17/894",
            ],
            "citationsBackward": [
                "US5093563A",
                "US5751830A",
                "US20030076485A1",
                "WO2005080928A1",
                "US20060227317A1",
                "JPS639877A",
                "US5565982A",
                "JP3332802B2",
                "JP3771777B2",
                "US6934034B2",
                "JP2005214927A",
                "US20060227316A1",
                "US7206062B2",
                "CN100578261C",
                "JP5514641B2",
                "US20130104661A1",
                "JP2013257302A",
                "JPWO2014203654A1",
                "US10000000B2",
            ],
            "citationsForward": [
                "US10845468B2",
                "US20180172806A1",
                "US11237252B2",
                "US20180156897A1",
                "US20220326355A1",
                "US12399278B1",
                "US12399279B1",
                "US12123950B2",
                "US12418719B2",
                "US10873738B2",
                "US12096121B2",
                "US11477363B2",
                "US11838626B2",
                "US11092690B1",
                "US11619718B2",
                "US11243296B2",
                "US10753736B2",
                "US11520021B2",
                "US11933967B2",
                "US12372318B2",
                "US12379185B2",
                "US12379177B2",
                "US10031215B1",
                "KR102373926B1",
                "EP3548840B1",
                "KR102254466B1",
                "US11624828B2",
                "KR102399757B1",
                "US10502618B2",
                "US9871339B1",
                "US10002986B1",
                "US10422880B2",
                "DE112018001060T5",
                "CN110832350B",
                "EP4246176A3",
                "CN113260873A",
                "US11822010B2",
                "US11415697B2",
                "CN110456366B",
                "IL321588A",
                "US11548433B2",
                "FR3112397B1",
                "CN111708024B",
                "EP4033270A4",
                "KR102628708B1",
                "US11740336B2",
                "US12216209B2",
                "US12153139B2",
                "US11567212B2",
                "CN113406664A",
                "WO2023191849A2",
                "US12130363B2",
                "US12366663B1",
                "US11592540B1",
                "US12571914B2",
            ],
            "citationsBackwardTotal": 19,
            "citationsForwardTotal": 55,
            "__source": {
                "actor": "khadinakbar/google-patents-scraper",
                "actorId": "9TNaptxQeIHf8bZNd",
                "runId": "xiAfEHKEl32fXSeJH",
                "datasetId": "DlbZZJT6kkyo0Utmq",
                "sampleRowIndex": 0,
                "projection": "Public business-record fields only; observed values unchanged. Added __source is provenance, not upstream payload.",
            },
        },
        {
            "patentId": "US10000001B2",
            "googlePatentsUrl": "https://patents.google.com/patent/US10000001B2/en",
            "scrapedAt": "2026-09-23T06:42:46.090Z",
            "mode": "details",
            "title": "Injection molding machine and mold thickness control method",
            "filingDate": "2015-12-08",
            "publicationDate": "2018-06-19",
            "grantDate": "2018-06-19",
            "priorityDate": "2014-12-24",
            "kindCode": "B2",
            "countryCode": "US",
            "type": "PATENT",
            "status": "GRANT",
            "assignee": "LS Mtron Ltd",
            "cpc": [
                "B",
                "B29",
                "B29C",
                "B29C45/00",
                "B29C45/17",
                "B29C45/76",
                "B29C45/64",
                "B29C45/66",
                "B29C45/80",
                "B29C45/661",
                "G",
                "G05",
                "G05B",
                "G05B19/00",
                "G05B19/02",
                "G05B19/18",
                "G05B19/182",
                "G05B19/402",
                "B29C2945/00",
                "B29C2945/76",
                "B29C2945/76003",
                "B29C2945/76083",
                "B29C2945/76177",
                "B29C2945/76224",
                "B29C2945/76227",
                "B29C2945/76344",
                "B29C2945/76431",
                "B29C2945/76494",
                "B29C2945/76505",
                "B29C2945/76822",
                "B29C2945/76866",
                "B29C45/1751",
                "B29C45/7653",
                "G05B2219/00",
                "G05B2219/30",
                "G05B2219/45",
                "G05B2219/45244",
            ],
            "citationsBackward": [
                "JP3276727B2",
                "US20020022069A1",
                "US20030039719A1",
                "KR100512595B1",
                "US20050098912A1",
                "US20080211126A1",
                "US20090026644A1",
                "US7804268B2",
                "JP2009208412A",
                "US20120146260A1",
                "US9296144B2",
                "JP2013132796A",
                "US20140134284A1",
                "US9022767B2",
                "US9090016B2",
                "US9108352B2",
                "US9566732B2",
                "CN1428232A",
                "JP3962725B2",
                "JP4146381B2",
            ],
            "citationsForward": [
                "US12600071B2",
                "CN109414860B",
                "JP6444955B2",
                "JP6538763B2",
                "US11850782B2",
                "CN111703053B",
            ],
            "citationsBackwardTotal": 20,
            "citationsForwardTotal": 6,
            "__source": {
                "actor": "khadinakbar/google-patents-scraper",
                "actorId": "9TNaptxQeIHf8bZNd",
                "runId": "xiAfEHKEl32fXSeJH",
                "datasetId": "DlbZZJT6kkyo0Utmq",
                "sampleRowIndex": 1,
                "projection": "Public business-record fields only; observed values unchanged. Added __source is provenance, not upstream payload.",
            },
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("zinin/patent-assignee-period-rollup").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 '{
  "items": [
    {
      "recordType": "patent_evidence_record",
      "schemaVersion": "2.0.0",
      "found": true,
      "checkedAt": "2026-09-18T15:19:59.476Z",
      "observedAt": "2026-09-18T15:19:59.476Z",
      "patentId": "US12345678B2",
      "title": "Thermal management system for an energy storage assembly",
      "patentDate": "2026-07-14",
      "assignee": "Example Energy Systems Inc.",
      "url": "https://patents.google.com/patent/US12345678B2/en",
      "jurisdiction": "US",
      "recordStatus": "granted",
      "__source": {
        "actor": "zinin/patent-monitor",
        "actorId": "kcLdXz58zRI7SIml5",
        "runId": "mFJpsRFyQjfHh4zLK",
        "datasetId": "88yXMBVUNp8tNPliz",
        "sampleRowIndex": 0,
        "projection": "Public business-record fields only; observed values unchanged. Added __source is provenance, not upstream payload."
      }
    },
    {
      "patentId": "US10000000B2",
      "googlePatentsUrl": "https://patents.google.com/patent/US10000000B2/en",
      "scrapedAt": "2026-09-23T06:42:42.482Z",
      "mode": "details",
      "title": "Coherent LADAR using intra-pixel quadrature detection",
      "filingDate": "2015-03-10",
      "publicationDate": "2018-06-19",
      "grantDate": "2018-06-19",
      "priorityDate": "2015-03-10",
      "kindCode": "B2",
      "countryCode": "US",
      "type": "PATENT",
      "status": "GRANT",
      "assignee": "Raytheon Co",
      "cpc": [
        "G",
        "G01",
        "G01S",
        "G01S7/00",
        "G01S7/48",
        "G01S7/483",
        "G01S7/486",
        "G01S7/4861",
        "G01S7/4863",
        "G01S13/00",
        "G01S13/88",
        "G01S13/89",
        "G01S7/4865",
        "G01S7/491",
        "G01S7/4912",
        "G01S7/4913",
        "G01S7/4914",
        "G01S7/4917",
        "G01S17/00",
        "G01S17/88",
        "G01S17/89",
        "G01S17/894"
      ],
      "citationsBackward": [
        "US5093563A",
        "US5751830A",
        "US20030076485A1",
        "WO2005080928A1",
        "US20060227317A1",
        "JPS639877A",
        "US5565982A",
        "JP3332802B2",
        "JP3771777B2",
        "US6934034B2",
        "JP2005214927A",
        "US20060227316A1",
        "US7206062B2",
        "CN100578261C",
        "JP5514641B2",
        "US20130104661A1",
        "JP2013257302A",
        "JPWO2014203654A1",
        "US10000000B2"
      ],
      "citationsForward": [
        "US10845468B2",
        "US20180172806A1",
        "US11237252B2",
        "US20180156897A1",
        "US20220326355A1",
        "US12399278B1",
        "US12399279B1",
        "US12123950B2",
        "US12418719B2",
        "US10873738B2",
        "US12096121B2",
        "US11477363B2",
        "US11838626B2",
        "US11092690B1",
        "US11619718B2",
        "US11243296B2",
        "US10753736B2",
        "US11520021B2",
        "US11933967B2",
        "US12372318B2",
        "US12379185B2",
        "US12379177B2",
        "US10031215B1",
        "KR102373926B1",
        "EP3548840B1",
        "KR102254466B1",
        "US11624828B2",
        "KR102399757B1",
        "US10502618B2",
        "US9871339B1",
        "US10002986B1",
        "US10422880B2",
        "DE112018001060T5",
        "CN110832350B",
        "EP4246176A3",
        "CN113260873A",
        "US11822010B2",
        "US11415697B2",
        "CN110456366B",
        "IL321588A",
        "US11548433B2",
        "FR3112397B1",
        "CN111708024B",
        "EP4033270A4",
        "KR102628708B1",
        "US11740336B2",
        "US12216209B2",
        "US12153139B2",
        "US11567212B2",
        "CN113406664A",
        "WO2023191849A2",
        "US12130363B2",
        "US12366663B1",
        "US11592540B1",
        "US12571914B2"
      ],
      "citationsBackwardTotal": 19,
      "citationsForwardTotal": 55,
      "__source": {
        "actor": "khadinakbar/google-patents-scraper",
        "actorId": "9TNaptxQeIHf8bZNd",
        "runId": "xiAfEHKEl32fXSeJH",
        "datasetId": "DlbZZJT6kkyo0Utmq",
        "sampleRowIndex": 0,
        "projection": "Public business-record fields only; observed values unchanged. Added __source is provenance, not upstream payload."
      }
    },
    {
      "patentId": "US10000001B2",
      "googlePatentsUrl": "https://patents.google.com/patent/US10000001B2/en",
      "scrapedAt": "2026-09-23T06:42:46.090Z",
      "mode": "details",
      "title": "Injection molding machine and mold thickness control method",
      "filingDate": "2015-12-08",
      "publicationDate": "2018-06-19",
      "grantDate": "2018-06-19",
      "priorityDate": "2014-12-24",
      "kindCode": "B2",
      "countryCode": "US",
      "type": "PATENT",
      "status": "GRANT",
      "assignee": "LS Mtron Ltd",
      "cpc": [
        "B",
        "B29",
        "B29C",
        "B29C45/00",
        "B29C45/17",
        "B29C45/76",
        "B29C45/64",
        "B29C45/66",
        "B29C45/80",
        "B29C45/661",
        "G",
        "G05",
        "G05B",
        "G05B19/00",
        "G05B19/02",
        "G05B19/18",
        "G05B19/182",
        "G05B19/402",
        "B29C2945/00",
        "B29C2945/76",
        "B29C2945/76003",
        "B29C2945/76083",
        "B29C2945/76177",
        "B29C2945/76224",
        "B29C2945/76227",
        "B29C2945/76344",
        "B29C2945/76431",
        "B29C2945/76494",
        "B29C2945/76505",
        "B29C2945/76822",
        "B29C2945/76866",
        "B29C45/1751",
        "B29C45/7653",
        "G05B2219/00",
        "G05B2219/30",
        "G05B2219/45",
        "G05B2219/45244"
      ],
      "citationsBackward": [
        "JP3276727B2",
        "US20020022069A1",
        "US20030039719A1",
        "KR100512595B1",
        "US20050098912A1",
        "US20080211126A1",
        "US20090026644A1",
        "US7804268B2",
        "JP2009208412A",
        "US20120146260A1",
        "US9296144B2",
        "JP2013132796A",
        "US20140134284A1",
        "US9022767B2",
        "US9090016B2",
        "US9108352B2",
        "US9566732B2",
        "CN1428232A",
        "JP3962725B2",
        "JP4146381B2"
      ],
      "citationsForward": [
        "US12600071B2",
        "CN109414860B",
        "JP6444955B2",
        "JP6538763B2",
        "US11850782B2",
        "CN111703053B"
      ],
      "citationsBackwardTotal": 20,
      "citationsForwardTotal": 6,
      "__source": {
        "actor": "khadinakbar/google-patents-scraper",
        "actorId": "9TNaptxQeIHf8bZNd",
        "runId": "xiAfEHKEl32fXSeJH",
        "datasetId": "DlbZZJT6kkyo0Utmq",
        "sampleRowIndex": 1,
        "projection": "Public business-record fields only; observed values unchanged. Added __source is provenance, not upstream payload."
      }
    }
  ]
}' |
apify call zinin/patent-assignee-period-rollup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zinin/patent-assignee-period-rollup"
        }
    }
}
```

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/cJYsdGbMROhiJ3zJt/builds/zIPHAGMAIQ9XaLJyT/openapi.json
