Wearable devices generate a huge amount of health data — the information is there, but turning it into something meaningful is a challenge.
Companies building health experiences run into the same problem: collecting data is just the beginning. The real work starts when you need to normalize information across devices, combine different metrics, calculate trends, and generate insights users can actually understand and act on.
That's why ROOK built the
User Health Profile
.
One profile, built from hundreds of health signals
The User Health Profile is a new ROOK feature that transforms wearable data into a structured health profile.
Instead of working with dozens of disconnected metrics, developers get a single profile organized into five key areas:
  • Activity
  • Sleep
  • Cardiovascular exercise
  • Recovery
  • Body care
Each profile includes normalized metrics, health scores, historical trends, and personalized insights generated from the user's recent wearable data. The system analyzes the last seven days of health information before generating the profile, giving applications a broader view than individual daily measurements can offer.
Beyond raw data
Collecting health data is relatively straightforward — creating meaningful context is much harder.
The User Health Profile combines multiple processing stages to turn raw wearable data into information applications can use right away:
  • Aggregates health data from multiple sources
  • Calculates standardized scores for each health domain
  • Detects improvements and declines over time
  • Generates personalized insights
  • Delivers the complete profile through a webhook
This lets teams focus on building user experiences instead of designing scoring models, trend calculations, and health interpretation engines from scratch.
Integrate it fast
The User Health Profile integrates directly into your existing ROOK integration.
Customers request a profile through the API, and ROOK handles everything internally — from data validation and aggregation to scoring, storage, and webhook delivery — improving efficiency and response times.
How to integrate User Health Profile
The integration works in two steps:
  1. Your application requests the profile through the API.
  2. ROOK processes the information and sends the result to your webhook.
API request
The
user_profile
endpoint:
POST /api/v2/user_profile
Send only the user identifier:
{
"user_id": ""
}
Example:
curl --request POST \
--url "https://api.tryrook.io/api/v2/user_profile" \
--header "Authorization: Basic <base64(client_uuid:password)>" \
--header "Content-Type: application/json" \
--data '{
"user_id": "user-12345"
}'
ROOK gets the
client_uuid
from authentication and internally generates a
request_id
and the request date. The API responds with
202 Accepted
and returns the request identifier:
{
"message": "User profile request queued",
"request_id": "<uuid>"
}
How it works
ROOK analyzes the user's available data, primarily from the last seven days, and builds five sub-profiles:
  • Activity
  • Sleep
  • Cardio
  • Recovery
  • Body
Each sub-profile can include:
  • Aggregated metrics
  • A score from zero to 100
  • A health level
  • A trend
  • Information about data coverage
The result also includes an overall user score.
What happens if a data point is missing
A missing metric is not interpreted as a bad result.
For example:
  • Having a low step count can produce a low score.
  • Having no step data at all means the value is unknown.
When a metric is missing, ROOK uses the other available metrics. The lack of information is reflected in the profile's confidence or coverage.
When there isn't enough data to calculate a sub-profile, its values may come back as null:
{
"score_int": null,
"level_string": null,
"trend_string": null
}
If there isn't enough information to generate any sub-profile, ROOK doesn't generate or send the profile.
Webhook response
When the profile is ready, ROOK sends it to the configured webhook:
{
"version": 1,
"document_version": <int>,
"data_structure": "user_profile",
"user_id": "<external_id_without_suffix>",
"client_uuid": "<client_uuid>",
"user_profile_data": {
"metadata": {
"datetime_string": "<YYYY-MM-DDTHH:MM:SS.ffffff±HH:MM>",
"user_id_string": "<external_id_without_suffix>",
"request_id_string": "<request_id>"
},
"demographics": { ... },
"profiles": { ... },
"overall": { ... },
"insights": [ ... ]
}
}
Your application must respond to the webhook with
200
,
201
, or
202
. If delivery fails, ROOK schedules retries.
Usage limits
The API allows:
  • Three requests per hour
  • 30 requests within a 24-hour window from the first request
Limits apply per user and per client.
User Health Profile FAQ
What is User Health Profile?
User Health Profile is a ROOK feature that transforms wearable data into a structured health profile.
The profile organizes information into five areas:
  • Activity
  • Sleep
  • Cardio
  • Recovery
  • Body
It also includes scores, trends, and personalized insights.
What problem does it solve?
It lets companies use processed health information without having to build their own aggregation, scoring, trend, and insight systems.
ROOK takes care of converting data from different sources into a consistent, integration-ready structure.
How is a profile requested?
ROOK gets the
client_uuid
from authentication and internally generates a
request_id
and the request date. The API responds with
202 Accepted
and returns the request identifier:
{
"message": "User profile request queued",
"request_id": "<uuid>"
}
Does the API return the profile immediately?
No. The flow is asynchronous.
The API receives the request, and ROOK processes the profile in the background. When the result is ready, we send it to the webhook configured by the client.
What information does ROOK use?
ROOK looks at the user's previously synced data, including:
  • Daily activity
  • Workouts
  • Sleep
  • Heart rate
  • HRV
  • Weight and other body metrics
  • Available demographic information
The main analysis window covers the last seven days. For some recovery calculations, ROOK may look at up to 14 days of sleep data.
Does User Health Profile connect directly to the wearable?
No. The profile is built from data that has already been synced and stored in ROOK. The user must first connect a supported data source and allow their data to sync.
What does each sub-profile include?
Each sub-profile includes:
  • Aggregated metrics
  • A score from zero to 100
  • A level
  • A trend
  • Information about data coverage
The exact information depends on the metrics available for each user.
How are levels interpreted?
Scores are classified as follows:
  • 80–100
    : Optimal
  • 65–79
    : Good
  • 50–64
    : Moderate
  • 30–49
    : Poor
  • Below 30
    : Critical
