USPTO Patent Center vs EPO Register Status Codes

USPTO and EPO encode the same prosecution milestones in incompatible vocabularies: the USPTO exposes free-form transaction codes and numeric application-status codes through Patent Center and the Patent Examination Data System, while the EPO Register and INPADOC deliver WIPO ST.27 legal-status event categories. A docketing engine that reasons over both portfolios must collapse these two dialects into one canonical status enum, deterministically, before any deadline logic runs.

This page contrasts the two encodings field by field, gives a representative mapping table from office codes to a shared internal status, and provides a focused Python normalizer that fails closed on any unmapped code. It sits directly beneath USPTO Data Schema Mapping, reuses the canonical-event discipline established there, and complements the field-level serialization differences documented in USPTO PAIR vs Patent Center Data Structures.

Why the two encodings do not line up

The mismatch is structural, not cosmetic. The USPTO models prosecution as a stream of transactions — every mailing, response, and internal action appends a short document code to the file wrapper, and a separate coarse application status summarizes where the case sits. The EPO, by contrast, publishes a procedural status in the European Patent Register and, for downstream consumers, a normalized legal-status event stream through INPADOC that follows the WIPO ST.27 categorization. One system is transaction-granular and US-specific; the other is event-categorical and designed for cross-office exchange.

Three consequences matter for docketing. First, cardinality differs: a single canonical status such as “under examination” corresponds to many USPTO transaction codes but to one ST.27 examination category. Second, the trigger semantics differ: a USPTO MN/=. transaction (mailing of a Notice of Allowance) opens a non-extendable issue-fee window under 35 U.S.C. § 151, whereas the EPO’s equivalent — a communication under Rule 71(3) EPC that grant is intended — opens a four-month response window with entirely different consequences. Third, terminal states are asymmetric: a US case is “abandoned”; a European application is “deemed to be withdrawn.” Treating these as the same string is safe only after both are mapped to one canonical ABANDONED.

Operational Action: Never let raw office status strings reach your deadline engine. Normalize at the ingestion boundary so downstream rule code sees only the canonical enum, and pin the mapping tables to a version so a code you have never seen becomes a reviewable alert rather than a silent default.

USPTO: transaction codes, PEDS status, and Patent Center

Patent Center is the USPTO’s current filing and file-wrapper interface, and the Patent Examination Data System (PEDS) is the bulk, machine-readable channel that exposes the same records as structured JSON and XML. Two fields carry status. The transaction history is a list of dated document codes — CTNF (non-final rejection mailed), CTFR (final rejection mailed), MN/=. (Notice of Allowance mailed), N271 (issue notification), and ABN (abandonment) are representative examples drawn from the file-wrapper vocabulary. Alongside the transactions, PEDS carries a coarse appStatus string and a numeric appStatusCode; for example code 30 is “Docketed New Case — Ready for Examination”, 150 is “Patented Case”, and 161 is “Abandoned — Failure to Respond to an Office Action”.

The transaction stream is authoritative for when a deadline-bearing event occurred, because it carries the mailing date; the numeric status is a convenient summary but lags the transaction and should never be the sole trigger. A docketing feed therefore reads both, prefers the transaction date as the anchor, and uses the numeric code as a corroborating cross-check. Retrieve these through the sanctioned USPTO Open Data Portal rather than scraping the Patent Center UI while the API is healthy.

EPO Register, INPADOC, and WIPO ST.27 categories

The European Patent Register publishes a human-readable procedural status — phrases such as “Examination is in progress”, “Communication under Rule 71(3) EPC” (intention to grant), “The patent has been granted”, and “The application is deemed to be withdrawn”. For automation, the durable representation is the legal-status event stream delivered through INPADOC and the EPO’s Open Patent Services, which follows WIPO Standard ST.27, the recommendation for the exchange of patent legal-status data.

