Requesting historical health data (REST API requests)
Learn how to request for historical data to be sent to your destination through the REST API
Overview
Terra API is event-based, meaning you don’t need to manually request data via the API.
For new and ongoing data updates, Terra API automatically sends them to your configured Data Destination (e.g. Webhook, Database, or cloud storage bucket).
If you need historical user data, you can request it using the Health & Fitness API endpoints by specifying the user ID, data type, and time range. This allows you to request past records on demand.
In this guide you will learn:
When are historical data requests useful?
How to use the Terra Dashboard to make a historical data request?
How to use the Terra's Health & Fitness API to make a historical data request?
Request Parameters (e.g. send to destination and include samples)
How to handle requests of very long time ranges ?
Prerequisites
In order to receive Data as Events, you'll need to:
API Key & dev-id: Obtain your Terra API Key and dev-id from your Terra Dashboard
Destination Configured: Set up a Data Destination where Terra will send event and data updates.
Data Sources Enabled: Enable the specific data sources your app requires (e.g., activity, sleep).
Connected at least a user. Requests are done using a
user_id
and at least a date.The User must be connected via Terra's Health & Fitness API.
The
user_id
is needed to make requests for historical data
1. When to request historical data?
a. Upon creating a New User
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.
Time Range limits in Historical Data Requests
Some providers impose limits on how far back a developer can request data. Those are:
Garmin: 5 years into the past, from the current point in time. This is subject to Garmin's backfill limits.
Polar: 30 days into the past, but not prior to the moment the user granted permission.
Health Connect: 30 days into the past, but not prior to the moment the user granted permission.
b. As a "pull down to refresh" functionality
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.
2. Request Data via 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.
3. Request Data via the API
To request historical data from your Backend, you need to call one of the Data Retrieval Endpoints. Refer to the API endpoints section for further details on usage.
Request Usage
Refer to the API endpoints section for further details on usage.
1. Required Parameters:
To request historical data, the following request parameters are required:
user_id
(required)start_date
(required)
2. Optional Parameters
Terra's Data Retrieval endpoints include many other useful and important parameters.
with_samples
must be set totrue
to receive granular data (refer toIntegration setup)to_webhook
must be set totrue
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 tofalse
.
Handling Asynchronous Data Retrievals
When making a
to_webhook=true
request, keep track of the value of theterra-reference
header.When the event is eventually sent to your Data Destination, the event's
terra-signature
will match that of the initial request, allowing you to mark off the data transfer as successfully completed.
API Request Example (Python)
Taking Python FastAPI as an example framework, you may set up your server code to look like the following:
@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"}
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
Request longer time ranges
Following a large request, you will receive the following:
1. "Large Request Processing" Event
You will immediately receive a Event Types event.
This indicates that Terra has acknowledged the large request and is currently processing the data retrieval from the Provider.
2. "Large Request Sending" Event
Once data retrieval has finished, Terra will organise the data into chunks, and send a Event Types payload, indicating the number of payloads to expect.
3. Chunks
When a large request is made, Terra will send the data to you in chunks of:
at most 10MB
at most 10 objects in the
data
array
The chunk size will be limited by whichever of the two limits gets hit first.
4. Header
ALL chunks will 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.
Last updated
Was this helpful?