Overview
Endpoints
More
Exposed API Documentation
Two endpoints for external integrators: authenticate with app credentials, then call the health gateway with the returned JWT.
https://dev-relay-backend.agent.scanbo.ai/api/v1
Access
Client credentials
Generate Client ID and Secret from OAuth / API before testing.
Headers
Tenant + country
Every request should include x-tenant-id and x-country-code.
Testing
Built-in runner
Use API Testing to inspect request, response, status, and latency.
Getting Started
Before calling any API, complete these 3 steps on the Relay platform.
Sign up or Sign in
Create your account on the Relay platform. Use the link below to open the portal.
https://dev-relay-backend.agent.scanbo.ai ->Create an Application
Go to Dashboard -> Applications -> New Application and fill in the required fields:
Go to Dashboard → Applications → New Application and fill in the required fields:
App Name — A unique name to identify your application
Webhook URL — Your server endpoint to receive health data events
Redirection URL — OAuth callback URL after user authorizes a device
Select Devices — Choose which health providers to enable (Apple Health, Oura, Fitbit, etc.)
Generate OAuth / API Credentials
Inside your application, go to OAuth / API Keys and generate credentials. You will get a Client ID and Client Secret — use these in the two APIs documented below.
Once you have your credentials, proceed to the App Credentials endpoint below to get your JWT token and start calling the Health Gateway.
Common Requirements
All requests under /api/v1 require tenant headers unless noted otherwise.
| Header | Required | Example | Description |
|---|---|---|---|
Content-Type | Yes (POST) | application/json | JSON request body |
x-country-code | Yes | IN | ISO country code (IN, US, EU, AE...) |
x-tenant-id | Yes* | relay-health-default | Tenant slug or ObjectId |
* In development, server may fall back to DEFAULT_TENANT_ID from environment.
Standard response envelope
JSON
{
"success": true,
"code": 200,
"message": "Human-readable message",
"data": { }
}Get User by App Credentials
Authenticate a registered application with client credentials. Returns user profile, JWT tokens, and active connector sources.
/api/v1/
Auth
None (body credentials)
Dispatcher field
routname
Value
get-user-by-app-credentials
Request
HTTP
POST /api/v1/ HTTP/1.1 Host: dev-relay-backend.agent.scanbo.ai Content-Type: application/json x-country-code: IN x-tenant-id: relay-health-default
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
routname | string | Yes | get-user-by-app-credentials |
clientId | string | Yes | App client ID |
clientSecret | string | Yes | App client secret |
applicationId | string | Yes* | Registered application ID |
JSON · Request
{
"routname": "get-user-by-app-credentials",
"clientId": "relay_app_client_7f3a9c2e1b",
"clientSecret": "sk_live_fake_8Qm2pL9xR4vN6wK1",
"applicationId": "674a1b2c3d4e5f6789012345"
}Success Response
JSON
{
"success": true,
"code": 200,
"message": "User retrieved successfully",
"data": {
"user": {
"id": "674901234567890123456789",
"firstName": "Priya",
"email": "priya.sharma@example-health.app",
"role": "user",
"userStatus": "active"
},
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"activeDevices": [
{ "key": "strava", "name": "Strava", "status": "active" },
{ "key": "oura", "name": "Oura Ring", "status": "ACTIVE" }
]
}
}Use data.accessToken as the Bearer token for Health API calls.
Error Responses
JSON
{ "success": false, "message": '"clientId" is required.', "code": 422 }JSON
{ "success": false, "message": "Invalid client credentials.", "code": 401 }JSON
{ "success": false, "message": "App credentials are inactive.", "code": 403 }cURL
Bash
curl -X POST 'https://dev-relay-backend.agent.scanbo.ai/api/v1/' \
-H 'Content-Type: application/json' \
-H 'x-country-code: IN' \
-H 'x-tenant-id: relay-health-default' \
-d '{
"routname": "get-user-by-app-credentials",
"clientId": "relay_app_client_7f3a9c2e1b",
"clientSecret": "sk_live_fake_8Qm2pL9xR4vN6wK1",
"applicationId": "674a1b2c3d4e5f6789012345"
}'Health API Gateway
Unified entry for wearable health operations. Uses routeName (camelCase), not routname.
/api/v1/health
Auth
Bearer accessToken
Public routes
connectOura, connectStrava...
Supported routeName values
| routeName | Auth | Purpose |
|---|---|---|
getAllHealthData | Yes | Aggregated health metrics from connected providers |
getUserProfile | Yes | Profile data per connected source |
getConnectionStatus | Yes | Provider link status and last sync |
connectOura | No | Start Oura OAuth flow |
connectStrava | No | Start Strava OAuth flow |
connectFitbit | No | Start Fitbit OAuth flow |
disconnectConnector | Yes | Disconnect one or more sources |
getOuraCompleteHealthData | Yes | Full Oura health payload |
Authenticated headers
HTTP
POST /api/v1/health HTTP/1.1 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... Content-Type: application/json x-country-code: IN x-tenant-id: relay-health-default
getConnectionStatus
Request
{ "routeName": "getConnectionStatus", "sourceType": ["strava","oura","fitbit"] }Response
{
"success": true,
"data": {
"connections": [
{ "sourceType": "strava", "connected": true, "lastSyncAt": "2026-05-21T18:45:00.000Z" },
{ "sourceType": "oura", "connected": true, "lastSyncAt": "2026-05-22T06:12:00.000Z" },
{ "sourceType": "fitbit", "connected": false, "lastSyncAt": null }
]
}
}getAllHealthData
Request
{
"routeName": "getAllHealthData",
"sourceType": ["oura", "strava"],
"startDate": "2026-05-01",
"endDate": "2026-05-21",
"categories": ["ALL"],
"useCache": true
}| Field | Type | Description |
|---|---|---|
sourceType | string | string[] | Provider key(s) or all |
startDate | string | YYYY-MM-DD |
endDate | string | YYYY-MM-DD |
categories | string[] | ALL, Sleep, Activity... |
useCache | boolean | Use cached provider data |
isFhirConvert | boolean | FHIR-shaped payloads when supported |
Response
{
"success": true,
"data": {
"providers": {
"oura": { "Sleep": { "summary": [{ "day": "2026-05-20", "score": 82 }] } },
"strava": { "dailyActivity": [{ "date": "2026-05-20", "distance": 5200.3 }] }
}
}
}iOS SDK
The Relay iOS SDK integrates with Apple HealthKit to extract health data on-device and forward normalized payloads through the Relay backend. No OAuth redirect is required — data is pulled directly from the device.
Common principles
HealthKit integrations have a few key characteristics that differ from OAuth-based providers:
Data is stored only on-device — it must be actively extracted via HealthKit APIs.
Permission control is granular — each metric type (steps, heart rate, sleep) needs individual user approval.
Data becomes available as soon as it is recorded, with no webhook or delay.
Integration requires active lifecycle management through the SDK.
Setup guide
| Item | Value | Notes |
|---|---|---|
| Minimum version | iOS 15+ | HealthKit capability must be enabled in Xcode. |
| Package | RelayHealthKitSDK | Available via Swift Package Manager. |
| Xcode setup | HealthKit capability | Enable in target → Signing & Capabilities. |
| Required credentials | clientId, applicationId, redirectUrl | Generate from Applications → OAuth / API. |
Swift · Initialization
import RelayHealthKitSDK let relay = RelayHealthKit( clientId: "relay_app_client_7f3a9c2e1b", applicationId: "674a1b2c3d4e5f6789012345", redirectUrl: "myapp://relay/callback" ) // Request HealthKit permissions from the user try await relay.requestAuthorization( readTypes: [.steps, .heartRate, .sleepAnalysis, .workouts] )
Usage example
Swift · Export & submit
// Export health data for a date range let payload = try await relay.exportHealthData( startDate: "2026-05-01", endDate: "2026-05-21" ) // Forward normalized payload to your backend try await yourBackend.submitHealthPayload(payload)
Detailed docs covering background delivery, backfill, logging, and Samsung Health are being prepared by the iOS team. This section will be updated when available.
Android SDK
The Relay Android SDK integrates with Android Health Connect to read user-approved health metrics and sync them through the Relay API using the same normalized schema as HealthKit.
Common principles
Android Health Connect shares the same device-first model as HealthKit:
Data is stored on-device via Health Connect — it must be actively extracted, not pushed.
Permission control is metric-level — steps, heart rate, sleep, and activity each need separate approval.
Health Connect requires Android 9+ with the Health Connect app installed on the device.
Integration requires active lifecycle management through the SDK and background service.
Setup guide
| Item | Value | Notes |
|---|---|---|
| Minimum version | Android 9.0+ | Health Connect app must be installed on the device. |
| Package | ai.scanbo.relay:health-connect-sdk | Add via Gradle with your private Maven token. |
| Manifest | health_permissions | Declare Health Connect read permissions in AndroidManifest.xml. |
| Required credentials | clientId, applicationId, packageName | Register Android package name in Applications. |
Kotlin · Initialization
import ai.scanbo.relay.health.RelayHealthConnect
val relay = RelayHealthConnect.Builder(context)
.clientId("relay_app_client_7f3a9c2e1b")
.applicationId("674a1b2c3d4e5f6789012345")
.packageName("com.example.healthapp")
.build()
// Request Health Connect permissions from the user
relay.requestPermissions(
setOf(Metric.STEPS, Metric.HEART_RATE, Metric.SLEEP, Metric.ACTIVITY)
)Usage example
Kotlin · Export & submit
// Export health data for a date range val payload = relay.exportHealthData( startDate = "2026-05-01", endDate = "2026-05-21" ) // Forward normalized payload to your backend yourBackend.submitHealthPayload(payload)
Detailed docs covering Samsung Health, background delivery, backfill, and logging are being prepared by the Android team. This section will be updated when available.
API Testing
Test credentials, health gateway, and liveness endpoints directly from this documentation page.
Test API from docs
Choose an endpoint, add credentials or token, run the request, and inspect request/response details.
Service Liveness
Simple process check — not the wearable gateway.
/health
Auth
None
JSON
{ "success": true, "message": "Service is running", "data": { "status": "healthy", "version": "1.0.0" } }Integration Flow
Authenticate with app credentials
POST /api/v1/ · routname: get-user-by-app-credentials
-> Receive accessToken, user, activeDevices
Check connections (optional)
POST /api/v1/health · routeName: getConnectionStatus
-> Authorization: Bearer <accessToken>
Fetch health data
routeName: getAllHealthData with date range and sourceType
-> providers { oura, strava, ... }
Notes for Integrators
->
Case: routname is normalized; getuserbyappcredentials also works.
->
Tokens: accessToken and token in the response are identical.
->
Dates: Use YYYY-MM-DD for startDate / endDate.
->
Data residency: x-country-code selects the regional database — match user registration region.
Relay Matrix Health Connector · Dev documentation
Health gateway
curl --request POST \
--url 'https://dev-relay-backend.agent.scanbo.ai/api/v1/health' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-country-code: IN' \
--header 'x-tenant-id: relay-health-default' \
--data '{
"routeName": "getConnectionStatus",
"sourceType": ["strava", "oura"]
}'{
"success": true,
"code": 200,
"message": "OK",
"data": {
"connections": [
{
"sourceType": "strava",
"connected": true,
"lastSyncAt": "2026-05-21T18:45:00.000Z"
},
{
"sourceType": "oura",
"connected": true,
"lastSyncAt": "2026-05-22T06:12:00.000Z"
}
]
}
}