All Posts
TutorialShare BuybacksSEC FilingsPython

Stock Buyback API: Repurchase Data in Python

Stock buyback API for share repurchase data in Python: shares bought, average price paid and remaining authorization, traced to the SEC filing.

Published October 25, 202616 min readStockFit Engineering
Stock Buyback API: Repurchase Data in Python

Apple repurchased and retired 402 million of its shares for $89.3 billion in the fiscal year ending 2025-09-27, an average of $222.14 a share. That is one request to a stock buyback API, and every number in it can be traced to a fact in Apple's 10-K. This tutorial shows the request, the response and that receipt, then works through what the same data looks like for companies that report buybacks differently.

The data is share repurchase execution: what a company actually spent, how many shares it bought, the average price it paid and, where the filer tags it, how much of the board's authorization is left. It comes from the XBRL in 10-K and 10-Q filings. The Python below pulls it, handles the three ways filers tag it, compares the average price paid with the current price, computes buyback yield and puts a stock split on the right basis. Every figure is live API output pulled on 2026-10-25; prices are the close on 2026-10-23.

What a stock buyback record contains

A buyback is announced once and executed over months or years. The announcement (a press release or an 8-K) says the board authorized, for example, a few billion dollars of repurchases. The execution shows up later, period by period, in the cash flow statement and in the equity note of the 10-Q and 10-K. /api/footnotes/buybacks serves the execution side, one object per fiscal year or per quarter:

FieldWhat it is
period, fiscalYear, fiscalPeriodPeriod end date as filed, and the fiscal labels (FY, Q1 to Q4)
dateFiledFiling date of the document the values come from
cashSpentCash paid for repurchases, from the cash flow statement
repurchased.value, repurchased.sharesDollar value and share count repurchased, from the equity note
repurchased.styleretired, treasury or repurchased: which XBRL concept family the filer used
repurchased.avgPricePerShare, avgPriceDerivedAverage price paid; the flag is true when it was computed as value divided by shares
program.authorized, remaining, consumedBoard authorization, headroom left and the amount used (authorized minus remaining), where tagged

Two rules shape every piece of code in this post. First, fields the filer did not tag are omitted, not null: a company that reports only a share count has no value key at all. Second, a zero is a value. A year with no buybacks comes back as zeros, not as a missing row. Monetary values are in US dollars by default (the currency parameter works as on the statement endpoints); share counts are never converted.

period=annual returns fiscal years and period=quarter the quarterly series, with limit up to 80 periods (plans can clamp it). The endpoint takes one identifier: symbol, cik, cusip, composite_figi or share_class_figi. Like the other footnote endpoints, it is on the Pro plan: $99/month or $828/year ($69/month billed annually). The cash figure alone is also on /api/financials/cash-flow-statement, which every plan can call: its commonStockRepurchased line for Apple's fiscal 2025 is the same 90,711,000,000 as cashSpent below.

Get Apple's share repurchases in Python

Four fiscal years of Apple buybacks, with curl first:

bash
curl "https://api.stockfit.io/v1/api/footnotes/buybacks?symbol=AAPL&period=annual&limit=4" \
  -H "Authorization: Bearer $STOCKFIT_API_KEY"

The response, newest year first, with the two latest years shown:

json
[
  {
    "period": "2025-09-27",
    "fiscalYear": 2025,
    "fiscalPeriod": "FY",
    "currency": "USD",
    "dateFiled": "2025-10-31",
    "cashSpent": 90711000000,
    "repurchased": {
      "value": 89300000000,
      "shares": 402000000,
      "style": "retired",
      "avgPricePerShare": 222.13930348258705,
      "avgPriceDerived": true
    }
  },
  {
    "period": "2024-09-28",
    "fiscalYear": 2024,
    "fiscalPeriod": "FY",
    "currency": "USD",
    "dateFiled": "2024-11-01",
    "cashSpent": 94949000000,
    "repurchased": {
      "value": 95000000000,
      "shares": 499000000,
      "style": "retired",
      "avgPricePerShare": 190.3807615230461,
      "avgPriceDerived": true
    }
  }
  // 2 more fiscal years: 2023-09-30 and 2022-09-24
]

