Wearables

Receive a wearable provider notification by URL token

  • Sandbox: available
  • Staging: available
  • Production: unknown
POST
/v1/wearables/webhooks/{projectId}/{provider}/{token}

Where a wearable provider tells ovok that one of its users has new data. Register it in the provider's developer portal where the provider asks for one; you never call it yourself.

Auth: none. The provider's signature over the body, or the secret token at the end of the URL, is the proof. Scope: the project in the path.

Behaviour

  • The URL is the provider's webhookUrl from GET /v1/wearables/providers: /v1/wearables/webhooks/<projectId>/<provider>, followed by /<token> for a provider that does not sign its notifications.
  • The body is the provider's own, as JSON or as form fields, at most 64 KB. ovok reads only the provider's user ids from it.
  • A call without the provider's signature header, or without a URL token of the right shape, is refused before anything is looked up.
  • ovok writes no data here. For each patient connected to a named account, it queues one sync, which runs about 30 seconds later. Notifications about the same connection within one 30-second window join one sync; one arriving while that sync runs queues the next window's, so no notification is lost.
  • A sync that finds another sync of the same connection running is queued once more, 30 seconds later.
  • A notification about an account nobody in the project has connected is accepted too, with outcome no_connection: providers stop calling URLs that keep failing.

Answers

StatusWhen
202The notification is accepted; outcome is queued, or no_connection when no patient here is connected to the named accounts (nothing is queued).
200A setup call, such as Polar's PING when the webhook is created; outcome is handshake, nothing is queued.
400 MALFORMED_NOTIFICATIONThe body is neither a JSON object nor form fields, or does not parse.
401 INVALID_SIGNATUREThe signature or the URL token is missing or does not match. WWW-Authenticate is sent.
404 PROJECT_NOT_FOUNDThere is no such project.
404 PROVIDER_NOT_AVAILABLEThe project has not set up the provider, or has switched it off.
404 WEBHOOK_NOT_SUPPORTEDovok takes no notifications from this provider.
413The body is larger than 64 KB.
422The project id is not a UUID, or the provider is not one ovok supports.
429More than 300 calls a minute from one address. Retry after Retry-After.
503 SYNC_QUEUE_UNAVAILABLEThe sync could not be queued. Retry after Retry-After.

Per provider

  • Withings: does not sign its notifications, so its URL ends with a token derived from a random secret ovok makes when the project saves its Withings credentials, keeps encrypted with them and never returns. ovok subscribes each patient at connect time with this URL, for measurements such as heart rate and SpO2 (appli 4), activity (16) and sleep (44); there is nothing to paste. Disconnecting revokes those three only. Changing the client secret keeps the URL; changing the client ID makes a new one. Until the secret exists, Withings has no webhookUrl and every call answers 401. The body is form fields userid, appli, startdate and enddate; ovok reads userid.
  • Polar: ovok creates the webhook when the project saves its Polar credentials switched on, and deletes it when the project removes them; webhookUrl is for information only. Polar signs each notification with Polar-Webhook-Signature, an HMAC-SHA256 of the body under the webhook's signing key, which ovok keeps encrypted with the credentials. Notifications for SLEEP and ACTIVITY_SUMMARY queue a sync.
  • Suunto: in the Suunto developer portal, open your app's settings, paste webhookUrl as its notification URL and set a notification secret. Give ovok the same secret as webhookSecret with POST or PATCH /v1/wearables/providers. Suunto signs each notification with X-HMAC-SHA256-Signature, the HMAC-SHA256 of the body under that secret, and names the account in username. Until the secret is stored, every Suunto notification answers 401.
  • Ultrahuman: sends no notifications; its data is synced daily and on demand.

Path Parameters

projectId*string

The project whose app at the provider sends the notification.

Formatuuid
provider*string
Value in"oura""whoop""strava""withings""polar""suunto""garmin""ultrahuman"
token*string

The secret last segment of the URL, for a provider that doesn't sign its notifications.

Length1 <= length <= 128

Response Body

Queued: a sync of each connection to the named accounts runs in about 30 seconds.

application/json
  1. response
outcome*string

queued: a sync of the named accounts is queued. no_connection: no patient here is connected to the named accounts, nothing queued. handshake: a setup call, nothing queued.

Value in"queued""no_connection""handshake"
Example Request
curl -X POST 'https://api.sandbox.ovok.com/v1/wearables/webhooks/497f6eca-6276-4993-bfeb-53cbbbba6f08/oura/string'
Example Response
{  "outcome": "queued"}