Skip to content

Integrate in one afternoon

54 exercises, each with a multi-frame demonstration in male and female variants. One API for the metadata, one URL pattern for the images.

Quickstart

Three steps to an image on screen.

1. Fetch the catalogue

bash
curl https://api.moveindex.dev/v1/exercises \
  -H "Authorization: Bearer $MOVEINDEX_KEY"

2. Read an image URL from the response

json
{
  "slug": "plank",
  "name": "Plank",
  "frame_count": 2,
  "images": {
    "male":   "https://cdn.moveindex.dev/$MOVEINDEX_KEY/exercises/plank-male.png",
    "female": "https://cdn.moveindex.dev/$MOVEINDEX_KEY/exercises/plank-female.png"
  },
  "watermarked": false
}

3. Render it

html
<img src="https://cdn.moveindex.dev/$MOVEINDEX_KEY/exercises/plank-male.png"
     alt="Plank demonstration" />

You can also build the URL yourself from a slug rather than storing ours — the pattern is stable and documented below.

Authentication

The API takes a bearer token. The image CDN takes the key in the path, because an <img> tag cannot send headers.

bash
# API
curl https://api.moveindex.dev/v1/exercises -H "Authorization: Bearer xdb_…"

# Images
https://cdn.moveindex.dev/xdb_…/exercises/plank-male.png

Your CDN key is not a secret

It ships in your web bundle and inside your app binary, so treat it as a public identifier rather than a credential. It is read-only, it cannot change anything, and you can rotate or revoke it at any time without a code change if you keep it in an environment variable. If you would rather it never reach the client, proxy image requests through your own server.

Images

Two canvases, two variants, one URL pattern.

bash
https://cdn.moveindex.dev/{key}/exercises/{slug}-{male|female}.png

Each image is a single tall picture containing the phases of the movement stacked vertically. frame_count tells you how many.

frame_countCanvasTypical
3768 × 1376most exercises
2896 × 1200holds and carries

Images are dark-gym photographs, which sit well on dark interfaces and poorly on light ones. They are scenes, not cutouts, so they cannot be composited onto another background. Check one against your design before you commit.

Endpoints

GET /v1/exercises

Search and filter the catalogue.

params: muscle, equipment, category, q, limit, offset

GET /v1/exercises/:slug

One exercise. Aliases resolve to their canonical entry.

GET /v1/meta

Every filter value with live counts.

GET /v1/usage

What this key has requested.

GET /health

Unauthenticated liveness check.

bash
curl https://api.moveindex.dev/v1/exercises \
  -H "Authorization: Bearer $MOVEINDEX_KEY" \
  -G -d muscle=quads -d equipment=barbell -d limit=20

Filter values

Live counts from the catalogue. Nothing to guess.

muscle

  • quads (12)
  • core (9)
  • back (9)
  • glutes (6)
  • hamstrings (5)
  • chest (4)
  • full_body (3)
  • shoulders (3)
  • forearms (2)
  • calves (1)

equipment

  • dumbbell (16)
  • bodyweight (13)
  • barbell (11)
  • cable (3)
  • sled (3)
  • sandbag (2)
  • pull_up_bar (2)
  • kettlebell (1)
  • medicine_ball (1)
  • machine (1)
  • band (1)

category

  • strength (40)
  • core (7)
  • hyrox (6)
  • mobility (1)

Errors

Every failure returns JSON with a stable error code.

401 missing_key No Authorization header, or it does not start with xdb_.
403 invalid_key The key is unknown or has been revoked.
403 inactive_key Billing has lapsed. The key exists but is not active.
403 upgrade_required A free key asked the CDN for a clean original.
404 not_found No such exercise. We log these — they become the generation queue.

Image responses also carry an x-moveindex-error header, so a lapsed key is distinguishable from a missing file rather than looking like a broken image.

Free tier

Integrate before you pay.

A free key returns the same metadata and the same URL shapes, pointing at watermarked 560px previews. Every field your integration reads is identical, so switching to a paid key changes the pictures and nothing else. Responses carry "watermarked": true so you can tell.

Licence

Every image is generated by us. There is no stock-photo chain, no model releases to chase and no unclear attribution — which is why we can license them cleanly for commercial use in your app.

Full terms are being drafted. Ask if you need them before then.