Wearables

Check a wearable webhook URL

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

Answers whether a webhook URL is live, for a provider that checks it before it sends notifications (Withings does). You never call it yourself.

Auth: none. A token at the end of the URL is not checked here. Scope: the project in the path.

Answers

  • 200 with no body when the project has set up and switched on the provider, and ovok takes notifications from it.
  • Otherwise the same 404 and 422 answers as POST on the same URL.

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"

Response Body

The project takes notifications from this provider.

Example Request
curl -X HEAD 'https://api.sandbox.ovok.com/v1/wearables/webhooks/497f6eca-6276-4993-bfeb-53cbbbba6f08/oura'
Example Response
Empty

Receive a signed wearable provider notification POST

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 | Status | When | |---|---| | `202` | The notification is accepted; `outcome` is `queued`, or `no_connection` when no patient here is connected to the named accounts (nothing is queued). | | `200` | A setup call, such as Polar's `PING` when the webhook is created; `outcome` is `handshake`, nothing is queued. | | `400 MALFORMED_NOTIFICATION` | The body is neither a JSON object nor form fields, or does not parse. | | `401 INVALID_SIGNATURE` | The signature or the URL token is missing or does not match. `WWW-Authenticate` is sent. | | `404 PROJECT_NOT_FOUND` | There is no such project. | | `404 PROVIDER_NOT_AVAILABLE` | The project has not set up the provider, or has switched it off. | | `404 WEBHOOK_NOT_SUPPORTED` | ovok takes no notifications from this provider. | | `413` | The body is larger than 64 KB. | | `422` | The project id is not a UUID, or the provider is not one ovok supports. | | `429` | More than 300 calls a minute from one address. Retry after `Retry-After`. | | `503 SYNC_QUEUE_UNAVAILABLE` | The 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.

Receive a wearable provider notification by URL token POST

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 | Status | When | |---|---| | `202` | The notification is accepted; `outcome` is `queued`, or `no_connection` when no patient here is connected to the named accounts (nothing is queued). | | `200` | A setup call, such as Polar's `PING` when the webhook is created; `outcome` is `handshake`, nothing is queued. | | `400 MALFORMED_NOTIFICATION` | The body is neither a JSON object nor form fields, or does not parse. | | `401 INVALID_SIGNATURE` | The signature or the URL token is missing or does not match. `WWW-Authenticate` is sent. | | `404 PROJECT_NOT_FOUND` | There is no such project. | | `404 PROVIDER_NOT_AVAILABLE` | The project has not set up the provider, or has switched it off. | | `404 WEBHOOK_NOT_SUPPORTED` | ovok takes no notifications from this provider. | | `413` | The body is larger than 64 KB. | | `422` | The project id is not a UUID, or the provider is not one ovok supports. | | `429` | More than 300 calls a minute from one address. Retry after `Retry-After`. | | `503 SYNC_QUEUE_UNAVAILABLE` | The 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.