Help us shape the future of Go! Take the 2026 Go Developer Survey

garminconnect

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 15, 2026 License: MIT Imports: 29 Imported by: 0

README

garminconnect-go

Unofficial Go client for the Garmin Connect API: health and wellness data, activities, devices, gear, workouts, training plans and more. Use it from any Go service to read and write Garmin Connect data for one account or many.

Install

go get github.com/katarsisxyz/garminconnect-go@latest
import gc "github.com/katarsisxyz/garminconnect-go"

Requires Go 1.24+. If the repository is private, let Go fetch it over git first:

go env -w GOPRIVATE=github.com/katarsisxyz/*

To work on this package and a service side by side, point the service at your local copy in its go.mod:

replace github.com/katarsisxyz/garminconnect-go => ../garminconnect-go

How it works

  • One *gc.Garmin per Garmin account. It holds that account's tokens and HTTP connections. Create it once, keep it for the life of the process and share it between goroutines; it is safe for concurrent use.
  • Password once, tokens after that. The first login uses email and password (plus an MFA code if the account has one) and produces tokens. From then on you log in with the tokens only. The password is never stored by the package and is cleared from memory after login.
  • Tokens refresh themselves. The access token is refreshed automatically shortly before it expires. Persist the refreshed tokens with a token file path or WithTokenSaver, otherwise the account has to be connected again once the refresh token expires.
  • Methods map to Garmin endpoints. Each takes a context.Context and returns Garmin's JSON as json.RawMessage, which you can forward as is or decode.

Integration guide

One account

For a personal service that reads one Garmin account.

1. Create the tokens once on your machine with cmd/smoke (see Testing against a real account). They are written to ~/.garminconnect/garmin_tokens.json.

2. Make the token file available to the service, for example by copying it to /data/garmin/garmin_tokens.json on the server or mounting it as a volume. Use a writable location so refreshed tokens can be saved back.

3. Log in at startup with the token path and reuse g in every handler:

func main() {
	g := gc.New("", "") // tokens only, no password
	if _, err := g.Login(context.Background(), "/data/garmin"); err != nil {
		log.Fatal("garmin login: ", err)
	}

	http.HandleFunc("GET /summary", func(w http.ResponseWriter, r *http.Request) {
		raw, err := g.GetUserSummary(r.Context(), r.URL.Query().Get("date"))
		if err != nil {
			writeGarminError(w, err) // see "Mapping errors to HTTP"
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write(raw)
	})
	log.Fatal(http.ListenAndServe(":8080", nil))
}

With a path, refreshed tokens are written back to the same file automatically.

Many accounts

For a service where each of your users connects their own Garmin account.

Storage. Keep one row per account with the token JSON, encrypted at rest; the refresh token gives full access to the account. Never store the Garmin password.

CREATE TABLE garmin_accounts (
  account_id  TEXT PRIMARY KEY,
  tokens      BYTEA NOT NULL,      -- encrypted token JSON
  updated_at  TIMESTAMPTZ NOT NULL
);

The examples below assume a small store interface over that table:

type TokenStore interface {
	Load(accountID string) (string, error) // "" when the account is not connected
	Save(accountID, tokenJSON string) error
	Delete(accountID string) error
}

Keeping clients. Cache one *gc.Garmin per account and create it from the stored tokens on first use. WithTokenSaver writes every refreshed token back to the store.

var errNotConnected = errors.New("garmin account not connected")

type Accounts struct {
	store   TokenStore
	mu      sync.Mutex
	clients map[string]*gc.Garmin
}

func NewAccounts(store TokenStore) *Accounts {
	return &Accounts{store: store, clients: map[string]*gc.Garmin{}}
}

func (a *Accounts) newClient(id, email, password string, opts ...gc.Option) *gc.Garmin {
	saver := gc.WithTokenSaver(func(t string) {
		if err := a.store.Save(id, t); err != nil {
			log.Printf("save garmin tokens for %s: %v", id, err)
		}
	})
	return gc.New(email, password, append(opts, saver)...)
}

// Get returns the client for a connected account.
func (a *Accounts) Get(ctx context.Context, id string) (*gc.Garmin, error) {
	a.mu.Lock()
	defer a.mu.Unlock()
	if g, ok := a.clients[id]; ok {
		return g, nil
	}
	tokens, err := a.store.Load(id)
	if err != nil {
		return nil, err
	}
	if tokens == "" {
		return nil, errNotConnected
	}
	g := a.newClient(id, "", "")
	if _, err := g.Login(ctx, tokens); err != nil {
		return nil, err // ErrAuthentication: the user must connect again
	}
	a.clients[id] = g
	return g, nil
}

// Forget drops a cached client, e.g. after its tokens were rejected.
func (a *Accounts) Forget(id string) {
	a.mu.Lock()
	delete(a.clients, id)
	a.mu.Unlock()
}

Connecting an account. Log in with the user's email and password once. The token saver stores the tokens as soon as Garmin issues them. When the account uses MFA, Login returns needsMFA=true and the same *gc.Garmin must be kept until the user sends the code.

type Connector struct {
	accounts *Accounts
	mu       sync.Mutex
	pending  map[string]pendingLogin // by account ID
}

type pendingLogin struct {
	g       *gc.Garmin
	expires time.Time
}

// Connect starts linking a Garmin account. needsMFA means the user must
// submit a code to FinishMFA within 10 minutes.
func (c *Connector) Connect(ctx context.Context, id, email, password string) (needsMFA bool, err error) {
	g := c.accounts.newClient(id, email, password, gc.WithReturnOnMFA())
	needsMFA, err = g.Login(ctx, "") // see the $GARMINTOKENS note below
	if err != nil {
		return false, err
	}
	if needsMFA {
		c.mu.Lock()
		c.pending[id] = pendingLogin{g, time.Now().Add(10 * time.Minute)}
		c.mu.Unlock()
		return true, nil
	}
	c.accounts.put(id, g)
	return false, nil
}

// FinishMFA completes a login that needed a code. A wrong code can be retried.
func (c *Connector) FinishMFA(ctx context.Context, id, code string) error {
	c.mu.Lock()
	p, ok := c.pending[id]
	c.mu.Unlock()
	if !ok || time.Now().After(p.expires) {
		return errors.New("no pending Garmin login; connect again")
	}
	if err := p.g.ResumeLogin(ctx, code); err != nil {
		return err
	}
	c.mu.Lock()
	delete(c.pending, id)
	c.mu.Unlock()
	c.accounts.put(id, p.g)
	return nil
}

func (a *Accounts) put(id string, g *gc.Garmin) {
	a.mu.Lock()
	a.clients[id] = g
	a.mu.Unlock()
}

Expose these behind your own authenticated endpoints, for example:

Endpoint Calls
POST /garmin/connect {email, password} Connect; answer {"mfa_required": true} when needed
POST /garmin/connect/mfa {code} FinishMFA
DELETE /garmin/connect Accounts.Forget and TokenStore.Delete
GET /garmin/summary?date=... Accounts.Get, then GetUserSummary

Using an account in a handler:

func (s *Server) summary(w http.ResponseWriter, r *http.Request) {
	id := currentAccountID(r) // from your own auth
	g, err := s.accounts.Get(r.Context(), id)
	if err == nil {
		var raw json.RawMessage
		if raw, err = g.GetUserSummary(r.Context(), r.URL.Query().Get("date")); err == nil {
			w.Header().Set("Content-Type", "application/json")
			w.Write(raw)
			return
		}
	}
	if errors.Is(err, gc.ErrAuthentication) {
		s.accounts.Forget(id) // tokens rejected: ask the user to connect again
	}
	writeGarminError(w, err)
}

Do not set $GARMINTOKENS in a multi-account service. Login falls back to it when the tokenstore argument is empty, which would make a new connection reuse another account's tokens.

Mapping errors to HTTP
func writeGarminError(w http.ResponseWriter, err error) {
	status := http.StatusBadGateway // Garmin or network failure
	switch {
	case errors.Is(err, errNotConnected):
		status = http.StatusConflict
	case errors.Is(err, gc.ErrInvalidArgument), errors.Is(err, gc.ErrInvalidFileFormat):
		status = http.StatusBadRequest
	case errors.Is(err, gc.ErrAuthentication):
		status = http.StatusUnauthorized // reconnect the Garmin account
	case errors.Is(err, gc.ErrNotFound):
		status = http.StatusNotFound
	case errors.Is(err, gc.ErrTooManyRequests):
		status = http.StatusTooManyRequests
	}
	http.Error(w, err.Error(), status)
}
Production checklist
  • Create one *gc.Garmin per account at startup or first use, never per request: logging in on every request is slow and triggers Garmin's rate limiting.
  • Persist tokens: a writable token path for one account, WithTokenSaver for many.
  • Encrypt stored tokens, and never log them or the password.
  • Connect accounts one at a time. Many password logins from the same server IP in a short time get blocked by Cloudflare (ErrTooManyRequests); token-based logins are not affected.
  • Pass the request's context so cancelled requests stop their Garmin calls.
  • Cache what you read if you serve it often; Garmin rate-limits accounts that poll heavily.
  • Run cmd/smoke when something breaks. Garmin can change this private API at any time.

Reference

Decoding responses

Forward json.RawMessage to your clients directly, or decode only the fields you need with As:

type Summary struct {
	TotalSteps int `json:"totalSteps"`
	RestingHR  int `json:"restingHeartRate"`
}
s, err := gc.As[Summary](g.GetUserSummary(ctx, "2026-10-01"))

Dates are YYYY-MM-DD strings, IDs are int64, and timestamps are time.Time (the zero value means now). Methods return nil when Garmin answers with an empty body.

Options
Option Effect
WithTokenSaver(fn) Call fn(tokenJSON) whenever tokens are obtained or refreshed
WithReturnOnMFA() Login returns needsMFA=true instead of prompting; finish with ResumeLogin
WithPromptMFA(fn) Ask for the MFA code during Login (CLIs)
WithRetry(n, min, max) Retries for 5xx and network errors on reads (default 3, 1s to 10s)
WithLogger(l) *slog.Logger for debug output (default: discard)
WithCN() Use garmin.cn accounts
WithVerifyLogin(false) Skip checking a new token against the API before accepting it

Login(ctx, tokenstore) takes a token directory or .json path, or the token JSON itself; an empty string falls back to $GARMINTOKENS. g.Client.Dumps() returns the current token JSON. Logout clears the session and deletes the token file.

Login tries several strategies in turn (mobile and web SSO, each with browser TLS fingerprints via tls-client) to get past Garmin's bot protection.

Errors
Error (errors.Is) Meaning
ErrAuthentication Bad credentials, failed MFA, or tokens the API rejects (401)
ErrTooManyRequests Rate limited by Garmin (429)
ErrNotFound Resource does not exist (404); also matches ErrConnection
ErrConnection Any other HTTP or network failure
ErrInvalidArgument Input rejected before any request was sent
ErrInvalidFileFormat Upload file is not FIT, GPX or TCX

gc.StatusCode(err) returns the HTTP status, or 0.

Endpoints
  • Daily health: summary, steps, floors, heart rate, resting HR, HRV, stress, sleep, body battery, SpO2, respiration, hydration, intensity minutes, lifestyle logging
  • Body: body composition, weigh-ins, blood pressure (read, add, delete)
  • Performance: VO2 max, training status, training readiness, load balance, endurance and hill score, race predictions, lactate threshold, FTP, heart rate and power zones, fitness age, running tolerance, personal records
  • Activities: list, search by date, details, splits, weather, HR and power zones, exercise sets, photos, upload and import (FIT, GPX, TCX), download (original, TCX, GPX, KML, CSV), create, rename, retype, delete
  • Devices and gear: devices, settings, alarms, solar data, gear, gear stats and defaults, link gear to activities
  • Workouts: list, get, download, upload, update, delete, schedule, push to device, plus typed builders (NewWorkout, IntervalStep, StrengthSet, pace, heart rate and power targets) and a catalog of 1527 strength exercises (Exercises, FindExercises)
  • Training plans, goals, badges and challenges
  • Women's health: menstrual cycle data, daily logs, calendar updates, pregnancy summary
  • Other: jet lag trips, nutrition logs, golf scorecards and stats, GraphQL

Run go doc github.com/katarsisxyz/garminconnect-go for every method and its arguments. Any endpoint not wrapped yet can be called with g.ConnectAPI(ctx, path, params) (JSON) or g.Download(ctx, path) (bytes).

Testing against a real account

cmd/smoke calls every read-only endpoint and prints an OK/ERR/SKIP table without printing any data:

go run ./cmd/smoke [YYYY-MM-DD]

It reuses the tokens in ~/.garminconnect. For the first run, copy credentials.example.json to credentials.json (gitignored) and fill it in; you will be asked for an MFA code if your account uses one. Once tokens are saved, credentials.json can be deleted.

Disclaimer

This uses Garmin Connect's private API, which Garmin can change at any time. It is not affiliated with or endorsed by Garmin.

License

MIT, see LICENSE. Derived from python-garminconnect by Ron Klinkien.

Documentation

Overview

Package garminconnect is a Go port of python-garminconnect, an unofficial client for the Garmin Connect API.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrAuthentication    = errors.New("garminconnect: authentication failed")
	ErrTooManyRequests   = errors.New("garminconnect: too many requests")
	ErrConnection        = errors.New("garminconnect: connection error")
	ErrNotFound          = errors.New("garminconnect: not found") // also matches ErrConnection
	ErrInvalidFileFormat = errors.New("garminconnect: invalid file format")
	ErrInvalidArgument   = errors.New("garminconnect: invalid argument")
)

Sentinel errors. Check them with errors.Is.

View Source
var (
	SportRunning          = SportType{1, "running", 1}
	SportCycling          = SportType{2, "cycling", 2}
	SportSwimming         = SportType{4, "swimming", 3}
	SportStrengthTraining = SportType{5, "strength_training", 5}
	SportCardioTraining   = SportType{6, "cardio_training", 6} // fitness equipment
	SportMultiSport       = SportType{10, "multi_sport", 10}
	SportWalking          = SportType{17, "walking", 17}
	SportHiking           = SportType{18, "hiking", 18}
)

Sport types from /workout-service/workout/types.

View Source
var ExerciseCategories = []string{
	"BANDED_EXERCISES",
	"BATTLE_ROPE",
	"BENCH_PRESS",
	"BIKE_OUTDOOR",
	"CALF_RAISE",
	"CARDIO",
	"CARRY",
	"CHOP",
	"CORE",
	"CRUNCH",
	"CURL",
	"DEADLIFT",
	"ELLIPTICAL",
	"FLOOR_CLIMB",
	"FLYE",
	"HIP_RAISE",
	"HIP_STABILITY",
	"HIP_SWING",
	"HYPEREXTENSION",
	"INDOOR_BIKE",
	"LADDER",
	"LATERAL_RAISE",
	"LEG_CURL",
	"LEG_RAISE",
	"LUNGE",
	"OLYMPIC_LIFT",
	"PLANK",
	"PLYO",
	"PULL_UP",
	"PUSH_UP",
	"ROW",
	"RUN",
	"RUN_INDOOR",
	"SANDBAG",
	"SHOULDER_PRESS",
	"SHOULDER_STABILITY",
	"SHRUG",
	"SIT_UP",
	"SLED",
	"SLEDGE_HAMMER",
	"SQUAT",
	"STAIR_STEPPER",
	"SUSPENSION",
	"TIRE",
	"TOTAL_BODY",
	"TRICEPS_EXTENSION",
	"WARM_UP",
}

ExerciseCategories lists all distinct exercise categories.

View Source
var Exercises = []Exercise{}/* 1527 elements not displayed */

