# S\&P 500 Quarterly Reports from SEC EDGAR XBRL (`mikee368/sp500-quarterly-reports`) Actor

Quarterly and annual financials for S\&P 500 companies from SEC EDGAR companyfacts XBRL: revenue, profit, EPS, balance sheet, cash flow, and derived free cash flow. One row per company per fiscal period.

- **URL**: https://apify.com/mikee368/sp500-quarterly-reports.md
- **Developed by:** [Mike Berckmoes](https://apify.com/mikee368) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 company period reports

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## S\&P 500 quarterly reports from SEC EDGAR XBRL

**Get one clean row per company per fiscal period for S\&P 500 names, from the official SEC companyfacts API.** Revenue, gross profit, operating income, net income, basic and diluted EPS, the balance sheet, operating cash flow, capex, derived free cash flow, and shares outstanding. Each figure records the XBRL tag that supplied it.

The figures are **as-reported XBRL data, not investment advice.** They are the values the company tagged in its 10-Q or 10-K. They are not adjusted, not a forecast, and not a recommendation.

Source: SEC EDGAR `data.sec.gov` companyfacts and `www.sec.gov/files/company_tickers.json`. The S\&P 500 list is the public `datasets/s-and-p-500-companies` CSV, with a snapshot bundled in the Actor if that file changes. No third-party fundamentals site is scraped.

### What you get

| Field | Meaning |
|---|---|
| `ticker`, `cik`, `companyName` | Apple Inc., 320193, AAPL. `BRK.B` is returned as `BRK-B`. |
| `form`, `fiscalYear`, `fiscalPeriod` | 10-Q or 10-K, fiscal year, Q1–Q4 or FY. Fiscal labels, not calendar quarters. |
| `periodStart`, `periodEnd`, `filedDate` | Period dates and the filing date. |
| `accessionNumber`, `filingUrl` | The filing the figures came from, linked on sec.gov. |
| `revenue`, `grossProfit`, `operatingIncome`, `netIncome` | As reported. Null when that concept is not tagged. |
| `epsBasic`, `epsDiluted` | As reported for that quarter. EPS is not invented for a derived Q4. |
| `totalAssets`, `totalLiabilities`, `stockholdersEquity` | Point-in-time balances. |
| `cashAndEquivalents`, `longTermDebt` | Point-in-time. Long-term debt prefers the noncurrent tag. |
| `operatingCashFlow`, `capex` | Quarter or year only. A year-to-date cash-flow number is not used as the quarter. |
| `freeCashFlow` | Always derived: operating cash flow minus the absolute value of capex. Null if either tag is missing. |
| `tags` | The concept used for each figure (`Revenues`, `RevenueFromContractWithCustomerExcludingAssessedTax`, `SalesRevenueNet`, and the other fallbacks). |
| `derived`, `derivedFields` | Q4 built as FY minus Q1 minus Q2 minus Q3 when no quarterly Q4 fact exists. |
| `notFound` | Unknown ticker, bad accession, or no companyfacts. That row is not charged. |

### How to use it

- **A few tickers.** `tickers: ["AAPL", "MSFT"]`. `periods` is the number of latest fiscal quarters (default 4, hard cap 20). `includeAnnual` adds the 10-K year for those fiscal years (default on).
- **The S\&P 500.** Set `allSp500` to true, or pass the ticker `all`. The run still stops at `maxCompanies` (default 20, hard cap 20). The status message says the full list needs multiple runs. Set `companyOffset` to 20, 40, 60, and so on to take the next slice. Constituent order is the order of the source list.
- **Chain from SEC EDGAR Filings Watch.** Pass that Actor's `cik` in `ciks`, or its `accessionNumber` in `accessions`. This Actor reads companyfacts once per CIK. It does not call Filings Watch. An accession-only run returns the periods on that filing.
- **Forms.** `forms` is `10-Q` and/or `10-K`. Anything else is rejected.

### How much does it cost?

Pay per event: **$2 per 1,000 period rows** (`company-period-report` at $0.002). This is a proposal; the final price is set when the Actor is published. A not-found row is free. A run of Apple and Microsoft for four quarters plus the annual rows is a few cents. Runs use 256 MB.

A local or private run that is not on pay-per-event stores the rows and reports `charged` as the number of period rows that would be billed.

### Good to know

- **SEC fair access.** The User-Agent is `mikee368-apify-sec-watch (apify.com/mikee368; mike.berckmoes@gmail.com)`, the filings-watch identity plus the contact address. The Actor stays under 5 requests per second. HTTP 429 is retried with `Retry-After`. If the ticker file on www.sec.gov is refused, CIKs are taken from the bundled S\&P 500 snapshot and the run continues on data.sec.gov. A 403 from data.sec.gov stops further SEC calls. The run still ends successfully, and the status message names the host that refused.
- **One session.** Ticker map, constituent list, and companyfacts share one HTTP client. Companyfacts is fetched once per CIK and only the concepts above are kept. The raw JSON is not written to the dataset.
- **Cache.** The ticker map and the S\&P 500 list are stored for 24 hours in the key-value store `sp500-quarterly-reports-cache`. A failed list download uses the bundled snapshot.
- **Tag fallbacks.** For each period the Actor tries `Revenues`, then `RevenueFromContractWithCustomerExcludingAssessedTax`, then `SalesRevenueNet`, and the other concepts listed in the code. The tag that won is in `tags`. A missing concept stays null.
- **Q4.** Most companies do not file a 10-Q for the fourth quarter. When Q1, Q2, Q3, and FY share one tag, Q4 is FY minus those three quarters and `derived` is true. EPS is not subtracted. Balance-sheet lines on that row are the year-end balances from the 10-K, which are the same instant.
- **Free cash flow** is always marked `freeCashFlowDerived: true` on a period row. The operating-cash-flow and capex tags are recorded even when the result is null.
- **Do not guess.** Two different values in the same filing for one concept become null. Share classes that companyfacts does not separate (Berkshire Class A and Class B) stay null rather than picking one.

### Not investment advice

This Actor delivers as-reported XBRL from public SEC filings. It does not give investment, accounting, legal, or tax advice. Totals can differ from a press release because of tag choice, amendments, or a derived fourth quarter. Read the filing at `filingUrl` before you rely on a number. This Actor is not affiliated with or endorsed by the U.S. Securities and Exchange Commission or by S\&P Dow Jones Indices.

### Data source and licence

SEC EDGAR public data. Information on sec.gov is U.S. government work. Automated access follows the SEC fair-access policy. The constituent CSV is a maintained public file; the bundled snapshot is only a fallback.

### FAQ

**Do I need an API key?** No.

**Why is operating cash flow null on a 10-Q?** Many 10-Qs tag cash flow as year-to-date. That number is not the quarter, so the quarter is null and free cash flow is null with it.

**Why is Q4 marked derived?** There was no quarterly Q4 fact. The flow fields are FY minus Q1–Q3.

**Can one run return all 500 companies?** No. `maxCompanies` caps the run at 20. Use `companyOffset` on later runs.

# Actor input Schema

## `tickers` (type: `array`):

US tickers, for example AAPL, MSFT, or BRK.B. The ticker all selects the S\&P 500 list. Dots are read as hyphens (BRK.B and BRK-B are the same). Leave empty when using CIKs, accessions, or allSp500.

## `ciks` (type: `array`):

SEC Central Index Keys, for example 320193. Use this to chain a row from sec-edgar-filings-watch. One companyfacts request per CIK. This Actor does not call that Actor.

## `accessions` (type: `array`):

SEC accession numbers, for example 0000320193-26-000020. The CIK is taken from the accession. When no tickers or CIKs are set, only periods on that filing are returned. One companyfacts request per CIK.

## `allSp500` (type: `boolean`):

Use the S\&P 500 constituent list when no ticker, CIK, or accession is given. The run still stops at Max companies. Covering the full list takes multiple runs (raise Company offset).

## `periods` (type: `integer`):

How many of the latest fiscal quarters to return per company (1-20). Annual rows are extra when Include annual is on.

## `includeAnnual` (type: `boolean`):

Also return the 10-K fiscal year for each selected quarter's fiscal year.

## `forms` (type: `array`):

SEC forms to read. Only 10-Q and 10-K. Q4 is derived from the 10-K when the company did not report a quarterly Q4 fact.

## `maxCompanies` (type: `integer`):

Hard cap on companies per run (1-20). allSp500 does not override this cap.

## `companyOffset` (type: `integer`):

Skip this many S\&P 500 constituents before Max companies. Use 0, then 20, then 40, to walk the full list.

## Actor input object example

```json
{
  "tickers": [
    "AAPL",
    "MSFT"
  ],
  "ciks": [],
  "accessions": [],
  "allSp500": false,
  "periods": 4,
  "includeAnnual": true,
  "forms": [
    "10-Q",
    "10-K"
  ],
  "maxCompanies": 20,
  "companyOffset": 0
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset with one row per company per fiscal period

## `summary` (type: `string`):

Status, SEC requests, cache, and counts

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "tickers": [
        "AAPL",
        "MSFT"
    ],
    "ciks": [],
    "accessions": [],
    "forms": [
        "10-Q",
        "10-K"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mikee368/sp500-quarterly-reports").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "tickers": [
        "AAPL",
        "MSFT",
    ],
    "ciks": [],
    "accessions": [],
    "forms": [
        "10-Q",
        "10-K",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("mikee368/sp500-quarterly-reports").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "tickers": [
    "AAPL",
    "MSFT"
  ],
  "ciks": [],
  "accessions": [],
  "forms": [
    "10-Q",
    "10-K"
  ]
}' |
apify call mikee368/sp500-quarterly-reports --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mikee368/sp500-quarterly-reports"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/0OZitOzQc3ZHe6eTv/builds/jnwnCaUtuHzymW0pd/openapi.json
