API
Introduction
The Sahha API lets you manage user profiles, upload data, and retrieve scores, biomarkers, archetypes, and insights. All endpoints use JSON and return standard HTTP status codes.
Authentication
Sahha uses token-based authentication. You'll work with two types of tokens depending on your use case:
| Token Type | Use Case | Header Format |
|---|---|---|
| Account Token | Server-to-server operations: create profiles, query any user's data by externalId | Authorization: account {token} |
| Profile Token | Single-user operations: query own data, update demographics | Authorization: profile {token} |
Find your clientId and clientSecret in the Sahha Dashboard under API Keys.
How It Works
- Get an Account Token — Exchange your
clientIdandclientSecretfor an account token - Create Profiles — Register user profiles via account token (server-side) or AppId/AppSecret headers (SDK) to receive a profile token and refresh token
- Access Data — Use account tokens (server-side) or profile tokens (client-side) to retrieve data
Which token should I use?
- Building a backend service? Use your Account Token to manage all profiles and query data by
externalId - Building a client app? Use Profile Tokens so each user can only access their own data
Token Details
| Aspect | Details |
|---|---|
| Expiration | Tokens expire after 24 hours |
| Refresh | Use the refreshToken from registration to get a new profile token via /oauth/profile/refreshToken |
| Storage | Store tokens securely; never expose client secrets in client-side code |
Quick Start
1. Get an Account Token
Exchange your credentials for an account token.
curl -X POST https://api.sahha.ai/api/v1/oauth/account/token \ -H "Content-Type: application/json" \ -d '{ "clientId": "your-client-id", "clientSecret": "your-client-secret" }' curl -X POST https://api.sahha.ai/api/v1/oauth/account/token \
-H "Content-Type: application/json" \
-d '{
"clientId": "your-client-id",
"clientSecret": "your-client-secret"
}'
Response:
{ "accountToken": "eyJhbGciOiJIUzI1NiIs...", "expiresIn": 86400} {
"accountToken": "eyJhbGciOiJIUzI1NiIs...",
"expiresIn": 86400
}
2. Create a Profile
Register a user profile using your account token:
curl -X POST https://api.sahha.ai/api/v1/oauth/profile/register \ -H "Authorization: account your-account-token" \ -H "Content-Type: application/json" \ -d '{ "externalId": "user-123" }' curl -X POST https://api.sahha.ai/api/v1/oauth/profile/register \
-H "Authorization: account your-account-token" \
-H "Content-Type: application/json" \
-d '{
"externalId": "user-123"
}'
Response:
{ "profileToken": "eyJhbGciOiJIUzI1NiIs...", "expiresIn": 86400, "tokenType": "Profile", "refreshToken": "hIw0LuHXHZKMD7bWV0Dl..."} {
"profileToken": "eyJhbGciOiJIUzI1NiIs...",
"expiresIn": 86400,
"tokenType": "Profile",
"refreshToken": "hIw0LuHXHZKMD7bWV0Dl..."
}
3. Retrieve Scores
Fetch health scores for a profile:
curl "https://api.sahha.ai/api/v1/profile/score/user-123?types=activity,sleep" \ -H "Authorization: account your-account-token" curl "https://api.sahha.ai/api/v1/profile/score/user-123?types=activity,sleep" \
-H "Authorization: account your-account-token"
With a profile token , omit the externalId from the path — the token identifies the profile: /api/v1/profile/score?types=activity,sleep
Response:
[ { "type": "activity", "value": 72.5, "state": "medium", "createdAt": "2024-01-15T10:30:00Z", "factors": [] }] [
{
"type": "activity",
"value": 72.5,
"state": "medium",
"createdAt": "2024-01-15T10:30:00Z",
"factors": []
}
]
Endpoints Summary
Quick overview of available endpoints.
Authentication
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | /api/v1/oauth/account/token | Get account token | None (uses clientId/clientSecret) |
| POST | /api/v1/oauth/profile/register | Register profile, get profile token | Account |
| POST | /api/v1/oauth/profile/register/appId | Register profile via SDK credentials | AppId/AppSecret headers |
| POST | /api/v1/oauth/profile/token | Get profile token for existing profile | Account |
| POST | /api/v1/oauth/profile/refreshToken | Refresh profile token | Profile |
Manage Profiles
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /api/v1/account/profile/{externalId} | Get profile by externalId | Account |
| GET | /api/v1/account/profile/search | Search profiles | Account |
| DELETE | /api/v1/profile | Delete profiles | Account |
Upload Data
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | /api/v1/profile/data/log | Post data logs | Profile |
Retrieve Profile Data
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /api/v1/profile/score | Get scores | Profile |
| GET | /api/v1/profile/score/{externalId} | Get scores by externalId | Account |
| GET | /api/v1/profile/biomarker | Get biomarkers | Profile |
| GET | /api/v1/profile/biomarker/{externalId} | Get biomarkers by externalId | Account |
| GET | /api/v1/profile/archetypes | Get archetypes | Profile |
| GET | /api/v1/profile/archetypes/{externalId} | Get archetypes by externalId | Account |
| GET | /api/v1/profile/insight/trend | Get trends | Profile |
| GET | /api/v1/profile/insight/trend/{externalId} | Get trends by externalId | Account |
| GET | /api/v1/profile/insight/comparison | Get comparisons | Profile |
| GET | /api/v1/profile/insight/comparison/{externalId} | Get comparisons by externalId | Account |
Profile Metadata
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /api/v1/profile/demographic | Get demographics | Profile |
| PUT | /api/v1/profile/demographic | Replace demographics | Profile |
| PATCH | /api/v1/profile/demographic | Update demographics | Profile |
| GET | /api/v1/profile/deviceInformation | Get device info | Profile |
| PUT | /api/v1/profile/deviceInformation | Update device info | Profile |
Common Query Parameters
| Parameter | Type | Description |
|---|---|---|
startDateTime | ISO 8601 | Filter results from this date/time |
endDateTime | ISO 8601 | Filter results until this date/time |
types | string[] | Filter by type (e.g., activity, sleep) |
categories | string[] | Filter by category |
periodicity | string | Filter by periodicity ( daily, weekly) |
Response Codes
| Code | Status | Description |
|---|---|---|
200 | OK | Request successful |
201 | Created | Profile registered successfully |
204 | No Content | Request successful but no data found for the query |
400 | Bad Request | Invalid parameters, malformed request, or externalId already in use |
401 | Unauthorized | Missing, invalid, or expired token |
Handling 204 responses
A 204 response means the request was valid but there's no data yet—common for new profiles or date ranges with no activity. Don't treat this as an error.
Best Practices
- Secure your credentials — Store
clientIdandclientSecretin environment variables, never in client-side code - Handle token expiration — Tokens expire in 24 hours; implement automatic refresh logic
- Use appropriate authorization — Use account tokens server-side, profile tokens client-side
- Filter your queries — Use
startDateTimeandendDateTimeto limit response size - Handle errors gracefully — Check for
401(invalid token) and400(bad request) responses
Support
Need help? Contact support@sahha.ai or join the Slack Community .