Exercises is every selectable strength exercise from the Garmin Connect workout editor (1527 exercises across 47 categories). Exercise may be "" (the workout shows only the category name).

Functions

func As

func As[T any](raw json.RawMessage, err error) (T, error)

As decodes a raw JSON result into T:

stats, err := garminconnect.As[MyStats](g.GetUserSummary(ctx, "2026-10-01"))

func PaceToMPS

func PaceToMPS(minutes, seconds int, units string) float64

PaceToMPS converts a min:sec pace per "km" or "mi" to m/s.

func ParseActivityDetailMetrics

func ParseActivityDetailMetrics(details json.RawMessage) ([]map[string]any, error)

ParseActivityDetailMetrics resolves the positional samples of GetActivityDetails into one map per sample keyed by metric name. Descriptors without a valid metricsIndex are skipped and samples missing a channel omit that key. The duration keys (sumDuration, sumElapsedDuration, sumMovingDuration) differ; pick the one you mean.

func SpeedToMPS

func SpeedToMPS(speed float64, units string) float64

SpeedToMPS converts a "kph" or "mph" speed to m/s.

func StatusCode

func StatusCode(err error) int

StatusCode returns the HTTP status carried by err, or 0.

func TokenFilePath

func TokenFilePath(path string) (string, error)

TokenFilePath returns the token file for a directory or .json path. It rejects "~user" paths and symlinks anywhere in the ancestry, so a planted symlink cannot redirect load/dump/logout.

Types

type ActivityDownloadFormat

type ActivityDownloadFormat int

ActivityDownloadFormat selects the DownloadActivity export format.

const (
	FormatOriginal ActivityDownloadFormat = iota // zip with the original FIT file
	FormatTCX
	FormatGPX
	FormatKML
	FormatCSV // csv of the splits
)

type BodyComposition

type BodyComposition struct {
	Weight            float64
	PercentFat        *float64
	PercentHydration  *float64
	VisceralFatMass   *float64
	BoneMass          *float64
	MuscleMass        *float64
	BasalMet          *float64
	ActiveMet         *float64
	PhysiqueRating    *float64
	MetabolicAge      *float64
	VisceralFatRating *float64
	BMI               *float64
}

