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
- Your API key. The same key works on v1 and v2, so both can run side by side while you migrate.
- Your plan and price. Current subscribers keep their plan and price for as long as their subscription stays active, with v2 included at no extra cost.
- v1 itself. v1 keeps working after v2 launches. You'll get at least 30 days' notice by email before it's retired.
- Languages.
?lang=works as in v1, with the same languages: Turkish (tr), German (de), Spanish (es), French (fr), Simplified Chinese (zh-SG) and Traditional Chinese (zh-HK). Names, instructions, tips, muscles and terms are translated; filter values stay in English. - Filters, quotas and errors.
bodyPart,targetandequipmenttake the same values as in v1. Request quota, rate limits, usage headers and the error format don't change.
What changes
| v1 | v2 | |
|---|---|---|
| Base path | /v1/exercises | /v2/exercises |
| API key | Header 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 |
| Media | gifUrl, a permanent GIF link | media: 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, /calories | Same paths under /v2 with v2 ids. similar and alternatives also take model. |
| Workouts and supplements | /v1/workout/generate, /v1/workout/program, /v1/supplements | Same 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/search | jointFocus, intensityLevel and movementTag on /v2/exercises |
Migrate in five steps
-
Send the key in the header
Change the path from
/v1to/v2, and move the key from?api-key=to theX-WorkoutX-Keyheader. 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" -
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.
TheGET /v2/exercises/legacy/0662 { "v1Id": "0662", "v1Name": "Push-up", "match": "equivalent", "exercise": { "id": "ex_WOZL6H", "name": "Push Ups Bodyweight", ... } }matchfield says how close the v2 exercise is:1,324 of the 1,327 v1 exercises have a v2 match. 582 of them are the same movement (matchMeaning What to do exactThe same movement Replace automatically equivalentThe same movement, named differently Replace automatically alternativeThe same movement with other equipment, or a close variation Suggest it, and let users confirm closestThe nearest exercise for the same muscles Suggest it, and let users confirm noneNo v2 exercise yet ( exerciseis null)Keep the v1 exercise for now exactorequivalent). -
Replace the GIF with a video
Play
media.mp4muted and looping, and showmedia.posterwhile 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(); -
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 fromGET /v2/exercises/{id}/mediawhen 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. -
Offer the female model
Male and female versions are separate exercises.
counterpartIdpoints at the same movement with the other model, so you can show it as a switch. To list one model only, filter with?model=femaleor?model=male.
Media by plan
| Plan | Video | Different exercises | Media views / month |
|---|---|---|---|
| Free | 300 × 360 with watermark | – | – |
| Starter | 600 × 720 | 1,000 per 30 days | 25,000 |
| Legacy Basic | 600 × 720 | 500 per 30 days | 25,000 |
| Growth, and legacy Pro | 600 × 720 | Unlimited | 150,000 |
| Scale, and legacy Ultra | 600 × 720 | Unlimited | 600,000 |
| Enterprise | 600 × 720 | Unlimited | Per 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.