USPTO Patent Maintenance-Fee Lapse Monitor — FTO Tracker avatar

USPTO Patent Maintenance-Fee Lapse Monitor — FTO Tracker

Pricing

from $4.40 / 1,000 results

Go to Apify Store
USPTO Patent Maintenance-Fee Lapse Monitor — FTO Tracker

USPTO Patent Maintenance-Fee Lapse Monitor — FTO Tracker

Expired patent tracker: US patents lapsed for non-payment of maintenance fees — now public domain. Weekly USPTO bulk events filtered to lapse/reinstatement, with grant date, patent age, entity size and Google Patents links.

Pricing

from $4.40 / 1,000 results

Rating

0.0

(0)

Developer

Kyle Maloney

Kyle Maloney

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

Share

Expired patent tracker: US patents lapsed for non-payment of maintenance fees, sourced directly from USPTO's official bulk maintenance-fee event product (PTMNFEE2) on the USPTO Open Data Portal (api.uspto.gov / data.uspto.gov — USPTO retired the old bulkdata.uspto.gov host in 2026). Every US utility patent owner must pay a maintenance fee at 4, 8, and 12 years after grant or the patent expires and enters the public domain. This actor surfaces exactly those lapse events — a freedom-to-operate (FTO) signal that is otherwise buried in a raw government text dump nobody parses into a searchable feed.

It also checks whether the patent came back. A lapse is not permanent: under 37 CFR 1.378 the owner can petition to accept a delayed payment, and USPTO records the revival as further events on the same patent. Measured on the 2026-05-26 snapshot, 1.51% of the patents that lapsed two years earlier had since been revived (204 of 13,519), and 0.13% were already revived inside the very same weekly file. Every lapse row therefore carries revived_after_lapse, and fto_flag is only true once that check has actually run.

Who this is for

  • IP / freedom-to-operate counsel — screening whether a blocking patent has quietly lapsed before advising a client to design around it or license it.
  • Competitive intelligence teams — tracking when a competitor (or anyone) lets a patent lapse, signaling abandoned R&D or a deprioritized product line.
  • Patent brokers & licensing shops — recently-lapsed, recently-granted patents can still be re-filed as a continuation or reveal licensing opportunities before the underlying tech is picked up by someone else.
  • R&D / product strategy — mining the public domain for technology that was patented and then abandoned, now free to build on.

