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

# The Data Catalog

> The Blockworks API describes itself. Two catalog endpoints enumerate every model, column, filter, and granularity, which is ideal for building dynamic UIs and AI agents.

The API is catalog-driven. Every model, column, filter operator, sort option, and granularity is
declared in a source-controlled data catalog, and that catalog is exposed over the API itself. You
never have to hardcode a field list or guess which filters a column supports. You can ask.

<CardGroup cols={2}>
  <Card title="Tabular catalog" icon="table" href="#tabular-catalog">
    `GET /query/tabular/catalog`
  </Card>

  <Card title="Timeseries catalog" icon="chart-line" href="#timeseries-catalog">
    `GET /query/timeseries/catalog`
  </Card>
</CardGroup>

Neither endpoint needs an API key. Pass `publicOnly=true` to list only the models published in
this reference; without it, internal models your key may not be able to query are listed too.

## Tabular catalog

```bash theme={null}
curl 'https://api.blockworks.com/query/tabular/catalog?publicOnly=true'
```

`data.models` is an array of tabular models. Trimmed to one model and three of its columns:

```json theme={null}
{
  "error": null,
  "data": {
    "models": [
      {
        "name": "Assets",
        "slug": "assets",
        "description": "Identity and relation fields for every crypto asset : id, slug, symbol, name, logo, primary project, and onchain platform contracts. Lookup and search surface for assets.",
        "access": {
          "tier": "public"
        },
        "columns": [
          {
            "name": "Asset ID",
            "field": "assetID",
            "description": "The unique identifier of the asset.",
            "type": "string",
            "primaryKey": true,
            "sortable": false,
            "defaultSort": false,
            "filters": [
              "Eq",
              "IsOneOf",
              "IsNotOneOf"
            ]
          },
          {
            "name": "Slug",
            "field": "slug",
            "description": "The URL slug of the asset.",
            "type": "string",
            "primaryKey": false,
            "identifier": 1,
            "sortable": true,
            "defaultSort": false,
            "filters": [
              "Eq",
              "IsOneOf"
            ]
          },
          {
            "name": "Circulating Marketcap",
            "field": "circulatingMarketcap",
            "description": "The circulating marketcap of the asset. Carried so search and filter results can be ranked by size.",
            "type": "float64",
            "primaryKey": false,
            "sortable": true,
            "defaultSort": false,
            "filters": [
              "Gt",
              "Gte",
              "Lt",
              "Lte"
            ]
          }
        ]
      }
    ]
  }
}
```

### Model fields

| Field         | Description                                                                                                                                                                                                |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`        | Human-readable model name.                                                                                                                                                                                 |
| `slug`        | URL segment: `/query/tabular/{slug}`. A few models also answer to aliases (`asset-entities` for `assets`, `network-entities` and `networks` for `blockchains`); the catalog lists the canonical slug only. |
| `description` | What the model contains.                                                                                                                                                                                   |
| `access`      | `tier` (`public`, `unpaid`, `paid`, `permissive`, `internal`) and, for `permissive`, a `permissionSlug`.                                                                                                   |
| `columns`     | Every public column on the model.                                                                                                                                                                          |

### Column fields

| Field         | Description                                                                                                                                                                   |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`        | Human-readable column name.                                                                                                                                                   |
| `field`       | Public field name: the key in the response, the value for `selections` and `sortBy`, and the base of every filter parameter.                                                  |
| `description` | What the column holds.                                                                                                                                                        |
| `type`        | Data type, e.g. `string`, `float64`, `int64`, `bool`, `time`, or an array type.                                                                                               |
| `unit`        | Denomination where meaningful: `usd`, `btc`, `sats`, `eth`, `gwei`, `native-token`, `percent`, `count`, `ratio`.                                                              |
| `primaryKey`  | Whether this column identifies the row for `/query/tabular/{model}/{id}`. Its values are also the series keys of the timeseries models keyed by this table.                   |
| `identifier`  | Priority of an alternative identifier the row endpoint also matches on, `1` first (for `assets`: `slug`, then `prioritySymbol`). Absent when the column is not an identifier. |
| `sortable`    | Whether the column may be used as `sortBy`.                                                                                                                                   |
| `defaultSort` | Whether this is the model's default sort column.                                                                                                                              |
| `filters`     | The filter operators enabled on this column, spelled exactly as they are appended to `field` to form a query parameter.                                                       |

### Filters are query-parameter suffixes