BodyComposition holds the optional fields of AddBodyComposition; nil fields are written as FIT "invalid".

type Client

type Client struct {

	// SkipStrategies names login strategies to skip, e.g. "mobile+tls".
	SkipStrategies map[string]bool
	// VerifyLogin validates each strategy's token against the API tier
	// before accepting it.
	VerifyLogin bool
	Log         *slog.Logger
	// OnTokens, when set, receives the token JSON (as Dumps returns it)
	// whenever tokens are obtained or refreshed. It runs outside the
	// client's lock, so it may call back into the client.
	OnTokens func(tokenJSON string)
	// contains filtered or unexported fields
}

Client talks to Garmin Connect: it logs in, holds tokens and signs API calls.

func NewClient

func NewClient(domain string) (*Client, error)

NewClient returns a client for domain "garmin.com" or "garmin.cn".

func (*Client) Dump

func (c *Client) Dump(path string) error

Dump writes the tokens to disk as 0600 inside a 0700 directory, atomically via an unpredictable temp file, since the refresh token grants persistent account access.

func (*Client) Dumps

func (c *Client) Dumps() string

Dumps serializes the tokens to JSON.

func (*Client) IsAuthenticated

func (c *Client) IsAuthenticated() bool

IsAuthenticated reports whether the client holds a token.

func (*Client) Load

func (c *Client) Load(path string) error

Load reads tokens from disk and remembers path for later refresh dumps.

func (*Client) Loads

func (c *Client) Loads(s string) error

Loads restores tokens from a JSON string produced by Dumps.

func (*Client) Login

func (c *Client) Login(ctx context.Context, email, password string, promptMFA func() (string, error), returnOnMFA bool) (needsMFA bool, err error)

Login runs the strategy chain. With returnOnMFA it returns needsMFA=true instead of calling promptMFA; finish with ResumeLogin.

func (*Client) Request

func (c *Client) Request(ctx context.Context, method, path string, opts *RequestOptions) ([]byte, error)

Request performs an authenticated call against connectapi and returns the raw body (nil for 204 / empty). Errors are *Error values whose Kind is ErrAuthentication (401), ErrTooManyRequests (429), ErrNotFound (404) or ErrConnection.

func (*Client) ResumeLogin

func (c *Client) ResumeLogin(ctx context.Context, code string) error

ResumeLogin completes a login that returned needsMFA. A wrong code keeps the pending MFA session so the caller can retry.

type DailyCalories

type DailyCalories struct {
	CalendarDate string   `json:"calendarDate"`
	Active       *float64 `json:"active"`
	Resting      *float64 `json:"resting"`
	Total        float64  `json:"total"`
}

DailyCalories is one day of active + resting (BMR) calories.

type DailyValue

type DailyValue struct {
	CalendarDate string  `json:"calendarDate"`
	Value        float64 `json:"value"`
}

DailyValue is one calendar date with a value.

type EndCondition

type EndCondition struct {
	ConditionTypeID  int    `json:"conditionTypeId"`
	ConditionTypeKey string `json:"conditionTypeKey"`
	DisplayOrder     int    `json:"displayOrder"`
	Displayable      bool   `json:"displayable"`
}

EndCondition says when a step ends.

type Error

type Error struct {
	Kind       error
	StatusCode int
	Msg        string
	Err        error
}

Error carries the error kind, the HTTP status (0 when not an HTTP failure) and the underlying cause.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Is

func (e *Error) Is(target error) bool

Is makes a not-found error also match ErrConnection, mirroring the Python exception hierarchy.

func (*Error) Unwrap

func (e *Error) Unwrap() []error

type ExecutableStep

type ExecutableStep struct {
	Type                    string         `json:"type"` // "ExecutableStepDTO"
	StepOrder               int            `json:"stepOrder"`
	StepType                *StepType      `json:"stepType,omitempty"`
	EndCondition            *EndCondition  `json:"endCondition,omitempty"`
	EndConditionValue       *float64       `json:"endConditionValue,omitempty"`
	TargetType              *TargetType    `json:"targetType,omitempty"`
	TargetValueOne          *float64       `json:"targetValueOne,omitempty"`
	TargetValueTwo          *float64       `json:"targetValueTwo,omitempty"`
	ZoneNumber              *int           `json:"zoneNumber,omitempty"`
	SecondaryTargetType     *TargetType    `json:"secondaryTargetType,omitempty"`
	SecondaryTargetValueOne *float64       `json:"secondaryTargetValueOne,omitempty"`
	SecondaryTargetValueTwo *float64       `json:"secondaryTargetValueTwo,omitempty"`
	SecondaryZoneNumber     *int           `json:"secondaryZoneNumber,omitempty"`
	StrokeType              map[string]any `json:"strokeType,omitempty"`
	EquipmentType           map[string]any `json:"equipmentType,omitempty"`
	ChildStepID             *int           `json:"childStepId,omitempty"`
	// Strength steps.
	Category     string         `json:"category,omitempty"`
	ExerciseName *string        `json:"exerciseName,omitempty"`
	WeightValue  *float64       `json:"weightValue,omitempty"` // grams
	WeightUnit   map[string]any `json:"weightUnit,omitempty"`
}

ExecutableStep is a warmup, interval, recovery, cooldown or rest step.

func CooldownStep

func CooldownStep(durationSecs float64, order int) *ExecutableStep

CooldownStep is a timed cooldown.

func DistanceIntervalStep

func DistanceIntervalStep(distanceMeters float64, order int, primary, secondary *Target) (*ExecutableStep, error)

DistanceIntervalStep is an interval that ends after distanceMeters.

func IntervalStep

func IntervalStep(durationSecs float64, order int, primary, secondary *Target) (*ExecutableStep, error)

IntervalStep is a timed interval with optional primary/secondary targets.

func RecoveryStep

func RecoveryStep(durationSecs float64, order int) *ExecutableStep

RecoveryStep is a timed recovery.

func StrengthExerciseStep

func StrengthExerciseStep(category string, order, reps int, exerciseName string, weightKG *float64) *ExecutableStep

StrengthExerciseStep is a rep-based exercise. category/exerciseName come from Exercises; weightKG nil means no target load.

func StrengthRestStep

func StrengthRestStep(durationSecs float64, order int) *ExecutableStep

StrengthRestStep is a timed rest between sets.

func WarmupStep

func WarmupStep(durationSecs float64, order int) *ExecutableStep

WarmupStep is a timed warmup.

type Exercise

type Exercise struct {
	Name     string `json:"name"`
	Category string `json:"category"`
	Exercise string `json:"exercise"`
}

Exercise is one strength-exercise catalog entry.

func FindExercises

func FindExercises(term string) []Exercise

FindExercises returns exercises whose name contains term, case-insensitively.

func ResolveExercise

func ResolveExercise(name string) (Exercise, bool)

ResolveExercise returns the catalog entry with this exact display name.

type Garmin

type Garmin struct {
	Client *Client

	DisplayName string
	FullName    string
	UnitSystem  string
	ProfileID   int64 // 0 when unknown
	// contains filtered or unexported fields
}

Garmin fetches data from Garmin Connect.

func New

func New(email, password string, opts ...Option) *Garmin

New returns a Garmin client. email/password may be empty when a tokenstore will be supplied to Login.

func (*Garmin) AddBodyComposition

func (g *Garmin) AddBodyComposition(ctx context.Context, ts time.Time, bc BodyComposition) (json.RawMessage, error)

AddBodyComposition uploads a weight-scale FIT record. A zero ts means now.

func (*Garmin) AddGearToActivity

func (g *Garmin) AddGearToActivity(ctx context.Context, gearUUID string, activityID int64) (json.RawMessage, error)

AddGearToActivity links gear to an activity.

func (*Garmin) AddHydrationData

func (g *Garmin) AddHydrationData(ctx context.Context, valueML float64, ts time.Time, cdate string) (json.RawMessage, error)

AddHydrationData adds (or with a negative value subtracts) water in ml. With neither ts nor cdate it uses now; with only cdate, midnight local; with only ts, its date; with both they must agree.

func (*Garmin) AddJetlagTrip

func (g *Garmin) AddJetlagTrip(ctx context.Context, start, end string, flights []JetlagFlight) (json.RawMessage, error)

AddJetlagTrip creates a trip; each flight is one leg (a connection is two flights). Garmin may refuse dates overlapping an existing trip with 400. The response carries tripId and flightIds; dailyStatus appears in GetJetlagTrips once travel starts.

func (*Garmin) AddWeighIn

func (g *Garmin) AddWeighIn(ctx context.Context, weight float64, unit string, ts time.Time) (json.RawMessage, error)

AddWeighIn adds a manual weigh-in. unit is "kg" or "lbs"; a zero ts means now.

func (*Garmin) AddWeighInWithTimestamps

