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

# Photo Timeline

> Browse event photos by capture time, with day/hour buckets and windowed pagination

## Overview

The Photo Timeline endpoints let participants discover their photos by **when** they were captured. Use the days endpoint to render a date / hour picker, then fetch a windowed slice of photos with the images endpoint. Photos are bucketed and queried by the capture timestamp recorded on each image; photos without a timestamp are excluded from both endpoints.

<Note>
  Photo timeline must be enabled for the event. Check the `timeline_search` flag from [Event Details](/api-reference/event-details) before calling either endpoint.
</Note>

<Note>
  This endpoint always returns every timestamped photo mapped to the event. It does not honour internal visibility flags such as `show_all_images`.
</Note>

## Endpoints

```
GET /api/v1/ext/{org_id}/event/{event_id}/timeline/days
GET /api/v1/ext/{org_id}/event/{event_id}/timeline/images
```

## Path Parameters

| Parameter  | Type   | Required | Description                                 |
| ---------- | ------ | -------- | ------------------------------------------- |
| `org_id`   | number | Yes      | Your organisation ID.                       |
| `event_id` | number | Yes      | The event whose timeline you want to query. |

## GET /timeline/days — Day and Hour Buckets

Returns per-day and per-hour photo counts for the timeline picker. Days are ordered ascending by date; within each day, `hours` are ordered ascending by hour. Dates are UTC calendar dates in `YYYY-MM-DD` format and hours are UTC hour values (`0`–`23`).

### Query Parameters

This endpoint takes no query parameters.

### Example Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -i \
    -H "X-API-Key: <your_9pic_api_key>" \
    "https://api.9pic.ai/api/v1/ext/903/event/456/timeline/days"
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      "https://api.9pic.ai/api/v1/ext/903/event/456/timeline/days",
      headers={"X-API-Key": "<your_9pic_api_key>"},
  )
  print(response.status_code, response.json())
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    "https://api.9pic.ai/api/v1/ext/903/event/456/timeline/days",
    { headers: { "X-API-Key": "<your_9pic_api_key>" } }
  );
  console.log(await response.json());
  ```
</CodeGroup>

### Example Response

<Tabs>
  <Tab title="Buckets Found">
    ```json theme={null}
    {
      "responseType": "success",
      "message": "Timeline buckets",
      "data": {
        "days": [
          {
            "date": "2024-01-01",
            "total": 125,
            "hours": [
              { "hour": 10, "count": 98 },
              { "hour": 11, "count": 27 }
            ]
          },
          {
            "date": "2024-01-02",
            "total": 42,
            "hours": [
              { "hour": 9, "count": 42 }
            ]
          }
        ]
      }
    }
    ```
  </Tab>

  <Tab title="No Timeline Data">
    ```json theme={null}
    {
      "responseType": "success",
      "message": "No timeline data",
      "data": {
        "days": []
      }
    }
    ```
  </Tab>
</Tabs>

## GET /timeline/images — Windowed Photos

Returns paginated photo objects (large URL, thumbnail URL, image ID, width, height) captured within a `[from, to)` Unix-epoch-second window, ordered by ascending capture timestamp.

### Query Parameters

| Parameter   | Type   | Required | Description                                                               |
| ----------- | ------ | -------- | ------------------------------------------------------------------------- |
| `from`      | number | Yes      | Window start as Unix epoch seconds. Inclusive.                            |
| `to`        | number | Yes      | Window end as Unix epoch seconds. Exclusive. Must be greater than `from`. |
| `page`      | number | No       | Page number (default: `1`).                                               |
| `page_size` | number | No       | Images per page (default: `32`, max: `100`).                              |

<Note>
  This endpoint returns paginated results. See the [Pagination Model](/api-reference/models/pagination).
</Note>

### Example Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -i \
    -H "X-API-Key: <your_9pic_api_key>" \
    "https://api.9pic.ai/api/v1/ext/903/event/456/timeline/images?from=1704103200&to=1704108000&page=1&page_size=32"
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      "https://api.9pic.ai/api/v1/ext/903/event/456/timeline/images",
      headers={"X-API-Key": "<your_9pic_api_key>"},
      params={
          "from": 1704103200,
          "to": 1704108000,
          "page": 1,
          "page_size": 32,
      },
  )
  print(response.status_code, response.json())
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    "https://api.9pic.ai/api/v1/ext/903/event/456/timeline/images?from=1704103200&to=1704108000&page=1&page_size=32",
    { headers: { "X-API-Key": "<your_9pic_api_key>" } }
  );
  console.log(await response.json());
  ```