A column with `"field": "circulatingMarketcap"` and `"filters": ["Gt", "Gte", "Lt", "Lte"]` is
filtered with `?circulatingMarketcapGte=1000000000`; one with `"field": "slug"` and
`"filters": ["Eq", "IsOneOf"]` with `?slugEq=bitcoin` or `?slugIsOneOf=bitcoin,ethereum`. There
is no translation step: the catalog value is the suffix. The full operator list, with the
value each one takes, is on [Filtering & pagination](/getting-started/filtering-pagination).

## Timeseries catalog

```bash theme={null}
curl 'https://api.blockworks.com/query/timeseries/catalog?publicOnly=true'
```

Trimmed to one model and three of its columns:

```json theme={null}
{
  "error": null,
  "data": {
    "models": [
      {
        "name": "Asset Price",
        "slug": "asset-price",
        "description": "Volume-weighted average price and volume for an asset over time.",
        "access": {
          "tier": "public"
        },
        "intervals": [
          "5m",
          "1h",
          "1d",
          "1w"
        ],
        "allowAllSeries": false,
        "columns": [
          {
            "name": "Time",
            "field": "time",
            "description": "Timestamp of the data point.",
            "type": "time",
            "time": true,
            "seriesKey": false
          },
          {
            "name": "Asset ID",
            "field": "assetID",
            "description": "The unique identifier of the asset.",
            "type": "string",
            "time": false,
            "seriesKey": true
          },
          {
            "name": "Close Price",
            "field": "close",
            "description": "Price at the candle close.",
            "type": "float64",
            "unit": "usd",
            "time": false,
            "seriesKey": false
          }
        ]
      }
    ]
  }
}
```

Timeseries models add three fields on top of the shared ones:

| Field                 | Description                                                                                                                                                                                                                                                           |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `intervals`           | The granularities this model supports, which are the valid values for the `{granularity}` path segment.                                                                                                                                                               |
| `allowAllSeries`      | Whether the multi-series endpoint may be called without `?series=`. When `false`, you must name the series you want.                                                                                                                                                  |
| `columns[].time`      | `true` for the model's time column, the leading value of every point.                                                                                                                                                                                                 |
| `columns[].seriesKey` | `true` for the column that identifies a series. Its values are the keys you pass to `?series=` or in the series-key path. For entity-keyed models they are the primary keys of a tabular model; see [Finding an id](/api-reference/data-api/discovery/finding-an-id). |

## Built for agents

The catalog is the reason an AI agent can use this API without a hand-written integration. Two
requests give it the complete, current surface area: every dataset, every field, every legal filter,
every granularity, including access tiers, so it knows what it can reach before it tries.

<Steps>
  <Step title="Discover">
    Fetch both catalogs. You now have every model slug and its description.
  </Step>

  <Step title="Select">
    Match the user's question to a model. `access.tier` tells you whether the key can query it.
  </Step>

  <Step title="Construct">
    Build the request from the columns: `field` names for `selections` and `sortBy`, `field` plus
    one of its `filters` values for each query parameter, `intervals` for the granularity path
    segment, and the `primaryKey` of the lookup table for a series key.
  </Step>

  <Step title="Interpret">
    For timeseries, use the response's `point_schema` to label the point arrays; for tabular, the
    `unit` on each column tells you how to format the number.
  </Step>
</Steps>

<Note>
  Catalog fields change as models are added and columns are exposed. Fetch the catalog rather than
  pinning a snapshot, and treat unknown fields as forward-compatible additions.
</Note>

### Example: find every model with an hourly granularity

```bash theme={null}
curl -s 'https://api.blockworks.com/query/timeseries/catalog?publicOnly=true' \
  | jq -r '.data.models[] | select(.intervals | index("1h")) | "\(.slug)\t\(.name)"'
```

### Example: list the sortable columns on a tabular model

```bash theme={null}
curl -s 'https://api.blockworks.com/query/tabular/catalog?publicOnly=true' \
  | jq -r '.data.models[] | select(.slug=="assets") | .columns[] | select(.sortable) | .field'
```

<CardGroup cols={3}>
  <Card title="Tabular catalog reference" icon="table" href="/api-reference/data-api/discovery/tabular-catalog">
    The endpoint page, with the full response shape.
  </Card>

  <Card title="Timeseries catalog reference" icon="chart-line" href="/api-reference/data-api/discovery/timeseries-catalog">
    The endpoint page, with the full response shape.
  </Card>

  <Card title="Finding an id" icon="key" href="/api-reference/data-api/discovery/finding-an-id">
    Which lookup table gives the series key of each timeseries model.
  </Card>
</CardGroup>
