{
  "info": {
    "_postman_id": "aifitnessapi-whoop",
    "name": "WHOOP (aifitnessapi.com)",
    "description": "WHOOP: OAuth 2.0 and Webhook samples requests built from the vendor documentation aifitnessapi.com quotes. Generated by scripts/build-collections.mjs; no secrets included. https://aifitnessapi.com/collections",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "item": [
    {
      "name": "OAuth 2.0",
      "description": "WHOOP's authorization-code flow as its documentation describes it, read 2026-11-05. Fill client_id, redirect_uri and scope in an environment of your own and keep client_secret there, never in a shared collection.\n\nThe same facts, with each source sentence, at https://aifitnessapi.com/integrate/whoop-api and https://aifitnessapi.com/tools/oauth-playground.",
      "item": [
        {
          "name": "1. Authorization URL (open in a browser)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "https://api.prod.whoop.com/oauth/oauth2/auth?response_type=code&client_id={{client_id}}&redirect_uri={{redirect_uri}}&scope={{scope}}&state={{state}}",
              "protocol": "https",
              "host": [
                "api",
                "prod",
                "whoop",
                "com"
              ],
              "path": [
                "oauth",
                "oauth2",
                "auth"
              ],
              "query": [
                {
                  "key": "response_type",
                  "value": "code"
                },
                {
                  "key": "client_id",
                  "value": "{{client_id}}"
                },
                {
                  "key": "redirect_uri",
                  "value": "{{redirect_uri}}"
                },
                {
                  "key": "scope",
                  "value": "{{scope}}"
                },
                {
                  "key": "state",
                  "value": "{{state}}"
                }
              ]
            },
            "description": "https://api.prod.whoop.com/oauth/oauth2/auth. Authorization URL (the API reference's authorizationCode flow). Open this URL in a browser (in Postman: copy it from the request bar); the user signs in and WHOOP redirects to {{redirect_uri}} with ?code=… Put that value in the auth_code variable.\n\nSource: WHOOP API reference, “Authentication”, https://developer.whoop.com/api/\n\nScope: The pages read here do not state the separator for the authorize request. WHOOP's sample token response lists granted scopes separated by spaces, so this tool joins them with spaces. Source: WHOOP Developer Platform, “OAuth 2.0”, https://developer.whoop.com/docs/developing/oauth/\n\nDocumented scopes (joined with spaces):\n- read:recovery: Recovery data, including score, heart rate variability, and resting heart rate\n- read:cycles: Cycles data, including day Strain and average heart rate during a physiological cycle\n- read:workout: Workout data, including activity Strain and average heart rate\n- read:sleep: Sleep data, including performance % and duration per sleep stage\n- read:profile: Profile data, including name and email\n- read:body_measurement: Body measurements data, including height, weight, and max heart rate\n- offline: A refresh token; without it WHOOP issues none\n\nPKCE: Not mentioned on the WHOOP OAuth page or API reference read here."
          },
          "response": []
        },
        {
          "name": "2. Exchange the code for tokens",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/x-www-form-urlencoded",
                "type": "text"
              }
            ],
            "url": {
              "raw": "https://api.prod.whoop.com/oauth/oauth2/token",
              "protocol": "https",
              "host": [
                "api",
                "prod",
                "whoop",
                "com"
              ],
              "path": [
                "oauth",
                "oauth2",
                "token"
              ]
            },
            "description": "https://api.prod.whoop.com/oauth/oauth2/token. Token URL, also used for refresh.\n\nSource: WHOOP API reference, “Authentication”, https://developer.whoop.com/api/\n\nClient credentials go in the form body.\n\nToken lifetime: Returned in expires_in, in seconds; WHOOP's sample refresh response shows 3600. Source: WHOOP Developer Platform, “OAuth 2.0”, https://developer.whoop.com/docs/developing/oauth/\n\nNote: If you generate state yourself it must be eight characters long; this tool generates eight. Source: WHOOP Developer Platform, “OAuth 2.0”, https://developer.whoop.com/docs/developing/oauth/\n\nNote: The redirect URL must be registered in the WHOOP Developer Dashboard. Source: WHOOP Developer Platform, “OAuth 2.0”, https://developer.whoop.com/docs/developing/oauth/\n\nNote: WHOOP's sample refresh payload sends client_id, client_secret and scope offline in the body. Source: WHOOP Developer Platform, “OAuth 2.0”, https://developer.whoop.com/docs/developing/oauth/",
            "body": {
              "mode": "urlencoded",
              "urlencoded": [
                {
                  "key": "grant_type",
                  "value": "authorization_code",
                  "type": "text"
                },
                {
                  "key": "code",
                  "value": "{{auth_code}}",
                  "type": "text"
                },
                {
                  "key": "redirect_uri",
                  "value": "{{redirect_uri}}",
                  "type": "text"
                },
                {
                  "key": "client_id",
                  "value": "{{client_id}}",
                  "type": "text"
                },
                {
                  "key": "client_secret",
                  "value": "{{client_secret}}",
                  "type": "text"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "3. Refresh the access token",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/x-www-form-urlencoded",
                "type": "text"
              }
            ],
            "url": {
              "raw": "https://api.prod.whoop.com/oauth/oauth2/token",
              "protocol": "https",
              "host": [
                "api",
                "prod",
                "whoop",
                "com"
              ],
              "path": [
                "oauth",
                "oauth2",
                "token"
              ]
            },
            "description": "Refresh: Using the refresh token invalidates the existing access tokens; the refresh token in the response replaces the old one, and of two simultaneous refreshes only the first succeeds.\n\nSource: WHOOP Developer Platform, “OAuth 2.0”, https://developer.whoop.com/docs/developing/oauth/",
            "body": {
              "mode": "urlencoded",
              "urlencoded": [
                {
                  "key": "grant_type",
                  "value": "refresh_token",
                  "type": "text"
                },
                {
                  "key": "refresh_token",
                  "value": "{{refresh_token}}",
                  "type": "text"
                },
                {
                  "key": "client_id",
                  "value": "{{client_id}}",
                  "type": "text"
                },
                {
                  "key": "client_secret",
                  "value": "{{client_secret}}",
                  "type": "text"
                },
                {
                  "key": "scope",
                  "value": "offline",
                  "type": "text",
                  "description": "WHOOP's sample refresh payload carries scope=offline."
                }
              ]
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "Webhook samples",
      "description": "WHOOP's documented example notifications, sent to {{local_url}} (your local handler) unchanged. Signature: Base64 of HMAC-SHA256, keyed by your client secret, over the X-WHOOP-Signature-Timestamp value (milliseconds since epoch) followed by the raw body, in X-WHOOP-Signature. Source: WHOOP Developer Platform, “Webhooks”, https://developer.whoop.com/docs/developing/webhooks/\n\nHeaders that carry a signature hold the placeholder WHOOP prints, so a handler that verifies signatures will reject these: to send correctly signed requests, use https://aifitnessapi.com/webhooks/send-sample.mjs. Respond: Return a 2XX, ideally within a second, and process on a queue. Every event type goes to every configured URL; answer 2XX to the ones you ignore.\n\nPayload library with JSON Schemas: https://aifitnessapi.com/webhooks#whoop.",
      "item": [
        {
          "name": "v2 example: sleep.updated",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{local_url}}",
              "host": [
                "{{local_url}}"
              ]
            },
            "description": "User 456 records a sleep and WHOOP posts to your v2 webhook endpoint; you then GET v2/activity/sleep/{id}.\n\nWHOOP's v2 example request flow. Source: WHOOP Developer Platform, “Webhooks”, https://developer.whoop.com/docs/developing/webhooks/",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"user_id\": 456,\n  \"id\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"type\": \"sleep.updated\",\n  \"trace_id\": \"e369c784-5100-49e8-8098-75d35c47b31b\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Field-table example: workout.updated",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{local_url}}",
              "host": [
                "{{local_url}}"
              ]
            },
            "description": "The example beside WHOOP's field table, with integer ids (the table documents id as int64 or string).\n\nWHOOP documents id as an integer (v1) or a UUID (v2). Source: WHOOP Developer Platform, “Webhooks”, https://developer.whoop.com/docs/developing/webhooks/",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"user_id\": 10129,\n  \"id\": 10235,\n  \"type\": \"workout.updated\",\n  \"trace_id\": \"d3709ee7-104e-4f70-a928-2932964b017b\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        }
      ]
    }
  ],
  "variable": [
    {
      "key": "client_id",
      "value": "",
      "type": "string",
      "description": "Your app's client ID, from the vendor's developer console."
    },
    {
      "key": "client_secret",
      "value": "",
      "type": "string",
      "description": "Keep it in a Postman or Bruno environment marked secret. This collection ships it empty."
    },
    {
      "key": "redirect_uri",
      "value": "",
      "type": "string",
      "description": "The redirect URI registered with the vendor."
    },
    {
      "key": "scope",
      "value": "",
      "type": "string",
      "description": "Scopes to request, joined as the vendor documents (see the authorization request)."
    },
    {
      "key": "state",
      "value": "",
      "type": "string",
      "description": "A random value you check on the redirect."
    },
    {
      "key": "auth_code",
      "value": "",
      "type": "string",
      "description": "The ?code= value from the redirect."
    },
    {
      "key": "refresh_token",
      "value": "",
      "type": "string",
      "description": "The refresh_token from the token response."
    },
    {
      "key": "local_url",
      "value": "http://localhost:3000/webhooks/whoop",
      "type": "string",
      "description": "Where your webhook handler listens."
    }
  ]
}
