API reference
App endpoints
Manage your apps from code. Each needs a signed-in console session, and changes need Origin and X-CSRF-Token.
Register an app
POST/v1/
Registers a public client. There is no client secret. Keep client_id; it is not a credential.
- Auth
- Console session cookie,
OriginandX-CSRF-Token - Host
- Portal origin only
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
Origin required | header | string | Exactly the CorrConnect portal origin. |
X-CSRF-Token required | header | string | The latest csrf_token from sign-in or GET /v1/account/me. |
Request body application/json
| Field | Type | Notes |
|---|---|---|
name required | string | Shown to athletes on the consent screen (2 to 80 characters). 2 to 80 characters |
redirect_uris required | array of string | 1 to 5 exact HTTPS callback URLs. No fragments, credentials or wildcards; plain-HTTP loopback works only on local development servers. 1 to 5 items |
Response 201
Successful Response
| Field | Type | Notes |
|---|---|---|
client_id required | string | |
name required | string | |
redirect_uris required | array of string | |
client_type required | string | One of public |
rate_limits required | object | |
rate_limits.tier required | string | One of free, custom |
rate_ required | integer | |
rate_ required | integer |
Errors
| Status | Code | When |
|---|---|---|
| 401 | authentication_ | No console session cookie was sent. |
| 401 | invalid_session | The session was signed out, replaced or never existed. |
| 401 | session_expired | The session is older than its lifetime (12 hours by default). |
| 403 | email_ | The account has not verified its email address yet. |
| 403 | origin_rejected | The Origin header is not the exact CorrConnect portal origin. |
| 403 | csrf_rejected | X-CSRF-Token is missing or is not the latest token from GET /v1/account/me. |
| 409 | app_ | The account already owns the maximum number of apps (10 by default). |
| 422 | invalid_ | A callback is not an exact HTTPS URL, or has a fragment, credentials or a wildcard. |
| 422 | validation_ | A field is missing, has the wrong type or is out of range; details.fields says which. |
| 429 | app_ | More than 20 registrations from this account, or 60 from this network address, in an hour. |
curl "$CORRCONNECT_BASE/v1/developer/apps" \
-H "Cookie: $CORRCONNECT_COOKIE" \
-H "Origin: $CORRCONNECT_BASE" \
-H "X-CSRF-Token: $CSRF_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Interval Notebook", "redirect_uris": ["https://developer.example/callback"]}'const response = await fetch(`${process.env.CORRCONNECT_BASE}/v1/developer/apps`, {
method: "POST",
headers: {
"Cookie": `${process.env.CORRCONNECT_COOKIE}`,
"Origin": `${process.env.CORRCONNECT_BASE}`,
"X-CSRF-Token": `${process.env.CSRF_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"name": "Interval Notebook", "redirect_uris": ["https://developer.example/callback"]}),
});
console.log(response.status, await response.json());import os
import requests
response = requests.post(
f"{os.environ['CORRCONNECT_BASE']}/v1/developer/apps",
headers={"Cookie": f"{os.environ['CORRCONNECT_COOKIE']}", "Origin": f"{os.environ['CORRCONNECT_BASE']}", "X-CSRF-Token": f"{os.environ['CSRF_TOKEN']}"},
json={"name": "Interval Notebook", "redirect_uris": ["https://developer.example/callback"]},
timeout=10,
)
print(response.status_code, response.json())import Foundation
let env = ProcessInfo.processInfo.environment
var request = URLRequest(url: URL(string: "\(env["CORRCONNECT_BASE"]!)/v1/developer/apps")!)
request.httpMethod = "POST"
request.setValue("\(env["CORRCONNECT_COOKIE"]!)", forHTTPHeaderField: "Cookie")
request.setValue("\(env["CORRCONNECT_BASE"]!)", forHTTPHeaderField: "Origin")
request.setValue("\(env["CSRF_TOKEN"]!)", forHTTPHeaderField: "X-CSRF-Token")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = Data(#"{"name": "Interval Notebook", "redirect_uris": ["https://developer.example/callback"]}"#.utf8)
let (data, response) = try await URLSession.shared.data(for: request)
print((response as! HTTPURLResponse).statusCode, String(decoding: data, as: UTF8.self)){
"client_id": "app_0123456789abcdef0123456789abcdef",
"name": "Interval Notebook",
"redirect_uris": [
"https://developer.example/callback"
],
"rate_limits": {
"tier": "free",
"per_15_minutes": 100,
"per_day": 10000
},
"client_type": "public"
}List your apps
GET/v1/
Oldest first. rate_limits shows the free tier or a custom limit.
- Auth
- Console session cookie
- Host
- Portal origin only
Response 200
Successful Response
| Field | Type | Notes |
|---|---|---|
data required | array of object | |
data[].client_id required | string | |
data[].name required | string | |
data[]. required | array of string | |
data[]. required | string (date-time) | |
data[]. required | object | |
data[]. required | string | One of free, custom |
data[]. required | integer | |
data[]. required | integer |
Errors
| Status | Code | When |
|---|---|---|
| 401 | authentication_ | No console session cookie was sent. |
| 401 | invalid_session | The session was signed out, replaced or never existed. |
| 401 | session_expired | The session is older than its lifetime (12 hours by default). |
| 403 | email_ | The account has not verified its email address yet. |
curl "$CORRCONNECT_BASE/v1/developer/apps" \
-H "Cookie: $CORRCONNECT_COOKIE"const response = await fetch(`${process.env.CORRCONNECT_BASE}/v1/developer/apps`, {
headers: {
"Cookie": `${process.env.CORRCONNECT_COOKIE}`,
},
});
console.log(response.status, await response.json());import os
import requests
response = requests.get(
f"{os.environ['CORRCONNECT_BASE']}/v1/developer/apps",
headers={"Cookie": f"{os.environ['CORRCONNECT_COOKIE']}"},
timeout=10,
)
print(response.status_code, response.json())import Foundation
let env = ProcessInfo.processInfo.environment
var request = URLRequest(url: URL(string: "\(env["CORRCONNECT_BASE"]!)/v1/developer/apps")!)
request.setValue("\(env["CORRCONNECT_COOKIE"]!)", forHTTPHeaderField: "Cookie")
let (data, response) = try await URLSession.shared.data(for: request)
print((response as! HTTPURLResponse).statusCode, String(decoding: data, as: UTF8.self)){
"data": [
{
"client_id": "app_0123456789abcdef0123456789abcdef",
"name": "Interval Notebook",
"redirect_uris": [
"https://developer.example/callback"
],
"created_at": "2026-10-09T12:00:00+00:00",
"rate_limits": {
"tier": "free",
"per_15_minutes": 100,
"per_day": 10000
}
}
]
}Delete an app
DELETE/v1/
Deletes the app with its grants, codes, tokens and webhook subscriptions. Athletes' grants end at once.
- Auth
- Console session cookie,
OriginandX-CSRF-Token - Host
- Portal origin only
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
app_id required | path | string | |
Origin required | header | string | Exactly the CorrConnect portal origin. |
X-CSRF-Token required | header | string | The latest csrf_token from sign-in or GET /v1/account/me. |
Response 200
Successful Response
| Field | Type | Notes |
|---|---|---|
status required | string | One of revoked |
Errors
| Status | Code | When |
|---|---|---|
| 401 | authentication_ | No console session cookie was sent. |
| 401 | invalid_session | The session was signed out, replaced or never existed. |
| 401 | session_expired | The session is older than its lifetime (12 hours by default). |
| 403 | email_ | The account has not verified its email address yet. |
| 403 | origin_rejected | The Origin header is not the exact CorrConnect portal origin. |
| 403 | csrf_rejected | X-CSRF-Token is missing or is not the latest token from GET /v1/account/me. |
| 404 | app_not_found | The app does not exist or belongs to another account. |
curl -X DELETE "$CORRCONNECT_BASE/v1/developer/apps/$APP_ID" \
-H "Cookie: $CORRCONNECT_COOKIE" \
-H "Origin: $CORRCONNECT_BASE" \
-H "X-CSRF-Token: $CSRF_TOKEN"const response = await fetch(`${process.env.CORRCONNECT_BASE}/v1/developer/apps/${process.env.APP_ID}`, {
method: "DELETE",
headers: {
"Cookie": `${process.env.CORRCONNECT_COOKIE}`,
"Origin": `${process.env.CORRCONNECT_BASE}`,
"X-CSRF-Token": `${process.env.CSRF_TOKEN}`,
},
});
console.log(response.status, await response.json());import os
import requests
response = requests.delete(
f"{os.environ['CORRCONNECT_BASE']}/v1/developer/apps/{os.environ['APP_ID']}",
headers={"Cookie": f"{os.environ['CORRCONNECT_COOKIE']}", "Origin": f"{os.environ['CORRCONNECT_BASE']}", "X-CSRF-Token": f"{os.environ['CSRF_TOKEN']}"},
timeout=10,
)
print(response.status_code, response.json())import Foundation
let env = ProcessInfo.processInfo.environment
var request = URLRequest(url: URL(string: "\(env["CORRCONNECT_BASE"]!)/v1/developer/apps/\(env["APP_ID"]!)")!)
request.httpMethod = "DELETE"
request.setValue("\(env["CORRCONNECT_COOKIE"]!)", forHTTPHeaderField: "Cookie")
request.setValue("\(env["CORRCONNECT_BASE"]!)", forHTTPHeaderField: "Origin")
request.setValue("\(env["CSRF_TOKEN"]!)", forHTTPHeaderField: "X-CSRF-Token")
let (data, response) = try await URLSession.shared.data(for: request)
print((response as! HTTPURLResponse).statusCode, String(decoding: data, as: UTF8.self)){
"status": "revoked"
}