Sonar uses three token types, each with a specific scope. The right token for a request depends on what it's doing and where the request originates — not just who is making it.

Token Types at a Glance

Token Issued by Lifetime Scope
API Key Dashboard 90 days, rotatable Full account — any user, any operation
User Token Your backend 1 hour, renewable Single user, read-only
Mobile Token Your backend 5 minutes, single-use SDK initialization only

API Key

Your API key gives full account access. Use it for server-to-server operations: creating and deleting users, querying any user's data, configuring webhooks.

text
Authorization: Bearer sk_live_abc123

API keys come in two variants:

Prefix Environment Behavior
sk_live_ Production Full access to real user data
sk_sandbox_ Sandbox New users are auto-seeded with 7 days of realistic data and pre-computed scores

What API keys can do:

Operation API Key
Create / delete users
Query any user's health data
Manage webhooks and events
Generate User Tokens and Mobile Tokens

Using an API Key

python
import requests

resp = requests.get(
    "https://api.sonarhealth.co/v1/users/usr_abc123/scores",
    headers={"Authorization": "Bearer sk_live_abc123"},
)
typescript
const resp = await fetch("https://api.sonarhealth.co/v1/users/usr_abc123/scores", {
  headers: { Authorization: "Bearer sk_live_abc123" },
});

Rotate API keys every 90 days from the dashboard. Keys older than 90 days are automatically revoked. If a key is compromised (committed to a public repo, logged to a client), rotate immediately — the old key is revoked the moment you generate a new one. After rotating, audit your webhook configurations and any server-side code that references the old key.

User Token

A User Token is a short-lived, read-only JWT scoped to a single Sonar user. Issue one from your backend and pass it to your frontend so clients can query health data directly — without a backend proxy and without ever seeing your API key.

What User Tokens can do:

Operation User Token
GET /users/{user_id}/scores (own user)
GET /users/{user_id}/daily (own user)
GET /users/{user_id}/sleep (own user)
GET /users/{user_id}/workouts (own user)
GET /users/{user_id}/timeseries (own user)
GET /users/{user_id}/devices (own user)
Any other user's data
Create / delete users
Manage webhooks

Issuing a User Token

Your backend generates a User Token for a specific Sonar user, then passes it to the client:

python
# Your backend — authenticated with API key
import requests

resp = requests.post(
    "https://api.sonarhealth.co/v1/auth/user-token",
    headers={"Authorization": "Bearer sk_live_abc123"},
    json={"user_id": "usr_abc123"},
)
token = resp.json()["token"]
expires_at = resp.json()["expires_at"]
# Pass token to your frontend
typescript
// Your backend — authenticated with API key
const resp = await fetch("https://api.sonarhealth.co/v1/auth/user-token", {
  method: "POST",
  headers: {
    Authorization: "Bearer sk_live_abc123",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ user_id: "usr_abc123" }),
});
const { token, expires_at } = await resp.json();
// Pass token to your frontend
json
{
  "token": "eyJhbGciOiJSUzI1NiIs...",
  "user_id": "usr_abc123",
  "expires_at": "2025-01-15T11:00:00Z"
}

Using a User Token

The client uses the token exactly like an API key — the Bearer scheme is the same:

typescript
// Your frontend — safe to use client-side
const resp = await fetch("https://api.sonarhealth.co/v1/users/usr_abc123/scores", {
  headers: { Authorization: `Bearer ${userToken}` },
});
python
# Mobile app / script — safe to expose in this context
resp = requests.get(
    "https://api.sonarhealth.co/v1/users/usr_abc123/scores",
    headers={"Authorization": f"Bearer {user_token}"},
)

Refreshing a User Token

Tokens expire after 1 hour. Refresh before expiry to keep the session alive:

python
resp = requests.post(
    "https://api.sonarhealth.co/v1/auth/user-token/refresh",
    headers={"Authorization": "Bearer sk_live_abc123"},
    json={"user_id": "usr_abc123"},
)
token = resp.json()["token"]
typescript
const { token } = await fetch("https://api.sonarhealth.co/v1/auth/user-token/refresh", {
  method: "POST",
  headers: {
    Authorization: "Bearer sk_live_abc123",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ user_id: "usr_abc123" }),
}).then(r => r.json());

Mobile Token

A Mobile Token is a single-use credential for initializing the Sonar Mobile SDK. It expires in 5 minutes and can only be used once — for the SDK handshake that associates a device with a Sonar user. It is not a REST API credential.

Generate a fresh Mobile Token each time a user opens your app and the SDK needs to connect:

python
# Your backend — authenticated with API key
resp = requests.post(
    "https://api.sonarhealth.co/v1/auth/mobile-token",
    headers={"Authorization": "Bearer sk_live_abc123"},
    json={"user_id": "usr_abc123", "scopes": ["activity", "sleep", "vitals"]},
)
token = resp.json()["token"]
# Pass to your mobile app — the SDK will use and consume it
typescript
// Your backend — authenticated with API key
const { token } = await fetch("https://api.sonarhealth.co/v1/auth/mobile-token", {
  method: "POST",
  headers: {
    Authorization: "Bearer sk_live_abc123",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ user_id: "usr_abc123", scopes: ["activity", "sleep", "vitals"] }),
}).then(r => r.json());
// Pass to your mobile app
Parameter Type Required Description
user_id string yes The Sonar user ID (e.g., usr_abc123)
scopes string[] no Metric categories to request (default: all)
json
{
  "token": "mt_xK9mP2...",
  "user_id": "usr_abc123",
  "expires_at": "2025-01-15T10:05:00Z"
}

The SDK exchanges this token for an internal session during initialize(). After that, the token is consumed and cannot be reused. If the token expires before the SDK uses it, initialize() fails with invalid_token — generate a fresh one from your backend and retry. Since Mobile Tokens are cheap to create (one API call, no state), the simplest pattern is to generate a new one every time your app foregrounds.

See Mobile SDK for how to pass it to the SDK.

Which Token to Use

Where is the request coming from?API KeyClient operation?User Token(issue from backend first)Mobile Token(issue from backend first)Your backend serverFrontend, mobile appRead health dataInitialize Mobile SDK Use API KeyWhat does it need to do?Use User TokenUse Mobile Token Where is the request coming from?API KeyClient operation?User Token(issue from backend first)Mobile Token(issue from backend first)Your backend serverFrontend, mobile appRead health dataInitialize Mobile SDK Use API KeyWhat does it need to do?Use User TokenUse Mobile Token
Scenario Token
Backend querying a user's scores for a nightly report API Key
Backend creating a new Sonar user on signup API Key
React dashboard displaying the logged-in user's recovery trend User Token
Mobile app showing health scores in-app (without going through your server) User Token
Mobile app initializing the Sonar SDK to start syncing device data Mobile Token

Error Responses

Status Error Meaning
401 invalid_token Token is malformed or does not exist
401 token_expired Token has passed its expires_at — refresh or reissue
403 insufficient_scope Token does not have permission for this operation (e.g., User Token trying to create a user)
403 wrong_user User Token was issued for a different user than the one in the path
json
{
  "error": "insufficient_scope",
  "message": "This token can only access data for user usr_abc123.",
  "details": {}
}

Next Steps

  • Mobile SDK Where Mobile Tokens are used to initialize device connections
  • API Conventions REST conventions, pagination, error handling, and rate limits