func (g *Garmin) AddWeighInWithTimestamps(ctx context.Context, weight float64, unit string, local, gmt time.Time) (json.RawMessage, error)

AddWeighInWithTimestamps adds a weigh-in with explicit local and GMT times; zero values default to now.

func (*Garmin) ConfirmMenstrualPeriodStart

func (g *Garmin) ConfirmMenstrualPeriodStart(ctx context.Context, periodStart string, periodLength, cycleLength int, predictedCycle bool) (json.RawMessage, error)

ConfirmMenstrualPeriodStart confirms a period start, e.g. turning a predicted cycle into a confirmed one. Pass the lengths shown that day.

func (*Garmin) ConnectAPI

func (g *Garmin) ConnectAPI(ctx context.Context, path string, params url.Values) (json.RawMessage, error)

ConnectAPI performs an arbitrary authenticated GET and returns the JSON.

func (*Garmin) CountActivities

func (g *Garmin) CountActivities(ctx context.Context) (int64, error)

CountActivities returns the total number of activities.

func (*Garmin) CreateGear

func (g *Garmin) CreateGear(ctx context.Context, s GearSpec) (json.RawMessage, error)

CreateGear creates gear (e.g. shoes) and returns it.

func (*Garmin) CreateManualActivity

func (g *Garmin) CreateManualActivity(ctx context.Context, start, timeZone, typeKey string, distanceKM float64, durationMin int, name string) (json.RawMessage, error)

CreateManualActivity creates a private activity. typeKey is the activity type key without the "activity_type_" prefix (e.g. "resort_skiing"); start is like "2023-12-02T10:00:00.000"; timeZone like "Europe/Paris".

func (*Garmin) CreateManualActivityFromJSON

func (g *Garmin) CreateManualActivityFromJSON(ctx context.Context, payload any) (json.RawMessage, error)

CreateManualActivityFromJSON creates an activity from a raw payload.

func (*Garmin) DeleteActivity

func (g *Garmin) DeleteActivity(ctx context.Context, id int64) (json.RawMessage, error)

DeleteActivity deletes an activity.

func (*Garmin) DeleteBloodPressure

func (g *Garmin) DeleteBloodPressure(ctx context.Context, version int64, cdate string) (json.RawMessage, error)

DeleteBloodPressure deletes one measurement.

func (*Garmin) DeleteJetlagTrip

func (g *Garmin) DeleteJetlagTrip(ctx context.Context, tripID int64) (json.RawMessage, error)

DeleteJetlagTrip deletes a trip.

func (*Garmin) DeleteWeighIn

func (g *Garmin) DeleteWeighIn(ctx context.Context, weightPK int64, cdate string) (json.RawMessage, error)

DeleteWeighIn deletes one weigh-in.

func (*Garmin) DeleteWeighIns

func (g *Garmin) DeleteWeighIns(ctx context.Context, cdate string, deleteAll bool) (int, error)

DeleteWeighIns deletes the weigh-ins of cdate and returns how many were deleted. With several on that day nothing is deleted unless deleteAll.

func (*Garmin) DeleteWorkout

func (g *Garmin) DeleteWorkout(ctx context.Context, id int64) (json.RawMessage, error)

DeleteWorkout deletes a workout template from the library.

func (*Garmin) Download

func (g *Garmin) Download(ctx context.Context, path string) ([]byte, error)

Download performs an authenticated GET and returns the raw bytes.

func (*Garmin) DownloadActivity

func (g *Garmin) DownloadActivity(ctx context.Context, id int64, format ActivityDownloadFormat) ([]byte, error)

DownloadActivity returns the activity export in the requested format.

func (*Garmin) DownloadHealthSnapshot

func (g *Garmin) DownloadHealthSnapshot(ctx context.Context, date string) ([]byte, error)

DownloadHealthSnapshot returns the Health Snapshot ZIP for a date.

func (*Garmin) DownloadWorkout

func (g *Garmin) DownloadWorkout(ctx context.Context, id int64) ([]byte, error)

DownloadWorkout returns a workout as a FIT file.

func (*Garmin) GetActivities

func (g *Garmin) GetActivities(ctx context.Context, start, limit int, activityType, subType string) (json.RawMessage, error)

GetActivities returns activities starting at offset start (0 = most recent). activityType/subType are optional filters ("" to skip).

func (*Garmin) GetActivitiesByDate

func (g *Garmin) GetActivitiesByDate(ctx context.Context, startdate, enddate, activityType, sortOrder string) (json.RawMessage, error)

GetActivitiesByDate returns all activities between startdate and enddate ("" = open), paging 20 at a time like the web UI. activityType (e.g. "running", "cycling") and sortOrder ("asc") are optional.

func (*Garmin) GetActivitiesForDate

func (g *Garmin) GetActivitiesForDate(ctx context.Context, date string) (json.RawMessage, error)

GetActivitiesForDate returns activities for a date.

func (*Garmin) GetActivity

func (g *Garmin) GetActivity(ctx context.Context, id int64) (json.RawMessage, error)

GetActivity returns the activity summary, including basic splits.

func (*Garmin) GetActivityDetails

func (g *Garmin) GetActivityDetails(ctx context.Context, id int64, maxChart, maxPoly int) (json.RawMessage, error)

GetActivityDetails returns detail charts (defaults: maxChart 2000, maxPoly 4000). See ParseActivityDetailMetrics.

func (*Garmin) GetActivityExerciseSets

func (g *Garmin) GetActivityExerciseSets(ctx context.Context, id int64) (json.RawMessage, error)

GetActivityExerciseSets returns the exercise sets of an activity.

func (*Garmin) GetActivityGear

func (g *Garmin) GetActivityGear(ctx context.Context, activityID int64) (json.RawMessage, error)

GetActivityGear returns the gear used for an activity.

func (*Garmin) GetActivityHRInTimezones

func (g *Garmin) GetActivityHRInTimezones(ctx context.Context, id int64) (json.RawMessage, error)

GetActivityHRInTimezones returns time in heart rate zones.

func (*Garmin) GetActivityImages

func (g *Garmin) GetActivityImages(ctx context.Context, id int64) (json.RawMessage, error)

GetActivityImages returns the photos attached to an activity. Their URLs are presigned and expire after 24 hours.

func (*Garmin) GetActivityPowerInTimezones

func (g *Garmin) GetActivityPowerInTimezones(ctx context.Context, id int64) (json.RawMessage, error)

GetActivityPowerInTimezones returns time in power zones.

func (*Garmin) GetActivitySplitSummaries

func (g *Garmin) GetActivitySplitSummaries(ctx context.Context, id int64) (json.RawMessage, error)

GetActivitySplitSummaries returns split summaries.

func (*Garmin) GetActivitySplits

func (g *Garmin) GetActivitySplits(ctx context.Context, id int64) (json.RawMessage, error)

GetActivitySplits returns activity splits.

func (*Garmin) GetActivityTypedSplits

func (g *Garmin) GetActivityTypedSplits(ctx context.Context, id int64) (json.RawMessage, error)

GetActivityTypedSplits returns typed splits (more detail for e.g. bouldering).

func (*Garmin) GetActivityTypes

func (g *Garmin) GetActivityTypes(ctx context.Context) (json.RawMessage, error)

GetActivityTypes returns all activity types.

func (*Garmin) GetActivityWeather

func (g *Garmin) GetActivityWeather(ctx context.Context, id int64) (json.RawMessage, error)

GetActivityWeather returns the weather during an activity.

func (*Garmin) GetAdaptiveTrainingPlanByID

func (g *Garmin) GetAdaptiveTrainingPlanByID(ctx context.Context, planID int64) (json.RawMessage, error)

GetAdaptiveTrainingPlanByID returns an adaptive training plan.

func (*Garmin) GetAdhocChallenges

func (g *Garmin) GetAdhocChallenges(ctx context.Context, start, limit int) (json.RawMessage, error)

GetAdhocChallenges returns historical ad-hoc challenges.

func (*Garmin) GetAllDayEvents

func (g *Garmin) GetAllDayEvents(ctx context.Context, cdate string) (json.RawMessage, error)

GetAllDayEvents returns daily events for cdate, including auto-detected activities.

func (*Garmin) GetAllDayStress

func (g *Garmin) GetAllDayStress(ctx context.Context, cdate string) (json.RawMessage, error)

GetAllDayStress returns all-day stress data for cdate.

func (*Garmin) GetAvailableBadgeChallenges

func (g *Garmin) GetAvailableBadgeChallenges(ctx context.Context, start, limit int) (json.RawMessage, error)

GetAvailableBadgeChallenges returns available badge challenges (start >= 1).

func (*Garmin) GetAvailableBadges

func (g *Garmin) GetAvailableBadges(ctx context.Context) (json.RawMessage, error)

GetAvailableBadges returns badges not yet earned.

func (*Garmin) GetBadgeChallenges

func (g *Garmin) GetBadgeChallenges(ctx context.Context, start, limit int) (json.RawMessage, error)

