API Documentation

One endpoint, one promise: ask what was knowable about a company on a date, and that's exactly — and only — what you get back.

Machine-readable: OpenAPI 3.1 spec — /openapi.json · live check: /status

Authentication

Send your API key with every request, either way:

x-api-key: tvd_your_key_here
# or
Authorization: Bearer tvd_your_key_here

Evaluation keys are issued after card-backed checkout on the pricing page; keys are deactivated when access ends. One key per person — don't share it. Limits depend on the plan (evaluation: 100 requests/day, 10 companies total, rolling 3-year history; Pro: 5,000 requests + 2,500 distinct tickers/day) — see Limits.

GET/v1/fundamentals

Returns, for each concept, the most recent fiscal period whose source filing had been filed on or before as_of — the point-in-time view. Note the boundary is inclusive: a 10-K filed on as_of itself counts as knowable that day (filings often land after market close — use the prior day if you need strict before-the-open semantics).

Query parameters

tickerrequired
US ticker symbol, e.g. AAPL. 1–12 chars (A–Z, 0–9, dot, dash). Unknown tickers return 404.
Share classes and other aliases resolve to the SEC filer they belong to — GOOG → GOOGL, BRK-A → BRK-B, and roughly 1,500 more (preferred-share tickers like BAC-PK → BAC, renamed issuers, OTC duplicates of a listed filer). When that happens the response echoes the ticker you sent and adds resolved_ticker plus a resolved_note explaining that fundamentals are reported at the filer level. Both fields are absent when no alias was involved.
as_ofrequired
The knowledge date, YYYY-MM-DD. Must be a real calendar date.
period
annual (default) or quarterly. Annual reads 10-K/10-K/A history; quarterly reads Q1–Q3 from 10-Q filings and supported Q4 values from the 10-K.
concept
Filter to a single concept (case-insensitive). One of: Revenue, NetIncome, Assets, StockholdersEquity, OperatingCashFlow, EPSDiluted, DilutedShares, GrossProfit, OperatingIncome, PretaxIncome, IncomeTaxExpense, CapitalExpenditures, CashAndCashEquivalents, CurrentAssets, CurrentLiabilities, NetPPE. Omit for all 16.

Response fields

period
Top-level cadence receipt: annual or quarterly. Clients should require this to match the request.
concept
Which fundamental this row is.
fiscal_year
Derived from period_end: the calendar year the fiscal period ends in, except 52/53-week closes falling Jan 1–7, which belong to the prior year. We deliberately do not use the filing's own fiscal-year label — in XBRL that label is the year of the filing, so a prior-year comparative carries the newer year and collides with the real row. When a company changes its fiscal year end, one calendar year can legitimately contain two annual closes; period_end is the join key of record, not fiscal_year.
period_end
The date the fiscal period ended.
fiscal_period
FY for annual rows; Q1–Q4 for quarterly rows.
period_start
Quarterly flow-period start. null for annual rows and instant balance-sheet concepts.
filed
When this value first became public — the point-in-time stamp.
value
The first-reported value — what was actually knowable at filed. Use this for backtests.
latest_value
The most recent revision of the value. May post-date your as_of — not point-in-time safe. Provided for reference only.
ytd_value
Quarterly cumulative value used to derive a discrete quarter when applicable; otherwise null.
derivation
reported, ytd_diff, fy_minus_9m, or fy_balance. Q4 EPS and diluted shares are never derived.
source_form
Filing family behind the row: 10-Q, 10-K, or derived.
lag_days
Days from period_end to filed — the size of the lookahead gap this row closes.
data_through
Top-level. The newest filing date in the dataset. We serve a snapshot, so anything filed after this date is not reflected; if your as_of is later, the response also carries a coverage_warning.
restated
true if a later filing revised the value by more than 0.5% — a materiality threshold. latest_value may differ slightly from value without tripping the flag (sub-0.5% revisions are shown but not flagged). Revisions are tracked within the same XBRL tag across filings.
qa_status
"clean", or "FLAG:" plus semicolon-separated reasons: lag_out_of_range (outside 0–90 days for 10-Q-sourced rows or 0–120 days for 10-K-sourced rows), revenue_magnitude, ambiguous_tag (another XBRL element in the same filing reported materially more for this period, so which one is the true total is uncertain), implausible_value (a scale/unit-corrupted figure was suppressed — the value is null), tag_switch_discontinuity (the XBRL element behind this concept differs from the adjacent fiscal year — Broadcom alternates ProfitLoss and NetIncomeLoss, for instance. The value is usually correct; the flag marks a scope change to check before you difference year over year, not an error), and stale_for_as_of (the newest period we hold for this concept is stale for the requested cadence), plus quarterly derivation and continuity flags documented in the OpenAPI schema. We flag; we never quietly fix.

