Client Data API

Your training data is yours. If you write code, you can read it directly: your programs, every exercise you have done, and every set you have recorded. The API is read-only and uses the login you already have.

Before you start

  • It is for clients only, and you only ever see your own data.
  • It works at studios that have turned it on. If you get api_disabled, ask your studio.
  • Trainer comments, recap notes, issue notes and trainer names are not included.
  • Base URL: https://app.everstrongsf.com/api/public/v1. All responses are JSON.

1. Get a token

Send your EverStrongSF username (or email) and password once. Store the tokens, not your password. The access token lasts 12 hours and the refresh token 30 days.

curl -X POST https://app.everstrongsf.com/api/public/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{"username": "[email protected]", "password": "…"}'

{
  "tokenType": "Bearer",
  "accessToken": "…",
  "refreshToken": "…",
  "accessExpiresAt": "2026-10-20T22:00:00.000Z",
  "refreshExpiresAt": "2026-11-19T10:00:00.000Z"
}

When the access token expires, POST {"refreshToken": "…"} to /auth/refresh for a new pair. The old pair stops working. Six wrong passwords lock sign-in for 30 minutes, the same as the app.

2. Call the API

curl "https://app.everstrongsf.com/api/public/v1/workouts?from=2026-01-01&limit=50" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
const res = await fetch("https://app.everstrongsf.com/api/public/v1/exercises", {
  headers: { Authorization: `Bearer ${accessToken}` },
});
const { data } = await res.json();
for (const e of data) console.log(e.exercise, e.firstWeight, "→", e.bestWeight);

Endpoints

POST/auth/tokenExchange your username and password for tokens
POST/auth/refreshExchange a refresh token for a new pair
POST/auth/revokeRevoke a token pair
GET/meYour name, studio and weight unit
GET/programsYour current programs, with how each exercise is set up
GET/exercisesEvery exercise you have performed, with first, best and latest weight
GET/workoutsEvery recorded set, newest first, paginated
GET/recapsDates of your sessions that have a recap, newest first

The full schema is at openapi.json (OpenAPI 3.1).

Workouts

One row per recorded set. Optional filters: from and to (YYYY-MM-DD, inclusive), exercise (exact name), program (letter) and limit (1–500, default 100). When there are more rows, the response carries a nextCursor. Pass it back as cursor with the same filters.

{
  "data": [
    {
      "id": "…",
      "date": "2026-10-14",
      "exercise": "Leg Press",
      "machineId": "…",
      "program": "A",
      "weight": 310,
      "reps": 9,
      "time": "1:52",
      "reachedFailure": true,
      "nextWeight": 320,
      "recordedAt": "2026-10-14T17:41:09.000Z"
    }
  ],
  "nextCursor": "…"
}
dateSession date, YYYY-MM-DD
exerciseMachine name
machineIdStable machine id. Survives a machine being renamed
programProgram letter (A, B, …), or null
weightWeight used, in the weightUnit from /me
repsRepetitions completed, or null
timeTime under load, m:ss
reachedFailureWhether the set reached momentary muscular failure
nextWeightWeight planned for next time, or null
recordedAtWhen the set was recorded, ISO 8601

Programs

Each exercise in your current programs, in order, with its prescription: protocol (failure, rep-max or drop-set), targetReps for a rep max, timeUnderTensionSeconds, the rep cadence, your machine setup (seat, back, hand, handle, pin, body position) and any notes, cues or warnings.

Errors and limits

Errors look like {"error": {"code": "…", "message": "…"}}. You can make 60 requests a minute.

400invalid_requestA parameter is missing or malformed
401invalid_credentials / unauthorized / token_expiredSign in again, or refresh
403forbiddenNot a client account
403api_disabledYour studio has not turned the API on
429rate_limited / too_many_attemptsWait for the Retry-After seconds

Keep it safe

A token reads your training data, so treat it like a password. Revoke one you no longer need by POSTing it to /auth/revoke. Changing your password does not revoke existing tokens. Revoke them too. Questions: [email protected].