LIVE
Cal BearsM V8+ SDCC 20265:48.2++18 ELO
HarvardM V8+ EARC Sprint5:52.1++12 ELO
WashingtonW V8+ Pac-126:24.8++9 ELO
StanfordM V4+ SDCC 20266:31.4-5 ELO
YaleW V4+ EARC Sprint7:02.3++22 ELO
PrincetonM V8+ EARC Sprint5:55.7++6 ELO
PennW V8+ EARC Sprint6:28.9++14 ELO
MITM 2x Charles6:44.1-3 ELO
Cal BearsM V8+ SDCC 20265:48.2++18 ELO
HarvardM V8+ EARC Sprint5:52.1++12 ELO
WashingtonW V8+ Pac-126:24.8++9 ELO
StanfordM V4+ SDCC 20266:31.4-5 ELO
YaleW V4+ EARC Sprint7:02.3++22 ELO
PrincetonM V8+ EARC Sprint5:55.7++6 ELO
PennW V8+ EARC Sprint6:28.9++14 ELO
MITM 2x Charles6:44.1-3 ELO
Getting StartedOverviewAuthenticationError Handling
Timing PartnersOverviewHereNOWAll Partners
Results APIGET /resultsGET /rankings
WebSocketConnectionEvents
Stripe & DonationsCheckoutDonationsWebhooks
Overview

The RegattaStream API is a REST + WebSocket API for live race result ingestion, rankings retrieval, and fan donation processing. It is designed to receive webhooks from any of 8 timing partners and broadcast results in real time to all connected clients.

REST API
Base URL: /api
🔌
WebSocket
Live race events & rankings updates
🤖
Claude AI
Narratives auto-generated 2s post-official
Authentication

Public read endpoints (/api/results, /api/rankings, /api/library) require no authentication. Timing partner webhooks are currently open — we recommend adding X-RS-Partner-Key validation before going live.

Admin endpoints require a JWT Bearer token obtained from POST /api/admin/login.

# Admin endpoints
Authorization: Bearer <jwt_token>

# Recommended timing partner auth (add to server.js)
X-RS-Partner-Key: <partner_secret>
Timing Partner Webhooks

Each timing platform posts results to its own endpoint. RegattaStream normalizes all payloads, runs the Speed Order™ update, generates an AI story via Claude, and broadcasts to all WebSocket clients within ~2 seconds.

POST/api/timing/:partnerAccepts race results from any timing partnerOpen

:partner must be one of: herenow, regattamaster, regattacentral, crewtimer, timeteam, regattatiming, rowtimer, clockcaster

HereNOW Integration

Primary partner for SDCC 2026. Configure your HereNOW account to POST results to:

POST https://regattastream.com/api/timing/herenow
Payload Format
{
  "regatta_name": "San Diego Crew Classic 2026",
  "event_name":   "Men's Varsity 8+",
  "heat":          "Final",
  "distance_m":   2000,
  "start_time":   "2026-04-05T09:14:00Z",
  "results": [
    {
      "place":        1,
      "club_name":    "Cal Bears",
      "time_display": "5:48.2",
      "time_ms":      348200,
      "margin":       ""
    },
    {
      "place":        2,
      "club_name":    "Washington",
      "time_display": "5:48.6",
      "time_ms":      348600,
      "margin":       "+0.4"
    }
  ]
}
Parameters
FieldTypeRequiredDescription
regatta_namestringRequiredFull regatta name — used for grouping and display
event_namestringRequiredEvent label e.g. "Men's Varsity 8+"
heatstringOptionalHeat identifier — "Final", "Heat 1", etc.
distance_mnumberOptionalRace distance in meters (default 2000)
start_timeISO 8601OptionalRace start time in UTC
resultsarrayRequiredArray of finisher objects (see below)
results[].placenumberRequiredFinishing position (1-based)
results[].club_namestringRequiredClub/team name — matched to Club database
results[].time_msnumberRequiredElapsed time in milliseconds
results[].time_displaystringOptionalHuman-readable time e.g. "5:48.2"
All Partners
LiveSDCC 2026
HereNOW
POST /api/timing/herenow
Primary SDCC 2026 partner. Configure webhook URL in HereNOW admin dashboard under "Result Delivery".
LiveSDCC 2026
RegattaMaster
POST /api/timing/regattamaster
Secondary SDCC 2026 partner. Add webhook URL in RegattaMaster event settings under "Integrations".
Active
RegattaCentral
POST /api/timing/regattacentral
Full integration. Contact RegattaCentral support to add your webhook endpoint to your event series.
Active
CrewTimer
POST /api/timing/crewtimer
Configure in CrewTimer event settings → Webhooks → Add Endpoint. Supports real-time and batch delivery.
Active
Time-Team
POST /api/timing/timeteam
European timing platform. Webhook configuration in the Time-Team portal under "Data Export".
Active
RegattaTiming
POST /api/timing/regattatiming
Masters-heavy platform. Supports age-adjusted results and para classifications natively.
Active
RowTimer
POST /api/timing/rowtimer
Lightweight timing solution popular at head race events. JSON webhook payload format.
Active
ClockCaster
POST /api/timing/clockcaster
Broadcast-focused timing platform. Webhook available in ClockCaster Pro and Enterprise tiers.
Results API
GET/api/resultsPaginated race results with optional filtersPublic
ParameterTypeDefaultDescription
pagenumber1Page number
limitnumber20Results per page (max 100)
regattastringFilter by regatta name (partial match)
eventstringFilter by event name
categorystringcollegiate, junior, masters, para, lightweight, club
clubstringFilter by club name
Response
{
  "races": [
    {
      "_id": "abc123",
      "regattaName": "SDCC 2026",
      "event": "Men's Varsity 8+",
      "timingPartner": "herenow",
      "officialAt": "2026-04-05T09:14:28Z",
      "aiStory": "Cal holds off Washington...",
      "results": [
        {
          "place": 1,
          "club":  "Cal Bears",
          "time":  "5:48.2",
          "eloBefore": 1740,
          "eloAfter":  1759,
          "eloDelta":  19
        }
      ]
    }
  ],
  "total": 142,
  "page":  1,
  "pages": 8
}
Speed Order™ Rankings
GET/api/rankingsSpeed Order™ rankings by categoryPublic
ParameterTypeDefaultDescription
categorystringcollegiatecollegiate · junior · masters · para · lightweight · club · novice
limitnumber25Number of clubs to return (max 200)
WebSocket Events