Apple tags its buybacks as shares repurchased and retired, so style is retired. It does not tag an average price, so the API divides value by shares and says so with avgPriceDerived: true. In Python, flatten each period into one row and read every optional field with .get():

python
import os
import requests

BASE = "https://api.stockfit.io/v1/api"
HEADERS = {"Authorization": f"Bearer {os.environ['STOCKFIT_API_KEY']}"}


def get(path, **params):
    r = requests.get(f"{BASE}/{path}", params=params, headers=HEADERS, timeout=60)
    r.raise_for_status()
    return r.json()


def buybacks(symbol, period="annual", limit=8):
    """One flat row per period. Fields the filer did not tag come back as None."""
    rows = []
    for p in get("footnotes/buybacks", symbol=symbol, period=period, limit=limit):
        rep = p.get("repurchased", {})
        prog = p.get("program", {})
        rows.append({
            "period": p["period"],
            "fiscalYear": p["fiscalYear"],
            "fiscalPeriod": p["fiscalPeriod"],
            "dateFiled": p["dateFiled"],
            "cashSpent": p.get("cashSpent"),
            "value": rep.get("value"),
            "shares": rep.get("shares"),
            "style": rep.get("style"),
            "avgPrice": rep.get("avgPricePerShare"),
            "avgDerived": rep.get("avgPriceDerived", False),
            "authorized": prog.get("authorized"),
            "remaining": prog.get("remaining"),
        })
    return rows


for r in buybacks("AAPL", limit=4):
    print(r["period"], f"{r['shares'] / 1e6:,.0f}M shares", f"{r['value'] / 1e9:.1f}B USD",
          f"avg {r['avgPrice']:.2f}", r["style"], "derived" if r["avgDerived"] else "tagged")
text
2025-09-27 402M shares 89.3B USD avg 222.14 retired derived
2024-09-28 499M shares 95.0B USD avg 190.38 retired derived
2023-09-30 471M shares 76.6B USD avg 162.63 retired derived
2022-09-24 569M shares 90.2B USD avg 158.52 retired derived

Over four fiscal years Apple bought 569M, 471M, 499M and 402M shares, and the average price it paid rose each year, from $158.52 to $222.14. That is a description of the record, not a verdict on it: whether a repurchase was a good use of cash is a question this data informs and does not answer.

Apple: shares repurchased and average price paid, four fiscal years
Source: /api/footnotes/buybacks?symbol=AAPL&period=annual, as of 2026-10-25. Average price is repurchased.value divided by repurchased.shares (avgPriceDerived: true); Apple does not tag it.

The receipt: Apple's 10-K

dateFiled is 2025-10-31, the day Apple filed its 10-K for the year ended September 27, 2025 (accession 0000320193-25-000079). The 402,000,000 shares are the XBRL fact us-gaap:StockRepurchasedAndRetiredDuringPeriodShares in that filing, and the $89.3 billion is its ...Value sibling. The last section of this post fetches that fact straight from the SEC so you can check it without trusting us.

cashSpent is not repurchased.value

In the same year, cashSpent is $90.711 billion and repurchased.value is $89.3 billion. They come from different statements. cashSpent is the cash flow line, cash that left the company in the period. value is the equity note, the cost of the shares repurchased. The two can differ because of settlement timing (a trade at period end that settles after it), costs and taxes the filer includes on one side only, and rounding: Apple reports the equity figure to a tenth of a billion. Do not assume which one applies to a given company without reading its note. Pick the one that fits your question, and say which you used.

Retired, treasury and repurchased: three buyback styles

A company can cancel repurchased shares (they are retired and stop existing) or keep them as treasury stock, held at cost and available to reissue. The accounting choice decides which XBRL concepts the filer uses, and filers also differ in what they tag at all. The API serves one concept family per period and names it in style:

Company, FY endstylevaluesharesavgPricePerShare
Apple, 2025-09-27retired$89,300,000,000402,000,000222.14 (derived)
AutoZone, 2025-08-30treasury$1,531,659,000447,0003,426.53 (derived)
Microsoft, 2026-06-30repurchasedomitted36,000,000omitted
O'Reilly, 2025-12-31retired$2,096,962,00022,728,00092.26 (tagged)
Home Depot, 2026-02-01treasury00omitted

