whoop-go

module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Apr 20, 2026 License: MIT

README

whoop-go

Go Reference CI Go Report Card

whoop-go is a production-grade, highly robust Go client library for integrating with the WHOOP API v2.

Engineered with resiliency in mind, it natively handles strict WHOOP rate limits (100 req/min) through transparent token buckets and exponential backoff jitter. It securely extracts HTTP webhooks using HMAC-SHA256 validations, and surfaces strongly-typed structs mapping the complex WHOOP domain (Cycles, Workouts, Sleep, and Recovery) via seamless pagination iterators.

Disclaimer: This is an unofficial open-source library and is not affiliated with, endorsed by, or supported by WHOOP.

Features

  • Built-in Resilience: Implements an intrinsic thread-safe token bucket rate-limiter enforcing the 100 req/min and 10,000 req/day WHOOP API quotas. Automatically intercepts HTTP 429 Too Many Requests responses, sleeping utilizing randomized exponential backoffs before retrying safely.
  • Webhook Verifier: Features whoop.ParseWebhook(r, secret), dynamically digesting inbound HTTP requests, safely streaming payloads, validating X-Whoop-Signature HMAC-SHA256 authenticity hashes without memory leaks, and returning structured skinny webhook types (workout.updated, cycle.updated, etc.).
  • Iterator Pagination: Converts cumbersome next_token URL query cursor traversals into a deeply idiomatic Go iterator pattern utilizing .NextPage(ctx).
  • Zero External Dependencies: Outside of the foundational Golang golang.org/x/time/rate token bucket algorithm, the client is strictly built upon Go standard primitives (net/http, crypto/hmac).

Component Architecture

The library is modularized by functional domains to provide strict operational boundaries:

  • client.go: Centralizes the configurable HTTP Client, injects global functional options (WithToken, WithBackoffBase), and integrates the rateLimiter.
  • ratelimit.go: Enforces concurrency-safe request throttling.
  • webhooks.go: Provides high-performance, single-pass webhook stream consumption and signature validation.
  • profile.go: Manages athlete basic profiles and highly granular BodyMeasurement data.
  • cycle.go: Maps the overarching physiological day with calculated Strain and HeartRate arrays.
  • sleep.go & recovery.go: Exposes complex sleep staging, restorative data markers, and systemic nervous recovery scorings.
  • workout.go: Maps chronological activity zone durations and absolute metric loads.

Installation

You need Go 1.22 or higher installed.

go get github.com/arvarik/whoop-go/whoop

Quick Start: The Webhook Example

The repository includes a fully-functional Webhook + REST architecture example at cmd/example/main.go. This script demonstrates how to securely parse live webhooks and trigger a secondary data scrape pipeline instantly.

Running the Example
# Copy the example .env and fill in your credentials
cp .env.example .env
vim .env   # Add your WHOOP_OAUTH_TOKEN and WHOOP_WEBHOOK_SECRET
source .env

# Start the Webhook Listener on Port 8080
make build-local
./bin/example
Getting an OAuth Token

The WHOOP API uses the OAuth 2.0 Authorization Code flow. The cmd/auth/main.go helper script handles the full flow, including automatic token refresh so you only need to sign in once.

  1. Ensure your application has http://localhost:8081/callback added as a Redirect URI in the WHOOP Developer Dashboard. If you're using a different redirect URI, set WHOOP_REDIRECT_URI.
  2. Export your credentials:
export WHOOP_CLIENT_ID="your_client_id"
export WHOOP_CLIENT_SECRET="your_client_secret"
# Optional: only needed if your redirect URI differs from http://localhost:8081/callback
# export WHOOP_REDIRECT_URI="http://localhost:3000/callback"
  1. Run the auth helper:
go run cmd/auth/main.go
  1. First run: Open the printed URL in your browser, sign in, and authorize. The script saves your session to .whoop_token.json.
  2. Subsequent runs: The script automatically refreshes your token using the saved session — no browser login needed.

Note: Access tokens expire after 1 hour. Simply re-run the script and it will silently refresh without opening a browser. The .whoop_token.json file is gitignored and should never be committed.

Verifying Credentials with cURL

Before building an integration, you can validate your OAuth token directly against the WHOOP API:

# Set your token
export WHOOP_OAUTH_TOKEN="your_oauth2_token_here"

# 1. Fetch your basic profile
curl -s -H "Authorization: Bearer $WHOOP_OAUTH_TOKEN" \
  "https://api.prod.whoop.com/developer/v2/user/profile/basic" | jq

