SEC companyfacts: Why fy == 2024 Returns the Wrong Balance Sheet, and What to Filter On

Ask SEC companyfacts for Apple's total assets with fy == 2024 and fp == "FY" and two numbers come back. The first one is not fiscal 2024's.

What came back

endval formfy fpfiled
2023-09-30352,583,000,00010-K 2024FY2024-11-01
2024-09-28364,980,000,00010-K 2024FY2024-11-01

fy and fp describe the filing, not the period the number is about. Apple's fiscal 2024 10-K contains two balance sheets, this year's and last year's, so two facts carry its label. Code that takes the first match (next(...), [0], drop_duplicates) gets fiscal 2023. We checked the last eight fiscal years of Apple, Walmart and Nike: the first match was the wrong year 24 times out of 24. Taking the last match was right 24 of 24, but only because the facts arrive sorted by end date, which is not a documented promise.

One balance sheet date, five filings

The same figure also appears in later filings as a comparative. Apple's balance sheet at 28 September 2024, $364,980 million, is in five of them:

formfy fpfiled frame
10-K2024FY2024-11-01none
10-Q2025Q12025-01-31none
10-Q2025Q22025-05-02none
10-Q2025Q32025-08-01none
10-K2025FY2025-10-31CY2024Q3I

So a filter on fy == 2025 and fp == "Q1" returns this number as well as the quarter you wanted (28 December 2024, $344,085 million). A quarter's filing always carries the prior fiscal year-end next to it.

frame is the Frames API's pick, not a fiscal label

The frame column above is the part that surprises people. It is not a label for the period. It marks one fact per period, the one the Frames API serves, and the SEC defines that as the last filed fact that fits. It sits on the newest filing to repeat the date, and moves when a newer one does:

Balance sheet dateframe carried by the fact in
Apple, 2024-09-28CY2024Q3I the fiscal 2025 10-K, filed 2025-10-31
Walmart, 2026-01-31CY2025Q4I its fiscal 2027 Q2 10-Q, filed 2026-08-28
Nike, 2013-05-31CY2013Q2I the fiscal 2014 10-K, filed 2014-07-25

Apple's fiscal year ends in late September, so its year-end balance sheet is calendar "Q3". Walmart's fiscal 2026 ends on 31 January 2026 and the frame calls it calendar "Q4" of 2025. Nike's May year-end is "Q2". None of that is a bug, and none of it is the fiscal year. Do not use frame to label a fiscal year, and do not read it as "the original".

The same date can have different numbers

Nike's balance sheet at 31 May 2013 appears in five filings with three different totals:

formfy / fp filedAssets at 2013-05-31
10-K2013 FY2013-07-23$17,584M
10-Q2014 Q12013-10-07$17,584M
10-Q2014 Q22014-01-07$17,584M
10-Q2014 Q32014-04-07$17,680M
10-K2014 FY2014-07-25$17,545M

We have not traced why each filing's figure differs. The point is that companyfacts keeps all five, so a rule has to choose. "As reported" is the earliest filing; "latest" is what the Frames API serves. A backtest needs the first, and the dates problem is bigger than it looks.

A rule that picks one value per fiscal year

Do not trust the labels; use what the filing itself says. A 10-K's balance sheet date is the latest date among its own balance sheet facts, so group by accession number and take that:

import collections

def annual_balance(facts, tag="Assets", forms=("10-K", "10-K/A", "10-KT")):
    rows = facts["facts"]["us-gaap"][tag]["units"]["USD"]
    by_filing = collections.defaultdict(list)
    for f in rows:
        if f["form"] in forms:
            by_filing[f["accn"]].append(f)

    out = {}
    for accn, fs in by_filing.items():
        # this filing's own balance sheet date
        period_end = max(f["end"] for f in fs)
        fact = next(f for f in fs if f["end"] == period_end)
        keep = out.get(period_end)
        # earliest filing = as reported
        if keep is None or fact["filed"] < keep["filed"]:
            out[period_end] = {"end": period_end, "val": fact["val"],
                               "filed": fact["filed"], "accn": accn}
    return sorted(out.values(), key=lambda r: r["end"])

Flip the < to > for the latest value instead. We ran it on Apple, Walmart and Nike, 17 fiscal year-ends each. The last four for Apple:

Fiscal year endTotal assets 10-K filed
2022-09-24$352,755M2022-10-28
2023-09-30$352,583M2023-11-03
2024-09-28$364,980M2024-11-01
2025-09-27$359,241M2025-10-31

It is not tested on filers that change their year-end, and a transition report (10-KT) is included in the forms list without having been exercised. Check those before relying on them.

Income and cash flow are worse

A balance sheet fact is a point in time. Income and cash-flow facts cover a span, and a 10-K reports three. Apple's fiscal 2025 revenue under fy == 2025 and fp == "FY":

startend daysRevenue
2022-09-252023-09-30370$383,285M
2023-10-012024-09-28363$391,035M
2024-09-292025-09-27363$416,161M

Three years carry the same label, and the 53-week year is 370 days, so "about 365" is not a rule. Match the span to the filing's period end: end == period_end and a duration of roughly a year. Quarterly cash flow has its own trap, because a 10-Q reports it year to date; that and the missing fourth quarter are covered in the point-in-time note.

When you would rather not do the selecting

BalanceProof returns each figure with the period it describes and the day it was filed, so there is nothing to disentangle. The keyless demo shows the shape, and total_assets and liabilities_and_equity come back side by side, because the filer's stated total is the referee:

curl https://balanceproof.dev/api/demo/AAPL

"period_end": "2026-06-27",
"filing_date": "2026-07-31",
"total_assets": {"value": 383266000000.0, "restated": false, ...},
"liabilities_and_equity": {"value": 383266000000.0, ...}

That is Apple's 10-Q for the quarter ended 27 June 2026, as of this writing; it moves when Apple files. A free key reads any of the 6,000+ companies and one year of history, longer series are on paid plans, and as_of returns what had been filed by a past date (Pro and above). Figures are as reported to the SEC. When a later filing revises a figure, the default view shows the revised value under the later filing's date; as_of queries return the value known on the date you ask. If you are building across all companies at once, the comparison of the SEC's bulk routes is the companion to this.

Questions

What do fy and fp mean in SEC companyfacts?
They label the filing that reported the fact: its fiscal year and fiscal period. A 10-K for fiscal 2024 contains the prior year's balance sheet as well, so both carry fy 2024 and fp FY. They do not say which period the value describes; the end date does.
What is the frame field in companyfacts?
It marks the one fact the Frames API serves for a calendar-aligned period: the last filed fact that fits it. It appears on one fact per period and moves to a newer filing when one repeats the period, so it is neither a fiscal label nor the original value.
How do I get one annual balance sheet value per fiscal year?
Group the 10-K facts by accession number, take the latest end date in each filing as that year's balance sheet date, and keep the earliest filing per date if you want the figure as originally reported. Do not filter on fy and fp alone.

See it on a real filing

Every figure on these pages is as reported, drawn at true proportion. No account needed.