Challenge results API
Challenge results API
Whitelabel portals and other supported integrations can build a challenge results experience with the endpoints below. They all use the challenge code and require an authenticated API request.
/api/v1/gamification/challenge/{code}/
Integration access
API credentials, supported authentication flows, and rate limits are arranged with DistantRace support. Treat a 404 from a result or analytics endpoint as unavailable to the current caller; the same response is used when privacy settings hide the resource.
Endpoint sequence #
| Endpoint | Use |
|---|---|
GET result-settings/ |
Discover result columns, sorting, totals, sections, distances, and which optional views are available |
GET heatmap/ |
Load aggregate workout-density cells when show_heatmap is enabled |
GET results/{challenger_id}/detailed/ |
Load one participant's result, aggregate statistics, comparisons, and activity timeline |
GET results/{challenger_id}/activities/{activity_id}/analytics/ |
Load splits, charts, and permitted sensor analytics for one accepted activity |
Start with result-settings/. Use its flags and column descriptors to decide which controls and screens to render instead of assuming every challenge has the same result format.
Get challenger_id values from the challenge's paginated results/ leaderboard. Activity IDs come from the nested activities.results list in the detailed response.
Result settings #
GET /api/v1/gamification/challenge/{code}/result-settings/
The response describes the current challenge result presentation:
primary_columnandordered_byidentify the ranking metric and default order.columnsandteam_columnsare ordered rendering descriptors; their keys map to fields in participant and team leaderboard rows.totals,progress,sections,distances, andparticipant_dataprovide optional challenge-wide context.show_mapandshow_heatmaptell the client which map views to offer.show_analyticssays whether this caller may see another participant's physiological activity data; it does not restrict the caller's own reachable analytics.results_limitedisnullfor unrestricted results. A number means that the caller can see only that many top rows, and result filtering, ordering, and pagination controls should be hidden.
These values are caller-aware. For example, the same challenge can return unrestricted settings to a participant and limited settings to a signed-in non-participant.
Workout heatmap #
GET /api/v1/gamification/challenge/{code}/heatmap/
The heatmap aggregates accepted GPS activities into approximately 150-metre grid cells. Each cell is [longitude, latitude, weight], where the weight is the number of distinct activities that passed through it. An activity contributes at most once to each cell, and workouts marked private in their source app are excluded.
Heatmaps are generated lazily. When no stored heatmap exists, the first request starts background generation and returns:
{"status": "pending"}
Poll again after a few seconds. A ready response contains generated_at, cell_size, activity_count, max_weight, truncated, and cells. Stored data can be served while a stale heatmap is refreshed in the background.
Use max_weight to normalize a weighted density layer. If truncated is true, the response contains the heaviest cells rather than every generated cell.
The endpoint returns 404 when the organizer has not enabled show_heatmap, during a hidden-results window, or when public results are restricted and the caller is not a participant.
Detailed participant result #
GET /api/v1/gamification/challenge/{code}/results/{challenger_id}/detailed/
The response combines:
- The participant's leaderboard row, chosen distance, rank, and
result_rank_total. statisticssuch as distance, duration, pace or speed, energy, steps, activity count, active days, longest streak, and average heart rate when available.is_own_result, which identifies whether the row belongs to the authenticated participant.head_to_head, available only when a participant views their own result. It includes rank and percentile, the ranking metric, gaps to nearby competitors and the leader, the field average, and podium rows.activities, a nested paginated list of accepted, visible activities credited to the result. Each row includes basic workout metadata, average pace, a route shape when available, andhas_analytics.
For a fixed-distance result, the activity list stops at the activity that completed the selected distance. Later activities do not appear because they did not contribute to that result.
Nested activity pagination #
The activity list has the usual count, next, previous, and results fields, but uses dedicated query parameters so it does not conflict with top-level pagination:
| Parameter | Meaning |
|---|---|
activities_page |
Page number, starting at 1 |
activities_per_page |
Items per page; default 25 and subject to the API maximum |
Location-free route shapes #
Activity timeline routes are not geographic coordinates. The server translates and scales each GPS track into a fixed 158 × 108 SVG coordinate space and returns only:
path— SVG path datastartandend— points in the normalized coordinate spacepoint_count— number of points in the returned shape
Absolute latitude, longitude, bounds, and center are not included. The same route translated to another location produces the same shape, so it is suitable for a thumbnail but cannot be plotted on a geographic map.
Per-activity analytics #
GET /api/v1/gamification/challenge/{code}/results/{challenger_id}/activities/{activity_id}/analytics/
The activity must be accepted, visible, and attached to that exact participant result. The response contains basic distance, duration, pace, and speed plus any analytics that can be derived from the stored streams:
| Block | Contents |
|---|---|
route |
The same location-free route shape used in the activity timeline |
km_splits |
Full kilometre splits plus an optional final partial split, including fastest and slowest markers |
elevation |
Downsampled profile, ascent, descent, minimum, and maximum |
heart_rate and hr_zones |
Downsampled heart-rate series, average, maximum, reference maximum, and time in five zones |
cadence |
Downsampled cadence series and average |
effort_score |
Heart-rate-derived effort estimate |
Blocks are independently nullable because providers and devices supply different streams. has_streams reports whether usable stream analytics exist. x_kind identifies whether chart x-values represent cumulative distance or elapsed time.
Low-sensitivity blocks—route shape, splits, pace, and elevation—are available to any caller who can reach the result. Physiological blocks—heart rate, zones, cadence, and effort—are always available for the caller's own reachable result. For another participant's activity, they are returned only when the organizer enabled show_analytics and the caller passes the result visibility rules. Otherwise those blocks are null and physio_restricted is true.
Visibility and privacy rules #
| Setting or state | Effect |
|---|---|
show_heatmap off |
Heatmap returns 404; result-settings reports show_heatmap: false |
show_analytics off |
Other participants' physiological activity blocks are removed; own reachable analytics are unaffected |
| Hidden-results window active | Participant result drill-downs are hidden; heatmap returns 404; show_heatmap and show_analytics are false |
hide_results_public on |
Signed-in non-participants are limited to the configured top results, cannot load the heatmap, and cannot view other participants' physiological analytics |
| Workout not accepted or not visible | It is omitted from the timeline and cannot be opened through the analytics endpoint |
Challenge participants retain access to full results outside a hidden-results window. Organization staff access can differ from participant access, but clients should still follow the caller-specific values returned by result-settings/.