> ## 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.

# Tabular vs Timeseries

> The Blockworks API serves two model kinds. Learn the URL shapes, response shapes, and when to reach for each.

Every dataset in the Blockworks API is one of two **model kinds**. The kind determines the URL
shape, the query parameters, and the response structure, but within a kind, every model behaves
identically. Learn one tabular endpoint and you have learned them all.

|               | Tabular                               | Timeseries                                    |
| ------------- | ------------------------------------- | --------------------------------------------- |
| **Answers**   | "What is true right now?"             | "How did this change over time?"              |
| **Shape**     | Rows with a primary key               | Points along a time axis, grouped into series |
| **URL**       | `/query/tabular/{model}`              | `/query/timeseries/{model}/{granularity}`     |
| **Narrowing** | Filter operators, sorting, pagination | Time window, granularity, series selection    |
| **Payload**   | Array of row objects                  | `point_schema` plus compact point arrays      |

## URL shapes

```
Tabular
  GET /query/tabular/catalog                        catalog of every tabular model
  GET /query/tabular/{model}                        many rows: filter, sort, paginate
  GET /query/tabular/{model}/{id}                   one row by identifier

Timeseries
  GET /query/timeseries/catalog                     catalog of every timeseries model
  GET /query/timeseries/{model}/{granularity}       many series over a time window
  GET /query/timeseries/{model}/{granularity}/{key} one series over a time window
```

Concretely:

```
GET /query/tabular/assets?symbolIsOneOf=BTC,ETH
GET /query/tabular/assets/bitcoin
GET /query/timeseries/asset-price/1d?series=1e31218a-e44e-4285-820c-8282ee222035&timeframe=30d
GET /query/timeseries/asset-price/1d/1e31218a-e44e-4285-820c-8282ee222035?timeframe=30d
```

## How they relate

```mermaid theme={null}
flowchart TD
    C["Catalog endpoints<br/>/query/tabular/catalog<br/>/query/timeseries/catalog"]

    C --> T["Tabular models"]
    C --> S["Timeseries models"]

    T --> TL["List endpoint<br/>filter · sort · paginate<br/>data: array of rows"]
    T --> TI["Single-row endpoint<br/>lookup by primary key<br/>or alternative identifier<br/>data: one row"]

    S --> SA["Multi-series endpoint<br/>series · timeframe<br/>data: point_schema + series"]
    S --> SK["Single-series endpoint<br/>timeframe<br/>data: point_schema + points"]

    TI -. "the row id becomes a series key" .-> SK
```

## Tabular models

A tabular model is a result set with a primary key: one row per entity, holding its current state.
Asset identity and metadata, exchange directories, current market metrics, ETF holdings.

**List endpoint.** `GET /query/tabular/{model}` returns an array of rows. Narrow it with filter
operators, order it with `sortBy`/`sortDirection`, and walk it with `page`/`pageSize`. See
[Filtering & pagination](/getting-started/filtering-pagination).

```bash theme={null}
curl -G 'https://api.blockworks.com/query/tabular/assets' \
  --header 'X-Blockworks-API-Key: YOUR_API_KEY' \
  --data-urlencode 'circulatingMarketcapGte=1000000000' \
  --data-urlencode 'sortBy=circulatingMarketcap' \
  --data-urlencode 'sortDirection=desc'
```

**Single-row endpoint.** `GET /query/tabular/{model}/{id}` returns exactly one row. Many models
accept alternative identifiers as well as the primary key (for assets, a slug or a symbol also
resolves), and `metadata.matchedField` reports which field the value matched on.

```bash theme={null}
curl 'https://api.blockworks.com/query/tabular/assets/bitcoin' \
  --header 'X-Blockworks-API-Key: YOUR_API_KEY'
```

## Timeseries models

A timeseries model has a time column, a series key, and one or more metric columns. Every request
picks a **granularity** in the path and a **time window** in the query string. See
[Granularity & time ranges](/getting-started/concepts/granularity).

### Series keys

The series key is the value that names one series: the `{seriesKey}` path segment, or one entry
of `?series=`. For entity-keyed models (assets, blockchains, protocols, ETFs) it is the
**primary key of a row in the matching tabular model**, usually a UUID such as
`1e31218a-e44e-4285-820c-8282ee222035` for Bitcoin. The tabular row endpoint accepts a slug or a
symbol and tells you the primary key; the timeseries path does not resolve them.

<Warning>
  `GET /query/timeseries/asset-price/1d/bitcoin` returns `200` with `"points": []` and no
  `entity`, not `404`. An empty series almost always means a slug or symbol was used where the
  `assetID` or `networkID` belongs. Resolve the identifier first with `/query/tabular/assets/bitcoin`
  or `/query/tabular/blockchains/solana`.
</Warning>

Aggregate models (sectors, sub-sectors, exchange regions) key their series by a plain name such as
`AI` or `Asia` instead. [Finding an id](/api-reference/data-api/discovery/finding-an-id) lists the
lookup table and accepted identifiers for every timeseries model.

**Single-series endpoint.** `GET /query/timeseries/{model}/{granularity}/{seriesKey}` returns one
series. This is the common case: one asset's price history, one protocol's revenue.

```bash theme={null}
curl -G 'https://api.blockworks.com/query/timeseries/asset-price/1d/1e31218a-e44e-4285-820c-8282ee222035' \
  --header 'X-Blockworks-API-Key: YOUR_API_KEY' \
  --data-urlencode 'timeframe=30d'
```

**Multi-series endpoint.** `GET /query/timeseries/{model}/{granularity}` returns several series in
one response. Name them with `?series=`, a comma-separated list of up to 20 series keys.

```bash theme={null}
curl -G 'https://api.blockworks.com/query/timeseries/asset-price/1d' \
  --header 'X-Blockworks-API-Key: YOUR_API_KEY' \
  --data-urlencode 'series=1e31218a-e44e-4285-820c-8282ee222035,21c795f5-1bfd-40c3-858e-e9d7e820c6d0' \
  --data-urlencode 'timeframe=ytd'
```

<Note>
  For models with a small number of series (sector aggregates, ETF providers, lending protocols),
  omitting `?series=` returns **every** series at once. Models with high series cardinality (most
  asset-keyed models) do not support that: omitting `?series=` returns `404` with a message telling
  you to name the series. The catalog's `allowAllSeries` flag tells you which is which.
</Note>

## Choosing between them

<CardGroup cols={2}>
  <Card title="Reach for tabular" icon="table">
    You want a screener, a leaderboard, a directory, or the current value of a metric across many
    entities. You want to filter, sort, and paginate.
  </Card>

  <Card title="Reach for timeseries" icon="chart-line">
    You want a chart, a trend, a return calculation, or a backtest. You know which entities you care
    about and you need history for them.
  </Card>
</CardGroup>

The two kinds compose. A common pattern is to use a tabular model to *find* the entities you care
about, then feed their identifiers into a timeseries model as series keys:

<Steps>
  <Step title="Find the entities">
    `GET /query/tabular/assets?circulatingMarketcapGte=1000000000&selections=assetID,symbol`
  </Step>

  <Step title="Pull their history">
    `GET /query/timeseries/asset-price/1d?series=<up to 20 assetIDs>&timeframe=ytd`
  </Step>
</Steps>

## Shared conventions

Both kinds share the same envelope, the same `selections` parameter, the same
`acceptFormat` options (`json`, `csv`, `jsonl`), and the same error semantics. See
[Responses](/getting-started/responses) and [Errors](/getting-started/errors).