retired maps to the StockRepurchasedAndRetiredDuringPeriod... concepts, treasury to the TreasuryStock...Acquired family (AutoZone tags TreasuryStockSharesAcquired), and repurchased to the generic StockRepurchasedDuringPeriod... pair. Microsoft tags only StockRepurchasedDuringPeriodShares, so its rows have a share count and the $22.271 billion of cashSpent, but no value and no average price. Alphabet is the mirror case: its annual rows carry a retired value and no share count. Home Depot's fiscal year ending 2026-02-01 is a real zero year, tagged as zero in the 10-K, and it should stay in your data as zero rather than disappear.

Code that assumes all fields exist crashes on Microsoft. Code that treats missing as zero reports that Microsoft spent nothing. Branch on what is there:

python
def describe(r):
    if r["shares"] is None and r["value"] is None:
        return "no repurchased block, cashSpent only"
    if r["shares"] == 0 and r["value"] in (0, None):
        return "no repurchases this period"
    if r["shares"] is None:
        return f"value only: {r['value']:,} USD, no share count tagged"
    if r["value"] is None:
        return f"shares only: {r['shares']:,} shares, no dollar value tagged"
    return f"{r['shares']:,} shares for {r['value']:,} USD ({r['style']})"


for sym in ("AAPL", "AZO", "MSFT", "HD"):
    r = buybacks(sym, limit=1)[0]
    print(sym, r["period"], describe(r))
text
AAPL 2025-09-27 402,000,000 shares for 89,300,000,000 USD (retired)
AZO 2025-08-30 447,000 shares for 1,531,659,000 USD (treasury)
MSFT 2026-06-30 shares only: 36,000,000 shares, no dollar value tagged
HD 2026-02-01 no repurchases this period

For counting the effect on shares outstanding, the style matters less than it seems: retired and treasury shares are both outside the outstanding count. The difference shows up on the balance sheet (issued shares fall only when shares are retired) and in what the company can reissue. If your real question is the net share count after employee stock issuance, our stock-based compensation dilution guide covers that side and uses buybacks as the offset.

Average price paid per share: tagged or derived

Some filers tag their own weighted average price, the concept TreasuryStockAcquiredAverageCostPerShare. When they do, the API serves it unchanged and there is no avgPriceDerived key. O'Reilly Automotive is one:

json
// GET /api/footnotes/buybacks?symbol=ORLY&period=annual&limit=1
[
  {
    "period": "2025-12-31",
    "fiscalYear": 2025,
    "fiscalPeriod": "FY",
    "currency": "USD",
    "dateFiled": "2026-02-27",
    "cashSpent": 2096962000,
    "repurchased": {
      "avgPricePerShare": 92.26,
      "value": 2096962000,
      "shares": 22728000,
      "style": "retired"
    },
    "program": { "remaining": 2400000000 }
  }
]

$92.26 is O'Reilly's own figure in its 10-K. Apple, AutoZone and Home Depot do not tag one, so their averages are value divided by shares, computed only within the same concept family. Mixing families would divide, say, a tax-withholding value by a program share count, which is why a filer with shares but no value (Microsoft) gets no average at all.

A derived average is only as precise as its inputs

Filers round. Apple reports 402 million shares and $89.3 billion; Home Depot reported 2,000,000 shares for $599,000,000 in the fiscal year ending 2025-02-02, which the API divides into $299.50. Both inputs are rounded to the unit shown in the filing, so the true average sits in a range:

python
def avg_bounds(value, shares, value_step, share_step):
    """Range of averages consistent with a value and a share count rounded to these steps."""
    lo = (value - value_step / 2) / (shares + share_step / 2)
    hi = (value + value_step / 2) / (shares - share_step / 2)
    return round(lo, 2), round(hi, 2)


print(avg_bounds(89.3e9, 402e6, 0.1e9, 1e6))  # AAPL, FY ending 2025-09-27
print(avg_bounds(599e6, 2e6, 1e6, 1e6))       # HD, FY ending 2025-02-02
text
(221.74, 222.54)
(239.4, 399.67)

Apple's $222.14 is good to within about 40 cents ($221.74 to $222.54). Home Depot's $299.50 could be anything from $239.40 to $399.67, because a share count rounded to the nearest million says little when the count is two million. Check avgPriceDerived and the size of the share count before you put a derived average next to a stock price with two decimals.