# 2. Fetch your body measurements
curl -s -H "Authorization: Bearer $WHOOP_OAUTH_TOKEN" \
  "https://api.prod.whoop.com/developer/v2/user/measurement/body" | jq

# 3. List recent physiological cycles (last 10)
curl -s -H "Authorization: Bearer $WHOOP_OAUTH_TOKEN" \
  "https://api.prod.whoop.com/developer/v2/cycle?limit=10" | jq

# 4. List recent workouts
curl -s -H "Authorization: Bearer $WHOOP_OAUTH_TOKEN" \
  "https://api.prod.whoop.com/developer/v2/activity/workout?limit=10" | jq

# 5. List recent sleep events
curl -s -H "Authorization: Bearer $WHOOP_OAUTH_TOKEN" \
  "https://api.prod.whoop.com/developer/v2/activity/sleep?limit=10" | jq

# 6. List recent recovery scores
curl -s -H "Authorization: Bearer $WHOOP_OAUTH_TOKEN" \
  "https://api.prod.whoop.com/developer/v2/recovery?limit=10" | jq
Under the Hood
  1. A WHOOP event triggers your webhook.updated skinny payload to exactly :8080/whoop/webhook.
  2. The whoop.ParseWebhook() helper validates the signature and asserts the event.Type.
  3. An explicit asynchronous processWorkout() GoRoutine utilizes client.Workout.GetByID(ctx, event.ID) to query the full Workout schema for local logging and storage!

Example API Calls

The library provides individual services attached to the core Client. Below are comprehensive examples showing basic interactions.

1. Initializing the Client

Configuration is heavily customizable utilizing the Functional Options pattern.

import "github.com/arvarik/whoop-go/whoop"

client := whoop.NewClient(
    whoop.WithToken("your_oauth_token"),
    whoop.WithMaxRetries(5),               // Automatically retry failures or 429 limits up to 5 times
    whoop.WithBaseURL("https://custom.proxy.example.com"), // Optional: override base URL
)
2. Validating Webhooks
http.HandleFunc("/whoop/webhook", func(w http.ResponseWriter, r *http.Request) {
    event, err := whoop.ParseWebhook(r, "my_webhook_secret_key")
    if err != nil {
        log.Printf("Fraudulent webhook prevented: %v", err)
        w.WriteHeader(http.StatusUnauthorized)
        return
    }

    log.Printf("Received genuine webhook event! Type: %s, ID: %s", event.Type, event.ID)
})
3. Fetching Cycles via Iterator Pagination

The WHOOP API caps returns at 50 arrays. You sequentially traverse all history easily via the NextPage(ctx) cursor logic.

// Fetch the initial block of Cycles
page, err := client.Cycle.List(ctx, &whoop.ListOptions{Limit: 10})
if err != nil {
    log.Fatal(err)
}

for {
    // Process current batch
    for _, cycle := range page.Records {
        fmt.Printf("Cycle: %d, Strain: %.1f\n", cycle.ID, cycle.Score.Strain)
    }

    // Traverse pagination seamlessly!
    page, err = page.NextPage(ctx)
    if err != nil {
        if errors.Is(err, whoop.ErrNoNextPage) {
            break // Done!
        }
        log.Fatal(err)
    }
}

Local Development / First Time Setup

If you are contributing to this library, you should run the setup command immediately after cloning. This automatically configures standard Git hooks to invoke the Go linter before allowing commits:

# Sets `core.hooksPath` to `.githooks` enabling the pre-commit action automatically
make setup

Run test coverage utilizing mocked REST architectures safely disconnected from Live APIs:

make test

Migrating from v0.2.0 → v0.3.0 (v1 → v2 API)

As of v0.3.0, this library targets the WHOOP API v2. The v1 API has been deprecated by WHOOP — several v1 endpoints (Sleep, Workout, Recovery) now return HTTP 404.

Key breaking changes:

  • Sleep.ID and Workout.ID changed from int → string (UUIDs)
  • Recovery.SleepID changed from int → string (UUID)
  • WebhookEvent.ID changed from int → string (UUID)
  • Workout zone durations JSON key renamed from zone_duration → zone_durations
  • New fields added: ScoreState, SportName, V1ID, CycleID (on Sleep), and ScopeOffline

License

This project is licensed under the MIT License.

Directories

Path Synopsis
cmd
auth command
example command
Package whoop provides a production-grade Go client for the WHOOP Developer API (v2).
Package whoop provides a production-grade Go client for the WHOOP Developer API (v2).

Jump to

Keyboard shortcuts

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