Download 8-K Exhibit 99 press releases with Python
Find earnings 8-Ks (Item 2.02), list their Exhibit 99 documents and download the press releases, using the 8-K events feed and the download API.
When a company announces earnings, the 8-K itself is a one page cover. The actual press release, with the headline numbers and the financial tables, is attached as Exhibit 99.1. Investor presentations, CFO commentary and supplemental tables follow as 99.2, 99.3 and so on. The same pattern applies to Item 7.01 (Regulation FD) 8-Ks, which carry investor day slides and other announcements as Exhibit 99.
This tutorial finds today's earnings 8-Ks, lists their Exhibit 99 documents and downloads the press releases.
Steps
/v1/form-8k?item=2.02returns 8-Ks classified by item, newest first, each with its index URL.- The filing index page lists every document with its exhibit type (
EX-99.1,EX-10.1,GRAPHIC...)./v1/downloadfetches it, and a regex reads the table. /v1/downloadfetches each exhibit as filed.
The script
import html
import os
import re
import requests
BASE = "https://secfeedapi.com"
HEADERS = {"Authorization": f"Bearer {os.environ['SECFEED_KEY']}"}
def get(path, **params):
r = requests.get(f"{BASE}{path}", params=params, headers=HEADERS, timeout=120)
r.raise_for_status()
return r
def exhibits(index_url):
"""[(type, description, url)] from the filing index page's document table."""
page = get("/v1/download", url=index_url).text
rows = re.findall(r'<td scope="row">([^<]*)</td>\s*<td scope="row"><a href="([^"]+)">[^<]*</a>.*?</td>\s*<td scope="row">([^<]*)</td>',
page, flags=re.S)
return [(typ.strip(), desc.strip(), "https://www.sec.gov" + href.replace("/ix?doc=", "")) for desc, href, typ in rows]
def to_text(doc):
doc = re.sub(r"(?is)<(head|script|style).*?</\1>", " ", doc)
doc = re.sub(r"(?i)<br\s*/?>|</(p|div|tr|h\d)>", "\n", doc)
return html.unescape(re.sub(r"<[^>]+>", " ", doc)).replace("\xa0", " ")
# 1. earnings releases filed today: 8-Ks with Item 2.02
events = get("/v1/form-8k", item="2.02", startDate="2026-10-13", size=4).json()["filings"]
os.makedirs("ex99", exist_ok=True)
for e in events:
# 2. the Exhibit 99 documents attached to each 8-K
ex99 = [x for x in exhibits(e["url"]) if x[0].startswith("EX-99")]
print(f"{e['company']} ({e['filed']}): {len(ex99)} exhibit 99 document(s)")
for typ, desc, url in ex99:
print(f" {typ:<8} {desc[:40]:<40} {url.rsplit('/', 1)[1]}")
# 3. download EX-99.1, the press release, and show its first lines
typ, desc, url = ex99[0]
doc = get("/v1/download", url=url).text
open(os.path.join("ex99", url.rsplit("/", 1)[1]), "w").write(doc)
text = to_text(doc)
lines = [" ".join(l.split()) for l in text.splitlines() if len(l.split()) >= 5]
headline = next((l for l in lines if re.search(r"quarter|results", l, re.I)), lines[0])
print(f" {len(text.split()):,} words. First line about results: {headline[:120]}")
print()
Output
EMERSON ELECTRIC CO (2026-10-13): 1 exhibit 99 document(s)
EX-99.1 EX-99.1 apensionrestatementxex991.htm
1,561 words. First line about results: Quarterly amounts may not sum to the annual amounts due to rounding. Earnings per share are computed independently each
WELLS FARGO & COMPANY/MN (2026-10-13): 3 exhibit 99 document(s)
EX-99.1 EXHIBIT 99.1 wfc3qer10-13x26ex991xrelea.htm
EX-99.2 EXHIBIT 99.2 wfc3qer10-13x26ex992xsuppl.htm
EX-99.3 EXHIBIT 99.3 ex993-wellsfargo3q26pres.htm
4,529 words. First line about results: Wells Fargo Reports Third Quarter 2026 Net Income of $6.0 billion, or $1.87 per Diluted Share
JOHNSON & JOHNSON (2026-10-13): 2 exhibit 99 document(s)
EX-99.1 EX-99.1 a2026q3exhibit991.htm
EX-99.2 EX-99.2 a2026q3exhibit992.htm
2,364 words. First line about results: Johnson & Johnson reports Q3 2026 results, raises 2026 guidance
UNITEDHEALTH GROUP INC (2026-10-13): 2 exhibit 99 document(s)
EX-99.1 EX-99.1 earningsrelease3q26unh.htm
EX-99.2 EX-99.2 uhgearnings_q32026vfinal.htm
5,250 words. First line about results: 1 UnitedHealth Group Reports Third Quarter 2026 Results • Third Quarter 2026 Revenues of $112.7 Billion; Earnings from O
Three of the four Exhibit 99.1 documents are classic quarterly earnings releases. The fourth shows why it pays to read the exhibit and not just the item code: Emerson's Item 2.02 8-K carries recast historical results after a pension accounting change, not a quarterly release.
Variations
- Regulation FD announcements. Use
item="7.01"for investor presentations and other voluntary disclosures. Many earnings 8-Ks have both 2.02 and 7.01. - One company over time. Search with
formType:"8-K" AND items:"2.02" AND ticker:NVDAon/v1/filingsto get every earnings 8-K for a ticker. - Text for NLP. The
to_texthelper is enough for headlines. For full documents, the extractor can also return 8-K item text, see Extract 8-K item text. - PDF copies. Pass the exhibit URL to
/v1/pdfto archive a rendered copy.
Notes
- Exhibit numbering follows Item 601 of Regulation S-K: 99 is "additional exhibits", used for press releases and presentations. Material contracts are Exhibit 10, see Download material contracts.
- Results furnished under Item 2.02 are "furnished", not "filed", which matters for liability but not for the data.