Log in with Endorphins

Let runners sign in with their Endorphins account and, with their consent, access their training data. Endorphins is a standard OAuth 2.0 and OpenID Connect (OIDC) provider, so you can use any off-the-shelf OIDC client library.

1. Register your app

Sign in to Endorphins, then go to /developer to register an app. Choose your redirect URIs and the scopes you need, and you'll receive a client_id (plus a client_secret for confidential server-side apps, shown once).

Your redirect URI is your own app's callback URL (for example https://your-app.com/api/integrations/endorphins/callback). Endorphins doesn't dictate the path, but the redirect_uri you send on /oauth/authorize must exactly match one you registered — matching is character-for-character with no wildcards. It must use HTTPS (http is allowed only for localhost) and must not contain a URL fragment.

2. Discovery

Everything auto-configures from our OpenID Connect discovery document at https://endorphinsrunning.com/.well-known/openid-configuration, which advertises the authorization, token, userinfo, and JWKS endpoints. id_tokens are signed with RS256; verify them against the published JWKS.

3. Authorization Code + PKCE flow

Send the user to /oauth/authorize with response_type=code, your client_id and redirect_uri, the scopes you need, a state value, a PKCE code_challenge (S256), and an optional nonce. The user signs in and approves the requested scopes on the Endorphins consent screen, and we redirect back to your redirect_uri with a code. Exchange the code at /oauth/token for an access_token, a refresh_token, and — when the openid scope was requested — a signed id_token.

4. Get the user's identity

Decode the id_token, or call /oauth/userinfo with the access token to get the user's sub, email, and name.

5. Scopes

All data scopes are read-only. Request only what your app needs.

6. Read the user's data

With a Bearer access token, call the resource endpoints below (same origin as the auth endpoints). Each requires its matching scope; a token missing that scope gets a 403. The developer docs include a full API reference with a sample request and response body for every endpoint.

Parameters: /gpt/activities accepts days (default 120, max 365) or sinceDate (ISO 8601); /gpt/recovery and /gpt/daily-energy accept days (default 30, max 365). To read a user's workouts, call GET https://endorphinsrunning.com/gpt/activities?days=30 with an Authorization: Bearer ACCESS_TOKEN header and the read:workouts scope. It returns { "activities": [ ... ] }, newest first, where each activity includes fields such as name, type, start_date (UTC) and start_date_local, distance (meters) plus distance_miles and distance_kilometers, moving_time and elapsed_time (seconds), average_pace_per_mile and average_pace_per_km, average_heartrate, total_elevation_gain (meters), trainingLoad, activitySource, and workoutId (the linked plan workout, if any). Which fields are present depends on the data source (Strava, Garmin, Apple Health). GPS map data and precise location fields are stripped from this endpoint for privacy.

7. Refresh and revoke

Use grant_type=refresh_token at /oauth/token for a fresh access token (refresh tokens rotate on each use). Tokens can be revoked at /oauth/revoke, and users can revoke your app anytime from their Endorphins account settings. Handle 401 responses by re-authorizing.

Security

Always use PKCE. Never expose a confidential client_secret in a browser or mobile binary; use a public (PKCE) app there. Validate the state and nonce values you sent, and verify the id_token signature, iss, and aud.

Ready to build?

Once you're logged in, head to the developer portal at /developer to register your first app.