Skip to main content

Webhooks

WHOOP webhooks allow you to get notified when an event takes place for users that have authenticated with your app. By subscribing to webhooks, you will be alerted when a user's data was updated rather than needing to constantly make API requests to check for updates.

Setting Up Webhooks

You will first need to create an HTTPS URL endpoint to receive webhooks. This endpoint should be capable of accepting POST requests with a body consisting of the webhook data format and be able to perform webhook signature validation.

With your webhook endpoint set up, you can create or update an app to start accepting webhooks at that URL. Simply add your HTTPS URL to the Webhook URL section at the bottom of the page and save the app.

That's it! The next time a WHOOP user that has authenticated with your app triggers one of the supported webhook events, you will receive a webhook alerting you of the change.

Webhook Specifications

Webhooks are sent over HTTPS as a POST request to your configured URL. The body of the webhook request includes the following fields:

user_id
int64

The WHOOP User for the event

id
int64

Identifier of the object that triggered this webhook

type
string
Enum: "workout.updated" "workout.deleted" "sleep.updated" "sleep.deleted" "recovery.updated" "recovery.deleted"

The type of event that triggered this webhook

trace_id
string

Trace ID for the event that triggered this webhook

{
  • "user_id": 10129,
  • "id": 10235,
  • "type": "workout.updated",
  • "trace_id": "d3709ee7-104e-4f70-a928-2932964b017b"
}

Webhook Event Types

There are several events that are published as webhooks:

Event TypeID TypeExplanation
recovery.updatedThe id of the cycle for the recoveryOccurs when a recovery is created or updated.
recovery.deletedThe id of the cycle for the recoveryOccurs when a recovery is deleted. Note: a recovery is deleted when its associated sleep is deleted.
workout.updatedThe id of the workoutOccurs when a workout is created or updated.
workout.deletedThe id of the workoutOccurs when a workout is deleted.
sleep.updatedThe id of the sleepOccurs when a sleep is created or updated.
sleep.deletedThe id of the sleepOccurs when a sleep is deleted.
note

All webhook event types will be sent to the Webhook URL configured against your app. As such, if you do not want to process a certain type of event, you can simply respond with a 2XX and skip any other processing you would normally do.

Webhooks Security

In order to validate that the webhooks you are receiving are originating from WHOOP, you will want to implement signature validation. This can be done by making use of two of the headers sent with each webhook request:

  • X-WHOOP-Signature - the actual signature
  • X-WHOOP-Signature-Timestamp - the milliseconds since epoch timestamp used to verify the signature

To verify the signature, first prepend the timestamp header value to the raw http request body. Then, generate a SHA256 HMAC signature of that string using the secret key for your app, which can be found in the WHOOP Developer Dashboard. Finally, base64 encode the result, and compare it to the signature header. If they do not match then the request is invalid and should be dropped.

See below for example signature validation pseudocode:

calculated_signature_string = base64Encode(HMACSHA256(timestamp_header + raw_http_request_body, client_secret))

Example Request Flow

To illustrate a webhook use case, check out the below example request flow that utilizes webhooks.

  1. WHOOP user 456 goes through the OAuth consent flow with your app, allowing you to read their sleep data.
  2. WHOOP user 456 records a sleep. WHOOP assigns id 1234 to this sleep.
  3. WHOOP makes a post request to your webhook endpoint with the body of:
    {
    "user_id": 456,
    "id": 1234,
    "type": "sleep.updated",
    "trace_id": "e369c784-5100-49e8-8098-75d35c47b31b"
    }
  4. Based on seeing sleep.updated in the type field, your app makes a GET request to the /activity/sleep/1234 endpoint using the access token for WHOOP user 456 in order to retrieve the sleep data.

As you begin implementing webhooks, you should have logic for interpreting each of these webhook event types. As shown in the example above, when you receive a sleep.updated webhook for user 456, you may want to make a request to the v1/activity/sleep/{sleepId} endpoint using the sleepId of 1234 and the token for user of 456 if you want to get the data of the sleep the webhook was sent for.

Webhooks Testing

To generate a webhook, first authenticate with your app to ensure your data is retrievable via the API. Then, open the WHOOP app and do one of the following:

  1. Log an activity in the past (e.g. navigate to yesterday and create a 5 minute cycling activity) – once this activity is processed, your webhook endpoint will receive a workout.updated webhook.
  2. Edit a previous sleep by changing the start or end time by 1 minute – once the sleep is processed, your webhook will receive both a sleep.updated webhook and a recovery.updated webhook.

You can then edit or delete the workout you created, and you can revert the sleep duration change. Each of these actions will also result in webhooks being sent – workout.updated, workout.deleted, and sleep.updated, respectively.

Delivery & Retries

WHOOP will retry webhook delivery for failed webhook requests five times over the course of about one hour. A webhook delivery is considered failed if it receives any response other than a successful 2XX, or if it receives no response before timing out.

In order to reduce the amount of delivery failures you encounter, you should consider processing the requests asynchronously after returning a successful response, e.g. with a queue worker.

Best Practices

While working with webhooks, it is important to follow these best practices in order to ensure that you can get the most out of the webhook system.

Respond quickly

As laid out in the Delivery & Retries section, WHOOP will not indefinitely retry if your webhook endpoint is determined to be unavailable. We recommend designing your webhook API to return a successful 2XX status code within a second and for high availability. If your webhook implementation has other dependencies or needs to do expensive work, one strategy is to have your API enqueue the event on a queue for asynchronous processing.

Validate signatures

Be sure to validate the message signature to ensure webhooks you receive were actually sent by WHOOP. Check out the Webhooks Security section to see more details on how to implement this.

Implement a reconciliation job

Since webhook delivery can fail webhooks should not be the sole source of truth for your application. Therefore, we recommend implementing a reconciliation job to occasionally fetch data from WHOOP.

Limitations

There are a few limitations to be aware of when implementing webhooks:

  • It is possible you will receive multiple webhook invocations for the same triggering event. You can make use of the trace_id field in the webhook to detect duplicate webhooks.
  • These are event based webhooks, meaning they are notifications of changes and not actually the changes themselves. You will need to call the API in order to retrieve the most up-to-date data around this event. There is an example of what this flow would look like in the Example Request Flow section.
  • It is possible that a webhook may be missed. You should implement a reconciliation job that can occasionally reach out to the WHOOP API for the data types you care about to fetch data that may have been missed.

Webhooks FAQs

Why are there only update and delete events? Do we get notified of create events?

Yes! When workouts, sleeps, or recoveries are created those events are published as an "update" event.

Are there webhooks for Day Strain, cycles, or body measurements?

Not at the moment; these data points should be retrieved by calling their respective APIs. All of the current webhook types are listed in the Event Types section.

How can I stop receiving webhooks for users who have disabled my integration?

It is best practice to revoke access tokens for users who have disabled your integration. Once you do revoke their access token, no webhooks will be sent for the user.