{"openapi":"3.1.0","info":{"title":"The Backend Lobby Competition API","version":"1.0.0","summary":"Programmatic competition management API","description":"AWS-hosted API for creating competitions, registering participants, generating single-elimination events, and submitting match results. All /v1 routes require a Cognito JWT.","contact":{"name":"The Backend Lobby"}},"jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","servers":[{"url":"https://api.thebackendlobby.com","description":"Deployed API custom domain"}],"tags":[{"name":"System","description":"Unauthenticated health and API-description endpoints."},{"name":"Competitions","description":"Competition lifecycle and configuration."},{"name":"Participants","description":"Competition participant registration and listing."},{"name":"Events","description":"Asynchronous event generation."},{"name":"Matches","description":"Match result submission."},{"name":"Developer Portal","description":"Identity, organizations, credentials, webhooks, and usage."}],"paths":{"/health":{"get":{"tags":["System"],"operationId":"getHealth","summary":"Check service health","security":[],"responses":{"200":{"description":"Service is available.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/docs/openapi.json":{"get":{"tags":["System"],"operationId":"getOpenApiDocument","summary":"Download this OpenAPI document","security":[],"responses":{"200":{"description":"OpenAPI 3.1 document.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/v1/me":{"get":{"tags":["Developer Portal"],"operationId":"getCurrentUser","summary":"Get the authenticated identity","responses":{"200":{"description":"Authenticated identity."},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/organizations":{"get":{"tags":["Developer Portal"],"operationId":"listOrganizations","summary":"List organizations owned by the current user","responses":{"200":{"description":"Organization collection."}}},"post":{"tags":["Developer Portal"],"operationId":"createOrganization","summary":"Create an organization","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"201":{"description":"Organization created."}}}},"/v1/organizations/{organizationId}":{"get":{"tags":["Developer Portal"],"operationId":"getOrganization","summary":"Get an owned organization","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Organization."},"403":{"description":"Not the organization owner."}}}},"/v1/organizations/{organizationId}/clients":{"get":{"tags":["Developer Portal"],"operationId":"listDeveloperClients","summary":"List developer clients","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Client collection without secrets."}}},"post":{"tags":["Developer Portal"],"operationId":"createDeveloperClient","summary":"Create a developer credential","description":"The plaintext client secret is returned once. OAuth token exchange is a roadmap capability.","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Credential created."}}}},"/v1/organizations/{organizationId}/webhooks":{"get":{"tags":["Developer Portal"],"operationId":"listWebhooks","summary":"List webhook registrations","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook collection."}}},"post":{"tags":["Developer Portal"],"operationId":"createWebhook","summary":"Register a webhook","description":"Stores webhook configuration. Delivery workers are a roadmap capability.","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Webhook registered."}}}},"/v1/organizations/{organizationId}/usage":{"get":{"tags":["Developer Portal"],"operationId":"getOrganizationUsage","summary":"Get current organization usage totals","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage summary."}}}},"/v1/competitions":{"post":{"tags":["Competitions"],"operationId":"createCompetition","summary":"Create a competition","description":"Creates a competition in DRAFT status. Supply an Idempotency-Key for retry-safe creation.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCompetitionRequest"}}}},"responses":{"201":{"description":"Competition created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Competition"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"500":{"$ref":"#/components/responses/InternalError"}}},"get":{"tags":["Competitions"],"operationId":"listCompetitions","summary":"List competitions for an organization","parameters":[{"name":"organizationId","in":"query","required":true,"description":"Organization identifier used when the competitions were created.","schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Competition collection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompetitionList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/competitions/{competitionId}":{"parameters":[{"$ref":"#/components/parameters/CompetitionId"}],"get":{"tags":["Competitions"],"operationId":"getCompetition","summary":"Get a competition","responses":{"200":{"description":"Competition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Competition"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"tags":["Competitions"],"operationId":"updateCompetition","summary":"Update a competition","description":"Uses optimistic concurrency. expectedVersion must equal the current competition version.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCompetitionRequest"}}}},"responses":{"200":{"description":"Updated competition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Competition"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/competitions/{competitionId}/participants":{"parameters":[{"$ref":"#/components/parameters/CompetitionId"}],"post":{"tags":["Participants"],"operationId":"registerParticipant","summary":"Register a participant","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterParticipantRequest"}}}},"responses":{"201":{"description":"Participant registered.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Participant"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}}},"get":{"tags":["Participants"],"operationId":"listParticipants","summary":"List competition participants","responses":{"200":{"description":"Participant collection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParticipantList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/competitions/{competitionId}/generate-event":{"parameters":[{"$ref":"#/components/parameters/CompetitionId"}],"post":{"tags":["Events"],"operationId":"generateEvent","summary":"Queue event generation","description":"Queues asynchronous event generation. The current worker supports SINGLE_ELIMINATION competitions.","responses":{"202":{"description":"Command accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptedCommand"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"description":"Command queue unavailable.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/competitions/{competitionId}/matches":{"parameters":[{"$ref":"#/components/parameters/CompetitionId"}],"get":{"tags":["Matches"],"operationId":"listMatches","summary":"List competition matches","description":"Returns generated matches ordered by round and event position. Clients can poll this endpoint after queuing event generation.","responses":{"200":{"description":"Match collection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/competitions/{competitionId}/matches/{matchId}/result":{"parameters":[{"$ref":"#/components/parameters/CompetitionId"},{"$ref":"#/components/parameters/MatchId"}],"post":{"tags":["Matches"],"operationId":"submitMatchResult","summary":"Submit a match result","description":"Marks a match COMPLETED when the winner belongs to the match and expectedVersion is current.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitMatchResultRequest"}}}},"responses":{"200":{"description":"Completed match.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Match"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"500":{"$ref":"#/components/responses/InternalError"}}}}},"components":{"securitySchemes":{"cognitoJwt":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT issued by the Cognito user pool created by the CDK stack."}},"parameters":{"CompetitionId":{"name":"competitionId","in":"path","required":true,"schema":{"type":"string","minLength":1},"example":"01JABCDEF1234567890ABCDEFX"},"MatchId":{"name":"matchId","in":"path","required":true,"schema":{"type":"string","minLength":1},"example":"01JABCDEF1234567890ABCDEFM"},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Client-generated unique key for retry-safe competition creation.","schema":{"type":"string","minLength":1,"maxLength":200},"example":"create-summer-2026-001"}},"responses":{"BadRequest":{"description":"Invalid JSON, missing input, or schema validation failure.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"Unauthorized":{"description":"Missing, expired, or invalid JWT.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"NotFound":{"description":"Requested resource was not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"Conflict":{"description":"Optimistic version conflict or duplicate resource.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"InternalError":{"description":"Unexpected server error.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"schemas":{"HealthResponse":{"type":"object","required":["status","stage"],"additionalProperties":false,"properties":{"status":{"type":"string","const":"ok"},"stage":{"type":"string","example":"dev"}}},"CompetitionFormat":{"type":"string","enum":["SINGLE_ELIMINATION","DOUBLE_ELIMINATION","ROUND_ROBIN","SWISS","LADDER","FREE_FOR_ALL","CUSTOM"]},"CompetitionStatus":{"type":"string","enum":["DRAFT","REGISTRATION","PENDING","RUNNING","PAUSED","COMPLETED","CANCELLED"]},"ParticipantType":{"type":"string","enum":["INDIVIDUAL","TEAM","BOT"]},"MatchStatus":{"type":"string","enum":["PENDING","READY","RUNNING","COMPLETED","CANCELLED","FORFEIT"]},"Metadata":{"type":"object","additionalProperties":true,"default":{}},"Rules":{"type":"object","additionalProperties":true,"default":{}},"CreateCompetitionRequest":{"type":"object","required":["organizationId","name","format"],"additionalProperties":false,"properties":{"organizationId":{"type":"string","minLength":1,"example":"org_demo"},"name":{"type":"string","minLength":1,"maxLength":200,"example":"Summer Championship"},"description":{"type":"string","maxLength":4000},"format":{"$ref":"#/components/schemas/CompetitionFormat"},"rules":{"$ref":"#/components/schemas/Rules"},"metadata":{"$ref":"#/components/schemas/Metadata"}}},"UpdateCompetitionRequest":{"type":"object","required":["expectedVersion"],"additionalProperties":false,"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":4000},"status":{"$ref":"#/components/schemas/CompetitionStatus"},"rules":{"$ref":"#/components/schemas/Rules"},"metadata":{"$ref":"#/components/schemas/Metadata"},"expectedVersion":{"type":"integer","minimum":1,"example":1}}},"Competition":{"allOf":[{"$ref":"#/components/schemas/CreateCompetitionRequest"},{"type":"object","required":["id","status","version","createdAt","updatedAt"],"additionalProperties":false,"properties":{"id":{"type":"string"},"status":{"$ref":"#/components/schemas/CompetitionStatus"},"version":{"type":"integer","minimum":1},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}]},"CompetitionList":{"type":"object","required":["items"],"additionalProperties":false,"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Competition"}}}},"RegisterParticipantRequest":{"type":"object","required":["displayName"],"additionalProperties":false,"properties":{"displayName":{"type":"string","minLength":1,"maxLength":200,"example":"Player One"},"type":{"$ref":"#/components/schemas/ParticipantType"},"seed":{"type":"integer","minimum":1},"metadata":{"$ref":"#/components/schemas/Metadata"}}},"Participant":{"allOf":[{"$ref":"#/components/schemas/RegisterParticipantRequest"},{"type":"object","required":["id","competitionId","createdAt"],"properties":{"id":{"type":"string"},"competitionId":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}]},"ParticipantList":{"type":"object","required":["items"],"additionalProperties":false,"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Participant"}}}},"AcceptedCommand":{"type":"object","required":["commandId","status"],"additionalProperties":false,"properties":{"commandId":{"type":"string"},"status":{"type":"string","const":"ACCEPTED"}}},"SubmitMatchResultRequest":{"type":"object","required":["winnerId","scores","expectedVersion"],"additionalProperties":false,"properties":{"winnerId":{"type":"string","minLength":1},"scores":{"type":"object","additionalProperties":{"type":"number"},"example":{"participant_1":3,"participant_2":1}},"expectedVersion":{"type":"integer","minimum":1}}},"Match":{"type":"object","required":["id","competitionId","round","position","participantIds","status","version","createdAt","updatedAt"],"additionalProperties":false,"properties":{"id":{"type":"string"},"competitionId":{"type":"string"},"round":{"type":"integer","minimum":1},"position":{"type":"integer","minimum":0},"participantIds":{"type":"array","items":{"type":"string"}},"winnerId":{"type":"string"},"scores":{"type":"object","additionalProperties":{"type":"number"}},"status":{"$ref":"#/components/schemas/MatchStatus"},"version":{"type":"integer","minimum":1},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"MatchList":{"type":"object","required":["items"],"additionalProperties":false,"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Match"}}}},"Problem":{"type":"object","required":["type","title","status"],"additionalProperties":false,"properties":{"type":{"type":"string","example":"about:blank"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"}}}}},"security":[{"cognitoJwt":[]}]}