CorrConnectDocs
Early accessRequest access

API reference

Athlete data endpoints

What your app reads with an athlete's access token. Field meanings are in the data model.

Get the athlete's subject

GET/v1/profile

Returns sub, this athlete's ID for your app. Every app sees a different sub for the same athlete, and it stays the same if they revoke and approve again. No email or name.

Auth
Bearer access token with profile:read
Host
Portal origin or API host

Response 200

Pairwise profile subject.

FieldTypeNotes
sub requiredstringccu_ and 32 hex characters: this athlete's ID for your app.

Errors

StatusCodeWhen
401invalid_access_tokenThe Bearer token is missing, malformed, expired or revoked.
403insufficient_scopeThe token does not carry the scope this endpoint needs.
429rate_limit_exceededYour app, or this athlete within your app, used its request limit.
429service_capacity_exceededAll third-party apps together reached the shared ceiling.
cURL
curl "$CORRCONNECT_BASE/v1/profile" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
JavaScript
const response = await fetch(`${process.env.CORRCONNECT_BASE}/v1/profile`, {
  headers: {
    "Authorization": `Bearer ${process.env.ACCESS_TOKEN}`,
  },
});
console.log(response.status, await response.json());
Python
import os

import requests

response = requests.get(
    f"{os.environ['CORRCONNECT_BASE']}/v1/profile",
    headers={"Authorization": f"Bearer {os.environ['ACCESS_TOKEN']}"},
    timeout=10,
)
print(response.status_code, response.json())
Swift
import Foundation

