Home / Guides / Capital raising
Capital raising

Most active underwriters in 424B4 prospectuses

Count which banks appear on the cover of 2026 final prospectuses, which are listed first, and which banks work together most often.

Every 424B4 final prospectus names its underwriters on the cover page. /v1/ipo returns them in terms.underwriters, in the order they appear. This tutorial counts the banks across all 2026 deals, notes which bank is listed first, and finds the pairs that share covers most often.

Cleaning the names

The underwriter list is read from cover page text, so it carries some layout words along with the bank names: headings like "Global Coordinators" or "Joint Book-Runners", notes like "(in alphabetical order)", and footnote asterisks. The same bank also appears under several legal names ("Goldman Sachs & Co. LLC", "Goldman Sachs International"). The script drops the layout words and maps common names to one label.

The code

import os
import re
from collections import Counter

import requests

BASE = "https://secfeedapi.com"
HEADERS = {"Authorization": f"Bearer {os.environ['SECFEED_KEY']}"}

filings, start = [], 0
while True:
    r = requests.get(f"{BASE}/v1/ipo", headers=HEADERS, timeout=300, params={
        "formType": "424B4", "startDate": "2026-01-01", "endDate": "2026-10-12", "size": 25, "from": start})
    r.raise_for_status()
    page = r.json()["filings"]
    if not page:
        break
    filings += page
    start += 25

NOISE = re.compile(r"order|coordinator|book.?runner|joint|manager|co-|underwriter|^\(|^and$", re.I)
ALIASES = {"goldman sachs": "Goldman Sachs", "j.p. morgan": "J.P. Morgan", "morgan stanley": "Morgan Stanley", "bofa": "BofA Securities",
           "citigroup": "Citigroup", "jefferies": "Jefferies", "barclays": "Barclays", "evercore": "Evercore ISI", "ubs": "UBS",
           "rbc": "RBC Capital Markets", "wells fargo": "Wells Fargo Securities", "leerink": "Leerink Partners", "td cowen": "TD Cowen"}


def clean(name):
    name = name.strip().rstrip("*").strip()
    if not name or NOISE.search(name):
        return None
    low = name.lower()
    return next((v for k, v in ALIASES.items() if k in low), re.sub(r",?\s+(LLC|Inc\.?|L\.P\.|Ltd\.?)$", "", name))


deals, seen = [], set()
for f in filings:
    t = f.get("terms") or {}
    key = (f["cik"], t.get("sharesOffered"), t.get("pricePerShare"))
    if key in seen:
        continue
    seen.add(key)
    banks = []
    for u in t.get("underwriters") or []:
        c = clean(u)
        if c and c not in banks:
            banks.append(c)
    if banks:
        deals.append({**f, "banks": banks})
print(f"{len(seen)} distinct 424B4 deals in 2026, {len(deals)} with underwriters on the cover page")

lead = Counter(d["banks"][0] for d in deals)
anyrole = Counter(b for d in deals for b in d["banks"])
print(f"\n{'Underwriter':28}{'Deals':>7}{'Listed first':>14}")
for bank, n in anyrole.most_common(15):
    print(f"{bank:28}{n:>7}{lead.get(bank, 0):>14}")

print("\nMost common pairs on the same cover:")
pairs = Counter(tuple(sorted(p)) for d in deals for i, a in enumerate(d["banks"]) for p in [(a, b) for b in d["banks"][i + 1:]])
for (a, b), n in pairs.most_common(5):
    print(f"  {n:3}  {a} + {b}")

Output

Run on 2026-10-13 (about two minutes, since every cover page is read).

431 distinct 424B4 deals in 2026, 139 with underwriters on the cover page

Underwriter                   Deals  Listed first
J.P. Morgan                      44            15
Goldman Sachs                    43            32
BofA Securities                  39             7
Jefferies                        36             8
Morgan Stanley                   35            10
Barclays                         27             1
Citigroup                        25             2
RBC Capital Markets              25             0
Stifel                           21             1
Evercore ISI                     19             0
Wolfe | Nomura Alliance          18             0
Baird                            17             0
William Blair                    17             0
Wells Fargo Securities           17             1
UBS                              17             1

Most common pairs on the same cover:
   29  BofA Securities + Goldman Sachs
   28  Goldman Sachs + J.P. Morgan
   27  BofA Securities + J.P. Morgan
   24  Barclays + Goldman Sachs
   21  J.P. Morgan + Morgan Stanley

Reading the result

  • Only 139 of 431 deals have underwriters extracted. Many small offerings use a single placement agent named in a format the parser does not pick up, and some covers are images. The ranking describes the larger, syndicated deals.
  • "Listed first" is the first bank on the cover after cleaning. Many covers list bookrunners in alphabetical order (the note is often printed on the cover), so first position is a weak signal of the lead left bank. Treat it as an approximation.
  • Counts are deals, not dollars. Weight by deal size with the gross proceeds from the largest offerings tutorial to rank by volume.

Variations

  • Dollar weighted league table: join each deal's sharesOffered * pricePerShare to its bank list and sum per bank.
  • Sector view: look up each issuer's SIC code with /v1/entities?cik=<cik> and count banks per industry.
  • Track a bank over time: filter deals to those that include one bank and group by month of filedAt.

Next steps

More capital raising guides

Run this guide with your own key

500 free API calls a month. Every example on this page works on the free plan.

Get free API key →