openapi: 3.2.0 info: title: Lucra Forge Recreational Games API description: "See https://docs.lucrasports.com/lucra-sdk/sdks-and-apis for implementation details.\n\n---\n\n## Environments\n\n| Environment | Base URL |\n|-------------|----------|\n| Sandbox | `https://forge.sandbox.lucrasports.com` |\n| Production | `https://forge.lucrasports.com` |\n\nUse sandbox for development and testing. Production credentials are separate and should only be used in live environments.\n\n---\n\n## Authentication\n\nAll requests require an API key passed in the `X-Lucra-Api-Key` header. Keys are provisioned by the Lucra team.\n\n```bash\ncurl https://forge.sandbox.lucrasports.com/api/ \\\n -H \"X-Lucra-Api-Key: \"\n```\n\n> **Note:** Unlike the legacy API, query parameter and request body authentication are not supported.\n\n---\n\n## Rate Limiting\n\nAll API requests are rate-limited per API key using a fixed-window strategy. Each key is allowed up to **100 requests per 10-second window**.\n\nWhen the limit is exceeded, the API responds with **429 Too Many Requests**.\n" version: '1.0' contact: {} servers: - url: / description: Current host - url: https://forge.lucrasports.com description: Production - url: https://forge.sandbox.lucrasports.com description: Sandbox tags: - name: Recreational Games paths: /api/recreational-games/{id}: get: description: 'Retrieve recreational game details by ID. Returns top-level game properties only. For the list of participant users, use `GET /recreational-games/:id/users`.' operationId: RecreationalGamesController_getRecreationalGame parameters: - name: id required: true in: path description: Recreational game UUID schema: type: string responses: '200': description: Recreational game retrieved successfully headers: X-Request-Id: description: Unique request identifier for tracing and debugging. schema: type: string example: req_abc123 content: application/json: schema: $ref: '#/components/schemas/RecreationalGameResponseDto' '404': description: Recreational game not found headers: X-Request-Id: description: Unique request identifier for tracing and debugging. schema: type: string example: req_abc123 content: application/json: schema: $ref: '#/components/schemas/Error' security: - X-Lucra-Api-Key: [] summary: Get Recreational Game tags: - Recreational Games /api/recreational-games/{id}/cancel: post: description: 'Cancel a recreational game and refund all participants. - All participant entry fees are refunded - Game status changes to `CANCELED_THROUGH_API` - Allowed only when status is `OPEN`, `CONFIRMED`, `LOCKED`, or `PENDING_OUTCOMES` - This action is irreversible' operationId: RecreationalGamesController_cancelRecreationalGame parameters: - name: id required: true in: path description: Recreational game UUID schema: type: string responses: '200': description: Recreational game cancelled successfully headers: X-Request-Id: description: Unique request identifier for tracing and debugging. schema: type: string example: req_abc123 content: application/json: schema: $ref: '#/components/schemas/RecreationalGameResponseDto' '404': description: Recreational game not found headers: X-Request-Id: description: Unique request identifier for tracing and debugging. schema: type: string example: req_abc123 content: application/json: schema: $ref: '#/components/schemas/Error' security: - X-Lucra-Api-Key: [] summary: Cancel Recreational Game tags: - Recreational Games /api/recreational-games/scores: post: description: 'Submit scores for one or more users in one or more recreational games. Identifies recreational games via `matchupId`, `matchupMetadata`, or `gameId`. Identifies users via `userId`, `phoneNumber`, or `userMetadata` per entry. Scores are applied to every recreational game that matches the criteria AND has all submitted users as participants. Once a user has `attemptFinished: true` recorded, further submissions for that user are silently ignored. This endpoint returns `202 Accepted` immediately; ingestion is processed asynchronously.' operationId: RecreationalGamesController_ingestScores parameters: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/IngestUserScoreDto' responses: '202': description: '' security: - X-Lucra-Api-Key: [] summary: Ingest scores tags: - Recreational Games /api/recreational-games/{id}/complete: post: description: 'Finalize a recreational game and distribute payouts. ## Outcome Provide exactly one of: - `isTie: true` — declares a full tie. All participants are refunded the buy-in minus their fee share. - `winningGroupIds: [...]` — one or more winning group UUIDs. A single id marks a sole winner; multiple ids mark a partial tie where the prize pool is split among the listed groups. - `winningUsers: [...]` — one or more user identifiers. Each is resolved to its participant group; identifiers must belong to the game. `winningGroupIds` and `winningUsers` may be combined; the union (deduped) determines the winning groups. For a `FREE_FOR_ALL` game, `isTie: true` is rejected. ## Constraints - Status must be `OPEN`, `CONFIRMED`, `LOCKED`, or `PENDING_OUTCOMES` - Games configured with `track_results = AUTOMATED` cannot be completed manually (auto-settlement is owned by the platform) - The game must have at least 2 participant groups ## Async processing This endpoint returns `202 Accepted` immediately. The actual completion is processed asynchronously. Subscribe to the `RecreationalGameCompleted` webhook event to be notified when completion finishes, and to `RecreationalGameCompletionFailed` to be notified of processing errors.' operationId: RecreationalGamesController_completeRecreationalGame parameters: - name: id required: true in: path description: Recreational game UUID schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CompleteRecreationalGameDto' responses: '404': description: Recreational game not found headers: X-Request-Id: description: Unique request identifier for tracing and debugging. schema: type: string example: req_abc123 content: application/json: schema: $ref: '#/components/schemas/Error' security: - X-Lucra-Api-Key: [] summary: Complete Recreational Game tags: - Recreational Games /api/recreational-games/{id}/users: get: description: Returns the paginated list of participant users for a recreational game. Each entry includes the user identity together with the group the user belongs to and the group outcome. operationId: RecreationalGamesController_getRecreationalGameUsers parameters: - name: id required: true in: path description: Recreational game UUID schema: type: string - name: limit required: false in: query description: Number of items to return per page schema: minimum: 1 maximum: 100 default: 25 type: number - name: offset required: false in: query description: Number of items to skip before returning results schema: minimum: 0 default: 0 type: number responses: '200': description: Recreational game users retrieved successfully headers: X-Request-Id: description: Unique request identifier for tracing and debugging. schema: type: string example: req_abc123 Link: description: 'Pagination links per RFC 8288. Relations: `next`, `prev`, `first`.' schema: type: string example: ; rel="next", ; rel="first" content: application/json: schema: type: array items: $ref: '#/components/schemas/RecreationalGameUserResponseDto' '404': description: Recreational game not found headers: X-Request-Id: description: Unique request identifier for tracing and debugging. schema: type: string example: req_abc123 content: application/json: schema: $ref: '#/components/schemas/Error' security: - X-Lucra-Api-Key: [] summary: List Recreational Game Users tags: - Recreational Games components: schemas: RecreationalGameResponseDto: type: object properties: id: type: string description: Unique identifier of the recreational game example: 550e8400-e29b-41d4-a716-446655440000 gameId: type: string description: External game identifier example: DARTS subtype: type: string description: Game format enum: - GROUP_VS_GROUP - FREE_FOR_ALL example: GROUP_VS_GROUP status: type: string description: Lifecycle status of the recreational game enum: - ACTIVE - COMPLETED - CANCELED example: ACTIVE buyIn: type: string description: Entry fee per participant as a decimal string example: '10.00' winningGroupId: type: - object - 'null' description: UUID of the winning group; null until completion example: a1b2c3d4-e5f6-4a5b-8c9d-0e1f2a3b4c5d createdByUserId: type: - object - 'null' description: UUID of the user who created the game example: 7c9e6679-7425-40de-944b-e07fc1f90ae7 isPublic: type: boolean description: Whether the game is publicly discoverable example: true metadata: type: - object - 'null' description: Arbitrary key-value data attached to the game example: externalId: game-123 createdAt: type: - object - 'null' description: Timestamp when the game was created example: '2026-04-30T00:00:00.000Z' closedAt: type: - object - 'null' description: Timestamp when the game was closed; null until completion example: '2026-04-30T01:30:00.000Z' required: - id - gameId - subtype - status - buyIn - winningGroupId - createdByUserId - isPublic - metadata - createdAt - closedAt RecreationalGameUserResponseDto: type: object properties: userId: type: string description: UUID of the user example: user-uuid userMetadata: type: - object - 'null' description: Arbitrary key-value data attached to the user example: externalId: user-external-id groupId: type: string description: UUID of the group example: a1b2c3d4-e5f6-4a5b-8c9d-0e1f2a3b4c5d groupName: type: - object - 'null' description: Display name for the group example: Team A outcome: type: - string - 'null' description: Outcome assigned to this group; null until completion enum: - WIN - LOSS - TIE required: - userId - userMetadata - groupId - groupName - outcome CompleteRecreationalGameOutcomeDto: type: object properties: isTie: type: boolean description: Declare a full tie. Mutually exclusive with winningGroupIds and winningUsers. example: false winningGroupIds: description: UUIDs of the winning participant groups. Single value for a sole winner, multiple for a partial tie. example: - a1b2c3d4-e5f6-4a5b-8c9d-0e1f2a3b4c5d type: array items: type: string winningUsers: description: User identifiers whose groups win. Each entry is resolved to a participant group at request time. type: array items: $ref: '#/components/schemas/WinningUserIdentifierDto' WinningUserIdentifierDto: type: object properties: userId: type: string description: User UUID (preferred when known) example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 phoneNumber: type: string description: User phone number in E.164 format example: '+15551234567' userMetadata: type: object description: Metadata key-value pairs to match a single user CompleteRecreationalGameDto: type: object properties: outcome: description: Outcome details for the game allOf: - $ref: '#/components/schemas/CompleteRecreationalGameOutcomeDto' required: - outcome IngestUserScoreDto: type: object properties: userScores: description: Array of user scores to submit type: array items: $ref: '#/components/schemas/IngestUserScoreEntryDto' matchupId: type: string description: Matchup UUID. One of matchupId, gameId, or matchupMetadata is required. example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 matchupMetadata: type: object description: Metadata key-value pairs to match matchups. One of matchupId, gameId, or matchupMetadata is required. gameId: type: string description: Game identifier to filter matchups. One of matchupId, gameId, or matchupMetadata is required. example: BASKETBALL locationId: type: string description: Location UUID to filter matchups. Applies to tournaments only. example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 required: - userScores Error: type: object properties: code: type: string description: Machine-readable HTTP error code example: NOT_FOUND errCode: type: string description: Machine-readable business error code example: TOURNAMENT_NOT_FOUND message: type: string description: Human-readable error message example: Tournament not found required: - code - errCode - message IngestUserScoreEntryDto: type: object properties: score: type: - object - 'null' description: Numeric score value. Send `null` to clear a previously submitted score. example: 150 userId: type: string description: User UUID. One of userId, phoneNumber, or userMetadata is required. example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 phoneNumber: type: string description: User phone number. One of userId, phoneNumber, or userMetadata is required. example: '+15551234567' userMetadata: type: object description: Metadata key-value pairs to match a user. One of userId, phoneNumber, or userMetadata is required. metadata: type: object description: Arbitrary metadata to attach to the score entry attemptFinished: type: boolean description: Marks the user's attempt as finished. Once set, further submissions for this user are ignored. example: false required: - score securitySchemes: X-Lucra-Api-Key: type: apiKey in: header name: X-Lucra-Api-Key description: API key for tenant authentication