Built for CrossFit developers
The CrossFit results API
your product can ship on
Seasons, competitions, divisions, workouts, leaderboards, athlete careers and affiliate gyms, plus the answers on top: where a score ranks in its division, what the time cap did to a field, which gym an athlete competed for. One versioned JSON API with an OpenAPI contract and responses that keep their shape.
Versioned REST API · OpenAPI 3 · Bearer authentication · Cursor pagination
See the payload
What a response looks like
Every example below is a live call against the production API.
https://api.crossfitapi.com/v1/athletes/search?q=Scott%20PanchikDeveloper{
"data": [
{
"id": "ath_06gc8qmznhrgnbax94hy6vyym8",
"name": "Scott Panchik",
"slug": "scott-panchik-34796",
"gender": "M",
"country": {
"code": "US",
"name": "United States"
},
"gym": {
"id": "gym_06gc8qe93svyxcfg2ab48bvyjg",
"name": "CrossFit Mentality"
},
"latest_season": 2026,
"competitions": 14
}
],
"pagination": {
"next_cursor": null,
"has_more": false
}
}The data
What you can ask it for
Everything shares ids, so a leaderboard row takes you straight to the athlete, their whole career, and the gym they competed for.
Competitions and seasons
Every CrossFit Open from 2011 to the current season, the Games, Quarterfinals and Semifinals, each with its stage, dates and status.
/v1/competitions/v1/open/v1/gamesDivisions and workouts
Canonical division keys that mean the same thing in 2014 and 2026, Rx, Scaled and Foundations as an axis, and every workout with its score type and derived time cap.
/v1/open/{year}/divisions/v1/open/{year}/workoutsLeaderboards
Full fields, filtered by division, scaled status, country or gym, cursor paginated so page two thousand costs what page one costs.
/v1/open/{year}/leaderboard/v1/workouts/{id}/leaderboardResults and workout scores
Overall placings and the workout-level breakdown underneath: reps, time, tiebreak, validity and the raw source value beside every decoded field.
/v1/results/{id}/v1/athletes/{id}/resultsAthletes and careers
Search by name, resolve an upstream id to a stable one, and pull an entire competitive career across every season and stage in a single request.
/v1/athletes/search/v1/athletes/{id}/careerAffiliate gyms
Thousands of affiliate locations with coordinates, searchable by name, city, country or radius, and linked to the athletes who competed for them.
/v1/gyms/v1/gyms/{id}/athletesScore decoding
The time cap, recovered from the score
An Open score is one integer with a rep count and the remaining time packed into it. Nobody publishes the convention, so we worked it out and kept the original beside our answer.
2026 Open · derived from 29,000 scores
A cap is only published when every decoded score in that workout implies the same one. Two different implied caps means the encoding changed, so we publish nothing and flag it.
score 3540044
breakdown "354 reps"
time 676
354 × 10000 + 44
44 + 676 = 720 ← the capWhose number is whose
Anything this API computed carries calculated_by. Where CrossFit publishes a percentile we serve theirs, in a field called source_percentile. You can always tell which figure came from CrossFit and which came from us.
What you can build
Things people have built with it
A complete career on one screen
Every season and stage an athlete has entered, with CrossFit's own rank and percentile per scope. A name search and one follow-up call.
{
"athlete": { "name": "Scott Panchik" },
"data": [
{ "year": 2026, "competition": "Open",
"scope": "country", "rank": 3,
"total_entrants": 10295,
"source_percentile": 99.0 }
]
}A whole division, filtered
Any season from 2011, any division, filtered to a country or a single gym, with cursor pagination that stays fast however deep you go.
GET /v1/open/2026/leaderboard
?division=men-45-49
&country=BE
{ "data": [ { "rank": 12, "athlete": {…},
"gym": {…} } ],
"pagination": { "has_more": true } }The nearest affiliates, with their athletes
Thousands of affiliate locations with coordinates, searchable by radius, and linked to the athletes who competed for them.
{
"name": "CrossFit Dansaert Athletics",
"city": "Brussels",
"country": { "code": "BE" },
"distance_km": 0.7
}Reference
Every endpoint
20 routes. Three of them work without a key.
| Method | Path | Plan | What it returns |
|---|---|---|---|
| GET | /v1/athletes/search | Developer | Find an athlete by name, country, gender or gym. |
| GET | /v1/athletes/{id} | Developer | One athlete with country and current gym. |
| GET | /v1/athletes/{id}/results | Developer | Results with the workout-level breakdown. |
| GET | /v1/athletes/{id}/career | Developer | Every season and stage, chronologically. |
| GET | /v1/athletes/source/{source}/{id} | Developer | Resolve an upstream competitor id. |
| GET | /v1/competitions | Developer | Every competition we hold, by year and type. |
| GET | /v1/competitions/{id}/leaderboard | Developer | Any competition, one shape. |
| GET | /v1/open | Developer | Open seasons, with what is covered for each. |
| GET | /v1/open/{year}/leaderboard | Developer | Filter by division, scaled, country, gym. |
| GET | /v1/open/{year}/divisions | Developer | Canonical division keys for that season. |
| GET | /v1/open/{year}/workouts | Developer | Workouts, with the derived time cap. |
| GET | /v1/games/{year}/leaderboard | Developer | The Games, scored in points. |
| GET | /v1/workouts/{id}/leaderboard | Developer | Ranked on one workout alone. |
| GET | /v1/results/{id} | Developer | One result and its workout scores. |
| GET | /v1/gyms | Developer | By name, city, country, or within a radius. |
| GET | /v1/gyms/{id}/athletes | Developer | Athletes who competed for a gym. |
| GET | /v1/countries | Developer | Countries, with gym and athlete counts. |
| GET | /v1/data | Open | What is covered, counted from the database. |
| GET | /v1/plans | Open | The entitlement table this API enforces. |
| GET | /v1/health | Open | Row counts, last sync, enabled sources. |
Getting started
From sign-up to first response
Subscribe
Pick a plan and check out through Stripe. The documentation and the OpenAPI document are open to read first.
Copy your key
One is minted on sign-up and shown once. Send it as a bearer token.
Make a call
Search an athlete, pull a season, or find the gyms near a postcode.
Ship
Cursor pagination, RateLimit headers, a stable envelope and an OpenAPI 3 document to generate a client from.
curl "https://api.crossfitapi.com/v1/athletes/search?q=Scott%20Panchik" \
-H "Authorization: Bearer cfapi_live_your_key"Common questions
Is this an official CrossFit product?
Where does the data come from?
How far back does it go?
Are your rankings official?
calculated_by and its method is documented, so our arithmetic always reads as ours.What happens when I hit my quota?
429 monthly_quota_exceeded with Retry-After pointing at the start of the next UTC month. Every response carries RateLimit-Remaining, so you can see the wall coming.Do I need a subscription to read the documentation?
Can I wire up CI without it counting against my quota?
cfapi_test_ key that reaches the same data and is free of the monthly quota.Start building this weekend
Plans start at $15 a month. The docs and the live explorer are open, so you can see exactly what comes back before you pay for anything.