ST.27 assigns every legal-status event to a standardized category — filing, examination, grant, lapse, reinstatement, discontinuation, and so on — plus a more granular event code. The category is the level a cross-office docketing system should key on, because event codes vary by office while the categories are stable and internationally agreed. INPADOC then supplies the effective date and the affected contracting states. Critically, a lapse in one designated state does not lapse the whole grant, so the ST.27 lapse category must be resolved per state before it collapses to a canonical status — a nuance the EPO Register Sync Architecture feed has to preserve.

Operational Action: Load the full ST.27 category table from the WIPO standard, not from a hand-typed subset, and record which INPADOC event code produced each canonical status so a restoration under Rule 135 EPC or re-establishment under Article 122 EPC can be reconstructed downstream.

A canonical status mapping table

The table maps representative office signals to a shared internal status and states the docketing consequence each carries. It is deliberately many-to-one on the USPTO side and category-keyed on the EPO side.

Canonical status USPTO Patent Center / PEDS signal EPO Register / INPADOC (ST.27) Docketing implication
FILED appStatusCode 19/20, pre-exam processing ST.27 filing category Start priority and PCT clocks; no response window yet
UNDER_EXAMINATION CTNF / CTFR; appStatusCode 41 ST.27 examination; Register “Art. 94(3) communication” Opens a response window (37 CFR § 1.136 / Rule 132 or Art. 94(3))
ALLOWED MN/=. Notice of Allowance mailed Register “Rule 71(3) intention to grant” US: non-extendable issue-fee window; EPO: 4-month Rule 71(3) window
GRANTED N271; appStatusCode 150 “Patented Case” ST.27 grant; Register “the patent has been granted” Switch case to the maintenance-fee / annuity track
ABANDONED ABN; appStatusCode 161 Register “deemed to be withdrawn” (Art. 94(4)) Open the revival / further-processing window
LAPSED Maintenance fee unpaid (37 CFR § 1.362) ST.27 lapse; INPADOC lapse in a contracting state Start the grace-period / restoration clock, per state
RESTORED Petition to revive granted (37 CFR § 1.137) ST.27 reinstatement; Rule 135 / Art. 122 relief Reopen the previously closed deadlines

The ALLOWED row is the sharpest divergence: the same canonical state carries a non-extendable US issue-fee period but an extendable European response period, so the canonical status is only a routing key — the actual arithmetic still branches on office. Reconcile the cross-office national-phase timing separately in USPTO vs EPO National Phase Entry Differences.

Mapping office codes to a canonical enum

The normalizer keeps two lookup tables — one per office — and a single entry point that fails closed. An unmapped code raises rather than defaulting to a benign status, because a silently swallowed grant or lapse is a missed-deadline vector. Validation at the boundary uses Pydantic so a malformed record never reaches the deadline engine.

from datetime import date
from enum import Enum
from typing import Literal
from pydantic import BaseModel, Field

class CanonicalStatus(str, Enum):
    FILED = "FILED"
    UNDER_EXAMINATION = "UNDER_EXAMINATION"
    ALLOWED = "ALLOWED"
    GRANTED = "GRANTED"
    ABANDONED = "ABANDONED"
    LAPSED = "LAPSED"
    RESTORED = "RESTORED"

# USPTO: file-wrapper transaction codes AND numeric PEDS app-status codes
# both collapse to the same canonical status. Source: USPTO Open Data Portal
# (https://developer.uspto.gov/) and PEDS (https://ped.uspto.gov/).
USPTO_MAP: dict[str, CanonicalStatus] = {
    "CTNF": CanonicalStatus.UNDER_EXAMINATION,  # non-final rejection mailed
    "CTFR": CanonicalStatus.UNDER_EXAMINATION,  # final rejection mailed
    "MN/=.": CanonicalStatus.ALLOWED,           # Notice of Allowance mailed
    "N271": CanonicalStatus.GRANTED,            # issue notification
    "ABN": CanonicalStatus.ABANDONED,           # abandonment
    "30": CanonicalStatus.FILED,                # docketed, ready for exam
    "41": CanonicalStatus.UNDER_EXAMINATION,    # non-final action mailed
    "150": CanonicalStatus.GRANTED,             # patented case
    "161": CanonicalStatus.ABANDONED,           # failure to respond
}

