{"activeVersionTag":"latest","latestAvailableVersionTag":"latest","collection":{"info":{"_postman_id":"9a3c764b-04e6-413c-8cbf-4ad7d18c5c16","name":"TournamentAPI","description":"TournamentAPI is a GraphQL API for running tournaments: creating them, taking entries, generating brackets, and recording match results. It's built with .NET 9, HotChocolate, and EF Core, backed by SQL Server.\n\n## Endpoint\n\n`POST https://localhost:7048/graphql` (also set as `graphqlUrl` in this collection's environment). Run the API locally with `dotnet run --project TournamentAPI` from the repo root. It uses a self-signed dev certificate, so you'll likely need to turn off SSL certificate verification for `localhost` in Postman's settings.\n\n## Authentication and authorization\n\nTwo separate checks apply to every request.\n\nFirst, an API key. Every call to `/graphql` needs an `X-API-Key` header, checked before any query or mutation runs. This collection adds it automatically through a pre-request script, reading the `apiKey` environment variable (already set to the local dev key from `appsettings.Development.json`).\n\nSecond, a JWT bearer token. Fields marked `[Authorize]`, which is most mutations plus `me`, also need `Authorization: Bearer <token>`. Get one from Authentication > Login User; this collection saves it to the `accessToken` environment variable automatically, and every request's Authorization tab already points at `{{accessToken}}`. Tokens expire after 10 minutes, so re-run Login User or Refresh Token when yours does.\n\n## Getting started\n\nRun Authentication > Register User once to create an account, or use one you already have. Then run Authentication > Login User: the access token is saved for you, and the server also sets an httpOnly `refreshToken` cookie that Postman's cookie jar picks up, so keep \"Send cookies\" enabled. From there, any other request in the collection already has its token and API key header wired up. When the token expires, run Refresh Token instead of logging in again.\n\n## Schema overview\n\nThe full schema definition is published in this workspace as a GraphQL spec (\"TournamentAPI GraphQL Schema\"), mirroring the repo's `schema.graphql`. Here's the shape you'll see in every request and response in this collection.\n\n`Query` has three fields: `tournaments` (paged, filterable, sortable), `tournamentById`, and `me`.\n\nEvery `Mutation` field returns a payload type named after the mutation itself (`createTournament` returns `CreateTournamentPayload`), with one field holding the actual result: an entity (`tournament`, `bracket`, `applicationUser`) or a bare scalar (`boolean`, `string`). That's why every request here selects a field with that name instead of the entity directly.\n\nCore types: `ApplicationUser` (profile, plus `playedTournaments`, `wonTournaments`, and `wonMatches` connections), `Tournament` (`owner`, `champion`, `bracket`, and a `participants` connection), `Bracket` (`matchesByBracket` connection), `Match` (`player1`, `player2`, `winner`, and the `version` concurrency token), and `TournamentParticipant` (links a user to a tournament with a `slotNumber`).\n\nEvery connection (`TournamentConnection`, `MatchConnection`, `TournamentParticipantConnection`) follows the same shape: `edges { node, cursor }`, `nodes`, `pageInfo`, and `totalCount`.\n\nThe schema also declares an `Error` interface (`message: String!`), but no payload implements it. Errors surface through the top-level `errors[]` array instead, as documented below.\n\n## Limits\n\nQuery depth is capped at 10, field cost at 3000, and execution at 30 seconds. Requests are rate-limited per IP (a 100-token bucket refilling 50 tokens a minute) plus a global cap of 100 concurrent requests.\n\n## Enums\n\n- `TournamentStatus`: `OPEN`, `CLOSED`, `COMPLETED`\n- `MatchStatus`: `SCHEDULED`, `PLAYED`, `NEEDS_REPLAY` (read-only, set indirectly through Play and Correct Match Result)\n\n## Error codes\n\nThese show up in `errors[].extensions.code` on a failed response, not in the payload itself.\n\n- Auth: `AUTH_API_KEY_INVALID`, `User.InvalidCredentials`, `User.AccountLockedOut`, `User.RegistrationFailed`, `User.RefreshTokenExpired`, `User.RefreshTokenInvalid`, `User.RefreshTokenReused`, `User.RefreshTokenConflict`\n- Tournament: `Tournament.NotFound`, `Tournament.NotOwner`, `Tournament.Closed`, `Tournament.Full`, `Tournament.UserAlreadyParticipant`, `Tournament.NameEmpty`, `Tournament.InvalidMaxParticipants`, `Tournament.MaxParticipantsBelowParticipantCount`, `Tournament.StartDateTooSoon`, `Tournament.CannotReopenWithBracket`, `Tournament.CannotReopenAfterStartDate`, `Tournament.CannotDeleteWithBracket`, `Tournament.StatusCannotBeSetManually`, `Tournament.CannotChangeCompletedStatus`\n- Bracket: `Bracket.AlreadyExists`, `Bracket.NotEnoughParticipants`, `Bracket.NotFound`, `Bracket.NoMatchesInRound`, `Bracket.NotAllMatchesPlayed`, `Bracket.GenerationNotAllowed`, `Bracket.NextRoundAlreadyGenerated`, `Bracket.RoundUpdateNotAllowed`, `Bracket.RoundDataChanged`\n- Match: `Match.NotFound`, `Match.AlreadyPlayed`, `Match.InvalidWinner`, `Match.TournamentNotClosed`, `Match.NegativeScore`, `Match.WinnerScoreMismatch`, `Match.NotYetPlayed`, `Match.NeedsReplay`, `Match.InvalidVersionToken`, `Match.VersionConflict`\n\n## Folders\n\nAuthentication (account and session lifecycle) leads into Users (your own profile), then Tournaments (list, create, manage), Participants (owner adding someone directly), Brackets (generate and advance), and Matches (record and correct results). Running them in that order works well the first time through.","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","isPublicCollection":false,"owner":"43726594","team":16688905,"collectionId":"9a3c764b-04e6-413c-8cbf-4ad7d18c5c16","publishedId":"2sBYB1N89c","public":true,"publicUrl":"https://documenter-api.postman.tech/view/43726594/2sBYB1N89c","privateUrl":"https://go.postman.co/documentation/43726594-9a3c764b-04e6-413c-8cbf-4ad7d18c5c16","customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"},"documentationLayout":"classic-double-column","customisation":{"metaTags":[{"name":"description","value":"TournamentAPI is a GraphQL-based web API for managing tournaments, participants, and brackets. It supports user registration, authentication via JWT, tournament creation and management, participant handling, bracket generation, and match play. The API is designed for extensibility and secure access, leveraging modern ."},{"name":"title","value":""}],"appearance":{"default":"dark","themes":[{"name":"dark","logo":null,"colors":{"top-bar":"212121","right-sidebar":"303030","highlight":"FF6C37"}},{"name":"light","logo":null,"colors":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"}}]}},"version":"8.12.6","publishDate":"2026-09-17T11:57:57.000Z","activeVersionTag":"latest","documentationTheme":"light","metaTags":{"title":"","description":"TournamentAPI is a GraphQL-based web API for managing tournaments, participants, and brackets. It supports user registration, authentication via JWT, tournament creation and management, participant handling, bracket generation, and match play. The API is designed for extensibility and secure access, leveraging modern ."},"logos":{"logoLight":null,"logoDark":null}},"statusCode":200},"environments":[{"name":"TournamentAPI - Local (HTTPS)","id":"8084498c-f63b-4fbe-aa60-dccf1d6654f4","owner":"43726594","values":[{"key":"baseUrl","value":"https://localhost:7048","enabled":true,"type":"default","description":"Local HTTPS profile from launchSettings.json. HTTPS is required because the refreshToken cookie is Secure."},{"key":"graphqlUrl","value":"{{baseUrl}}/graphql","enabled":true,"type":"default","description":"The single GraphQL endpoint every request in this collection targets."},{"key":"apiKey","value":"pk_test_3K7s9x2mPq8vN4Lr6Hf2bT5wX1yZ8cD3eF7gH9jK","enabled":true,"type":"secret","description":"X-API-Key header value, required on every request. This is the local dev key from appsettings.Development.json - swap it for the target environment's key elsewhere."},{"key":"accessToken","value":"","enabled":true,"type":"secret","description":"JWT bearer token. Filled automatically by the Login User and Refresh Token requests' test scripts."},{"key":"userEmail","value":"alice@example.com","enabled":true,"type":"default","description":"Example account email used by Register User and Login User."},{"key":"userPassword","value":"Password123!","enabled":true,"type":"secret","description":"Example account password used by Register User and Login User."},{"key":"tournamentId","value":"1","enabled":true,"type":"default","description":"Tournament id used across the Tournaments/Participants/Brackets requests. Auto-updated after Create Tournament."},{"key":"bracketId","value":"1","enabled":true,"type":"default","description":"Bracket id used by Update Round. Auto-updated after Generate Bracket."},{"key":"matchId","value":"1","enabled":true,"type":"default","description":"Match id used by Play and Correct Match Result."},{"key":"winnerId","value":"1","enabled":true,"type":"default","description":"User id of the declared match winner, used by Play and Correct Match Result."},{"key":"userId","value":"2","enabled":true,"type":"default","description":"User id used by Add Participant (the participant being added, not the caller)."},{"key":"roundNumber","value":"1","enabled":true,"type":"default","description":"Round number used by Update Round."},{"key":"matchVersion","value":"","enabled":true,"type":"default","description":"Opaque optimistic-concurrency token for a match, required by Correct Match Result. Read it from Get Tournament By Id's bracket.matchesByBracket.version field."}],"published":true}],"user":{"authenticated":false,"permissions":{"publish":false}},"run":{"button":{"js":"https://run.pstmn.io/button.js","css":"https://run.pstmn.io/button.css"}},"web":"https://www.getpostman.com/","team":{"logo":"https://res.cloudinary.com/postman/image/upload/t_team_logo_pubdoc/v1/team/b636de0ffd85610dedb81b0fe5d12b55bfc6fa43c910cfaf5206d8b4590cff71","favicon":""},"isEnvFetchError":false,"languages":"[{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"HttpClient\"},{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"RestSharp\"},{\"key\":\"curl\",\"label\":\"cURL\",\"variant\":\"cURL\"},{\"key\":\"dart\",\"label\":\"Dart\",\"variant\":\"http\"},{\"key\":\"go\",\"label\":\"Go\",\"variant\":\"Native\"},{\"key\":\"http\",\"label\":\"HTTP\",\"variant\":\"HTTP\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"OkHttp\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"Unirest\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"Fetch\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"jQuery\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"XHR\"},{\"key\":\"c\",\"label\":\"C\",\"variant\":\"libcurl\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Axios\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Native\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Request\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Unirest\"},{\"key\":\"objective-c\",\"label\":\"Objective-C\",\"variant\":\"NSURLSession\"},{\"key\":\"ocaml\",\"label\":\"OCaml\",\"variant\":\"Cohttp\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"cURL\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"Guzzle\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"HTTP_Request2\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"pecl_http\"},{\"key\":\"powershell\",\"label\":\"PowerShell\",\"variant\":\"RestMethod\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"http.client\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"Requests\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"httr\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"RCurl\"},{\"key\":\"ruby\",\"label\":\"Ruby\",\"variant\":\"Net::HTTP\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"Httpie\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"wget\"},{\"key\":\"swift\",\"label\":\"Swift\",\"variant\":\"URLSession\"}]","languageSettings":[{"key":"csharp","label":"C#","variant":"HttpClient"},{"key":"csharp","label":"C#","variant":"RestSharp"},{"key":"curl","label":"cURL","variant":"cURL"},{"key":"dart","label":"Dart","variant":"http"},{"key":"go","label":"Go","variant":"Native"},{"key":"http","label":"HTTP","variant":"HTTP"},{"key":"java","label":"Java","variant":"OkHttp"},{"key":"java","label":"Java","variant":"Unirest"},{"key":"javascript","label":"JavaScript","variant":"Fetch"},{"key":"javascript","label":"JavaScript","variant":"jQuery"},{"key":"javascript","label":"JavaScript","variant":"XHR"},{"key":"c","label":"C","variant":"libcurl"},{"key":"nodejs","label":"NodeJs","variant":"Axios"},{"key":"nodejs","label":"NodeJs","variant":"Native"},{"key":"nodejs","label":"NodeJs","variant":"Request"},{"key":"nodejs","label":"NodeJs","variant":"Unirest"},{"key":"objective-c","label":"Objective-C","variant":"NSURLSession"},{"key":"ocaml","label":"OCaml","variant":"Cohttp"},{"key":"php","label":"PHP","variant":"cURL"},{"key":"php","label":"PHP","variant":"Guzzle"},{"key":"php","label":"PHP","variant":"HTTP_Request2"},{"key":"php","label":"PHP","variant":"pecl_http"},{"key":"powershell","label":"PowerShell","variant":"RestMethod"},{"key":"python","label":"Python","variant":"http.client"},{"key":"python","label":"Python","variant":"Requests"},{"key":"r","label":"R","variant":"httr"},{"key":"r","label":"R","variant":"RCurl"},{"key":"ruby","label":"Ruby","variant":"Net::HTTP"},{"key":"shell","label":"Shell","variant":"Httpie"},{"key":"shell","label":"Shell","variant":"wget"},{"key":"swift","label":"Swift","variant":"URLSession"}],"languageOptions":[{"label":"C# - HttpClient","value":"csharp - HttpClient - C#"},{"label":"C# - RestSharp","value":"csharp - RestSharp - C#"},{"label":"cURL - cURL","value":"curl - cURL - cURL"},{"label":"Dart - http","value":"dart - http - Dart"},{"label":"Go - Native","value":"go - Native - Go"},{"label":"HTTP - HTTP","value":"http - HTTP - HTTP"},{"label":"Java - OkHttp","value":"java - OkHttp - Java"},{"label":"Java - Unirest","value":"java - Unirest - Java"},{"label":"JavaScript - Fetch","value":"javascript - Fetch - JavaScript"},{"label":"JavaScript - jQuery","value":"javascript - jQuery - JavaScript"},{"label":"JavaScript - XHR","value":"javascript - XHR - JavaScript"},{"label":"C - libcurl","value":"c - libcurl - C"},{"label":"NodeJs - Axios","value":"nodejs - Axios - NodeJs"},{"label":"NodeJs - Native","value":"nodejs - Native - NodeJs"},{"label":"NodeJs - Request","value":"nodejs - Request - NodeJs"},{"label":"NodeJs - Unirest","value":"nodejs - Unirest - NodeJs"},{"label":"Objective-C - NSURLSession","value":"objective-c - NSURLSession - Objective-C"},{"label":"OCaml - Cohttp","value":"ocaml - Cohttp - OCaml"},{"label":"PHP - cURL","value":"php - cURL - PHP"},{"label":"PHP - Guzzle","value":"php - Guzzle - PHP"},{"label":"PHP - HTTP_Request2","value":"php - HTTP_Request2 - PHP"},{"label":"PHP - pecl_http","value":"php - pecl_http - PHP"},{"label":"PowerShell - RestMethod","value":"powershell - RestMethod - PowerShell"},{"label":"Python - http.client","value":"python - http.client - Python"},{"label":"Python - Requests","value":"python - Requests - Python"},{"label":"R - httr","value":"r - httr - R"},{"label":"R - RCurl","value":"r - RCurl - R"},{"label":"Ruby - Net::HTTP","value":"ruby - Net::HTTP - Ruby"},{"label":"Shell - Httpie","value":"shell - Httpie - Shell"},{"label":"Shell - wget","value":"shell - wget - Shell"},{"label":"Swift - URLSession","value":"swift - URLSession - Swift"}],"layoutOptions":[{"value":"classic-single-column","label":"Single Column"},{"value":"classic-double-column","label":"Double Column"}],"versionOptions":[],"environmentOptions":[{"value":"0","label":"No Environment"},{"label":"TournamentAPI - Local (HTTPS)","value":"43726594-8084498c-f63b-4fbe-aa60-dccf1d6654f4"}],"canonicalUrl":"https://documenter.gw.postman.com/view/metadata/2sBYB1N89c"}