Average price paid vs the current share price

The most common question asked of buyback data is how the price a company paid compares with where the stock trades now. Take the latest fiscal year's average from the buyback endpoint and the latest close from /api/price/quote:

python
def latest_close(symbol):
    q = get("price/quote", symbols=symbol)[symbol]
    return q["close"], q["ts"][:10]


for sym in ("AAPL", "ORLY", "AZO"):
    last = buybacks(sym, limit=1)[0]
    close, day = latest_close(sym)
    gap = close / last["avgPrice"] - 1
    print(sym, last["period"], f"avg {last['avgPrice']:.2f}", f"close {close:.2f} on {day}", f"{gap:+.1%}")
text
AAPL 2025-09-27 avg 222.14 close 347.73 on 2026-10-23 +56.5%
ORLY 2025-12-31 avg 92.26 close 89.92 on 2026-10-23 -2.5%
AZO 2025-08-30 avg 3426.53 close 3200.76 on 2026-10-23 -6.6%

On 2026-10-23, Apple closed 56.5% above the $222.14 average it paid in its last fiscal year, O'Reilly 2.5% below its tagged $92.26, and AutoZone 6.6% below its derived $3,426.53. Read these as a snapshot comparison between one day's close and a full year's average, nothing more: the gap moves every trading day, and it says nothing about what the stock will do.

Keep both sides on the same share basis. O'Reilly did a 15-for-1 split in 2025, and its FY2025 average is already in post-split dollars, so it compares directly with today's quote. For older periods, see the split pitfall below. For prices at a past date, use /api/price/history with adjusted=false: the default adjusted series is back-adjusted for dividends and understates past prices, while the unadjusted close is on the current split basis with no dividend deduction. The batch form of the quote (symbols=AAPL,ORLY,AZO) needs a paid plan; one symbol per request works on Free.

Remaining buyback authorization

program.remaining is the board-authorized amount not yet used, as of the period end. Far fewer filers tag it than tag execution figures, so expect it to be absent more often than not. Where it is tagged, it shows how much room a program has left. Cisco's annual rows:

  • Fiscal year ending 2025-07-26: $14.2 billion remaining.
  • Fiscal year ending 2026-07-25: $8.1 billion remaining, after $6.106 billion of repurchases in the year.

The $6.1 billion fall in headroom matches the year's repurchases to the hundred million, which is consistent with no new authorization being added during the year; the 10-K's equity note is where to confirm it. Meta's quarterly rows show the other pattern of sparse tagging: $28.23 billion remaining at 2025-06-30, $25.03 billion at 2025-09-30 and $25.03 billion at 2025-12-31, then no program block on the 2026 quarters, because the filings for those quarters carry no fact under that concept. Absent means not tagged, not zero.

Authorized and consumed

A few filers also tag the authorization itself. O'Reilly's row for fiscal year 2023 has all three program fields:

json
// GET /api/footnotes/buybacks?symbol=ORLY&period=annual, the row for 2023-12-31
"program": {
  "authorized": 25800000000,
  "remaining": 2600000000,
  "consumed": 23200000000
}

$25.8 billion is the cumulative authorization since the program began, as the 10-K tags it (StockRepurchaseProgramAuthorizedAmount1, dated 2023-11-16 in the filing rather than at the year end), $2.6 billion is what was left at year end, and consumed is the API's derived difference, $23.2 billion. Because the authorization is cumulative, consumed covers the program's whole life, not one year.

Sanity-check program values

The API passes filer facts through as tagged, including filer mistakes. The classic one in program data is a unit error: a value entered in a table labelled “in thousands” that was already in dollars comes out a thousand times too large. Two checks catch it cheaply. Remaining can never exceed authorized, and remaining should not jump by orders of magnitude between neighbouring periods:

python
def check_program(rows, factor=50):
    """Flag program values that cannot be right. rows: one company, newest first."""
    flags = []
    for i, r in enumerate(rows):
        rem, auth = r["remaining"], r["authorized"]
        if rem is None:
            continue
        if auth is not None and rem > auth:
            flags.append((r["period"], "remaining exceeds authorized"))
        near = [x["remaining"] for x in rows[max(0, i - 1):i + 2]
                if x is not r and x["remaining"]]
        if near and rem > factor * max(near):
            flags.append((r["period"], f"remaining is over {factor}x its neighbours, check units"))
    return flags


