USPTO Patent Maintenance-Fee Lapse Monitor — FTO Tracker
Pricing
from $4.40 / 1,000 results
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
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
- Resolves the newest weekly USPTO
PTMNFEE2snapshot 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. - 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.
- Classifies each event against USPTO's own code dictionary, which ships inside
the same zip (163 documented codes), so
event_code_descriptionis USPTO's wording, not ours, and an unknown code fails the run instead of being quietly bucketed as "other". - Groups every event by patent (USPTO lists a patent's events contiguously) and, for
each lapse, looks for a post-expiration revival —
EXPX, a granted petition (PMFG/PTGR), a delayed-payment petition (M1558/M2560/…) or an accepted maintenance-fee payment. - Returns a normalized, filterable feed with a direct Google Patents link, plus the
honest denominator:
matches_in_window_totalis how many rows matched in the whole snapshot, andresults_truncatedsays whethermaxResultscut 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 inmatches_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
| Field | Description |
|---|---|
patent_number | US patent number, zero padding stripped (11324169, RE45927, D1000000) |
patent_kind | utility, reissue, design, plant, sir or defensive_publication |
application_number | Associated USPTO application number |
event_code | Raw USPTO event code (EXP., EXPX, M1551, PMFG, …); null on the rare row USPTO ships with a blank code |
event_code_description | USPTO's own description of that code, read from the dictionary shipped inside the same zip |
event_type | Normalized: lapsed, reinstated, fee_paid, or other |
event_date | Date of the maintenance-fee event (YYYY-MM-DD) |
grant_date | Patent grant date (YYYY-MM-DD) |
filing_date | Original application filing date (YYYY-MM-DD) |
patent_age_years_at_event | Years between grant and event (1 decimal place) |
entity_size | large / small / micro — from the fee code, else the entity-indicator column |
entity_indicator_raw | Raw USPTO entity column: N (undiscounted), Y (small), M (micro) |
revived_after_lapse | Lapse 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_code | Code of the earliest revival event (e.g. PMFG, M1558, EXPX), else null |
revival_event_date | Date of that revival event, else null |
post_lapse_event_codes | Every event recorded after the lapse, as CODE@YYYY-MM-DD, comma separated — including non-revival signals such as a petition merely filed (PMFP) |
fto_flag | true 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_count | How many maintenance-fee events the snapshot holds for this patent |
latest_event_code / latest_event_date | The most recent event on this patent in the snapshot |
google_patents_url | Direct link to the patent on Google Patents |
source_file | The USPTO snapshot zip this event was parsed from |
snapshot_date | Date of the weekly USPTO cumulative snapshot this row was read from |
snapshot_max_event_date | Newest event date found anywhere in that snapshot — its true data end |
window_start / window_end | The event-date window this run covered |
snapshot_is_newest_available | true if answered from USPTO's newest weekly file, false if an older one had to be used, null if not checked |
newest_available_snapshot | Newest weekly snapshot USPTO offered at run time |
snapshot_lag_days | Days between the snapshot that answered and the newest one (0 = fully current) |
matches_in_window_total | Total rows matching your query in the whole snapshot, before maxResults |
results_truncated | true when matches_in_window_total exceeded maxResults |
scan_complete | true when the entire snapshot was streamed and counted |
source_lines_scanned / source_lines_unparsed | Lines read, and lines that did not parse as an event |
served_from_cache | true 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_at | UTC 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_run | Requests this run made against USPTO's per-file download allowance (0 on a cache hit) |
download_budget_remaining | Downloads 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-Lengthof 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.andEXPX, at least 100,000EXP.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.