let env = ProcessInfo.processInfo.environment
var request = URLRequest(url: URL(string: "\(env["CORRCONNECT_BASE"]!)/v1/profile")!)
request.setValue("Bearer \(env["ACCESS_TOKEN"]!)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
print((response as! HTTPURLResponse).statusCode, String(decoding: data, as: UTF8.self))
Response 200
{
  "sub": "ccu_0123456789abcdef0123456789abcdef"
}

List activities

GET/v1/activities

The athlete's activities, newest first by when CorrConnect stored them. Pass next_cursor back as cursor for the next page; null means you have them all.

Auth
Bearer access token with activities:read
Host
Portal origin or API host

Parameters

NameInTypeNotes
limitqueryintegerHow many records to return. 1 to 100 Default 25
cursorquerystring or nullThe next_cursor from the previous page. Never build or edit one.
sourcequerystringOnly records from this source. One of manual_json, gpx, tcx, fit

Response 200

Normalized activity page.

FieldTypeNotes
data requiredarray of object
data[].id requiredstringCorrConnect activity ID (act_ and 32 hex characters).
data[].source requiredstringWhere the record came from. Treat values you do not know as other sources. One of manual_json, gpx, tcx, fit
data[].activity_type requiredstringNormalized sport. One of run, ride, swim, walk, strength, other
data[].started_at requiredstring (date-time)Start time with its UTC offset.
data[].duration_seconds requirednumberDuration in seconds; duration_basis says how it was measured when the source tells us.
data[].distance_metersnumber or nullDistance in meters, or absent or null when the source has none.
data[].titlestring or nullName the athlete or file gave it.
data[].duration_basisstringHow duration_seconds was measured, for example recorded_lap_sum.
data[].distance_basisstringHow distance_meters was measured.
data[].provenanceobjectFile format and position, for example {"format": "FIT", "session_index": 1}.
data[].segmentsarray of objectGPX segments: point counts, start and end times, elapsed seconds.
data[].lapsarray of objectTCX or FIT laps: start, duration and distance. Never raw GPS points.
data[].created_at requiredstring (date-time)When CorrConnect stored it. Lists sort on this, newest first.
next_cursor requiredstring or null

Errors

StatusCodeWhen
400invalid_sourcesource is not one of the listed values.
400invalid_limitlimit is outside 1 to 100.
400invalid_cursorcursor is not a next_cursor value CorrConnect returned.
401invalid_access_tokenThe Bearer token is missing, malformed, expired or revoked.
403insufficient_scopeThe token does not carry the scope this endpoint needs.
422validation_failedA field is missing, has the wrong type or is out of range; details.fields says which.
429rate_limit_exceededYour app, or this athlete within your app, used its request limit.
429service_capacity_exceededAll third-party apps together reached the shared ceiling.
cURL
curl "$CORRCONNECT_BASE/v1/activities?limit=25" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
JavaScript
const response = await fetch(`${process.env.CORRCONNECT_BASE}/v1/activities?limit=25`, {
  headers: {
    "Authorization": `Bearer ${process.env.ACCESS_TOKEN}`,
  },
});
console.log(response.status, await response.json());
Python
import os

import requests

response = requests.get(
    f"{os.environ['CORRCONNECT_BASE']}/v1/activities?limit=25",
    headers={"Authorization": f"Bearer {os.environ['ACCESS_TOKEN']}"},
    timeout=10,
)
print(response.status_code, response.json())
Swift
import Foundation

let env = ProcessInfo.processInfo.environment
var request = URLRequest(url: URL(string: "\(env["CORRCONNECT_BASE"]!)/v1/activities?limit=25")!)
request.setValue("Bearer \(env["ACCESS_TOKEN"]!)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
print((response as! HTTPURLResponse).statusCode, String(decoding: data, as: UTF8.self))
Response 200
{
  "data": [
    {
      "id": "act_0123456789abcdef0123456789abcdef",
      "source": "manual_json",
      "activity_type": "run",
      "started_at": "2026-09-22T11:15:00+00:00",
      "duration_seconds": 2400,
      "distance_meters": 8046.7,
      "created_at": "2026-09-22T11:16:00+00:00"
    }
  ],
  "next_cursor": null
}

Get one activity

GET/v1/activities/{activity_id}

One activity belonging to the token's athlete, in the same shape as list items. Use it with the activity_id from an activity.created event.

Auth
Bearer access token with activities:read
Host
Portal origin or API host

Parameters

NameInTypeNotes
activity_id requiredpathstring

Response 200

Normalized activity summary.

FieldTypeNotes
id requiredstringCorrConnect activity ID (act_ and 32 hex characters).
source requiredstringWhere the record came from. Treat values you do not know as other sources. One of manual_json, gpx, tcx, fit
activity_type requiredstringNormalized sport. One of run, ride, swim, walk, strength, other
started_at requiredstring (date-time)Start time with its UTC offset.
duration_seconds requirednumberDuration in seconds; duration_basis says how it was measured when the source tells us.
distance_metersnumber or nullDistance in meters, or absent or null when the source has none.
titlestring or nullName the athlete or file gave it.
duration_basisstringHow duration_seconds was measured, for example recorded_lap_sum.
distance_basisstringHow distance_meters was measured.
provenanceobjectFile format and position, for example {"format": "FIT", "session_index": 1}.
segmentsarray of objectGPX segments: point counts, start and end times, elapsed seconds.
lapsarray of objectTCX or FIT laps: start, duration and distance. Never raw GPS points.
created_at requiredstring (date-time)When CorrConnect stored it. Lists sort on this, newest first.

Errors

StatusCodeWhen
401invalid_access_tokenThe Bearer token is missing, malformed, expired or revoked.
403insufficient_scopeThe token does not carry the scope this endpoint needs.
404activity_not_foundNo activity with this ID belongs to the token's athlete.
429rate_limit_exceededYour app, or this athlete within your app, used its request limit.
429service_capacity_exceededAll third-party apps together reached the shared ceiling.
cURL
curl "$CORRCONNECT_BASE/v1/activities/$ACTIVITY_ID" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
JavaScript
const response = await fetch(`${process.env.CORRCONNECT_BASE}/v1/activities/${process.env.ACTIVITY_ID}`, {
  headers: {
    "Authorization": `Bearer ${process.env.ACCESS_TOKEN}`,
  },
});
console.log(response.status, await response.json());
Python
import os

import requests

response = requests.get(
    f"{os.environ['CORRCONNECT_BASE']}/v1/activities/{os.environ['ACTIVITY_ID']}",
    headers={"Authorization": f"Bearer {os.environ['ACCESS_TOKEN']}"},
    timeout=10,
)
print(response.status_code, response.json())
Swift
import Foundation

let env = ProcessInfo.processInfo.environment
var request = URLRequest(url: URL(string: "\(env["CORRCONNECT_BASE"]!)/v1/activities/\(env["ACTIVITY_ID"]!)")!)
request.setValue("Bearer \(env["ACCESS_TOKEN"]!)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
print((response as! HTTPURLResponse).statusCode, String(decoding: data, as: UTF8.self))
Response 200
{
  "id": "act_0123456789abcdef0123456789abcdef",
  "source": "fit",
  "activity_type": "ride",
  "started_at": "2026-09-22T11:15:00+00:00",
  "duration_seconds": 3600,
  "created_at": "2026-09-22T11:16:00+00:00"
}