{"openapi":"3.1.0","info":{"title":"1PM Workout API","version":"1.0.0","description":"Read and log your 1PM Workout training and food log. Make an API key in the app (Settings > Connect AI) and send it as \"Authorization: Bearer 1pm_key_...\". The same operations are available to AI apps as an MCP server at https://www.1pmw.fit/mcp. A food log day holds at most 100 entries."},"servers":[{"url":"https://www.1pmw.fit/api/v1"}],"externalDocs":{"description":"Guide","url":"https://www.1pmw.fit/developers"},"security":[{"bearer":[]}],"paths":{"/me":{"get":{"operationId":"get_status","summary":"Where the user stands","description":"Where the user stands in 1PM Workout: level and rank, streak (and the last day to keep it), the planned training days, whether today is a training day and whether today's workout is done, the next workout with its exercises and sets, totals, and the last workout. Start here for any question about the user's training.","responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"patch":{"operationId":"update_plan","summary":"Change the plan","description":"Changes the user's training plan: the weekdays they train on, the reminder time, running or brisk walking for the cardio, or their level. Only what is given changes. Changing the level starts that level's sessions from zero. Returns the status after the change.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"trainingDays":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6},"minItems":1,"maxItems":7,"uniqueItems":true,"description":"The weekdays to train on, as numbers: 0 is Sunday, 1 Monday ... 6 Saturday. E.g. [1, 3, 5]."},"reminderTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"Time of day for the training reminder, HH:MM (24 hours)."},"cardio":{"type":"string","enum":["run","walk"],"description":"\"run\", or \"walk\" to swap the run for brisk walking."},"level":{"type":"integer","minimum":1,"maximum":10,"description":"The level to train at, from 1 to 10."}},"additionalProperties":false}}}},"responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/program":{"get":{"operationId":"get_program","summary":"The workouts of a theme","description":"What the workouts of the program consist of: the exercises, how each is split into sets, and the rest between sets. Returns all ten levels of a theme, or one level. Without a theme it uses the user's own theme and their run-or-walk choice. Use it to explain a level or to compare levels; the user's next workout is already part of get_status.","security":[{},{"bearer":[]}],"parameters":[{"name":"theme","in":"query","required":false,"description":"Theme id. Defaults to the theme the user trains with.","schema":{"type":"string","enum":["opm","bluelock","haikyuu","ippo","slamdunk","kuroko","megalobox","dumbbells","runwind","babysteps"]}},{"name":"level","in":"query","required":false,"description":"A single level from 1 to 10. Leave out for all ten.","schema":{"type":"integer","minimum":1,"maximum":10}},{"name":"cardio","in":"query","required":false,"description":"\"walk\" swaps the run for brisk walking. Defaults to what the user picked.","schema":{"type":"string","enum":["run","walk"]}}],"responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/themes":{"get":{"operationId":"list_themes","summary":"The anime themes","description":"The ten anime themes of 1PM Workout, each with its four exercises, the ten rank names (one per level) and its quote. The theme itself is picked in the app.","security":[{},{"bearer":[]}],"responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/workouts":{"get":{"operationId":"list_workouts","summary":"The workout history","description":"The user's finished workouts, newest first, each with its date, level, exercises, how it felt (ok or hard) and how long it took, plus totals across everything they ever logged. Narrow it down with from and to.","parameters":[{"name":"limit","in":"query","required":false,"description":"How many workouts to return. Defaults to 20.","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"from","in":"query","required":false,"description":"Only workouts on or after this day, YYYY-MM-DD.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"to","in":"query","required":false,"description":"Only workouts on or before this day, YYYY-MM-DD.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}],"responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"log_workout","summary":"Log a finished workout","description":"Logs a workout the user has finished: the whole session of a level (every exercise, all sets), the same as finishing it in the app. It counts for the streak and, if feel is given, towards the next level: three workouts that felt ok unlock the next level. Only call this when the user says they did the workout, never to plan one. Ask how it felt (ok or hard) if they didn't say: calling this again with feel rates the workout that was logged without one, it doesn't log another. A partial workout can't be logged.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"feel":{"type":"string","enum":["ok","hard"],"description":"How the workout felt. Without it the workout is logged but does not count towards the next level until it is rated."},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"The day the workout was done, YYYY-MM-DD in the user's own calendar. Defaults to today."},"level":{"type":"integer","minimum":1,"maximum":10,"description":"The level that was done. Defaults to the user's current level."},"durationMinutes":{"type":"number","minimum":1,"maximum":600,"description":"How long it took, in minutes, if the user said."},"cardio":{"type":"string","enum":["run","walk"],"description":"Whether the last exercise was the run or the brisk walk. Defaults to what the user picked."},"theme":{"type":"string","enum":["opm","bluelock","haikyuu","ippo","slamdunk","kuroko","megalobox","dumbbells","runwind","babysteps"],"description":"Theme id, if it was done with another theme than the usual one."}},"additionalProperties":false}}}},"responses":{"201":{"description":"The result.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/food":{"get":{"operationId":"get_food_log","summary":"The food log of a day","description":"What the user logged in the calorie tracker on one day: every entry with its calories, protein, carbs and fat, and the totals of the day. Defaults to today.","parameters":[{"name":"date","in":"query","required":false,"description":"The day, YYYY-MM-DD in the user's own calendar. Defaults to today.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}],"responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"log_food","summary":"Add food to a day","description":"Adds food to the user's calorie tracker. Give every item its own entry with the calories of the portion that was eaten; estimate the calories and macros from typical values when the user only describes the meal. Only call this for something the user says they ate or drank.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"What it was, e.g. \"2 scrambled eggs\"."},"calories":{"type":"number","minimum":0,"maximum":10000,"description":"Energy of the portion in kcal."},"protein":{"type":"number","minimum":0,"maximum":1000,"description":"Protein of the portion in grams."},"carbs":{"type":"number","minimum":0,"maximum":1000,"description":"Carbohydrates of the portion in grams."},"fat":{"type":"number","minimum":0,"maximum":1000,"description":"Fat of the portion in grams."},"grams":{"type":"number","minimum":0,"maximum":10000,"description":"Weight of the portion in grams, if known."},"brand":{"type":"string","maxLength":60,"description":"Brand or where it is from, if any."}},"required":["name","calories"],"additionalProperties":false},"minItems":1,"maxItems":20,"description":"What was eaten, one entry per food."},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"The day it was eaten, YYYY-MM-DD in the user's own calendar. Defaults to today."}},"required":["items"],"additionalProperties":false}}}},"responses":{"201":{"description":"The result.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/food/history":{"get":{"operationId":"get_food_history","summary":"Daily food totals","description":"The daily totals (calories, protein, carbs, fat) of the last days the user logged food on, newest first, with the average over those days.","parameters":[{"name":"days","in":"query","required":false,"description":"How many days back, today included. Defaults to 7.","schema":{"type":"integer","minimum":1,"maximum":90}}],"responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/food/{date}/{id}":{"delete":{"operationId":"delete_food_entry","summary":"Remove a food entry","description":"Removes one entry from the calorie tracker, for something that was logged by mistake. Takes the day and the id of the entry, both from get_food_log.","parameters":[{"name":"date","in":"path","required":true,"description":"The day the entry is on, YYYY-MM-DD.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"id","in":"path","required":true,"description":"The id of the entry.","schema":{"type":"string","minLength":1,"maxLength":40}}],"responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"An API key made in the app, or an OAuth access token."}},"responses":{"Error":{"description":"What went wrong: a short code and a sentence.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"]}}}}}}}