Moving from v1 to v2

v2 is a new exercise library: 1,900+ movements as 2,700+ clips, 720p MP4 animations at 30 fps, and male and female models. This guide shows what changes in your integration and how to move one screen at a time.

v2 is live. The /v2 endpoints work with your existing API key today, and v1 keeps working exactly as it does now while you migrate.

What stays the same

What changes

v1v2
Base path/v1/exercises/v2/exercises
API keyHeader or ?api-key=X-WorkoutX-Key header only. A key in the URL returns 400.
Exercise ids"0662""ex_WOZL6H", with the old ids in legacyIds
MediagifUrl, a permanent GIF linkmedia: mp4, poster and expiresAt, links that expire after about a day
Lists{ total, count, data }{ total, limit, offset, results }
Muscles["Triceps"][{ "group": "Triceps", "anatomical": ["Triceps brachii"] }]
New fields–model, counterpartId, tips, loopSeconds, recommendedSets, recommendedReps
Smart endpoints/v1/exercises/{id}/similar, /alternatives, /caloriesSame paths under /v2 with v2 ids. similar and alternatives also take model.
Workouts and supplements/v1/workout/generate, /v1/workout/program, /v1/supplementsSame paths under /v2, with a new engine. Sessions add a warm-up, cool-down, supersets or circuits, rest, RIR and swaps, and take model, avoidJoints and format. Programs add deloads, weekly volume and an exerciseLibrary. See the workout docs. Supplement lists use the v2 page shape.
Joint & Rehab filters/v1/exercises/searchjointFocus, intensityLevel and movementTag on /v2/exercises

Migrate in five steps

  1. Send the key in the header Change the path from /v1 to /v2, and move the key from ?api-key= to the X-WorkoutX-Key header. Keys in URLs end up in app bundles and server logs, so v2 refuses them.
    curl 'https://api.workoutxapp.com/v2/exercises?bodyPart=chest&limit=10' \
      -H "X-WorkoutX-Key: wx_your_key_here"
  2. Map the exercise ids you've stored For each v1 id your app saves (in workouts, favorites or history), call the legacy endpoint once and store the v2 id it returns. Leading zeros are optional.
    GET /v2/exercises/legacy/0662
    
    {
      "v1Id": "0662",
      "v1Name": "Push-up",
      "match": "equivalent",
      "exercise": { "id": "ex_WOZL6H", "name": "Push Ups Bodyweight", ... }
    }
    The match field says how close the v2 exercise is:
    matchMeaningWhat to do
    exactThe same movementReplace automatically
    equivalentThe same movement, named differentlyReplace automatically
    alternativeThe same movement with other equipment, or a close variationSuggest it, and let users confirm
    closestThe nearest exercise for the same musclesSuggest it, and let users confirm
    noneNo v2 exercise yet (exercise is null)Keep the v1 exercise for now
    1,324 of the 1,327 v1 exercises have a v2 match. 582 of them are the same movement (exact or equivalent).
  3. Replace the GIF with a video Play media.mp4 muted and looping, and show media.poster while it loads or in lists. MP4 plays natively on every platform and is usually smaller than the GIF it replaces.

    Web

    <video src="{media.mp4}" poster="{media.poster}"
           autoplay loop muted playsinline></video>

    iOS (Swift)

    let item = AVPlayerItem(url: URL(string: media.mp4)!)
    let player = AVQueuePlayer()
    let looper = AVPlayerLooper(player: player, templateItem: item)  // keep a reference
    player.isMuted = true
    player.play()

    Android (Kotlin, Media3 ExoPlayer)

    val player = ExoPlayer.Builder(context).build().apply {
        setMediaItem(MediaItem.fromUri(media.mp4))
        repeatMode = Player.REPEAT_MODE_ONE
        volume = 0f
        prepare()
        play()
    }

    Flutter (video_player)

    final controller = VideoPlayerController.networkUrl(Uri.parse(media.mp4));
    await controller.initialize();
    await controller.setLooping(true);
    await controller.setVolume(0);
    await controller.play();
  4. Store ids, not media links Media links are signed and stop working 24–25 hours after they're issued (media.expiresAt). Save the exercise id, and get links when you show the exercise: from the exercise response, or from GET /v2/exercises/{id}/media when they've expired. Within the same hour the API returns identical links, so normal caching keeps working. Downloading the files or serving them from your own servers or CDN isn't permitted on any plan.
  5. Offer the female model Male and female versions are separate exercises. counterpartId points at the same movement with the other model, so you can show it as a switch. To list one model only, filter with ?model=female or ?model=male.

Media by plan

PlanVideoDifferent exercisesMedia views / month
Free300 × 360 with watermark––
Starter600 × 7201,000 per 30 days25,000
Legacy Basic600 × 720500 per 30 days25,000
Growth, and legacy Pro600 × 720Unlimited150,000
Scale, and legacy Ultra600 × 720Unlimited600,000
Enterprise600 × 720UnlimitedPer contract

A media view is one video or poster started; a player's follow-up range requests don't count. On Starter, once 1,000 different exercises have been used in any 30 days, new exercises come back with media: null and mediaLimitReached: true, while the ones you already use keep working. The X-Media-Exercises-Limit, -Used and -Remaining headers show where you are.

SDKs

v2 support in the JavaScript and Python SDKs ships with the launch (Swift and Flutter follow). They add wx.v2 with the same endpoints, and freshMedia(id), which reuses media links until they're close to expiry and fetches new ones after that.

Questions

Do I have to migrate when v2 launches?

No. v1 keeps working, and you'll get at least 30 days' notice by email before it's retired. Moving earlier gets your users the new animations and the female model sooner.

Will my price change?

No. Subscribers keep their current plan and price for as long as the subscription stays active, and v2 is included. New prices apply only to new subscriptions or if you switch plans.

Can I use v1 and v2 at the same time?

Yes. The same key works on both, and requests to either count toward the same monthly quota.

Are there GIFs in v2?

No, v2 delivers MP4 only. GIFs at the same quality were several times larger than the MP4, and every platform plays MP4 natively. v1 keeps serving its GIFs until v1 is retired.

Why do media links expire?

The animations are licensed for streaming inside your app, not for redistribution. Expiring links let us keep access tied to an active plan. Store ids and request links when you show an exercise.

Anything unclear, or a v1 exercise you need in v2? Email business@workoutxapp.com.