These values help summarize the available information, but they don't represent a medical diagnosis.
What happens if a metric is missing?
ROOK doesn't interpret missing data as a negative result. For example, having no step data isn't the same as having a low step count. When a metric isn't available, the system uses the other valid metrics and reflects the missing information in the result's coverage or confidence.
How does HRV availability affect the Cardio and Recovery profiles?
HRV is a particularly important metric for the Cardio and Recovery profiles. It accounts for 30% of the Cardio calculation, and in Recovery, HRV together with its variation from baseline accounts for 60% of the score.
If a user's data source doesn't provide HRV, ROOK doesn't interpret the absence as a negative value or assign a score of zero. Instead, it calculates the sub-profile using the available metrics and adjusts the weighting between them. This reduced data availability is reflected in the result's coverage or confidence.
As a result, without HRV, Cardio can be calculated using roughly 70% of the originally weighted metrics, and Recovery around 40%. If other required metrics are also missing, the sub-profile's score, level, or trend may come back as null.
For this reason, Cardio and Recovery offer more complete coverage mainly for users with sources that report HRV, such as Oura, Whoop, Garmin, and Polar. For sources that don't provide HRV, such as Fitbit under current coverage, these sub-profiles may show lower confidence or may not have enough data to be calculated.
What happens if there's no information for a sub-profile?
When there aren't enough metrics to calculate a sub-profile, its fields may come back as null:
{
"score_int": null,
"level_string": null,
"trend_string": null
}
That sub-profile should not be interpreted as a score of zero.
What happens if there isn't enough data to generate any profile?
ROOK doesn't generate or send an empty profile. In that case, processing ends with an internal insufficient-data result, and no webhook is sent.
How is the overall score calculated?
The overall score combines the five sub-profiles with the following weights:
  • Activity: 20%
  • Sleep: 25%
  • Cardio: 25%
  • Recovery: 20%
  • Body: 10%
Sub-profiles without usable data should not be treated as negative values.
How do trends work?
ROOK compares the current score with the last available previous profile for the same user. The trend can be:
  • improving
  • declining
  • stable
  • null
We use a stability band of approximately ±5%. The trend will be null when there's no previous profile or when one of the required scores isn't available.
What are insights?
Insights are observations generated from predefined rules. They can point to:
  • Risks
  • Trends
  • Positive patterns
  • Relationships between different areas of the profile
Each insight includes a confidence value tied to the coverage of the data used to generate it. It does not represent diagnostic certainty.
How many insights can a user receive?
There's no defined maximum limit.
ROOK delivers the insights that meet the rules after removing duplicates and resolving conflicting messages.
How is the profile delivered?
ROOK sends the profile via a POST request to the webhook configured by the client.
Simplified example:
{
"version": 1,
"document_version": <int>,
"data_structure": "user_profile",
"user_id": "<external_id_without_suffix>",
"client_uuid": "<client_uuid>",
"user_profile_data": {
"metadata": {
"datetime_string": "<YYYY-MM-DDTHH:MM:SS.ffffff±HH:MM>",
"user_id_string": "<external_id_without_suffix>",
"request_id_string": "<request_id>"
},
"demographics": { ... },
"profiles": { ... },
"overall": { ... },
"insights": [ ... ]
}
}
What should the webhook respond with?
The client's endpoint must respond with one of these codes:
  • 200 OK
  • 201 Created
  • 202 Accepted
Any other response code — including other 2xx codes such as 204 — or a timeout is treated as a failed delivery. After a successful delivery, ROOK marks the profile as synced.
What happens if the webhook fails?
ROOK keeps the profile pending and attempts to deliver it again, up to 3 additional attempts after the initial failure, following this sequence:
  • First retry: ~2 hours after the initial failure
  • Second retry: ~24 hours after the first retry
  • Third retry: ~24 hours after the second retry
If all four delivery attempts fail (the initial one plus the three retries), ROOK flags the document for deletion after 10 days. The total window is approximately 50 hours.
How can webhook authenticity be verified?
In webhooks compatible with version two, ROOK includes the header:
X-ROOK-HASH
The client must validate this signature before processing the content.
What is document_version?
document_version
identifies the profile's version. The first generation uses version one. When ROOK recalculates the profile, it increments this value. Clients can use it to avoid duplicates or ignore older versions.
Does ROOK recalculate the profile on every request?
Not necessarily. ROOK uses two filters to detect whether the data or metrics changed. When there are no changes, it can reuse the existing profile and resend it to the webhook without running the full processing pipeline.
Does the profile update automatically when new data arrives?
No. The profile is generated on demand. If new data arrives after the calculation, the client must request a new generation.
Are there usage limits?
Yes. Limits apply per client and per user:
  • Three requests per hour
  • 30 requests within a 24-hour window from the first request
When the limit is exceeded, the API responds with
429 Too Many Requests
and includes the following headers so the client can retry correctly:
  • X-RateLimit-Limit-Hour
    : request limit per hour
  • X-RateLimit-Remaining-Hour
    : requests remaining in the current hour
  • X-RateLimit-Limit-Day
    : request limit per day
  • X-RateLimit-Remaining-Day
    : requests remaining in the current day
  • Retry-After
    : seconds to wait before retrying
What happens if the client doesn't have access to the feature?
The API responds with:
{
"error": "Forbidden",
"exception": "feature_not_included",
"path": "/api/v2/user_profile",
"method": "POST"
}
This means the User Health Profile entitlement isn't enabled for the client.
Does User Health Profile provide medical diagnoses?
No. User Health Profile organizes, summarizes, and interprets available data using rules and scoring models. Results should be used as contextual information, not as a medical diagnosis, treatment, or recommendation.