Public API reference
Device Weekly APIs
These two read-only endpoints expose the weekly triathlon plan and the rolling daily habits view for a second device. All dates use the Europe/Warsaw day boundary.
Endpoint 1
Triathlon current week
https://discipline.nomoonshots.com/api/triathlon/current-week
Returns the current training week, including week metadata and one entry per day. Workout days contain the full workout object. Rest days contain the rest suggestion.
Top-level fields
today: current date in Warsaw.week_index: zero-based index of the active training week.start_dateandend_date: current week boundaries.phaseandfocus: summary of the training block.days: seven day records for the current week.
Day object fields
date,dow,status,phase,is_today.workoutis present only for workout days.rest_suggestionis present only for rest days.workoutincludes title, duration, intensity, segments, substitutions, and equipment data.
Example response
Open endpoint{
"today": "2026-04-26",
"week_index": 7,
"start_date": "2026-04-20",
"end_date": "2026-04-26",
"phase": "Tri base → build",
"focus": "More race-effort bike; optional tempo run.",
"days": [
{
"date": "2026-04-20",
"dow": "Monday",
"status": "rest",
"phase": "Tri base → build",
"is_today": false,
"rest_suggestion": "Optional mobility + easy walk; rest if you feel beat up."
},
{
"date": "2026-04-21",
"dow": "Tuesday",
"status": "workout",
"phase": "Tri base → build",
"is_today": false,
"workout": {
"type": [
"swim"
],
"title": "Pool swim: aerobic development + pacing",
"duration_min": 45,
"intensity_overall": {
"rpe": "2-6",
"zones": "Mostly Z1-Z3"
},
"segments": [
{
"name": "Warm-up",
"duration_min": 8,
"details": "300m easy + 4×25m build, 15s rest"
},
{
"name": "Drills",
"duration_min": 8,
"details": "4×50m drill/swim, 20s rest"
},
{
"name": "Main set",
"duration_min": 22,
"details": "8×100m steady, 20–25s rest. Negative split last 2 reps."
},
{
"name": "Cool-down",
"duration_min": 7,
"details": "200m easy"
}
],
"target_volume": "1400-1800m",
"substitution_ids": [
"swim_no_access"
],
"equipment_group_ids": [
"swim"
]
}
},
{
"date": "2026-04-22",
"dow": "Wednesday",
"status": "rest",
"phase": "Tri base → build",
"is_today": false,
"rest_suggestion": "Optional mobility + easy walk; rest if you feel beat up."
},
{
"date": "2026-04-23",
"dow": "Thursday",
"status": "workout",
"phase": "Tri base → build",
"is_today": false,
"workout": {
"type": [
"bike",
"run_brick"
],
"title": "Bike: tempo development + brick",
"duration_min": 45,
"intensity_overall": {
"rpe": "2-8",
"zones": "Mostly Z1-Z3; quality reps Z4-Z5 when scheduled"
},
"segments": [
{
"name": "Warm-up",
"duration_min": 8,
"details": "Easy spin + 2×20s fast legs"
},
{
"name": "Main set",
"duration_min": 22,
"details": "3×5 min tempo/race-effort (RPE 6–7) / 2 min easy"
},
{
"name": "Brick run",
"duration_min": 10,
"details": "Easy jog; focus on relaxed cadence"
},
{
"name": "Cool-down",
"duration_min": 5,
"details": "Easy spin/walk"
}
],
"substitution_ids": [
"bike_bad_weather",
"run_bad_weather"
],
"equipment_group_ids": [
"bike",
"run"
]
}
},
{
"date": "2026-04-24",
"dow": "Friday",
"status": "rest",
"phase": "Tri base → build",
"is_today": false,
"rest_suggestion": "Optional mobility + easy walk; rest if you feel beat up."
},
{
"date": "2026-04-25",
"dow": "Saturday",
"status": "workout",
"phase": "Tri base → build",
"is_today": false,
"workout": {
"type": [
"bike"
],
"title": "Bike: endurance + race-effort blocks",
"duration_min": 75,
"intensity_overall": {
"rpe": "2-8",
"zones": "Mostly Z2; controlled Z3-Z4 blocks; brief Z5 surges when scheduled"
},
"segments": [
{
"name": "Warm-up",
"duration_min": 10,
"details": "Easy spin"
},
{
"name": "Main set",
"duration_min": 55,
"details": "3×10 min at steady race effort (RPE 6–7) / 3 min easy; remainder Z2"
},
{
"name": "Cool-down",
"duration_min": 10,
"details": "Easy spin"
}
],
"substitution_ids": [
"bike_bad_weather"
],
"equipment_group_ids": [
"bike"
]
}
},
{
"date": "2026-04-26",
"dow": "Sunday",
"status": "workout",
"phase": "Tri base → build",
"is_today": true,
"workout": {
"type": [
"run",
"strength"
],
"title": "Run: tempo option + strength B",
"duration_min": 75,
"intensity_overall": {
"rpe": "2-7",
"zones": "Mostly Z2; tempo segments Z3-Z4 when scheduled"
},
"segments": [
{
"name": "Warm-up",
"duration_min": 12,
"details": "Easy jog"
},
{
"name": "Tempo blocks",
"duration_min": 24,
"details": "2×10 min tempo (RPE 6) / 3 min easy"
},
{
"name": "Easy",
"duration_min": 19,
"details": "Easy jog"
},
{
"name": "Strength block B",
"duration_min": 20,
"details": "See strength_exercises list; keep 1–2 reps in reserve (no grinding)."
}
],
"substitution_ids": [
"run_bad_weather"
],
"equipment_group_ids": [
"gym",
"run"
],
"strength": {
"block_id": "B",
"sets_rule": "meta.strength_blocks.progression"
}
}
}
]
}
Endpoint 2
Daily habits weekly window
https://discipline.nomoonshots.com/api/daily-habits/weekly
Returns a rolling 7-day window that includes today and the previous 6 calendar days. The payload includes stable task definitions plus per-day summaries and per-task completion state.
Top-level fields
today,start_date,end_date: date range for the window.tasks: ordered task definitions shared across all days.days: seven day records in ascending date order.
Day object fields
modeandmode_locked: standard vs minimum-day state.required_count,completed_count,day_complete.planned_minutesandcompleted_minutes: computed using the day mode.tasks: per-task entries with explicitcompletedstatus andminutes_for_day_mode.
Minimum mode rule: the required count is
min(3, task_count). If no day mode row exists, the API defaults to standard and unlocked.
Example response
Open endpoint{
"today": "2026-04-26",
"start_date": "2026-04-20",
"end_date": "2026-04-26",
"tasks": [
{
"id": 1,
"slug": "shipped-proof-unit",
"label": "Marketing - 100days experiment added",
"position": 1,
"target_minutes": 20,
"minimum_target_minutes": 10
},
{
"id": 2,
"slug": "sales-outbound",
"label": "Sales - 30 DMs",
"position": 2,
"target_minutes": 60,
"minimum_target_minutes": 20
},
{
"id": 3,
"slug": "social-replies",
"label": "Social - 30 replies",
"position": 3,
"target_minutes": 45,
"minimum_target_minutes": 15
},
{
"id": 4,
"slug": "job-applications",
"label": "Job Search - 3 application",
"position": 4,
"target_minutes": 45,
"minimum_target_minutes": 20
},
{
"id": 5,
"slug": "course-progress",
"label": "Course - 30 minutes on a new chapter",
"position": 5,
"target_minutes": 30,
"minimum_target_minutes": 15
},
{
"id": 6,
"slug": "marketing-build-post",
"label": "Build in Public - summary post of the day",
"position": 6,
"target_minutes": 15,
"minimum_target_minutes": 10
}
],
"days": [
{
"date": "2026-04-20",
"is_today": false,
"mode": "standard",
"mode_locked": false,
"required_count": 6,
"completed_count": 0,
"planned_minutes": 215,
"completed_minutes": 0,
"day_complete": false,
"tasks": [
{
"task_id": 1,
"slug": "shipped-proof-unit",
"label": "Marketing - 100days experiment added",
"completed": false,
"target_minutes": 20,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 20
},
{
"task_id": 2,
"slug": "sales-outbound",
"label": "Sales - 30 DMs",
"completed": false,
"target_minutes": 60,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 60
},
{
"task_id": 3,
"slug": "social-replies",
"label": "Social - 30 replies",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 45
},
{
"task_id": 4,
"slug": "job-applications",
"label": "Job Search - 3 application",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 45
},
{
"task_id": 5,
"slug": "course-progress",
"label": "Course - 30 minutes on a new chapter",
"completed": false,
"target_minutes": 30,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 30
},
{
"task_id": 6,
"slug": "marketing-build-post",
"label": "Build in Public - summary post of the day",
"completed": false,
"target_minutes": 15,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 15
}
]
},
{
"date": "2026-04-21",
"is_today": false,
"mode": "standard",
"mode_locked": false,
"required_count": 6,
"completed_count": 0,
"planned_minutes": 215,
"completed_minutes": 0,
"day_complete": false,
"tasks": [
{
"task_id": 1,
"slug": "shipped-proof-unit",
"label": "Marketing - 100days experiment added",
"completed": false,
"target_minutes": 20,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 20
},
{
"task_id": 2,
"slug": "sales-outbound",
"label": "Sales - 30 DMs",
"completed": false,
"target_minutes": 60,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 60
},
{
"task_id": 3,
"slug": "social-replies",
"label": "Social - 30 replies",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 45
},
{
"task_id": 4,
"slug": "job-applications",
"label": "Job Search - 3 application",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 45
},
{
"task_id": 5,
"slug": "course-progress",
"label": "Course - 30 minutes on a new chapter",
"completed": false,
"target_minutes": 30,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 30
},
{
"task_id": 6,
"slug": "marketing-build-post",
"label": "Build in Public - summary post of the day",
"completed": false,
"target_minutes": 15,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 15
}
]
},
{
"date": "2026-04-22",
"is_today": false,
"mode": "standard",
"mode_locked": false,
"required_count": 6,
"completed_count": 0,
"planned_minutes": 215,
"completed_minutes": 0,
"day_complete": false,
"tasks": [
{
"task_id": 1,
"slug": "shipped-proof-unit",
"label": "Marketing - 100days experiment added",
"completed": false,
"target_minutes": 20,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 20
},
{
"task_id": 2,
"slug": "sales-outbound",
"label": "Sales - 30 DMs",
"completed": false,
"target_minutes": 60,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 60
},
{
"task_id": 3,
"slug": "social-replies",
"label": "Social - 30 replies",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 45
},
{
"task_id": 4,
"slug": "job-applications",
"label": "Job Search - 3 application",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 45
},
{
"task_id": 5,
"slug": "course-progress",
"label": "Course - 30 minutes on a new chapter",
"completed": false,
"target_minutes": 30,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 30
},
{
"task_id": 6,
"slug": "marketing-build-post",
"label": "Build in Public - summary post of the day",
"completed": false,
"target_minutes": 15,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 15
}
]
},
{
"date": "2026-04-23",
"is_today": false,
"mode": "standard",
"mode_locked": false,
"required_count": 6,
"completed_count": 0,
"planned_minutes": 215,
"completed_minutes": 0,
"day_complete": false,
"tasks": [
{
"task_id": 1,
"slug": "shipped-proof-unit",
"label": "Marketing - 100days experiment added",
"completed": false,
"target_minutes": 20,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 20
},
{
"task_id": 2,
"slug": "sales-outbound",
"label": "Sales - 30 DMs",
"completed": false,
"target_minutes": 60,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 60
},
{
"task_id": 3,
"slug": "social-replies",
"label": "Social - 30 replies",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 45
},
{
"task_id": 4,
"slug": "job-applications",
"label": "Job Search - 3 application",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 45
},
{
"task_id": 5,
"slug": "course-progress",
"label": "Course - 30 minutes on a new chapter",
"completed": false,
"target_minutes": 30,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 30
},
{
"task_id": 6,
"slug": "marketing-build-post",
"label": "Build in Public - summary post of the day",
"completed": false,
"target_minutes": 15,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 15
}
]
},
{
"date": "2026-04-24",
"is_today": false,
"mode": "standard",
"mode_locked": false,
"required_count": 6,
"completed_count": 0,
"planned_minutes": 215,
"completed_minutes": 0,
"day_complete": false,
"tasks": [
{
"task_id": 1,
"slug": "shipped-proof-unit",
"label": "Marketing - 100days experiment added",
"completed": false,
"target_minutes": 20,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 20
},
{
"task_id": 2,
"slug": "sales-outbound",
"label": "Sales - 30 DMs",
"completed": false,
"target_minutes": 60,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 60
},
{
"task_id": 3,
"slug": "social-replies",
"label": "Social - 30 replies",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 45
},
{
"task_id": 4,
"slug": "job-applications",
"label": "Job Search - 3 application",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 45
},
{
"task_id": 5,
"slug": "course-progress",
"label": "Course - 30 minutes on a new chapter",
"completed": false,
"target_minutes": 30,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 30
},
{
"task_id": 6,
"slug": "marketing-build-post",
"label": "Build in Public - summary post of the day",
"completed": false,
"target_minutes": 15,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 15
}
]
},
{
"date": "2026-04-25",
"is_today": false,
"mode": "standard",
"mode_locked": false,
"required_count": 6,
"completed_count": 0,
"planned_minutes": 215,
"completed_minutes": 0,
"day_complete": false,
"tasks": [
{
"task_id": 1,
"slug": "shipped-proof-unit",
"label": "Marketing - 100days experiment added",
"completed": false,
"target_minutes": 20,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 20
},
{
"task_id": 2,
"slug": "sales-outbound",
"label": "Sales - 30 DMs",
"completed": false,
"target_minutes": 60,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 60
},
{
"task_id": 3,
"slug": "social-replies",
"label": "Social - 30 replies",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 45
},
{
"task_id": 4,
"slug": "job-applications",
"label": "Job Search - 3 application",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 45
},
{
"task_id": 5,
"slug": "course-progress",
"label": "Course - 30 minutes on a new chapter",
"completed": false,
"target_minutes": 30,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 30
},
{
"task_id": 6,
"slug": "marketing-build-post",
"label": "Build in Public - summary post of the day",
"completed": false,
"target_minutes": 15,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 15
}
]
},
{
"date": "2026-04-26",
"is_today": true,
"mode": "standard",
"mode_locked": false,
"required_count": 6,
"completed_count": 0,
"planned_minutes": 215,
"completed_minutes": 0,
"day_complete": false,
"tasks": [
{
"task_id": 1,
"slug": "shipped-proof-unit",
"label": "Marketing - 100days experiment added",
"completed": false,
"target_minutes": 20,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 20
},
{
"task_id": 2,
"slug": "sales-outbound",
"label": "Sales - 30 DMs",
"completed": false,
"target_minutes": 60,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 60
},
{
"task_id": 3,
"slug": "social-replies",
"label": "Social - 30 replies",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 45
},
{
"task_id": 4,
"slug": "job-applications",
"label": "Job Search - 3 application",
"completed": false,
"target_minutes": 45,
"minimum_target_minutes": 20,
"minutes_for_day_mode": 45
},
{
"task_id": 5,
"slug": "course-progress",
"label": "Course - 30 minutes on a new chapter",
"completed": false,
"target_minutes": 30,
"minimum_target_minutes": 15,
"minutes_for_day_mode": 30
},
{
"task_id": 6,
"slug": "marketing-build-post",
"label": "Build in Public - summary post of the day",
"completed": false,
"target_minutes": 15,
"minimum_target_minutes": 10,
"minutes_for_day_mode": 15
}
]
}
]
}