Exercise API docs
Everything you need to show HEPonDemand exercises in your product. No key yet? Get a free sandbox key.
Downloads: OpenAPI 3.1 file · Postman collection · License
Quickstart
- Get a key. Test keys start with
hod_test_and see 20 sample exercises with watermarked pictures. Live keys start withhod_live_and see the whole library. Keep keys on your server, never in an app or web page. If your servers have fixed IP addresses, ask us to limit your live keys to them, so a leaked key doesn't work anywhere else. - Make a call.
curl https://hepondemand.com/api/v1/exercises?body_region=knee&per_page=5 \ -H "Authorization: Bearer $HOD_API_KEY" - Show an exercise. Use
name,steps,cautionsanddefault_dosage. Showimages[].thumbnail_urlin lists andfull_urlon detail screens, withalt_text, and showdisclosurewith every AI-generated picture anddisclaimerwith every exercise. - Stay in sync. Store what you need for up to 30 days. Refresh with
updated_since, or on Growth with/changes, which also tells you what was removed.
const res = await fetch("https://hepondemand.com/api/v1/exercises/clamshell", {
headers: { Authorization: `Bearer ${process.env.HOD_API_KEY}` },
});
const { data } = await res.json();
console.log(data.name, data.steps, data.default_dosage);Endpoints
Base URL: https://hepondemand.com/api/v1. Every response is JSON except the PDF. Lists return { data, page, per_page, total, has_more }; single items return { data }.
| Endpoint | What it returns | Plans |
|---|---|---|
GET /exercises | List and search. Filters: body_region, condition, equipment, position, movement, specialty, difficulty, q, updated_since. Paged with page and per_page (max 100). | All |
GET /exercises/{id} | One exercise, by id or slug. | All |
GET /programs | Ready-made programs by condition (filter: condition). | All |
GET /programs/{id} | One program with its exercises, in order, with dosage. | All |
GET /taxonomy | Every filter value, with slugs and names. | All |
GET /changes?since= | Exercises updated or removed since a time, oldest first. Page with next_cursor. | Growth, Platform |
…?include=videos | On /exercises and /exercises/{id}: adds each exercise's videos (signed links that play in a video tag). Without it, nothing changes. | Growth, Platform |
GET /exercises/{id}/handout.pdf | A print-ready patient handout for one exercise. | Growth, Platform |
Filters take comma-separated slugs from /taxonomy and match any of them, e.g. ?body_region=knee,hip&equipment=none. difficulty is easy, moderate or hard. updated_since takes an ISO 8601 date or date-time.
Pictures
Picture links are signed and expire after about a day (expires_at), and stay the same for an hour so they cache well. Don't store the links: fetch the exercise again for fresh ones. Each picture has ai_generated and, when true, a disclosure you must show with it: “Illustration generated with AI and reviewed by a licensed clinician.”
Limits and headers
- About 10 requests a second per key. Over that you get
429 rate_limitedwithRetry-After: 1. - A monthly quota by plan (calendar month, UTC). Only successful calls count. Over it you get
429 quota_exceededwithRetry-Afterset to when it resets. - Every response has
X-RateLimit-Limit,X-RateLimit-RemainingandX-RateLimit-Reset(Unix seconds), plusX-Api-Mode(testorlive). - Picture links don't count toward the quota.
Errors
Errors look like { "error": { "code": "not_found", "message": "Exercise not found" } }.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | A query parameter is missing or not valid. The message names it. |
| 401 | unauthorized | No key, or the key is wrong, revoked or expired. |
| 403 | account_suspended | The account is suspended (usually a failed payment), cancelled, or not paid yet. |
| 403 | ip_not_allowed | Your account limits live keys to approved server addresses, and this request came from another one. |
| 403 | plan_required | Your plan doesn't include this endpoint (change feed, handout PDFs and videos need Growth). |
| 404 | not_found | No such exercise or program, or not one your key can see. |
| 429 | rate_limited | More than 10 requests a second on one key. Wait for Retry-After (1 second). |
| 429 | quota_exceeded | This month's calls are used up. Retry-After says when the quota resets. |
| 500 | server_error | Something went wrong on our side. Try again shortly. |
| 503 | api_disabled | The API is temporarily closed. |
Display rules
- Show the content only inside the product named on your account.
- Keep the AI picture disclosure and the clinical disclaimer: “For use under the direction of a licensed clinician. Not medical advice.”
- Starter: show the credit in each exercise's
attributionfield. - No bulk export, resale or AI training. See the license.
Changelog
2026-11-06
- Optional server address allow-list: live keys can be limited to your servers' IP addresses (new 403 ip_not_allowed).
2026-11-05
- Exercise videos (Growth and up): add include=videos to /exercises or /exercises/{id}. Without it, responses are unchanged.
2026-11-04
- First version (v1): exercises, programs, taxonomy, change feed, handout PDFs.
- Signed picture links in thumbnail and full sizes, each labelled AI-generated.
- Test keys (Sandbox) and live keys, monthly quotas and a per-key burst limit.
v1 only ever gains fields and endpoints; nothing is renamed or removed. Questions? Contact us.