HEALTHCARE REFERENCE / PYTHON + CSV

Research FDA application history in Python

Add recorded approval dates, submission counts and document counts to an application-number portfolio using the Drugs@FDA reference.

01 / THE EXAMPLE

Research a portfolio of FDA applications

You have FDA application numbers and want to find their recorded submissions, original approval status dates, and available supporting documents. The reference connects those records to application type and sponsor, with a separate table for each relationship.

The optional input.csv contains three fictional research-project labels paired with real FDA application numbers. Those same records appear in the portfolio list in the Python code below. The labels illustrate how to keep your own work attached to the added FDA information.

Samples from the purchased reference

Save these two files together. They contain the three selected application records and all 54 of their submission records, unchanged from the $29 download. Columns and filenames match the purchased files. The full reference has 194,160 submission records, 29,391 application records and separate document, product and action-category tables.

02 / PYTHON

Code example

The code adds the snapshot’s sponsor and application type, selects dated original submissions with FDA status AP, and counts the recorded submissions and linked document records. It works in a notebook, IPython or a script with Python’s standard library.

Paths are relative to your working folder; use from pathlib import Path; print(Path.cwd()) to check it, or supply full paths.

Python 3.10+ · Jupyter, IPython or a script
import csv
from collections import defaultdict
from pathlib import Path

# Optional: replace this list with rows from your own portfolio CSV.
# Project labels are fictional; application numbers are real FDA identifiers.
portfolio = [
    {'project': 'Anticoagulant review', 'application_number': '202155'},
    {'project': 'Diabetes portfolio', 'application_number': '204629'},
    {'project': 'GI portfolio', 'application_number': '205613'},
]
data_folder = Path('.')
with (data_folder / 'applications.csv').open(newline='', encoding='utf-8') as f:
    applications = {r['application_number']: r for r in csv.DictReader(f)}
submissions = defaultdict(list)
with (data_folder / 'submissions.csv').open(newline='', encoding='utf-8') as f:
    for row in csv.DictReader(f):
        submissions[row['application_number']].append(row)

results = []
for project in portfolio:
    number = project['application_number']
    application = applications.get(number)
    records = submissions[number]
    # AP is the source approval status. Retain all other statuses in the data.
    original_dates = sorted({r['status_date'] for r in records
                             if r['submission_type'] == 'ORIG'
                             and r['submission_status'] == 'AP' and r['status_date']})
    result = {**project,
              'application_type': application['application_type'] if application else '',
              'sponsor': application['sponsor_name'] if application else '',
              'original_approval_dates': ' | '.join(original_dates),
              'recorded_submissions': len(records),
              'linked_document_records': sum(int(r['document_count']) for r in records),
              'status': 'matched' if application else 'application_record_missing'}
    results.append(result)
    print(f"{number} | {result['sponsor']} | original approval: "
          f"{result['original_approval_dates'] or 'not supplied'} | "
          f"{result['recorded_submissions']} submissions | "
          f"{result['linked_document_records']} linked documents")

03 / RESULTS

Analysis of the output

202155 | BRISTOL MYERS SQUIBB | original approval: 2012-12-28 | 25 submissions | 43 linked documents
204629 | BOEHRINGER INGELHEIM | original approval: 2014-08-01 | 26 submissions | 55 linked documents
205613 | SALIX | original approval: 2014-10-07 | 3 submissions | 7 linked documents

Application 202155 is associated with BRISTOL MYERS SQUIBB in this snapshot. Its original submission has an approval status date of December 28, 2012; the retained file contains 25 submissions and 43 documents linked to those submission keys. The other two application numbers receive the same summary without mixing their records.

Inspect the history behind the summary

Filter submissions.csv by application_number to examine original and supplemental records, status dates, review priorities and the FDA’s submission-class descriptions. The delivered documents.csv joins on submission_key and provides document types and source URLs for letters, labels, reviews and other materials.

A submission may have several documents and action categories. The supplied counts summarize each relationship separately. Joining both detail tables directly can multiply rows; a count of action-category records is not a count of independently dated events. Some documents are application-level records rather than submission attachments and are labeled accordingly.

Read status dates in context

The date is when the recorded status was applied, not when FDA received the submission. This snapshot does not contain every prior status transition, so it cannot establish review duration. Tentative approvals and other statuses remain in the complete table. An absent original approval date is not proof that an application was never approved.

The sponsor and application type describe the captured application record, not necessarily the sponsor or type at the historical date. FDA has converted some NDAs to BLAs under the same application number. Missing parent records, missing dates and suspicious source dates have explicit flags.

04 / YOUR DATA

Using the full dataset

Extract the ZIP and replace both samples with applications.csv and submissions.csv from that release, or set data_folder to its directory. The code runs unchanged. To use your own CSV with project and application_number columns, replace the inline list with:

with open("my_portfolio.csv", newline="", encoding="utf-8") as f:
    portfolio = list(csv.DictReader(f))

Keep application numbers as six-character text, including leading zeros. Product numbers and NDCs are different identifiers. The package includes field dictionaries, original-row accounting, unresolved relationships, source and processing records, and the checked example.

Connect to the Orange Book

The Orange Book reference adds patent and exclusivity listings. Compare its application number and type (N for NDA; A for ANDA) with this snapshot. Product-specific joins also require the three-digit product number. Check unmatched and type-disagreement cases, including applications converted to BLAs. A shared application does not assign every submission to every product. An audited full crosswalk between the products is not included.

05 / PROVENANCE

Sources and versions

FDA downloadable tables were captured October 16, 2026. The source page reported October 16 as its last-updated date; the ZIP members are timestamped October 15. These are distinct from an exhaustive coverage cutoff, which the files do not state. ACD packaged this release on 2026-10-16.

FDA describes broad approved-human-drug coverage, with most associated documents available since 1998. Older history can be incomplete, and some product categories are outside the database. The original source remains free. This is an analytical reference, not a clinical recommendation or a live regulatory monitoring service.

Sources: FDA bulk tables and field definitions, coverage and comparison with the Orange Book, and submission field semantics. Initial ACD release and preparation details.

Example checked October 16, 2026 against both these samples and the complete purchased files. Source and processing records, sample checksums · Expected result CSV. Independent preparation; no agency endorsement.