Garmin Connect endpoints used by the web app
In October 2026 the API calls made by the Garmin Connect web app
(connect.garmin.com) were compared with what this library implements. This
document lists the result: new methods, extended existing methods, and the
differences that were found and deliberately left alone. For every method the
table gives the HTTP verb, path and query parameters the web app sends.
All paths are relative to https://connectapi.garmin.com unless a full URL is
shown. The Verified column says whether the call was executed against a real
account while adding it:
yes – returned HTTP 200 with the expected shape;
yes (empty) – returned 200 with an empty list/object because the account
has no such data, so the field names are not confirmed;
no – a write, or data the test account does not have; the request shape
matches what the web app sends but was not confirmed with a response.
Dates are YYYY-MM-DD. Methods whose date argument is optional default to
today in the user's Garmin timezone (Garmin.today()), not the machine's
clock.
Performance metrics (metrics-service)
Method
Request
Notes
Verified
get_max_metrics_latest(cdate=None)
GET /metrics-service/metrics/maxmet/latest/{date}
Latest VO2 max: generic (running), cycling, heatAltitudeAcclimation.
yes
get_max_metrics_range(start, end, aggregation="daily", sport=None)
GET /metrics-service/metrics/maxmet/{daily|weekly|monthly}/{start}/{end}[?sport=]
Existing method; aggregation and sport are new and optional.
yes
get_training_readiness_range(start, end)
GET /metrics-service/metrics/trainingreadiness/{start}/{end}
Several entries per day are possible (inputContext).
yes
get_weekly_training_status(start, end)
GET /metrics-service/metrics/trainingstatus/weekly/{displayName}?fromCalendarDate&toCalendarDate
Weekly load / status series of the Training Status page.
yes
get_heat_altitude_acclimation(cdate=None)
GET /metrics-service/metrics/heataltitudeacclimation/latest/{date}
yes
get_heat_altitude_acclimation_range(start, end, aggregation="daily")
GET /metrics-service/metrics/heataltitudeacclimation/{daily|weekly|monthly}/{start}/{end}
yes
get_cycling_ability(cdate=None)
GET /metrics-service/metrics/cycling-ability/latest?calendarDate=
yes
get_cycling_ability_range(start, end, aggregation="DAILY")
GET /metrics-service/metrics/cycling-ability?startDate&endDate&aggregation
Returns cyclingAbilitiesMap keyed by date.
yes
get_running_economy(cdate=None)
GET /metrics-service/metrics/runningeconomy/latest/{date}
Empty without a capable device.
yes (empty)
get_running_economy_range(start, end, aggregation="daily")
GET /metrics-service/metrics/runningeconomy/{daily|weekly}?startDate&endDate
yes (empty)
get_stamina_curve(cdate=None, sport_type="running")
GET /metrics-service/metrics/stamina-curve/latest?calendarDate&sportType
yes (empty)
get_endurance_score(start, end=None, aggregation="weekly")
GET /metrics-service/metrics/endurancescore/stats?startDate&endDate&aggregation
Existing method; aggregation (daily/weekly) is new.
yes
Not added: /metrics-service/metrics/eventracetimeprojections/{eventId}/{d1}/{d2}
(date semantics unclear) and the internal manualstresslevel path.
Biometrics (biometric-service, userprofile-service/biometric)
Method
Request
Notes
Verified
get_heart_rate_zones_v2(generate_defaults=False)
GET /biometric-service/heartRateZones/v2?generateDefaults=
The web app reads zones from v2; get_heart_rate_zones keeps v1.
yes
update_heart_rate_zones(zones)
PUT /biometric-service/heartRateZones/ with a list of per-sport zone objects
Pass the (edited) objects from get_heart_rate_zones_v2.
yes (unchanged object)
update_power_zones(zones)
PUT /biometric-service/powerZones/all with a list of per-sport objects
Pass the (edited) objects from get_power_zones.
yes (unchanged object)
get_biometric_stats(start, end, aggregation="daily", user_first_day="monday")
GET /biometric-service/stats?aggregation&userFirstDay&startDate&endDate
Per-period weight, body fat, LT, FTP statistics.
yes
get_power_to_weight_range(start, end, aggregation="daily", sport=None)
GET /biometric-service/stats/powerToWeight/range/{start}/{end}?aggregation[&sport]
One series per sport.
yes
get_critical_swim_speed(cdate=None)
GET /biometric-service/criticalSwimSpeed/latest/{date}
yes (empty)
get_critical_swim_speed_range(start, end, aggregation=None)
GET /biometric-service/criticalSwimSpeed/range/{start}/{end}[?aggregation]
yes (empty)
get_glucose_data(cdate)
GET /biometric-service/biometric/glucose/{date}
glucoseList.
yes (empty)
get_glucose_data_range(start, end)
GET /biometric-service/biometric/glucose/{start}/{end}
yes (empty)
get_current_biometrics()
GET /userprofile-service/biometric/current/{displayName}
Height, weight, VO2 max, LT speed/HR, FTP.
yes
Fitness statistics (fitnessstats-service, fitnessage-service, personalrecord-service)
Method
Request
Notes
Verified
get_power_curve(start, end, sport="cycling")
GET /fitnessstats-service/powerCurve?startDate&endDate&sport
yes (empty)
get_available_metrics(start, end, activity_types=None)
GET /fitnessstats-service/activity/availableMetrics?startDate&endDate[&activityType]
Which metrics get_progress_summary_between_dates can return.
yes
get_one_rep_max(cdate=None, exercise_type=None)
GET /fitnessstats-service/vbt-stats/one-rep-max[/{exerciseType}]/current/{date}
yes (empty)
get_one_rep_max_history(exercise_type, start, end, aggregation="daily")
GET /fitnessstats-service/vbt-stats/one-rep-max/{exerciseType}/{daily|monthly}?startDate&endDate
404 when the exercise has no data.
no
get_fitness_age_details(cdate=None)
GET /fitnessage-service/fitnessage/v2/{date}
Components and achievable fitness age.
yes
get_fitness_age_daily(start, end)
GET /fitnessage-service/stats/daily/{start}/{end}
yes
get_fitness_age_weekly(end=None, weeks=52)
GET /fitnessage-service/stats/weekly/{end}/{weeks}
yes
get_personal_record(include_history=None, months=None)
GET /personalrecord-service/personalrecord/prs/{displayName}[?includeHistory&months]
Existing method; both parameters are new and only sent when given.
yes
get_personal_record_candidates()
GET /personalrecord-service/personalrecordcandidate/{displayName}
Records awaiting confirmation.
yes
get_personal_record_types()
GET /personalrecord-service/personalrecordtype/prtypes/{displayName}
Type id → key, sport, bounds.
yes
get_personal_records_for_activity(activity_id)
GET /personalrecord-service/personalrecord/prByActivityId/{activityId}
yes (empty)
get_progress_summary_between_dates(...)
GET /fitnessstats-service/activity?...&groupByParentActivityType=true|false
Existing method; the boolean is now sent lowercase like the web app.
yes
Daily statistics (usersummary-service)
Method
Request
Notes
Verified
get_daily_stats(start, end, stats_type="STEPS", current_date=None, aggregated=False)
GET /usersummary-service/stats/daily[/aggregated]/{start}/{end}?statsType=STEPS|PUSHES|CALORIES¤tDate
The series the web reports use; get_daily_steps keeps the older stats/steps/daily path, which still works.
yes
get_daily_heart_rate_stats(start, end)
GET /usersummary-service/stats/heartRate/daily/{start}/{end}
Resting / min / max HR per day.
yes
get_weekly_heart_rate_stats(end=None, weeks=52)
GET /usersummary-service/stats/heartRate/weekly/{end}/{weeks}
yes
get_daily_stress_stats(start, end)
GET /usersummary-service/stats/stress/daily/{start}/{end}
yes
get_daily_body_battery_stats(start, end)
GET /usersummary-service/stats/bodybattery/daily/{start}/{end}
Daily low/high.
yes
get_daily_intensity_minutes_stats(start, end)
GET /usersummary-service/stats/im/daily/{start}/{end}
yes
get_daily_respiration_stats(start, end)
GET /usersummary-service/stats/respiration/daily/{start}/{end}
yes
get_daily_floors_stats(start, end)
GET /usersummary-service/stats/floors/daily/{start}/{end}
yes
get_weekly_floors_stats(end=None, weeks=52)
GET /usersummary-service/stats/floors/weekly/{end}/{weeks}
yes
get_daily_hydration_stats(start, end)
GET /usersummary-service/stats/hydration/daily/{start}/{end}
yes (empty)
get_weekly_hydration_stats(end=None, weeks=52)
GET /usersummary-service/stats/hydration/weekly/{end}/{weeks}
yes (empty)
get_weekly_calories_stats(end=None, weeks=52)
GET /usersummary-service/stats/calories/weekly/{end}/{weeks}
yes
get_monthly_steps(end=None, months=12)
GET /usersummary-service/stats/steps/monthly/{end}/{months}
yes
get_stats_averages(start, end)
GET /usersummary-service/stats/averages/{start}/{end}
Average steps and resting HR.
yes
get_lifetime_totals()
GET /usersummary-service/stats/connectLifetimeTotals/{displayName}
yes
get_daily_summaries(start, end)
GET /usersummary-service/v2/dailysummaries?startDate&endDate
One get_user_summary record per day in a single call.
yes
get_week_average_resting_hr(cdate=None)
GET /usersummary-service/usersummary/weekAverageRestingHR/{displayName}?calendarDate
yes
get_hydration_all_data(cdate=None)
GET /usersummary-service/usersummary/hydration/allData/{date}
Intake, goal, sweat loss, containers.
yes
Wellness (wellness-service, userstats-service, sleep-service)
Method
Request
Notes
Verified
get_spo2_acclimation_data(cdate=None)
GET /wellness-service/wellness/daily/spo2acclimation/{date}
Superset of get_spo2_data (whose daily/spo2 path still works).
yes
get_daily_movement(cdate=None)
GET /wellness-service/wellness/dailyMovement?calendarDate
yes
get_steps_goal(cdate=None)
GET /wellness-service/wellness/wellness-goals/consolidated/steps/{date}
Device vs. user step goal.
yes
set_steps_goal(steps, cdate=None)
PUT /wellness-service/wellness/wellness-goals/consolidated/steps/{date} with the goal object
Positive value → userGoal (userGoalCategory: manual); None/0 → back to the device's automatic goal (my-auto).
yes
get_sync_timestamp()
GET /wellness-service/wellness/syncTimestamp
UTC timestamp string.
yes
get_hourly_intensity_minutes(end=None, days=7)
GET /wellness-service/stats/hourly/im/{end}/{days}
Garmin accepts 1–7 days inside the current week.
yes
get_acclimation_stats(start, end)
GET /wellness-service/stats/daily/acclimation?fromDate&untilDate
SpO2 acclimation statistics.
yes
get_weekly_wellness_stats(start, end, metric_ids=None)
GET /userstats-service/wellness/weekly/{displayName}?fromWeekStartDate&untilWeekStartDate&metricId&grpParentActType=false
Default metric 60 = resting HR.
yes
get_monthly_wellness_stats(start, end, metric_ids=None)
GET /userstats-service/wellness/monthly/{displayName}?fromMonthStartDate&untilMonthStartDate&metricId&grpParentActType=false
yes
get_weekly_activity_stats(start, end, group_by_activity_type=True)
GET /userstats-service/activities/weekly/{displayName}?fromWeekStartDate&untilWeekStartDate&grpActType
yes
get_user_statistics()
GET /userstats-service/statistics/{displayName}
Totals per activity type.
yes
get_daily_sleep(cdate=None, non_sleep_buffer_minutes=60)
GET /sleep-service/sleep/dailySleepData?date[&nonSleepBufferMinutes]
The Sleep page's current call; get_sleep_data keeps the wellness-service variant.
yes
get_naps(cdate=None, include_overlaps=True)
GET /sleep-service/sleep/naps/{date}?includeOverlaps
yes (empty)
get_sleep_stats_weekly(end=None, weeks=52)
GET /sleep-service/stats/sleep/weekly/{end}/{weeks}
yes
get_sleep_stats_overall(start, end)
GET /sleep-service/stats/sleep/overall/{start}/{end}
yes
Health Snapshot (wellnessactivity-service)
Method
Request
Notes
Verified
get_health_snapshots(cdate=None)
GET /wellnessactivity-service/activity/summary/{date}
yes (empty)
get_health_snapshots_range(start, end)
GET /wellnessactivity-service/activity/summary/range/{start}/{end}
Entries carry activityUuid.uuid.
yes
get_health_snapshot(cdate, snapshot_uuid)
GET /wellnessactivity-service/activity/summary/{date}/{uuid}
yes
get_health_snapshot_epochs(snapshot_uuid)
GET /wellnessactivity-service/activity/epoch/{uuid}
Per-epoch HR, HRV, SpO2, respiration, stress.
yes
download_health_snapshot_session(cdate, snapshot_uuid)
GET /download-service/files/wellness/activity/{date}/{uuid}
FIT bytes of one session.
yes
Nutrition (nutrition-service)
Method
Request
Notes
Verified
get_nutrition_status()
GET /nutrition-service/user/nutritionCurrentStatus
yes
get_calorie_summary(start, end, current_date=None)
GET /nutrition-service/calorie/summary/daily?startDate&endDate¤tDate&isDataForReport=true
Per-meal totals with goals.
yes
get_nutrition_daily_food_log(cdate, include_goals=True, include_nutrition=True, meal_id=None)
GET /nutrition-service/food/logs/{date}?includeGoals&includeNutrition[&mealId]
Existing method; the flags the web app always sends are new.
yes
Weight and blood pressure (weight-service, bloodpressure-service)
Method
Request
Notes
Verified
get_latest_weight(cdate=None)
GET /weight-service/weight/latest?date&ignorePriority=true
yes
get_first_weight()
GET /weight-service/weight/first
yes
get_daily_last_weight(start, end)
GET /weight-service/weight/daily/last?startDate&endDate
Last weigh-in per day.
yes
get_weight_snapshot(start, end)
GET /weight-service/weight/daterangesnapshot?startDate&endDate
dateWeightList.
yes
get_weekly_weight(end=None)
GET /weight-service/weight/weeklyRange/{end-363d}/{end}
Garmin insists on exactly 52 weeks (364 days inclusive).
yes
get_blood_pressure_day(cdate=None)
GET /bloodpressure-service/bloodpressure/dayview/{date}
yes (empty)
get_daily_last_blood_pressure(start, end)
GET /bloodpressure-service/bloodpressure/daily/last/{start}/{end}
yes (empty)
get_weekly_blood_pressure(end=None)
GET /bloodpressure-service/bloodpressure/weeklyRange/{end-363d}/{end}
Same 52-week rule.
yes (empty)
update_blood_pressure(measurement, *, notes)
PUT /bloodpressure-service/bloodpressure with the measurement object
Garmin stores only the changed notes; value changes are echoed but not saved — delete and re-add to correct values.
yes
ECG (https://ghs.garmin.com/ghs/ecg/v1)
The ECG service lives on a sibling host; the client now accepts full URLs on
*.garmin.com / *.garmin.cn for this purpose. Accounts without the ECG
feature get a 404.
Method
Request
Notes
Verified
get_ecg_daily(start, end)
GET https://ghs.<domain>/ghs/ecg/v1/ecg/daily?firstDay&lastDay
content per day.
yes
get_ecg_list(start="2021-01-01", end=None, page_size=20, page=None)
GET https://ghs.<domain>/ghs/ecg/v1/ecg/list?firstDay&lastDay&pageSize[&page]
content[].detailId.
yes
get_ecg(ecg_id)
GET https://ghs.<domain>/ghs/ecg/v1/ecg/{ecgId}
Waveform of one recording.
no
Goals, badges and challenges
Method
Request
Notes
Verified
get_effective_goals(cdate=None)
GET /goal-service/goal/user/effective/{date}
Intensity minutes, floors, hydration goals in effect.
yes
get_user_goals()
GET /goal-service/goal/user
Steps/weight/calorie goals (userGoalPk).
yes
get_weight_goal(start, end)
GET /goal-service/goal/user/effective/weightgoal/{start}/{end}
yes (empty)
set_daily_goal(goal_type, value, cdate=None)
PUT /goal-service/goal/user/effective/{goal-type}/{date} {"goalValue", "goalType"}
INTENSITY_MINUTES, FLOORS_CLIMBED, HYDRATION, WEIGHT_GRAMS; path uses floors-climbed style except WEIGHT_GRAMS.
yes (FLOORS_CLIMBED)
get_badge_attributes()
GET /badge-service/badge/attributes
Types, categories, difficulties.
yes
get_badge_detail(badge_id)
GET /badge-service/badge/detail/v3/{badgeId}
yes
get_latest_earned_badges(limit=5)
GET /badge-service/badge/earned/latest/{displayName}?limit
yes
get_badges_for_activity(activity_id)
GET /badge-service/badge/{displayName}/earned/activity/{activityId}
yes (empty)
get_badges_for_day(cdate=None)
GET /badge-service/badge/{displayName}/earned/dailysummary/{date}
yes (empty)
get_available_virtual_challenges(start=1, limit=100)
GET /badgechallenge-service/virtualChallenge/available?start&limit
Expeditions.
yes
get_completed_virtual_challenges(start=1, limit=100)
GET /badgechallenge-service/virtualChallenge/completed?desc=true&start&limit
yes (empty)
get_badge_challenge(challenge_uuid)
GET /badgechallenge-service/badgeChallenge/{uuid}
no
get_active_adhoc_challenges()
GET /adhocchallenge-service/adHocChallenge/nonCompleted
Running friend challenges.
yes (empty)
Method
Request
Notes
Verified
get_user_timezone()
GET /userprofile-service/userprofile/personal-information/{displayName}
IANA timezone of the profile, cached; see today()/now().
yes
get_personal_information(include_biometric=True, include_vo2max=True)
same ?includeBiometric&includeVO2Max
userInfo, biometricProfile, VO2 max.
yes
get_user_profile_base()
GET /userprofile-service/userprofile/userProfileBase
yes
get_privacy_settings()
GET /privacysettings-service/privacy-settings
yes
get_usage_indicators()
GET /web-gateway/snapshot/usageIndicators
Which features the account's devices support.
yes
update_user_settings(settings)
PUT /userprofile-service/userprofile/user-settings/ with the settings object
Overlaid on get_user_profile(); userData merged one level deep.
yes (unchanged object)
set_primary_training_device(device_id)
PUT /userprofile-service/userprofile/user-settings/primary-training-device {"deviceId"}
yes
get_jetlag_status(cdate=None)
GET /jetlag-service/jetlag/status/daily/{date}
Empty without a trip.
yes (empty)
Activities (activitylist-service, activity-service, segment-service)
Method
Request
Notes
Verified
search_activities(start=0, limit=20, **filters)
GET /activitylist-service/activities/search/activities?start&limit&…
Full web filter set: activityType, activitySubType, startDate, endDate, search, favorite=1, sortBy/sortOrder, minDistance/maxDistance, minDuration/maxDuration, minElevation/maxElevation, eventType, excludeChildren.
yes
get_fastest_splits(start, end, activity_type="running", number_of_bests=10)
GET /activitylist-service/activities/fastest-splits?numberOfBests&startDate&endDate&activityType
yes
get_favorite_activities(limit=5)
GET /activitylist-service/activities/favorite/{displayName}?limit
yes (empty)
set_activity_favorite(activity_id, favorite=True)
PUT /activity-service/activity/{id} {"activityId", "metadataDTO": {"favorite"}}
Same partial update as set_activity_name. Read back via metadataDTO.favorite and get_favorite_activities().
yes
update_activity(activity_id, fields)
PUT /activity-service/activity/{id} {"activityId", **fields}
Generic partial update (activityName, description, activityTypeDTO, eventTypeDTO, metadataDTO, accessControlRuleDTO).
yes
get_activity_laps(activity_id)
GET /activity-service/activity/{id}/laps
lapDTOs.
yes
get_activity_rounds(activity_id)
GET /activity-service/activity/{id}/rounds
HIIT/boxing rounds with sets.
yes (empty)
get_activity_step_details(activity_id)
GET /activity-service/activity/{id}/stepdetails
Structured-workout steps.
yes (empty)
get_activity_jump_details(activity_id)
GET /activity-service/activity/{id}/jumpDetails
yes (empty)
get_activity_subsecond_details(activity_id, maxchart=2000)
GET /activity-service/activity/{id}/subseconddetails?maxChartSize
Only when metadataDTO.hasSubsecondData.
yes (empty)
get_activity_swim_details(activity_id, maxchart=2000, maxpoly=4000)
GET /activity-service/activity/{id}/swimDetails?maxChartSize&maxPolylineSize
Pool swims use this instead of /details.
yes (empty)
get_activity_map_details(activity_id, maxpoly=4000, max_heat_map=4000)
GET /activity-service/activity/{id}/mapdetails?maxPolylineSize&maxHeatMapSize
Polyline + heat map without charts.
yes
get_activity_polyline(activity_id)
GET /activity-service/activity/polyline/{id}
Encoded gPolyline.
yes
get_activity_power_curve(activity_id)
GET /activity-service/activity/{id}/powerCurve
yes (empty)
get_adjacent_activities(activity_id)
GET /activity-service/activity/{id}/prev + /next
{"previous", "next"} ids.
yes
get_activity_event_types()
GET /activity-service/activity/eventTypes
yes
get_activity_segments(activity_id)
GET /segment-service/segment/list/{activityId}
yes (empty)
Method
Request
Notes
Verified
get_gear_list(start=0, limit=20, gear_statuses=None, gear_type=None, sort_order=None)
GET /gear-service/gear/v2/list?start&limit[&gearStatuses&gearType&sortOrder]
Dashed uuids; get_gear returns legacy undashed uuids that v2 does not accept.
yes
get_gear_details(gear_uuid)
GET /gear-service/gear/v2/{uuid}
yes
set_gear_status(gear_uuid, status)
PUT /gear-service/gear/v2/{uuid}/status/{ACTIVE|RETIRED}
no
update_gear(gear_uuid, *, name, brand, model, gear_type, first_use_date, usage_type, max_usage_distance_km, max_usage_duration_min, notes, activity_type_keys)
PUT /gear-service/gear/v2/{uuid} with the complete gear object
Garmin rejects partial bodies (400); the object from get_gear_details is sent back with the changed fields. notes persists — the legacy get_gear() record simply never includes it.
yes
delete_gear(gear_uuid)
DELETE /gear-service/gear/v2/{uuid}
Gone from get_gear_details (404) and get_gear_list afterwards.
yes
get_gear_types()
GET /gear-service/gear/types
yes
get_user_gear_types()
GET /gear-service/gear/v2/user-gear-types
yes
get_gear_make_models(keywords)
GET /gear-service/gear/makemodels?keywords
Autocomplete for the gear form.
yes
get_activity_gear_v2(activity_id)
GET /gear-service/activity/v2/{activityId}
get_activity_gear keeps the legacy filterGear?activityId call.
yes (empty)
Devices (device-service, devicesettings-service)
Method
Request
Notes
Verified
get_all_devices()
GET /device-service/deviceregistration/devices/all/{displayName}
Includes inactive devices.
yes
get_historical_devices()
GET /device-service/deviceregistration/devices/historical
yes
get_active_devices()
GET /device-service/deviceservice/device-info/active/{displayName}
yes
get_user_device(device_id)
GET /device-service/deviceservice/user-device/{deviceId}
Last upload/download timestamps.
yes
get_device_app_info(device_id)
GET /device-service/deviceservice/app-info/device/{deviceId}
yes
get_sensors()
GET /device-service/sensors
Paired sensors.
yes (empty)
get_device_messages()
GET /device-service/devicemessage/messages
Pending software updates / pushed items.
yes
get_device_displayed_activities(device_id)
GET /devicesettings-service/device/displayed-activities/{deviceId}
yes (empty)
update_device_settings(device_id, settings)
PUT /device-service/deviceservice/device-info/settings/{deviceId}
Partial settings object.
no
get_device_solar_gain(device_id, start, end)
GET /device-service/devicemonitoring/solargain/{deviceId}/{start}/{end}
The web app's multi-day solar call; get_device_solar_data keeps the web-gateway view.
yes (empty)
Workouts and schedule (workout-service)
Method
Request
Notes
Verified
get_workouts(start, limit, *, my_workouts_only, shared_workouts_only, include_atp, order_by, order_seq, sport_type_keys)
GET /workout-service/workouts?start&limit[&myWorkoutsOnly&sharedWorkoutsOnly&includeAtp&orderBy&orderSeq&sportTypeKey…]
Existing method; the filters are new, optional keywords.
yes
get_scheduled_workouts_by_period(start, end)
GET /workout-service/schedule/workoutScheduleByPeriod?startDate&endDate
Includes adaptive-plan sessions; the proper source for "next workout".
yes (empty)
get_workout_count(include_atp=False)
GET /workout-service/workouts/count?includeAtp
yes
get_workout_sport_types()
GET /workout-service/workouts/sport-types
yes
get_workout_types()
GET /workout-service/workout/types
Source of the ids in garminconnect.workout.
yes
get_strength_benchmarks()
GET /workout-service/benchmarks
yes
copy_workout(workout_id, name)
POST /workout-service/workout/copy/{workoutId} (text/plain name)
Returns the new workout with its workoutId.
yes
reschedule_workout(scheduled_workout_id, cdate)
PUT /workout-service/schedule/{scheduleId}
Existing entry + calendarDate.
yes
send_scheduled_workouts_to_devices()
PUT /workout-service/schedule/sendtodevices
no
Training plans (trainingplan-service)
Method
Request
Notes
Verified
get_training_plans(limit=None, start=None, status=None)
GET /trainingplan-service/trainingplan/plans[?limit&start&status]
Existing method; parameters are new and optional.
yes
get_active_training_plans(cdate=None)
GET /trainingplan-service/trainingplan/active-plans?startDate
yes (empty)
get_training_plan_tasks(plan_id, locale="en")
GET /trainingplan-service/trainingplan/tasks/{planId}?localeKey
yes
search_training_plans(start=1, limit=20, locale="en", **filters)
POST /trainingplan-service/trainingplan/search?start&limit&locale[&types&subTypes&categories&version] (empty form body)
Garmin's plan catalogue.
yes
schedule_training_plan(plan_id, start_date)
GET /trainingplan-service/trainingplan/schedule/{planId}?startDate
Side-effecting GET, as the web app does it.
no
delete_training_plan(plan_id)
DELETE /trainingplan-service/trainingplan/trainingplan/{planId}
no
Calendar (calendar-service)
Method
Request
Notes
Verified
get_calendar_year(year)
GET /calendar-service/year/{year}
yes
get_calendar_week(cdate=None, first_day_of_week=1)
GET /calendar-service/year/{y}/month/{m-1}/day/{d}/start/{firstDayOfWeek}
Month is 0-based; 0 = Sunday … 6 = Saturday.
yes
get_calendar_events(start, end)
GET /calendar-service/events?startDate&endDate
Race / goal events.
yes
get_upcoming_events(days_forward=90, limit=10)
GET /calendar-service/events/upcoming?numDaysForward&limit
yes
get_primary_event()
GET /calendar-service/event/primary
None when there is no primary event.
yes
get_calendar_event(event_id)
GET /calendar-service/event/{eventId}
yes
create_calendar_event(event) / update_calendar_event(event_id, event) / delete_calendar_event(event_id)
POST /calendar-service/event, PUT/DELETE /calendar-service/event/{eventId}
Full event object as returned by get_calendar_event.
no
move_calendar_item(item_type, item_id, cdate, item=None)
PUT /calendar-service/calendarItem/{itemType}/{id}/date/{date}
no
create_calendar_note(cdate, name, content="") / update_calendar_note(note_id, cdate, name, content="") / delete_calendar_note(note_id)
POST /calendar-service/note, PUT/DELETE /calendar-service/note/{id} {"noteName", "content", "date"[, "id"]}
yes
Method
Request
Notes
Verified
get_courses()
GET /course-service/course/owner/{displayName}
yes (empty)
get_course(course_id)
GET /course-service/course/{courseId}
Geo points included.
no
create_course(course) / update_course(course_id, course) / delete_course(course_id)
POST /course-service/course, PUT/DELETE /course-service/course/{courseId}
no
download_course(course_id, fmt="gpx")
GET /course-service/course/gpx/{courseId} or /fit/{courseId}/0?elevation=true
no
import_course(file_path)
POST /course-service/course/import (multipart file)
GPX, TCX or FIT.
no
convert_activity_to_course(activity_id)
GET /course-service/course/convert/activity/{activityId}
Returns an unsaved course object for create_course.
yes
get_course_favorites() / set_course_favorite(course_id, favorite=True)
GET/POST /course-service/course/favorites, DELETE …/favorites/course/{courseId}
yes (empty) / no
get_pace_bands()
GET /course-service/pacebands
PacePro bands.
yes (empty)
PDF reports (reportexport-service)
Method
Request
Notes
Verified
request_report(category, start, end, options=None, locale="en-US")
POST /reportexport-service/export/init/{category}/{start}/{end}?locale
Categories seen: bloodPressure, wellnessactivity. Returns reportId.
no
get_report_status(report_id)
GET /reportexport-service/export/reportStatus/{reportId}
Poll until progress.status == "READY".
no
download_report(report_id)
GET /reportexport-service/export/reportContent/{reportId}
PDF bytes.
no
Other changes to existing methods
Method
Change
get_menstrual_data_for_date(fordate, today_date=None)
Now sends todayDate (defaults to today in the user's timezone) like the web app always does.
request_reload(cdate, device_id=None)
Optional device id appended to the path.
get_next_scheduled_workout()
Docstring corrected: adaptive-plan sessions are available via get_scheduled_workouts_by_period.
today(), now(), get_user_timezone()
New helpers; every default date/timestamp the library fills in now uses the profile timezone.
Differences found and deliberately kept
These library calls differ from what the web app sends today, but every one
of them was confirmed to still work against a live account, so they were kept
for backwards compatibility. The web-app variant is available as a new method
where useful.
Library call
Web app today
get_spo2_data → /wellness/daily/spo2/{date}
/wellness/daily/spo2acclimation/{date} (get_spo2_acclimation_data)
get_all_day_events → /wellness/dailyEvents?calendarDate
/wellness/dailyEvents/{displayName}?calendarDate
get_daily_steps → /stats/steps/daily/{s}/{e}
/stats/daily/{s}/{e}?statsType=STEPS¤tDate (get_daily_stats)
get_heart_rates, get_steps_data → …/{displayName}?date
same path without the display name
get_sleep_data → wellness-service/…/dailySleepData/{displayName}
sleep-service/sleep/dailySleepData?date (get_daily_sleep)
get_hill_score → /metrics/hillscore
not called by the web app any more (served through GraphQL hillScoreScalar), still responds
get_device_solar_data → /web-gateway/solar/…?singleDayView
multi-day ranges use /devicemonitoring/solargain/… (get_device_solar_gain)
get_gear, get_gear_stats, get_gear_defaults, set_gear_default → legacy gear-service/gear/…
gear-service/gear/v2/… (get_gear_list, get_gear_details, …)
upload_activity → multipart field file
field userfile, path /upload-service/upload/.fit
push_workout_to_device → list body to device-service/devicemessage/messages
single object to devicemessage-service/devicemessage/messages
get_gear_activities → start=0
start=1; the server returns the same first page for both
Social and account-administration endpoints of the web app are left out on
purpose: comments, likes, image flags, connections and followers, groups,
leaderboards, inbox/newsfeed, ad-hoc challenge invites, profile image upload,
Office 365 calendar sync, Fitbit import, dive/golf/animal (dog) specifics, the
Index scale set-up (weightscale-service), nutrition food search/favourites/
recipes/custom foods, dashboard layout (userfocus-service) and UI
preferences (userpreference-service). Open an issue if you need one of them.
The GraphQL gateway operations the dashboard uses are listed in
graphql_operations.md .