# EPO: keyed on the WIPO ST.27 event category as delivered via INPADOC / OPS.
# Load the authoritative category set from WIPO ST.27, Annex I
# (https://www.wipo.int/standards/en/pdf/03-27-01.pdf); this is a subset.
EPO_ST27_MAP: dict[str, CanonicalStatus] = {
    "FILING": CanonicalStatus.FILED,
    "EXAMINATION": CanonicalStatus.UNDER_EXAMINATION,
    "INTENTION_TO_GRANT": CanonicalStatus.ALLOWED,   # Rule 71(3) EPC
    "GRANT": CanonicalStatus.GRANTED,
    "DISCONTINUATION": CanonicalStatus.ABANDONED,    # deemed withdrawn / refused
    "LAPSE": CanonicalStatus.LAPSED,
    "REINSTATEMENT": CanonicalStatus.RESTORED,       # Rule 135 / Art. 122
}

_TABLES: dict[str, dict[str, CanonicalStatus]] = {
    "USPTO": USPTO_MAP,
    "EPO": EPO_ST27_MAP,
}

def to_canonical(office: Literal["USPTO", "EPO"], raw_code: str) -> CanonicalStatus:
    """Map an office status/event code to the canonical enum, failing closed.

    A code the pinned table does not recognize raises — an unmapped grant or
    lapse must surface for human confirmation, never default silently.
    """
    table = _TABLES.get(office)
    if table is None:
        raise ValueError(f"Unknown office: {office!r}")
    canonical = table.get(raw_code.strip())
    if canonical is None:
        raise ValueError(
            f"Unmapped {office} status code {raw_code!r} — verify against source taxonomy"
        )
    return canonical

class NormalizedStatusEvent(BaseModel):
    """The single shape both offices are reduced to before docketing."""
    office: Literal["USPTO", "EPO"]
    raw_code: str = Field(min_length=1, max_length=16)
    canonical: CanonicalStatus
    effective_date: date
    jurisdiction: str  # ISO office code; ST.27 lapses resolve per contracting state

    @classmethod
    def from_raw(cls, office: Literal["USPTO", "EPO"], raw_code: str,
                 effective_date: date, jurisdiction: str) -> "NormalizedStatusEvent":
        return cls(
            office=office,
            raw_code=raw_code,
            canonical=to_canonical(office, raw_code),
            effective_date=effective_date,
            jurisdiction=jurisdiction,
        )

# Verify: both dialects reach one status.
# to_canonical("USPTO", "MN/=.") is CanonicalStatus.ALLOWED
# to_canonical("EPO", "INTENTION_TO_GRANT") is CanonicalStatus.ALLOWED
Two-column mapping from USPTO and EPO status codes to one canonical status enum A three-column diagram. The left column lists representative USPTO Patent Center and PEDS signals; the right column lists the matching EPO Register and INPADOC ST.27 event categories; the centre column holds the canonical status enum. Each left-hand USPTO signal and its right-hand EPO counterpart both point inward with arrows that terminate on the same central canonical box, showing that two incompatible office vocabularies collapse to one shared status. Rows, top to bottom, pair: appStatusCode 19/20 pre-exam and the ST.27 filing category to FILED; CTNF/CTFR and the ST.27 examination category to UNDER_EXAMINATION; MN/=. Notice of Allowance and the Rule 71(3) intention-to-grant status to ALLOWED; N271 with appStatusCode 150 and the ST.27 grant category to GRANTED; ABN with appStatusCode 161 and the deemed-withdrawn status to ABANDONED; and an unpaid maintenance fee with the ST.27 lapse category to LAPSED. USPTO PATENT CENTER / PEDS CANONICAL STATUS ENUM EPO REGISTER / INPADOC (ST.27) appStatusCode 19/20 pre-exam processing FILED ST.27 filing category application filed CTNF / CTFR · appStatus 41 Office action mailed UNDER_ EXAMINATION ST.27 examination Art. 94(3) communication MN/=. Notice of Allowance mailed ALLOWED Rule 71(3) EPC intention to grant N271 · appStatus 150 patented case GRANTED ST.27 grant category the patent has been granted ABN · appStatus 161 failure to respond ABANDONED deemed to be withdrawn Art. 94(4) EPC maintenance fee unpaid 37 CFR 1.362 LAPSED ST.27 lapse category lapse in a contracting state Two office vocabularies converge on one canonical status — office still branches the arithmetic (e.g. ALLOWED).

Deadline implications once the status is canonical

Canonicalization routes a case to the right rule set, but the arithmetic still depends on the originating office. An ALLOWED US case starts a non-extendable three-month issue-fee window; an ALLOWED European case starts the four-month period to reply to the Rule 71(3) communication, which is extendable by further processing. An ABANDONED US case can be revived on a petition showing the delay was unintentional under 37 CFR § 1.137; a DISCONTINUATION-derived European case reopens through further processing under Rule 135 EPC or re-establishment under Article 122 EPC, and the contrast between those two European remedies is worked through in EPO Further Processing vs Re-establishment of Rights. Feeding these normalized events into the shared Automated Deadline Calculation & Rule Engines keeps the office-specific branch in one place.

Operational Action: Keep the canonical enum small and status-oriented, and push office-specific arithmetic into the rule engine keyed on (canonical, office). Expanding the enum to encode office nuances re-couples the two dialects you just separated.

Known pitfalls

  • Numeric status lag. The PEDS appStatusCode can trail the transaction that actually opened the deadline. Anchor on the dated transaction and treat the numeric status as corroboration, not the trigger.
  • Per-state EPO lapse. An INPADOC lapse event names specific contracting states; collapsing it to a single LAPSED for the whole family drops still-live national rights. Resolve the affected states before you set status.
  • Unmapped codes. Both offices add and rename codes. A default-to-benign branch converts a new grant or lapse code into silence — the exact failure the USPTO Data Schema Mapping layer refuses. Raise, alert, and route to review instead.
  • Register text drift. The EPO Register’s human-readable phrases are localized and can be reworded; key on the ST.27 event delivered by INPADOC, never on a scraped Register string.

Frequently Asked Questions

Is a USPTO numeric application-status code enough to drive docketing on its own?
No. The numeric appStatusCode is a coarse summary that can lag the file-wrapper transaction which actually opened a deadline. Anchor the docket on the dated transaction code (for example CTNF or MN/=.) and use the numeric status only as a corroborating cross-check, because the transaction carries the mailing date the statutory window runs from.
What is WIPO ST.27 and why key EPO status on it rather than the Register text?
WIPO ST.27 is the international recommendation for exchanging patent legal-status data. It assigns each event to a stable, agreed category — filing, examination, grant, lapse, reinstatement — that INPADOC and the EPO's Open Patent Services deliver programmatically. The European Patent Register's human-readable phrases are localized and can be reworded, so keying on the ST.27 event category is far more durable than parsing Register text.
Does mapping USPTO and EPO to one canonical status make their deadlines identical?
No. The canonical status is only a routing key. An ALLOWED US case opens a non-extendable issue-fee window, while an ALLOWED European case opens the extendable four-month Rule 71(3) response period. The arithmetic still branches on the originating office; the enum just ensures both portfolios enter the correct rule set.
How should the mapper behave when it meets a status code it has never seen?
Fail closed. An unmapped code usually means the office changed its taxonomy and the pinned table lags it. The normalizer raises rather than defaulting to a benign status, the record is routed to review, and an alert fires — so a new grant or lapse code is never silently dropped and converted into a missed deadline.

↑ Back to USPTO Data Schema Mapping