print("CSCO", check_program(buybacks("CSCO", limit=2)))
print("META", check_program(buybacks("META", period="quarter", limit=6)))
text
CSCO []
META []

Clean series return no flags. The factor is a judgment call: new authorizations can legitimately move remaining several times over, while a unit error moves it about a thousand times. When a row is flagged, open the filing before you use it.

Buyback yield from market cap

Buyback yield is repurchases divided by market capitalization. The numerator here is the buyback endpoint; the denominator is shares outstanding at period end from /api/financials/balance-sheet times the unadjusted close on the last trading day on or before the period end:

python
from datetime import date, timedelta


def close_on_or_before(symbol, day):
    """Unadjusted close on the last trading day on or before `day`."""
    start = (date.fromisoformat(day) - timedelta(days=7)).isoformat()
    body = get("price/history", symbol=symbol, adjusted="false", **{"from": start, "to": day})
    ts, close = body["data"][-1]
    return close


def buyback_yield(symbol):
    bb = buybacks(symbol, limit=1)[0]
    sheets = get("financials/balance-sheet", symbol=symbol, period="annual", limit=2)
    # Join on fiscal year and period, not on the period date string.
    sheet = next(s for s in sheets
                 if (s["fiscalYear"], s["fiscalPeriod"]) == (bb["fiscalYear"], bb["fiscalPeriod"]))
    mcap = sheet["facts"]["sharesOutstanding"] * close_on_or_before(symbol, bb["period"])
    return bb, mcap, bb["value"] / mcap, bb["cashSpent"] / mcap


bb, mcap, on_value, on_cash = buyback_yield("AAPL")
print(f"AAPL FY{bb['fiscalYear']}: market cap {mcap / 1e12:.3f}T USD, "
      f"yield {on_value:.2%} on value, {on_cash:.2%} on cashSpent")
text
AAPL FY2025: market cap 3.774T USD, yield 2.37% on value, 2.40% on cashSpent

Apple's fiscal year ended on Saturday 2025-09-27, so the close is Friday 2025-09-26's $255.46. Times 14,773,260,000 shares outstanding, that is a market cap of $3.774 trillion, and the yield is 2.37% on repurchased value or 2.40% on cashSpent. Neither is the right one in general; publish which numerator you used. Other reasonable choices, such as an average market cap over the year, give other numbers, so say that too.

The join is on fiscalYear and fiscalPeriod, not on the period date string. Different endpoints can label the same fiscal period with slightly different dates, and a join on the date silently drops the row. Add dividends paid to the numerator and you have shareholder yield; our dividend payout ratio API guide shows where those figures come from.

Buyback data pitfalls, each with a receipt

1. A stock split puts one series on two bases

O'Reilly split its stock 15-for-1 on 2025-06-10. Its FY2025 10-K restated the prior year onto the new basis, and that restated figure is what the API serves: the FY2024 row reads 29,043,000 shares at $71.50 with dateFiled 2026-02-27. The original FY2024 10-K (accession 0000898173-25-000008) said 1,936,000 shares at $1,072.47. The FY2023 row was never restated: it still reads 3,568,000 shares at $883.13, dateFiled 2024-02-28. Plot the raw series and O'Reilly appears to have bought about eight times as many shares in 2024 as in 2023 at about a twelfth of the price.

dateFiled tells you which basis a row is on. Compare it with the split dates from /api/company/stock-splits and scale shares up and the average down for rows filed before a split. Dollar values do not change:

python
splits = get("company/stock-splits", symbol="ORLY")
# [{"date": "2025-06-10", "ratio": 15, "type": "forward", ...}]


def to_current_basis(rows, splits):
    """Put rows filed before a split on today's share basis. Dollar values never change."""
    out = []
    for r in rows:
        factor = 1.0
        for s in splits:
            if r["dateFiled"] < s["date"]:
                factor *= s["ratio"]
        r = dict(r, splitFactor=factor)
        if factor != 1.0:
            if r["shares"] is not None:
                r["shares"] *= factor
            if r["avgPrice"] is not None:
                r["avgPrice"] /= factor
        out.append(r)
    return out


