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
{
"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:
| 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.