Package: whoop
WHOOP for PythonTools for acquiring and analyzing Whoop API data.WHOOP is a wearable strap for monitoring sleep, activity, and workouts. Learn more about WHOOP athttps://www.whoop.com.WHOOP API documentation can be found athttps://developer.whoop.com/api.ContentsInstallationGetting StartedAPI RequestsGet ProfileGet Body MeasurementGet Cycle By IDGet Cycle CollectionGet Recovery For CycleGet Recovery CollectionGet Sleep By IDGet Sleep CollectionGet Workout By IDGet Workout CollectionUsage With DataFrameInstallationThewhoopmodule can be installed via pip:pip install whoopGetting StartedIn order to use the WHOOP client, you must have your WHOOP email and password.It is best practice to store these values in a.envfile:# WHOOP credentialsUSERNAME="<USERNAME>"PASSWORD="<PASSWORD>"You can usepython-dotenvto load the enviroment variables for use in code:importosfromdotenvimportload_dotenvload_dotenv()un=os.getenv("USERNAME")or""pw=os.getenv("PASSWORD")or""Once the environment variables are loaded, aWhoopClientobject can be created:fromwhoopimportWhoopClient# Using a traditional constructorclient=WhoopClient(username,password)...# Using a context managerwithWhoopClient(username,password)asclient:...The WHOOP client will authenticate the client upon construction by default. This involves fetching an access token from the API. If you don't want this request to happen automatically, passauthenticate=Falseinto the object constructor. In order to make other requests, you will need to manually call theauthenticate()method so that the other requests have the proper authorization headers:client=WhoopClient(client_id,client_secret,refresh_token,authenticate=False)client.authenticate()...API RequestsThere are ten different API requests thatWhoopClientcan make. Full WHOOP API documentation can be found onWHOOP's website.Get ProfileGet the user's basic profile.Method:get_profile()Payload: NoneExample Response:{"user_id":10129,"email":"jsmith123@whoop.com","first_name":"John","last_name":"Smith"}Get Body MeasurementGet the user's body measurements.Method:get_body_measurement()Payload: NoneExample Response:{"height_meter":1.8288,"weight_kilogram":90.7185,"max_heart_rate":200}Get Cycle By IDGet the cycle for the specified ID.Method:get_cycle_by_id(cycle_id: str)Payload:cycle_id: ID of the cycle to retrieve. Passed into the request path.Example Response:{"id":93845,"user_id":10129,"created_at":"2022-04-24T11:25:44.774Z","updated_at":"2022-04-24T14:25:44.774Z","start":"2022-04-24T02:25:44.774Z","end":"2022-04-24T10:25:44.774Z","timezone_offset":"-05:00","score_state":"SCORED","score":{"strain":5.2951527,"kilojoule":8288.297,"average_heart_rate":68,"max_heart_rate":141}}Get Cycle CollectionGet all physiological cycles for a user. Results are sorted by start time in descending order.Method:get_cycle_collection(start_date: str = None, end_date: str = <today's date>)Payload:startDate: The earliest date for which to get data, pulled from thestart_dateparameter. Returns cycles that occurred after or during (inclusive) this time. Expected in ISO 8601 format (YYYY-MM-DD HH:MM:SS). Defaults to no start date.endDate: The latest date for which to get data, pulled from theend_dateparameter. Returns cycles that intersect this time or ended before (exclusive) this time. Expected in ISO 8601 format (YYYY-MM-DD HH:MM:SS). Defaults to today's date.Example Response:[{"id":93845,"user_id":10129,"created_at":"2022-04-24T11:25:44.774Z","updated_at":"2022-04-24T14:25:44.774Z","start":"2022-04-24T02:25:44.774Z","end":"2022-04-24T10:25:44.774Z","timezone_offset":"-05:00","score_state":"SCORED","score":{"strain":5.2951527,"kilojoule":8288.297,"average_heart_rate":68,"max_heart_rate":141}},...]Get Recovery For CycleGet the recovery for a cycleMethod:get_recovery_for_cycle(cycle_id: str)Payload:cycle_id: ID of the cycle to retrieve. Passed into the request path.Example Response:{"cycle_id":93845,"sleep_id":10235,"user_id":10129,"created_at":"2022-04-24T11:25:44.774Z","updated_at":"2022-04-24T14:25:44.774Z","score_state":"SCORED","score":{"user_calibrating":False,"recovery_score":44,"resting_heart_rate":64,"hrv_rmssd_milli":31.813562,"spo2_percentage":95.6875,"skin_temp_celsius":33.7}}Get Recovery CollectionGet all recoveries for a user. Results are sorted by start time of the related sleep in descending order.Method:get_recovery_collection(start_date: str = None, end_date: str = <today's date>)Payload:startDate: The earliest date for which to get data, pulled from thestart_dateparameter. Returns cycles that occurred after or during (inclusive) this time. Expected in ISO 8601 format (YYYY-MM-DD HH:MM:SS). Defaults to no start date.endDate: The latest date for which to get data, pulled from theend_dateparameter. Returns cycles that intersect this time or ended before (exclusive) this time. Expected in ISO 8601 format (YYYY-MM-DD HH:MM:SS). Defaults to today's date.Example Response:[{"cycle_id":93845,"sleep_id":10235,"user_id":10129,"created_at":"2022-04-24T11:25:44.774Z","updated_at":"2022-04-24T14:25:44.774Z","score_state":"SCORED","score":{"user_calibrating":False,"recovery_score":44,"resting_heart_rate":64,"hrv_rmssd_milli":31.813562,"spo2_percentage":95.6875,"skin_temp_celsius":33.7}},...]Get Sleep By IDGet the sleep for the specified ID.Method:get_sleep_by_id(sleep_id: str)Payload:sleep: ID of the sleep to retrieve. Passed into the request path.Example Response:{"id":93845,"user_id":10129,"created_at":"2022-04-24T11:25:44.774Z","updated_at":"2022-04-24T14:25:44.774Z","start":"2022-04-24T02:25:44.774Z","end":"2022-04-24T10:25:44.774Z","timezone_offset":"-05:00","nap":False,"score_state":"SCORED","score":{"stage_summary":{},"sleep_needed":{},"respiratory_rate":16.11328125,"sleep_performance_percentage":98,"sleep_consistency_percentage":90,"sleep_efficiency_percentage":91.69533848}}Get Sleep CollectionGet all sleeps for a user. Results are sorted by start time in descending order.Method:get_sleep_collection(start_date: str = None, end_date: str = <today's date>)Payload:startDate: The earliest date for which to get data, pulled from thestart_dateparameter. Returns sleeps that occurred after or during (inclusive) this time. Expected in ISO 8601 format (YYYY-MM-DD HH:MM:SS). Defaults to no start date.endDate: The latest date for which to get data, pulled from theend_dateparameter. Returns sleeps that intersect this time or ended before (exclusive) this time. Expected in ISO 8601 format (YYYY-MM-DD HH:MM:SS). Defaults to today's date.Example Response:[{"id":93845,"user_id":10129,"created_at":"2022-04-24T11:25:44.774Z","updated_at":"2022-04-24T14:25:44.774Z","start":"2022-04-24T02:25:44.774Z","end":"2022-04-24T10:25:44.774Z","timezone_offset":"-05:00","nap":False,"score_state":"SCORED","score":{"stage_summary":{},"sleep_needed":{},"respiratory_rate":16.11328125,"sleep_performance_percentage":98,"sleep_consistency_percentage":90,"sleep_efficiency_percentage":91.69533848}},...]Get Workout By IDGet the workout for the specified ID.Method:get_workout_by_id(workout_id: str)Payload:workout_id: ID of the workout to retrieve. Passed into the request path.Example Response:{"id":1043,"user_id":9012,"created_at":"2022-04-24T11:25:44.774Z","updated_at":"2022-04-24T14:25:44.774Z","start":"2022-04-24T02:25:44.774Z","end":"2022-04-24T10:25:44.774Z","timezone_offset":"-05:00","sport_id":1,"score_state":"SCORED","score":{"strain":8.2463,"average_heart_rate":123,"max_heart_rate":146,"kilojoule":1569.34033203125,"percent_recorded":100,"distance_meter":1772.77035916,"altitude_gain_meter":46.64384460449,"altitude_change_meter":-0.781372010707855,"zone_duration":{}}}Get Workout CollectionGet all workouts for a user. Results are sorted by start time in descending order.Method:get_workout_collection(start_date: str = None, end_date: str = <today's date>)Payload:startDate: The earliest date for which to get data, pulled from thestart_dateparameter. Returns workouts that occurred after or during (inclusive) this time. Expected in ISO 8601 format (YYYY-MM-DD HH:MM:SS). Defaults to no start date.endDate: The latest date for which to get data, pulled from theend_dateparameter. Returns workouts that intersect this time or ended before (exclusive) this time. Expected in ISO 8601 format (YYYY-MM-DD HH:MM:SS). Defaults to today's date.Example Response:[{"id":1043,"user_id":9012,"created_at":"2022-04-24T11:25:44.774Z","updated_at":"2022-04-24T14:25:44.774Z","start":"2022-04-24T02:25:44.774Z","end":"2022-04-24T10:25:44.774Z","timezone_offset":"-05:00","sport_id":1,"score_state":"SCORED","score":{"strain":8.2463,"average_heart_rate":123,"max_heart_rate":146,"kilojoule":1569.34033203125,"percent_recorded":100,"distance_meter":1772.77035916,"altitude_gain_meter":46.64384460449,"altitude_change_meter":-0.781372010707855,"zone_duration":{}}},...]Usage With DataFrameUsing WHOOP API data with a Pandas DataFrame is very straightforward:>>>importpandasaspd>>>sleep=client.get_sleep_collection("2022-05-01","2022-05-07")>>>pd.json_normalize(sleep)iduser_idcreated_atupdated_at\04308789039959452022-05-07T14:56:28.389Z2022-05-07T15:12:22.933Z14303781499959452022-05-06T18:11:27.029Z2022-05-06T18:11:29.172Z24297045029959452022-05-05T14:31:14.954Z2022-05-05T14:43:15.744Z34290553999959452022-05-04T13:35:13.911Z2022-05-04T13:35:15.758Z44283754779959452022-05-03T12:26:02.170Z2022-05-03T12:26:04.151Z54278732689959452022-05-02T15:55:10.734Z2022-05-02T15:55:13.140Z64273000919959452022-05-01T17:06:54.808Z2022-05-01T17:06:57.067Z74270698529959452022-05-01T11:26:47.991Z2022-05-01T11:26:49.684Zstartendtimezone_offsetnap\02022-05-07T04:46:52.867Z2022-05-07T14:40:57.427Z-04:00False12022-05-06T05:09:00.681Z2022-05-06T15:09:12.415Z-04:00False22022-05-05T04:59:16.774Z2022-05-05T14:29:44.886Z-04:00False32022-05-04T05:04:02.916Z2022-05-04T13:28:57.733Z-04:00False42022-05-03T05:29:46.133Z2022-05-03T12:14:54.861Z-04:00False52022-05-02T05:12:48.073Z2022-05-02T15:49:36.453Z-04:00False62022-05-01T11:53:13.942Z2022-05-01T14:51:19.894Z-04:00True72022-05-01T06:14:52.087Z2022-05-01T09:19:14.856Z-04:00Falsescore_statescore.stage_summary.total_in_bed_time_milli\0SCORED356435991SCORED354609072SCORED342409593SCORED302938554SCORED243077675SCORED380036236SCORED103965997SCORED11004129score.stage_summary.total_awake_time_milli\037440351206451522937299327693524338473352235345668110371608235score.stage_summary.total_no_data_time_milli\0010203040506070score.stage_summary.total_light_sleep_time_milli\015384266113169346212210534312689932466553835111950036590069874971785score.stage_summary.total_slow_wave_sleep_time_milli\07633425178740532781436435554196455262905101015516176253373008130score.stage_summary.total_rem_sleep_time_milli\0888187311235299321127876239280375487413615144717246205226571415979score.stage_summary.sleep_cycle_count\0819253444596371score.stage_summary.disturbance_countscore.sleep_needed.baseline_milli\0172797580011227976121221279764423152797676441227977085582797740661279777287427977728score.sleep_needed.need_from_sleep_debt_milli\001359692232372743363697940597920926979220472098329score.sleep_needed.need_from_recent_strain_milli\03675391304726265590131812597427059754267956071463907score.sleep_needed.need_from_recent_nap_milliscore.respiratory_rate\0013.3984381013.0664062012.5683593013.1640624013.5351565-971549613.5351566014.1210947014.941406score.sleep_performance_percentagescore.sleep_consistency_percentage\0100.083.01100.081.0298.075.0382.068.0474.065.05100.062.0626.051.0730.078.0score.sleep_efficiency_percentage089.857010194.178050291.421684391.993940489.586520594.118080693.448790787.927660[8rowsx25columns]