Example

curl "https://tradevodata.com/v1/fundamentals?ticker=AAPL&as_of=2024-06-30&concept=Revenue" \
  -H "x-api-key: tvd_your_key_here"
{
  "ticker": "AAPL",
  "as_of": "2024-06-30",
  "period": "annual",
  "data_through": "2026-07-24",
  "count": 1,
  "fundamentals": [{
    "concept": "Revenue",
    "fiscal_year": 2023,
    "fiscal_period": "FY",
    "period_end": "2023-09-30",
    "period_start": null,
    "filed": "2023-11-03",
    "lag_days": 34,
    "value": 383285000000,
    "latest_value": 383285000000,
    "ytd_value": null,
    "derivation": "reported",
    "source_form": "10-K",
    "restated": false,
    "qa_status": "clean"
  }]
}

Note the answer is FY2023, not FY2024 — on 2024-06-30 the FY2024 10-K had not been filed yet. That is the whole product.

curl "https://tradevodata.com/v1/fundamentals?ticker=AAPL&as_of=2025-02-15&period=quarterly" \
  -H "x-api-key: tvd_your_key_here"

Quarterly rows keep the same point-in-time rule and label reported versus derived values. Omit period to preserve the annual default.

The data_through value above is illustrative — it advances with every data load. Read the live one from any response, or check /status.

Python

The official client. as_of is a required argument on every query — there is no way to ask it for “Apple's revenue”, only for what was knowable on a given date, which is how lookahead bias stops being something you can write by accident. Zero dependencies; pandas is optional.

Quarterly client support ships in version 0.2.0. A fresh install gets the current release; upgrade first if this package is already installed in the environment.

pip install tradevodata
# Existing environment: pip install --upgrade tradevodata
import tradevodata as tv

df = tv.sample()                    # 5-company proof pack — no API key needed

client = tv.Client(api_key="tvd_...")           # or set TRADEVODATA_API_KEY
client.fundamentals("AAPL", as_of="2024-06-30") # -> FY2023; annual default
client.fundamentals("AAPL", as_of="2025-02-15", period="quarterly")
client.snapshot(as_of="2024-06-30", concept="Revenue", to_pandas=True)

Source: github.com/christianpichichero-max/tradevodata-py · PyPI

Note: as of June 2024, the newest knowable Apple annual revenue is FY2023 — FY2024 wasn't filed until 2024-11-01. That's the product.

Python (plain requests)

import requests

r = requests.get(
    "https://tradevodata.com/v1/fundamentals",
    params={"ticker": "AAPL", "as_of": "2024-06-30"},
    headers={"x-api-key": "tvd_your_key_here"},
)
for f in r.json()["fundamentals"]:
    print(f["concept"], f["value"], "known since", f["filed"])

R

library(httr)

r <- GET(
  "https://tradevodata.com/v1/fundamentals",
  query = list(ticker = "AAPL", as_of = "2024-06-30"),
  add_headers(`x-api-key` = "tvd_your_key_here")
)
for (f in content(r)$fundamentals) {
  cat(f$concept, f$value, "known since", f$filed, "\n")
}

Errors