Connect to the same host as the HTTP server — no separate port required. All race results, AI stories, and ranking updates are broadcast in real time.

const ws = new WebSocket(
  `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}`
);

ws.onmessage = (e) => {
  const msg = JSON.parse(e.data);

  switch (msg.type) {
    case 'race_result': handleResult(msg.data);    break;
    case 'story':       handleStory(msg.data);     break;
    case 'speed_order': updateRankings(msg.data);  break;
    case 'new_content': showLibraryCard(msg.data); break;
  }
};

ws.onclose = () => setTimeout(connect, 3000); // auto-reconnect
WebSocket Event Types
race_result

Broadcast immediately when a timing partner POST is received and processed. Contains full results array with Speed Order™ deltas, regatta name, event name, and timing partner.

story

Broadcast ~2 seconds after race_result once Claude generates the AI narrative. Contains raceId and story string. Match to result card by raceId.

speed_order

Broadcast after Speed Order™ recalculation. Contains array of { club, elo, delta } objects for all clubs affected by the race.

new_content

Broadcast when admin publishes a new article or video. Contains { type, title, slug, category }.

Stripe Checkout
POST/api/stripe/checkoutCreate a Stripe Checkout Session (30-day trial)
POST/api/stripe/portalOpen Stripe Billing Portal for plan management
⚠ Webhook Setup Required

Add https://yourdomain.com/api/stripe/webhook in your Stripe Dashboard → Webhooks. Listen for: checkout.session.completed, customer.subscription.deleted, payment_intent.succeeded

Fan Donations

Fan donations route 88% directly to the club via Stripe Connect. Each donation creates a PaymentIntent with automatic transfer to the club's connected Stripe account.

POST/api/donateCreate fan donation PaymentIntent with auto-transfer to club
FieldTypeRequiredDescription
clubSlugstringRequiredClub identifier — must match a Club document with stripeAccountId
amountnumberRequiredAmount in USD (minimum $1)
messagestringOptionalOptional message from donor to club
Stripe Webhooks
POST/api/stripe/webhookStripe webhook — handles subscription + payment events
EventActionNotes
checkout.session.completedActivate subscriptionSets club.stripeStatus = "active"
customer.subscription.deletedDeactivate subscriptionSets club.stripeStatus = "inactive"
payment_intent.succeededRecord donation receiptLogs to Donation collection, triggers thank-you email
Error Handling

All errors return a JSON body with an error field.

HTTP StatusMeaningNotes
200SuccessRequest processed normally
400Bad RequestMissing required fields — check payload structure
401UnauthorizedMissing or invalid JWT — required for admin routes
404Not FoundResource does not exist
500Server ErrorCheck server logs — often MongoDB or Stripe connection
📧 For integration support: hello@regattastream.com