> For the complete documentation index, see [llms.txt](https://docs.tryterra.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tryterra.co/unified-api/requesting-historical-data.md).

# Historical data requests

Request a user's past data from the Unified API, either to your destination or in the response.

Terra is event-based: new and ongoing data reaches your destination (e.g. webhook, database, or cloud storage bucket) without any requests from you. To get data from before a user connected, request it from the Unified API endpoints by user ID, data type and time range.

## Before you begin

* Get your **API key** and **dev ID** from the [Terra dashboard](https://dashboard.tryterra.co/).
* [Set up a destination](/destinations/setting-up-data-destinations.md) where Terra sends event and data updates.
* [Enable the data sources](/unified-api/setting-up-data-sources.md) your app requires.
* [Connect at least one user](/unified-api/authentication-flow.md) through the Unified API. Requests take that user's `user_id` and at least a start date.

## When to request historical data

### When a user first connects

When an end user first connects an account (e.g. wearable, device, health app), you will by default only receive data from that point onwards.

If you would like to **build a historical health & fitness profile of the user,** to establish **baselines** for statistics, or for any other calculations, you can make a request to Terra for data from prior to the user's authentication.

{% hint style="info" %}
**Time range limits**

Some [providers](/unified-api/setting-up-data-sources.md) impose limits on how far back a developer can request data. Those are:

* **Garmin**: Garmin sets how far back history goes for each Garmin app. History is only available for users who enabled Garmin's historical data permission.
* **Polar**: workouts go back 30 days into the past, but not prior to the moment the user granted permission. Sleep and daily data go back about a year, including from before the user granted permission.
* **Coros:** 3 months into the past, from the current point in time, or 24 hours prior to the user's authentication. Whichever of the two limits gets hit first gets applied
* **Health Connect**: 30 days into the past, but not prior to the moment the user granted permission.
  {% endhint %}

### As a refresh fallback

As a **fallback**, you should implement a "pull down to refresh" functionality or alternative (like a sync now button, etc...).

Hitting this button should trigger a data pull of the last e.g. 14 days of data for the user, for all the data types you ingest.

## Request data from the dashboard

You may want your customer support team to use the Terra dashboard to debug by re-sending data, or verifying whether or not Terra fetches the data correctly. See the guide below for a step by step tutorial on how to do so.

{% embed url="<https://app.guideflow.com/player/dr96elwaor>" %}

## Request data from the API

To request historical data from your **backend**, call one of the [Data Retrieval Endpoints](https://docs.tryterra.co/reference#historical-data-retrieval). Refer to the [API endpoints](https://docs.tryterra.co/reference) section for further details on usage.

{% prompt description="Pull a user's historical data without sending it to your webhook" icon="terminal" openInAIProviders="true" defaultExpanded="full" %}

```markdown
Pull the last 30 days of sleep and daily data for user 8f2a1c and show me the payload shape, without sending it to my webhook.

Use the Terra CLI: brew install tryterra/tap/terra, or npm install -g @tryterra/cli, then terra login. Run terra docs ask --question "<question>" for anything you need from the Terra docs, and terra <command> --help for usage.
```

{% endprompt %}

### Request parameters

**Required parameters**

* `user_id`
* `start_date`

**Optional parameters**

Terra's Data Retrieval endpoints include many other useful and important parameters.

1. `with_samples` must be set to `true` to receive granular data (see [Choose data types](/unified-api/setting-up-data-sources.md#choose-data-types)).
2. `to_webhook` must be set to `true` if you want to receive data asynchronously to your Destination. For synchronous data retrieval (if your use case is time-sensitive), just set this parameter to `false`. It defaults to `true` if not provided.
3. `end_date` is exclusive on these endpoints. Data is returned up to but not including this date, so pass the day after the last day you want.

{% hint style="info" %}
**Handling asynchronous data retrievals**

When making a `to_webhook=true` request, keep track of the value of the `terra-reference` header. When the event is eventually sent to your webhook, the event's `terra-reference` will match that of the initial request, allowing you to mark off the data transfer as successfully completed
{% endhint %}

### Example: backfill after a user connects

Taking **Python FastAPI** as an example framework, you may set up your server code to look like the following:

{% code title="Python" lineNumbers="true" %}

```python
@app.post("/webhook")
async def webhook_handler(request: Request):
    payload = await request.json()
    
    if payload.get("type") == "auth" and payload.get("status") == "success":
        # Calculate date range, to get data from 28 days ago to today
        start_date = (datetime.utcnow() - timedelta(days=28)).strftime('%Y-%m-%d')
        end_date = (datetime.utcnow() + timedelta(days=1)).strftime('%Y-%m-%d')
        headers = {
            "x-api-key": os.getenv("TERRA_API_KEY"), 
            "dev-id": os.getenv("TERRA_DEVELOPER_ID")
        }
        endpoints = [
            "/activity", 
            "/daily", 
            "/sleep", 
            "/body"
        ]

        # Fetch data from each endpoint
        results = {}
        for endpoint in endpoints:
            try:
                response = requests.get(
                    f"{TERRA_API_URL}{endpoint}", 
                    headers=headers, 
                    params={
                        "start_date": start_date, 
                        "end_date": end_date,
                        "to_webhook": True
                        }
                    )
                response.raise_for_status()
                results[endpoint] = response.json()
            except requests.HTTPError as e:
                raise HTTPException(status_code=response.status_code, detail=f"Error fetching data from {endpoint}")

        return {"message": "Data fetched successfully", "data": results}
    
    return {"message": "Webhook type or status did not match criteria"}
```

{% endcode %}

## Request longer time ranges

Time ranges longer than one month must use `to_webhook=true`, and Terra sends the data **asynchronously**. The same request with `to_webhook=false` returns a `400`. This is due to the large amounts of data being transferred, which would hang the request making/handling process for >30 seconds.

Following a large request, you will receive the following:

1. **"Large request processing" event**: you will immediately receive a [https://docs.tryterra.co/reference/health-and-fitness-api/event-types#large-request-processing](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#large-request-processing "mention") event. This indicates that Terra has acknowledged the large request and is currently processing the data retrieval from the [Provider](https://docs.tryterra.co/introduction/core-concepts#sources).
2. **"Large request sending" event**: once data retrieval has finished, Terra will organise the data into chunks, and send a [https://docs.tryterra.co/reference/health-and-fitness-api/event-types#large-request-sending](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#large-request-sending "mention") payload, indicating **the number of payloads to expect.**
3. **Chunks**: Terra sends the data to you in chunks of at most 10MB each.
4. **Header**: all chunks contain the **same** `terra-reference` header value. Once the number of payloads indicated with the same `terra-reference` header value have been received, you can consider the data transfer request complete.

## Next steps

* [Writing data to providers](/unified-api/write-data.md): send planned workouts back to a user's provider.
* [Event delivery](/destinations/events.md): track deliveries, retries and resends of the data you requested.
* [Troubleshooting](/unified-api/debugging-faq.md): find out why requested data did not arrive.
