{
  "openapi": "3.1.0",
  "info": {
    "title": "Tradevo Data API",
    "version": "1.0.0",
    "summary": "Point-in-time US equity fundamentals from SEC EDGAR.",
    "description": "Fundamentals returned as first reported, each stamped with the date it became public (`filed`), so backtests avoid lookahead bias. One ticker per request, key-metered. Get a key at https://tradevodata.com.",
    "contact": {
      "name": "Tradevo Data",
      "url": "https://tradevodata.com"
    },
    "license": {
      "name": "Source data: U.S. SEC EDGAR (public domain)"
    }
  },
  "servers": [
    {
      "url": "https://tradevodata.com"
    }
  ],
  "security": [
    {
      "apiKeyAuth": []
    }
  ],
  "paths": {
    "/v1/fundamentals": {
      "get": {
        "operationId": "getFundamentals",
        "summary": "Point-in-time fundamentals for a ticker, as of a date",
        "description": "Returns the most recent annual fundamental values that had already been filed on or before `as_of` (first_filed <= as_of). Point-in-time correct \u2014 no lookahead.",
        "parameters": [
          {
            "name": "ticker",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Z0-9.\\-]{1,12}$"
            },
            "example": "AAPL",
            "description": "US stock symbol (1\u201312 chars: A\u2013Z, 0\u20139, '.', '-'). Share classes and other aliases resolve to the SEC filer they belong to (GOOG \u2192 GOOGL, BRK-A \u2192 BRK-B, preferred-share tickers such as BAC-PK \u2192 BAC, and roughly 1,500 more); when that happens the response echoes the ticker you sent and adds `resolved_ticker` and `resolved_note`."
          },
          {
            "name": "as_of",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2024-06-30",
            "description": "Return only values that were public on or before this date (YYYY-MM-DD)."
          },
          {
            "name": "concept",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "Revenue",
                "NetIncome",
                "Assets",
                "StockholdersEquity",
                "OperatingCashFlow",
                "EPSDiluted",
                "DilutedShares"
              ]
            },
            "description": "Optional. Restrict to one concept (case-insensitive). Omit to return all available."
          }
        ],
        "responses": {
          "200": {
            "description": "Point-in-time fundamentals. May be an empty set with a `note` if nothing had been filed yet. The `data_through` value in the example is illustrative \u2014 it advances with every data load.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FundamentalsResponse"
                },
                "example": {
                  "ticker": "AAPL",
                  "as_of": "2024-06-30",
                  "data_through": "2026-07-24",
                  "count": 1,
                  "fundamentals": [
                    {
                      "concept": "Revenue",
                      "fiscal_year": 2023,
                      "period_end": "2023-09-30",
                      "filed": "2023-11-03",
                      "value": 383285000000,
                      "latest_value": 383285000000,
                      "restated": false,
                      "qa_status": "clean"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid ticker, as_of, or concept.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Ticker not in the Tradevo Data universe.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Daily request limit exceeded."
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (database unreachable). Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Service + dataset health",
        "security": [],
        "responses": {
          "200": {
            "description": "Healthy.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "rows": {
                      "type": "integer",
                      "description": "Live row count from the database.",
                      "example": 312751
                    },
                    "published_rows": {
                      "type": "integer",
                      "description": "Row count the current site deploy advertises.",
                      "example": 312751
                    },
                    "stale_build": {
                      "type": "boolean",
                      "description": "true when rows != published_rows.",
                      "example": false
                    },
                    "db_ms": {
                      "type": "integer",
                      "description": "Database round-trip time in milliseconds.",
                      "example": 12
                    }
                  },
                  "required": [
                    "ok",
                    "rows",
                    "published_rows",
                    "stale_build",
                    "db_ms"
                  ]
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (database unreachable): `{ ok: false, error }`. Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "description": "Public liveness check, no key needed. `rows` is a live count(*) of the fundamentals table; `published_rows` is the count the current site deploy advertises; `stale_build` is true when the two disagree (the data moved and the deploy has not caught up \u2014 the API serves the live rows either way). Responses are edge-cached for 60 seconds."
      }
    },
    "/v1/download": {
      "get": {
        "operationId": "getBulkDownload",
        "summary": "Full dataset as one gzipped CSV",
        "description": "The entire point-in-time dataset as a single gzipped CSV (columns: ticker, cik, concept, xbrl_tag, fiscal_year, period_end, first_filed, lag_days, filed_reliable, original_value, latest_value, restated, qa_status). Included in the flat $49/mo plan. Costs 1 request unit; separately capped at 3 downloads per key per UTC day. Verify your file against the `x-dataset-sha256` header.",
        "responses": {
          "200": {
            "description": "The gzipped CSV. Headers: `x-dataset-sha256` (sha256 of the .csv.gz bytes), `x-dataset-rows`, `x-dataset-generated-at`.",
            "content": {
              "application/gzip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Feature not yet available.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Daily request quota or daily download limit (3) exceeded. Resets at 00:00 UTC (see Retry-After)."
          },
          "503": {
            "description": "Export not generated yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/snapshot": {
      "get": {
        "operationId": "getSnapshot",
        "summary": "Whole-universe point-in-time cross-section, as of a date",
        "description": "For every ticker (and every concept, unless filtered), the most recent value that was already public on or before `as_of` (first_filed <= as_of). One call per rebalance date is all a cross-sectional backtest needs. Costs 25 request units against the daily quota (a whole-universe cross-section is the workload of thousands of per-ticker calls).",
        "parameters": [
          {
            "name": "as_of",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2024-06-30",
            "description": "Return only values that were public on or before this date (YYYY-MM-DD)."
          },
          {
            "name": "concept",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "Revenue",
                "NetIncome",
                "Assets",
                "StockholdersEquity",
                "OperatingCashFlow",
                "EPSDiluted",
                "DilutedShares"
              ]
            },
            "description": "Optional. Restrict to one concept (case-insensitive). Omit to return all (~36k rows, a few MB of JSON)."
          }
        ],
        "responses": {
          "200": {
            "description": "The point-in-time cross-section.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SnapshotResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid as_of or concept.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Feature not yet available.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Daily request quota exceeded. Resets at 00:00 UTC (see Retry-After)."
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (database unreachable). Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Your Tradevo Data API key (starts with `tvd_`). Get one at https://tradevodata.com."
      }
    },
    "schemas": {
      "FundamentalsResponse": {
        "type": "object",
        "properties": {
          "ticker": {
            "type": "string"
          },
          "resolved_ticker": {
            "type": "string",
            "example": "GOOGL",
            "description": "Present only when `ticker` was an alias (share class, preferred-share ticker, renamed issuer) that resolved to a different filer-level ticker. Fundamentals are reported under this ticker."
          },
          "resolved_note": {
            "type": "string",
            "example": "GOOG and GOOGL are share classes of the same SEC filer; fundamentals are reported at the filer level.",
            "description": "Present only alongside `resolved_ticker`. Human-readable explanation of the alias resolution."
          },
          "as_of": {
            "type": "string",
            "format": "date"
          },
          "count": {
            "type": "integer"
          },
          "fundamentals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Fundamental"
            }
          },
          "note": {
            "type": "string",
            "description": "Present only when count is 0."
          },
          "data_through": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "example": "2026-07-22",
            "description": "The newest first_filed date in the dataset. The dataset is a snapshot; filings published after this date are not reflected. The example value is illustrative; the live value advances with every data load."
          },
          "coverage_warning": {
            "type": "string",
            "description": "Present only when as_of is later than data_through."
          },
          "staleness_note": {
            "type": "string",
            "description": "Present only when one or more returned rows are flagged stale_for_as_of."
          }
        },
        "required": [
          "ticker",
          "as_of",
          "count",
          "fundamentals"
        ]
      },
      "Fundamental": {
        "type": "object",
        "properties": {
          "concept": {
            "type": "string",
            "example": "Revenue"
          },
          "fiscal_year": {
            "type": "integer",
            "example": 2023
          },
          "period_end": {
            "type": "string",
            "format": "date"
          },
          "filed": {
            "type": "string",
            "format": "date",
            "description": "Date this value first became public (point-in-time key)."
          },
          "value": {
            "type": [
              "number",
              "null"
            ],
            "description": "First-knowable (point-in-time) value. null when suppressed as implausible \u2014 see qa_status."
          },
          "latest_value": {
            "type": [
              "number",
              "null"
            ],
            "description": "Most recent revision. May post-date as_of, so it is NOT point-in-time safe. null when suppressed."
          },
          "restated": {
            "type": "boolean",
            "description": "True if later amended by more than 0.5%."
          },
          "qa_status": {
            "type": "string",
            "example": "clean",
            "description": "Per-row quality verdict. \"clean\", or \"FLAG:\" followed by one or more semicolon-separated reasons: lag_out_of_range (filing lag outside 0-120 days), revenue_magnitude (revenue outside plausible bounds), ambiguous_tag (another XBRL tag in the same filing reported materially more for this period, so the choice of element is uncertain), implausible_value (a scale/unit-corrupted value was suppressed \u2014 value and/or latest_value are null), tag_switch_discontinuity (the XBRL element behind this concept differs from the adjacent fiscal year, e.g. Broadcom alternates ProfitLoss and NetIncomeLoss; the value is usually correct and the flag marks a scope change to check before differencing year over year, not an error), stale_for_as_of (the newest fiscal period we hold for this concept ends more than ~18 months before your as_of)."
          },
          "lag_days": {
            "type": [
              "integer",
              "null"
            ],
            "example": 58,
            "description": "Days from period_end to first_filed \u2014 how long after the fiscal period ended this value became public."
          }
        }
      },
      "SnapshotResponse": {
        "type": "object",
        "properties": {
          "as_of": {
            "type": "string",
            "format": "date"
          },
          "concept": {
            "type": "string",
            "description": "Present only when the request filtered by concept."
          },
          "count": {
            "type": "integer"
          },
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SnapshotRow"
            }
          },
          "data_through": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "example": "2026-07-22",
            "description": "The newest first_filed date in the dataset. The dataset is a snapshot; filings published after this date are not reflected. The example value is illustrative; the live value advances with every data load."
          },
          "coverage_warning": {
            "type": "string",
            "description": "Present only when as_of is later than data_through."
          },
          "staleness_note": {
            "type": "string",
            "description": "Present only when one or more returned rows are flagged stale_for_as_of."
          }
        },
        "required": [
          "as_of",
          "count",
          "rows"
        ]
      },
      "SnapshotRow": {
        "type": "object",
        "properties": {
          "ticker": {
            "type": "string",
            "example": "AAPL"
          },
          "concept": {
            "type": "string",
            "example": "Revenue"
          },
          "fiscal_year": {
            "type": "integer",
            "example": 2023
          },
          "period_end": {
            "type": "string",
            "format": "date"
          },
          "filed": {
            "type": "string",
            "format": "date",
            "description": "Date this value first became public (point-in-time key)."
          },
          "value": {
            "type": [
              "number",
              "null"
            ],
            "description": "First-knowable (point-in-time) value. null when suppressed as implausible \u2014 see qa_status."
          },
          "latest_value": {
            "type": [
              "number",
              "null"
            ],
            "description": "Most recent revision. May post-date as_of, so it is NOT point-in-time safe. null when suppressed."
          },
          "restated": {
            "type": "boolean"
          },
          "qa_status": {
            "type": "string",
            "example": "clean",
            "description": "Per-row quality verdict. \"clean\", or \"FLAG:\" followed by one or more semicolon-separated reasons: lag_out_of_range (filing lag outside 0-120 days), revenue_magnitude (revenue outside plausible bounds), ambiguous_tag (another XBRL tag in the same filing reported materially more for this period, so the choice of element is uncertain), implausible_value (a scale/unit-corrupted value was suppressed \u2014 value and/or latest_value are null), tag_switch_discontinuity (the XBRL element behind this concept differs from the adjacent fiscal year, e.g. Broadcom alternates ProfitLoss and NetIncomeLoss; the value is usually correct and the flag marks a scope change to check before differencing year over year, not an error), stale_for_as_of (the newest fiscal period we hold for this concept ends more than ~18 months before your as_of)."
          },
          "lag_days": {
            "type": [
              "integer",
              "null"
            ],
            "example": 58,
            "description": "Days from period_end to first_filed \u2014 how long after the fiscal period ended this value became public."
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ]
      }
    }
  }
}
