# Metric History

> Returns one statement-derived metric (ratios, margins, growth and every *_ttm name) as a series of points, one per fiscal period end, newest first.

`GET https://api.bavest.co/v2/equities/metrics/history`

Group: Equities. Route id: `v2_equities_metrics_history`. Included in: Startup, Pro, Growth.

## Description

Returns one statement-derived metric (ratios, margins, growth and every *_ttm name) as a series of points, one per fiscal period end, newest first. Suppressed periods are returned as explicit null points with a reason instead of being omitted, so point counts stay stable for mirrors; see the Metric History guide for basis, vintage and TTM-overlap semantics.

## Authentication

Send your API key in the `x-api-key` header on every request. No key yet? Sign up at https://dashboard.bavest.co/sign-up (free trial). The examples read the key from the `BAVEST_API_KEY` environment variable.

## Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `symbol` | query | string | one of symbol, isin | Stock ticker symbol (e.g., `AAPL`, `MSFT`, `GOOGL`). Provide exactly one of symbol or isin. Example `AAPL`. |
| `isin` | query | string | one of symbol, isin | ISIN code (e.g., `US0378331005`). Provide exactly one of symbol or isin. Clear the symbol example before using an ISIN. |
| `name` | query | string | yes | Metric name. Discover valid names via GET /equities/metrics/names. Example `roe_ttm`. |
| `basis` | query | string | no | Reporting basis. Defaults to TTM for *_ttm names, FY otherwise. One of `FY`, `Q1`, `Q2`, `Q3`, `Q4`, `H1`, `H2`, `TTM`. |
| `vintage` | query | string | no | MR = most recent restated statements. AR / as_of point-in-time replay is not yet enabled. One of `MR`. Default `MR`. |
| `from` | query | string (date) | no | Earliest period end (inclusive). |
| `to` | query | string (date) | no | Latest period end (inclusive). |
| `provenance` | query | boolean | no | When true, each point carries a provenance block (knownAt, restated, and the vendor's acceptedDate/filingDate claim). Empty while ledger coverage has not begun for the security. Default `false`. |
| `changedSince` | query | string (date-time) | no | Incremental sync. Returns only points whose value changed at or after this ISO-8601 timestamp. Pass the `syncCursor` of the previous response; points upsert on periodEnd, so re-pulling an overlap is harmless. |

Required: one of `symbol`, `isin`.

## Response

200 Successful response (`application/json`).

| Field | Type | Always present | Description |
|---|---|---|---|
| `data` | object | no |  |
| `data.metric` | object | no |  |
| `data.metric.id` | string | no | Example: `roe_ttm`. |
| `data.metric.name` | string | no | Example: `roe_ttm`. |
| `data.metric.unit` | string \| null | no | Example: `RATIO`. |
| `data.metric.currency` | string \| null | no | Example: `USD`. |
| `data.metric.calcVersion` | string \| null | no | Example: `2026.08`. |
| `data.basis` | string | no | One of `FY`, `Q1`, `Q2`, `Q3`, `Q4`, `H1`, `H2`, `TTM`. |
| `data.vintage` | string | no | One of `MR`. |
| `data.warning` | string | no | Present when no history is materialized yet for this security/metric/basis. |
| `data.syncCursor` | string (date-time) \| null | no | Latest change time across the whole series (not only the returned points). Pass it as `changedSince` on the next call. Null when no history is materialized. Example: `2026-07-22T21:42:19.701813+00:00`. |
| `data.points` | array of object | no |  |
| `data.points[].periodEnd` | string (date) | no |  |
| `data.points[].periodLabel` | string | no |  |
| `data.points[].calendarPeriod` | string | no | Calendar bucket the fiscal point belongs to, derived from the real filed period dates. Sub-annual points take the calendar quarter of their period end (CY2025Q3); annual points take the calendar year holding the majority of the fiscal year, so a non-December year-end aligns with December filers. Labeling only -- no value is interpolated across fiscal boundaries. Example: `CY2025Q3`. |
| `data.points[].value` | number \| null | no |  |
| `data.points[].valid` | boolean | no |  |
| `data.points[].updatedAt` | string (date-time) \| null | no | When this point's value last changed in our store. |
| `data.points[].reason` | string | no | Why the point is null (only on suppressed points). |
| `data.points[].rootCause` | string | no | Detail behind the suppression (only on suppressed points). |
| `data.points[].provenance` | object | no | Present only when provenance=true. |
| `data.points[].provenance.knownAt` | string (date-time) \| null | no | When we first knew the currently served value (our honest first-seen axis). Null before ledger coverage begins for this security. |
| `data.points[].provenance.firstKnownAt` | string (date-time) \| null | no | When we first observed any value for this period. |
| `data.points[].provenance.restated` | boolean | no | True when this period has more than one distinct observed version in our ledger. For TTM it flags the anchor quarter. |
| `data.points[].provenance.acceptedDate` | string (date-time) \| null | no | The vendor's claimed acceptance date. FABRICATED for non-SEC filers (~96-99% of EU rows equal the period end); never our knowledge axis. |
| `data.points[].provenance.filingDate` | string (date) \| null | no | The vendor's claimed filing date, subject to the same fabrication caveat as acceptedDate. |
| `meta` | ResponseMeta | no | Response envelope metadata. Always present on a 200: `time` is set by `core/response.py` on every successful response. Errors carry the same block, built by the same code, so a client parses one meta shape whether the call succeeded or failed. |
| `meta.time` | integer | no | Server-side processing time in milliseconds. Example: `17`. |
| `meta.parameters` | object | no | Echo of the request parameters the endpoint resolved. |

## Example request

```bash
curl 'https://api.bavest.co/v2/equities/metrics/history?symbol=AAPL&name=roe_ttm&vintage=MR' \
  -H "x-api-key: $BAVEST_API_KEY"
```

## Example response

```json
{
  "data": {
    "metric": {
      "id": "roe_ttm",
      "name": "roe_ttm",
      "unit": "RATIO",
      "currency": null,
      "calcVersion": "2026.07"
    },
    "basis": "TTM",
    "vintage": "MR",
    "syncCursor": "2026-08-31T07:51:48.126480+00:00",
    "points": [
      {
        "periodEnd": "2026-06-27",
        "periodLabel": "TTM",
        "calendarPeriod": "CY2026Q2",
        "value": 1.1991,
        "valid": true,
        "updatedAt": "2026-08-31T07:51:48.126480+00:00"
      },
      {
        "periodEnd": "2026-03-28",
        "periodLabel": "TTM",
        "calendarPeriod": "CY2026Q1",
        "value": 1.151,
        "valid": true,
        "updatedAt": "2026-08-31T07:51:47.732996+00:00"
      }
    ]
  },
  "meta": {
    "parameters": {
      "name": "roe_ttm",
      "symbol": "AAPL"
    },
    "time": 2276
  }
}
```

## Errors

| Status | Meaning |
|---|---|
| 400 | Invalid request parameters. Returned when required query parameters are missing, have invalid types, or violate constraints (e.g., providing both symbol and isin when they are mutually exclusive). |
| 401 | Missing or invalid API key. |
| 404 | Resource not found. |
| 429 | Rate limit exceeded. Retry after the `Retry-After` header interval. |
| 500 | An unexpected error occurred on the server. If the issue persists, contact support with the X-Request-Id header value. |
| 502 | Upstream data provider returned an error or is temporarily unavailable. Retry after a short delay. |
| 504 | The request timed out waiting for a response from the upstream data provider. This may occur for complex queries or during peak load. |
| default | An unexpected error occurred on the server. If the issue persists, contact support with the X-Request-Id header value. |

- `403` from the gateway: the API key is invalid or switched off.
- `429` with message `Limit Exceeded`: the monthly quota of the key is used up. With `Too Many Requests`: the key is throttled, or this route is not in the key's plan. Wait for `Retry-After` when it is sent.

## Links

- HTML page: https://dashboard.bavest.co/docs/v2_equities_metrics_history
- OpenAPI: https://dashboard.bavest.co/openapi.json (YAML: https://dashboard.bavest.co/openapi.yaml)
- Authentication: https://dashboard.bavest.co/docs/authentication.md
- MCP server for AI agents: https://dashboard.bavest.co/docs/mcp.md
- All routes: https://dashboard.bavest.co/llms.txt