GetBadgeChallenges returns completed badge challenges (start >= 1).

func (*Garmin) GetBloodPressure

func (g *Garmin) GetBloodPressure(ctx context.Context, startdate, enddate string) (json.RawMessage, error)

GetBloodPressure returns blood pressure for startdate..enddate.

func (*Garmin) GetBodyBattery

func (g *Garmin) GetBodyBattery(ctx context.Context, startdate, enddate string) (json.RawMessage, error)

GetBodyBattery returns body battery values for startdate..enddate.

func (*Garmin) GetBodyBatteryEvents

func (g *Garmin) GetBodyBatteryEvents(ctx context.Context, cdate string) (json.RawMessage, error)

GetBodyBatteryEvents returns body battery events (sleep, activities, naps) for cdate.

func (*Garmin) GetBodyComposition

func (g *Garmin) GetBodyComposition(ctx context.Context, startdate, enddate string) (json.RawMessage, error)

GetBodyComposition returns body composition for startdate..enddate (enddate "" means a single day).

func (*Garmin) GetCaloriesDaily

func (g *Garmin) GetCaloriesDaily(ctx context.Context, start, end string) ([]DailyCalories, error)

GetCaloriesDaily returns daily active and resting calories for start..end.

func (*Garmin) GetCyclingFTP

func (g *Garmin) GetCyclingFTP(ctx context.Context) (json.RawMessage, error)

GetCyclingFTP returns the latest cycling Functional Threshold Power.

func (*Garmin) GetDailySteps

func (g *Garmin) GetDailySteps(ctx context.Context, start, end string) (json.RawMessage, error)

GetDailySteps returns daily steps for start..end, splitting ranges over Garmin's 28-day limit into several requests.

func (*Garmin) GetDailyTrainingStatus

func (g *Garmin) GetDailyTrainingStatus(ctx context.Context, cdate string) (json.RawMessage, error)

GetDailyTrainingStatus returns the training status and acute/chronic load for cdate.

func (*Garmin) GetDailyWeighIns

func (g *Garmin) GetDailyWeighIns(ctx context.Context, cdate string) (json.RawMessage, error)

GetDailyWeighIns returns weigh-ins for cdate.

func (*Garmin) GetDeviceAlarms

func (g *Garmin) GetDeviceAlarms(ctx context.Context) (json.RawMessage, error)

GetDeviceAlarms returns the alarms of all devices.

func (*Garmin) GetDeviceLastUsed

func (g *Garmin) GetDeviceLastUsed(ctx context.Context) (json.RawMessage, error)

GetDeviceLastUsed returns the last used device.

func (*Garmin) GetDeviceSettings

func (g *Garmin) GetDeviceSettings(ctx context.Context, deviceID int64) (json.RawMessage, error)

GetDeviceSettings returns settings of a device.

func (*Garmin) GetDeviceSolarData

func (g *Garmin) GetDeviceSolarData(ctx context.Context, deviceID int64, startdate, enddate string) (json.RawMessage, error)

GetDeviceSolarData returns solar input of a device for startdate..enddate (enddate "" = single day view).

func (*Garmin) GetDevices

func (g *Garmin) GetDevices(ctx context.Context) (json.RawMessage, error)

GetDevices returns the devices registered to the account.

func (*Garmin) GetEarnedBadges

func (g *Garmin) GetEarnedBadges(ctx context.Context) (json.RawMessage, error)

GetEarnedBadges returns all earned badges.

func (*Garmin) GetEnduranceScore

func (g *Garmin) GetEnduranceScore(ctx context.Context, startdate, enddate string) (json.RawMessage, error)

GetEnduranceScore returns the score for one day (enddate "") or weekly aggregates for a range.

func (*Garmin) GetFitnessAgeData

func (g *Garmin) GetFitnessAgeData(ctx context.Context, cdate string) (json.RawMessage, error)

GetFitnessAgeData returns fitness age data for cdate.

func (*Garmin) GetFloors

func (g *Garmin) GetFloors(ctx context.Context, cdate string) (json.RawMessage, error)

GetFloors returns floors-climbed chart data for cdate.

func (*Garmin) GetFunctionalThresholdPowerRange

func (g *Garmin) GetFunctionalThresholdPowerRange(ctx context.Context, start, end, sport, aggregation string) (json.RawMessage, error)

GetFunctionalThresholdPowerRange returns FTP history for a sport (default "RUNNING") and aggregation (default "daily").

func (*Garmin) GetGear

func (g *Garmin) GetGear(ctx context.Context, userProfileNumber int64) (json.RawMessage, error)

GetGear returns the gear of a user profile number.

func (*Garmin) GetGearActivities

func (g *Garmin) GetGearActivities(ctx context.Context, gearUUID string, limit int) (json.RawMessage, error)

GetGearActivities returns activities that used the gear (limit capped at 1000); [] for retired/removed gear.

func (*Garmin) GetGearDefaults

func (g *Garmin) GetGearDefaults(ctx context.Context, userProfileNumber int64) (json.RawMessage, error)

GetGearDefaults returns default gear per activity type.

func (*Garmin) GetGearStats

func (g *Garmin) GetGearStats(ctx context.Context, gearUUID string) (json.RawMessage, error)

GetGearStats returns statistics of a gear item; {} for retired/removed gear.

func (*Garmin) GetGoals

func (g *Garmin) GetGoals(ctx context.Context, status string, start, limit int) (json.RawMessage, error)

GetGoals returns all goals with status "active" (default), "future" or "past", paging from the 1-based start (default 1) by limit (default 30).

func (*Garmin) GetGolfClubStats

func (g *Garmin) GetGolfClubStats(ctx context.Context, limit int) (json.RawMessage, error)

GetGolfClubStats returns golf clubs and their statistics (default limit 1000).

func (*Garmin) GetGolfScorecard

func (g *Garmin) GetGolfScorecard(ctx context.Context, scorecardID int64) (json.RawMessage, error)

GetGolfScorecard returns a scorecard's detail.

func (*Garmin) GetGolfShotData

func (g *Garmin) GetGolfShotData(ctx context.Context, scorecardID int64, holes string) (json.RawMessage, error)

GetGolfShotData returns shot data per hole. holes is "" for every hole or holes 1-18 separated by ',' or '-' ("1,2,3"). Garmin drops holes 10-18 from filtered queries, so any of those returns all 18 holes.

func (*Garmin) GetGolfSummary

func (g *Garmin) GetGolfSummary(ctx context.Context, start, limit int) (json.RawMessage, error)

GetGolfSummary returns golf scorecard summaries (default limit 100).

func (*Garmin) GetGolfUserStats

func (g *Garmin) GetGolfUserStats(ctx context.Context) (json.RawMessage, error)

GetGolfUserStats returns golf statistics such as handicap and strokes gained.

func (*Garmin) GetHRVData

func (g *Garmin) GetHRVData(ctx context.Context, cdate string) (json.RawMessage, error)

GetHRVData returns heart rate variability data for cdate.

func (*Garmin) GetHRVDataRange

func (g *Garmin) GetHRVDataRange(ctx context.Context, start, end string) (json.RawMessage, error)

GetHRVDataRange returns HRV data for start..end in one request.

func (*Garmin) GetHeartRateZones

func (g *Garmin) GetHeartRateZones(ctx context.Context) (json.RawMessage, error)

GetHeartRateZones returns heart rate zones for all sport profiles.

func (*Garmin) GetHeartRates

func (g *Garmin) GetHeartRates(ctx context.Context, cdate string) (json.RawMessage, error)

GetHeartRates returns heart rate data for cdate.

func (*Garmin) GetHillScore

func (g *Garmin) GetHillScore(ctx context.Context, startdate, enddate string) (json.RawMessage, error)

GetHillScore returns the score for one day (enddate "") or daily values for a range.

func (*Garmin) GetHydrationData

func (g *Garmin) GetHydrationData(ctx context.Context, cdate string) (json.RawMessage, error)

GetHydrationData returns hydration data for cdate.

func (*Garmin) GetInProgressBadges

func (g *Garmin) GetInProgressBadges(ctx context.Context) (json.RawMessage, error)

GetInProgressBadges returns earned and available badges still in progress, de-duplicated by badgeId (available wins).

func (*Garmin) GetInProgressVirtualChallenges

func (g *Garmin) GetInProgressVirtualChallenges(ctx context.Context, start, limit int) (json.RawMessage, error)

GetInProgressVirtualChallenges returns in-progress virtual challenges (start >= 1).

func (*Garmin) GetIntensityMinutesData

func (g *Garmin) GetIntensityMinutesData(ctx context.Context, cdate string) (json.RawMessage, error)

GetIntensityMinutesData returns intensity minutes for cdate.

func (*Garmin) GetJetlagTrips

func (g *Garmin) GetJetlagTrips(ctx context.Context) (json.RawMessage, error)

GetJetlagTrips returns all Jet Lag Adviser trips with their flights.

func (*Garmin) GetLactateThreshold