for r in to_current_basis(buybacks("ORLY", limit=3), splits):
    note = f" (x{r['splitFactor']:g})" if r["splitFactor"] != 1 else ""
    print(r["period"], "filed", r["dateFiled"], f"{r['shares']:,.0f} shares", f"avg {r['avgPrice']:.2f}{note}")
text
2025-12-31 filed 2026-02-27 22,728,000 shares avg 92.26
2024-12-31 filed 2026-02-27 29,043,000 shares avg 71.50
2023-12-31 filed 2024-02-28 53,520,000 shares avg 58.88 (x15)

Treat the date rule as a first pass and confirm it with the data: a filing made shortly after a split can still report the old basis, and the jump in the average price shows which basis a row is on. The same problem in earnings data, with more cases, is in our guide to adjusting historical EPS for stock splits.

2. Missing fields are omitted, not null

Covered above, and worth repeating because it is the most common crash: Microsoft has no value, Alphabet has no shares, many filers have no program. Read with .get() and keep None distinct from zero.

3. Two dollar figures, two meanings

cashSpent and repurchased.value answer different questions. AutoZone's fiscal year ending 2025-08-30 shows $1,578,186,000 of cash spent against $1,531,659,000 of shares acquired. Use one consistently across companies and periods.

4. Annual rows are not a fourth quarter

The quarterly series is built from 10-Q facts, and the annual row never stands in for a Q4. Some filers tag only year-to-date repurchases in their 10-Qs, and the fourth quarter has no 10-Q at all, so a quarterly row can carry cashSpent with no repurchased block. Check for the block before you compute anything per quarter, and do not back out a quarter by subtracting unless every input is present. Our Q4 earnings guide covers the subtraction and its traps.

5. Join on fiscal labels

As in the yield code: when you combine buyback rows with statement rows, match fiscalYear and fiscalPeriod. The period date for the same fiscal period can differ by a day or two between endpoints.

Verify a buyback number against the SEC filing

Every value in a buyback response comes from XBRL facts in a filing, so you can check it against the SEC's own API. The SEC describes it on its EDGAR APIs page: “The company-concept API returns all the XBRL disclosures from a single company (CIK) and concept (a taxonomy and tag) into a single JSON file”. Ask it for Apple's retired shares:

python
# data.sec.gov answers 403 to generic user agents: declare who you are.
SEC_HEADERS = {"User-Agent": "Your Name your.email@example.com"}


def sec_facts(cik, concept, end, unit="shares", form="10-K"):
    url = f"https://data.sec.gov/api/xbrl/companyconcept/CIK{cik}/us-gaap/{concept}.json"
    facts = requests.get(url, headers=SEC_HEADERS, timeout=60).json()["units"][unit]
    return [f for f in facts if f["end"] == end and f["form"] == form]


for f in sec_facts("0000320193", "StockRepurchasedAndRetiredDuringPeriodShares", "2025-09-27"):
    print(f["start"], f["end"], f["val"], f["accn"], f["filed"])
text
2024-09-29 2025-09-27 402000000 0000320193-25-000079 2025-10-31

Same value, same period, and the accession number 0000320193-25-000079 is the 10-K, filed on the dateFiled the buyback endpoint returned. The concept to query follows from style:

  • retired: StockRepurchasedAndRetiredDuringPeriodShares and StockRepurchasedAndRetiredDuringPeriodValue
  • treasury: TreasuryStockSharesAcquired and its value sibling
  • repurchased: StockRepurchasedDuringPeriodShares and its value sibling
  • A tagged average: TreasuryStockAcquiredAverageCostPerShare (unit USD/shares)
  • Program: StockRepurchaseProgramRemainingAuthorizedRepurchaseAmount1 and StockRepurchaseProgramAuthorizedAmount1

Pass unit="USD" for the dollar concepts. A period can appear in several filings, for example as the prior-year column of the next 10-K. Where those facts differ, as in the split restatement above, match the one whose filed date equals the API's dateFiled.

What buyback data from 10-K and 10-Q filings does not cover

Monthly detail. When a company repurchased shares, its 10-Q or 10-K includes an issuer purchases table under Regulation S-K Item 703, with total shares purchased, average price paid, shares bought under announced programs and the amount that may yet be purchased, month by month. That table is HTML, not XBRL, so the API stops at quarters. If you need month-level rows, that table is the source; some commercial vendors carry it too (ORTEX lists “Monthly detail” for its buyback data, delivered by “API, CSV, ORTEX platform”).

