Skip to content
Developers
OpenAPI
GET /api/v1/events/{eventId}/livescope: tracking:read

Event live status

API v1 Last updated 2026-10-01 View as Markdown

#Event live status

The event's races and start groups, with the live flags a broadcast overlay needs to decide what to poll next. Start here, then call Race live for whichever race is actually live.

Requires both the tracking:read scope and the event's organiser having turned on Share live tracking with API partners (panel: Advanced settings → Mobile broadcast & tracking) — sharing off answers 404 TRACKING_NOT_SHARED for every call below, scope or no scope.

#Headers

Header Required Value
Authorization yes Bearer <access_token>

#Path parameters

Param Type Note
eventId UUID or legacy id from List events; another club's, unpublished, or unknown ⇒ 404 EVENT_NOT_FOUND

#Request

curl -s https://sail-club-server.cloud.run/api/v1/events/1143117a-9c2b-4e7a-8f1d-2b6a9c4e7f10/live \
  -H "Authorization: Bearer $TOKEN"
const res = await fetch(`https://sail-club-server.cloud.run/api/v1/events/${eventId}/live`, {
  headers: { Authorization: `Bearer ${token}` },
});
if (res.status === 404) { /* not found, not published, or sharing is off for this event */ }
const live = await res.json();
res = requests.get(
    f"https://sail-club-server.cloud.run/api/v1/events/{event_id}/live",
    headers={"Authorization": f"Bearer {token}"},
    timeout=10,
)
live = res.json()
var res = await client.GetAsync($"/api/v1/events/{eventId}/live");
res.EnsureSuccessStatusCode();
var live = await res.Content.ReadFromJsonAsync<PublicEventLiveDto>();
<?php
$ch = curl_init("https://sail-club-server.cloud.run/api/v1/events/$eventId/live");
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Authorization: Bearer $token"]]);
$live = json_decode(curl_exec($ch), true);

#Response

{
  "eventId": "1143117a-9c2b-4e7a-8f1d-2b6a9c4e7f10",
  "delaySeconds": 30,
  "dataAsOf": "2027-05-01T12:00:00.000Z",
  "races": [
    {
      "raceId": "9a1c0d2b-7e4a-46f8-9c1d-2e3f9a1c0d2b",
      "raceNo": 1,
      "name": "Race 1",
      "status": "Started",
      "isLive": true,
      "startGroups": [
        {
          "startGroupId": "2b6a9c4e-7f10-4a1c-8d2b-7e4a6f8c1d2e",
          "name": "Start A",
          "state": "Started",
          "startTimeUtc": "2027-05-01T11:30:00Z",
          "finishTimeUtc": null,
          "courseVersion": 3
        }
      ]
    }
  ]
}

200 — same caching headers as every data endpoint, a shared 5-second server-side cache per event.

#Response fields

Field Type Null? Note
eventId string no canonical event id
delaySeconds int no 0–600, the organiser's current delay for this event
dataAsOf date-time (UTC) no when this body was built; also X-Data-As-Of
races[] array no (may be empty) every race of the event, in raceNo order — filter on isLive for an overlay
races[].raceId / raceNo / name / status uuid / int / string / string no status is PublicRaceItemDto.status
races[].isLive bool no the race's mobile-broadcast live flag
races[].startGroups[] array no start order within the race
startGroups[].startGroupId / name uuid / string no pass startGroupId to Track
startGroups[].state string no Scheduled, StartSequence, Started, Finished, Postponed, GeneralRecall, Abandoned, APEarly, StartLineReady, PostponedAshore, PostponedToday, AbandonedAshore, AbandonedToday
startGroups[].startTimeUtc date-time yes null before a gun time is set
startGroups[].finishTimeUtc date-time yes null while racing
startGroups[].courseVersion int no increments on every course change — refetch Course when it does

#Errors

HTTP Code
404 EVENT_NOT_FOUND
404 TRACKING_NOT_SHARED
401 API_TOKEN_MISSING / API_TOKEN_INVALID
403 API_SCOPE_MISSING / API_IP_NOT_ALLOWED
429 RATE_LIMIT_EXCEEDED
503 API_UNAVAILABLE

#Caching

One shared cache entry per eventId, refreshed every 5 seconds. Poll this one call to decide which race to follow; don't poll it faster than its own Cache-Control: max-age — see Rate limits for the separate, higher tracking:read bucket (120/min) this endpoint shares with the other three tracking calls.

Prompt for AI agents ready to paste into an agent
Implement getEventLive(eventId) for the Sail Club API.

GET https://sail-club-server.cloud.run/api/v1/events/{eventId}/live
Authorization: Bearer <access_token>
Scope required: tracking:read

Success 200: { eventId, delaySeconds, dataAsOf, races: [ { raceId, raceNo, name, status, isLive,
  startGroups: [ { startGroupId, name, state, startTimeUtc, finishTimeUtc, courseVersion } ] } ] } — fetch
  GET /api/v1/openapi.json for the exact schema.
404 EVENT_NOT_FOUND: unknown/other club's/unpublished event — not retryable.
404 TRACKING_NOT_SHARED: the organiser hasn't turned on live tracking sharing for this event — not retryable,
  not fixable by the caller; the organiser must enable it in their panel.
401/403/429/503: same handling as every other call — see the full-integration prompt on /docs/overview.

For each race where isLive is true, call GET /api/v1/races/{raceId}/live for boat positions, wind and the
unofficial order; use startGroups[].startGroupId with GET /api/v1/races/{raceId}/track for the 1Hz trail.

Adapt to your actual stack — the endpoint, path param and response shape above are language-neutral.