> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blockworks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Timeseries

> timeseries_catalog and timeseries_data let you discover what metric series exist, then pull the exact data points at the granularity and window you want.

Two tools cover timeseries, and like the tabular pair they are meant to be used in order: the assistant discovers
what exists, then reads it.

| Tool                 | Purpose                                                                                       |
| -------------------- | --------------------------------------------------------------------------------------------- |
| `timeseries_catalog` | List the timeseries models, or describe one in full: metrics, granularities, and series rules |
| `timeseries_data`    | Read points from one model, for chosen series, at a granularity, over a window                |

Timeseries models are metrics observed over time (prices, supply, revenue, volumes, mindshare) split into named
series, usually one per asset, protocol, exchange, or sector. Reach for these when you want the actual numbers
rather than a single current figure; for *what is true right now*, the [tabular tools](/mcp/tools/datasets) are the
shorter path, and for qualitative questions start with [`search_documents`](/mcp/tools/search).

This is the same discover-then-query model the REST [Data API](/getting-started/concepts/catalog) uses, backed by
the same catalog.

## The workflow

<Steps>
  <Step title="The assistant discovers what is queryable">
    `timeseries_catalog` with no arguments returns one compact entry per model: `slug`, `name`, `description`,
    `access`, `metricCount`, the `intervals` it supports, and `allowAllSeries`. Passing `search` narrows the list
    by a case-insensitive substring match on name, slug, and description.

    Passing a `model` slug returns that model in full, including every metric column with its `field`, `type`,
    `unit`, and whether it is the leading time column or the series key.

    Two fields decide how the read is shaped:

    * **`intervals`** are the granularities the model supports, such as `1h`, `1d`, `1w`.
    * **`allowAllSeries`** says whether the model can return every series at once. When it is false, the assistant
      must name the series keys it wants.

    You can trigger this step explicitly:

    ```text theme={null}
    What Blockworks timeseries datasets are available for DeFi protocols?
    ```

    ```text theme={null}
    Which granularities does the asset price dataset support?
    ```
  </Step>

  <Step title="The assistant reads the points">
    With a model identified, `timeseries_data` reads it:

    | Argument       | What it does                                                                   |
    | -------------- | ------------------------------------------------------------------------------ |
    | `model`        | The model slug, exactly as the catalog returns it. Required                    |
    | `granularity`  | One of the model's intervals. Defaults to `1d`                                 |
    | `series`       | The series keys to read, at most 20. Omit only on models with `allowAllSeries` |
    | `selections`   | Which metric fields each point carries. Omit for every metric                  |
    | `timeframe`    | A relative or calendar window. Defaults to `90d`                               |
    | `start`, `end` | An explicit window instead of `timeframe`. Never both                          |
    | `bounds`       | Return only the first and last point of the window for each series             |

    ```text theme={null}
    What is Bitcoin's daily price over the last 90 days?
    ```

    ```text theme={null}
    Show me Ethereum's weekly active addresses for the past year.
    ```

    ```text theme={null}
    Compare daily trading volumes for Bitcoin and Solana this quarter.
    ```
  </Step>
</Steps>

In practice you rarely drive the two steps separately. You ask the second kind of question and the assistant runs
the catalog lookup first on its own. Asking the discovery question explicitly is useful when you want to know what
is available before committing to an analysis.

## Series keys

Series keys are the model's own identifiers, and they are usually opaque ids rather than tickers or names. To turn
a name or a symbol into a series key, the assistant reads the matching tabular model with
[`tabular_data`](/mcp/tools/datasets) and takes the identifier from the matching row. You do not have to ask for
that step; naming the asset precisely is what makes it resolve cleanly.

## Granularity and time ranges

A request always settles two things: the resolution of the series and the window it covers. Coarser granularities
cover longer histories in fewer points; finer ones give you intraday shape at the cost of volume. If an assistant
returns a series at a resolution you did not want, say so explicitly ("hourly, not daily") and it will re-query.

Choose the window with either `timeframe` or `start`/`end`, never both:

* **Relative**: `30d`, `12h`, `4w`, or `ytd`, `qtd`, `mtd`, `dtd`.
* **Calendar**: a bare year (`2026`), a month (`2026-06`), or a day (`2026-06-01`) selects that whole period.
* **Explicit**: `start` is inclusive, `end` is exclusive, and both accept `YYYY-MM-DD`, RFC3339, or unix seconds.
  `end` defaults to now.

With none of them, the window defaults to **the last 90 days**, so an unqualified question does not pull a model's
whole history. The same resolution and window model is documented in full for the REST API on
[Granularity and time ranges](/getting-started/concepts/granularity).

## What comes back

| Field                  | What it is                                                                                             |
| ---------------------- | ------------------------------------------------------------------------------------------------------ |
| `model`, `granularity` | The model read, and the resolution it was read at                                                      |
| `point_schema`         | What each position of a point array means, in order                                                    |
| `series`               | One entry per series: its `key`, the `entity` it identifies where the model maps one, and its `points` |
| `totalPoints`          | How many points the call returned across all series                                                    |

Points are positional arrays rather than objects: position 0 is a unix timestamp in seconds, and the remaining
positions follow `point_schema` in order. That is why `point_schema` has to be read before any point is
interpreted, and it is the same compact shape the REST API returns.

<Note>
  One call returns at most **20 series** and **5000 points**, and a read that exceeds either is rejected rather
  than truncated, so a partial series is never passed off as a complete one. If that happens, shorten the
  timeframe, use a coarser granularity, name fewer series, select fewer metrics, or set `bounds` to get only the
  window's first and last point.
</Note>

<Tip>
  `bounds` is the cheap way to compute a change over a period. "How much did X move this quarter?" needs two
  points, not ninety.
</Tip>

## Getting better results

* **Name the entity precisely.** "Ethereum" and "Ethereum L2s" resolve to different series.
* **State the granularity when it matters.** "Daily", "hourly", "weekly" removes a guess.
* **Give an explicit window.** "Last 90 days" or "since January" beats "recently".
* **Ask for fewer metrics** on a wide model. Naming the metric you want keeps the read under the point cap.
* **Ask for the underlying points** when you want to verify. "Include the raw values" makes it obvious the answer
  came from the series rather than the model's own knowledge.

<Note>
  `timeseries_catalog` lists only the models Blockworks publishes to the public API, and reading one still depends
  on your key's entitlements. An assistant's "that dataset is not available" may be an entitlements boundary rather
  than a gap in coverage.
</Note>