What it does

  1. Resolves the newest weekly USPTO PTMNFEE2 snapshot through the Open Data Portal. Identifying it is free (product metadata sits in ODP's 5,000,000-calls-per-week bucket), so every run knows which week it is in before deciding whether to spend a download. If the same question has already been answered against that snapshot, the cached answer is replayed and nothing is downloaded — see Download quota below.
  2. Streams the whole ~195 MB zip — the entire file, every run — parsing USPTO's fixed-width 57-character event layout by byte offset. The full file is never held in memory.
  3. Classifies each event against USPTO's own code dictionary, which ships inside the same zip (163 documented codes), so event_code_description is USPTO's wording, not ours, and an unknown code fails the run instead of being quietly bucketed as "other".
  4. Groups every event by patent (USPTO lists a patent's events contiguously) and, for each lapse, looks for a post-expiration revivalEXPX, a granted petition (PMFG/PTGR), a delayed-payment petition (M1558/M2560/…) or an accepted maintenance-fee payment.
  5. Returns a normalized, filterable feed with a direct Google Patents link, plus the honest denominator: matches_in_window_total is how many rows matched in the whole snapshot, and results_truncated says whether maxResults cut the answer short.

Example input

{
"mode": "lapsed",
"lookbackWeeks": 4,
"grantYearMin": 2018,
"maxResults": 500
}
  • mode"lapsed" (default) returns only expiration events; "reinstated" returns patents that came back from expiration (EXPX); "all_events" returns everything including routine fee payments (useful for building a full per-patent fee history).
  • lookbackWeeks — how far back to include events (default 4 ≈ 1 month). Applied as an event-date window against the snapshot that actually answered.
  • grantYearMin / grantYearMax — optional. Recently-granted patents that already lapsed tend to be the most actionable FTO signal (an abandoned patent from 3 years ago vs. one that expired at the natural end of its 20-year term).
  • maxResults — cap on rows returned (default 500). A 4-week window typically holds ~18,000 lapse events, so the default is a slice: the run returns the most recent ones and reports the true total in matches_in_window_total.
  • odpApiKey — optional. Your own FREE USPTO Open Data Portal API key (register at data.uspto.gov, ~2 min). If left blank the actor uses its built-in default key. USPTO scopes its download allowance to the API key, so supplying your own gives you an entirely separate budget (and the actor tracks it separately too).
  • allowFullFile — legacy switch from the retired bulkdata.uspto.gov host; ignored on the ODP path (the snapshot is always streamed, never fully held in memory).

Output fields

FieldDescription
patent_numberUS patent number, zero padding stripped (11324169, RE45927, D1000000)
patent_kindutility, reissue, design, plant, sir or defensive_publication
application_numberAssociated USPTO application number
event_codeRaw USPTO event code (EXP., EXPX, M1551, PMFG, …); null on the rare row USPTO ships with a blank code
event_code_descriptionUSPTO's own description of that code, read from the dictionary shipped inside the same zip
event_typeNormalized: lapsed, reinstated, fee_paid, or other
event_dateDate of the maintenance-fee event (YYYY-MM-DD)
grant_datePatent grant date (YYYY-MM-DD)
filing_dateOriginal application filing date (YYYY-MM-DD)
patent_age_years_at_eventYears between grant and event (1 decimal place)
entity_sizelarge / small / micro — from the fee code, else the entity-indicator column
entity_indicator_rawRaw USPTO entity column: N (undiscounted), Y (small), M (micro)
revived_after_lapseLapse rows only. true = USPTO recorded a post-expiration revival for this patent; false = the patent's full event history was checked and there is none; null = not checked
revival_event_codeCode of the earliest revival event (e.g. PMFG, M1558, EXPX), else null
revival_event_dateDate of that revival event, else null
post_lapse_event_codesEvery event recorded after the lapse, as CODE@YYYY-MM-DD, comma separated — including non-revival signals such as a petition merely filed (PMFP)
fto_flagtrue only when this is a lapse and no revival was found; false when the patent was revived or the row is not a lapse; null when the revival check could not run
patent_event_countHow many maintenance-fee events the snapshot holds for this patent
latest_event_code / latest_event_dateThe most recent event on this patent in the snapshot
google_patents_urlDirect link to the patent on Google Patents
source_fileThe USPTO snapshot zip this event was parsed from
snapshot_dateDate of the weekly USPTO cumulative snapshot this row was read from
snapshot_max_event_dateNewest event date found anywhere in that snapshot — its true data end
window_start / window_endThe event-date window this run covered
snapshot_is_newest_availabletrue if answered from USPTO's newest weekly file, false if an older one had to be used, null if not checked
newest_available_snapshotNewest weekly snapshot USPTO offered at run time
snapshot_lag_daysDays between the snapshot that answered and the newest one (0 = fully current)
matches_in_window_totalTotal rows matching your query in the whole snapshot, before maxResults
results_truncatedtrue when matches_in_window_total exceeded maxResults
scan_completetrue when the entire snapshot was streamed and counted
source_lines_scanned / source_lines_unparsedLines read, and lines that did not parse as an event
served_from_cachetrue when this answer was replayed from the actor's cached copy of the same snapshot and the same query, so no USPTO download was spent; false when the snapshot was downloaded and parsed on this run
answer_computed_atUTC timestamp of the run that actually streamed and parsed the snapshot. On a replay this is earlier than the current run, so freshness is never overstated
downloads_used_this_runRequests this run made against USPTO's per-file download allowance (0 on a cache hit)
download_budget_remainingDownloads the actor will still allow itself against the snapshot it served, under a self-imposed cap set below USPTO's documented 20. A conservative internal count — USPTO exposes no remaining-quota counter

Download quota, and why this actor caches

USPTO documents the constraint plainly on data.uspto.gov/apis/api-rate-limits:

"For the same file downloaded using the Bulk Datasets Downloads API, you are limited to 20 downloads per year using your API key" "You can download up to 5 files per 10 seconds from the same IP address."

The allowance is scoped to the API key and the file, not to the caller's IP — the same counter continues across different networks, so a proxy changes nothing. Because USPTO publishes a new file every Tuesday, the practical ceiling is 20 runs during the week a given snapshot is the newest one.

This actor therefore keeps a named cache keyed by (snapshot date, query). The first run of the week against a given question streams and parses the 195 MB file; every repeat of the same question against the same weekly snapshot answers from cache and downloads nothing. A new USPTO release invalidates the cache automatically, so freshness always wins when it is available. It also keeps a per-key ledger of download attempts, so a file USPTO has reported exhausted is never probed again — a rejected request still increments USPTO's counter.

Steady-state cost is therefore about one download per week per distinct question, roughly 5% of the allowance, and every row states what it cost (served_from_cache, downloads_used_this_run, download_budget_remaining).

When the newest snapshot genuinely cannot be obtained, the actor falls back to the next-newest — so the answer can be a week or two behind.

How the lookback window works

lookbackWeeks is measured back from the snapshot that actually answered, not from today. window_start / window_end state that period exactly on every row, and snapshot_lag_days states how far behind USPTO's newest file it is. If no obtainable snapshot reaches the requested window, the run fails loudly with 0 rows billed rather than reporting "no lapses found".

What makes a run fail instead of returning a thin answer

Every gate below runs before a single row is pushed, so a failure bills nothing:

  • the downloaded byte count must match the Content-Length of the snapshot (a truncated body otherwise ends the stream normally and looks like a complete answer);
  • at least 20,000,000 event lines must be read from a cumulative snapshot, and at least 95% of them must parse (measured healthy: 26,889,079 lines, 100.00% parsed);
  • USPTO's shipped code dictionary must be present and must still define EXP. and EXPX, at least 100,000 EXP. events must be present (measured: 3,590,629), and no more than 1% of events may carry a code absent from that dictionary (measured: 0);
  • each patent's events must still be listed contiguously, because the revival check depends on it (measured: 8,497,655 patents, 0 violations);
  • a 0-row result is only returned when the snapshot genuinely reaches into the requested window.

Use as an MCP tool

This actor is Pay-Per-Event and discoverable via mcp.apify.com — an AI agent (Claude, Cursor, etc.) can call it directly as a tool to answer "which patents just expired for non-payment" style questions, chaining the google_patents_url output into a follow-up full-text fetch. Billing is unchanged when called as a tool, and a run that cannot answer fails without billing.

FAQ

Which patents just expired for non-payment? Run with default mode: "lapsed" — every row is a confirmed EXP. event, and fto_flag: true additionally means no revival was recorded for that patent.

Can a "lapsed" patent come back? Yes, and that is why revived_after_lapse exists. USPTO grants petitions to accept delayed maintenance-fee payments under 37 CFR 1.378 — roughly 1–1.5% of lapses are reversed over the following two years. Rows where that has already happened are returned with fto_flag: false and the revival code and date attached.

I asked for 4 weeks and got 500 rows — is that everything? Check matches_in_window_total and results_truncated. A 4-week window typically holds ~18,000 lapses; raise maxResults (up to 50,000) or narrow with grantYearMin / grantYearMax to get the subset you care about.

Does this include design or plant patents? Design and plant patents do not pay maintenance fees, so they have no lapse events — but their other maintenance-fee-file events are parsed, and reissue patents (RE…) do pay maintenance fees and are included (3,478 reissue lapse events in the 2026-05-26 snapshot).

Is there a patent maintenance fee lapse list I can search? Yes — this actor turns USPTO's raw bulk file into exactly that: a queryable, date-ranged, entity-size-tagged lapse list with direct Google Patents links.

How do I find public domain patents from 2026? Set mode: "lapsed" and narrow with grantYearMin / grantYearMax to focus on recently-granted patents that have already lapsed — the most actionable FTO subset.

Notes on the source format

USPTO's weekly PTMNFEE2 zip contains two text files: the event file (MaintFeeEvents_YYYYMMDD.txt, ~26.9 million fixed-width 57-character rows) and MaintFeeEventsDesc_YYYYMMDD.txt, USPTO's own dictionary of every event code. This actor reads both — the layout is parsed by byte offset and the vocabulary is closed against USPTO's dictionary rather than a hard-coded list, so a renamed or new code is detected on the run it appears rather than silently becoming "other".

This is a screening tool built on USPTO's published maintenance-fee record, not a legal determination. Confirm any freedom-to-operate conclusion against Patent Center / PAIR before acting on it.

Pricing

Pay-Per-Event: $8 per 1,000 result rows (Result dataset-item event only — no double-charging). Runs that cannot answer fail loudly and bill nothing.