func (g *Garmin) GetLactateThreshold(ctx context.Context, latest bool, start, end, aggregation string) (json.RawMessage, error)

GetLactateThreshold returns running lactate threshold data. With latest it returns {"speed_and_heart_rate", "power"}; otherwise the history for start..end (end "" = today) as {"speed", "heart_rate", "power"}.

func (*Garmin) GetLastActivity

func (g *Garmin) GetLastActivity(ctx context.Context) (json.RawMessage, error)

GetLastActivity returns the most recent activity, or nil.

func (*Garmin) GetLifestyleLoggingData

func (g *Garmin) GetLifestyleLoggingData(ctx context.Context, cdate string) (json.RawMessage, error)

GetLifestyleLoggingData returns lifestyle logging data for cdate.

func (*Garmin) GetMaxMetrics

func (g *Garmin) GetMaxMetrics(ctx context.Context, cdate string) (json.RawMessage, error)

GetMaxMetrics returns max metrics (VO2 max etc.) for cdate.

func (*Garmin) GetMaxMetricsRange

func (g *Garmin) GetMaxMetricsRange(ctx context.Context, start, end string) (json.RawMessage, error)

GetMaxMetricsRange returns max metrics for start..end.

func (*Garmin) GetMenstrualCalendarData

func (g *Garmin) GetMenstrualCalendarData(ctx context.Context, startdate, enddate string) (json.RawMessage, error)

GetMenstrualCalendarData returns cycles with days in startdate..enddate (Garmin rejects windows over 90 days).

func (*Garmin) GetMenstrualCycleSummary

func (g *Garmin) GetMenstrualCycleSummary(ctx context.Context, date string) (json.RawMessage, error)

GetMenstrualCycleSummary returns the cycle summary for date.

func (*Garmin) GetMenstrualDataForDate

func (g *Garmin) GetMenstrualDataForDate(ctx context.Context, date string) (json.RawMessage, error)

GetMenstrualDataForDate returns the menstrual day view for a date.

func (*Garmin) GetMenstrualLastConfirmed

func (g *Garmin) GetMenstrualLastConfirmed(ctx context.Context, date string) (json.RawMessage, error)

GetMenstrualLastConfirmed returns the last confirmed cycle as of date.

func (*Garmin) GetMenstrualReports

func (g *Garmin) GetMenstrualReports(ctx context.Context, date string, cycles int, next bool, reportType, today string) (json.RawMessage, error)

GetMenstrualReports returns reports for 1, 6 or 12 cycles ending at date. reportType defaults to "CYCLE", today to the current date.

func (*Garmin) GetMorningTrainingReadiness

func (g *Garmin) GetMorningTrainingReadiness(ctx context.Context, cdate string) (json.RawMessage, error)

GetMorningTrainingReadiness returns the readiness computed right after waking (inputContext AFTER_WAKEUP_RESET), falling back to the first entry on devices that do not set inputContext. nil when there is no data.

func (*Garmin) GetNextScheduledWorkout

func (g *Garmin) GetNextScheduledWorkout(ctx context.Context) (json.RawMessage, error)

GetNextScheduledWorkout returns the earliest workout scheduled today or later in this or next month, or {} when none. Adaptive/Coach plans may show sessions the calendar service does not return yet.

func (*Garmin) GetNonCompletedBadgeChallenges

func (g *Garmin) GetNonCompletedBadgeChallenges(ctx context.Context, start, limit int) (json.RawMessage, error)

GetNonCompletedBadgeChallenges returns non-completed badge challenges (start >= 1).

func (*Garmin) GetNutritionDailyFoodLog

func (g *Garmin) GetNutritionDailyFoodLog(ctx context.Context, cdate string) (json.RawMessage, error)

GetNutritionDailyFoodLog returns the food log for cdate.

func (*Garmin) GetNutritionDailyMeals

func (g *Garmin) GetNutritionDailyMeals(ctx context.Context, cdate string) (json.RawMessage, error)

GetNutritionDailyMeals returns the meals for cdate.

func (*Garmin) GetNutritionDailySettings

func (g *Garmin) GetNutritionDailySettings(ctx context.Context, cdate string) (json.RawMessage, error)

GetNutritionDailySettings returns nutrition settings for cdate.

func (*Garmin) GetPersonalRecord

func (g *Garmin) GetPersonalRecord(ctx context.Context) (json.RawMessage, error)

GetPersonalRecord returns personal records. For running, typeId 1..7 is 1 km, 1 mile, 5 km, 10 km, half marathon, marathon, longest run.

func (*Garmin) GetPowerZones

func (g *Garmin) GetPowerZones(ctx context.Context) (json.RawMessage, error)

GetPowerZones returns power zones for all sports.

func (*Garmin) GetPowerZonesForSport

func (g *Garmin) GetPowerZonesForSport(ctx context.Context, sport string) (json.RawMessage, error)

GetPowerZonesForSport returns power zones for a sport key, e.g. "CYCLING".

func (*Garmin) GetPregnancySummary

func (g *Garmin) GetPregnancySummary(ctx context.Context) (json.RawMessage, error)

GetPregnancySummary returns the pregnancy snapshot.

func (*Garmin) GetPrimaryTrainingDevice

func (g *Garmin) GetPrimaryTrainingDevice(ctx context.Context) (json.RawMessage, error)

GetPrimaryTrainingDevice returns the primary training device and the priority of all devices.

func (*Garmin) GetProgressSummaryBetweenDates

func (g *Garmin) GetProgressSummaryBetweenDates(ctx context.Context, startdate, enddate, metric string, groupByActivities bool) (json.RawMessage, error)

GetProgressSummaryBetweenDates returns lifetime progress for a metric ("elevationGain", "duration", "distance" (default), "movingDuration").

func (*Garmin) GetRHRDaily

func (g *Garmin) GetRHRDaily(ctx context.Context, start, end string) ([]DailyValue, error)

GetRHRDaily returns daily resting heart rate for start..end (up to ~1 year) in one request.

func (*Garmin) GetRHRDay

func (g *Garmin) GetRHRDay(ctx context.Context, cdate string) (json.RawMessage, error)

GetRHRDay returns resting heart rate data for cdate.

func (*Garmin) GetRacePredictions

func (g *Garmin) GetRacePredictions(ctx context.Context, startdate, enddate, predType string) (json.RawMessage, error)

GetRacePredictions returns 5k/10k/half/marathon predictions. Pass all empty for the latest, or all three (predType "daily" or "monthly", range at most one year) for history.

func (*Garmin) GetRespirationData

func (g *Garmin) GetRespirationData(ctx context.Context, cdate string) (json.RawMessage, error)

GetRespirationData returns respiration data for cdate.

func (*Garmin) GetRunningTolerance

func (g *Garmin) GetRunningTolerance(ctx context.Context, startdate, enddate, aggregation string) (json.RawMessage, error)

GetRunningTolerance returns running tolerance for a range; aggregation is "daily" or "weekly" (default).

func (*Garmin) GetScheduledWorkoutByID

func (g *Garmin) GetScheduledWorkoutByID(ctx context.Context, id int64) (json.RawMessage, error)

GetScheduledWorkoutByID returns a scheduled workout.

func (*Garmin) GetScheduledWorkouts

func (g *Garmin) GetScheduledWorkouts(ctx context.Context, year, month int) (json.RawMessage, error)

GetScheduledWorkouts returns the calendar of a month (1-12).

func (*Garmin) GetSleepDaily

func (g *Garmin) GetSleepDaily(ctx context.Context, start, end string) (json.RawMessage, error)

GetSleepDaily returns daily sleep summaries for start..end, chunked by 28 days, de-duplicated and sorted by calendarDate.

func (*Garmin) GetSleepData

func (g *Garmin) GetSleepData(ctx context.Context, cdate string) (json.RawMessage, error)

GetSleepData returns sleep data for cdate. Some CN accounts report the *Local timestamps offset twice; prefer the *GMT fields when in doubt.

func (*Garmin) GetSpo2Data

func (g *Garmin) GetSpo2Data(ctx context.Context, cdate string) (json.RawMessage, error)

GetSpo2Data returns SpO2 data for cdate; a string lastSevenDaysAvgSpO2 is converted to a number.

func (*Garmin) GetStats

func (g *Garmin) GetStats(ctx context.Context, cdate string) (json.RawMessage, error)

GetStats is an alias of GetUserSummary.

func (*Garmin) GetStatsAndBody

func (g *Garmin) GetStatsAndBody(ctx context.Context, cdate string) (json.RawMessage, error)

GetStatsAndBody merges the daily summary with the body composition average.

func (*Garmin) GetStepsData

func (g *Garmin) GetStepsData(ctx context.Context, cdate string) (json.RawMessage, error)

GetStepsData returns the step chart data for cdate.

func (*Garmin) GetStressData

func (g *Garmin) GetStressData(ctx context.Context, cdate string) (json.RawMessage, error)

