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_column and ordered_by identify the ranking metric and default order.
  • columns and team_columns are ordered rendering descriptors; their keys map to fields in participant and team leaderboard rows.
  • totals, progress, sections, distances, and participant_data provide optional challenge-wide context.
  • show_map and show_heatmap tell the client which map views to offer. show_analytics says whether this caller may see another participant's physiological activity data; it does not restrict the caller's own reachable analytics.
  • results_limited is null for 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.
  • statistics such 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, and has_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 data
  • start and end — points in the normalized coordinate space
  • point_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/.

View as Markdown