400
Missing/invalid ticker, as_of, concept, or period. The body explains which.
401
Missing, invalid, or deactivated API key.
403
Evaluation key on a Pro-only endpoint (/v1/download, /v1/snapshot), or an evaluation requesting a 51st distinct company. Pro-only endpoint denials are not metered. Upgrade on the pricing page.
404
Ticker not in the universe (5,168 US companies with filing data).
429 · requests
Daily request quota (100/day evaluation, 5,000/day Pro) exceeded. Resets 00:00 UTC — the Retry-After header says how many seconds until then.
429 · tickers
Daily distinct-ticker limit (2,500/day) reached. Same reset, same Retry-After header. The error body says which limit you hit.
500
Our fault. If it persists, email support.

An empty result with count: 0 and a note means the ticker exists but nothing had been filed on or before your as_of.

GET/v1/health

Public liveness check (no key needed): returns { ok, rows, published_rows, stale_build, quarterly_rows, published_quarterly_rows, stale_build_quarterly, quarterly_public, db_ms }.

ok
true when the database answered. On failure the endpoint returns 503 with { ok: false, error }.
rows
Live row count for the concepts this API version publishes, read from the database rather than a build-time constant.
published_rows
The row count this deploy of the site advertises (632,466 at the moment).
stale_build
true when rows and published_rows disagree — the published data moved and the site deploy has not caught up yet. The API itself is serving the live published rows either way.
quarterly_rows
Live quarterly row count.
published_quarterly_rows
The quarterly count advertised by this deploy.
stale_build_quarterly
true when the live and advertised quarterly counts disagree.
quarterly_public
true when quarterly requests are enabled on this deployment.
db_ms
Milliseconds the database round-trip took.

Responses are edge-cached for 60 seconds, so the count is at most a minute old.

Limits

Daily limits per key, by plan. All reset at 00:00 UTC, and every 429 carries a Retry-After header with the seconds until reset.

100 requests · evaluation
Total requests per day during the 7-day free trial.
10 companies · evaluation lifetime
Distinct companies across the entire evaluation. Previously queried companies remain available after the cap is reached.
3 years · evaluation history
A rolling three-year as_of window for annual and quarterly per-company queries. Pro unlocks the complete available history.
5,000 requests · paid
Total requests per day. Sized so a normal research workflow never notices it.
2,500 tickers · paid
Distinct tickers per day. Repeat calls for the same ticker are free — only the first request for each new ticker counts.

The honest why: the dataset is the product. A real backtest touches a few hundred names; a full-universe scrape is all 5,168. The ticker cap sits between those two on purpose — it's an anti-bulk-extraction wall, not a revenue lever. For whole-universe work, don't fight the cap — use the bulk endpoints below (paid plan).

Bulk & cross-section

For whole-universe work — cross-sectional screens, factor backtests — don't loop the per-ticker endpoint. Both are Pro-only endpoints ($29/mo after the evaluation); an evaluation key gets a 403 here, un-metered.

GET /v1/download
The entire point-in-time dataset as one gzipped CSV. Add ?period=quarterly for the quarterly file; omit it for the annual default (632,466 annual rows). Costs 1 request, capped at 3 downloads/day across both cadences. Verify integrity against the x-dataset-sha256 response header.
GET /v1/snapshot?as_of=YYYY-MM-DD
Every ticker's latest value that was public on or before as_of — the whole-universe cross-section for one rebalance date. Optional &concept= and &period=quarterly. Costs 25 requests (the workload of thousands of per-ticker calls).
curl -H "x-api-key: tvd_..." "https://tradevodata.com/v1/download?period=quarterly" -o tradevodata-quarterly.csv.gz
curl -H "x-api-key: tvd_..." "https://tradevodata.com/v1/snapshot?as_of=2025-02-15&period=quarterly&concept=Revenue"

Coverage & semantics

  • 5,168 US companies · 632,466 point-in-time rows · 16 concepts · up to 12 fiscal years.
  • Annual 10-K/10-K/A plus quarterly 10-Q history (SEC EDGAR XBRL). Q4 is reported where tagged or derived and labelled where supported; Q4 EPS and diluted shares are not derived.
  • filed is the earliest filing that reported the value — across synonym XBRL tags, so re-tagged values keep their true first-public date.
  • Support: email us. Manage billing at /account.

Inspect the proof before you need a key.

The public proof pack covers 5 companies and 3 fiscal years with the same fields — no signup.

Or run the 3-minute Colab — nothing to install.