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

# List periods

> List when this DataSource has data, in total and per DataSet

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

`GET /v1/signals/{signal_id}/datasources/{datasource_id}/periods`

The total is what the DataSource covers; the per-DataSet lists are what each can actually answer for, and they differ. Periods outside this Signal's wave window are absent from both.

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

## Parameters

### Path parameters

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

## Example request

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

## Response 200

Content: `application/json`. When this DataSource has data — in total, and per DataSet.

**Both, because they answer different questions.** The total is what the
DataSource covers and is what a consumer picking a date range wants; the
per-DataSet lists are what each DataSet can actually answer for, and they
can differ a great deal. A period id means the same thing in every
DataSet, so the total is their union.

Periods outside this Signal's wave window are absent from both, since a
query could never reach them.

- `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.
- `datasource_id` (string, required)
- `granularity` (string, required): The bucket period ids are stated in. Months — the smallest a wave is stored at, so every coarser granularity a DataSet offers is a grouping of these.
- `total` (object, required): The union across every readable DataSet.
  - `count` (integer, required)
  - `first` (string, nullable): Id of the earliest period, or null when there are none.
  - `last` (string, nullable): Id of the latest period. What an unanchored query ends on.
  - `periods` (array of objects, required)
    - `id` (string or integer, required)
    - `label` (string, required)
    - `group` (string, nullable)
    - `type` (string, nullable)
    - `description` (string, nullable)
    - `demand_space` (object, nullable): For an attribute: the demand space the survey assigns it to. Absent where there is none.
      - `id` (integer, required)
      - `label` (string, required)
- `datasets` (array of objects, required)
  - `count` (integer, required)
  - `first` (string, nullable): Id of the earliest period, or null when there are none.
  - `last` (string, nullable): Id of the latest period. What an unanchored query ends on.
  - `periods` (array of objects, required)
    - `id` (string or integer, required)
    - `label` (string, required)
    - `group` (string, nullable)
    - `type` (string, nullable)
    - `description` (string, nullable)
    - `demand_space` (object, nullable): For an attribute: the demand space the survey assigns it to. Absent where there is none.
      - `id` (integer, required)
      - `label` (string, required)
  - `dataset_id` (string, required)
  - `url` (string, required)

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