GetStressData returns stress data for cdate (same endpoint as GetAllDayStress).

func (*Garmin) GetTrainingFourWeekLoadBalance

func (g *Garmin) GetTrainingFourWeekLoadBalance(ctx context.Context, cdate string) (json.RawMessage, error)

GetTrainingFourWeekLoadBalance returns the load focus for the four weeks ending at cdate.

func (*Garmin) GetTrainingLoadActivities

func (g *Garmin) GetTrainingLoadActivities(ctx context.Context, startdate, enddate string, metrics []string, activityType string) (json.RawMessage, error)

GetTrainingLoadActivities returns activities with training load metrics. metrics nil uses the defaults; an empty non-nil slice requests none.

func (*Garmin) GetTrainingPlanByID

func (g *Garmin) GetTrainingPlanByID(ctx context.Context, planID int64) (json.RawMessage, error)

GetTrainingPlanByID returns a phased training plan.

func (*Garmin) GetTrainingPlans

func (g *Garmin) GetTrainingPlans(ctx context.Context) (json.RawMessage, error)

GetTrainingPlans returns all available training plans.

func (*Garmin) GetTrainingReadiness

func (g *Garmin) GetTrainingReadiness(ctx context.Context, cdate string) (json.RawMessage, error)

GetTrainingReadiness returns training readiness snapshots for cdate.

func (*Garmin) GetTrainingStatus

func (g *Garmin) GetTrainingStatus(ctx context.Context, cdate string) (json.RawMessage, error)

GetTrainingStatus returns aggregated training status for cdate.

func (*Garmin) GetUserProfile

func (g *Garmin) GetUserProfile(ctx context.Context) (json.RawMessage, error)

GetUserProfile returns all user settings.

func (*Garmin) GetUserSummary

func (g *Garmin) GetUserSummary(ctx context.Context, cdate string) (json.RawMessage, error)

GetUserSummary returns the daily activity summary for cdate (YYYY-MM-DD).

func (*Garmin) GetUserprofileSettings

func (g *Garmin) GetUserprofileSettings(ctx context.Context) (json.RawMessage, error)

GetUserprofileSettings returns user profile settings.

func (*Garmin) GetWeeklyIntensityMinutes

func (g *Garmin) GetWeeklyIntensityMinutes(ctx context.Context, start, end string) (json.RawMessage, error)

GetWeeklyIntensityMinutes returns weekly intensity minute aggregates.

func (*Garmin) GetWeeklySteps

func (g *Garmin) GetWeeklySteps(ctx context.Context, end string, weeks int) (json.RawMessage, error)

GetWeeklySteps returns weekly step aggregates for weeks ending at end.

func (*Garmin) GetWeeklyStress

func (g *Garmin) GetWeeklyStress(ctx context.Context, end string, weeks int) (json.RawMessage, error)

GetWeeklyStress returns weekly stress aggregates for weeks ending at end.

func (*Garmin) GetWeighIns

func (g *Garmin) GetWeighIns(ctx context.Context, startdate, enddate string) (json.RawMessage, error)

GetWeighIns returns weigh-ins between startdate and enddate.

func (*Garmin) GetWorkoutByID

func (g *Garmin) GetWorkoutByID(ctx context.Context, id int64) (json.RawMessage, error)

GetWorkoutByID returns a workout.

func (*Garmin) GetWorkouts

func (g *Garmin) GetWorkouts(ctx context.Context, start, limit int) (json.RawMessage, error)

GetWorkouts returns workouts from offset start (default limit 100).

func (*Garmin) ImportActivity

func (g *Garmin) ImportActivity(ctx context.Context, path string) (json.RawMessage, error)

ImportActivity uploads a file as an import, with Garmin Connect Mobile headers, so it is not re-exported to third parties like Strava. A duplicate is reported as an error with StatusCode 409.

func (*Garmin) InitMenstrualCycleSetup

func (g *Garmin) InitMenstrualCycleSetup(ctx context.Context, periodStart string, periodLength, cycleLength int) (json.RawMessage, error)

InitMenstrualCycleSetup starts cycle tracking with the first confirmed period. Not for editing an already configured account; change tracking flags with UpdateMenstrualSettings.

func (*Garmin) Login

func (g *Garmin) Login(ctx context.Context, tokenstore string) (needsMFA bool, err error)

Login authenticates. tokenstore is a token directory/file path or inline token JSON (falls back to $GARMINTOKENS); cached tokens are used when valid, otherwise it logs in with credentials and persists new tokens. needsMFA is true only with WithReturnOnMFA.

func (*Garmin) Logout

func (g *Garmin) Logout(tokenstore string) error

Logout clears in-memory auth state and deletes the cached token file (the directory and other files stay). It does not revoke tokens at Garmin.

func (*Garmin) PushWorkoutToDevice

func (g *Garmin) PushWorkoutToDevice(ctx context.Context, workoutID, deviceID int64) (json.RawMessage, error)

PushWorkoutToDevice sends a workout to a device. workoutID 0 pushes the latest workout in the library; deviceID 0 picks the last used device.

func (*Garmin) QueryGarminGraphQL

func (g *Garmin) QueryGarminGraphQL(ctx context.Context, query any) (json.RawMessage, error)

QueryGarminGraphQL posts a GraphQL request body ({"query": ..., "variables": ...}).

func (*Garmin) RemoveGearFromActivity

func (g *Garmin) RemoveGearFromActivity(ctx context.Context, gearUUID string, activityID int64) (json.RawMessage, error)

RemoveGearFromActivity unlinks gear from an activity.

func (*Garmin) RequestReload

func (g *Garmin) RequestReload(ctx context.Context, cdate string) (json.RawMessage, error)

RequestReload asks Garmin to reload offloaded data for cdate.

func (*Garmin) ResumeLogin

func (g *Garmin) ResumeLogin(ctx context.Context, code string) error

ResumeLogin completes a login that returned needsMFA and persists tokens to the tokenstore path given to Login, if any.

func (*Garmin) ScheduleWorkout

func (g *Garmin) ScheduleWorkout(ctx context.Context, workoutID int64, date string) (json.RawMessage, error)

ScheduleWorkout puts a workout on the calendar on date (YYYY-MM-DD).

func (*Garmin) SetActivityDescription

func (g *Garmin) SetActivityDescription(ctx context.Context, id int64, description string) (json.RawMessage, error)

SetActivityDescription sets an activity's description.

func (*Garmin) SetActivityExerciseSets

func (g *Garmin) SetActivityExerciseSets(ctx context.Context, id int64, payload any) (json.RawMessage, error)

SetActivityExerciseSets replaces all exercise sets of an activity. payload has the shape GetActivityExerciseSets returns.

func (*Garmin) SetActivityName

func (g *Garmin) SetActivityName(ctx context.Context, id int64, title string) (json.RawMessage, error)

SetActivityName renames an activity.

func (*Garmin) SetActivityType

func (g *Garmin) SetActivityType(ctx context.Context, id int64, typeID int, typeKey string, parentTypeID int) (json.RawMessage, error)

SetActivityType changes an activity's type.

func (*Garmin) SetBloodPressure

func (g *Garmin) SetBloodPressure(ctx context.Context, systolic, diastolic, pulse int, ts time.Time, notes string) (json.RawMessage, error)

SetBloodPressure adds a measurement. pulse 0 omits the heart rate; a zero ts means now.

func (*Garmin) SetGearDefault

func (g *Garmin) SetGearDefault(ctx context.Context, activityType, gearUUID string, defaultGear bool) (json.RawMessage, error)

SetGearDefault makes gear the default for an activity type (e.g. "RUNNING"), or removes that default when defaultGear is false.

func (*Garmin) UnscheduleWorkout

func (g *Garmin) UnscheduleWorkout(ctx context.Context, scheduledWorkoutID int64) (json.RawMessage, error)

UnscheduleWorkout removes a scheduled workout, keeping the template.

func (*Garmin) UpdateJetlagTrip

func (g *Garmin) UpdateJetlagTrip(ctx context.Context, tripID int64, start, end string, flights []JetlagFlight) (json.RawMessage, error)

UpdateJetlagTrip replaces a trip, so flights must hold every flight; keep the FlightID of each flight that stays.

func (*Garmin) UpdateMenstrualCalendar

func (g *Garmin) UpdateMenstrualCalendar(ctx context.Context, startdate, enddate string, cycleDates [][]string, today string) (json.RawMessage, error)

UpdateMenstrualCalendar replaces period dates in startdate..enddate. Each inner list is one period of consecutive dates; omitted confirmed days in range are removed. Do not post predicted cycles as confirmed.

func (*Garmin) UpdateMenstrualDailyLog

func (g *Garmin) UpdateMenstrualDailyLog(ctx context.Context, date string, l MenstrualDailyLog) (json.RawMessage, error)

UpdateMenstrualDailyLog replaces the daily log of date. Read GetMenstrualDataForDate first and pass every value to keep.

func (*Garmin) UpdateMenstrualSettings

