# Dataset queries

Select financial series and reporting periods, then retrieve their values.

Source: <https://docs.finbar.com/api-mcp/dataset-query>

```text
POST /v1/entities/{entity_id}/dataset/query
```

This endpoint requires `datasets:read`. First [read the catalogue](https://docs.finbar.com/api-mcp/catalogue.md)
to obtain the IDs, scope paths and periods you want. The query returns historical
values for the selected series, keeping reporting groups separate.

## Build the request

Save the following JSON as `query.json`. These are illustrative values: replace
the dataset ID, metric ID, reporting group, scope path and period with values
from your catalogue.

```json
{
  "expected_dataset_id": "11111111-1111-4111-8111-111111111111",
  "metric_ids": ["income_statement.revenue.root"],
  "reporting_group_ids": ["income_statement"],
  "scope_combinations": [
    [{"scope_group_id": "consolidated", "scope_id": "consolidated"}]
  ],
  "periods": {
    "mode": "exact",
    "exact": [{"year": 2025, "end_month": 12, "duration_months": 12}]
  },
  "value_version": "original",
  "limit": 25
}
```

| Body field            | Required | Meaning                                                                                              |
| --------------------- | -------- | ---------------------------------------------------------------------------------------------------- |
| `metric_ids`          | Yes      | 1–50 distinct metric IDs                                                                             |
| `scope_combinations`  | Yes      | 1–50 complete scope paths; each is a returned series's ordered `scopes` array, with up to 20 entries |
| `periods`             | Yes      | An exact selection, fiscal range or trailing window                                                  |
| `reporting_group_ids` | No       | Up to 50 group IDs; omit to include all matching groups                                              |
| `expected_dataset_id` | No       | Detects whether the publication changed since discovery                                              |
| `value_version`       | No       | `original` (default) or `latest_restated`                                                            |
| `limit`               | No       | Series per page, from 1 to 100; default 25                                                           |
| `cursor`              | No       | Continuation value from `next_cursor`                                                                |

`scope_combinations` is an array of paths because one request can select
several parts of a company. Each inner array must match a complete catalogue
path in the same order. The query returns existing series matching your metric,
scope and optional group selections; it does not create or combine series.

## Send the query

Set `ENTITY_ID` to the company ID used for discovery. Use your
[access token](https://docs.finbar.com/api-mcp/authentication.md) as `ACCESS_TOKEN`:

```bash
curl --fail-with-body --silent --show-error \
  "https://api.finbar.com/v1/entities/$ENTITY_ID/dataset/query" \
  --header "Authorization: Bearer $ACCESS_TOKEN" \
  --header 'Content-Type: application/json' \
  --data-binary @query.json
```

## Select a different period window

Replace only the `periods` field to use either of these alternatives. See
[reporting periods](https://docs.finbar.com/api-mcp/periods.md) for fiscal-month and duration definitions.

### Fiscal range

Select all available observations whose fiscal ends fall between the two
endpoints, inclusive. Range endpoints use duration 0:

```json
{
  "mode": "fiscal_range",
  "from": {"year": 2024, "end_month": 1, "duration_months": 0},
  "to": {"year": 2025, "end_month": 12, "duration_months": 0}
}
```

### Trailing window

Select the last 24 months ending at the latest populated historical period
in the matching series:

```json
{"mode": "trailing", "months": 24}
```

Both modes can return multiple durations, including quarterly and year-to-date
values. To request only annual values, use `exact` with the annual periods from
the catalogue.

## Read the response

**POST /v1/entities/{entity\_id}/dataset/query — 200 response**

Example response. IDs and values are illustrative.

```json
{
  "entity_id": "O-11111111111111111111111111111111",
  "name": "Example Company",
  "dataset_id": "11111111-1111-4111-8111-111111111111",
  "created_timestamp": "2026-01-15T10:00:00Z",
  "periods": [
    {
      "year": 2025,
      "end_month": 12,
      "duration_months": 12
    }
  ],
  "series": [
    {
      "series_id": "revenue.consolidated",
      "reporting_group_id": "income_statement",
      "metric_id": "income_statement.revenue.root",
      "label": "Revenue",
      "basis": "statutory",
      "scopes": [
        {
          "scope_group_id": "consolidated",
          "scope_id": "consolidated"
        }
      ],
      "number_format": "#,##0.0",
      "period_meaning": "span",
      "values": [
        {
          "number": 1234.5,
          "text": "1,234.5",
          "number_format": "#,##0.0",
          "fill_type": "as_reported",
          "value_version": "original",
          "report_period": {
            "year": 2025,
            "end_month": 12,
            "duration_months": 0
          },
          "sources": [
            {
              "item_id": "T-example",
              "row_index": 0,
              "column_index": 0
            }
          ]
        }
      ]
    }
  ],
  "next_cursor": "opaque-next-page-cursor"
}
```

Each entry in `series` identifies the metric, reporting group and scopes.
Its `values` array aligns by position with the response's `periods` array.
A missing observation is `null`; a reported zero is a value object with
`number: 0`.

See [values and sources](https://docs.finbar.com/api-mcp/values.md) before displaying or calculating with
the result. That page explains stored scale, restatements and source references.

## Continue or refresh

For another page, add the returned `next_cursor` as `cursor` in `query.json`
and send the same query. Keep the selections and `expected_dataset_id` unchanged.
Stop when `next_cursor` is absent.

| Result                         | Meaning and next step                                                                                  |
| ------------------------------ | ------------------------------------------------------------------------------------------------------ |
| `400` with `validation_failed` | Check the field issues. Unknown metrics, groups and scope paths must be corrected using the catalogue. |
| Empty `series` or `periods`    | The valid selections have no matching results. Recheck the combination and period window.              |
| `409` with `dataset_changed`   | Fetch the current metadata and catalogue, rebuild the query and restart pagination.                    |
