{"openapi":"3.1.0","info":{"title":"Anatome — Muscle Group Image Generator API","version":"3.0.0","description":"Anatome — Apache-2.0 licensed muscle group image generator + exercise database. SVG rendering of 23 muscle groups (male + female, front + back, dual view), backed by 1,324 exercise records from wrkout/exercises.json (Unlicense metadata; the dataset's photography is of unverified origin and is not cleared for redistribution). Anatomical SVG paths from react-native-body-highlighter (MIT, © Hicham El Boussarghini). MCP-compatible.  AUTHENTICATION: none. Anatome is keyless — no signup, no API key, no token.  FAIR USE: 50 requests per caller per day, resetting at 00:00 UTC. Over the limit, endpoints return 429 with `error: \"daily_fair_use_limit_reached\"`, `retryable: false` and a `reset_at` timestamp; the MCP endpoint instead returns a normal result with `isError: true` so the calling model sees the explanation. A 429 here means the caller is out of requests for the day — it does not mean the service is down, and retrying before `reset_at` will not help. For higher limits see https://platform.anatome.dev.","termsOfService":"https://anatome.dev/tos","contact":{"name":"NextSolutions","url":"https://nextsolutions.studio","email":"contact@nextsolutions.studio"},"license":{"name":"Apache-2.0","url":"https://www.apache.org/licenses/LICENSE-2.0"}},"servers":[{"url":"https://api.anatome.dev","description":"Cloudflare Workers (production)"}],"tags":[{"name":"Image Generation","description":"Render anatomical SVG diagrams"},{"name":"Exercise Database","description":"1,324 exercises with muscle mappings"},{"name":"MCP","description":"Model Context Protocol JSON-RPC"},{"name":"Discovery","description":"Catalog and capability endpoints"},{"name":"Skill Guides","description":"WORK IN PROGRESS — calisthenics skill progressions. Content is unverified and media coverage is incomplete; treat as provisional."}],"paths":{"/generateImage":{"post":{"tags":["Image Generation"],"summary":"Generate a muscle diagram (full schema)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"gender":{"type":"string","enum":["male","female"],"default":"male"},"view":{"type":"string","enum":["front","back","dual"],"default":"dual"},"layers":{"type":"array","items":{"type":"object","properties":{"color":{"type":"string","example":"#DC2626","description":"Hex, rgb(), or url(#gradientId)"},"muscles":{"type":"array","items":{"type":"string"},"example":["chest","abs"]},"opacity":{"type":"number","minimum":0,"maximum":1,"example":1},"stroke":{"type":"string"},"strokeWidth":{"type":"number"}},"required":["color","muscles"]}},"defs":{"type":"array","description":"SVG gradient/pattern definitions","items":{"type":"object"}},"width":{"type":"integer","default":768},"height":{"type":"integer","default":1024},"background":{"type":"string","default":"transparent"},"body_color":{"type":"string","default":"#282828"},"border_color":{"type":"string","default":"#dfdfdf"},"border_width":{"type":"number","default":1.5},"contour":{"type":"string","enum":["on","stroke","off"],"default":"on","description":"Body silhouette behind the muscles: on (filled, default), stroke (outline only, fill none), off (skip)"},"contour_color":{"type":"string","description":"Contour fill; defaults to body_color"},"contour_stroke":{"type":"string","description":"Contour stroke; defaults to border_color"},"contour_width":{"type":"number","description":"Contour stroke width; defaults to border_width"},"per_muscle":{"type":"object","description":"Per-muscle style override (highest priority)"},"side_filter":{"type":"object","description":"Highlight only one side: { biceps: 'left' }"},"format":{"type":"string","enum":["svg","png"],"default":"svg"},"output":{"type":"string","enum":["json","raw"],"default":"json"}}},"examples":{"simple":{"summary":"Single layer","value":{"gender":"male","view":"front","layers":[{"color":"#DC2626","muscles":["chest","abs"]}]}},"multicolor":{"summary":"Primary + secondary","value":{"view":"dual","layers":[{"color":"red","muscles":["chest"]},{"color":"blue","muscles":["triceps"]}]}}}}}},"responses":{"200":{"description":"Rendered SVG","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"svg":{"type":"string"},"format":{"type":"string"},"gender":{"type":"string"},"view":{"type":"string"},"muscles_rendered":{"type":"array","items":{"type":"string"}},"available_muscles_count":{"type":"integer"},"attribution":{"type":"string"},"attribution_source":{"type":"string"},"license":{"type":"string"},"duration_ms":{"type":"integer"}}}},"image/svg+xml":{"schema":{"type":"string"}}}},"500":{"description":"Server error"}}},"get":{"tags":["Image Generation"],"summary":"Generate a muscle diagram (query syntax)","parameters":[{"name":"muscles","in":"query","schema":{"type":"string"},"example":"chest,abs","description":"Comma-separated slugs (single layer)"},{"name":"color","in":"query","schema":{"type":"string"},"example":"#FF0000"},{"name":"layers","in":"query","schema":{"type":"string"},"example":"DC2626:chest,abs|0000FF:triceps","description":"Pipe-separated COLOR:muscles groups"},{"name":"gender","in":"query","schema":{"type":"string","enum":["male","female"]}},{"name":"view","in":"query","schema":{"type":"string","enum":["front","back","dual"]}},{"name":"output","in":"query","schema":{"type":"string","enum":["json","raw"]}},{"name":"contour","in":"query","schema":{"type":"string","enum":["on","stroke","off"]},"description":"Body silhouette: on (filled), stroke (outline only), off (skip)"},{"name":"contour_color","in":"query","schema":{"type":"string"},"description":"Contour fill; defaults to body_color"},{"name":"contour_stroke","in":"query","schema":{"type":"string"},"description":"Contour stroke; defaults to border_color"},{"name":"contour_width","in":"query","schema":{"type":"number"},"description":"Contour stroke width; defaults to border_width"}],"responses":{"200":{"description":"Rendered SVG"}}}},"/listMuscles":{"get":{"tags":["Discovery"],"summary":"List all supported muscles","responses":{"200":{"description":"Muscle catalog","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"count":{"type":"integer"},"muscles":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"views":{"type":"array","items":{"type":"string"}},"body_region":{"type":"string","nullable":true},"antagonists":{"type":"array","items":{"type":"string"}}}}}}}}}}}}},"/muscleInfo":{"get":{"tags":["Discovery"],"summary":"Per-muscle reference with exercise counts","parameters":[{"name":"slug","in":"query","required":true,"schema":{"type":"string"},"example":"chest"}],"responses":{"200":{"description":"Muscle detail"},"404":{"description":"Unknown slug"}}}},"/listEquipment":{"get":{"tags":["Discovery"],"summary":"List distinct equipment values from the exercise bundle","responses":{"200":{"description":"Equipment list"}}}},"/listGuides":{"get":{"tags":["Skill Guides"],"summary":"List the bundled skill-progression guides (WORK IN PROGRESS)","description":"WORK IN PROGRESS — media coverage is incomplete and the coaching cues are unreviewed; every response carries `status: \"work_in_progress\"`. Curated calisthenics skill catalog (CC-BY-4.0 content, served by this Apache-2.0 API). Returns one row per guide with tree and step counts.","responses":{"200":{"description":"Guide list","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"count":{"type":"integer"},"guides":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"summary":{"type":"string"},"tree_count":{"type":"integer"},"step_count":{"type":"integer"},"difficulty_order":{"type":"array","items":{"type":"string"}},"guide_url":{"type":"string"}}}},"guide_catalog_attribution":{"type":"string"},"guide_catalog_license":{"type":"string"},"license":{"type":"string"}}}}}}}}},"/getGuide":{"get":{"tags":["Skill Guides"],"summary":"Get one guide plus a summary of each skill tree (WORK IN PROGRESS)","description":"WORK IN PROGRESS — unverified content, incomplete media. Responses carry `status: \"work_in_progress\"`.","parameters":[{"name":"slug","in":"query","required":true,"schema":{"type":"string"},"example":"calisthenics"}],"responses":{"200":{"description":"Guide with tree summaries","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"slug":{"type":"string"},"name":{"type":"string"},"summary":{"type":"string"},"tree_count":{"type":"integer"},"step_count":{"type":"integer"},"difficulty_order":{"type":"array","items":{"type":"string"}},"trees":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"family":{"type":"string"},"difficulty":{"type":"string"},"summary":{"type":"string"},"step_count":{"type":"integer"},"prerequisites":{"type":"array","items":{"type":"string"}},"primary_muscles":{"type":"array","items":{"type":"string"}},"anatome_imageSrc":{"type":"string","nullable":true,"description":"Ready-to-embed muscle diagram for the skill"},"tree_url":{"type":"string"}}}}}}}}},"400":{"description":"Missing or malformed slug"},"404":{"description":"Unknown guide"}}}},"/getGuideTree":{"get":{"tags":["Skill Guides"],"summary":"Get one full skill tree with every progression step (WORK IN PROGRESS)","description":"WORK IN PROGRESS — the cues have not been reviewed by a coach and some steps have no demo media. Responses carry `status: \"work_in_progress\"`; present the content as provisional rather than as verified training advice. Each step carries intent, cues, common faults, drills, programming, unlock criteria and demo media references.","parameters":[{"name":"tree","in":"query","required":true,"schema":{"type":"string"},"example":"planche"},{"name":"guide","in":"query","schema":{"type":"string","default":"calisthenics"},"example":"calisthenics"}],"responses":{"200":{"description":"Full skill tree","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"guide_slug":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"family":{"type":"string"},"difficulty":{"type":"string"},"summary":{"type":"string"},"prerequisites":{"type":"array","items":{"type":"string"}},"primary_muscles":{"type":"array","items":{"type":"string"}},"secondary_muscles":{"type":"array","items":{"type":"string"}},"anatome_layers_payload":{"type":"array","items":{"type":"object","properties":{"color":{"type":"string","example":"#DC2626","description":"Hex, rgb(), or url(#gradientId)"},"muscles":{"type":"array","items":{"type":"string"},"example":["chest","abs"]},"opacity":{"type":"number","minimum":0,"maximum":1,"example":1},"stroke":{"type":"string"},"strokeWidth":{"type":"number"}},"required":["color","muscles"]}},"anatome_imageSrc":{"type":"string","nullable":true},"steps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"order":{"type":"integer"},"name":{"type":"string"},"level":{"type":"string"},"intent":{"type":"string"},"cues":{"type":"array","items":{"type":"string"}},"common_faults":{"type":"array","items":{"type":"string"}},"drills":{"type":"array","items":{"type":"object"}},"programming":{"type":"object"},"unlock":{"type":"object"},"media":{"type":"array","items":{"type":"object"}}}}}}}}}},"400":{"description":"Missing or malformed slug"},"404":{"description":"Unknown guide or tree"}}}},"/workoutImage":{"post":{"tags":["Image Generation"],"summary":"Session heatmap — stack muscle activation across multiple exercises","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"exercises":{"type":"array","items":{"type":"string"},"example":["bench press","squat","overhead press"]},"gender":{"type":"string","enum":["male","female"],"default":"male"},"view":{"type":"string","enum":["front","back","dual"],"default":"dual"},"output":{"type":"string","enum":["json","raw"],"default":"json"}},"required":["exercises"]}}}},"responses":{"200":{"description":"Combined workout SVG + muscle hit counts"},"400":{"description":"Missing exercises array"}}}},"/searchExercises":{"get":{"tags":["Exercise Database"],"summary":"Search the exercise database","description":"Fuzzy name search across 1,324 exercises with optional muscle/equipment/level filters. Default response includes free-exercise-db fields (instructions, images, force, category, etc.) plus Anatome mappings. Use fields= to trim or fields=all for variations and relatedExerciseIds.","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"},"example":"bench","description":"Name search query"},{"name":"muscle","in":"query","schema":{"type":"string"},"example":"chest","description":"Filter by Anatome muscle slug"},{"name":"equipment","in":"query","schema":{"type":"string"},"example":"barbell"},{"name":"level","in":"query","schema":{"type":"string","enum":["beginner","intermediate","expert"]}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":50},"example":5},{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0},"example":0},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor from prior response next_cursor"},{"name":"fields","in":"query","schema":{"type":"string"},"description":"Comma-separated field list, or all/* for full records"},{"name":"lang","in":"query","schema":{"type":"string","enum":["en","es","it","tr","ru","zh","hi","pl","ko","fr"]},"description":"Instruction language. Overrides Accept-Language. Unknown tags fall back to English wrkout cues."}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"total_matched":{"type":"integer"},"offset":{"type":"integer"},"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true},"results":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"primaryMuscles":{"type":"array","items":{"type":"string"}},"secondaryMuscles":{"type":"array","items":{"type":"string"}},"equipment":{"type":"string"},"level":{"type":"string"},"category":{"type":"string"},"image_url":{"type":"string","nullable":true,"deprecated":true,"description":"Always null. Retired with /exerciseGif — see video_url."},"gif_url":{"type":"string","nullable":true,"deprecated":true,"description":"Always null on public JSON. Licensed GymVisual GIFs are not advertised here — first-party pages construct GET /exerciseGif?id=<ext_id> themselves. See has_licensed_media."},"has_licensed_media":{"type":"boolean","description":"True when this ext_id has a GymVisual join (media may exist in R2). Not a URL and not a licence. Bytes are served only to allowlisted Origins/Referers or X-Anatome-Media-Key."},"licensed_media_kinds":{"type":"array","items":{"type":"string","enum":["video","anim","still"]},"description":"Gated demo tiers that exist for this row, best first, so a first-party page can pick one instead of probing and eating a 404. Availability metadata only — no URL, no filename, not a grant. Empty when there is no join."},"video_url":{"type":"string","nullable":true,"description":"Demonstration video (YouTube) for this exercise, from yuhonas/free-exercise-db PR #26. A link only — Anatome hosts no video bytes. Link or embed with YouTube's own player; do not extract frames."},"video_exercise_specific":{"type":"boolean","nullable":true,"description":"True when this clip backs only this exercise. False when it is shared with related exercises in the same family and may not show this exact variant — 1,158 of 1,324 exercises share a clip. Filter on this when you need a true depiction rather than coverage."},"anatome_imageSrc":{"type":"string","description":"Ready-to-embed absolute <img src> URL for Anatome's own generated muscle diagram"},"anatome_layers_payload":{"type":"array","items":{"type":"object"}},"instructions":{"type":"array","items":{"type":"string"},"description":"Step-by-step cues. Language follows Accept-Language or ?lang= (en,es,it,tr,ru,zh,hi,pl,ko,fr). English is always wrkout/exercises.json (Unlicense). Other langs are hasaneyldrm/exercises-dataset (MIT) when Hasan's English cue is the same lift as wrkout (a subset of the 198 media joins); otherwise English is returned and instructions_lang is en."},"instructions_lang":{"type":"string","description":"Language of the instructions array actually returned."},"instructions_langs":{"type":"array","items":{"type":"string"},"description":"Hasan translation langs this row can serve (no en — English is always wrkout). Empty when unmatched or when the Hasan EN cue is a different lift. Not in the searchExercises default projection (it is [] or the same 9 tags on every row) — ask for it with fields=, or read it off the full getExercise record."},"instruction_source":{"type":"string","enum":["wrkout","hasan"],"description":"wrkout = Unlicense English cues. hasan = MIT translated steps from hasaneyldrm/exercises-dataset."},"images":{"type":"array","items":{"type":"string"},"deprecated":true,"description":"Always empty. Retired with /exerciseImage — the source photography's copyright could not be established."},"source_images":{"type":"array","items":{"type":"string"},"deprecated":true,"description":"Always empty. Retired with /exerciseImage."},"movementType":{"type":"string","nullable":true,"description":"Alias of mechanic (compound / isolation)"},"keywords":{"type":"array","items":{"type":"string"}},"variations":{"type":"array","items":{"type":"object","properties":{"ext_id":{"type":"string"},"name":{"type":"string"},"anatome_imageSrc":{"type":"string","nullable":true}}}},"relatedExerciseIds":{"type":"array","items":{"type":"string"}}}}},"exercise_db_attribution":{"type":"string"},"license":{"type":"string"}}}}}}}}},"/getExercise":{"get":{"tags":["Exercise Database"],"summary":"Fetch exercise(s) — 4 modes","description":"Provide exactly one of: name (fuzzy), id, muscle (+limit), or random=1.","parameters":[{"name":"name","in":"query","schema":{"type":"string"},"example":"bench press"},{"name":"id","in":"query","schema":{"type":"string"},"example":"Bench_Press"},{"name":"muscle","in":"query","schema":{"type":"string"},"example":"chest"},{"name":"limit","in":"query","schema":{"type":"integer","default":10}},{"name":"random","in":"query","schema":{"type":"integer","enum":[1]},"example":1},{"name":"fields","in":"query","schema":{"type":"string"},"description":"Comma-separated field list, or all/* (default: full record incl. instructions)"},{"name":"lang","in":"query","schema":{"type":"string","enum":["en","es","it","tr","ru","zh","hi","pl","ko","fr"]},"description":"Instruction language. Overrides Accept-Language. Unknown tags fall back to English wrkout cues."}],"responses":{"200":{"description":"Exercise found"},"404":{"description":"No match"}}}},"/exerciseMedia":{"get":{"tags":["Exercise Database"],"summary":"Licensed GymVisual media by tier (allowlisted callers only)","description":"One route for every tier named in an exercise's licensed_media_kinds. The `anim` and `still` tiers are reachable ONLY here; /exerciseGif, /exerciseImage and /exerciseVideo are aliases for gif, thumb and video. Same gate, same 403/404 semantics; Range/206/HEAD apply to kind=video. Read licensed_media_kinds and pick a tier rather than probing — 318 of the 1,324 rows have no MP4.","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string"},"example":"0003","description":"Hasan id (all 1,324 rows) or an Anatome ext_id alias (the 198 joined spine rows)"},{"name":"kind","in":"query","required":true,"schema":{"type":"string","enum":["video","anim","still","gif","thumb"]},"example":"video"}],"responses":{"200":{"description":"Media bytes for the requested tier"},"206":{"description":"Partial content (kind=video)"},"400":{"description":"Missing or invalid id, or unknown kind"},"403":{"description":"Caller is not allowlisted"},"404":{"description":"Unknown id, no asset of this kind for the row, or no object in R2"}}}},"/exerciseGif":{"get":{"tags":["Exercise Database"],"summary":"Licensed GymVisual GIF (allowlisted callers only)","description":"Serves a GymVisual GIF from R2 when this deployment has the object. Public JSON never includes this URL. Ungated callers (no matching Origin/Referer, no X-Anatome-Media-Key) get 403. MCP_TRUSTED_KEY is not a grant. Name join is from hasaneyldrm/exercises-dataset (MIT metadata); bytes remain © Gym visual and require a Gym visual licence. Cloning this repo is not a licence. Missing object or empty bucket → 404. Do not commit media files.","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string"},"example":"0003","description":"Hasan id (0003, all 1,324 rows) or an Anatome ext_id alias (Air_Bike, the 198 joined spine rows)"}],"responses":{"200":{"description":"image/gif"},"400":{"description":"Missing or invalid id"},"403":{"description":"Caller is not allowlisted"},"404":{"description":"Unknown id, no asset of this kind for the row, or no object in R2"}}}},"/exerciseImage":{"get":{"tags":["Exercise Database"],"summary":"Licensed GymVisual thumb, or 410 for the retired wrkout path proxy","description":"GET /exerciseImage?id=<ext_id> serves a licensed thumb (same gate as /exerciseGif). GET /exerciseImage?path=… without id is the retired wrkout photography proxy and always returns 410 — that path is unread (no traversal). Do not pass caller-supplied paths.","parameters":[{"name":"id","in":"query","schema":{"type":"string"},"description":"Hasan id or Anatome ext_id alias for a licensed thumb"},{"name":"path","in":"query","schema":{"type":"string"},"deprecated":true,"description":"Retired wrkout proxy. Ignored. Always 410 when id is absent."}],"responses":{"200":{"description":"image/jpeg (when id= is gated and present in R2)"},"403":{"description":"Caller is not allowlisted"},"404":{"description":"Unknown id, no asset of this kind for the row, or no object in R2"},"410":{"description":"Retired wrkout ?path= proxy"}}}},"/exerciseVideo":{"get":{"tags":["Exercise Database"],"summary":"Licensed GymVisual MP4 (allowlisted callers only)","description":"Same gate as /exerciseGif. Supports Range / 206 / HEAD for seeking. Public JSON never includes this URL. Empty bucket → 404. 1,006 of the 1,324 rows ship an MP4; the other 318 ship an illustration instead and 404 here — read licensed_media_kinds on the exercise record rather than probing.","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string"},"example":"0003"}],"responses":{"200":{"description":"video/mp4"},"206":{"description":"Partial content"},"403":{"description":"Caller is not allowlisted"},"404":{"description":"Unknown id, no asset of this kind for the row, or no object in R2"},"416":{"description":"Unsatisfiable Range"}}}},"/resolveExercise":{"get":{"tags":["Exercise Database"],"summary":"Resolve an exercise to muscle layers","parameters":[{"name":"exercise","in":"query","required":true,"schema":{"type":"string"},"example":"bench press"}],"responses":{"200":{"description":"Resolved layers"}}},"post":{"tags":["Exercise Database"],"summary":"Resolve an exercise (JSON body)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"exercise":{"type":"string"}},"required":["exercise"]}}}},"responses":{"200":{"description":"Resolved layers"}}}},"/mcp":{"post":{"tags":["MCP"],"summary":"MCP JSON-RPC 2.0 endpoint","description":"MCP JSON-RPC 2.0 endpoint. Tools: generate_muscle_image, list_muscles, resolve_exercise, search_exercises, get_exercise.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string","example":"2.0"},"id":{"type":"integer"},"method":{"type":"string"},"params":{"type":"object"}}}}}},"responses":{"200":{"description":"JSON-RPC response"}}},"get":{"tags":["MCP"],"summary":"MCP capability descriptor","responses":{"200":{"description":"Server info + tool names"}}}},"/openapi":{"get":{"tags":["Discovery"],"summary":"This OpenAPI 3.1 spec","responses":{"200":{"description":"OpenAPI document"}}}},"/selfTest":{"get":{"tags":["Discovery"],"summary":"Run the self-test suite","responses":{"200":{"description":"Test summary"}}}}}}