Skip to content

Quickstart — your first API edit

This walkthrough takes you from zero to a verified live change. You'll mint an API key as an organisation admin, make one read and one write request against the API, and watch the change land in the app or the web dashboard in real time.

You need:

  • An organisation admin account in RaceRanger.
  • The base URL for the environment you're integrating against (see Base URLs).
  • A command-line tool that speaks HTTPS (curl, httpie, Postman, Bruno, etc.). All examples below use curl.

1. Mint an org-scoped API key

API keys are minted from inside the RaceRanger app — never via the public API. This keeps every key tied to a real admin's user record for audit.

  1. Open app.raceranger.com and sign in as an organisation admin.
  2. In the top nav, click Organizations.
  3. On the left sidebar (your organisation card), click Edit organization.
  4. In the modal that opens, switch to the API keys tab (next to General). If you don't see this tab, your organisation hasn't been opted into API access yet — ask the RaceRanger team to enable it.
  5. Click + New key.
  6. The Create org API key dialog opens. Fill in:

    • Name (required) — something descriptive like "Race-day dashboard". You'll see this in the keys list later when rotating or revoking.
    • Scopes (required) — tap the filter chips for the scopes the integration actually needs. Read-only integrations should hold read:* only; write:* and manage:webhooks are org-key-only (see the scope table).
    • Restrict to event IDs (optional) — comma-separated list of event IDs to narrow this key to specific events only. Leave empty for "every event in this organisation".
    • Expires in (days, max 730) — defaults to 365. Rotate before expiry; revoked keys can't be reactivated.
  7. Tap Create.

  8. An API key created dialog appears with the plaintext key (rr_o_…) and its scopes + expiry. Copy it into your secret store immediately — it is displayed once and RaceRanger has no way to recover the plaintext after this dialog closes.

If you lose the plaintext, revoke the key and mint a new one.

For per-event read access (handing one race-day to a partner without giving them access to anything else), open Edit Event instead and use its own API keys tab. Event-scoped keys (rr_e_…) are read-only.


2. Smoke-test the key

Set a couple of shell variables to keep the rest of this page tidy:

export RR_BASE="https://raceranger-api-2wm0cky.ew.gateway.dev"  # testing
export RR_KEY="rr_o_…paste_your_key_here…"

Confirm the key works by listing the events you can see:

curl -sS "$RR_BASE/v1/events" -H "Authorization: Bearer $RR_KEY" \
  | python3 -m json.tool

Expected output:

{
  "data": [
    {
      "id": "evt_abc",
      "name": "Spring Sprint 2026",
      "sport": "triathlon",
      "dateFrom": "2026-05-04T07:00:00Z",
      "isOver": false,
      "organizationId": "your-org"
    }
  ]
}

If you get 401 unauthorized, double-check the Authorization: Bearer prefix and the absence of trailing whitespace. If you get 403, the key's scope set doesn't include read:events — re-mint with the right scopes. See the authentication reference for the full scope table.


3. Read a specific event and race

Pick an event id from the response above and a race under it:

export EVENT_ID="evt_abc"

curl -sS "$RR_BASE/v1/events/$EVENT_ID/races" \
  -H "Authorization: Bearer $RR_KEY" \
  | python3 -m json.tool

Each race in data[] has an id, a name, and a startTime. Pick one to edit:

export RACE_ID="<race id from the response>"

4. Edit the race via the API

All write operations need an Idempotency-Key header. Pick a stable client-side identifier — most teams use the user's action UUID or a hash of the intended change. Re-sending the same key with the same body within 24 h returns the cached response; sending it with a different body returns 400.

This PATCH renames a race:

curl -sS -X PATCH "$RR_BASE/v1/events/$EVENT_ID/races/$RACE_ID" \
  -H "Authorization: Bearer $RR_KEY" \
  -H "Idempotency-Key: rename-race-$(date +%s)" \
  -H "Content-Type: application/json" \
  -d '{"name": "Sprint Course — Heat 1"}' \
  | python3 -m json.tool

Expected response (200):

{
  "data": {
    "id": "race_xyz",
    "name": "Sprint Course — Heat 1",
    "startTime": "2026-05-04T07:00:00Z",
    "isDraftingAllowed": true,
    "gender": "open"
  }
}

The change is committed to Firestore immediately and propagates to every connected client in under a second.

Some fields freeze once the race starts

Races have a one-way lifecycle. Competition-defining fields — name, gender, startTime, numberSeries, swimDistanceMeters/bikeDistanceMeters/runDistanceMeters, isDraftingAllowed, penaltyTimeS, draftingTimeS, penaltyBoxEnabled, stopAndGoEnabled, bikePenaltyBoxEnabled, bikePenaltyBoxAmount — can only be changed before the race has started. Once isActive=true (set by an official in the app), a PATCH touching any of them returns 403. Operational toggles (isTrackingEnabled, toRolesEnabled, reduceNotifications) stay editable. Lifecycle (start, stop) is intentionally not exposed via the API — it lives in the officials' app.


5. Verify the edit in the app or web

You don't need to refresh anything — RaceRanger uses live Firestore listeners. Open the event you just edited in either surface:

  • Mobile app — open RaceRanger on a logged-in device, navigate to the event, then the race list. The renamed race appears immediately.
  • Web — open app.raceranger.com, sign in, open the event. The race name reflects the API change the moment the PATCH responded.

If you don't see the change:

  • Make sure you're looking at the right organisation. Org-scoped keys can see every event under their organisation, including ones the current signed-in user might not have role access to.
  • Check the response of step 4 — if you got 200 but the field doesn't match what you sent, double-check field names against the API reference.

6. Tidy up

Whether or not the integration is going to production, two cleanup habits:

  • Don't leave broad-scope keys lying around. Revoke unused keys from the same API keys tab where you minted them. Revocation is immediate (auth cache TTL is 60 s at most).
  • Rotate before expiry. When a key's expiresAt is within a few days, mint its replacement first, point your integration at the new key, then revoke the old one. The pattern is the same as rotating a webhook secret — overlap rather than swap.

What you exercised

Going through this once verifies, in order:

  1. The org-admin minting flow and that the plaintext key is shown exactly once.
  2. The Bearer-token auth path (header parsing, key lookup, scope check).
  3. Cross-event tenant isolation via org-key scoping.
  4. The Idempotency-Key round-trip on a write endpoint.
  5. The pre-start race lifecycle guard.
  6. Firestore live-sync from API write back to mobile / web clients.

For more advanced flows — bulk athlete import, webhook subscriptions for live race events, secret rotation — see the full reference and the webhooks guide.