Daily repurchases. The SEC adopted a rule in May 2023 that would have required daily repurchase data. A federal court vacated it, and the SEC's technical amendments (Release 34-99778) state that the vacatur “was effective as of December 19, 2023, and had the legal effect of reverting to the rules and forms that existed prior to the effective date of the Repurchase Rule.” The monthly Item 703 table is therefore still the finest granularity filers report.

Announcements. New authorizations announced by press release or 8-K appear here only once a 10-Q or 10-K tags the program amount, and many filers never tag it. The endpoint is built for what was executed.

Quarterly coverage depends on how the filer tags
Filers that tag only year-to-date repurchases in their 10-Qs leave some quarters with cashSpent and no share count. Use annual rows for multi-year comparisons, and test for the repurchased block before computing per-quarter averages.

The buyback endpoint is on the Pro plan; the cash flow statement, balance sheet and price endpoints used here are on every plan. You can start with a and the cash flow line, and add the footnote data when you need shares, average prices and authorization.

FAQ

Q.How do I get stock buyback data in Python?
Call GET /api/footnotes/buybacks with requests, a symbol (for example AAPL) and period=annual or period=quarter. Each period returns cashSpent, a repurchased block (value, shares, style, avgPricePerShare, avgPriceDerived) and, where the filer tags it, a program block (authorized, remaining, consumed). Read optional fields with .get(), because fields the filer did not tag are omitted. For Apple's fiscal year ending 2025-09-27 it returns 402,000,000 shares retired for $89.3 billion, a derived average of $222.14.
Q.Where do I find how many shares a company repurchased?
In the equity note and the issuer purchases table of its 10-K and 10-Q, and in the XBRL facts behind them: StockRepurchasedAndRetiredDuringPeriodShares, TreasuryStockSharesAcquired or StockRepurchasedDuringPeriodShares, depending on how the filer accounts for buybacks. The buyback API returns that count as repurchased.shares and names the concept family in repurchased.style. Some filers tag only a dollar value, in which case no share count is returned.
Q.How is the average price paid per share for buybacks calculated?
If the filer tags its own weighted average (TreasuryStockAcquiredAverageCostPerShare), the API returns that figure unchanged, as for O'Reilly's $92.26 in fiscal 2025. Otherwise it divides the repurchased value by the shares within the same concept family and sets avgPriceDerived to true. A derived average inherits the filer's rounding: Apple's $222.14 lies between $221.74 and $222.54, and Home Depot's $299.50 for 2,000,000 shares and $599,000,000 could be anywhere from $239.40 to $399.67.
Q.What is the difference between retired and treasury shares in a buyback?
Retired shares are cancelled when repurchased and no longer exist; treasury shares are held by the company at cost and can be reissued. Both are excluded from shares outstanding. The choice decides which XBRL concepts a filer uses, and the API reports it as repurchased.style: retired (Apple), treasury (AutoZone, Home Depot) or repurchased for the generic concepts (Microsoft).
Q.How do I find the remaining buyback authorization for a stock?
Read program.remaining from /api/footnotes/buybacks. It is the authorized amount not yet used at the period end, tagged by far fewer filers than execution figures, so it is often absent. Cisco's remaining authorization went from $14.2 billion at its fiscal year end on 2025-07-26 to $8.1 billion on 2026-07-25. Check that remaining never exceeds authorized and does not jump by orders of magnitude between periods, which signals a unit error in the filing.
Q.Is buyback data available monthly or quarterly?
The API returns annual and quarterly data from 10-K and 10-Q XBRL. The monthly issuer purchases table required by Regulation S-K Item 703 is HTML rather than XBRL, so it is not in the API; read it from the filing itself. Daily repurchase data is not reported to the SEC, because the 2023 rule that would have required it was vacated effective December 19, 2023.
Q.Which StockFit plan includes the buyback endpoint?
/api/footnotes/buybacks is on the Pro plan, $99/month or $828/year ($69/month billed annually). The cash flow statement, which carries the cash paid for repurchases, the balance sheet and the price endpoints are available on every plan, including Free.

Ready to build?

Free API key, no credit card.