</CodeGroup>

### Example Response

<Tabs>
  <Tab title="Images Found">
    ```json theme={null}
    {
      "responseType": "success",
      "message": "Records for timeline window",
      "data": {
        "images": [
          {
            "img_url": "https://photos.9pic.ai/imgs/456/large/a4402318-0cf4-4e1e-b8e8-ac8e8f2fc244.jpg",
            "height": 4860,
            "width": 3240,
            "image_id": "a4402318-0cf4-4e1e-b8e8-ac8e8f2fc244",
            "thumbnail_url": "https://photos.9pic.ai/imgs/456/small/a4402318-0cf4-4e1e-b8e8-ac8e8f2fc244.jpg",
            "original_url": null
          },
          {
            "img_url": "https://photos.9pic.ai/imgs/456/large/b5513429-1d05-5f2f-c9f9-bd9f9g3gd355.jpg",
            "height": 4860,
            "width": 3240,
            "image_id": "b5513429-1d05-5f2f-c9f9-bd9f9g3gd355",
            "thumbnail_url": "https://photos.9pic.ai/imgs/456/small/b5513429-1d05-5f2f-c9f9-bd9f9g3gd355.jpg",
            "original_url": null
          }
        ],
        "pagination": {
          "total": 125,
          "currentPage": 1,
          "totalPages": 4,
          "hasNextPage": true,
          "hasPreviousPage": false,
          "page_size": 32
        }
      }
    }
    ```
  </Tab>

  <Tab title="Empty Window">
    ```json theme={null}
    {
      "responseType": "success",
      "message": "No images found",
      "data": {
        "images": [],
        "pagination": {
          "total": 0,
          "currentPage": 0,
          "totalPages": 0,
          "hasNextPage": false,
          "hasPreviousPage": false,
          "page_size": 32
        }
      }
    }
    ```
  </Tab>
</Tabs>

## Response Models

| Model                                                                                              | Description                                            |
| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| <a href="/api-reference/models/search-responses#timelinedaysresponse">TimelineDaysResponse</a>     | Top-level envelope for `GET /timeline/days`.           |
| <a href="/api-reference/models/search-responses#timelinedayitem">TimelineDayItem</a>               | One date bucket inside `data.days[]`.                  |
| <a href="/api-reference/models/search-responses#timelinehourbucket">TimelineHourBucket</a>         | One hour bucket inside `data.days[].hours[]`.          |
| <a href="/api-reference/models/search-responses#timelineimagesresponse">TimelineImagesResponse</a> | Top-level envelope for `GET /timeline/images`.         |
| <a href="/api-reference/models/image">ImageItem</a>                                                | Image object returned inside `data.images[]`.          |
| <a href="/api-reference/models/pagination">PaginationInfo</a>                                      | Pagination metadata returned inside `data.pagination`. |

<Tip>
  `original_url` is `null` in the timeline response. Use [Download Original Photos](/api-reference/download-original-photos) with `method: "image_ids"` to fetch presigned download links for the originals once a participant picks photos from their window.
</Tip>

## Error Responses

| Status | Meaning                                                                                                     |
| ------ | ----------------------------------------------------------------------------------------------------------- |
| `400`  | `to` is not greater than `from`.                                                                            |
| `401`  | API key is missing.                                                                                         |
| `403`  | API key is invalid, inactive, token/event ownership mismatch, or photo timeline is disabled for this event. |
| `404`  | Event configuration not found.                                                                              |
| `422`  | Required `from` or `to` query parameter is missing or not an integer.                                       |
| `429`  | Rate limit exceeded. Back off and retry.                                                                    |
| `500`  | Internal failure.                                                                                           |

See [Errors](/api-reference/errors) for canonical descriptions and retry guidance.
