{
  "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, '.', '-')."
          },
          {
            "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FundamentalsResponse"
                },
                "example": {
                  "ticker": "AAPL",
                  "as_of": "2024-06-30",
                  "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"
                    },
                    "rows": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (database unreachable). Retry shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/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"
          },
          "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."
          },
          "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."
          },
          "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"
        ]
      }
    }
  }
}
