Your League's Data, In Your Own Tools

Sweeps has a secure, read-only API for pulling your League's Games, Signups, Rounds, and more into a club website's backend, a spreadsheet, or anything else that can make a server-side HTTPS request. (Calls must come from a server, not browser JavaScript — that would expose your key.) You choose exactly which data it shares — per category, per League.

Quickstart

  1. In the app, open Admin → Settings → API Access.
  2. Flip on the master switch, then the data categories you want to share.
  3. Generate an API key (your admin PIN confirms it). The full key is shown exactly once — copy it then.
  4. Send it with every request:
curl -H "Authorization: Bearer swp_your_key_here" \
  https://sweeps.teecrew.app/api/v1/games

Every list endpoint returns the same envelope, paged with limit and offset:

{
  "data": [ ... ],
  "pagination": { "limit": 50, "offset": 0, "hasMore": true }
}

Endpoints

All endpoints are read-only GET requests. Each maps to one data category the commissioner can switch on or off independently. Prefer a machine-readable contract? The full OpenAPI 3.1 spec covers every endpoint, parameter, and response schema below — point your client generator or API tooling at it.

GET /api/v1/gamesGames

The League's Game schedule, newest first.

limitRows per page. Default 50, maximum 200.
offsetRows to skip. Default 0.
statusFilter by Game status: scheduled, in_progress, completed, finalized, or cancelled.

Fields: id, name, date, status, scoringFormat, courseId

GET /api/v1/signupsSignups

Who is currently signed up for each Game (withdrawn signups are excluded).

limitRows per page. Default 50, maximum 200.
offsetRows to skip. Default 0.
game_idOnly signups for this Game (integer id).

Fields: id, gameId (null if the Game record isn't linked yet or the Game was cancelled), playerId, playerName, paymentStatus (null until a payment record exists), inSweepsGame, signedUpAt

GET /api/v1/roundsRounds

Each player's score record per Game, newest first.

limitRows per page. Default 50, maximum 200.
offsetRows to skip. Default 0.
game_idOnly Rounds for this Game (integer id).
include_holesSet to true to attach hole-by-hole detail to each Round.

Fields: id, gameId, playerId, playerName, grossTotal, netTotal, stablefordPoints, status, date — plus holes[] (holeNumber, grossScore, netScore, stablefordPoints, notPlayed) when include_holes=true

GET /api/v1/seriesSeries

The League's Series and their date ranges.

limitRows per page. Default 50, maximum 200.
offsetRows to skip. Default 0.

Fields: id, name, year, startDate, endDate, closedAt

GET /api/v1/playersPlayers

League roster with handicaps. Names and handicaps only — never phone numbers or emails.

limitRows per page. Default 50, maximum 200.
offsetRows to skip. Default 0.

Fields: membershipId, playerId, playerName, handicap, handicapCalculated, handicapStatus, role, isActive

GET /api/v1/paymentsPayments

Amounts and paid status for Game and Series fees, as two lists: gamePayments and seriesPayments. The one endpoint with a different envelope: data holds the two lists, and pagination reports hasMore per list — { limit, offset, gamePayments: { hasMore }, seriesPayments: { hasMore } }.

limitRows per page. Default 50, maximum 200.
offsetRows to skip. Default 0.
game_idOnly gamePayments for this Game (integer id).

Fields: gamePayments: id, gameId, playerId, amount, status, paidAt · seriesPayments: id, seasonYear, playerId, amount, status, paidAt

GET /api/v1/audit-logsActivity Log

The League's admin activity log, newest first.

limitRows per page. Default 50, maximum 200.
offsetRows to skip. Default 0.

Fields: id, actionType, actionCategory, actorRole, targetEntityType, targetEntityId, createdAt

Errors and limits

Errors come back as { "error": { "code", "message" } } with a matching HTTP status:

StatusCodeMeaning
400VALIDATION_ERRORA query parameter is malformed (for example game_id=abc).
401UNAUTHORIZEDMissing, malformed, unknown, or revoked API key.
403FORBIDDENAPI access is off for the League, or this category isn't enabled.
429RATE_LIMITEDToo many requests — honor the Retry-After header and retry.
500INTERNAL_ERRORSomething failed on our side — safe to retry with backoff.

Rate limits: 60 requests per minute per key, plus a shared platform ceiling — so an occasional 429 under 60/min is possible; back off per the Retry-After header. Repeated requests with invalid keys are additionally limited per source IP. Responses are never cached across Leagues.

How it's secured

  • Keys are hashed.Sweeps stores only a SHA-256 hash of your key — it can't be recovered later, by anyone. Lose it and you revoke it and generate a new one.
  • Everything is off by default. The API rejects every request until a commissioner turns it on, and each data category is a separate switch.
  • Keys see one League only. A key is bound to the League that created it, every query is filtered to that League, and database-level row isolation backs that up wherever the underlying table supports it.
  • Read-only by construction. There are no write endpoints — nothing an integration can break.
  • No personal contact data. Player endpoints return names and handicaps, never phone numbers or emails.
  • PIN-confirmed management, audited. Creating or revoking a key and changing permissions all require the admin PIN and land in the League's activity log. Revocation takes effect immediately.

Ready to try it? Open Admin → Settings → API Access in the app, or see everything else Sweeps does on the features page.