func (g *Garmin) UpdateMenstrualSettings(ctx context.Context, settings map[string]any, userSettingsID int64) (json.RawMessage, error)

UpdateMenstrualSettings overlays settings onto the stored userMenstrualCycleSettings. userSettingsID 0 uses the profile's id.

func (*Garmin) UpdateWorkout

func (g *Garmin) UpdateWorkout(ctx context.Context, id int64, workout any) (json.RawMessage, error)

UpdateWorkout replaces a workout in place (keeping its id, so schedules stay valid). workout must be the complete structure; workoutId is forced to id.

func (*Garmin) UploadActivity

func (g *Garmin) UploadActivity(ctx context.Context, path string) (json.RawMessage, error)

UploadActivity uploads a FIT, GPX or TCX file.

func (*Garmin) UploadWorkout

func (g *Garmin) UploadWorkout(ctx context.Context, workout any) (json.RawMessage, error)

UploadWorkout creates a workout from a *Workout (see NewWorkout), a JSON string, json.RawMessage or any value that marshals to a JSON object/array.

type GearSpec

type GearSpec struct {
	GearType     string // e.g. "SHOES"
	Brand        string
	Model        string
	Name         string
	FirstUseDate string  // YYYY-MM-DD
	UsageType    string  // default "DISTANCE"
	MaxUsageKM   float64 // retirement threshold; 0 = none
	MaxUsageMin  float64 // retirement threshold; 0 = none
	Notes        string
	// ActivityTypeKeys are lowercase keys (e.g. "running") the gear becomes
	// the default for.
	ActivityTypeKeys []string
}

GearSpec describes new gear for CreateGear. Only GearType "SHOES" and UsageType "DISTANCE" are confirmed against a real account; other values are likely SCREAMING_SNAKE_CASE too.

type JetlagFlight

type JetlagFlight struct {
	FlightID             int64  `json:"flightId,omitempty"`
	TripID               int64  `json:"tripId,omitempty"`
	OriginLocation       string `json:"originLocation"`
	OriginTimezone       string `json:"originTimezone"`
	OriginTimestamp      string `json:"originTimestamp"`
	DestinationLocation  string `json:"destinationLocation"`
	DestinationTimezone  string `json:"destinationTimezone"`
	DestinationTimestamp string `json:"destinationTimestamp"`
}

JetlagFlight is one flight leg. Timezones are UTC offsets at that place on that date ("-07:00"); timestamps are local times without an offset ("2026-10-04T15:20:00"). Garmin does not geocode the free-text locations.

type MenstrualDailyLog

type MenstrualDailyLog struct {
	Symptoms       []string
	Moods          []string
	Flow           string
	Discharge      []string
	SexDrive       string
	SexualActivity string
	Notes          *string
	OvulationDay   *bool
}

MenstrualDailyLog is a full-day snapshot: Garmin clears omitted lists and enums. Notes nil keeps the stored note, "" clears it. OvulationDay nil is stored as false.

type Option

type Option func(*Garmin)

Option configures New.

func WithCN

func WithCN() Option

WithCN targets garmin.cn instead of garmin.com.

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger sets the logger (default: discard).

func WithPromptMFA

func WithPromptMFA(fn func() (string, error)) Option

WithPromptMFA sets the callback that returns an MFA code during Login.

func WithRetry

func WithRetry(attempts int, minWait, maxWait time.Duration) Option

WithRetry sets retries for transient 5xx/network errors on GET calls (default 3, 1s..10s backoff). attempts=0 disables. 401/429/4xx never retry.

func WithReturnOnMFA

func WithReturnOnMFA() Option

WithReturnOnMFA makes Login return needsMFA=true instead of prompting; finish with ResumeLogin.

func WithTokenSaver

func WithTokenSaver(fn func(tokenJSON string)) Option

WithTokenSaver calls fn with the token JSON whenever tokens are obtained or refreshed, so a service can persist them (e.g. per account in a database) and pass them back to Login later.

func WithVerifyLogin

func WithVerifyLogin(v bool) Option

WithVerifyLogin(false) restores the legacy "first token wins" login.

type RepeatGroup

type RepeatGroup struct {
	Type               string        `json:"type"` // "RepeatGroupDTO"
	StepOrder          int           `json:"stepOrder"`
	StepType           *StepType     `json:"stepType,omitempty"`
	NumberOfIterations int           `json:"numberOfIterations"`
	WorkoutSteps       []Step        `json:"workoutSteps"`
	EndCondition       *EndCondition `json:"endCondition,omitempty"`
	EndConditionValue  *float64      `json:"endConditionValue,omitempty"`
	ChildStepID        *int          `json:"childStepId,omitempty"`
	SmartRepeat        bool          `json:"smartRepeat"`
	SkipLastRestStep   *bool         `json:"skipLastRestStep,omitempty"`
}

RepeatGroup repeats its steps NumberOfIterations times.

func NewRepeatGroup

func NewRepeatGroup(iterations int, steps []Step, order int, skipLastRest *bool) *RepeatGroup

NewRepeatGroup repeats steps; skipLastRest optionally drops the final recovery/rest step.

func StrengthSet

func StrengthSet(category string, order, sets, reps int, restSecs float64, exerciseName string, weightKG *float64) *RepeatGroup

StrengthSet is one "N sets" block: a repeat group at order holding the exercise (order+1) and rest (order+2). Advance your order counter by 3.

type RequestOptions

type RequestOptions struct {
	Params      url.Values
	Headers     map[string]string
	Body        []byte
	ContentType string
}

RequestOptions configures a raw API call.

type SportType

type SportType struct {
	SportTypeID  int    `json:"sportTypeId"`
	SportTypeKey string `json:"sportTypeKey"`
	DisplayOrder int    `json:"displayOrder,omitempty"`
}

SportType identifies a workout sport.

type Step

type Step interface {
	// contains filtered or unexported methods
}

Step is an ExecutableStep or a RepeatGroup.

type StepType

type StepType struct {
	StepTypeID   int    `json:"stepTypeId"`
	StepTypeKey  string `json:"stepTypeKey"`
	DisplayOrder int    `json:"displayOrder"`
}

StepType identifies a step kind.

type Target

type Target struct {
	// contains filtered or unexported fields
}

Target is an intensity target; build one with the *Target functions.

func CadenceTarget

func CadenceTarget(lower, upper float64) (*Target, error)

CadenceTarget: steps (running) or revolutions (cycling) per minute.

func CustomHeartRateTarget

func CustomHeartRateTarget(lower, upper float64) (*Target, error)

CustomHeartRateTarget: beats per minute.

func CustomPowerTarget

func CustomPowerTarget(lower, upper float64) (*Target, error)

CustomPowerTarget: watts.

func HeartRateZoneTarget

func HeartRateZoneTarget(zone int) *Target

HeartRateZoneTarget uses one of the user's configured heart rate zones.

func PaceTarget

func PaceTarget(lower, upper float64) (*Target, error)

PaceTarget: m/s (see PaceToMPS), so the slower pace is the lower limit.

func PowerZoneTarget

func PowerZoneTarget(zone int) *Target

PowerZoneTarget uses one of the user's configured power zones.

func SpeedTarget

func SpeedTarget(lower, upper float64) (*Target, error)

SpeedTarget: m/s.

func SwimCSSOffsetTarget

func SwimCSSOffsetTarget(offsetSeconds float64) (*Target, error)

SwimCSSOffsetTarget is a secondary-only swim target: a signed pace offset in seconds from Critical Swim Speed (positive = slower).

type TargetType

type TargetType struct {
	WorkoutTargetTypeID  int    `json:"workoutTargetTypeId"`
	WorkoutTargetTypeKey string `json:"workoutTargetTypeKey"`
	DisplayOrder         int    `json:"displayOrder"`
}

TargetType identifies a step's intensity target.

type Workout

type Workout struct {
	WorkoutName             string           `json:"workoutName"`
	SportType               SportType        `json:"sportType"`
	EstimatedDurationInSecs int              `json:"estimatedDurationInSecs"`
	WorkoutSegments         []WorkoutSegment `json:"workoutSegments"`
	Author                  map[string]any   `json:"author"`
	Description             *string          `json:"description,omitempty"`
}

Workout is the upload body of UploadWorkout.

func NewWorkout

func NewWorkout(sport SportType, name string, estimatedSecs int, steps ...Step) *Workout

NewWorkout returns a workout for sport with one segment holding steps.

type WorkoutSegment

type WorkoutSegment struct {
	SegmentOrder int       `json:"segmentOrder"`
	SportType    SportType `json:"sportType"`
	WorkoutSteps []Step    `json:"workoutSteps"`
}

WorkoutSegment holds the steps of one sport.

Directories

Path Synopsis
cmd
smoke command
Command smoke calls every read-only endpoint against a real account and prints an OK/ERR/SKIP table.
Command smoke calls every read-only endpoint against a real account and prints an OK/ERR/SKIP table.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL