openFDA serves device recalls through two endpoints, and they start a decade apart. The RES endpoint reaches back to late 2002. The enforcement endpoint, the one that carries a recall's Class I, II or III classification, holds 0 records with a report date earlier than 2012-06-20. Severity lives only in the enforcement file, so 7,527 of the 22,500 recall events in the RES endpoint, 33.45%, have no class anywhere in the API.
The reader who has to do something about that is anyone building or buying a device recall trend line or a recall-severity feature from openFDA. FDA's own Device Enforcement overview page states coverage from 2004 to the present. A developer who trusts that page and charts Class I device recalls by initiation year gets a curve that climbs into 2013 with nothing in the endpoint to say that the early years of the chart are mostly empty.
Three things change once the two files are joined. Fence any Class I series at initiation year 2013, or at report date 2012-06-20 where the series runs on report dates. Read openfda.device_class in the RES payload as what it is, the regulatory class of the device's product code. Treat the 7,527 RES events with no enforcement record as carrying no class in the API, and keep that qualifier: 7,504 of them, all initiated before 2013-01-01, carry the RES status Terminated on every row, which is what FDA records when it has classified a recall and closed it out.
Where each file starts
The recall file, fda.recall, is the RES endpoint, and in the export of 2026-09-10 it holds 59,123 records, one row per cfres_id, which is one recalled product inside a recall event. The enforcement file, fda.enforcement, in the export of 2026-09-02, holds 39,884 records, one row per recall_number.
Collapsed to events, the two sit further apart. The recall file has 22,500 events, counted as distinct res_event_number. The enforcement file has 14,974 events, counted as distinct event_id. 14,973 events appear in both.
Almost nothing goes missing in the enforcement direction. 1 enforcement event has no RES record sharing its event id: event 98346, Beckman Coulter Mishima, reported 2026-03-18. In the other direction the shortfall is the finding. 7,527 RES events, 33.45% of the 22,500, have no enforcement row at all, and therefore no Class I, II or III value to read. Run the same anti-join at row level, on recall_number against product_res_number, and 19,241 RES records are unjoined, 32.5% of all RES records.
The gap has a date on it
Group RES events by the earliest initiation date on their rows and the missing severity is not spread across the file. It sits in one block of years, and the share of RES events with no enforcement record runs like this:
- 100% for 2003 and 100% for 2004
- between 97.1% and 99.6% across 2005 to 2009, with 2009 the lowest at 97.1%
- 96.4% in 2010
- 90.2% in 2011
- 23.2% in 2012
- 0 events across initiation years 2013 to 2025 together
The 7,527 unjoined events break into three groups, and all three point at the same boundary. 7,455 events were posted in RES before 2012-06-20, the enforcement file's earliest report date. 53 events were posted after that date and before 2026: recalls initiated between 2002 and 2011 that RES re-posted in a two-day batch on 2015-06-25 and 2015-06-26. The remaining 19 events were initiated in 2026 and carry the RES status Open, Classified, their enforcement reports not yet exported when these files were pulled.
The boundary holds from the other side too. Among events initiated before June 2012 that do have an enforcement record, 0 events were reported before 2012-06-20. Every pre-opening recall that carries a class in the API received its first enforcement report on or after the day the enforcement file begins.
The Class I ramp is the file opening
Chart Class I device recall events from the enforcement file by initiation date and the early years climb: 5 events initiated in 2011, 45 in 2012, 71 in 2013, which is the first initiation year the file covers in full.
One of the five 2011 events needs a caveat. Event 98868 carries an initiation date of 2011-01-17 in both files against a report in June 2026, and whether the year is mis-keyed could not be determined here, so the count is printed as the data returns it. Restrict the same query to events reported before 2014-01-01 and 2011 has 4 Class I events, all of them reported between 2012-06-20 and 2013-04-17.
The severity mix stays level across the same boundary. Counted as enforcement events with any Class I row over all enforcement events initiated that year, the Class I share is 4.4% for 2011, 5.5% for 2012 and 5.7% for 2013. Total recall activity is level too: RES, which covers all three years without a gap, shows 1,163 recall events initiated in 2011, 1,072 in 2012 and 1,227 in 2013.
So the Class I count climbs while the total and the share hold steady. What the climb records is how much of each year the enforcement file holds.
The device_class field carries the product code's class
The recall endpoint offers nothing to fill the gap. Of the 59,123 RES records in the 2026-09-10 export, the number whose stored payload has a top-level key named classification is 0 records.
There is a field that looks like a substitute and is not one. 57,841 RES records carry openfda.device_class, which reports the regulatory class of the device's product code, assigned when the device type was classified. Join the enforcement rows classified Class I back to their RES rows and 2,754 of them sit on records whose payload gives openfda.device_class 2, with 463 on device_class 3. A Class I recall of a class 2 device is unremarkable: the recall class describes the hazard of the defect, the device class describes the controls on the device type. Anyone who has used device_class as a severity proxy has built a feature on the wrong variable.
What is already on the record
The mechanism is documented in a developer write-up. FDA Recall API: A Working Guide to openFDA Enforcement sets out that openFDA's enforcement endpoints bottom out at report_date 2012-06-20 despite documentation claiming 2004 onwards, and that the recall endpoint carries no classification field. That guide is where the claim about the live API rests; the floor counted here is the floor of the bulk file this publication ingests. FDA's own Device Enforcement overview still states 2004 to present.
The hazard is current. A 2026 preprint, RecallRisk-BERT: A Multi-Task Framework for Post-Report Medical Device Recall Triage, builds a recall triage model on openFDA device recall records reaching back to November 2002, a span only the RES endpoint covers, without noting that 7,527 of the 22,500 RES events carry no severity in the API.
This is a different caveat from the one the trade already has. GAO's 2011 report on FDA's oversight of device recalls and the MD+DI interview with its author concern firm self-reporting and FDA's management of the recall process, and GAO's 2026 report on limitations in recall oversight analyses RES and the recall process itself. Neither addresses which openFDA endpoint carries what. A reader who has already filed "recall data is messy" under self-reporting should file this separately.
Set against that, the honest limits of the story: the two mechanical facts are published, experienced openFDA users already know the enforcement endpoint is the weekly Enforcement Report while RES is the older CDRH database, and what follows from the quantified gap is a data-hygiene rule rather than a statement about any firm's recalls.
The rule has a worked example on this site. Medical Device Manufacturing builds its recall pages from the join described here, and 19,303 recall pages are withheld from publication under a single gate reason, no classification: recall not joined to an enforcement record. The rows exist; the pages do not publish, because there is no class to print on them.
How the numbers were counted
Two openFDA datasets and one internal table stand behind these counts, and each was pulled on its own date.
fda.recall, the RES endpoint, export 2026-09-10. One row is one recalled product, keyed by cfres_id, and the file holds 59,123 records. One event is a distinct res_event_number, and an event's initiation year is the earliest event_date_initiated across its rows. The year shares and the yearly event totals apply no filter beyond the year named. The posting-date split uses event_date_posted, or event_date_created where posted is null.
fda.enforcement, the enforcement endpoint, export 2026-09-02. One row is one enforcement report, keyed by recall_number, and the file holds 39,884 records. One event is a distinct event_id. The Class I counts filter on classification = 'Class I' and group by the year of recall_initiation_date. The 0 records figure counts rows with report_date earlier than 2012-06-20.
The join runs on recall_number = product_res_number at row level and on event_id = res_event_number at event level. The gap counts are anti-joins in both directions, and the 19,241 unjoined records returns the same number on either key.
mdm.data_page, this publication's own page table, in the state its pages were built. One row is one built page. The count filters on template = 'recall', gate_passed false, and the gate reason that names the missing classification. It sits below the 19,241 unjoined RES records because the pages were built against an earlier state of the join than the recall export used here.
What these files cannot say
The 2012-06-20 floor counted above is the floor of the bulk file. That the live device/enforcement endpoint bottoms out at the same report date is documented in the developer guide cited above, and that document, not this corpus, is the basis for any statement about the live API.
Neither file explains itself. Nothing in the recall or enforcement data says why the enforcement file begins on 2012-06-20, and no cause for the boundary is asserted here.
The missing class is missing in the API. 7,504 RES-only events initiated before 2013-01-01 carry recall_status Terminated on every row, so FDA classified those recalls before closing them. Whether FDA's public web RES database displays that class for a pre-June-2012 record was not checked for this piece, and the claim stays bounded to what the API returns.
The classification-key count was run against the stored payload of each RES record in the ingested corpus. Stated against the documented columns, the position is the same: fda.recall has no classification column.
Event 98868's initiation date of 2011-01-17 is printed as both files return it, alongside a report date in June 2026. No correction to that year is made here, and the 2011 Class I count includes it.
The current year is partial in both exports, and the two files were pulled on different days. The 19 events initiated in 2026 with no enforcement record are a timing effect of that gap and can be expected to join once their enforcement reports are exported.
None of this counts recalls that firms never reported to FDA. That undercount is GAO's subject, and it is measured nowhere in these two files.