# Studying Stocks API: full documentation Source: https://studyingstocks.com/developers --- # Overview > API version: v1 The Studying Stocks API gives you standardized fundamentals for listed US companies, built from SEC EDGAR filings, and our own free cash flow valuation. It is a read-only JSON API. - **Our data only.** Every value comes from SEC EDGAR filings (public domain) or from our own calculations on them. Calculated items (free cash flow, ROIC, debt to free cash flow, the valuation) are marked as such in the [line items](https://studyingstocks.com/developers/line-items) guide. - **Source-linked.** Responses link to the company's SEC filings, so you can check a value where it was reported. - **Built for developers and AI agents.** One version, a few endpoints, an OpenAPI 3.1 document, [llms.txt](https://studyingstocks.com/llms.txt) and a [skill file](https://studyingstocks.com/developers/skill) for agents. ## Base URL ```text https://studyingstocks.com/api/v1 ``` ## Endpoints | Endpoint | Returns | |---|---| | `GET /companies` | Covered companies, with search, exchange filter and paging | | `GET /companies/{symbol}` | A company's profile and data coverage | | `GET /companies/{symbol}/financials` | Standardized line items per period (TTM or annual) | | `GET /companies/{symbol}/financials/revisions` | Restatement history of the line items | | `GET /companies/{symbol}/valuation` | Our 10-year free cash flow valuation | | `GET /status` | API version, data freshness and number of companies (no key needed) | ## Access and price API access is included in the **Premium plan**, for personal and commercial use, with no extra tiers. Subscribers create their key on the [profile page](https://studyingstocks.com/profile#api-access). Limits are 60 requests per minute and 10,000 per day per key; if you need more, [contact us for higher limits](mailto:contact@studyingstocks.com). ## Terms in short - The data is provided as is and is not investment advice. - The [rate limits](https://studyingstocks.com/developers/rate-limits) apply. - v1 is in **beta** and may change; every change is announced in the [changelog](https://studyingstocks.com/developers/changelog). ## Where to go next 1. [Quickstart](https://studyingstocks.com/developers/quickstart): from key to first request in two minutes. 2. [Authentication](https://studyingstocks.com/developers/authentication), [rate limits](https://studyingstocks.com/developers/rate-limits) and [errors](https://studyingstocks.com/developers/errors). 3. The endpoint pages, or the [interactive reference](https://studyingstocks.com/developers/reference). --- # Pricing > API version: v1 API access is included in the **Premium plan**. There is one plan and no API tiers, for personal and commercial use. | Plan | Price | |---|---| | Monthly | $4.99 per month | | Yearly | $34.99 per year | All prices are in US dollars. Cancel any time; the key stops working when the subscription ends. ## What is included - Every endpoint of API v1: companies, profiles, standardized financials, revisions and the valuation. See the [endpoint list](https://studyingstocks.com/developers) in the overview. - One API key, which you create, regenerate and revoke on your profile page. - 60 requests per minute and 10,000 requests per day per key. See [rate limits](https://studyingstocks.com/developers/rate-limits). - Data from SEC EDGAR filings and our own calculations, with links to the filings. - The Markdown docs, `llms.txt` and the OpenAPI document, free and without a key. - Everything else in Premium: fair value metrics, unlimited analyses and no ads on the website. ## Need more? If 60 requests per minute or 10,000 per day is not enough, [contact us](mailto:contact@studyingstocks.com) at contact@studyingstocks.com and tell us what you are building. ## How to get a key 1. Sign up or log in at https://studyingstocks.com/register or https://studyingstocks.com/login. 2. Subscribe to Premium on the pricing page of the website. 3. Open your profile page at https://studyingstocks.com/profile#api-access and press **Create API key**. 4. Follow the [quickstart](https://studyingstocks.com/developers/quickstart). --- # Quickstart > API version: v1 ## 1. Get your key Subscribe to the Premium plan, open your [profile page](https://studyingstocks.com/profile#api-access) and press **Create API key**. Copy the key right away: it is shown only once. Keep it in an environment variable, never in code or in a URL: ```bash export STUDYING_STOCKS_API_KEY="ss_live_..." ``` ## 2. Make a request Ask for the last five fiscal years of revenue and free cash flow of Cisco: **curl** ```bash curl "https://studyingstocks.com/api/v1/companies/CSCO/financials?period=annual&items=revenue,free_cash_flow&limit=5" \ -H "X-Api-Key: $STUDYING_STOCKS_API_KEY" ``` **Python** ```python import os import requests response = requests.get( "https://studyingstocks.com/api/v1/companies/CSCO/financials", params={"period": "annual", "items": "revenue,free_cash_flow", "limit": 5}, headers={"X-Api-Key": os.environ["STUDYING_STOCKS_API_KEY"]}, ) response.raise_for_status() for row in response.json()["data"]: print(row["period"], row["values"]) ``` **JavaScript** ```javascript const response = await fetch( "https://studyingstocks.com/api/v1/companies/CSCO/financials?period=annual&items=revenue,free_cash_flow&limit=5", { headers: { "X-Api-Key": process.env.STUDYING_STOCKS_API_KEY } }, ); if (!response.ok) throw new Error(await response.text()); const { data } = await response.json(); console.log(data); ``` The response has a `data` array, newest period first, and a `meta` object: ```json { "data": [ { "period": "FY2026", "period_end": "2026-07-25", "fiscal_year": 2026, "fiscal_quarter": 4, "values": { "revenue": 63325000000, "free_cash_flow": 12767000000 } } ], "meta": { "symbol": "CSCO", "currency": "USD", "period": "annual", "source": "SEC EDGAR", "api_version": "v1", "generated_at": "2026-10-16T02:00:00Z" } } ``` ## 3. Explore - [Companies](https://studyingstocks.com/developers/companies) lists what is covered; [Company profile](https://studyingstocks.com/developers/company-profile) shows a company's coverage. - [Valuation](https://studyingstocks.com/developers/valuation) returns our fair value per share and the assumptions behind it. - Watch the [rate limit headers](https://studyingstocks.com/developers/rate-limits) while you build, and handle the [errors](https://studyingstocks.com/developers/errors). --- # Authentication > API version: v1 Every endpoint except [Status](https://studyingstocks.com/developers/status) needs an API key, sent in the `X-Api-Key` header: ```bash curl "https://studyingstocks.com/api/v1/companies/AAPL" -H "X-Api-Key: ss_live_..." ``` ## The key - A key looks like `ss_live_` followed by 40 random letters and digits. - **Header only.** There is no `?apikey=` query parameter, on purpose: keys in URLs end up in server logs, proxies and browser history. A key in the query string is ignored and the request is answered with `401`. - Keep the key secret and do not use it in code that runs in a browser or an app you distribute. ## Creating, regenerating and revoking Only active Premium subscribers can manage a key, on the [profile page](https://studyingstocks.com/profile#api-access): - **Create:** the full key is shown **once**. We store only a SHA-256 hash and the first characters (the prefix), so we cannot show it again or recover it. - **Regenerate:** creates a new key and revokes the old one at once. Do this if a key may have leaked. - **Revoke:** the key stops working at once. ## When the subscription ends A key works only while its owner's Premium subscription is active. When the subscription lapses, requests are answered with `403` and the code `subscription_inactive`. Because the check is cached, this can take up to 5 minutes to show. Renew the subscription and the same key works again. ## Errors | Status | Code | Meaning | |---|---|---| | 401 | `unauthenticated` | The header is missing, or the key is malformed, unknown or revoked | | 403 | `subscription_inactive` | The key is valid but its Premium subscription is not active | | 429 | `rate_limited` | Too many requests (also for repeated requests with a wrong key from one IP address) | See [errors](https://studyingstocks.com/developers/errors) for the format. --- # Rate limits > API version: v1 ## Limits | Limit | Value | |---|---| | Requests per minute, per key | 60 | | Requests per day, per key | 10,000 | | `GET /status` and `GET /openapi.json` (no key), per IP address | 60 per minute | The minute window starts at your first request in it. The day is the UTC calendar day and resets at 00:00 UTC. **Need more?** [Contact us for higher limits](mailto:contact@studyingstocks.com). ## Headers Every response from an endpoint that needs a key carries: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests allowed in the current window | | `X-RateLimit-Remaining` | Requests left in the current window | | `X-RateLimit-Reset` | Unix time (seconds) when the window resets | | `X-RateLimit-Day-Limit` | Requests allowed per day | | `X-RateLimit-Day-Remaining` | Requests left today | The first three describe the minute window, or the day when the day is the one that is used up. A request with a wrong key is answered `401` with `X-RateLimit-Auth-Limit`, `X-RateLimit-Auth-Remaining` and `X-RateLimit-Auth-Reset`: that is a separate limit on failed attempts per IP address, not your key's limit. A `403` carries the headers of your key, without counting the request. ## When you hit the limit The response is `429` with the code `rate_limited` and a `Retry-After` header: the number of seconds to wait. ```json { "error": { "code": "rate_limited", "message": "Rate limit reached. Retry after the number of seconds in the Retry-After header.", "docs": "https://studyingstocks.com/developers/errors#rate_limited" } } ``` Wait for `Retry-After` seconds, then retry. Do not retry in a tight loop. ## Caching Responses are cached for up to 1 hour and refreshed whenever a company's data is updated, so the same request is cheap. Company data changes at most a few times a day, so there is little to gain from polling more often than that. Requests served from the cache still count against your limits. --- # Errors > API version: v1 Errors are JSON, never an HTML page, with the same shape for every endpoint: ```json { "error": { "code": "not_found", "message": "No listed company with the symbol ZZZZ is covered. See GET /api/v1/companies for the covered companies.", "docs": "https://studyingstocks.com/developers/errors#not_found" } } ``` `code` is stable and meant for your code to branch on. `message` is for people and may change. `docs` links to the entry below. An `invalid_parameter` error can also carry a `details` object with a message per parameter. ## unauthenticated **HTTP 401.** The `X-Api-Key` header is missing, or the key is malformed, unknown or revoked. See [authentication](https://studyingstocks.com/developers/authentication). ## subscription_inactive **HTTP 403.** The key is valid, but the Premium subscription behind it is not active. Renew it on your profile page. ## not_found **HTTP 404.** The path does not exist, or the company is not covered: it is not listed, or we have no SEC EDGAR data for it yet. ## method_not_allowed **HTTP 405.** The API is read-only: use `GET`. ## invalid_parameter **HTTP 422.** A query parameter is invalid, for example an unknown line item, a date that is not `YYYY-MM-DD` or a `limit` above the maximum. The message names the parameter. A query parameter that the endpoint does not document is rejected too, instead of being ignored silently: `?apikey=...` or a misspelled `perpage` answers 422, the message lists the parameters the endpoint accepts, and `details` has one entry per unknown name. So a typo can never quietly return the wrong data. ## rate_limited **HTTP 429.** Too many requests. Wait for the number of seconds in the `Retry-After` header. See [rate limits](https://studyingstocks.com/developers/rate-limits). ## server_error **HTTP 500.** Something went wrong on our side. The response never contains internal details. Try again later and [tell us](mailto:contact@studyingstocks.com) if it persists. --- # Changelog > API version: v1 While v1 is in beta we may change it in place, and every change is listed here. After the beta, breaking changes will go to a new version (`v2`) and v1 will keep working for an announced period. Response objects are closed in the OpenAPI document: every field is described. New fields are announced here, and clients should tolerate added fields (ignore what they do not know) instead of failing on them. The `contract:` line of an entry is the SHA-256 fingerprint of the API description (the OpenAPI document) as it was after that change, so you can tell whether the API you integrated against has changed. ## 2026-10-16: unknown query parameters are rejected contract: 64cca979b4bf3195cdbdca7b3197ae33a35a176561c0164e225c3a6542c54f99 Every endpoint now answers `422 invalid_parameter` for a query parameter it does not document (see [errors](https://studyingstocks.com/developers/errors#invalid_parameter)). Before, unknown parameters were ignored. The OpenAPI document also describes every response object completely (`additionalProperties: false`), lists the always-present fields as `required`, and documents the 422 response of every endpoint. ## 2026-10-16: v1 beta contract: ce6c85c7a0e302ee7a49df902e7e01605008bacda1198729ab1b60f675e49c7e The first release of the API. - Endpoints: `GET /companies`, `GET /companies/{symbol}`, `GET /companies/{symbol}/financials`, `GET /companies/{symbol}/financials/revisions`, `GET /companies/{symbol}/valuation` and `GET /status`. - Line items: `revenue`, `net_income`, `eps_basic`, `dividends_per_share`, `free_cash_flow`, `shares_basic`, `shares_diluted`, `total_debt`, `cash_and_equivalents`, `roic` and `debt_to_fcf`. - Periods: `ttm` and `annual`. Discrete quarters (`period=quarter`) and the items `eps_diluted`, `operating_cash_flow` and `capital_expenditure` are planned and not available yet. - Authentication with the `X-Api-Key` header; limits of 60 requests per minute and 10,000 per day per key. - OpenAPI 3.1 document, interactive reference, `llms.txt` and `skill.md`. --- # Periods and fiscal calendars > API version: v1 ## TTM and annual - **`period=ttm`** (the default) returns one row per quarter end. Flow items (revenue, net income, free cash flow, per-share earnings and dividends) are the **trailing twelve months** ending on that date. Balance sheet items (`total_debt`, `cash_and_equivalents`) are the value on that date. Share counts are the weighted average of the quarter. - **`period=annual`** returns only the rows at the end of a fiscal year, so each value is that fiscal year's. Discrete quarters (`period=quarter`) are not available yet. ## Labels Periods are labelled with the company's **own fiscal calendar**, taken from its SEC filings: `2026Q4` is the fourth fiscal quarter of fiscal year 2026, which for Cisco ends in July 2026. Annual rows are labelled `FY2026`. Each row also has `fiscal_year` and `fiscal_quarter` as numbers and the real `period_end` date; use `period_end` to compare companies on a calendar. The profile endpoint reports `fiscal_year_end_month`. Fifty-two and 53-week years can end in the first days of the next month; the fiscal year is still the one the company reports. ## Filtering and order Rows are newest first. `from` and `to` filter by `period_end` (`YYYY-MM-DD`). `limit` caps the number of rows (default 20, maximum 40; ten years of quarters is 40 rows). ## Missing values If a company did not report an item for a period, the item is left out of `values`. A period with none of the requested items is left out of the response. --- # Line items and definitions > API version: v1 Values are in units of the reporting currency (`USD` for all companies today), not thousands or millions. Per-share values are decimals. Ratios are fractions: `0.18` is 18%. | Item | Unit | Definition | Origin | |---|---|---|---| | `revenue` | currency | Revenue | SEC filings | | `net_income` | currency | Net income attributable to common shareholders | SEC filings | | `eps_basic` | currency per share | Basic earnings per share | SEC filings | | `dividends_per_share` | currency per share | Dividends declared per share | SEC filings | | `free_cash_flow` | currency | Operating cash flow minus capital expenditure | Calculated by us | | `shares_basic` | shares | Weighted average basic shares outstanding | SEC filings | | `shares_diluted` | shares | Weighted average diluted shares outstanding | SEC filings | | `total_debt` | currency | Long-term debt including current maturities, plus short-term borrowings | SEC filings | | `cash_and_equivalents` | currency | Cash, cash equivalents and short-term investments | SEC filings | | `roic` | fraction | After-tax operating income divided by invested capital (debt plus equity minus cash) | Calculated by us | | `debt_to_fcf` | years | `total_debt` divided by `free_cash_flow`; left out when free cash flow is not positive | Calculated by us | ## Where the numbers come from Reported items are read from the company's 10-K and 10-Q filings (XBRL data published by the SEC). Companies tag the same thing in different ways, so we map several tags to each item and use the one the company reports. Share counts are adjusted for stock splits. Calculated items are derived from the reported ones. Companies that do not report under US GAAP (many foreign filers) are not covered yet. ## Not available yet `eps_diluted`, `operating_cash_flow` and `capital_expenditure` are planned. Asking for them returns `invalid_parameter` today. --- # Restatements > API version: v1 Companies restate earlier results: a later filing or an amendment (10-K/A, 10-Q/A) can change a number that was reported before. We keep every value we have recorded for a period and line item, as a numbered version, and the newest version is the one the [financials](https://studyingstocks.com/developers/financials) endpoint returns. The [revisions](https://studyingstocks.com/developers/revisions) endpoint lists the periods and items that changed, newest period first. For each one it gives the current value and every version: ```json { "period": "2026Q3", "period_end": "2026-04-25", "item": "revenue", "current_value": 61500000000, "versions": [ { "version": 1, "value": 61200000000, "current": false, "recorded_at": "2026-05-20T02:00:00Z" }, { "version": 2, "value": 61500000000, "current": true, "recorded_at": "2026-08-14T02:00:00Z" } ] } ``` ## What `recorded_at` means `recorded_at` is when **our update saw** the new value, not the date of the filing. Our data is refreshed from SEC EDGAR within hours of a new filing, and every few days for every company. The `financials` response and the profile give you the link to the company's filings on sec.gov to find the filing that changed the value. ## Using it - To backtest, use the version with the `recorded_at` before your decision date. - Small revisions are normal; split adjustments change per-share values and share counts of earlier periods together. - A company or item without revisions returns an empty `data` array. --- # Valuation methodology > API version: v1 The [valuation](https://studyingstocks.com/developers/valuation) endpoint returns our discounted cash flow (DCF) model. It uses **only** the company's own SEC filings: no analyst forecasts and no market data. The response reports `methodology_version`, which changes whenever the method does. ## Steps (version 1) 1. **History.** The free cash flow and revenue of the last fiscal years (up to six). 2. **Base.** The latest fiscal year's revenue times the **median free cash flow margin** of the last five years, which smooths one-off years. 3. **Growth.** The revenue CAGR of the last five years, limited to between -5% and +15% a year. Years 1 to 5 grow at this rate; in years 6 to 10 the rate fades in equal steps to the perpetual growth rate of 2.5%. 4. **Discounting.** Each projected year is discounted at the required return of **8.5%**. 5. **Terminal value.** The year-10 cash flow grows at 2.5% a year forever (Gordon growth), is divided by required return minus growth, and is discounted back like year 10. 6. **Fair value.** Present value of the 10 years plus the terminal value, minus net debt (`total_debt` minus `cash_and_equivalents`, each from the newest period that reports it; a missing value is never treated as zero), divided by the latest diluted share count (basic when diluted is not reported). The `assumptions` object reports the required return, perpetual growth and the first-stage growth, `free_cash_flow_projection` has each projected year with its discount factor and present value, and `inputs` has the balance sheet date and values used. ## When there is no valuation A free cash flow model does not fit every company. The response is still `200`, with `meaningful: false` and a `reason`: | Code | Why | |---|---| | `financial_company` | Banks, insurers, brokers and real estate companies (SIC 6000 to 6799): free cash flow says little about their value | | `no_industry_code` | We do not know the SEC industry code, so we cannot tell whether the model fits | | `insufficient_history` | Fewer than three fiscal years of data, or free cash flow that is not positive enough to project | | `no_share_count` | The latest share count is not available | | `missing_balance_sheet` | No period reports total debt, or none reports cash | | `not_calculable` | The result was not a finite number | ## Limits of the model It extrapolates the past. It does not know about acquisitions, new products, or changing margins, and a single discount rate for every company is a simplification. Treat the result as one input, not as advice. The data is provided as is and is not investment advice. --- # Using the API from AI agents > API version: v1 Most callers of this API are agents, so the docs come in forms an agent can read directly. All of them are generated from the same source as these pages. | What | URL | |---|---| | Index of the docs for LLMs | [`/llms.txt`](https://studyingstocks.com/llms.txt) | | All docs in one file | [`/llms-full.txt`](https://studyingstocks.com/llms-full.txt) | | Any docs page as Markdown | the page URL plus `.md`, for example `https://studyingstocks.com/developers/authentication.md` | | Agent guide: which endpoint for what | [`/developers/skill.md`](https://studyingstocks.com/developers/skill.md) | | OpenAPI 3.1 document | [`/api/v1/openapi.json`](https://studyingstocks.com/api/v1/openapi.json) | ## Tips for agents - Give the agent the skill file and the key (as a secret, in an environment variable or the tool's credential store, never in the prompt). - Ask for only what you need: `items=revenue,free_cash_flow&limit=5` keeps responses small. - Branch on `error.code`, not on the message. On `rate_limited`, wait `Retry-After` seconds. - Check `meta.generated_at` and the company's `data_updated_at` before saying how current a number is. - Quote the `filings_url` or the SEC link when you tell a user where a number comes from. ## MCP A Model Context Protocol server that exposes these endpoints as tools is planned. It is not available yet. --- # Agent skill > API version: v1 Use this file to call the Studying Stocks API correctly. ## What the API is Read-only JSON API with standardized fundamentals of listed US companies from SEC EDGAR filings, and a free cash flow valuation. Base URL: `https://studyingstocks.com/api/v1`. Values are in the reporting currency (USD), in units (not thousands). All data comes from SEC filings or is calculated from them. ## Authenticate Send `X-Api-Key: ` on every request except `GET /status`. The user supplies the key (`ss_live_` + 40 characters). Never put it in a URL, a log or a message to the user. Limits: 60 requests per minute and 10,000 per day. ## Which endpoint for what | The user wants | Call | |---|---| | To know whether a company is covered, or to find a ticker | `GET /companies?search=` | | A company's industry, fiscal year end, or how much history we have | `GET /companies/{symbol}` | | Revenue, profit, cash flow, debt, shares, ROIC... over time | `GET /companies/{symbol}/financials?items=...` | | Whether a past number was restated | `GET /companies/{symbol}/financials/revisions` | | A fair value per share, or the free cash flow projection | `GET /companies/{symbol}/valuation` | | Whether the API is up and how fresh the data is | `GET /status` | ## Periods - `period=ttm` (default): trailing twelve months at each quarter end. `period=annual`: fiscal year ends only. Rows are newest first. - Labels follow the company's own fiscal calendar (`2026Q4`, `FY2026`). Use `period_end` to compare companies on dates. - `limit` defaults to 20 and is at most 40. Use `from` and `to` (`YYYY-MM-DD`, on `period_end`). - Items: `revenue`, `net_income`, `eps_basic`, `dividends_per_share`, `free_cash_flow`, `shares_basic`, `shares_diluted`, `total_debt`, `cash_and_equivalents`, `roic` (a fraction), `debt_to_fcf` (years). An item without a value is missing from `values`: do not treat that as zero. - Not available yet: `period=quarter`, `eps_diluted`, `operating_cash_flow`, `capital_expenditure`. ## Valuation Check `data.meaningful` first. When `false`, tell the user `data.reason.message` and do not invent a value. When `true`, `fair_value_per_share` comes from a 10-year projection at an 8.5% required return and 2.5% perpetual growth; report the assumptions with the number. It is not investment advice. ## Errors Every error is `{"error": {"code", "message", "docs"}}`. Branch on `code`: - `unauthenticated` (401): the key is missing or wrong. Ask the user for a valid key. - `subscription_inactive` (403): the Premium subscription behind the key is not active. - `not_found` (404): not covered, or no SEC data yet. Do not guess another symbol. - `invalid_parameter` (422): fix the parameter named in the message. - `rate_limited` (429): wait `Retry-After` seconds, then retry. - `server_error` (500): retry later. ## More - Docs index: [llms.txt](https://studyingstocks.com/llms.txt). Full docs: [llms-full.txt](https://studyingstocks.com/llms-full.txt). Any page as Markdown: add `.md` to its URL. - OpenAPI 3.1: `https://studyingstocks.com/api/v1/openapi.json`. --- # Interactive reference > API version: v1 The interactive reference renders the OpenAPI 3.1 document of the API. It lists every endpoint, parameter and response schema, and lets you send requests with your key. - Open it in the browser: https://studyingstocks.com/developers/reference - OpenAPI document (JSON): https://studyingstocks.com/api/v1/openapi.json The document is the source of the endpoint pages in these docs, so the two always agree. --- # Companies > API version: v1 Companies covered by the API: listed companies with SEC EDGAR data. Search by ticker prefix or company name, filter by exchange, page through the results. `GET /api/v1/companies` Requires an API key in the `X-Api-Key` header. ## Parameters | Name | In | Type | Required | Description | |---|---|---|---|---| | `search` | query | string | no | Ticker prefix or part of the company name. | | `exchange` | query | string | no | Exchange, for example `NASDAQ` or `NYSE`. | | `page` | query | integer | no | Page number, starting at 1. | | `per_page` | query | integer | no | Companies per page. Default 50, maximum 100. | ## Request **curl** ```bash curl "https://studyingstocks.com/api/v1/companies?search=cisco" \ -H "X-Api-Key: $STUDYING_STOCKS_API_KEY" ``` **Python** ```python import os import requests response = requests.get("https://studyingstocks.com/api/v1/companies", params={"search": "cisco"}, headers={"X-Api-Key": os.environ["STUDYING_STOCKS_API_KEY"]}) response.raise_for_status() print(response.json()) ``` **JavaScript** ```javascript const response = await fetch("https://studyingstocks.com/api/v1/companies?search=cisco", { headers: { "X-Api-Key": process.env.STUDYING_STOCKS_API_KEY }, }); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ## Response A page of companies. ```json { "data": [ { "symbol": "CSCO", "name": "Cisco Systems, Inc.", "exchange": "Nasdaq", "cik": "0000858877", "sic": "3576", "sic_description": "Industrial and Commercial Machinery and Computer Equipment", "currency": "USD", "first_period_end": "2017-07-29", "last_period_end": "2026-07-25", "data_updated_at": "2026-10-15T02:00:00Z" } ], "meta": { "page": 1, "per_page": 50, "total": 1, "last_page": 1, "source": "SEC EDGAR", "api_version": "v1", "generated_at": "2026-10-16T02:00:00Z" } } ``` ### Response fields | Field | Type | Description | |---|---|---| | `data[].symbol` | string | Ticker symbol. | | `data[].name` | string or null | Company name. | | `data[].exchange` | string or null | Listing exchange. | | `data[].cik` | string or null | SEC Central Index Key, ten digits. | | `data[].sic` | string or null | SEC Standard Industrial Classification code. | | `data[].sic_description` | string or null | Name of the SIC major group (the first two digits of the code). | | `data[].currency` | string | Reporting currency of every monetary value. | | `data[].first_period_end` | string or null | End date of the oldest period we have. | | `data[].last_period_end` | string or null | End date of the latest period we have. | | `data[].data_updated_at` | string or null | When we last synchronized this company with SEC EDGAR. | | `meta.source` | string | Where the data comes from: always SEC EDGAR (calculated items are derived from it). | | `meta.api_version` | string | | | `meta.generated_at` | string | When this response was generated (responses are cached for a few hours). | | `meta.page` | integer | | | `meta.per_page` | integer | | | `meta.total` | integer | | | `meta.last_page` | integer | | ## Errors | Status | Code | When | |---|---|---| | 401 | [`unauthenticated`](https://studyingstocks.com/developers/errors#unauthenticated) | Missing or invalid API key. | | 403 | [`subscription_inactive`](https://studyingstocks.com/developers/errors#subscription_inactive) | The Premium subscription behind the key is not active. | | 422 | [`invalid_parameter`](https://studyingstocks.com/developers/errors#invalid_parameter) | A query parameter is invalid. | | 429 | [`rate_limited`](https://studyingstocks.com/developers/errors#rate_limited) | Rate limit reached. | | 500 | [`server_error`](https://studyingstocks.com/developers/errors#server_error) | Something went wrong on our side. | All errors have the [same shape](https://studyingstocks.com/developers/errors). --- # Company profile > API version: v1 One company's profile and coverage: identifiers, fiscal year end, the first and last period we have, which line items are available, and a link to its SEC filings. `GET /api/v1/companies/{symbol}` Requires an API key in the `X-Api-Key` header. ## Parameters | Name | In | Type | Required | Description | |---|---|---|---|---| | `symbol` | path | string | yes | Ticker symbol of a listed company, for example `CSCO`. Case-insensitive. | ## Request **curl** ```bash curl "https://studyingstocks.com/api/v1/companies/CSCO" \ -H "X-Api-Key: $STUDYING_STOCKS_API_KEY" ``` **Python** ```python import os import requests response = requests.get("https://studyingstocks.com/api/v1/companies/CSCO", headers={"X-Api-Key": os.environ["STUDYING_STOCKS_API_KEY"]}) response.raise_for_status() print(response.json()) ``` **JavaScript** ```javascript const response = await fetch("https://studyingstocks.com/api/v1/companies/CSCO", { headers: { "X-Api-Key": process.env.STUDYING_STOCKS_API_KEY }, }); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ## Response The company profile. ```json { "data": { "symbol": "CSCO", "name": "Cisco Systems, Inc.", "exchange": "Nasdaq", "cik": "0000858877", "sic": "3576", "sic_description": "Industrial and Commercial Machinery and Computer Equipment", "currency": "USD", "first_period_end": "2017-07-29", "last_period_end": "2026-07-25", "data_updated_at": "2026-10-15T02:00:00Z", "fiscal_year_end_month": 7, "coverage": { "first_period": { "period": "2017Q4", "period_end": "2017-07-29" }, "last_period": { "period": "2026Q4", "period_end": "2026-07-25" }, "ttm_periods": 37, "annual_periods": 9, "line_items": [ "revenue", "net_income", "eps_basic", "dividends_per_share", "free_cash_flow", "shares_basic", "shares_diluted", "total_debt", "cash_and_equivalents", "roic", "debt_to_fcf" ] }, "links": { "sec_filings": "https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=0000858877&type=10-&dateb=&owner=include&count=40", "financials": "https://studyingstocks.com/api/v1/companies/CSCO/financials", "valuation": "https://studyingstocks.com/api/v1/companies/CSCO/valuation" } }, "meta": { "symbol": "CSCO", "source": "SEC EDGAR", "api_version": "v1", "generated_at": "2026-10-16T02:00:00Z" } } ``` ### Response fields | Field | Type | Description | |---|---|---| | `data.symbol` | string | Ticker symbol. | | `data.name` | string or null | Company name. | | `data.exchange` | string or null | Listing exchange. | | `data.cik` | string or null | SEC Central Index Key, ten digits. | | `data.sic` | string or null | SEC Standard Industrial Classification code. | | `data.sic_description` | string or null | Name of the SIC major group (the first two digits of the code). | | `data.currency` | string | Reporting currency of every monetary value. | | `data.first_period_end` | string or null | End date of the oldest period we have. | | `data.last_period_end` | string or null | End date of the latest period we have. | | `data.data_updated_at` | string or null | When we last synchronized this company with SEC EDGAR. | | `data.fiscal_year_end_month` | integer or null | Month (1-12) the fiscal year ends in. | | `data.coverage.first_period` | object or null | | | `data.coverage.last_period` | object or null | | | `data.coverage.ttm_periods` | integer | Number of quarter-end periods. | | `data.coverage.annual_periods` | integer | Number of fiscal years. | | `data.coverage.line_items` | array of string | Line items with at least one value. | | `data.links.sec_filings` | string or null | SEC's list of the company's periodic filings. | | `data.links.financials` | string | | | `data.links.valuation` | string | | | `meta.source` | string | Where the data comes from: always SEC EDGAR (calculated items are derived from it). | | `meta.api_version` | string | | | `meta.generated_at` | string | When this response was generated (responses are cached for a few hours). | | `meta.symbol` | string | | ## Errors | Status | Code | When | |---|---|---| | 401 | [`unauthenticated`](https://studyingstocks.com/developers/errors#unauthenticated) | Missing or invalid API key. | | 403 | [`subscription_inactive`](https://studyingstocks.com/developers/errors#subscription_inactive) | The Premium subscription behind the key is not active. | | 404 | [`not_found`](https://studyingstocks.com/developers/errors#not_found) | The company is not covered. | | 422 | [`invalid_parameter`](https://studyingstocks.com/developers/errors#invalid_parameter) | An unknown query parameter was sent. | | 429 | [`rate_limited`](https://studyingstocks.com/developers/errors#rate_limited) | Rate limit reached. | | 500 | [`server_error`](https://studyingstocks.com/developers/errors#server_error) | Something went wrong on our side. | All errors have the [same shape](https://studyingstocks.com/developers/errors). --- # Financials > API version: v1 Standardized line items per period, newest first. Every value is the trailing twelve months (TTM) ending at the period end; balance sheet items (`total_debt`, `cash_and_equivalents`) are the value at the period end. `period=annual` keeps only the fiscal year ends. A period is left out when none of the requested items has a value for it, and an item without a value is omitted from `values`. `GET /api/v1/companies/{symbol}/financials` Requires an API key in the `X-Api-Key` header. ## Parameters | Name | In | Type | Required | Description | |---|---|---|---|---| | `symbol` | path | string | yes | Ticker symbol of a listed company, for example `CSCO`. Case-insensitive. | | `period` | query | string (ttm \| annual) | no | `ttm` (default): the trailing twelve months at each quarter end. `annual`: the fiscal year ends only. Discrete quarters are not available yet. | | `items` | query | string | no | Comma-separated line items to return. Default: all. One of: `revenue`, `net_income`, `eps_basic`, `dividends_per_share`, `free_cash_flow`, `shares_basic`, `shares_diluted`, `total_debt`, `cash_and_equivalents`, `roic`, `debt_to_fcf`. | | `from` | query | string | no | Only periods with a period end on or after this date (`YYYY-MM-DD`). | | `to` | query | string | no | Only periods with a period end on or before this date (`YYYY-MM-DD`). | | `limit` | query | integer | no | Number of periods. Default 20, maximum 40. | ## Request **curl** ```bash curl "https://studyingstocks.com/api/v1/companies/CSCO/financials?period=annual&items=revenue,free_cash_flow&limit=5" \ -H "X-Api-Key: $STUDYING_STOCKS_API_KEY" ``` **Python** ```python import os import requests response = requests.get("https://studyingstocks.com/api/v1/companies/CSCO/financials", params={"period": "annual", "items": "revenue,free_cash_flow", "limit": "5"}, headers={"X-Api-Key": os.environ["STUDYING_STOCKS_API_KEY"]}) response.raise_for_status() print(response.json()) ``` **JavaScript** ```javascript const response = await fetch("https://studyingstocks.com/api/v1/companies/CSCO/financials?period=annual&items=revenue,free_cash_flow&limit=5", { headers: { "X-Api-Key": process.env.STUDYING_STOCKS_API_KEY }, }); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ## Response Periods with their values. ```json { "data": [ { "period": "2026Q4", "period_end": "2026-07-25", "fiscal_year": 2026, "fiscal_quarter": 4, "values": { "revenue": 63325000000, "free_cash_flow": 12767000000 } } ], "meta": { "symbol": "CSCO", "currency": "USD", "period": "ttm", "items": [ "revenue", "free_cash_flow" ], "count": 1, "filings_url": "https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=0000858877&type=10-&dateb=&owner=include&count=40", "source": "SEC EDGAR", "api_version": "v1", "generated_at": "2026-10-16T02:00:00Z" } } ``` ### Response fields | Field | Type | Description | |---|---|---| | `data[].period` | string | Fiscal period label: `2026Q4` for TTM periods, `FY2026` for annual ones. | | `data[].period_end` | string | | | `data[].fiscal_year` | integer | | | `data[].fiscal_quarter` | integer | | | `data[].values` | object | Line items by name; items without a value are omitted. | | `data[].values.revenue` | number | Revenue. | | `data[].values.net_income` | number | Net income attributable to common shareholders. | | `data[].values.eps_basic` | number | Earnings per share, basic. Per-share values are decimals. | | `data[].values.dividends_per_share` | number | Dividends declared per share. | | `data[].values.free_cash_flow` | number | Calculated: operating cash flow minus capital expenditure. | | `data[].values.shares_basic` | number | Weighted average basic shares outstanding. | | `data[].values.shares_diluted` | number | Weighted average diluted shares outstanding. | | `data[].values.total_debt` | number | Total debt at the period end (long-term debt, current maturities and short-term borrowings). | | `data[].values.cash_and_equivalents` | number | Cash, cash equivalents and short-term investments at the period end. | | `data[].values.roic` | number | Calculated: return on invested capital as a fraction (0.18 = 18%). | | `data[].values.debt_to_fcf` | number | Calculated: total debt divided by free cash flow, in years. Omitted when free cash flow is not positive. | | `meta.source` | string | Where the data comes from: always SEC EDGAR (calculated items are derived from it). | | `meta.api_version` | string | | | `meta.generated_at` | string | When this response was generated (responses are cached for a few hours). | | `meta.symbol` | string | | | `meta.currency` | string | | | `meta.period` | string | | | `meta.items` | array of string | | | `meta.count` | integer | | | `meta.filings_url` | string or null | SEC's list of the company's periodic filings, where each value can be checked. | ## Errors | Status | Code | When | |---|---|---| | 401 | [`unauthenticated`](https://studyingstocks.com/developers/errors#unauthenticated) | Missing or invalid API key. | | 403 | [`subscription_inactive`](https://studyingstocks.com/developers/errors#subscription_inactive) | The Premium subscription behind the key is not active. | | 404 | [`not_found`](https://studyingstocks.com/developers/errors#not_found) | The company is not covered. | | 422 | [`invalid_parameter`](https://studyingstocks.com/developers/errors#invalid_parameter) | A query parameter is invalid. | | 429 | [`rate_limited`](https://studyingstocks.com/developers/errors#rate_limited) | Rate limit reached. | | 500 | [`server_error`](https://studyingstocks.com/developers/errors#server_error) | Something went wrong on our side. | All errors have the [same shape](https://studyingstocks.com/developers/errors). --- # Revisions > API version: v1 Restatement history: every period and line item whose value changed after we first recorded it, with each earlier value and when we recorded it. `recorded_at` is when our sync saw the value, not the filing date. The filing that restated a value can be found through the company's SEC filings link. `GET /api/v1/companies/{symbol}/financials/revisions` Requires an API key in the `X-Api-Key` header. ## Parameters | Name | In | Type | Required | Description | |---|---|---|---|---| | `symbol` | path | string | yes | Ticker symbol of a listed company, for example `CSCO`. Case-insensitive. | | `items` | query | string | no | Comma-separated line items to check. Default: all. One of: `revenue`, `net_income`, `eps_basic`, `dividends_per_share`, `free_cash_flow`, `shares_basic`, `shares_diluted`, `total_debt`, `cash_and_equivalents`, `roic`, `debt_to_fcf`. | | `from` | query | string | no | Only revisions with a period end on or after this date (`YYYY-MM-DD`). | | `to` | query | string | no | Only revisions with a period end on or before this date (`YYYY-MM-DD`). | | `limit` | query | integer | no | Number of revised period and item pairs. Default 50, maximum 200. | ## Request **curl** ```bash curl "https://studyingstocks.com/api/v1/companies/CSCO/financials/revisions?items=revenue" \ -H "X-Api-Key: $STUDYING_STOCKS_API_KEY" ``` **Python** ```python import os import requests response = requests.get("https://studyingstocks.com/api/v1/companies/CSCO/financials/revisions", params={"items": "revenue"}, headers={"X-Api-Key": os.environ["STUDYING_STOCKS_API_KEY"]}) response.raise_for_status() print(response.json()) ``` **JavaScript** ```javascript const response = await fetch("https://studyingstocks.com/api/v1/companies/CSCO/financials/revisions?items=revenue", { headers: { "X-Api-Key": process.env.STUDYING_STOCKS_API_KEY }, }); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ## Response Revised values, newest period first. Empty when nothing was revised. ```json { "data": [ { "period": "2026Q3", "period_end": "2026-04-25", "item": "revenue", "current_value": 61500000000, "versions": [ { "version": 1, "value": 61200000000, "current": false, "recorded_at": "2026-05-20T02:00:00Z" }, { "version": 2, "value": 61500000000, "current": true, "recorded_at": "2026-08-14T02:00:00Z" } ] } ], "meta": { "symbol": "CSCO", "currency": "USD", "items": [ "revenue" ], "count": 1, "source": "SEC EDGAR", "api_version": "v1", "generated_at": "2026-10-16T02:00:00Z" } } ``` ### Response fields | Field | Type | Description | |---|---|---| | `data[].period` | string | | | `data[].period_end` | string | | | `data[].item` | string | | | `data[].current_value` | number or null | | | `data[].versions[].version` | integer | | | `data[].versions[].value` | number | | | `data[].versions[].current` | boolean | | | `data[].versions[].recorded_at` | string or null | When our sync recorded this value. | | `meta.source` | string | Where the data comes from: always SEC EDGAR (calculated items are derived from it). | | `meta.api_version` | string | | | `meta.generated_at` | string | When this response was generated (responses are cached for a few hours). | | `meta.symbol` | string | | | `meta.currency` | string | | | `meta.items` | array of string | | | `meta.count` | integer | | ## Errors | Status | Code | When | |---|---|---| | 401 | [`unauthenticated`](https://studyingstocks.com/developers/errors#unauthenticated) | Missing or invalid API key. | | 403 | [`subscription_inactive`](https://studyingstocks.com/developers/errors#subscription_inactive) | The Premium subscription behind the key is not active. | | 404 | [`not_found`](https://studyingstocks.com/developers/errors#not_found) | The company is not covered. | | 422 | [`invalid_parameter`](https://studyingstocks.com/developers/errors#invalid_parameter) | A query parameter is invalid. | | 429 | [`rate_limited`](https://studyingstocks.com/developers/errors#rate_limited) | Rate limit reached. | | 500 | [`server_error`](https://studyingstocks.com/developers/errors#server_error) | Something went wrong on our side. | All errors have the [same shape](https://studyingstocks.com/developers/errors). --- # Valuation > API version: v1 Our discounted cash flow (DCF) valuation, built only from the company's SEC filings: a 10-year free cash flow projection, the assumptions, and the fair value per share. When a free cash flow model does not fit the company (banks, insurers and real estate companies, or too little history) the response has `meaningful: false` and a `reason`. See the valuation methodology guide. `GET /api/v1/companies/{symbol}/valuation` Requires an API key in the `X-Api-Key` header. ## Parameters | Name | In | Type | Required | Description | |---|---|---|---|---| | `symbol` | path | string | yes | Ticker symbol of a listed company, for example `CSCO`. Case-insensitive. | ## Request **curl** ```bash curl "https://studyingstocks.com/api/v1/companies/CSCO/valuation" \ -H "X-Api-Key: $STUDYING_STOCKS_API_KEY" ``` **Python** ```python import os import requests response = requests.get("https://studyingstocks.com/api/v1/companies/CSCO/valuation", headers={"X-Api-Key": os.environ["STUDYING_STOCKS_API_KEY"]}) response.raise_for_status() print(response.json()) ``` **JavaScript** ```javascript const response = await fetch("https://studyingstocks.com/api/v1/companies/CSCO/valuation", { headers: { "X-Api-Key": process.env.STUDYING_STOCKS_API_KEY }, }); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ## Response The valuation, or the reason there is none. ```json { "data": { "meaningful": true, "fair_value_per_share": 61.42, "fair_equity_value": 245000000000, "enterprise_value": 249000000000, "net_debt": 4000000000, "currency": "USD", "assumptions": { "required_return": 0.085, "perpetual_growth": 0.025, "projection_years": 10, "stage_one_years": 5, "stage_one_growth": 0.04 }, "inputs": { "as_of": "2026-07-25", "balance_sheet_as_of": "2026-07-25", "total_debt": 28000000000, "cash_and_equivalents": 24000000000, "shares": 4000000000 }, "free_cash_flow_history": [ { "fiscal_year": 2025, "free_cash_flow": 11500000000 }, { "fiscal_year": 2026, "free_cash_flow": 12767000000 } ], "free_cash_flow_projection": [ { "fiscal_year": 2027, "free_cash_flow": 13300000000, "growth_rate": 0.04, "discount_factor": 1.085, "present_value": 12258064516.13 } ], "terminal_value": { "value": 330000000000, "present_value": 145000000000 }, "reason": null, "methodology_version": "1" }, "meta": { "symbol": "CSCO", "currency": "USD", "source": "SEC EDGAR", "api_version": "v1", "generated_at": "2026-10-16T02:00:00Z" } } ``` ### Response fields | Field | Type | Description | |---|---|---| | `data.meaningful` | boolean | `false` when a free cash flow model does not fit this company; see `reason`. | | `data.reason` | object or null | | | `data.methodology_version` | string | | | `data.fair_value_per_share` | number | Fair value per share, in the reporting currency. | | `data.fair_equity_value` | number | | | `data.enterprise_value` | number | Present value of the projected free cash flows and the terminal value. | | `data.net_debt` | number | | | `data.currency` | string | | | `data.assumptions.required_return` | number | Discount rate as a fraction. | | `data.assumptions.perpetual_growth` | number | Growth after the projection, as a fraction. | | `data.assumptions.projection_years` | integer | | | `data.assumptions.stage_one_years` | integer | | | `data.assumptions.stage_one_growth` | number | Yearly growth in the first stage, as a fraction. | | `data.inputs.as_of` | string | Period end of the latest period, where the share count is taken from. | | `data.inputs.balance_sheet_as_of` | string | Oldest period end that debt and cash are taken from: the newest period that reports each. | | `data.inputs.total_debt` | number | | | `data.inputs.cash_and_equivalents` | number | | | `data.inputs.shares` | number | | | `data.free_cash_flow_history[].fiscal_year` | integer | | | `data.free_cash_flow_history[].free_cash_flow` | number | | | `data.free_cash_flow_projection[].fiscal_year` | integer | | | `data.free_cash_flow_projection[].free_cash_flow` | number | | | `data.free_cash_flow_projection[].growth_rate` | number | | | `data.free_cash_flow_projection[].discount_factor` | number or null | | | `data.free_cash_flow_projection[].present_value` | number or null | | | `data.terminal_value` | object or null | | | `meta.source` | string | Where the data comes from: always SEC EDGAR (calculated items are derived from it). | | `meta.api_version` | string | | | `meta.generated_at` | string | When this response was generated (responses are cached for a few hours). | | `meta.symbol` | string | | | `meta.currency` | string | | ## Errors | Status | Code | When | |---|---|---| | 401 | [`unauthenticated`](https://studyingstocks.com/developers/errors#unauthenticated) | Missing or invalid API key. | | 403 | [`subscription_inactive`](https://studyingstocks.com/developers/errors#subscription_inactive) | The Premium subscription behind the key is not active. | | 404 | [`not_found`](https://studyingstocks.com/developers/errors#not_found) | The company is not covered. | | 422 | [`invalid_parameter`](https://studyingstocks.com/developers/errors#invalid_parameter) | An unknown query parameter was sent. | | 429 | [`rate_limited`](https://studyingstocks.com/developers/errors#rate_limited) | Rate limit reached. | | 500 | [`server_error`](https://studyingstocks.com/developers/errors#server_error) | Something went wrong on our side. | All errors have the [same shape](https://studyingstocks.com/developers/errors). --- # Status > API version: v1 API version, data freshness and the number of covered companies. Needs no API key; limited to 60 requests per minute per IP address. `GET /api/v1/status` Needs no API key. ## Request **curl** ```bash curl "https://studyingstocks.com/api/v1/status" ``` **Python** ```python import os import requests response = requests.get("https://studyingstocks.com/api/v1/status") response.raise_for_status() print(response.json()) ``` **JavaScript** ```javascript const response = await fetch("https://studyingstocks.com/api/v1/status"); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ## Response The API is up. ```json { "data": { "status": "ok", "api_version": "v1", "companies_covered": 4210, "data_updated_at": "2026-10-16T02:00:00Z" }, "meta": { "source": "SEC EDGAR", "api_version": "v1", "generated_at": "2026-10-16T02:00:00Z" } } ``` ### Response fields | Field | Type | Description | |---|---|---| | `data.status` | string | | | `data.api_version` | string | | | `data.companies_covered` | integer | | | `data.data_updated_at` | string or null | When the most recent company was synchronized with SEC EDGAR. | | `meta.source` | string | Where the data comes from: always SEC EDGAR (calculated items are derived from it). | | `meta.api_version` | string | | | `meta.generated_at` | string | When this response was generated (responses are cached for a few hours). | ## Errors | Status | Code | When | |---|---|---| | 422 | [`invalid_parameter`](https://studyingstocks.com/developers/errors#invalid_parameter) | An unknown query parameter was sent. | | 429 | [`rate_limited`](https://studyingstocks.com/developers/errors#rate_limited) | Rate limit reached. | | 500 | [`server_error`](https://studyingstocks.com/developers/errors#server_error) | Something went wrong on our side. | All errors have the [same shape](https://studyingstocks.com/developers/errors).