Templates
Your organization’s reusable library of workouts, phases, blocks and prescriptions.
Templates are the reusable building blocks coaches assign to athletes. Template rows carry their parent id (workoutId, programId, …) when they belong to a larger template. All lists accept search on the template name.
List workout templates
Workout templates of your organization’s library, newest first, without their content.
Request
curl "https://api-next.vitruve.fit/v1/templates/workouts?search=strength&limit=20" \
-H "X-API-Key: YOUR_API_KEY"const response = await fetch(
'https://api-next.vitruve.fit/v1/templates/workouts?search=strength&limit=20',
{ headers: { 'X-API-Key': process.env.VITRUVE_API_KEY } }
)
const body = await response.json()
if (!response.ok) throw new Error(`${response.status}: ${body.message}`)
console.log(body.data)import os
import requests
response = requests.get(
"https://api-next.vitruve.fit/v1/templates/workouts?search=strength&limit=20",
headers={"X-API-Key": os.environ["VITRUVE_API_KEY"]},
timeout=30,
)
response.raise_for_status()
print(response.json()["data"])Response 200
{
"ok": true,
"timestamp": 1738247125207,
"data": [
{
"id": "41d6e9b3-a8f5-4c07-92e1-d5b0c3a76f84",
"name": "Lower body strength",
"isTemplate": true,
"rpe": null,
"userId": null,
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"scheduledWorkoutId": null,
"completedAt": null,
"startedAt": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"testType": null
}
],
"meta": {
"limit": 20,
"hasMore": true,
"nextCursor": "ZTU2M2ZlYzMtM2IxYy00…"
}
}Query parameters
searchstring- Case-insensitive match on the template name.
limitintegerdefault50- Page size, 1–100.
cursorstringmeta.nextCursorfrom the previous page. Omit it to get the first page.
Notes
- Lists return the template rows only, newest
createdAtfirst. Fetch the detail endpoint for the content. - Athlete-performed and athlete-assigned workouts are never returned here. Use
GET /workoutsfor those.
Response fields
iduuid- Workout template id. Pass it to
GET /templates/workouts/{id}. namestring- Template name.
isTemplateboolean- Always
trueon these endpoints. testTypestringnullable- Test protocol of the workout, such as
vertical_jumporlinear_sprint.nullfor regular training.
Failures are described in error codes.
Get a workout template
One workout template with its full tree: blocks → prescription groups → prescriptions → parameters and planned sets.
Request
curl "https://api-next.vitruve.fit/v1/templates/workouts/41d6e9b3-a8f5-4c07-92e1-d5b0c3a76f84" \
-H "X-API-Key: YOUR_API_KEY"const response = await fetch(
'https://api-next.vitruve.fit/v1/templates/workouts/41d6e9b3-a8f5-4c07-92e1-d5b0c3a76f84',
{ headers: { 'X-API-Key': process.env.VITRUVE_API_KEY } }
)
const body = await response.json()
if (!response.ok) throw new Error(`${response.status}: ${body.message}`)
console.log(body.data)import os
import requests
response = requests.get(
"https://api-next.vitruve.fit/v1/templates/workouts/41d6e9b3-a8f5-4c07-92e1-d5b0c3a76f84",
headers={"X-API-Key": os.environ["VITRUVE_API_KEY"]},
timeout=30,
)
response.raise_for_status()
print(response.json()["data"])Response 200
{
"ok": true,
"timestamp": 1738247125207,
"data": {
"id": "41d6e9b3-a8f5-4c07-92e1-d5b0c3a76f84",
"name": "Lower body strength",
"isTemplate": true,
"rpe": null,
"userId": null,
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"scheduledWorkoutId": null,
"completedAt": null,
"startedAt": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"testType": null,
"blocks": [
{
"id": "6a2f9d14-b8c3-4e70-a5d1-0c7e3b94f826",
"name": "Strength",
"isTemplate": true,
"order": 0,
"workoutId": "41d6e9b3-a8f5-4c07-92e1-d5b0c3a76f84",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"prescriptionsGroups": [
{
"id": "e8b40c7d-5f19-4a26-9d83-2b6a1e0f7c45",
"name": "Main lift",
"isTemplate": true,
"order": 0,
"blockId": "6a2f9d14-b8c3-4e70-a5d1-0c7e3b94f826",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"prescriptions": [
{
"id": "1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"exerciseId": "1c7a5e93-f804-4b26-a9d1-3e6b0d82c4f7",
"prescriptionsGroupId": "e8b40c7d-5f19-4a26-9d83-2b6a1e0f7c45",
"name": "Back squat",
"order": 0,
"note": "Stop the set if mean velocity drops below 0.55 m/s.",
"isTemplate": true,
"isVbt": true,
"trainingType": "vbt",
"trainingAlgorithm": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"seriePrescriptions": [
{
"id": "9d5e2a07-c4b1-4f38-a6e9-71f0d3c8b524",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"prescriptionId": "1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
"prescriptionTypeId": "3e9d7a12-c5b8-4f40-a136-d82e4b6f9c05",
"unitId": "fa52c8d4-17e3-4b69-8d0a-6c3f9e1b2a78",
"order": 0,
"isRange": false,
"isTopMode": false,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null
}
],
"series": [
{
"id": "b2c86f41-03ad-4e95-b7d2-5e18a9c04f63",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"prescriptionId": "1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
"order": 0,
"completedAt": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"serieValues": [
{
"id": "5f03d8b6-e917-4c2a-8b45-c6a2f1e7d390",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"serieId": "b2c86f41-03ad-4e95-b7d2-5e18a9c04f63",
"seriePrescriptionId": "9d5e2a07-c4b1-4f38-a6e9-71f0d3c8b524",
"valuePrescriptedInf": null,
"valuePrescriptedSup": null,
"valuePrescripted": 80,
"valueExecuted": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null
}
],
"metricValues": [],
"repetitions": []
}
]
}
]
}
]
}
]
}
}Path parameters
iduuidrequired- Resource id.
Notes
- Same tree as
GET /workouts/{id}, starting at this level. Every nested level excludes deleted rows and is sorted byorder. serieValuesare returned in theunitIdof theirseriePrescriptionId, not in the stored base unit.- In a template,
serieshold the planned values:valueExecutedandcompletedAtarenull, and there are no repetitions or metric values. - Returns 404 for an id that is not a template, even if the workout exists in your organization.
Response fields
blocks[]object[]- Blocks, in order.
blocks[].prescriptionsGroups[]object[]- Prescription groups. More than one prescription in a group is a superset.
blocks[].prescriptionsGroups[].prescriptions[].exerciseIduuid- Exercise. Resolve with
GET /exercises/{id}. blocks[].prescriptionsGroups[].prescriptions[].seriePrescriptions[].prescriptionTypeIduuid- Parameter type (load, repetitions, velocity…). Resolve with
GET /prescription-types/{id}. blocks[].prescriptionsGroups[].prescriptions[].seriePrescriptions[].unitIduuid- Unit of the parameter. Resolve with
GET /units/{id}. blocks[].prescriptionsGroups[].prescriptions[].seriePrescriptions[].isRangebooleannullable- When
true, the planned value isvaluePrescriptedInf–valuePrescriptedSupinstead ofvaluePrescripted. blocks[].prescriptionsGroups[].prescriptions[].series[]object[]- Planned sets, in order.
blocks[].prescriptionsGroups[].prescriptions[].series[].serieValues[].seriePrescriptionIduuid- The parameter this value belongs to, in
seriePrescriptions. blocks[].prescriptionsGroups[].prescriptions[].series[].serieValues[].valuePrescriptednumbernullable- Planned value, in the parameter’s
unitId.
Failures are described in error codes.
List phase templates
Phase templates of your organization’s library, newest first, without their scheduled workouts.
Request
curl "https://api-next.vitruve.fit/v1/templates/phases?limit=20" \
-H "X-API-Key: YOUR_API_KEY"const response = await fetch(
'https://api-next.vitruve.fit/v1/templates/phases?limit=20',
{ headers: { 'X-API-Key': process.env.VITRUVE_API_KEY } }
)
const body = await response.json()
if (!response.ok) throw new Error(`${response.status}: ${body.message}`)
console.log(body.data)import os
import requests
response = requests.get(
"https://api-next.vitruve.fit/v1/templates/phases?limit=20",
headers={"X-API-Key": os.environ["VITRUVE_API_KEY"]},
timeout=30,
)
response.raise_for_status()
print(response.json()["data"])Response 200
{
"ok": true,
"timestamp": 1738247125207,
"data": [
{
"id": "d71a5c38-6e04-4f9b-a2c7-8b3d0f6e1a95",
"name": "Accumulation",
"isTemplate": true,
"order": null,
"weeks": 4,
"programId": null,
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null
}
],
"meta": {
"limit": 20,
"hasMore": true,
"nextCursor": "ZTU2M2ZlYzMtM2IxYy00…"
}
}Query parameters
searchstring- Case-insensitive match on the template name.
limitintegerdefault50- Page size, 1–100.
cursorstringmeta.nextCursorfrom the previous page. Omit it to get the first page.
Notes
- Lists return the template rows only, newest
createdAtfirst. Fetch the detail endpoint for the content.
Response fields
iduuid- Template id.
namestring- Template name, as shown in the library.
isTemplateboolean- Always
trueon these endpoints. orderintegernullable- Position inside its parent template.
programIduuidnullable- Parent template when this one belongs to a larger template. Resolve with
GET /programs/{id}.nullfor a standalone template. weeksintegernullable- Length of the phase in weeks.
Failures are described in error codes.
Get a phase template
One phase template with its scheduled workouts, oldest first. Each scheduled workout carries its workout row, without content.
Request
curl "https://api-next.vitruve.fit/v1/templates/phases/d71a5c38-6e04-4f9b-a2c7-8b3d0f6e1a95" \
-H "X-API-Key: YOUR_API_KEY"const response = await fetch(
'https://api-next.vitruve.fit/v1/templates/phases/d71a5c38-6e04-4f9b-a2c7-8b3d0f6e1a95',
{ headers: { 'X-API-Key': process.env.VITRUVE_API_KEY } }
)
const body = await response.json()
if (!response.ok) throw new Error(`${response.status}: ${body.message}`)
console.log(body.data)import os
import requests
response = requests.get(
"https://api-next.vitruve.fit/v1/templates/phases/d71a5c38-6e04-4f9b-a2c7-8b3d0f6e1a95",
headers={"X-API-Key": os.environ["VITRUVE_API_KEY"]},
timeout=30,
)
response.raise_for_status()
print(response.json()["data"])Response 200
{
"ok": true,
"timestamp": 1738247125207,
"data": {
"id": "d71a5c38-6e04-4f9b-a2c7-8b3d0f6e1a95",
"name": "Accumulation",
"isTemplate": true,
"order": null,
"weeks": 4,
"programId": null,
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"scheduledWorkouts": [
{
"id": "30e8b6f2-d5a9-4c17-9e63-a4f1c07b2d58",
"color": "#69E0C1",
"phaseId": "d71a5c38-6e04-4f9b-a2c7-8b3d0f6e1a95",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"include": [],
"exclude": [],
"recurrence": [
1,
4
],
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"workout": {
"id": "c9f42e60-17b8-4d3a-b5e1-6d0a8c3f9b27",
"name": "Lower body strength",
"isTemplate": true,
"rpe": null,
"userId": null,
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"scheduledWorkoutId": "30e8b6f2-d5a9-4c17-9e63-a4f1c07b2d58",
"completedAt": null,
"startedAt": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"testType": null
}
}
]
}
}Path parameters
iduuidrequired- Resource id.
Notes
- Scheduled workouts whose workout is deleted are left out.
scheduledWorkouts[].workouthas noblocks. Fetch its content withGET /templates/workouts/{id}.
Response fields
scheduledWorkouts[]object[]- Workouts planned in the phase, oldest
createdAtfirst. scheduledWorkouts[].recurrenceinteger[]- Recurrence as stored by the Vitruve planner.
scheduledWorkouts[].includeinteger[]- Occurrences added to the recurrence, as stored by the planner.
scheduledWorkouts[].excludeinteger[]- Occurrences removed from the recurrence, as stored by the planner.
scheduledWorkouts[].workoutobject- The workout row, without blocks.
Failures are described in error codes.
List block templates
Block templates of your organization’s library, newest first, without their content.
Request
curl "https://api-next.vitruve.fit/v1/templates/blocks?limit=20" \
-H "X-API-Key: YOUR_API_KEY"const response = await fetch(
'https://api-next.vitruve.fit/v1/templates/blocks?limit=20',
{ headers: { 'X-API-Key': process.env.VITRUVE_API_KEY } }
)
const body = await response.json()
if (!response.ok) throw new Error(`${response.status}: ${body.message}`)
console.log(body.data)import os
import requests
response = requests.get(
"https://api-next.vitruve.fit/v1/templates/blocks?limit=20",
headers={"X-API-Key": os.environ["VITRUVE_API_KEY"]},
timeout=30,
)
response.raise_for_status()
print(response.json()["data"])Response 200
{
"ok": true,
"timestamp": 1738247125207,
"data": [
{
"id": "6a2f9d14-b8c3-4e70-a5d1-0c7e3b94f826",
"name": "Strength",
"isTemplate": true,
"order": 0,
"workoutId": "41d6e9b3-a8f5-4c07-92e1-d5b0c3a76f84",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null
}
],
"meta": {
"limit": 20,
"hasMore": true,
"nextCursor": "ZTU2M2ZlYzMtM2IxYy00…"
}
}Query parameters
searchstring- Case-insensitive match on the template name.
limitintegerdefault50- Page size, 1–100.
cursorstringmeta.nextCursorfrom the previous page. Omit it to get the first page.
Notes
- Lists return the template rows only, newest
createdAtfirst. Fetch the detail endpoint for the content.
Response fields
iduuid- Template id.
namestring- Template name, as shown in the library.
isTemplateboolean- Always
trueon these endpoints. orderintegernullable- Position inside its parent template.
workoutIduuidnullable- Parent template when this one belongs to a larger template. Resolve with
GET /templates/workouts/{id}.nullfor a standalone template.
Failures are described in error codes.
Get a block template
One block template with its tree: prescription groups → prescriptions → parameters and planned sets.
Request
curl "https://api-next.vitruve.fit/v1/templates/blocks/6a2f9d14-b8c3-4e70-a5d1-0c7e3b94f826" \
-H "X-API-Key: YOUR_API_KEY"const response = await fetch(
'https://api-next.vitruve.fit/v1/templates/blocks/6a2f9d14-b8c3-4e70-a5d1-0c7e3b94f826',
{ headers: { 'X-API-Key': process.env.VITRUVE_API_KEY } }
)
const body = await response.json()
if (!response.ok) throw new Error(`${response.status}: ${body.message}`)
console.log(body.data)import os
import requests
response = requests.get(
"https://api-next.vitruve.fit/v1/templates/blocks/6a2f9d14-b8c3-4e70-a5d1-0c7e3b94f826",
headers={"X-API-Key": os.environ["VITRUVE_API_KEY"]},
timeout=30,
)
response.raise_for_status()
print(response.json()["data"])Response 200
{
"ok": true,
"timestamp": 1738247125207,
"data": {
"id": "6a2f9d14-b8c3-4e70-a5d1-0c7e3b94f826",
"name": "Strength",
"isTemplate": true,
"order": 0,
"workoutId": "41d6e9b3-a8f5-4c07-92e1-d5b0c3a76f84",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"prescriptionsGroups": [
{
"id": "e8b40c7d-5f19-4a26-9d83-2b6a1e0f7c45",
"name": "Main lift",
"isTemplate": true,
"order": 0,
"blockId": "6a2f9d14-b8c3-4e70-a5d1-0c7e3b94f826",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"prescriptions": [
{
"id": "1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"exerciseId": "1c7a5e93-f804-4b26-a9d1-3e6b0d82c4f7",
"prescriptionsGroupId": "e8b40c7d-5f19-4a26-9d83-2b6a1e0f7c45",
"name": "Back squat",
"order": 0,
"note": "Stop the set if mean velocity drops below 0.55 m/s.",
"isTemplate": true,
"isVbt": true,
"trainingType": "vbt",
"trainingAlgorithm": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"seriePrescriptions": [
{
"id": "9d5e2a07-c4b1-4f38-a6e9-71f0d3c8b524",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"prescriptionId": "1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
"prescriptionTypeId": "3e9d7a12-c5b8-4f40-a136-d82e4b6f9c05",
"unitId": "fa52c8d4-17e3-4b69-8d0a-6c3f9e1b2a78",
"order": 0,
"isRange": false,
"isTopMode": false,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null
}
],
"series": [
{
"id": "b2c86f41-03ad-4e95-b7d2-5e18a9c04f63",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"prescriptionId": "1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
"order": 0,
"completedAt": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"serieValues": [
{
"id": "5f03d8b6-e917-4c2a-8b45-c6a2f1e7d390",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"serieId": "b2c86f41-03ad-4e95-b7d2-5e18a9c04f63",
"seriePrescriptionId": "9d5e2a07-c4b1-4f38-a6e9-71f0d3c8b524",
"valuePrescriptedInf": null,
"valuePrescriptedSup": null,
"valuePrescripted": 80,
"valueExecuted": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null
}
],
"metricValues": [],
"repetitions": []
}
]
}
]
}
]
}
}Path parameters
iduuidrequired- Resource id.
Notes
- Same tree as
GET /workouts/{id}, starting at this level. Every nested level excludes deleted rows and is sorted byorder. serieValuesare returned in theunitIdof theirseriePrescriptionId, not in the stored base unit.- In a template,
serieshold the planned values:valueExecutedandcompletedAtarenull, and there are no repetitions or metric values.
Response fields
prescriptionsGroups[]object[]- Prescription groups, in order. More than one prescription in a group is a superset.
prescriptionsGroups[].prescriptions[].seriePrescriptions[].prescriptionTypeIduuid- Parameter type (load, repetitions, velocity…). Resolve with
GET /prescription-types/{id}. prescriptionsGroups[].prescriptions[].seriePrescriptions[].unitIduuid- Unit of the parameter. Resolve with
GET /units/{id}. prescriptionsGroups[].prescriptions[].seriePrescriptions[].isRangebooleannullable- When
true, the planned value isvaluePrescriptedInf–valuePrescriptedSupinstead ofvaluePrescripted. prescriptionsGroups[].prescriptions[].series[]object[]- Planned sets, in order.
prescriptionsGroups[].prescriptions[].series[].serieValues[].seriePrescriptionIduuid- The parameter this value belongs to, in
seriePrescriptions. prescriptionsGroups[].prescriptions[].series[].serieValues[].valuePrescriptednumbernullable- Planned value, in the parameter’s
unitId.
Failures are described in error codes.
List prescription group templates
Prescription group (superset) templates of your organization’s library, newest first, without their content.
Request
curl "https://api-next.vitruve.fit/v1/templates/prescriptions-groups?limit=20" \
-H "X-API-Key: YOUR_API_KEY"const response = await fetch(
'https://api-next.vitruve.fit/v1/templates/prescriptions-groups?limit=20',
{ headers: { 'X-API-Key': process.env.VITRUVE_API_KEY } }
)
const body = await response.json()
if (!response.ok) throw new Error(`${response.status}: ${body.message}`)
console.log(body.data)import os
import requests
response = requests.get(
"https://api-next.vitruve.fit/v1/templates/prescriptions-groups?limit=20",
headers={"X-API-Key": os.environ["VITRUVE_API_KEY"]},
timeout=30,
)
response.raise_for_status()
print(response.json()["data"])Response 200
{
"ok": true,
"timestamp": 1738247125207,
"data": [
{
"id": "e8b40c7d-5f19-4a26-9d83-2b6a1e0f7c45",
"name": "Main lift",
"isTemplate": true,
"order": 0,
"blockId": "6a2f9d14-b8c3-4e70-a5d1-0c7e3b94f826",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null
}
],
"meta": {
"limit": 20,
"hasMore": true,
"nextCursor": "ZTU2M2ZlYzMtM2IxYy00…"
}
}Query parameters
searchstring- Case-insensitive match on the template name.
limitintegerdefault50- Page size, 1–100.
cursorstringmeta.nextCursorfrom the previous page. Omit it to get the first page.
Notes
- Lists return the template rows only, newest
createdAtfirst. Fetch the detail endpoint for the content.
Response fields
iduuid- Template id.
namestring- Template name, as shown in the library.
isTemplateboolean- Always
trueon these endpoints. orderintegernullable- Position inside its parent template.
blockIduuidnullable- Parent template when this one belongs to a larger template. Resolve with
GET /templates/blocks/{id}.nullfor a standalone template.
Failures are described in error codes.
Get a prescription group template
One prescription group template with its prescriptions, their parameters and planned sets.
Request
curl "https://api-next.vitruve.fit/v1/templates/prescriptions-groups/e8b40c7d-5f19-4a26-9d83-2b6a1e0f7c45" \
-H "X-API-Key: YOUR_API_KEY"const response = await fetch(
'https://api-next.vitruve.fit/v1/templates/prescriptions-groups/e8b40c7d-5f19-4a26-9d83-2b6a1e0f7c45',
{ headers: { 'X-API-Key': process.env.VITRUVE_API_KEY } }
)
const body = await response.json()
if (!response.ok) throw new Error(`${response.status}: ${body.message}`)
console.log(body.data)import os
import requests
response = requests.get(
"https://api-next.vitruve.fit/v1/templates/prescriptions-groups/e8b40c7d-5f19-4a26-9d83-2b6a1e0f7c45",
headers={"X-API-Key": os.environ["VITRUVE_API_KEY"]},
timeout=30,
)
response.raise_for_status()
print(response.json()["data"])Response 200
{
"ok": true,
"timestamp": 1738247125207,
"data": {
"id": "e8b40c7d-5f19-4a26-9d83-2b6a1e0f7c45",
"name": "Main lift",
"isTemplate": true,
"order": 0,
"blockId": "6a2f9d14-b8c3-4e70-a5d1-0c7e3b94f826",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"prescriptions": [
{
"id": "1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"exerciseId": "1c7a5e93-f804-4b26-a9d1-3e6b0d82c4f7",
"prescriptionsGroupId": "e8b40c7d-5f19-4a26-9d83-2b6a1e0f7c45",
"name": "Back squat",
"order": 0,
"note": "Stop the set if mean velocity drops below 0.55 m/s.",
"isTemplate": true,
"isVbt": true,
"trainingType": "vbt",
"trainingAlgorithm": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"seriePrescriptions": [
{
"id": "9d5e2a07-c4b1-4f38-a6e9-71f0d3c8b524",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"prescriptionId": "1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
"prescriptionTypeId": "3e9d7a12-c5b8-4f40-a136-d82e4b6f9c05",
"unitId": "fa52c8d4-17e3-4b69-8d0a-6c3f9e1b2a78",
"order": 0,
"isRange": false,
"isTopMode": false,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null
}
],
"series": [
{
"id": "b2c86f41-03ad-4e95-b7d2-5e18a9c04f63",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"prescriptionId": "1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
"order": 0,
"completedAt": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"serieValues": [
{
"id": "5f03d8b6-e917-4c2a-8b45-c6a2f1e7d390",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"serieId": "b2c86f41-03ad-4e95-b7d2-5e18a9c04f63",
"seriePrescriptionId": "9d5e2a07-c4b1-4f38-a6e9-71f0d3c8b524",
"valuePrescriptedInf": null,
"valuePrescriptedSup": null,
"valuePrescripted": 80,
"valueExecuted": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null
}
],
"metricValues": [],
"repetitions": []
}
]
}
]
}
}Path parameters
iduuidrequired- Resource id.
Notes
- Same tree as
GET /workouts/{id}, starting at this level. Every nested level excludes deleted rows and is sorted byorder. serieValuesare returned in theunitIdof theirseriePrescriptionId, not in the stored base unit.- In a template,
serieshold the planned values:valueExecutedandcompletedAtarenull, and there are no repetitions or metric values.
Response fields
prescriptions[]object[]- Prescriptions, in order. More than one is a superset.
prescriptions[].seriePrescriptions[].prescriptionTypeIduuid- Parameter type (load, repetitions, velocity…). Resolve with
GET /prescription-types/{id}. prescriptions[].seriePrescriptions[].unitIduuid- Unit of the parameter. Resolve with
GET /units/{id}. prescriptions[].seriePrescriptions[].isRangebooleannullable- When
true, the planned value isvaluePrescriptedInf–valuePrescriptedSupinstead ofvaluePrescripted. prescriptions[].series[]object[]- Planned sets, in order.
prescriptions[].series[].serieValues[].seriePrescriptionIduuid- The parameter this value belongs to, in
seriePrescriptions. prescriptions[].series[].serieValues[].valuePrescriptednumbernullable- Planned value, in the parameter’s
unitId.
Failures are described in error codes.
List prescription templates
Single-exercise templates of your organization’s library, newest first, without their parameters and sets.
Request
curl "https://api-next.vitruve.fit/v1/templates/prescriptions?search=squat&limit=20" \
-H "X-API-Key: YOUR_API_KEY"const response = await fetch(
'https://api-next.vitruve.fit/v1/templates/prescriptions?search=squat&limit=20',
{ headers: { 'X-API-Key': process.env.VITRUVE_API_KEY } }
)
const body = await response.json()
if (!response.ok) throw new Error(`${response.status}: ${body.message}`)
console.log(body.data)import os
import requests
response = requests.get(
"https://api-next.vitruve.fit/v1/templates/prescriptions?search=squat&limit=20",
headers={"X-API-Key": os.environ["VITRUVE_API_KEY"]},
timeout=30,
)
response.raise_for_status()
print(response.json()["data"])Response 200
{
"ok": true,
"timestamp": 1738247125207,
"data": [
{
"id": "1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"exerciseId": "1c7a5e93-f804-4b26-a9d1-3e6b0d82c4f7",
"prescriptionsGroupId": "e8b40c7d-5f19-4a26-9d83-2b6a1e0f7c45",
"name": "Back squat",
"order": 0,
"note": "Stop the set if mean velocity drops below 0.55 m/s.",
"isTemplate": true,
"isVbt": true,
"trainingType": "vbt",
"trainingAlgorithm": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null
}
],
"meta": {
"limit": 20,
"hasMore": true,
"nextCursor": "ZTU2M2ZlYzMtM2IxYy00…"
}
}Query parameters
searchstring- Case-insensitive match on the template name.
limitintegerdefault50- Page size, 1–100.
cursorstringmeta.nextCursorfrom the previous page. Omit it to get the first page.
Notes
- Lists return the template rows only, newest
createdAtfirst. Fetch the detail endpoint for the content.
Response fields
iduuid- Template id.
namestring- Template name, as shown in the library.
isTemplateboolean- Always
trueon these endpoints. orderintegernullable- Position inside its parent template.
prescriptionsGroupIduuidnullable- Parent template when this one belongs to a larger template. Resolve with
GET /templates/prescriptions-groups/{id}.nullfor a standalone template. exerciseIduuid- Exercise. Resolve with
GET /exercises/{id}. trainingTypestringnullablevbt,jump,sprintorreaction.nullon rows written before the field existed.isVbtbooleannullable- Legacy VBT flag. Read it when
trainingTypeisnull. notestringnullable- Coach note shown to the athlete.
Failures are described in error codes.
Get a prescription template
One single-exercise template with its parameters (seriePrescriptions) and planned sets (series).
Request
curl "https://api-next.vitruve.fit/v1/templates/prescriptions/1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17" \
-H "X-API-Key: YOUR_API_KEY"const response = await fetch(
'https://api-next.vitruve.fit/v1/templates/prescriptions/1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17',
{ headers: { 'X-API-Key': process.env.VITRUVE_API_KEY } }
)
const body = await response.json()
if (!response.ok) throw new Error(`${response.status}: ${body.message}`)
console.log(body.data)import os
import requests
response = requests.get(
"https://api-next.vitruve.fit/v1/templates/prescriptions/1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
headers={"X-API-Key": os.environ["VITRUVE_API_KEY"]},
timeout=30,
)
response.raise_for_status()
print(response.json()["data"])Response 200
{
"ok": true,
"timestamp": 1738247125207,
"data": {
"id": "1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"exerciseId": "1c7a5e93-f804-4b26-a9d1-3e6b0d82c4f7",
"prescriptionsGroupId": "e8b40c7d-5f19-4a26-9d83-2b6a1e0f7c45",
"name": "Back squat",
"order": 0,
"note": "Stop the set if mean velocity drops below 0.55 m/s.",
"isTemplate": true,
"isVbt": true,
"trainingType": "vbt",
"trainingAlgorithm": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"seriePrescriptions": [
{
"id": "9d5e2a07-c4b1-4f38-a6e9-71f0d3c8b524",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"prescriptionId": "1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
"prescriptionTypeId": "3e9d7a12-c5b8-4f40-a136-d82e4b6f9c05",
"unitId": "fa52c8d4-17e3-4b69-8d0a-6c3f9e1b2a78",
"order": 0,
"isRange": false,
"isTopMode": false,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null
}
],
"series": [
{
"id": "b2c86f41-03ad-4e95-b7d2-5e18a9c04f63",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"prescriptionId": "1f7c3e95-a2d8-4b61-8e04-d93b5a2c6f17",
"order": 0,
"completedAt": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null,
"serieValues": [
{
"id": "5f03d8b6-e917-4c2a-8b45-c6a2f1e7d390",
"organizationId": "7d3f8a52-1c0e-4b8e-9f4a-2e6b1d9c5a10",
"serieId": "b2c86f41-03ad-4e95-b7d2-5e18a9c04f63",
"seriePrescriptionId": "9d5e2a07-c4b1-4f38-a6e9-71f0d3c8b524",
"valuePrescriptedInf": null,
"valuePrescriptedSup": null,
"valuePrescripted": 80,
"valueExecuted": null,
"createdAt": "2026-02-11T09:30:00.000Z",
"updatedAt": "2026-02-11T09:30:00.000Z",
"deletedAt": null
}
],
"metricValues": [],
"repetitions": []
}
]
}
}Path parameters
iduuidrequired- Resource id.
Notes
- Same tree as
GET /workouts/{id}, starting at this level. Every nested level excludes deleted rows and is sorted byorder. serieValuesare returned in theunitIdof theirseriePrescriptionId, not in the stored base unit.- In a template,
serieshold the planned values:valueExecutedandcompletedAtarenull, and there are no repetitions or metric values.
Response fields
exerciseIduuid- Exercise. Resolve with
GET /exercises/{id}. trainingTypestringnullablevbt,jump,sprintorreaction.nullon rows written before the field existed.isVbtbooleannullable- Legacy VBT flag. Read it when
trainingTypeisnull. notestringnullable- Coach note shown to the athlete.
seriePrescriptions[].prescriptionTypeIduuid- Parameter type (load, repetitions, velocity…). Resolve with
GET /prescription-types/{id}. seriePrescriptions[].unitIduuid- Unit of the parameter. Resolve with
GET /units/{id}. seriePrescriptions[].isRangebooleannullable- When
true, the planned value isvaluePrescriptedInf–valuePrescriptedSupinstead ofvaluePrescripted. series[]object[]- Planned sets, in order.
series[].serieValues[].seriePrescriptionIduuid- The parameter this value belongs to, in
seriePrescriptions. series[].serieValues[].valuePrescriptednumbernullable- Planned value, in the parameter’s
unitId.
Failures are described in error codes.