Skip to content

API integrations

Public beta

The HTTP API is in public beta. Endpoints and authentication are stable. The production endpoint is now active on the API Gateway; the hostname will move to api.raceranger.com once DNS is live. Update your base URL when that happens — no other change is required.

RaceRanger exposes a read-and-write HTTP API for organisations that want to push athlete data in, pull live race results out, or subscribe to webhook deliveries when something changes during a race.

The API is intended for organisation tooling, federation integrations, and reporting pipelines. The mobile app itself does not use this API — it talks to Firebase directly.

Base URLs

Environment Current URL Planned URL
Production Active — see your API key welcome email for the current URL https://api.raceranger.com
Testing https://raceranger-api-2wm0cky.ew.gateway.dev https://api-test.raceranger.com

All paths are versioned under /v1. The current version is v1; any breaking changes will ship under a new prefix.

In this section

  • Quickstart — zero to a verified live edit: mint a key, make a write, see it land in the app.
  • Authentication — API key tiers, scopes, how to mint a key from inside the app.
  • Webhooks — subscribing to live event deliveries, verifying HMAC signatures, retries.
  • Reference — full OpenAPI reference for every endpoint, including request and response schemas.

Quick example

curl https://raceranger-api-2wm0cky.ew.gateway.dev/v1/events \
  -H "Authorization: Bearer rr_o_..."
{
  "data": [
    {
      "id": "evt_abc",
      "name": "Spring Sprint 2026",
      "sport": "triathlon",
      "dateFrom": "2026-05-04T07:00:00Z",
      "isOver": false
    }
  ]
}

Rate limits

Default per-key limits are 120 requests/minute and 1000 requests/hour. Every successful response includes X-RateLimit-Limit-Minute and X-RateLimit-Limit-Hour headers. When a key exceeds its limit the API returns HTTP 429 with a Retry-After header — wait the requested number of seconds before retrying.

Idempotency

All write endpoints (POST, PATCH, bulk imports, webhook creation) require an Idempotency-Key header. Pick a stable client-generated key between 8 and 128 characters. Reusing the same key with the same body within 24 hours returns the cached response; reusing the same key with a different body returns 400.

Errors

Errors follow a single shape:

{
  "error": {
    "code": "forbidden",
    "message": "Key lacks required scope: write:events"
  }
}
Status Meaning
400 Bad request — validation failed or idempotency mismatch.
401 Missing or invalid API key.
403 Key lacks the required scope, or the key is not authorised for the requested resource.
404 The resource does not exist or the key cannot see it.
429 Rate limit exceeded.

Malformed JSON returns 500

If you send Content-Type: application/json with a body that isn't valid JSON, the request returns 500 Internal Server Error with Content-Type: text/plain instead of our usual typed JSON error. This is a Cloud Functions runtime quirk — the platform's body parser runs before our error handler can catch the parse failure. Validate your JSON client-side, or always JSON.stringify(...) before sending.