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

# Get dataset

> Describe one DataSet: its dimensions, period and where its metrics are

API versions: v1 (current) https://docs.odysseysignal.com/api/reference/get-dataset.md

`GET /v1/signals/{signal_id}/datasources/{datasource_id}/datasets/{dataset_id}`

Authentication: an API key in `X-Api-Key`, or `Authorization: Bearer <token>`.

## Parameters

### Path parameters

- `signal_id` (string, required)
- `datasource_id` (string, required)
- `dataset_id` (string, required)

## Example request

```bash
curl "https://api.odysseysignal.app/v1/signals/{signal_id}/datasources/{datasource_id}/datasets/{dataset_id}" \
  -H "X-Api-Key: $ODYSSEY_API_KEY"
```

## Response 200

Content: `application/json`. A DataSet's full self-description: what it holds and how it may be cut.

- `environment` (string, nullable): The data environment the answer was read in, `prod` or `test`: the one Odyssey set on the Signal, or the one an Odyssey person picked for this call.
- `id` (string, required)
- `type` (string, required)
- `name` (string, required)
- `description` (string, nullable)
- `datasource_id` (string, required)
- `contract_version` (string, required)
- `period` (object, required): How this DataSet may be asked about time. The period is a dimension with first-class syntax, so it is described here rather than sitting only in the request schema.
  - `standard` (object, required): The standard period: what a question that names no period is answered at, as the portal opens. Use it unless the user asks for another period.
    - `granularity` (string, required)
    - `rolling` (integer, required): Moving-average window; 1 means none.
    - `complete_only` (boolean, required)
    - `label` (string, required): The portal's name for it, e.g. "Quarter, smoothed (4)".
  - `options` (array of objects, required): Every period this DataSet can be asked about, as the portal's period selector offers them: the standard first, then the other windows at its unit, then the coarser units, then the finer ones. Send one as `period` (with `last` and `ending` as needed); nothing outside this list is answered.
    - `granularity` (string, required)
    - `rolling` (integer, required): Moving-average window; 1 means none.
    - `complete_only` (boolean, required)
    - `label` (string, required): The portal's name for it, e.g. "Quarter, smoothed (4)".
  - `granularities` (array of string, required): Granularities this DataSet may be asked for, finest first.
  - `default_granularity` (string, required): What a question that names no granularity is answered at: the Signal's standard unit, else the data project's.
  - `smallest_bucket` (string, required): The bucket the data is stored at. Nothing finer can be asked for; anything coarser is rolled up.
  - `max_periods` (integer, required): Upper bound on `period.last`.
  - `default_periods` (integer, required)
  - `max_rolling` (integer, required): Upper bound on `period.rolling`, the moving-average window in periods. 1 means no smoothing.
  - `default_rolling` (integer, required): `period.rolling` when the question leaves it out, at `default_granularity`. Other units: `defaults_by_granularity`.
  - `rolling_options` (map of array of integer, required): The `period.rolling` values allowed at each granularity of this DataSet, as in the portal. 1 means no smoothing; any other value is refused.
  - `default_complete_only` (boolean, required): `period.complete_only` when the question leaves it out, at `default_granularity`.
  - `defaults_by_granularity` (map of object, required): The portal's preset per unit: what `rolling` and `complete_only` are when a question names that unit and leaves them out. The answer echoes what was run in `meta.period`.
    - `rolling` (integer, required)
    - `complete_only` (boolean, required)
  - `ending_format` (string, required): Format of `period.ending`. Omit `ending` for the latest available period.
- `languages` (array of string): Languages this DataSet can be read in. **Perception only** — a survey is translated and the other datasets carry one vocabulary everywhere, so an empty list means the question does not arise rather than that none is available. The DataSource's `language` is which of these answers come back in.
- `metric_count` (integer, required): How many metrics this DataSet publishes to this caller. Enough to decide whether to fetch them, which is why the list itself is a separate request.
- `metrics_url` (string, required): Where this DataSet's metrics and their groups are described. Its own endpoint because the list is long — a perception dataset publishes a metric per configured question and each carries the parameters a query needs — and because a caller browsing DataSets is not yet reading metrics.
- `dimensions` (array of objects, required)
  - `id` (string, required)
  - `name` (string, required)
  - `description` (string, nullable)
  - `kind` (string, required): categorical | temporal | entity | derived
  - `filterable` (boolean, required)
  - `groupable` (boolean, required)
  - `multi_select` (boolean, required): Whether a filter on this dimension accepts several values.
  - `values` (array of string, nullable): Members, inline, when they are a closed list the API defines. Otherwise null — fetch `values_url`.
  - `values_url` (string, nullable): Where to enumerate this dimension's members. Present when they come from the data rather than from a fixed list, because which values exist differs per DataSource.
- `query_url` (string, required): Where to POST a query against this DataSet. Published so a client never assembles an action path itself — the one path it cannot get wrong silently.
- `defaults` (object, nullable): What an open question is answered with on this Signal: unit, market, brands, and where each comes from. Only on the Signal-rooted path.
  - `granularity` (string, required): The unit of a question that names none (also `period.default_granularity`).
  - `granularity_source` (string, required): `signal` when the Signal's standard unit, `data_project` when the project's, `api` otherwise. One of `signal`, `data_project`, `api`.
  - `market` (object, required, nullable): The market a question that names none, and does not break down by market, is answered for. Null: the figures pool every market in `pooled_markets`, and the answer warns.
    - `id` (integer, required)
    - `label` (string, required)
    - `source` (string, default "signal", always "signal"): Who set it: Odyssey, on the Signal.
  - `pooled_markets` (integer, required): How many markets an open question pools when there is no standard market.
  - `competitors` (object, required, nullable): The brands a question that names none covers. Null: every brand this Signal may read.
    - `method` (string, required): `list`: the brands in `brands`. `top`: the `count` brands ranked highest by `rank_metric` over the latest twelve months of data, whatever period the question asks, for the markets it runs with, as the portal's top-N; ranked when a question needs them. One of `list`, `top`.
    - `brands` (array of integer, nullable): Brand ids of a `list` set (labels: list_brands or the dimension values).
    - `count` (integer, nullable)
    - `rank_metric` (string, nullable): The metric key a `top` set is ranked by.
    - `source` (string, default "signal", always "signal")
  - `own_brands` (object, nullable): The customer's own brands. Null: the Signal names none. With several, ask which one a question is about.
    - `brands` (array of integer, required): The customer's own brands this Signal may read. A question about one of them names it in `focus`.
    - `standard` (integer, nullable): The own brand added to the default competitors of a question without `focus`, as the portal adds its active brand. Null: none is added.
    - `source` (string, default "signal", always "signal")
  - `notes` (array of string): Each Signal setting that is not applied here, and why.

## Errors

Errors are `application/problem+json` (RFC 9457): `type`, `title`, `status`, `detail` and, for some, more fields that say how to fix the call. The `type` is `https://api.odysseysignal.app/problems/<code>`.

| Status | Code | When |
|---|---|---|
| 400 | `invalid-request` | The request is not valid for this DataSet; `detail` says why. |
| 401 | `unauthorized` | No credential, or one that is not accepted. |
| 403 | `forbidden` | The credential is valid but does not cover what was asked. |
| 404 | `not-found` | Nothing there, or nothing this credential may read. |
| 422 | `validation-failed` | The request does not match the contract; `errors` lists each field. |
| 429 | `rate_limited` | Too many requests, or the monthly quota is used up. |
| 503 | `unavailable` | A service behind the API did not answer; try again. |
