Plus plan · Data API v1

Your club's data, on tap.

The Data API is a read-only REST API for pulling your events and participant data into spreadsheets, warehouses, or your own tools. It's included with the Plus plan.

Exchange your API key for a short-lived access token
A token can only read its own club's data
Tokens live 15 minutes · 120 requests/min per token
Keys are hashed at rest and revocable anytime

Getting started

Authentication is a two-step flow (OAuth2 client-credentials style). Your long-lived API key is only ever used to mint short-lived access tokens; the data endpoints accept only those tokens.

  1. 1. Upgrade your club to Plus (Dashboard → Settings → Billing).
  2. 2. Open Settings → Apps and generate an API key. The full key is shown once — copy it and store it like a password.
  3. 3. Exchange the key for an access token (valid 15 minutes):
curl -X POST -H "Authorization: Bearer jr_YOUR_KEY" \
  https://b.joinrun.club/v1/oauth/token

# → { "access_token": "eyJ…", "token_type": "Bearer", "expires_in": 900 }
  1. 4. Call the data endpoints with the access token. Reuse it until it expires, then mint a new one.
curl -H "Authorization: Bearer eyJ…ACCESS_TOKEN" \
  https://b.joinrun.club/v1/events

Base URL: https://b.joinrun.club. All responses are JSON unless you ask for CSV.

Endpoints

POST/v1/oauth/token

Exchange your API key (sent as the Bearer token) for a short-lived access token. No request body is needed.

{
  "access_token": "eyJhbGciOiJIUzI1NiJ9…",
  "token_type": "Bearer",
  "expires_in": 900
}

Cache the token and reuse it for its full 15-minute lifetime — a well-behaved client mints ~4 tokens per hour. Minting is limited to 10 requests/minute per IP. Key revocation and plan changes take effect at the next mint.

GET/v1/events

List your club's events, newest first, with registration and attendance counts.

  • limitinteger
    Page size, 1–500. Default 100.
  • offsetinteger
    Rows to skip. Default 0.
  • visibilitystring
    Optional filter: public or private.
{
  "object": "list",
  "data": [
    {
      "id": "9f3c…",
      "slug": "sunday-long-run-9f3c12",
      "title": "Sunday Long Run",
      "startAt": "2026-07-12T01:00:00.000Z",
      "endAt": "2026-07-12T03:30:00.000Z",
      "timezone": "Asia/Kolkata",
      "location": "Cubbon Park",
      "visibility": "public",
      "participantCount": 84,
      "attendeeCount": 61,
      "publicUrl": "https://joinrun.club/yourclub/sunday-long-run-9f3c12"
    }
  ],
  "limit": 100,
  "offset": 0,
  "total": 42,
  "hasMore": false
}
GET/v1/events/:id

A single event's details, including its registration form fields — useful for interpreting the answers in the participants feed.

{
  "id": "9f3c…",
  "slug": "sunday-long-run-9f3c12",
  "title": "Sunday Long Run",
  "startAt": "2026-07-12T01:00:00.000Z",
  "endAt": "2026-07-12T03:30:00.000Z",
  "timezone": "Asia/Kolkata",
  "location": "Cubbon Park",
  "locationUrl": "https://maps.google.com/…",
  "description": "Easy pace, all welcome.",
  "visibility": "public",
  "capacity": 120,
  "fields": [
    { "id": "name",  "label": "Full name", "type": "text",  "required": true },
    { "id": "email", "label": "Email",     "type": "email", "required": true }
  ],
  "participantCount": 84,
  "attendeeCount": 61,
  "publicUrl": "https://joinrun.club/yourclub/sunday-long-run-9f3c12"
}
GET/v1/events/:id/participants

Registrations for one event, merged with attendance. Answers are keyed by the event's field ids.

  • limitinteger
    Page size, 1–500. Default 100.
  • offsetinteger
    Rows to skip. Default 0.
  • formatstring
    json (default) or csv for a ready-to-open export.
{
  "object": "list",
  "eventId": "9f3c…",
  "fields": [
    { "id": "name",  "label": "Full name", "type": "text",  "required": true },
    { "id": "email", "label": "Email",     "type": "email", "required": true }
  ],
  "data": [
    {
      "id": "77aa…",
      "submittedAt": "2026-07-08T14:03:22.000Z",
      "answers": { "name": "Priya Sharma", "email": "priya@example.com" },
      "attended": true,
      "attendedAt": "2026-07-12T01:12:41.000Z"
    }
  ],
  "limit": 100,
  "offset": 0,
  "total": 84,
  "hasMore": false
}

CSV export of the same data:

curl -H "Authorization: Bearer eyJ…ACCESS_TOKEN" \
  "https://b.joinrun.club/v1/events/EVENT_ID/participants?format=csv" \
  -o participants.csv

Pagination

List endpoints return total and hasMore. To fetch everything, keep requesting with offset += limit until hasMore is false.

Errors

Errors use conventional HTTP status codes with a JSON body: { "error": "…" }

StatusMeaning
401 unauthorizedMissing/revoked API key on mint, or a missing/expired access token on a data route. If a previously working token starts returning 401, it has expired — mint a new one.
403 forbiddenThe club's Plus subscription is no longer active.
404 not_foundNo such event in your club — other clubs' events always 404.
429 rate_limitedOver 120 requests/minute on data routes, or over 10 mints/minute — back off and retry.

Keep your key safe

Ready to build?

Upgrade to Plus and generate your first key in minutes.

See pricing