# VéloPeak > VéloPeak is a virtual cycling coach powered by AI. It builds a periodized training plan around your races, analyses every activity you sync, and adapts the plan when life gets in the way. Available on the web and as iOS and Android apps, in English, Brazilian Portuguese and European Portuguese. VéloPeak is built for amateur and competitive amateur cyclists. Cycling is the core sport; runs and swims also count toward the athlete's Load, Fatigue and Form. An athlete's data is private by default; they choose what to share (single-activity links, authorized apps). Key features: - Periodized plans: every A race gets its own base, build, peak and taper cycle. - Workout alternatives: swap any session for a similar, easier, harder, longer or shorter one, rebuilt around the athlete's FTP. - Fitness, Fatigue and Form recomputed after every synced activity. - Daily Energy score from heart rate variability, resting heart rate and sleep (Apple Health, Health Connect). - Analysis of every activity and unlimited chat with the virtual coach, in the app, on WhatsApp or on Telegram. - Live workouts with Bluetooth sensors in the mobile app. Metric names used by VéloPeak: Load (TLS), Fitness (CLS), Fatigue (ALS), Form (LBI), Intensity (TIR), Weighted Power (WP), FTP. Pricing: one plan with everything included, 15-day free trial, cancel anytime. Prices: €14.99/month or €161.89/year; R$69.90/month or R$754.92/year. Connections: - Activity sync: Strava, Intervals.icu, Wahoo and Polar (direct). Garmin, MyWhoosh and other devices or apps reach VéloPeak through Intervals.icu or Strava. Athletes can also import a .FIT file, and workouts recorded in the mobile app sync automatically. - Planned workouts sent to: Wahoo (direct) and Intervals.icu, from where they reach Garmin and MyWhoosh. - Health data: Apple Health (iOS), Health Connect (Android), with Intervals.icu wellness filling gaps. - Coach channels: WhatsApp, Telegram. Mobile apps: [App Store (iOS)](https://apps.apple.com/app/id6792008109) and [Google Play (Android)](https://play.google.com/store/apps/details?id=com.velopeakapp). Website: https://velo-peak.com Contact: - Support email: support@velo-peak.com - Contact form: https://velo-peak.com/en/contact - Legal entity: VÉLO TECHNOLOGY, UNIPESSOAL LDA (Sociedade Unipessoal por Quotas) - Tax ID (NIPC): 518257754 - Share capital: 1.000,00 EUR - Registered office: Praceta José Luís Nunes, nº 104, CY, Paranhos, 4200-605 Porto, Portugal - Legal representative: Getúlio Strapazzon (Founder) --- Source: https://velo-peak.com/en/wiki/about # About VéloPeak > Learn who we are, why we built VéloPeak, and what drives us. VéloPeak is an AI-powered cycling coaching platform built for everyday cyclists who want to train smarter, without needing a personal coach or a sports science degree. We believe that the gap between amateur and elite cycling has never been about talent. It has always been about access to the right information, at the right time. VéloPeak exists to close that gap. ## Our story It started with a personal problem. Our founder is a cycling enthusiast who trains indoors during the week and rides outdoors on weekends. Like most amateur cyclists, he wanted to improve, but the tools available were either too complex, too expensive, or built for professionals. Generic training plans ignored his actual fitness data. Coaching apps required manual input and expensive monthly fees with a human coach. So he did what any engineer would do: he built his own solution. The first version was not an app. It was an AI agent: a personal script that would read his activity data from Strava and Intervals.icu, analyse his fitness metrics, and generate a personalised weekly training plan automatically. No manual input. No subscriptions. Just data-driven training, tailored to his schedule and goals. It worked. Better than expected. After a few months of riding with AI-generated plans, the question became impossible to ignore: > *"Why should only I have access to this?"* That question became VéloPeak. ## What we are building VéloPeak is the coaching tool we always wished existed, with professional-grade coaching depth and the simplicity of an app anyone can use on day one. We integrate with the tools cyclists already use (Strava, Intervals.icu, Wahoo, Garmin) and layer AI coaching on top: automatic activity analysis, personalised training plans, fitness tracking, and actionable weekly summaries. No manual input. No sports science jargon. Just better riding. --- Source: https://velo-peak.com/en/wiki/mission # Our Mission > The mission and purpose behind VéloPeak — why we exist and what we are working towards. ## Mission **Make AI cycling coaching accessible to every cyclist — from the first pedal stroke to the podium.** We believe performance should not be gated behind expensive coaches or overly complex tools. Every cyclist, regardless of level or budget, deserves access to intelligent, personalised coaching that adapts to their life. ## Why it matters The sports science behind elite cycling performance is not secret. The principles are well understood: progressive overload, recovery, zone-based training, aerobic development, VO2 max improvement. What has been missing is a tool that applies these principles automatically — without requiring the athlete to become a sports scientist themselves. VéloPeak is that tool. By connecting your existing data (Strava activities, fitness metrics, device integrations) and applying AI reasoning on top, VéloPeak acts as the coach that is always available, always up to date with your actual fitness, and never gives you a generic plan. ## What success looks like We know we are doing our job when: - A cyclist who never had a training plan starts seeing measurable improvement in their FTP and VO2 Max within weeks - Someone who used to guess at their training intensity now rides every session with purpose - Athletes who could not afford a personal coach have access to a level of coaching insight that was previously reserved for professionals That is the standard we hold ourselves to. Not features shipped. Not users acquired. Real improvement, on real bikes, for real people. --- Source: https://velo-peak.com/en/wiki/values # Our Values > The principles that guide how we build VéloPeak and how we work. These are not aspirational statements written for a pitch deck. They are the principles we apply every day when deciding what to build, what to cut, and how to treat the people who use VéloPeak. ## Simplicity first Every feature we build starts with one question: *can a cyclist who has never used a coaching tool understand this in under 10 seconds?* If the answer is no, it is not ready. Complexity is the enemy of adoption. The best coaching tool is the one people actually use — every week, not just when they remember to log in. ## Data in service of the athlete We have access to a lot of data. Power curves, heart rate variability, training load, Fitness, Fatigue, Form. The temptation is to surface all of it and let the user figure it out. We resist that temptation. Numbers exist to drive better decisions, not to impress. VéloPeak translates data into guidance — clear, actionable, human. ## Built by cyclists, for cyclists Every feature in VéloPeak was born from a real need felt on a real ride. We do not build from assumptions or market research alone. We build from experience — and we test everything the same way a cyclist tests their fitness: by riding. ## AI with purpose AI is not a feature. It is the foundation. But AI without purpose produces noise, not coaching. Every AI interaction in VéloPeak has a job: analyse this activity, generate this plan, explain this metric. We do not use AI to make things look smart. We use it to make athletes ride better. ## Continuous improvement The best version of VéloPeak does not exist yet. Neither does the best version of any athlete using it. That is not a problem — that is the point. We ship, we learn, we improve. Just like training: consistent effort over time compounds into results. --- Source: https://velo-peak.com/en/wiki/team # Our Team > Meet the people behind VéloPeak. ![Getúlio Strapazzon](https://velo-peak.com/team/founder.jpg) ## Getúlio Strapazzon **Founder & CEO** [LinkedIn](https://www.linkedin.com/in/strapazzon) · [GitHub](https://github.com/Strapazzon) Software engineer and cycling enthusiast who built VéloPeak to solve his own training problem. Over a decade of experience in full stack development and AI. Leads product, engineering, and strategy. Getúlio started VéloPeak as a personal AI agent that read his activity data from Strava and Intervals.icu, analysed his fitness metrics, and generated a weekly training plan on its own. What started as a side project became the platform you see today. He's responsible for the entire technical stack, from the AI coaching engine and fitness analytics to integrations with Strava, Garmin, Wahoo, and other cycling platforms. --- Source: https://velo-peak.com/en/wiki/fitness-metrics # Fitness Metrics > Understand every metric on your VéloPeak dashboard and how to use them to train smarter. VéloPeak tracks a set of key numbers that tell you how your body is adapting to training and what you're capable of. They all start from **Load** (TLS, Training Load Score) — a measure of how hard each workout was relative to your FTP. --- ## Fitness **Fitness** (CLS, Chronic Load Score) — a 42-day exponential moving average of your daily Load. Think of it as your long-term fitness base. It rises when you train consistently over weeks and months, and drops when you rest or reduce volume. A higher Fitness means your body is adapted to absorbing more work. > A Fitness of 50–70 is typical for an amateur rider training 8–10h per week. Elite amateurs often sit at 80–100+. --- ## Fatigue **Fatigue** (ALS, Acute Load Score) — a 7-day exponential moving average of your daily Load. This reflects how tired you are *right now*. After a big training block, Fatigue spikes. After a rest day it drops quickly. Fatigue always reacts faster than Fitness because of the shorter time constant. --- ## Form **Form** (LBI, Load Balance Index) — simply **Fitness minus Fatigue**. This is the number that tells you whether you're ready to perform: | Form | What it means | | --- | --- | | **> +5** | Fresh — rested and ready to race or test | | **-10 to +5** | Neutral — good for quality training | | **-30 to -10** | Fatigued — productive overload zone | | **< -30** | Overreached — risk of illness or injury | A negative Form isn't bad — it's expected during hard training blocks. The goal is to manage it: go deep during build phases, then taper to bring Form positive before key events. --- ## FTP **Functional Threshold Power** — the highest average power you can sustain for approximately one hour, measured in watts (W). FTP is the foundation of all training zones and every calculation on this dashboard. It is used to: - Define your 7 power zones (Z1–Z7) - Calculate Load for each activity - Derive W/kg and estimated VO₂ Max You can update your FTP in **Settings > Profile** after a ramp test, 20-minute test, or by asking your coach. --- ## W/kg **Power-to-Weight Ratio** — your FTP divided by your body weight in kilograms. ``` W/kg = FTP (watts) ÷ Weight (kg) ``` This is the single most important metric for climbing and overall cycling performance. Two riders with the same FTP will climb at very different speeds if their weights differ. | W/kg | Level | | --- | --- | | < 2.0 | Beginner | | 2.0 – 3.0 | Recreational | | 3.0 – 3.5 | Sportive / Gran Fondo | | 3.5 – 4.0 | Club racer | | 4.0 – 5.0 | Amateur racer | | > 5.0 | Elite / Professional | --- ## VO₂ Max (estimated) **Maximal Oxygen Uptake** — the maximum rate at which your body can consume oxygen during intense exercise, expressed in ml/kg/min. VéloPeak estimates your VO₂ Max from FTP and weight using the **Coggan formula**: ``` VO₂ Max (est.) = (W/kg × 10.8) + 7 ``` This is an estimate — a lab VO₂ Max test is more accurate — but it provides a useful benchmark to track progress over time. | VO₂ Max | Level | | --- | --- | | < 35 | Beginner | | 35 – 45 | Recreational | | 45 – 55 | Trained | | 55 – 65 | Well-trained | | > 65 | Elite | As your FTP improves relative to your weight, your estimated VO₂ Max will rise. --- ## Load (week) **Weekly Load** — the sum of Load (TLS, Training Load Score) from all activities in the last 7 days. This gives you a quick view of your current weekly training load: | Weekly Load | Typical volume | | --- | --- | | < 150 | Low (maintenance) | | 150 – 300 | Moderate (base training) | | 300 – 500 | High (structured build) | | > 500 | Very high (race prep / overload) | Use this alongside Fatigue and Form to decide whether to add intensity or back off. --- ## How VéloPeak calculates these values 1. Every time you sync your Strava activities, VéloPeak calculates a **Load** value for each workout using your FTP and Weighted Power (WP). 2. Activities are grouped by day (multiple workouts on the same day are summed). 3. The Fitness and Fatigue exponential moving averages are computed across your full activity history. 4. The result is stored as a daily snapshot and shown on your dashboard. 5. W/kg and VO₂ Max are derived in real-time from your profile FTP and weight. The more history you have synced, the more accurate the numbers will be. --- ## Tips - **Before a race:** aim for Form between +5 and +20 — fit but fresh. - **After a big week:** a Form of -20 to -30 is normal. Don't panic. - **Grow Fitness slowly:** 3–5 points per week max to avoid injury. - **Track W/kg over months:** a rising W/kg (without gaining weight) confirms real fitness gains. - **VO₂ Max plateaus:** once you're above 50, gains come from consistency and high-intensity work over years, not weeks. --- ## Body and Health Metrics Weight, body fat, HRV, heart rate, critical power, W', and pace thresholds are tracked separately as Input Metrics. [View the Input Metrics guide](https://velo-peak.com/en/wiki/input-metrics) ### VO2 Max - Measured vs Estimated If you have a lab-measured VO2 Max value less than 60 days old, VeloPeak uses that instead of the Coggan estimate. Your dashboard shows the source. --- Source: https://velo-peak.com/en/wiki/training-intensity # Training Intensity & Load > How the plan builder sets your intensity, spaces your hard days, and aims at a fitness target for your event. When you build a plan, VéloPeak makes a few choices for you and leaves a few to you. This page explains the ones on the "Schedule & intensity" step: how aggressively the plan builds, what a hard day is, how much you ride, and what the fitness target means. You never have to leave the screen to understand a control, but here is the full picture. --- ## Intensity adjustment Your weekly volume is set automatically from periodization tables. The intensity adjustment is a separate dial: it sets how fast your fitness climbs each week, measured as the **Fitness ramp** (Fitness points gained per week). - **Conservative:** about 3 points per week. Best when you are returning from a break, carrying life stress, or injury-prone. - **Moderate:** about 4 points per week. - **Balanced:** about 5 points per week. The standard choice for most trained athletes across a season. - **Demanding:** about 6 points per week. For athletes with good recovery and training experience. - **Aggressive:** about 8 points per week. Maximum load, suitable only for short blocks. Expect high fatigue and a higher injury risk. The same dial also decides where in the target fitness band your plan aims (see target Fitness below): Conservative aims low in the band, Aggressive aims at the top. Faster gains are not free. A steeper ramp means more accumulated fatigue, so pick the level your recovery can actually absorb. --- ## Hard and easy days Each weekday you train is one of three kinds: - **Structured:** a prescribed session with a target effort, for example 4x8 minutes at threshold. The plan writes the workout for you. - **Free ride:** an unstructured ride you do however you like. The plan counts it as endurance and leaves the content to you. - **High intensity:** your single hardest structured day of the week. You can pin one day as this; it cannot be the long ride. Fitness is built by stress followed by recovery, not by stress alone. So the plan alternates hard and easy: it never puts two hard days back to back, and it keeps the day after a hard day, a free ride, or the long ride easy so you absorb the work instead of digging a hole. The long ride and free rides are never downgraded, and if you pin a high-intensity day the plan protects it by easing the day before. This is why a day you marked hard can end up easy in your plan: the rhythm comes first. --- ## Weekly volume Volume comes from your **annual training hours**, which the plan estimates from your recent history or from the experience tier you pick. Annual hours feed the periodization tables that set each week's target hours and its Load ceiling, which then get distributed across your training days. Typical ranges by experience: - **Beginner:** around 300 hours per year. - **Sport (recreational):** around 425 hours per year. - **Advanced:** around 600 hours per year. - **Expert:** around 800 hours per year. - **Elite:** around 1050 hours per year. You can adjust the weekly number directly. The plan never exceeds the weekly Load ceiling for your volume, reducing intensity on quality days first if a week would run over. --- ## Target Fitness Fitness (CLS, Chronic Load Score) is your fitness base: a 42-day average of daily Load. For a race objective, the plan sets a **target Fitness** for race day, drawn from a reference band for that kind of event, and the meter shows where your plan is projected to leave you against that target. Where in the band you aim is set by the intensity adjustment, and each athlete level has a recommended ceiling within it. If your target sits above the ceiling for your level, the plan still lets you proceed but flags it: the projected fitness exceeds the typical range for your level, so watch your fatigue closely and back off if form drops. --- Source: https://velo-peak.com/en/wiki/input-metrics # Input Metrics > Every metric you can log in VeloPeak — what it means, how to measure it, and how your coach uses it. These are the numbers you enter manually in VeloPeak. Together they give your AI coach the context to calibrate training zones, model your race capacity, and flag recovery issues before they become injuries. --- ## Weight Body mass in kg. Used to compute W/kg (power-to-weight ratio) and estimated VO2 Max. Log after waking, before eating, for consistency. Tracking trends over months is more useful than any single reading. **Impact:** W/kg, VO2 Max estimate, athlete classification --- ## Body Fat Percentage of body mass that is fat tissue. Measured via DEXA scan, bioimpedance scale (BIA), or skin calipers. BIA scales give consistent readings when measured at the same time and hydration state each day. | Body Fat | Men | Women | | --- | --- | --- | | Athletic | 6-13% | 14-20% | | Fit | 14-17% | 21-24% | | Average | 18-24% | 25-31% | **Impact:** Body composition tracking, context for W/kg changes --- ## HRV Heart Rate Variability - the millisecond-level variation between successive heartbeats. More variation means a healthier autonomic nervous system and better recovery. Measure on waking, lying down, before coffee. Apps: HRV4Training, Elite HRV, Garmin morning report. Trends matter more than absolute values. A reading 10-15% below your personal baseline indicates moderate fatigue. Greater than 15% below baseline indicates high fatigue. **Impact:** Coach readiness assessment --- ## Max Heart Rate The highest heart rate you have ever reached during maximal effort. Defines all HR-based training zones. Auto-updated from your activity data when a new maximum is observed. Estimation formula (Tanaka): 208 - (0.7 x age). Direct measurement is always more accurate. **Impact:** All 5 HR training zones --- ## Resting Heart Rate HR measured at complete rest, ideally lying down on waking before getting up. A chronically elevated resting HR (more than 5-10 bpm above your norm) is an early signal of overtraining, illness, or poor sleep. | Resting HR | Level | | --- | --- | | Less than 40 bpm | Elite | | 40-50 bpm | Highly trained | | 50-60 bpm | Fit | | 60-80 bpm | Average | | More than 80 bpm | Below average / fatigued | **Impact:** Recovery monitoring, coach readiness signals --- ## FTP **Functional Threshold Power** — the highest average power you can sustain for approximately one hour, measured in watts (W). The single most important number in cycling training. FTP defines all 7 power training zones, calculates Load for every activity, and determines your W/kg ratio. Update it in **Settings > Profile** after any structured test. How to measure: - **Ramp test:** 1-minute incremental steps to failure — use 75% of peak minute power - **20-minute test:** all-out 20-minute effort — use 95% of average power - **60-minute TT:** average power from a maximal 1-hour effort (direct measurement) | FTP (W/kg) | Level | | --- | --- | | Less than 2.0 | Beginner | | 2.0 – 3.0 | Recreational | | 3.0 – 3.5 | Sportive | | 3.5 – 4.0 | Club racer | | 4.0 – 5.0 | Amateur racer | | Greater than 5.0 | Elite / Professional | **Impact:** All 7 power training zones, Load calculation, W/kg, VO2 Max estimate --- ## Critical Power The highest power output you can sustain aerobically without accumulating fatigue - the asymptote of your power-duration curve. Derived mathematically from your MMP data (5-minute and 20-minute best powers). VeloPeak calculates this automatically after every activity that improves your power curve. ``` P(t) = CP + W'/t ``` CP is typically 2-5% higher than FTP. **Impact:** W' calculation, CP+W' anaerobic model, race tactics --- ## W-Prime Your anaerobic energy reserve above Critical Power, measured in kilojoules (kJ). Often written as W' (W-prime). Like a rechargeable battery: depletes when you ride above CP (sprints, attacks, climbs), recharges when you ride below CP. **Example:** CP = 280 W, W' = 20 kJ. You can ride at 380 W (100 W above CP) for exactly 200 seconds before exhausting W'. At 480 W (200 W above CP), only 100 seconds. | W' | Rider type | | --- | --- | | Less than 15 kJ | Pure climber / diesel | | 15-22 kJ | All-rounder | | 22-30 kJ | Punchy / criterium specialist | | Greater than 30 kJ | Sprinter / track | **How it is calculated.** VeloPeak derives W' automatically from your MMP (Maximal Mean Power) data using the 2-parameter Critical Power model `P(t) = CP + W'/t`. Using your best 5-minute (P300) and 20-minute (P1200) power values: ``` W' = (P300 - P1200) x 400 [Joules, divided by 1000 for kJ] CP = P1200 - W'/1200 [Watts] ``` To keep your W' estimate fresh, do hard maximal efforts in the 3 to 8 minute range periodically. Stale 5-minute or 20-minute bests yield a stale W'. **How it influences your training.** W' represents the size of your anaerobic tank and shapes how your coach designs sessions: - VO2max work (3 to 8 minute intervals above CP) directly stresses and grows W' - Anaerobic capacity work (15 to 60 second all-out repeats) develops the top end of W' depletion - Sweet-spot and tempo sessions train CP rather than W', preserving the reserve In races and group rides, W' is what lets you follow attacks, sprint for primes, and recover between efforts. A higher W' means more tolerance for repeated surges. A lower W' means you must ride more conservatively and rely on aerobic durability. **Impact:** Sprint capacity, race tactics, ability to follow attacks and recover --- ## Threshold Heart Rate Heart rate at FTP / lactate threshold intensity. Used to calibrate heart rate zones when power data is unavailable. Best measured during a 20-minute all-out effort or a structured threshold test. **Impact:** HR-based training zones for threshold sessions --- ## Running Threshold Pace Your maximum sustainable running pace for approximately 60 minutes - the running equivalent of FTP. Usually measured via a 30-minute time trial (use 95% of average pace) or a 5 km race. Input as mm:ss per km. **Impact:** Running training zones, Load for run workouts --- ## Swimming Threshold Pace Critical Swim Speed (CSS) - your maximum sustainable swimming pace for approximately 60 minutes. Typically measured using the CSS test (400 m TT + 200 m TT). Input as seconds per 100 m. **Impact:** Swim training zones, Load for swim workouts --- ## Lactate Threshold Power Power output at your Lactate Threshold 2 (LT2) / Maximal Lactate Steady State (MLSS), measured via a staged blood lactate test. Most precise measure of your aerobic ceiling. | LT2 / FTP ratio | Interpretation | | --- | --- | | LT2 greater than FTP | FTP may be set too low | | LT2 approximately equal to FTP | Well-calibrated | | LT2 less than FTP | FTP may be set too high | **Impact:** Precise power zone calibration, comparison with FTP estimates --- ## VO2 Max Maximum oxygen uptake - the gold standard of aerobic capacity, measured in ml/kg/min. Two sources: 1. **Measured** (lab or field test): entered manually, valid for 60 days. After 60 days VeloPeak falls back to the estimate. 2. **Estimated** (Coggan formula): VO2 Max = (W/kg x 10.8) + 7 - always available, updates automatically when FTP or weight changes. | VO2 Max | Level | | --- | --- | | Less than 35 | Beginner | | 35-45 | Recreational | | 45-55 | Trained | | 55-65 | Well-trained | | 65-75 | Elite | | Greater than 75 | World-class | **Impact:** Athlete classification, performance ceiling, coaching context --- Source: https://velo-peak.com/en/wiki/power-curve # Power Curve > Understand what the power curve is, how to read it, and how to use it to identify your strengths and areas for improvement in cycling. The power curve — also known as the **Maximal Mean Power (MMP) curve** — is one of the most powerful tools for understanding your performance as a cyclist. It answers a simple question: **what is the highest average power you can sustain for each effort duration?** --- ## What is the power curve The chart shows, for each duration (from 5 seconds up to 1 hour or more), the highest average power you have ever produced in a recorded activity. It is your performance "fingerprint" — unique to each athlete. The horizontal axis shows **durations** (5s, 30s, 1min, 5min, 10min, 20min, 1h). The vertical axis shows the corresponding **watts**. The higher the curve, the stronger you are at every type of effort. --- ## How to read the curve The curve reveals your **metabolic strengths**: | Region | Duration | Energy system | Typical profile | | --- | --- | --- | --- | | Neuromuscular | 5 – 15s | ATP-PCr (explosive) | Sprinter | | Anaerobic | 30s – 2min | Anaerobic glycolysis | Short climb attacker | | VO₂ Max | 3 – 8min | High-intensity aerobic | Climber, short TT | | Threshold | 20 – 60min | Aerobic / lactate threshold | Time trialist, rouleur | A curve that is high at short durations and drops steeply indicates a **sprinter**. A curve that stays high across long durations indicates an **endurance rider** or climber. --- ## Reference lines VéloPeak shows two reference lines on the chart: - **FTP** — your Functional Threshold Power. The point where the curve crosses this line (or drops below it) marks approximately the highest effort you can sustain for ~1 hour. - **VO₂ Max zone (120% of FTP)** — above this threshold are the high-intensity efforts that most effectively develop VO₂ Max. The more time your curve spends above this line, the greater your top-end aerobic capacity. --- ## How VéloPeak calculates the curve VéloPeak uses a **sliding window** over the power stream of each activity: 1. For each target duration (5s, 30s, 1min, etc.), it scans every second of the activity looking for the window with the highest average power. 2. It stores the highest value found. 3. After each new activity, it compares against your history and only updates if a new personal record was set. The result is always the **best across your entire history** — not just from the last activity. > The curve is only as good as the activity history you have synced. The more activities with power data, the more accurate and complete the curve will be. --- ## Personal Records (PRs) A **personal record** at a given duration means that in that activity, you produced the highest average power of your career for that time window. VéloPeak highlights PR data points visually on the chart. Improving your PRs in the 3–8 minute range is a direct signal of VO₂ Max gains. Improving your 20–60 minute PRs indicates progress at the lactate threshold. --- ## How to use the curve to train smarter - **Identify weaknesses:** if the curve dips significantly in a specific region, that is your opportunity. - **Track progress:** a curve that rises over months confirms your training is working. - **Validate your FTP:** if your 20-minute power is well above 105% of your current FTP, your FTP may be outdated. - **Choose targeted workouts:** want to improve your 5-minute power? Do VO₂ Max intervals (Z5). Want to improve your 20-minute power? Work at threshold (Z4). --- ## Tips - **Data quality matters:** the curve only reflects what has been measured. Activities without power data do not contribute to the curve. - **The curve never drops — only rises:** since it always stores the best historical value, it only changes upward when a new record is set. - **Time-based comparison:** in a future update, VéloPeak will show curves for different periods (e.g. this year vs. last year) to visualise your progression directly. --- Source: https://velo-peak.com/en/wiki/connect-intervals-icu # Connect Intervals.icu > How the Intervals.icu integration works in VéloPeak — connection, automatic sync, and force sync. VéloPeak connects to Intervals.icu using OAuth 2.0, the same secure standard used by thousands of apps. We never see your Intervals.icu password — you authorise access directly on Intervals.icu's website. ## What we access When you connect Intervals.icu, VéloPeak requests the following permissions: - **Read activities** — power, heart rate, cadence, Load, Intensity, and training metrics from your activities - **Create and push workouts** — to send AI-generated workouts directly to your Intervals.icu training calendar ## Connecting from Settings 1. Go to **Settings → Connections & Apps** 2. Click **Connect** next to Intervals.icu 3. You will be redirected to the Intervals.icu authorisation page 4. After approving, you are sent back to VéloPeak automatically Once connected, VéloPeak immediately syncs your recent native activities (not those imported from Strava — those are already handled by the Strava integration). ## How automatic sync works VéloPeak uses **Intervals.icu Webhooks**. Every time you upload a native activity to Intervals.icu, it sends a notification to VéloPeak in real time. We then: 1. Fetch the full activity data (including power streams) 2. Run the AI analysis 3. Update your fitness metrics (Fitness, Fatigue, Form) There is nothing you need to do — it happens automatically within a few minutes of uploading. ## Force sync from Settings If you need to re-process recent activities or trigger a manual sync, go to **Settings → Connections & Apps** and click **Force sync** next to Intervals.icu. Force sync will re-fetch your last 30 native activities and process any that have not yet been analysed. ## Disconnecting Intervals.icu You can disconnect Intervals.icu at any time from **Settings → Connections & Apps**. This will: - Remove your access token from our servers - Stop all future syncs and webhooks - **Not** delete your existing activity data or analyses in VéloPeak To delete your activity data, use the **Delete account** option in Settings. --- Source: https://velo-peak.com/en/wiki/strava-integration # Strava Integration > How the Strava integration works in VéloPeak — connection, automatic sync, and force sync. VéloPeak connects to Strava using OAuth 2.0, the same secure standard used by thousands of apps. We never see your Strava password — you authorise access directly on Strava's website. ## What we access When you connect Strava, VéloPeak requests the following permissions: - **Read activities** — distance, duration, elevation, power, heart rate, cadence, and GPS data from your rides - **Post comments** — to leave a motivational coaching note on your activity (only if you enable this in Settings) We do **not** request write access to your activities, segments, or profile. ## Connecting during onboarding When you first sign up, VéloPeak will prompt you to connect your Strava account. Click **Connect Strava** and you will be redirected to Strava's authorisation page. After approving, you are sent back to VéloPeak automatically. ![Strava connection screen during onboarding](https://velo-peak.com/content/en-strava-onboarding.png) Once connected, VéloPeak immediately fetches your recent activities and begins analysing them. ## How automatic sync works VéloPeak uses **Strava Webhooks**. Every time you save a ride on Strava (or your device syncs), Strava sends a notification to VéloPeak in real time. We then: 1. Fetch the full activity data 2. Run the AI analysis 3. Send you an email summary (if enabled) 4. Post a coaching comment on the activity (if enabled) There is nothing you need to do — it happens automatically within a few minutes of finishing a ride. ## Force sync from Settings If you need to re-analyse a recent activity or trigger a manual sync, go to **Settings → Connections & Apps** and click **Force sync** next to Strava. ![Force sync button in Settings → Connections & Apps](https://velo-peak.com/content/en-strava-manual-sync.png) Force sync will re-fetch your last 10 activities and re-run analysis on any that have not yet been processed. ## Disconnecting Strava You can disconnect Strava at any time from **Settings → Connections & Apps**. This will: - Remove your Strava access token from our servers - Stop all future syncs and webhooks - **Not** delete your existing activity data or analyses in VéloPeak To delete your activity data, use the **Delete account** option in Settings. --- Source: https://velo-peak.com/en/wiki/sync-workouts-mywhoosh # Sync workouts to MyWhoosh automatically > How to connect Intervals.icu and MyWhoosh so that VéloPeak workouts appear automatically in your MyWhoosh calendar. VéloPeak pushes approved workouts directly to your Intervals.icu training calendar. If you also connect MyWhoosh to Intervals.icu, those workouts will appear automatically in your MyWhoosh calendar — no manual importing needed. ## How it works The flow is straightforward: 1. **VéloPeak** generates your weekly training plan and, once you approve a workout, pushes it to your **Intervals.icu** calendar 2. **MyWhoosh** syncs scheduled workouts from Intervals.icu automatically 3. Open MyWhoosh on any device and your workout is already there, ready to ride ## Step 1 — Connect VéloPeak to Intervals.icu If you have not done this yet: 1. Go to **Settings → Connections & Apps** in VéloPeak 2. Click **Connect** next to Intervals.icu 3. Authorise access on the Intervals.icu website 4. You will be redirected back to VéloPeak automatically See [Connect Intervals.icu](https://velo-peak.com/en/wiki/connect-intervals-icu) for full details. ## Step 2 — Connect MyWhoosh to Intervals.icu 1. Go to [event.mywhoosh.com](https://event.mywhoosh.com/auth/login) and log in 2. Open your **Profile** page 3. Click **Connections** in the left sidebar 4. Find **Intervals.icu** in the list and click **Connect** 5. You will be redirected to Intervals.icu — log in and authorise MyWhoosh 6. You will be brought back to MyWhoosh with a confirmation message The Connect button will change to Disconnect, confirming the link is active. ## Step 3 — Approve a workout in VéloPeak Once both connections are active: 1. Go to **Plan** in VéloPeak 2. Review your weekly plan and approve individual workouts (or click **Approve all**) 3. VéloPeak pushes the approved workouts to your Intervals.icu calendar immediately 4. Open MyWhoosh — the workout will appear in your calendar within a few minutes ## What syncs - Structured workouts with power targets (watts) - Workout name and description - Scheduled date MyWhoosh requires version **5.2.0 or later** for native Intervals.icu integration. Update the app if workouts are not appearing. ## Troubleshooting **Workout not showing in MyWhoosh** - Check that both connections are active (VéloPeak → Intervals.icu and MyWhoosh → Intervals.icu) - Make sure the workout was approved in VéloPeak — pending workouts are not pushed - Wait a few minutes and refresh the MyWhoosh calendar - Verify MyWhoosh is on version 5.2.0 or later **Connection was lost** - Reconnect from the respective settings page (VéloPeak Settings or MyWhoosh Profile → Connections) - Approving a workout again will re-push it to Intervals.icu --- Source: https://velo-peak.com/en/wiki/import-fit-garmin # Get workouts on your Garmin > How VéloPeak workouts reach your Garmin Edge or watch via Intervals.icu VéloPeak generates workouts in the .fit format, the native Garmin training file. The same file is also accepted by MyWhoosh, Zwift and Wahoo ELEMNT. ## With Intervals.icu connected (recommended) Once you connect your Intervals.icu account in **Settings > Connections**, VéloPeak pushes every workout to your Intervals calendar automatically. Intervals.icu then relays it to your Garmin Connect account, and the workout appears on the calendar of your Edge or watch on the day it is scheduled. When you start the workout on your device, the power field shows live 3-second average power during intervals, not the lap average. This is what `target_type=power_3s` in the .fit file gives you. ## Manual download If you prefer to upload a single workout by hand: 1. Open the workout in VéloPeak and click **Export > Download .fit**. 2. Send the file to your phone or computer. 3. Import it on Garmin Connect (Training > Workouts > Import) or sideload it onto your Edge under `/GARMIN/NEWFILES/`. ## Tips - Set your FTP correctly in VéloPeak. Power targets in the .fit file are absolute watts resolved against your FTP at export time. - The same .fit file works on MyWhoosh, Zwift and Wahoo ELEMNT, with no separate file per platform. --- Source: https://velo-peak.com/en/wiki/api-getting-started # API integration > Connect an app to the VeloPeak API in four steps, then explore every endpoint in the interactive reference. **Full reference:** browse every endpoint and schema, and run live requests, in the [interactive API reference](https://velo-peak.com/en/developers). This page is the quickstart; everything else lives there. The VeloPeak API is read-only. It exposes an authorizing athlete's **planned workouts** and **completed activities**, and lets your app subscribe to **webhooks**. Authentication is OAuth 2.0 (authorization code with PKCE). Base URL: `https://velo-peak.com/api/v1` ## 1. Register your app In VeloPeak, open **Settings → Developer** and create an app. You receive a `client_id` and a `client_secret` (shown once), and you choose: - **Redirect URIs**, where athletes return after authorizing. - **Scopes** your app needs: `athlete:read`, `workouts:read`, `activities:read`, `webhooks`. Pick only what you use; the consent screen shows exactly these. ## 2. Get the athlete's authorization Send the athlete to the authorize endpoint with a PKCE challenge: ``` GET https://velo-peak.com/api/auth/oauth2/authorize ?response_type=code &client_id=YOUR_CLIENT_ID &redirect_uri=YOUR_REDIRECT_URI &scope=athlete:read workouts:read &state=RANDOM &code_challenge=BASE64URL_SHA256_OF_VERIFIER &code_challenge_method=S256 ``` They sign in, approve the consent screen, and return to your `redirect_uri` with a `code`. Exchange it for a token: ``` POST https://velo-peak.com/api/auth/oauth2/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code=THE_CODE &redirect_uri=YOUR_REDIRECT_URI &client_id=YOUR_CLIENT_ID &client_secret=YOUR_CLIENT_SECRET &code_verifier=YOUR_PKCE_VERIFIER ``` You receive an `access_token` and a `refresh_token`. ## 3. Call the API Send the token as a Bearer header: ``` GET https://velo-peak.com/api/v1/workouts Authorization: Bearer ACCESS_TOKEN ``` The full list of endpoints, parameters and response shapes is in the [API reference](https://velo-peak.com/en/developers). ## 4. Receive events (optional) With the `webhooks` scope, register a callback to be notified when workouts or activities change. Every delivery is signed with an `X-VeloPeak-Signature` header (HMAC-SHA256). The reference documents the subscription endpoint and the payload. --- Open the [API reference](https://velo-peak.com/en/developers) to try the endpoints with your token. --- Source: https://velo-peak.com/docs/api/README.md # VeloPeak Public API Agent-oriented reference for the public REST API. It mirrors the live, interactive reference at `/developers` (rendered from `GET /api/v1/openapi.json`). This folder is the source-of-truth text for integrators and AI agents. - **Endpoints:** [endpoints.md](https://velo-peak.com/docs/api/endpoints.md) - **Webhooks:** [webhooks.md](https://velo-peak.com/docs/api/webhooks.md) ## What it is A mostly read-only API that exposes an authorizing athlete's **planned workouts** and **completed activities**, plus outbound **webhooks**. The only write capability is `POST /uploads` (scope `activities:write`), which accepts a completed-ride `.fit` file (processed asynchronously); apps cannot otherwise create, edit, or delete an athlete's data. - **Base URL:** `https://velo-peak.com/api/v1` - **Auth:** OAuth 2.0, authorization code grant with PKCE (required). Bearer access tokens. - **Format:** JSON. Errors are `{ "error": "code" }` with an appropriate HTTP status. ## Authorization flow (OAuth 2.0 + PKCE) ### 1. Register an app A VeloPeak user creates an app at **Settings → Developer** (`/settings/developer`). It yields a `client_id` and a `client_secret` (shown once). The developer sets: - **Redirect URIs** (exact-match, https only; http allowed only for loopback). No wildcards or fragments. - **Scopes** the app may request (see below). An app can only ever request scopes it registered. ### 2. Send the athlete to authorize ``` GET https://velo-peak.com/api/auth/oauth2/authorize ?response_type=code &client_id=CLIENT_ID &redirect_uri=REDIRECT_URI # must exactly match a registered URI &scope=athlete:read workouts:read # space-delimited; add offline_access for a refresh token &state=RANDOM &code_challenge=BASE64URL(SHA256(verifier)) &code_challenge_method=S256 ``` The athlete signs in and approves the consent screen, then is redirected to `REDIRECT_URI?code=AUTH_CODE&state=RANDOM`. ### 3. Exchange the code for tokens ``` POST https://velo-peak.com/api/auth/oauth2/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code=AUTH_CODE &redirect_uri=REDIRECT_URI &client_id=CLIENT_ID &client_secret=CLIENT_SECRET &code_verifier=PKCE_VERIFIER ``` Response: `{ "access_token": "...", "token_type": "Bearer", "expires_in": 3600, "scope": "...", "refresh_token": "..." }`. The `refresh_token` is present only if `offline_access` was in the requested scope. ### 4. Refresh (optional) ``` POST https://velo-peak.com/api/auth/oauth2/token Content-Type: application/x-www-form-urlencoded grant_type=refresh_token &refresh_token=REFRESH_TOKEN &client_id=CLIENT_ID &client_secret=CLIENT_SECRET ``` Refresh does not widen scope; the new token carries the scopes originally granted. ### 5. Call the API ``` GET https://velo-peak.com/api/v1/workouts Authorization: Bearer ACCESS_TOKEN ``` ## Scopes | Scope | Grants | | ------------------ | ---------------------------------------------------------- | | `athlete:read` | `GET /athlete` (id, name, email) | | `workouts:read` | `GET /workouts`, `/workouts/{id}`, `/workouts/{id}/export` | | `activities:read` | `GET /activities`, `/activities/{id}` | | `activities:write` | `POST /uploads`, `GET /uploads/{id}` (upload a `.fit`) | | `webhooks` | Manage push subscriptions (`/push_subscriptions`) | `openid`, `profile`, `email`, `offline_access` are standard OIDC scopes and are always permitted (the resource server enforces only the five above). A request for a scope the app did not register is rejected at `/authorize` with `invalid_scope`. ## Pagination List endpoints accept `page` (>= 1, default 1) and `pageSize` (1–100, default 20), plus a `from`/`to` date filter (`YYYY-MM-DD`). They return: ```json { "items": [ ... ], "total": 0, "page": 1, "pageSize": 20, "totalPages": 1 } ``` ## Errors All errors are `{ "error": "code" }`. Common codes: | HTTP | error | Meaning | | ---- | ---------------------------------- | ---------------------------------------------- | | 401 | `unauthorized` | Missing bearer token | | 401 | `invalid_token` | Token unknown, expired, or app disabled | | 403 | `insufficient_scope` | Token lacks the scope the endpoint requires | | 429 | `rate_limited` | Rate limit hit; see the `Retry-After` header | | 400 | `invalid_query` / `invalid_params` | Bad query/path parameters | | 404 | `not_found` | Resource not found or not owned by the athlete | Unauthorized responses include a `WWW-Authenticate: Bearer` header. ## Rate limiting Requests are limited per app and per (app, athlete). On `429` the response carries a `Retry-After` header (seconds). Treat the limits as best-effort and back off. ## Notes for agents - Workout intensity targets are **fractions** of the athlete's FTP / max HR (`power_pct_ftp`, `hr_pct_max`), not absolute watts/bpm. For device files use the `.fit`/`.zwo` export endpoint, which resolves targets at encode time. - The athlete `id` is a stable opaque id; it is also the `owner_id` in webhook payloads. - The API never returns secrets, tokens, internal database ids, or the full athlete profile. - `/activities` is not cycling-only: running, swimming, walking, and hiking are returned too, with no sport filter. Use `Activity.sport_category` for a stable, provider-independent sport value (see [endpoints.md](https://velo-peak.com/docs/api/endpoints.md)). --- Source: https://velo-peak.com/docs/api/endpoints.md # Endpoints Base URL: `https://velo-peak.com/api/v1`. All endpoints (except `openapi.json`) require `Authorization: Bearer ACCESS_TOKEN` and the scope noted per endpoint. ## GET /athlete Scope: `athlete:read`. The authorizing athlete's identity. Deliberately minimal. ```json { "id": "user_abc123", "name": "Ana Silva", "email": "ana@example.com" } ``` | Field | Type | Notes | | ------- | -------------- | ---------------------------------------- | | `id` | string | Stable athlete id (= webhook `owner_id`) | | `name` | string \| null | | | `email` | string \| null | | Never returns sex, country, timezone, metrics, tokens, or internal ids. ## GET /workouts Scope: `workouts:read`. Paginated planned workouts. Query: `from`, `to` (`YYYY-MM-DD`), `page` (>=1), `pageSize` (1–100). ``` GET /api/v1/workouts?from=2026-01-01&to=2026-01-31&page=1&pageSize=20 ``` Returns the pagination envelope with `items: PlannedWorkout[]` (see schema below). ## GET /workouts/{id} Scope: `workouts:read`. A single `PlannedWorkout`. `404 not_found` if the workout is not owned by the athlete. `id` is a UUID. ## GET /workouts/{id}/export Scope: `workouts:read`. Download the workout as a file. Query: `format=fit` (default) or `format=zwo`. - `fit` → `application/octet-stream` (Garmin/Wahoo/Zwift compatible) - `zwo` → `application/xml` (Zwift) Power is encoded as a fraction of FTP, so no athlete FTP is needed at encode time. ## GET /activities Scope: `activities:read`. Paginated completed activities. Same query params as `/workouts` (`from`, `to`, `page`, `pageSize`), plus `sport` to filter to one normalised category: `cycling`, `running`, `swimming`, `walking`, `hiking`. `sport` matches `sport_category` on each returned `Activity`, not the raw `sport` (provider) field. Returns `items: Activity[]`. ``` GET /api/v1/activities?sport=running&page=1&pageSize=20 ``` ## GET /activities/{id} Scope: `activities:read`. A single `Activity`. Pass `?include=streams` to embed the (heavy) power/HR/cadence time-series. `404 not_found` if not owned. `id` is a UUID. ## POST /uploads Scope: `activities:write`. Upload the file of a completed ride. Processing is **asynchronous**: the endpoint creates an upload in `processing` status and returns it immediately, then processes the file in the background. On success the upload becomes an `Activity`. Poll `GET /uploads/{id}` until `activity_id` is set (success) or `error` is non-null (failure). Only `data_type=fit` is supported today. Uploads are throttled per athlete. Exceeding the daily volume returns `429` `daily_upload_quota_exceeded`; having too many uploads still `processing` returns `429` `too_many_pending_uploads`. Back off and retry later. Send the file as `multipart/form-data`: | Field | Required | Notes | | ------------- | -------- | ------------------------------------------- | | `file` | yes | The activity file | | `data_type` | yes | File format. Only `fit` is supported today | | `external_id` | no | Client identifier; defaults to the filename | | `name` | no | Activity title | Returns `201` with an `Upload` object whose `activity_id` is `null` and `status` is `"Your activity is still being processed."`. Poll `GET /uploads/{id}` until `activity_id` is set or `error` is non-null. Errors: `400` (missing `file` / `data_type`, unsupported `data_type`, empty file), `413 file_too_large`, `415 unsupported_content_type` (not multipart). ## GET /uploads/{id} Scope: `activities:write`. Poll the status of an upload. Returns an `Upload` object. `404 not_found` if not owned. `id` is a UUID. ```json { "id": "...", "id_str": "...", "external_id": "ride.fit", "error": null, "status": "Your activity is ready.", "activity_id": "" } ``` ## GET /openapi.json Public, no auth. The OpenAPI 3.1 document for this API. --- ## Schemas ### PlannedWorkout ```json { "id": "0e4c...uuid", "date": "2026-01-02", "name": "Threshold 2x20", "sport": "ride", "description": "...", "planned_duration_s": 3600, "planned_load": 75, "is_ftp_test": false, "status": "scheduled", "structure": [ /* WorkoutStep[] */ ], "created_at": "2026-01-01T00:00:00.000Z" } ``` | Field | Type | Notes | | -------------------- | -------------------------------------- | ------------------------------- | | `id` | string (uuid) | | | `date` | string \| null | `YYYY-MM-DD` (scheduled date) | | `name` | string \| null | | | `sport` | string \| null | e.g. `ride` | | `description` | string \| null | | | `planned_duration_s` | integer \| null | | | `planned_load` | integer \| null | | | `is_ftp_test` | boolean | | | `status` | `scheduled` \| `executed` \| `skipped` | | | `structure` | WorkoutStep[] | empty if the workout has no doc | | `created_at` | string \| null | ISO 8601 | ### WorkoutStep Targets are ranges expressed as fractions (power/HR) or rpm (cadence). Any target may be absent. ```json { "kind": "intervals", "duration_s": 600, "target": {}, "repeat": 2, "on": { "kind": "steady", "duration_s": 1200, "target": { "power_pct_ftp": { "low": 0.95, "high": 1.0 } } }, "off": { "kind": "steady", "duration_s": 300, "target": { "power_pct_ftp": { "low": 0.5, "high": 0.5 } } } } ``` | Field | Type | Notes | | ---------------------- | --------------------------------------------------------------- | -------------------------- | | `kind` | `warmup` \| `steady` \| `intervals` \| `cooldown` \| `freeride` | | | `duration_s` | integer | | | `target.power_pct_ftp` | `{ low, high }` (fractions of FTP) \| absent | e.g. 0.85 = 85% FTP | | `target.hr_pct_max` | `{ low, high }` (fractions of max HR) \| absent | | | `target.cadence_rpm` | `{ low, high }` (rpm) \| absent | | | `repeat` | integer \| absent | intervals only | | `on` / `off` | WorkoutStep \| absent | intervals work/rest phases | ### Activity VeloPeak ingests all endurance activities, not just cycling — running, swimming, walking, and hiking are included here too. Nothing is filtered by sport; use `sport_category` to distinguish them. ```json { "id": "a1b2...uuid", "date": "2026-01-02T07:30:00.000Z", "name": "Morning ride", "sport": "ride", "sport_category": "cycling", "source": "strava", "distance_m": 42000, "duration_s": 5400, "elevation_m": 620, "load": 88.5, "weighted_power": 235, "intensity": 0.82, "planned_workout_id": "0e4c...uuid", "created_at": "2026-01-02T08:00:00.000Z" } ``` | Field | Type | Notes | | -------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string (uuid) | | | `date` | string \| null | ISO 8601 | | `name` | string \| null | | | `sport` | string \| null | Raw provider string, e.g. `Run`, `Ride`, `MOUNTAIN_BIKING`. Kept for backward compatibility; prefer `sport_category`. | | `sport_category` | string \| null | Normalised: `cycling`, `running`, `swimming`, `walking`, `hiking`. Same value regardless of which provider or raw spelling produced the activity. `null` only on legacy rows that predate this field. Filterable via `?sport=` on `GET /activities`. | | `source` | string \| null | `strava`, `intervals`, `garmin`, `wahoo`, `mywhoosh`, ... | | `distance_m` | integer \| null | | | `duration_s` | integer \| null | | | `elevation_m` | integer \| null | | | `load` | number \| null | | | `weighted_power` | integer \| null | Watts. Not meaningful for non-power sports (running/swimming/walking/hiking); `null` there. | | `intensity` | number \| null | | | `planned_workout_id` | string \| null | linked planned workout, if matched | | `created_at` | string \| null | ISO 8601 | | `streams` | object \| null | only when `?include=streams`; a fixed allowlist regardless of sport | `streams` channels: `time`, `watts`, `heartrate`, `cadence`, `altitude`, `velocity_smooth` (speed, m/s), `distance`. A channel a sport's provider doesn't record (e.g. `watts` for a swim) is simply absent from the object. There is no separate pace channel — derive pace from `distance` and `time`, or from `velocity_smooth`. ### Upload Returned by `POST /uploads` and `GET /uploads/{id}`. | Field | Type | Notes | | ------------- | -------------- | ----------------------------------------------------- | | `id` | string | Upload id (UUID) | | `id_str` | string | String form of the id (same value) | | `external_id` | string \| null | Client identifier; defaults to the filename | | `error` | string \| null | Error message if processing failed; null otherwise | | `status` | string | Human-readable processing status | | `activity_id` | string \| null | Stored activity id once processed; null while pending | --- Source: https://velo-peak.com/docs/api/webhooks.md # Webhooks With the `webhooks` scope, an app registers one callback URL and receives a POST whenever an authorizing athlete's planned workout (or activity) is created, updated, or deleted. ## Register a subscription ``` POST https://velo-peak.com/api/v1/push_subscriptions Authorization: Bearer ACCESS_TOKEN # scope: webhooks Content-Type: application/json { "callback_url": "https://yourapp.com/velopeak/webhook", "verify_token": "your-random-token" } ``` Before activating, VeloPeak validates the callback (must be https, public host; private/loopback/metadata IPs are rejected) and performs a **GET challenge** to it: ``` GET https://yourapp.com/velopeak/webhook ?hub.mode=subscribe &hub.challenge=RANDOM &hub.verify_token=your-random-token ``` Your endpoint must reply `200` with JSON `{ "hub.challenge": "RANDOM" }` (echo it). On success the subscription is created and the response is: ```json { "id": "sub-uuid", "callback_url": "https://yourapp.com/velopeak/webhook", "status": "active", "created_at": "2026-01-01T00:00:00.000Z", "signing_secret": "whsec_..." // returned ONCE; store it to verify signatures } ``` - `GET /api/v1/push_subscriptions` → `{ "items": [subscription] }` (one per app). - `DELETE /api/v1/push_subscriptions/{id}` → `{ "ok": true }`. You can also manage the subscription from the app's page in `/settings/developer`. ## Event payload Each event is a POST to your `callback_url`: ```json { "object_type": "workout", // "workout" | "activity" "object_id": "0e4c...uuid", // the workout/activity id "aspect_type": "create", // "create" | "update" | "delete" "owner_id": "user_abc123", // the athlete id (= GET /athlete id) "subscription_id": "sub-uuid", "event_time": 1730000000 // unix epoch seconds } ``` Acknowledge quickly with any `2xx`. Non-2xx (or no response) is retried with exponential backoff until it succeeds or is dropped after several attempts. Deduplicate on `object_id` + `event_time`; the same event may be delivered more than once. ## Verify the signature Every delivery carries `X-VeloPeak-Signature: sha256=`, the HMAC-SHA256 of the **raw request body** keyed by your subscription `signing_secret`. Verify before trusting the payload: ```ts import { createHmac, timingSafeEqual } from "node:crypto" function verify(rawBody: string, header: string, signingSecret: string): boolean { const expected = "sha256=" + createHmac("sha256", signingSecret).update(rawBody).digest("hex") const a = Buffer.from(expected) const b = Buffer.from(header) return a.length === b.length && timingSafeEqual(a, b) } ``` ```python import hmac, hashlib def verify(raw_body: bytes, header: str, signing_secret: str) -> bool: expected = "sha256=" + hmac.new(signing_secret.encode(), raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, header) ``` ## Lifecycle - Events are only delivered for athletes who currently authorize the app with the `webhooks` scope and a live token. - When the athlete **revokes** the app (or the app is disabled), delivery stops and queued events for that athlete are dropped. --- Source: https://velo-peak.com/en/wiki/terms-of-service # Terms of Service > Terms and conditions for using VéloPeak Welcome to VéloPeak. VéloPeak is a brand of **VÉLO TECHNOLOGY, UNIPESSOAL LDA** ("we", "us"). By creating an account, you agree to the following terms. ## Company information - **Legal name:** VÉLO TECHNOLOGY, UNIPESSOAL LDA - **Legal form:** Sociedade Unipessoal por Quotas (Portugal) - **Tax ID (NIPC):** 518257754 - **Share capital:** 1.000,00 EUR - **Registered office:** Praceta José Luís Nunes, nº 104, CY, Paranhos, 4200-605 Porto, Portugal - **Legal representative:** Getúlio Strapazzon (Founder) - **Email:** [support@velo-peak.com](mailto:support@velo-peak.com) ## The service VéloPeak is an AI-powered cycling coaching platform. We analyse your activity data, generate personalised training plans, and track your fitness metrics over time. ## Stability and availability We work to keep the platform running reliably. VéloPeak is software, so you may occasionally encounter bugs, incomplete features, or temporary outages. We do not guarantee a specific service level (SLA). ## Data handling We take care with your data, but changes to the platform may, in rare cases, result in partial or total data loss, including activities, workouts, analyses, and profile settings. We recommend keeping backups of any data you consider important. ## Communication By creating an account, you agree that we may contact you by email about your account, service updates, and changes to the platform. You can opt out of non-essential emails at any time from your account settings. ## Acceptable use You are expected to use the platform responsibly and for its intended purpose: planning and analysing cycling workouts. You may not use VéloPeak for commercial purposes, reverse engineering, or any activity that compromises the security of the platform. ## No warranties VéloPeak is provided "as is", without warranties of any kind, express or implied. We are not responsible for training decisions made based on the platform's recommendations. ## Right to revoke access We reserve the right to suspend or revoke your access at any time, without prior notice, for violation of these terms or other legitimate reasons. ## Subscriptions and billing Paid plans are billed through Stripe. You can cancel your subscription at any time from your account settings. Cancellations take effect at the end of the current billing period. ## Privacy The data you share with us (activities, metrics, and profile information) is handled in accordance with our Privacy Policy. We do not sell or share your data with third parties. ## Changes to these terms We may update these terms at any time. If we make significant changes, we will notify you by email. Continued use of the platform after notification constitutes acceptance of the new terms. ## Contact If you have questions about these terms, contact us at [support@velo-peak.com](mailto:support@velo-peak.com). --- Last updated: April 2026 --- Source: https://velo-peak.com/en/wiki/privacy-policy # Privacy Policy > How VéloPeak collects, uses, and protects your personal data **Last updated: October 2026** VéloPeak ("we", "us", "our") is committed to protecting your privacy. This policy explains what data we collect, how we use it, and what rights you have. ## Who we are VéloPeak is a cycling coaching platform powered by artificial intelligence. VéloPeak is a brand of **VÉLO TECHNOLOGY, UNIPESSOAL LDA**, the data controller responsible for your personal data. - **Legal name:** VÉLO TECHNOLOGY, UNIPESSOAL LDA - **Legal form:** Sociedade Unipessoal por Quotas (Portugal) - **Tax ID (NIPC):** 518257754 - **Share capital:** 1.000,00 EUR - **Registered office:** Praceta José Luís Nunes, nº 104, CY, Paranhos, 4200-605 Porto, Portugal - **Legal representative:** Getúlio Strapazzon (Founder) - **Email:** [support@velo-peak.com](mailto:support@velo-peak.com) ## Data we collect ### Account data When you create an account, we collect your **name**, **email address**, and a hashed **password** (if you register with email). If you sign in with a third-party provider (Google), we receive your name and email from that provider. ### Profile data To personalise your training, we collect and store information you provide: **date of birth**, **biological sex**, **body weight**, **FTP (Functional Threshold Power)**, **preferred language**, and your **coach profile text**. ### Strava integration If you connect Strava, we receive and store your **Strava athlete ID**, **access and refresh tokens**, and your **activity data** (distance, duration, elevation, power, heart rate, cadence, GPS streams, and other metrics). We may also post comments on your Strava activities on your behalf, if you enable that feature. ### Training platform integration If you connect a third-party training platform, we store your **API credentials** and **athlete ID** to read your fitness metrics (Fitness, Fatigue, Form) and push workouts to your calendar. ### Device integrations If you connect a supported training device or platform, we store the **OAuth tokens** required to push workouts to your device. We do not read activity data from these integrations. ### Health data (Apple Health and Health Connect) The VéloPeak mobile app can read health data from **Apple Health** on iOS and from **Health Connect** on Android. This is **opt-in** — you enable it in the app and grant access in the system prompt — and it is **read-only**: VéloPeak never writes anything back to either. When enabled, we read these data types on iOS: **heart rate variability (SDNN)**, **resting heart rate**, **respiratory rate**, **blood oxygen saturation**, **sleeping wrist temperature**, **body temperature**, **VO2 max**, **step count**, **active energy burned** and **sleep analysis**. On Android the list is the same, except that Health Connect exposes a single **skin temperature** type in place of the two iOS temperature types. On your device, these readings are reduced to one value per calendar day, plus **one sleep session per night** — its bedtime, wake time and sleep stages. That is what is sent to VéloPeak's servers, where it is used to compute your daily readiness score. The app may also register for background delivery, which only wakes it to run that same daily sync. **When you use the AI coach**, a short summary of this data — your recovery score, how your HRV and resting heart rate compare to your baseline, and last night's sleep — is included in the context sent to our AI inference provider, so the coach can take your recovery into account. This is the same provider listed under Sub-processors below, it receives only that summary, and your data is not used to train AI models. Beyond that, health data is **never** used for advertising or marketing, **never** shared with any other third party, **never** sold, and **never** written to iCloud or any other cloud storage. You can revoke access at any time — on iOS in Settings › Privacy & Security › Health, on Android in the Health Connect app — or by disconnecting the health source in VéloPeak. Doing so stops any further reading immediately. ### Polar integration If you connect your Polar account, we receive and store your **Polar user ID** and an **access token**, and read data from your Polar account (Polar Flow) through Polar's official API. This is **read-only**: VéloPeak never writes training or health data to Polar. **Activities.** We read the exercises you record with your Polar device: **sport**, **start time**, **duration**, **distance**, **calories**, **average and maximum heart rate** and **training load**. **Health data.** VéloPeak can also read these data types from Polar: **sleep** (when you fell asleep and woke up, the time in each sleep stage, interruptions, heart rate during the night and Polar's own sleep scores), **Nightly Recharge** (overnight **heart rate variability (RMSSD)**, average heart rate and breathing rate, and Polar's recovery status), **daily activity** (steps, calories and active time), **continuous heart rate**, **cardio load**, **SleepWise** alertness and bedtime periods, and the **physical information** in your Polar account (weight, height, date of birth, sex, maximum and resting heart rate, heart rate thresholds, VO2 max, training background, typical day and sleep goal). We do **not** request skin or body temperature, skin contact, blood oxygen or ECG data from Polar. From this data we keep one value per calendar day (sleep duration and stages, heart rate variability, overnight heart rate, breathing rate, steps and active energy) plus **one sleep session per night**, and use them to compute your daily readiness score, in the same way as the health data described above. Your Polar weight is used only if you have not given us a weight yourself. The records Polar returns are also stored as received. The same rules apply as for the health data above: only the short recovery summary reaches our AI inference provider when you use the AI coach, and this data is **never** used for advertising or marketing, **never** shared with any other third party and **never** sold. Where VéloPeak shows health data that comes from Polar, it credits Polar Flow as the source. You can disconnect Polar at any time in VéloPeak under Settings › Connections & Apps. This stops any further reading immediately, asks Polar to remove VéloPeak's access, and deletes the records stored as received from Polar. The daily values already calculated stay in your history until you delete your account or ask us to delete them. ### Bluetooth sensors During a workout, the app connects over Bluetooth to your own equipment — smart trainer, power meter, cadence sensor, heart-rate strap — and records their readings: **power**, **cadence**, **heart rate** and **speed**. These form the activity you save at the end of the session. Bluetooth is used only to read from these sensors. The app does **not** collect your location, on iOS or Android. ### Payment data Payments are processed by a certified payment processor. We store your **customer ID** and **subscription status**. We never store card numbers or payment details — those remain with the payment processor. ### Usage data We collect standard server logs including **IP address**, **browser type**, **pages visited**, and **timestamps**, for security and performance purposes. ### Error monitoring To maintain service stability and quality, we use an active error monitoring service that automatically captures technical data when failures or unexpected behaviour occur. This may include **error messages**, **stack traces**, **page URLs**, **browser type and version**, **operating system**, and **IP addresses**. This data is used exclusively to detect, diagnose, and resolve technical issues — it is not linked to your identity and is never used for marketing or profiling purposes. The legal basis for this processing is our legitimate interest in providing a reliable and secure service (Article 6(1)(f) GDPR). ### AI interactions When you use the VéloPeak coach chat, your messages and activity context are sent to a third-party AI provider to generate responses. We do not use your data to train AI models. ## How we use your data | Purpose | Basis | | --- | --- | | Providing the service (training plans, analysis, coaching) | Contract | | Syncing with Strava and connected platforms | Contract + Consent | | Processing payments | Contract | | Sending transactional emails (welcome, analysis, weekly summary) | Contract | | Security, fraud prevention, debugging | Legitimate interest | | Improving the platform | Legitimate interest | | Analytics (understanding how the platform is used) | Consent | | Measuring and improving our own marketing campaigns | Consent | We do not sell your personal data. We use analytics and marketing cookies only with your consent, and marketing cookies only to measure and improve our own advertising campaigns. ## Third-party services We use third-party sub-processors to operate the platform. These include providers for: - **Database hosting** — EU-based infrastructure - **Application hosting and CDN** — EU-based infrastructure - **AI model inference** — US-based provider (data processed for response generation only; not used for model training) - **Payment processing** — US-based provider (PCI-DSS compliant) - **Transactional email delivery** — US-based provider - **Strava** — activity data integration (US-based) - **Polar**: activity and health data integration (Finland, EU). We only receive data from Polar; we send it none of your training or health data - **Error and performance monitoring** — third-party provider (technical error data only; retained for 90 days; used exclusively for fault detection and resolution) - **Web analytics**: Google (Google Analytics 4 and Google Tag Manager), loaded only after you consent to analytics cookies - **Marketing measurement**: Google and Meta (Facebook/Instagram) advertising tools, loaded only after you consent to marketing cookies **Health data is shared with only one of the sub-processors above:** the AI model inference provider, and only as the short recovery summary described under "Health data". No other sub-processor on this list receives it. Where data is transferred outside the EU/EEA, we ensure appropriate safeguards are in place (Standard Contractual Clauses or equivalent). You may request the full list of sub-processors by contacting us at [support@velo-peak.com](mailto:support@velo-peak.com). ## Data retention - **Account data:** retained for as long as your account is active, and up to 30 days after deletion - **Activity data:** retained for as long as your account is active - **Health and sensor data:** retained for as long as your account is active, and deleted with it. The records stored as received from Polar are also deleted when you disconnect Polar - **Payment records:** retained for 7 years for legal and tax compliance - **Server logs:** retained for 90 days - **Error monitoring data:** retained for 90 days ## Your rights (GDPR) If you are in the EU/EEA, you have the right to: - **Access** the personal data we hold about you - **Correct** inaccurate data - **Delete** your account and associated data - **Export** your data in a portable format - **Restrict** or **object** to certain processing - **Withdraw consent** at any time (for consent-based processing) To exercise any of these rights, contact us at [support@velo-peak.com](mailto:support@velo-peak.com). We will respond within 30 days. You also have the right to lodge a complaint with your local data protection authority. ## Cookies We use cookies and similar technologies in three categories: - **Strictly necessary**: required for the site to work (authentication, security, keeping you signed in). Always active, and cannot be disabled. - **Analytics**: help us understand how the platform is used (pages visited, features used, session duration) so we can improve it. We use Google Analytics 4, loaded through Google Tag Manager. - **Marketing**: let us measure and improve our own advertising campaigns (for example, which campaign brought a visitor to us). We use Google and Meta tools for this. **Non-essential cookies are off by default.** On your first visit we show a cookie banner and load these technologies in a *consent-denied* state (Google Consent Mode). Nothing is sent to analytics or marketing providers until you consent. You choose per category: accept all, reject non-essential, or manage each category individually. You can review or withdraw your consent at any time via the **"Cookie settings"** link in the site footer. Withdrawing consent is as easy as giving it, and declining non-essential cookies never affects your access to the platform. The legal basis for non-essential (analytics and marketing) cookies is your **consent** (Article 6(1)(a) GDPR and the ePrivacy rules). Strictly necessary cookies rely on our legitimate interest in operating a secure service. ## Children VéloPeak is not directed at children under 16. We do not knowingly collect data from children. If you believe a child has provided us with data, contact us and we will delete it. ## Changes to this policy We may update this policy from time to time. If we make significant changes, we will notify you by email. The date at the top of this page reflects the most recent update. ## Contact For any privacy questions or requests, contact us at [support@velo-peak.com](mailto:support@velo-peak.com).