Changelog
What changed in the API, the console and the docs, newest first.
Every change to the API, the console and these docs that you can see from outside — a new endpoint, a new field, a new provider, a breaking change — lands here. How we bill and how a plan is bought is not part of the API; that lives on pricing.
A date here is a release, not the day a particular commit landed — everything that shipped together is listed together. Breaking marks a change that can stop working code from working; there is a paragraph under each one saying what to do about it.
Want something that isn't here yet? Ask for it on the roadmap — it is the same board this changelog is written against.
2026-10-23
- Apple Watch: pauses in the FIT. The FIT for an Apple Watch workout now has timer
events:
startwhen it began,stop_allandstartaround each pause, the athlete's or the auto-pause's (timer_triggersays which), andstop_allat the end, as a Garmin file does. A workout your user paused while doing one you pushed now also gets its lap per step; the lap a pause fell in spans it, with the pause intotal_elapsed_timeand not intotal_timer_time. It needs the SDK's new release, which sends the pauses aseventsinhealthkit.v1. Workouts from older releases arrive as before. Workouts has the details.
2026-10-08
- Suunto Run: a workout push now says it cannot land. The Suunto Run and Run 2 do not run
SuuntoPlus Guides, which is the only way a workout reaches a Suunto watch. Suunto accepted
those pushes anyway, so they came back
syncedand showed in the Suunto app as "Not compatible with watch". A push for a user whose last workout was recorded on one of those watches now comes backunsupportedwith the reason inerror, and no guide is created. Activities and wellness from those watches are unaffected. Which providers get it has the details. - Apple Watch: a lap per step. The FIT for a workout your user did from one you pushed
now has one lap per step, each with
intensityandwkt_step_index, and the plan asworkoutandworkout_stepmessages, as a Garmin file does. It was a single lap before. The boundaries are placed from the plan, so a workout that was paused, cut short, or has a step ending on the lap button still arrives as one lap. When they do it has the details.
2026-10-06
-
WHOOP is the ninth provider.
POST /v1/connectacceptswhoop, and it covers every strap that syncs to the WHOOP app. Finished workouts arrive asactivity.createdonce WHOOP has scored them. WHOOP exports no workout file, so the FIT behindfile.urlis one we write from its summary: sport, times, heart rate, energy and time in each heart-rate zone, with no GPS track and no per-second samples.sportis on our vocabulary andnameis WHOOP's own sport name. Sleep, recovery, the day's strain and weight arrive aswellness.created(sleep,hrv,daily,body_composition), with the recovery score and day Strain insummary. Connecting replays the last five years as ordinary deliveries. No workout push: WHOOP has no API to receive one. What each provider sends and the support matrix have the details. -
Traditional Chinese on the pages we host. The consent screen, the confirmation after it and the manage page are now also written in Traditional Chinese —
zh-HantaslangonPOST /v1/connectandPOST /v1/connections/manage-link.zh-TW,zh-HKandzh-MOare read as Traditional too; every otherzhtag, a barezhincluded, is still Simplified. One thing to know: a user whose browser orlangsays Taiwan, Hong Kong or Macau now sees Traditional where they saw Simplified before. Language has the details.
2026-10-05
- Suunto is the eighth provider.
POST /v1/connectacceptssuunto, and it covers every watch that syncs to the Suunto app. Finished workouts arrive asactivity.createdwith Suunto's FIT file. Sleep, overnight HRV, daily totals and recovery arrive aswellness.created(sleep,hrv,daily,stress). Connecting replays five years of workouts and a year of wellness as ordinary deliveries.POST /v1/workoutsreaches Suunto asprovider: "suunto": the workout becomes a SuuntoPlus Guide, which your user picks on the watch before starting. What each provider sends and which providers get a workout have the details.
2026-10-03
- Chinese, Korean and Japanese on the pages we host. The consent screen, the
confirmation after it and the manage page are now also written in Simplified Chinese,
Korean and Japanese —
zh,koandjaaslangonPOST /v1/connectandPOST /v1/connections/manage-link, with or without a region. Anyzhtag,zh-TWincluded, gets Simplified. As with the first nine, a user whose browser is set to one of these now sees it where they saw English before. Language has the details.
2026-10-02
- Workout push to Apple Watch.
POST /v1/workoutsnow reaches Apple Watch, asprovider: "apple". Apple has no server API for it, so the last step runs in your iOS app: setschedulesWorkouts: truein theStrideeHealthSDK, callrequestWorkoutSchedulingAuthorization()when the user turns it on, and the SDK schedules what you push with WorkoutKit. The push ispendinguntil the user's phone syncs, thensynced; edits and deletes follow at the next sync. Nothing changes for an app that doesn't turn it on — an Apple connection is a workout target only once itsscopeshowsworkout_scheduling. Apple carries time, distance, calorie and open steps, pace, heart rate, power and cadence targets, heart-rate and power zones, and repeats; it needs ascheduled_date, and anything it can't express comes backunsupported. And when the user does a workout you pushed, itsactivity.creatednow says so indata.workout_id— also onGET /v1/activities. A device token can now read one thing: the workouts scheduled for its own user's watch. Workouts on Apple Watch has the setup. - Apple Health. Apple Watch and iPhone data now reaches you from HealthKit, pushed by
your own iOS app with the new
StrideeHealthSwift package (iOS 17+). Your server mints a one-hour device token for the signed-in user withPOST /v1/device-tokens; the app uses it on/v1/device/*to connect the user and upload, and can push for that one user only and read nothing. Workouts arrive asactivity.createdwithprovider: "apple"and a FIT file we encode from HealthKit's samples; wellness arrives as nine kinds —daily,sleep,hrv,fitness,respiration,pulse_ox,body_composition,blood_pressureandskin_temperature. Apple's HRV is SDNN and lands inhrv_sdrr, nothrv_avg. Apps that read HealthKit themselves can relay the same JSON from their backend withPOST /v1/accounts/{id}/apple/workoutsand/apple/wellness.POST /v1/connectwithapplestays a400, now pointing at device tokens, and disconnecting an Apple connection also revokes that user's device tokens. The package also has the pieces for asking well:HealthAccessPrimer, a SwiftUI screen to show before Apple's one-time permission sheet;requestAuthorization()to ask without connecting; andstatus.authorizationplusstatus.lastDataFound, which together are how you notice a user who left the switches off — iOS never reports a denied read. Apple Health has the setup. - The pages we host now speak nine languages. The consent screen, the confirmation
after it and the manage page your users disconnect from are available in English, German,
Danish, Norwegian, Swedish, Polish, Czech, Slovak and Spanish. They follow your user's
browser language on their own, so there is nothing to change. To choose instead, pass
langonPOST /v1/connectorPOST /v1/connections/manage-link—de,da,nb,sv,pl,cs,sk,esoren, with or without a region — and it wins over the browser. A language we don't have yet falls back rather than failing. One thing to know: a user whose browser is set to one of these languages now sees it where they saw English before. Language has the details.
2026-09-28
- Return URIs for mobile apps. A return URI can now be your app's own scheme in
reverse-domain form, such as
com.yourapp.ios:/stridee-callback, as well as anhttps://URL. Register it under Return URIs or withPOST /platform/redirect-uris, and pass it asreturn_urionPOST /v1/connectso the browser sheet you opened consent in closes back into your app. Mobile apps has the details.
2026-09-26
- Your colours on the hosted pages. The pages your athletes see — consent, connected,
declined, failed, manage and link expired — are redesigned, and take your brand: a page
background, a button colour and a corner shape, from
GET/PUT /platform/brandor the Branding screen. Text, card and glow follow from the background you choose. The screen previews every page, on a phone or a desktop, as you type. Nothing changes for an account that sets nothing.
2026-09-25
- Choosing events per endpoint. A webhook endpoint can now receive a subset of events.
Send
enabled_eventswith exact types or family wildcards such aswellness.*onPOSTorPATCH /platform/webhooks, or choose them on the Webhooks screen. Existing endpoints stay on["*"], so nothing you receive changes.pingandaccount.deletedare delivered whatever you subscribe to. Choosing events has the details.
2026-09-24
- Routes.
POST /v1/routesputs a route on your user's Garmin as a Course: send the GPX, TCX or FITfile(base64), and we read its name, description, sport and track, and compute the distance and climb. Sendname,descriptionorsportto override the file. A track over 10,000 points is thinned to fit.GET,PATCHandDELETE /v1/routes/{id}and a pagedGET /v1/routeswork the same way as workouts, and each push carries the samestatusandreasoncodes. Garmin needs the athlete's Course Import permission. Route and workout pushes share the 60-per-minute device-push limit./v1/routestakes bodies up to about 14 MB for the file; every other signed call keeps its 1 MiB limit. The console has a new Routes screen. Routes has the details.
2026-09-23
- Strength workouts.
POST /v1/workoutsaccepts"sport": "strength"and a newexercisestep, withname,sets,reps, and optionalweight_kg,rest_secondsandnote. Exercises inside arepeatmake a circuit. Garmin gets each exercise as sets of reps with the load and rest, matched to Garmin's exercise library where we can. COROS and Wahoo can't carry a load, so a workout with an exercise comes backunsupportedfrom both.repsdurations are now accepted onstrengthas well ascardioandhiit. Workouts has the format.
2026-09-19
- Zepp publishes overnight HRV. An Amazfit night's HRV now arrives as a
wellness.createdevent of kindhrv, with the night's average inhrv_avg. It is Garmin's HRV summary field for field, so code that already reads Garmin HRV reads this with no branch. Zepp sends no per-reading values: itshrvValuesisnull, and so is that key behindseries_url. Wellness has the per-provider shape.
2026-09-18
-
Garmin wellness history now backfills on connect. The wellness docs have said history on connect applies to wellness as well as activities. On Garmin it did not: a user who granted historical export got years of activities and no wellness history at all. We now request Garmin's Health API history for every summary type except
epoch—sleep,hrv,daily,stress,respiration,pulse_ox,fitness,body_composition,blood_pressure,skin_temperatureandhealth_snapshot. Garmin serves only one month of wellness history, against years of activities, so expect about the last four weeks. Each summary arrives as an ordinarywellness.created, with its own oldcalendarDate. The user needs both historical and health export granted. Users who connected before today are backfilled in the background over the coming days, with no reconnect needed. -
Fitbit is the seventh provider.
POST /v1/connectacceptsfitbit, and it covers Pixel Watch too. It is built on the Google Health API, not the Fitbit Web API that Google is retiring, so a user who linked Fitbit elsewhere through the old API consents again here. Finished workouts arrive asactivity.createdwith a TCX file — Google exports no FIT. Sleep, resting heart rate, HRV, breathing rate and SpO₂ arrive aswellness.created(sleep,daily,hrv,respiration,pulse_ox). Partial consent is honoured: each kind is read only if the user granted it, andscopeon the connection says what they granted. No workout push, and no history on connect yet. The support matrix has the current shape.
2026-09-14
-
The Stridee CLI: real deliveries on localhost, with no tunnel.
stridee listen --forward-to localhost:3000/webhooksopens an outbound connection to us and acts as one more webhook endpoint on your account for as long as it runs. Every event your account emits is POSTed to your local server exactly as production gets it: the same sealed envelope, the samewebhook-id,webhook-timestampandwebhook-signatureheaders. The CLI never decrypts anything, so the code under test is your handler's own verify and decrypt. Each delivery prints one line saying what your handler answered and whether it echoed the nonce, and shows up in the console's delivery log like any other.stridee loginhas no token. The CLI generates an Ed25519 keypair, sends only the public half, and approving the code in the console registers it as a signing key. It shows under Keys as Made by the Stridee CLI, andstridee logoutrevokes it.stridee trigger pingpings running listeners only, never production endpoints. Listening does not take deliveries away from your production endpoints: the listener gets a copy. Listeners do not count toward your endpoint limit, and an account can run up to five at once.Install it with
curl -fsSL https://download.stridee.com/install.sh | sh— macOS and Linux, Intel and ARM, one static binary and nothing else left on the machine. Every command, with its options and examples, is in the CLI reference, generated from the CLI's own definitions so it matches whatstridee <command> --helpprints. -
Workout pushes say why they did not land. Each entry in
pushes[]now carriesreason, a stable code to branch on, next toerror, which is still a sentence you should not parse.failedcovered three problems with three different fixes, andreasonseparates them:not_permitted(the athlete connected but did not grant workout access, so they have to reconnect, and retrying won't help until they do),not_connected, andprovider_error(the only one worth aPATCH).unsupportedandschedule_failedcomplete the set. A clean push has noreasonat all. Pushes made before this release have been backfilled.A Garmin push that Garmin answers with 401 or 403 is now reported as
not_permittedinstead of a provider refusal. That means the athlete switched Workout Import off in Garmin Connect before we heard about it. Theerrorsentences for Garmin and Wahoo now say what to ask the athlete to do. The console's Workouts screen shows the reason under each push. Workouts has the full table. -
COROS takes undated workouts. A workout with no
scheduled_dateused to come backunsupportedfor COROS, because the COROS calendar had nowhere to put it. It now goes to the athlete's COROS workout library and reportssynced. A dated workout still has to fall between today and a year ahead.
2026-09-09
-
Zepp publishes wellness — sleep, and sleep only. An Amazfit night now arrives as a
wellness.createdevent with the stage breakdown, Zepp's own sleep score,finalityand the per-stage timeline behindseries_url. Zepp's health API mirrors Garmin's field for field, so code that already reads Garmin sleep reads this with no branch, andzeppis now a value theproviderfilter onGET /v1/wellnessaccepts.There is no
dailyfrom a Zepp watch — steps, calories and resting heart rate are not on their health push. Overnight HRV is on it and is deliberately not published: Zepp documents no schema for it, and we would rather serve nothing than a resting-HRV number nobody has verified. Wellness has the per-provider shape. -
COROS history on connect now reaches your event stream. The walk existed before but wrote first-party rows only; it delivers through the same fan-out as live activities now, so past workouts arrive as ordinary
activity.createdevents with nothing marking them as historical.How deep is the athlete's choice, not ours. COROS's consent screen carries a checkbox offering access to their previous workouts — left alone it grants 90 days, ticked it grants their whole history, and we walk 30-day windows back until COROS answers 5011. Nothing in the API says which grant you got, so we cannot tell you in advance how far a given user goes. Two caveats, both COROS's: the deep grant expires 24 hours after binding, so history is collected at once rather than offered as a setting later, and COROS serves only what was recorded on a COROS device — a FIT imported through Training Hub is never listed. Provider support & limits has both in full.
-
Wahoo connections replay history, up to five years of it. Connecting a Wahoo athlete now delivers their past workouts as ordinary
activity.createdevents — same shape, same file block, nothing marking them as historical. It was the one connectable provider that started at the athlete's next activity.Wahoo publishes no backfill endpoint, so this is a pull rather than a replay, and their rate limit is per application rather than per athlete. A heavy athlete's full history can therefore take up to a few days to finish arriving; recent workouts come first, and live ones are never delayed behind it. Provider support & limits has the current depth and the caveat in full.
2026-09-06
- Hammerhead is the sixth provider.
POST /v1/connectaccepts it and finished rides arrive asactivity.createdlike any other. It has no wellness surface to publish — it is a bike computer — and workout push is not built against it yet, so naming it onPOST /v1/workoutsis a 422. The support matrix has the current shape. - Provider support & limits is now a page: /docs/providers. It says, per provider, which endpoints work, how far back history reaches and what is missing. It replaces asking in Discord, which was the way to find this out before.
2026-08-23
-
Zepp is a connectable provider.
-
The platform moved to its own host,
platform.stridee.com. The docs, the console and this page all live here now, andstridee.com/developer/*is no longer the address.Breaking, for bookmarks and links only. The API host is unchanged — nothing your code calls has moved. Update links you have published; the old paths do not serve the console.
2026-08-16
- Your name and logo on the consent screen. Set them on Branding and the page an athlete sees when they connect a watch says who they are connecting it to. The name and the logo are shown together or not at all.
2026-08-09
The first public shape of the platform.
GET /v1/activities, across every connected provider, in one normalized shape.- Encrypted deliveries. Every webhook body is sealed to your public key as a JWE and signed with a detached JWS you verify against our published JWKS. See Encrypted deliveries and Verifying a delivery.
- Request logs, on Logs — every signed call to
/v1/*, including the ones we refused. A 401 you cannot explain from your side is a row you can read from ours. - Connected accounts, on Accounts, keyed by your own
external_user_id. - Resending a delivery, per delivery, from the endpoint that received it. Nothing retries automatically — a person presses a button. Design your outage handling for that.
- Registered redirect URIs, on Redirect URIs.
POST /v1/connectwill only return to a URL on that list. - Every platform id is a UUID v4 — key ids, webhook ids, event ids, delivery ids. They are opaque: nothing in the string tells you what it names, so store them as given, compare them whole, and keep the id next to the thing it belongs to.
Something wrong or missing on this page? Tell us in Discord. Need something the API doesn’t do yet? Request it on the roadmap.