{"openapi":"3.1.0","info":{"title":"ParlaySports API","description":"JSON REST API for brands, leagues, matches, question groups, question definitions, listeners, users, and question answers.\n\nAuthenticate with ``Authorization: Bearer <api_key>`` from ``POST /api/auth/register`` or ``POST /api/auth/login``.\n\n**Admin-only** operations are summarized with ``[Admin]`` and require ``User.is_admin=true`` (else ``403``). Player-allowed writes: auth register/login/logout, ``PATCH /api/users/me``, ``PUT /api/question-answers``, ``POST /api/user-feedback``. Many catalog GETs stay open.\n\nInteractive docs: `/docs` (Swagger), `/redoc`, schema at `/openapi.json`. Narrative guides live under the MkDocs **API** section (`docs/api/`).","version":"0.1.0"},"paths":{"/api/auth/register":{"post":{"tags":["auth"],"summary":"Register a new player account","description":"Creates a non-admin ``local_password`` user and returns a Bearer API key (plaintext once). Copy ``api_key`` into Swagger Authorize.","operationId":"auth_register_api_auth_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthRegisterRequest"}}},"required":true},"responses":{"201":{"description":"User created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthTokenOut"}}}},"409":{"description":"Username or email already taken"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/login":{"post":{"tags":["auth"],"summary":"Log in with username or email and password","description":"Validates ``local_password`` credentials (``username`` field accepts username or email; username may be null on the account), revokes prior active API keys, and returns a new Bearer API key.","operationId":"auth_login_api_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthLoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthTokenOut"}}}},"401":{"description":"Invalid credentials or inactive account"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/logout":{"post":{"tags":["auth"],"summary":"Revoke the current API key","description":"Revokes the Bearer API key used on this request.","operationId":"auth_logout_api_auth_logout_post","responses":{"204":{"description":"Successful Response"}},"security":[{"HTTPBearer":[]}]}},"/api/brands":{"get":{"tags":["brands"],"summary":"List brands","description":"Returns brands ordered by name. Optional ``q`` filters with a case-insensitive substring match on name, colors, logo filename, or id.","operationId":"brands_list_api_brands_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Case-insensitive search across name, primary/secondary color, logo filename, and id.","title":"Q"},"description":"Case-insensitive search across name, primary/secondary color, logo filename, and id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandListOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["brands"],"summary":"[Admin] Create a brand","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nCreate a brand with name and hex colors. Optional ``logo`` multipart file is stored at ``brands/{id}/{filename}`` in ``AWS_S3_DEFAULT_BUCKET``.","operationId":"brands_create_api_brands_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_brands_create_api_brands_post"}}}},"responses":{"201":{"description":"Brand created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Invalid colors or logo"},"409":{"description":"Duplicate name"},"503":{"description":"S3 bucket not configured (when uploading a logo)"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/brands/{brand_id}":{"get":{"tags":["brands"],"summary":"Get a brand","operationId":"brands_get_api_brands__brand_id__get","parameters":[{"name":"brand_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Brand Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandOut"}}}},"404":{"description":"Brand not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["brands"],"summary":"[Admin] Update a brand","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nPartial update via multipart form. Omit fields to leave them unchanged. Optional ``logo`` replaces the stored object; ``clear_logo=true`` removes it.","operationId":"brands_patch_api_brands__brand_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"brand_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Brand Id"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_brands_patch_api_brands__brand_id__patch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Invalid colors, logo, or clear+upload conflict"},"404":{"description":"Brand not found"},"409":{"description":"Duplicate name"},"503":{"description":"S3 bucket not configured (when touching logo)"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["brands"],"summary":"[Admin] Delete a brand","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nDeletes the brand row and any S3 logo object.","operationId":"brands_delete_api_brands__brand_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"brand_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Brand Id"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Brand not found"},"503":{"description":"S3 bucket not configured (when a logo exists)"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/brands/{brand_id}/question-sponsorships":{"get":{"tags":["brands"],"summary":"List question sponsorship slots for a brand","description":"Returns this brand's pre-allocated question sponsorship slots. When ``match_ids`` is provided, only those matches are included (empty list returns no rows).","operationId":"brands_list_question_sponsorships_api_brands__brand_id__question_sponsorships_get","parameters":[{"name":"brand_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Brand Id"}},{"name":"match_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string","format":"uuid"}},{"type":"null"}],"title":"Match Ids"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandQuestionSponsorshipsListOut"}}}},"404":{"description":"Brand not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["brands"],"summary":"[Admin] Assign question sponsorship slots to matches","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nFor each match id, optionally replace this brand's existing question sponsorship rows, then insert ``slots``. Or set ``random_percent`` (1–100) to insert ``round(question_max_count * percent / 100)`` random slots per match (mutually exclusive with non-empty ``slots``). Capacity is ``sponsored_slot_count <= match.question_max_count``. Empty ``slots`` with replace clears the brand's question sponsorships on those matches. Whole-match sponsor remains ``PATCH /api/matches/{id}`` (``sponsor_brand_id``).","operationId":"brands_assign_question_sponsorships_api_brands__brand_id__question_sponsorships_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"brand_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Brand Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandQuestionSponsorshipsAssign"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandQuestionSponsorshipsAssignOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Match not editable or invalid slot target"},"404":{"description":"Brand or match not found"},"409":{"description":"Over capacity or duplicate question_number target"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/question-definitions/sample-catalog":{"get":{"tags":["question-definitions"],"summary":"Compact sample-feed field catalog for a league","description":"Builds a path catalog from the packaged sample match feed for the league (used by the definition editor field browser).","operationId":"sample_catalog_api_question_definitions_sample_catalog_get","parameters":[{"name":"league","in":"query","required":true,"schema":{"type":"string","description":"League slug, e.g. mlb","title":"League"},"description":"League slug, e.g. mlb"},{"name":"include_samples","in":"query","required":false,"schema":{"type":"boolean","description":"When true, include a representative ``sample_event`` per event type (larger payload).","default":true,"title":"Include Samples"},"description":"When true, include a representative ``sample_event`` per event type (larger payload)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeagueSampleCatalog"}}}},"400":{"description":"Unsupported league slug","content":{"application/json":{"example":{"detail":"Unsupported league: nhl"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/question-definitions/preview":{"post":{"tags":["question-definitions"],"summary":"[Admin] Preview question copy against a sample event","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nRenders ``question_text`` against a sample event and optional ``store_state`` / ``issuance_state_extract``. Does not persist anything.","operationId":"preview_copy_api_question_definitions_preview_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewResponse"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Template or extract failure","content":{"application/json":{"example":{"detail":"…"}}}},"404":{"description":"Referenced sample context missing","content":{"application/json":{"example":{"detail":"…"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/question-definitions/export":{"get":{"tags":["question-definitions"],"summary":"[Admin] Export question definitions as CSV","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nDownload every in-game question definition across all leagues (including archived). Columns are the live table fields plus a ``league`` slug; JSON columns are serialized as JSON strings.","operationId":"export_definitions_endpoint_api_question_definitions_export_get","responses":{"200":{"description":"Successful Response"},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."}},"security":[{"HTTPBearer":[]}]}},"/api/question-definitions/import":{"post":{"tags":["question-definitions"],"summary":"[Admin] Import question definitions from CSV","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nUpload the export-shaped CSV (``league`` slug plus live table columns). ``dry_run=true`` (default) validates every row and returns creates/updates/errors without writing. ``dry_run=false`` applies all valid creates and updates in one transaction; any row error refuses the whole import. Blank ``id`` creates; unknown ``id`` is an error. Rows missing from the file are not deleted. Changing a definition does not rewrite open issuance snapshots.","operationId":"import_definitions_endpoint_api_question_definitions_import_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"When true (default), validate and diff only. When false, apply all rows in one transaction if none have errors.","default":true,"title":"Dry Run"},"description":"When true (default), validate and diff only. When false, apply all rows in one transaction if none have errors."}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_import_definitions_endpoint_api_question_definitions_import_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CsvImportPreview"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Malformed CSV, or apply refused because a row failed validation (body is the same preview shape)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/question-definitions":{"get":{"tags":["question-definitions"],"summary":"List question definitions","description":"League-scoped list of definition summaries for the editor sidebar. Optional ``q`` filters by name or id; optional ``is_pivotal_moment`` filters pivotal vs non-pivotal; optional ``created_*`` / ``updated_*`` are half-open UTC bounds on those timestamps.","operationId":"list_definitions_endpoint_api_question_definitions_get","parameters":[{"name":"league","in":"query","required":true,"schema":{"type":"string","description":"League slug, e.g. mlb","title":"League"},"description":"League slug, e.g. mlb"},{"name":"include_inactive","in":"query","required":false,"schema":{"type":"boolean","description":"When false (default), only non-archived definitions are returned. When true, include archived definitions.","default":false,"title":"Include Inactive"},"description":"When false (default), only non-archived definitions are returned. When true, include archived definitions."},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Case-insensitive substring match on definition name or id.","title":"Q"},"description":"Case-insensitive substring match on definition name or id."},{"name":"is_pivotal_moment","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"When set, only definitions with this pivotal-moment flag.","title":"Is Pivotal Moment"},"description":"When set, only definitions with this pivotal-moment flag."},{"name":"created_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Inclusive lower bound on created_at (UTC ISO datetime). Requires created_to.","title":"Created From"},"description":"Inclusive lower bound on created_at (UTC ISO datetime). Requires created_to."},{"name":"created_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Exclusive upper bound on created_at (UTC ISO datetime). Requires created_from.","title":"Created To"},"description":"Exclusive upper bound on created_at (UTC ISO datetime). Requires created_from."},{"name":"updated_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Inclusive lower bound on updated_at (UTC ISO datetime). Requires updated_to.","title":"Updated From"},"description":"Inclusive lower bound on updated_at (UTC ISO datetime). Requires updated_to."},{"name":"updated_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Exclusive upper bound on updated_at (UTC ISO datetime). Requires updated_from.","title":"Updated To"},"description":"Exclusive upper bound on updated_at (UTC ISO datetime). Requires updated_from."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionDefinitionListOut"}}}},"404":{"description":"League not found","content":{"application/json":{"example":{"detail":"League 'mlb' not found in database. Seed leagues first."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["question-definitions"],"summary":"[Admin] Create a question definition","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nCreate a definition for the league given by the ``league`` query param. Name must be unique within that league.","operationId":"create_definition_endpoint_api_question_definitions_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"league","in":"query","required":true,"schema":{"type":"string","description":"League slug, e.g. mlb","title":"League"},"description":"League slug, e.g. mlb"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionDefinitionCreate"}}}},"responses":{"201":{"description":"Definition created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionDefinitionOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"League not found","content":{"application/json":{"example":{"detail":"League 'mlb' not found in database. Seed leagues first."}}}},"409":{"description":"Name already exists for this league","content":{"application/json":{"example":{"detail":"A definition named 'Hit?' already exists for this league."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/question-definitions/{definition_id}":{"get":{"tags":["question-definitions"],"summary":"Get one question definition","description":"Full editable payload plus server-managed ids and timestamps.","operationId":"get_definition_endpoint_api_question_definitions__definition_id__get","parameters":[{"name":"definition_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Definition Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionDefinitionOut"}}}},"404":{"description":"Definition not found","content":{"application/json":{"example":{"detail":"Question definition not found"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["question-definitions"],"summary":"[Admin] Update a question definition (full editable payload)","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nFull replace of editable fields. Name must remain unique within the owning league.","operationId":"update_definition_endpoint_api_question_definitions__definition_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"definition_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Definition Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionDefinitionUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionDefinitionOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Definition not found","content":{"application/json":{"example":{"detail":"Question definition not found"}}}},"409":{"description":"Name already exists for this league","content":{"application/json":{"example":{"detail":"A definition named 'Hit?' already exists for this league."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["question-definitions"],"summary":"[Admin] Delete a question definition","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nHard-delete when no issuances or sponsorship slots reference the definition. Scrubs the id from league/match allowlists. Archive instead when dependents exist.","operationId":"delete_definition_endpoint_api_question_definitions__definition_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"definition_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Definition Id"}}],"responses":{"204":{"description":"Definition deleted"},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Definition not found","content":{"application/json":{"example":{"detail":"Question definition not found"}}}},"409":{"description":"Definition still referenced","content":{"application/json":{"example":{"detail":"Cannot delete definition …: 1 question issuance(s) reference it. Archive it instead."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/question-definitions/{definition_id}/clone":{"post":{"tags":["question-definitions"],"summary":"[Admin] Clone a question definition","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nCopy a definition. Optional body ``name`` overrides the default ``'<original> (copy)'``.","operationId":"clone_definition_endpoint_api_question_definitions__definition_id__clone_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"definition_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Definition Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/QuestionDefinitionClone"},{"type":"null"}],"title":"Body"}}}},"responses":{"201":{"description":"Clone created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionDefinitionOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Empty clone name","content":{"application/json":{"example":{"detail":"Clone name cannot be empty"}}}},"404":{"description":"Source definition not found","content":{"application/json":{"example":{"detail":"Question definition not found"}}}},"409":{"description":"Clone name already exists for this league","content":{"application/json":{"example":{"detail":"A definition named 'Hit? (copy)' already exists for this league."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/question-definitions/{definition_id}/archive":{"post":{"tags":["question-definitions"],"summary":"[Admin] Archive a question definition","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nSets ``is_archived=true`` so the definition is hidden from the default admin tree and is never issued. Does not change ``is_active`` (league-default inclusion).","operationId":"archive_definition_endpoint_api_question_definitions__definition_id__archive_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"definition_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Definition Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionDefinitionOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Definition not found","content":{"application/json":{"example":{"detail":"Question definition not found"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/question-definitions/{definition_id}/activate":{"post":{"tags":["question-definitions"],"summary":"[Admin] Reactivate a question definition","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nSets ``is_archived=false`` so the definition appears in the admin tree again. Does not turn on ``is_active`` (league-default inclusion).","operationId":"activate_definition_endpoint_api_question_definitions__definition_id__activate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"definition_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Definition Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionDefinitionOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Definition not found","content":{"application/json":{"example":{"detail":"Question definition not found"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/question-groups":{"get":{"tags":["question-groups"],"summary":"[Admin] List question groups","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nLeague-scoped list of issuance groups (concurrency lanes).","operationId":"question_groups_list_api_question_groups_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"league","in":"query","required":true,"schema":{"type":"string","description":"League slug, e.g. mlb","title":"League"},"description":"League slug, e.g. mlb"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionGroupListOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Unsupported league slug"},"404":{"description":"League not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["question-groups"],"summary":"[Admin] Create a question group","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nCreate a league-scoped issuance group. Slug is immutable after create.","operationId":"question_groups_create_api_question_groups_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"league","in":"query","required":true,"schema":{"type":"string","description":"League slug, e.g. mlb","title":"League"},"description":"League slug, e.g. mlb"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionGroupCreate"}}}},"responses":{"201":{"description":"Question group created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionGroupOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Invalid slug, period map, or league"},"404":{"description":"League not found"},"409":{"description":"Duplicate slug for this league"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/question-groups/export":{"get":{"tags":["question-groups"],"summary":"[Admin] Export question groups as CSV","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nDownload every question group across all leagues. Columns are the live table fields plus a ``league`` slug; JSON columns are serialized as JSON strings.","operationId":"export_groups_endpoint_api_question_groups_export_get","responses":{"200":{"description":"Successful Response"},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."}},"security":[{"HTTPBearer":[]}]}},"/api/question-groups/{group_id}":{"get":{"tags":["question-groups"],"summary":"[Admin] Get a question group","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.","operationId":"question_groups_get_api_question_groups__group_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Group Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionGroupOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Question group not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["question-groups"],"summary":"[Admin] Update a question group","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nPartial update. Slug cannot change.","operationId":"question_groups_patch_api_question_groups__group_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Group Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionGroupUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionGroupOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Invalid period map or fields"},"404":{"description":"Question group not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["question-groups"],"summary":"[Admin] Delete a question group","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\n409 when any question definition still references the group.","operationId":"question_groups_delete_api_question_groups__group_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Group Id"}}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Question group not found"},"409":{"description":"Definitions still reference this group"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/match-question-definitions/export":{"get":{"tags":["match-question-definitions"],"summary":"[Admin] Export Match question definitions as CSV","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nDownload every Match question definition across all leagues (including archived). Columns are the live table fields plus a ``league`` slug; JSON columns are serialized as JSON strings.","operationId":"export_definitions_endpoint_api_match_question_definitions_export_get","responses":{"200":{"description":"Successful Response"},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."}},"security":[{"HTTPBearer":[]}]}},"/api/match-question-definitions/import":{"post":{"tags":["match-question-definitions"],"summary":"[Admin] Import Match question definitions from CSV","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nUpload the export-shaped CSV (``league`` slug plus live table columns). ``dry_run=true`` (default) validates every row and returns creates/updates/errors without writing. ``dry_run=false`` applies all valid creates and updates in one transaction; any row error refuses the whole import. Blank ``id`` creates; unknown ``id`` is an error. Rows missing from the file are not deleted. Changing a definition does not rewrite open Match question issuance snapshots.","operationId":"import_definitions_endpoint_api_match_question_definitions_import_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"When true (default), validate and diff only. When false, apply all rows in one transaction if none have errors.","default":true,"title":"Dry Run"},"description":"When true (default), validate and diff only. When false, apply all rows in one transaction if none have errors."}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_import_definitions_endpoint_api_match_question_definitions_import_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CsvImportPreview"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Malformed CSV, or apply refused because a row failed validation (body is the same preview shape)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/match-question-definitions":{"get":{"tags":["match-question-definitions"],"summary":"List Match question definitions","description":"League-scoped list of Match question definition summaries.","operationId":"list_definitions_endpoint_api_match_question_definitions_get","parameters":[{"name":"league","in":"query","required":true,"schema":{"type":"string","description":"League slug, e.g. mlb","title":"League"},"description":"League slug, e.g. mlb"},{"name":"include_inactive","in":"query","required":false,"schema":{"type":"boolean","description":"When false (default), only active definitions are returned. When true, include archived (inactive) definitions.","default":false,"title":"Include Inactive"},"description":"When false (default), only active definitions are returned. When true, include archived (inactive) definitions."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchQuestionDefinitionListOut"}}}},"404":{"description":"League not found","content":{"application/json":{"example":{"detail":"League 'mlb' not found in database. Seed leagues first."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["match-question-definitions"],"summary":"[Admin] Create a Match question definition","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nCreate a Match question definition for the league given by the ``league`` query param. Name must be unique within that league.","operationId":"create_definition_endpoint_api_match_question_definitions_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"league","in":"query","required":true,"schema":{"type":"string","description":"League slug, e.g. mlb","title":"League"},"description":"League slug, e.g. mlb"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchQuestionDefinitionCreate"}}}},"responses":{"201":{"description":"Definition created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchQuestionDefinitionOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"League not found","content":{"application/json":{"example":{"detail":"League 'mlb' not found in database."}}}},"409":{"description":"Name already exists for this league","content":{"application/json":{"example":{"detail":"A Match question definition named 'Who will win the match' already exists for this league."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/match-question-definitions/{definition_id}":{"get":{"tags":["match-question-definitions"],"summary":"Get one Match question definition","description":"Full editable payload plus server-managed ids and timestamps.","operationId":"get_definition_endpoint_api_match_question_definitions__definition_id__get","parameters":[{"name":"definition_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Definition Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchQuestionDefinitionOut"}}}},"404":{"description":"Definition not found","content":{"application/json":{"example":{"detail":"Match question definition not found"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["match-question-definitions"],"summary":"[Admin] Update a Match question definition","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nFull replace of editable fields. Name must remain unique within the owning league.","operationId":"update_definition_endpoint_api_match_question_definitions__definition_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"definition_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Definition Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchQuestionDefinitionUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchQuestionDefinitionOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Definition not found","content":{"application/json":{"example":{"detail":"Match question definition not found"}}}},"409":{"description":"Name already exists for this league","content":{"application/json":{"example":{"detail":"A Match question definition named 'Who will win the match' already exists for this league."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["match-question-definitions"],"summary":"[Admin] Delete a Match question definition","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nHard-delete when no Match question issuances reference the definition. Scrubs the id from league/match allowlists. Archive instead when dependents exist.","operationId":"delete_definition_endpoint_api_match_question_definitions__definition_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"definition_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Definition Id"}}],"responses":{"204":{"description":"Definition deleted"},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Definition not found","content":{"application/json":{"example":{"detail":"Match question definition not found"}}}},"409":{"description":"Definition still referenced","content":{"application/json":{"example":{"detail":"Cannot delete definition …: 1 match question issuance(s) reference it. Archive it instead."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/match-question-definitions/{definition_id}/clone":{"post":{"tags":["match-question-definitions"],"summary":"[Admin] Clone a Match question definition","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nCopy a definition. Optional body ``name`` overrides the default ``'<original> (copy)'``.","operationId":"clone_definition_endpoint_api_match_question_definitions__definition_id__clone_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"definition_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Definition Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MatchQuestionDefinitionClone"},{"type":"null"}],"title":"Body"}}}},"responses":{"201":{"description":"Clone created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchQuestionDefinitionOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Empty clone name","content":{"application/json":{"example":{"detail":"Clone name cannot be empty"}}}},"404":{"description":"Source definition not found","content":{"application/json":{"example":{"detail":"Match question definition not found"}}}},"409":{"description":"Clone name already exists for this league","content":{"application/json":{"example":{"detail":"A Match question definition named 'Who will win the match (copy)' already exists for this league."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/match-question-definitions/{definition_id}/archive":{"post":{"tags":["match-question-definitions"],"summary":"[Admin] Archive (deactivate) a Match question definition","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nSets ``is_active=false`` so the definition is not issued.","operationId":"archive_definition_endpoint_api_match_question_definitions__definition_id__archive_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"definition_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Definition Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchQuestionDefinitionOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Definition not found","content":{"application/json":{"example":{"detail":"Match question definition not found"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/match-question-definitions/{definition_id}/activate":{"post":{"tags":["match-question-definitions"],"summary":"[Admin] Reactivate a Match question definition","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nSets ``is_active=true`` so the definition may be issued again.","operationId":"activate_definition_endpoint_api_match_question_definitions__definition_id__activate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"definition_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Definition Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchQuestionDefinitionOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Definition not found","content":{"application/json":{"example":{"detail":"Match question definition not found"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/leagues":{"get":{"tags":["leagues"],"summary":"List leagues","description":"Returns all leagues with default question configuration (caps, period distribution, points, answer window).","operationId":"leagues_list_api_leagues_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeagueListOut"}}}}}}},"/api/leagues/{league_id}":{"get":{"tags":["leagues"],"summary":"Get a league by id","description":"Load one league by internal league id.","operationId":"leagues_get_api_leagues__league_id__get","parameters":[{"name":"league_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"League Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeagueOut"}}}},"404":{"description":"League not found","content":{"application/json":{"example":{"detail":"League not found"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["leagues"],"summary":"[Admin] Update league question defaults","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nPartial update of league question defaults (max count, min interval, period distribution, points, answer window). Omitted fields are unchanged. Invalid period-distribution shapes return 400.","operationId":"leagues_patch_api_leagues__league_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"league_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"League Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeagueUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeagueOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"League not found","content":{"application/json":{"example":{"detail":"League not found: <uuid>"}}}},"400":{"description":"Invalid period distribution shape","content":{"application/json":{"example":{"detail":"default_question_period_distribution values must be integers (bad value for '1')"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/leagues/{league_id}/question-inheritance":{"get":{"tags":["leagues"],"summary":"[Admin] Inspect question-settings inheritance for a league","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nRead-only inspect payload: league defaults, groups, definitions, and the settings matrix. No match overrides or issuance traces. Pass ``kind=match`` for Match questions. Optional ``definition_id`` pins group / definition layers.","operationId":"leagues_question_inheritance_api_leagues__league_id__question_inheritance_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"league_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"League Id"}},{"name":"kind","in":"query","required":false,"schema":{"$ref":"#/components/schemas/InheritanceKind","description":"in_game (listener props) or match (pre-game).","default":"in_game"},"description":"in_game (listener props) or match (pre-game)."},{"name":"definition_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Optional definition to pin group / definition layers.","title":"Definition Id"},"description":"Optional definition to pin group / definition layers."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionInheritanceOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"League or definition not found","content":{"application/json":{"example":{"detail":"League not found: <uuid>"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/matches":{"get":{"tags":["matches"],"summary":"List matches filtered by league, scheduled range, and/or status","description":"Filter matches by league slug, UTC instant range on ``Match.scheduled`` (``scheduled_from`` / ``scheduled_to``, half-open), status, ``is_test``, ``listener_events_archived``, and/or ``followed`` (requires auth). When no scheduled range is set, defaults to UTC calendar today. Clients convert local calendar days to UTC instants before calling.","operationId":"list_matches_endpoint_api_matches_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"league","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"League slug, e.g. mlb","title":"League"},"description":"League slug, e.g. mlb"},{"name":"scheduled_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Inclusive lower bound on Match.scheduled (UTC ISO datetime). Requires scheduled_to.","title":"Scheduled From"},"description":"Inclusive lower bound on Match.scheduled (UTC ISO datetime). Requires scheduled_to."},{"name":"scheduled_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Exclusive upper bound on Match.scheduled (UTC ISO datetime). Requires scheduled_from.","title":"Scheduled To"},"description":"Exclusive upper bound on Match.scheduled (UTC ISO datetime). Requires scheduled_from."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/MatchStatuses"},{"type":"null"}],"description":"Match status filter, e.g. closed","title":"Status"},"description":"Match status filter, e.g. closed"},{"name":"is_test","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"When set, filter by Match.is_test","title":"Is Test"},"description":"When set, filter by Match.is_test"},{"name":"listener_events_archived","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"When set, filter by Match.listener_events_archived (S3 gamedata archive availability).","title":"Listener Events Archived"},"description":"When set, filter by Match.listener_events_archived (S3 gamedata archive availability)."},{"name":"followed","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"When set, filter to matches the caller follows (true) or does not follow (false). Requires Bearer auth.","title":"Followed"},"description":"When set, filter to matches the caller follows (true) or does not follow (false). Requires Bearer auth."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchListOut"}}}},"401":{"description":"``followed`` set without a valid Bearer API key","content":{"application/json":{"example":{"detail":"Not authenticated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/matches/{match_id}/follow":{"post":{"tags":["matches"],"summary":"Follow a match","description":"Follow a match for open-question filtering and (when the user has a non-null ``match_daily_follow_count``) answer gating. Non-test follows count against the user's daily cap in their ``match_follow_timezone``. Test matches do not consume quota. Closed matches cannot be newly followed. Idempotent when already following.","operationId":"follow_match_endpoint_api_matches__match_id__follow_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"match_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Match Id"}}],"responses":{"200":{"description":"Follow created or already present","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchFollowOut"}}}},"404":{"description":"Match not found","content":{"application/json":{"example":{"detail":"Match not found: <uuid>"}}}},"409":{"description":"Daily follow limit reached, or match is closed","content":{"application/json":{"examples":{"daily_limit":{"value":{"detail":"Daily follow limit reached (3/3 for timezone UTC)."}},"closed":{"value":{"detail":"Cannot follow a closed match (status is closed)."}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["matches"],"summary":"Unfollow a match","description":"Unfollow a match. Before start (or any test match) the follow row is deleted and today's quota is refunded. After start, non-test follows stay as spent rows so the daily slot is not refunded; re-follow reactivates the same row without using another slot. Closed matches still cannot be newly followed.","operationId":"unfollow_match_endpoint_api_matches__match_id__follow_delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"match_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Match Id"}}],"responses":{"200":{"description":"Follow removed or marked spent after start","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchFollowOut"}}}},"404":{"description":"Match not found or not following","content":{"application/json":{"examples":{"not_following":{"value":{"detail":"Not following this match."}},"not_found":{"value":{"detail":"Match not found: <uuid>"}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/matches/{match_id}/question-inheritance":{"get":{"tags":["matches"],"summary":"[Admin] Inspect question-settings inheritance for a match","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nRead-only inspect payload: league defaults, match overrides, groups, definitions, settings matrix, and per-issuance decision traces from pinned snapshots. Pass ``kind=match`` for Match questions. Optional ``definition_id`` filters traces and pins layers.","operationId":"match_question_inheritance_api_matches__match_id__question_inheritance_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"match_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Match Id"}},{"name":"kind","in":"query","required":false,"schema":{"$ref":"#/components/schemas/InheritanceKind","description":"in_game (listener props) or match (pre-game).","default":"in_game"},"description":"in_game (listener props) or match (pre-game)."},{"name":"definition_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Optional definition to pin group / definition layers.","title":"Definition Id"},"description":"Optional definition to pin group / definition layers."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionInheritanceOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Match or definition not found","content":{"application/json":{"example":{"detail":"Match not found: <uuid>"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/matches/{match_id}/question-issuance-denials":{"get":{"tags":["matches"],"summary":"[Admin] List blocked in-game issuance attempts for a match","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nRead-only. Compact listener records for events where at least one definition trigger matched but nothing published (caps, group, probability skip, pending slot occupied). Does not include silent misses where no trigger matched. Optional ``failed_step`` filters by the first short-circuit gate id.","operationId":"match_question_issuance_denials_api_matches__match_id__question_issuance_denials_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"match_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Match Id"}},{"name":"failed_step","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional first closed gate id, e.g. match_max.","title":"Failed Step"},"description":"Optional first closed gate id, e.g. match_max."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionIssuanceDenialListOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Match not found","content":{"application/json":{"example":{"detail":"Match not found: <uuid>"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/matches/{match_id}/event-timeline":{"get":{"tags":["matches"],"summary":"[Admin] Match event timeline points","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nRead-only scatter facts from ``match_timeline_points`` (stream events plus in-game / Match question issue and resolve markers) and period-change marks. ``match_id`` is the internal match id. Empty ``points`` means nothing has been ingested and this match has no issuances yet.","operationId":"match_event_timeline_api_matches__match_id__event_timeline_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"match_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Match Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchEventTimelineOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Match not found","content":{"application/json":{"example":{"detail":"Match not found: <uuid>"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/matches/{match_id}/question-issuances":{"get":{"tags":["matches"],"summary":"List in-game questions issued for a match","description":"Requires Bearer API key. Returns the match's **in-game** question issuance history oldest first (listener props, not Match questions), including sequence, issued/resolved periods, answer metrics, the pinned question definition when present, and History-style resolution debug fields (condition evaluations / event fields) when resolved. Non-admin callers receive **resolved issuances only** (no open/live issuance ids). Admins receive the full open+resolved history. Live player questions use ``GET /api/question-answers/open`` and the play WebSocket, not this endpoint.","operationId":"list_question_issuances_endpoint_api_matches__match_id__question_issuances_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"match_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Match Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionIssuanceListOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"404":{"description":"Match not found","content":{"application/json":{"example":{"detail":"Match not found: <uuid>"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/matches/{match_id}":{"get":{"tags":["matches"],"summary":"Get one match with related entities and effective settings","description":"Ops detail for a single match: related league/season/teams, effective question settings, full listener_* settings (defaults filled in), and all listener lifecycle rows.","operationId":"get_match_endpoint_api_matches__match_id__get","parameters":[{"name":"match_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Match Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchDetailOut"}}}},"404":{"description":"Match not found","content":{"application/json":{"example":{"detail":"Match not found: <uuid>"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["matches"],"summary":"[Admin] Update in-game and Match question overrides, auto_dispatch_listener, and/or test-match status","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nPartial update. Omitted fields are unchanged; explicit ``null`` on override fields clears them to league defaults. ``status`` is allowed only for ``is_test`` matches. In-game and Match question overrides cannot change after a listener has started or once the match leaves ``scheduled``.","operationId":"patch_match_api_matches__match_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"match_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Match Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchListItemOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Invalid update (non-test status, overrides locked, …)","content":{"application/json":{"examples":{"non_test_status":{"value":{"detail":"Only test matches (is_test) can change status via the API."}},"overrides_locked":{"value":{"detail":"In-game and Match question overrides cannot be changed after a listener has started."}}}}}},"404":{"description":"Match not found","content":{"application/json":{"example":{"detail":"Match not found: <uuid>"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["matches"],"summary":"[Admin] Delete an is_test match (stops listener; cleans related DB rows)","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nStops any listener, then deletes answers, issuances, listener rows, and the match. Only ``is_test`` matches. Unavailable in the main environment (404).","operationId":"delete_match_api_matches__match_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"match_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Match Id"}}],"responses":{"204":{"description":"Test match deleted"},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Match is not a test match","content":{"application/json":{"example":{"detail":"Only test matches (is_test) can be deleted"}}}},"404":{"description":"Match not found, or clone/delete disabled in main","content":{"application/json":{"examples":{"not_found":{"value":{"detail":"Match not found: <uuid>"}},"main_env":{"value":{"detail":"Match clone-and-listen is not available in the main environment."}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/matches/{match_id}/events/download":{"get":{"tags":["matches"],"summary":"Download the match event recording JSON","description":"Attachment download of the archived match event recording (``{shortcode}.json``) from ``AWS_S3_MATCH_ARCHIVE_BUCKET``. Shared across all listener runs for the match; requires ``listener_events_archived``.","operationId":"download_match_events_api_matches__match_id__events_download_get","parameters":[{"name":"match_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Match Id"}}],"responses":{"200":{"description":"Successful Response"},"404":{"description":"Match or events file not found / not archived","content":{"application/json":{"example":{"detail":"Event recording not available until archived to S3."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/matches/{match_id}/clone":{"post":{"tags":["matches"],"summary":"[Admin] Clone a CLOSED match as is_test and start an srsim listener","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nValidates a recording exists for the source Sportradar match id, clones the CLOSED match as ``is_test`` (question overrides, match sponsor, and question sponsorships omitted → copy source), persists listener/srsim settings, and enqueues ``start_match_listener``. Unavailable in the main environment (404). See MkDocs guides for srsim anchors vs distribution period keys.","operationId":"clone_match_api_matches__match_id__clone_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"match_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Match Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MatchCloneRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchCloneOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"400":{"description":"Source not CLOSED, missing sr_id, or bad recording","content":{"application/json":{"example":{"detail":"Only CLOSED matches can be cloned for srsim; status is 'scheduled'."}}}},"404":{"description":"Match not found, or clone disabled in main","content":{"application/json":{"examples":{"not_found":{"value":{"detail":"Match not found: <uuid>"}},"main_env":{"value":{"detail":"Match clone-and-listen is not available in the main environment."}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/matches/{match_id}/start-listener":{"post":{"tags":["matches"],"summary":"[Admin] Enqueue start_match_listener for a match","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nEnqueue Celery ``start_match_listener`` using ``Match.listener_start_settings``. Default ``force=true`` clears Redis start barriers. Prefer ``POST .../stop-listener`` first if a run is live. Test-match starts are unavailable in the main environment (404); live matches may be started in any environment.","operationId":"start_match_listener_endpoint_api_matches__match_id__start_listener_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"match_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Match Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StartMatchListenerRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartMatchListenerOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Match not found, or test-match start disabled in main","content":{"application/json":{"examples":{"not_found":{"value":{"detail":"Match not found: <uuid>"}},"main_env":{"value":{"detail":"Starting test match listeners is not available in the main environment."}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/matches/{match_id}/stop-listener":{"post":{"tags":["matches"],"summary":"[Admin] Stop match listeners (revoke Celery, close open rows, clear Redis barriers)","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nOperator stop path: set cooperative stop flag, revoke Celery tasks, clear Redis start barriers, and mark open lifecycle rows ended. Best-effort — Redis/Celery failures are logged and do not fail the request.","operationId":"stop_match_listener_endpoint_api_matches__match_id__stop_listener_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"match_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Match Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StopMatchListenerOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"Match not found","content":{"application/json":{"example":{"detail":"Match not found: <uuid>"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/match-listeners":{"get":{"tags":["match-listeners"],"summary":"List match listeners grouped by match","description":"Browse listener lifecycle rows for a league and UTC instant range on ``Match.scheduled`` (``scheduled_from`` / ``scheduled_to``, half-open). Groups matches that have at least ``min_runs`` listener rows. ``match_id`` may be an internal match id or Sportradar match id. Clients convert local calendar days to UTC instants before calling.","operationId":"list_match_listeners_endpoint_api_match_listeners_get","parameters":[{"name":"league","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"League slug, e.g. mlb","title":"League"},"description":"League slug, e.g. mlb"},{"name":"scheduled_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Inclusive lower bound on Match.scheduled (UTC ISO datetime). Required with scheduled_to.","title":"Scheduled From"},"description":"Inclusive lower bound on Match.scheduled (UTC ISO datetime). Required with scheduled_to."},{"name":"scheduled_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Exclusive upper bound on Match.scheduled (UTC ISO datetime). Required with scheduled_from.","title":"Scheduled To"},"description":"Exclusive upper bound on Match.scheduled (UTC ISO datetime). Required with scheduled_from."},{"name":"match_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Optional internal match id (Match.id) or Sportradar match id (Match.sr_id); applied together with league and scheduled filters","title":"Match Id"},"description":"Optional internal match id (Match.id) or Sportradar match id (Match.sr_id); applied together with league and scheduled filters"},{"name":"min_runs","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Only include matches with at least this many runs","default":1,"title":"Min Runs"},"description":"Only include matches with at least this many runs"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchListenerListOut"}}}},"400":{"description":"Invalid filter combination","content":{"application/json":{"example":{"detail":"league is required"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/match-listeners/{listener_id}/log":{"get":{"tags":["match-listeners"],"summary":"Read the per-run text log for a match listener","description":"Returns the text log content for one lifecycle row when the file exists. ``available=false`` with a ``reason`` when the log is missing.","operationId":"get_match_listener_log_endpoint_api_match_listeners__listener_id__log_get","parameters":[{"name":"listener_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listener Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchListenerLogOut"}}}},"404":{"description":"Listener row not found","content":{"application/json":{"example":{"detail":"Match listener <uuid> not found"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/match-listeners/{listener_id}/log/download":{"get":{"tags":["match-listeners"],"summary":"Download the per-run text log file","description":"Attachment download of the archived listener text log from ``AWS_S3_MATCH_ARCHIVE_BUCKET`` (``text/plain``). Streams from S3.","operationId":"download_match_listener_log_api_match_listeners__listener_id__log_download_get","parameters":[{"name":"listener_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listener Id"}}],"responses":{"200":{"description":"Successful Response"},"404":{"description":"Listener or log file not found","content":{"application/json":{"example":{"detail":"Match listener <uuid> not found"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/match-listeners/{listener_id}/events/download":{"get":{"tags":["match-listeners"],"summary":"Download the match event recording JSON","description":"Attachment download of the archived event recording from ``AWS_S3_MATCH_ARCHIVE_BUCKET`` (``application/json``). Streams from S3.","operationId":"download_match_listener_events_api_match_listeners__listener_id__events_download_get","parameters":[{"name":"listener_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listener Id"}}],"responses":{"200":{"description":"Successful Response"},"404":{"description":"Listener or events file not found","content":{"application/json":{"example":{"detail":"Match listener <uuid> not found"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/users/me":{"get":{"tags":["users"],"summary":"Get the authenticated user profile","operationId":"users_me_api_users_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserOut"}}}}},"security":[{"HTTPBearer":[]}]},"patch":{"tags":["users"],"summary":"Update the authenticated user's profile","description":"Player-allowed write: email, names, postal_code, date_of_birth, match_follow_timezone, notify_on_issuance, notify_on_resolve.","operationId":"users_me_patch_api_users_me_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserMeUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/users/me/points":{"get":{"tags":["users"],"summary":"Get scored points totals for the authenticated user","operationId":"users_me_points_api_users_me_points_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"period_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Inclusive UTC start of the period window","title":"Period From"},"description":"Inclusive UTC start of the period window"},{"name":"period_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Exclusive UTC end of the period window","title":"Period To"},"description":"Exclusive UTC end of the period window"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPointsOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/users/me/devices":{"post":{"tags":["users"],"summary":"Register or refresh a push device","description":"Idempotent upsert on ``device_id``. Call after login, cold start, token rotation, and permission grant. Reassigns the row when the same ``device_id`` arrives under a different user. Always bumps ``updated_at``. Not rate-limited — cold-start re-registration is expected. Returns **201** when created, **200** when refreshed.","operationId":"users_me_devices_upsert_api_users_me_devices_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushDeviceCreate"}}},"required":true},"responses":{"200":{"description":"Existing device refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushDeviceOut"}}}},"201":{"description":"New device registered"},"401":{"description":"Not authenticated"},"422":{"description":"Validation error"}},"security":[{"HTTPBearer":[]}]}},"/api/users/me/devices/{device_id}":{"delete":{"tags":["users"],"summary":"Unregister a push device","description":"Hard-delete the authenticated user's device row. Idempotent: **204** whether or not the row existed. Call on logout.","operationId":"users_me_devices_delete_api_users_me_devices__device_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"device_id","in":"path","required":true,"schema":{"type":"string","title":"Device Id"}}],"responses":{"204":{"description":"Deleted or already absent"},"401":{"description":"Not authenticated"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/users":{"get":{"tags":["users"],"summary":"[Admin] List users","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nOptional exact ``username`` / ``email``, substring ``q`` (username, email, first/last name, or user id), ``is_admin`` filter, ``followed_match_id`` (users following that match), ``sort_by`` / ``sort_dir``, and ``offset`` / ``limit``. ``user_count`` is the total match count (for pagination).","operationId":"users_list_api_users_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"username","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Exact username filter","title":"Username"},"description":"Exact username filter"},{"name":"email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Exact email filter","title":"Email"},"description":"Exact email filter"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Substring search on username, email, first/last name, or user id","title":"Q"},"description":"Substring search on username, email, first/last name, or user id"},{"name":"is_admin","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"When set, only admin or only non-admin users","title":"Is Admin"},"description":"When set, only admin or only non-admin users"},{"name":"followed_match_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"When set, only users who follow this internal match id","title":"Followed Match Id"},"description":"When set, only users who follow this internal match id"},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","description":"Sort column: username, email, first_name, last_name, is_admin, is_active, auth_method, created_at","default":"username","title":"Sort By"},"description":"Sort column: username, email, first_name, last_name, is_admin, is_active, auth_method, created_at"},{"name":"sort_dir","in":"query","required":false,"schema":{"type":"string","description":"Sort direction: asc or desc","default":"asc","title":"Sort Dir"},"description":"Sort direction: asc or desc"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Rows to skip (pagination)","default":0,"title":"Offset"},"description":"Rows to skip (pagination)"},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":200,"minimum":1},{"type":"null"}],"description":"Max rows (omit for no cap)","title":"Limit"},"description":"Max rows (omit for no cap)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserListOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["users"],"summary":"[Admin] Create a user","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.","operationId":"users_create_api_users_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/users/{user_id}/question-answers":{"get":{"tags":["users"],"summary":"[Admin] List answers for a user","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nOps History uses this path (not the self-scoped list).","operationId":"users_question_answers_api_users__user_id__question_answers_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"match_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Optional match filter","title":"Match Id"},"description":"Optional match filter"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionAnswerListOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/users/{user_id}/points":{"get":{"tags":["users"],"summary":"[Admin] Get scored points for a user","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.","operationId":"users_points_api_users__user_id__points_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"period_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Period From"}},{"name":"period_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Period To"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPointsOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/users/{user_id}":{"get":{"tags":["users"],"summary":"[Admin] Get a user by id","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.","operationId":"users_get_api_users__user_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["users"],"summary":"[Admin] Update a user","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.","operationId":"users_patch_api_users__user_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["users"],"summary":"[Admin] Deactivate a user","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nSoft-deactivates the account (``is_active=false``).","operationId":"users_delete_api_users__user_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/question-answers/open":{"get":{"tags":["question-answers"],"summary":"List open (unresolved, unexpired) questions","description":"Returns unresolved issuances whose answer window is still open, limited to matches the caller follows. Matches qualify when status is scheduled, created, delayed, or inprogress, or when scheduled falls in a sliding UTC window around now. Embeds the caller's current answer when already answered. Requires Bearer API key.","operationId":"question_answers_open_api_question_answers_open_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenQuestionListOut"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/question-answers":{"get":{"tags":["question-answers"],"summary":"List answers for the authenticated user","description":"Answer history for the caller. Newest first when ``limit`` is set. Includes match/question context and resolution fields when available. Locked pending Match answers are returned first and do not consume ``limit`` (Play keeps them visible above the regular recent strip).","operationId":"question_answers_list_api_question_answers_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"match_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Optional match filter","title":"Match Id"},"description":"Optional match filter"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"description":"Max rows (newest first). Defaults to 100; Play uses a smaller limit.","default":100,"title":"Limit"},"description":"Max rows (newest first). Defaults to 100; Play uses a smaller limit."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionAnswerListOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["question-answers"],"summary":"Create or update an answer for the authenticated user","description":"Upserts one answer per (user, question_issuance_id). Player-allowed write. Allowed only while the issuance is unresolved and within the league answer window.","operationId":"question_answers_upsert_api_question_answers_put","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionAnswerUpsert"}}}},"responses":{"200":{"description":"Answer created or updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionAnswerOut"}}}},"400":{"description":"Invalid selected_answer_identifier (not in issuance choices)","content":{"application/json":{"example":{"detail":"Invalid selected_answer_identifier"}}}},"403":{"description":"Restricted user is not following the match","content":{"application/json":{"example":{"detail":"You must follow this match before answering."}}}},"404":{"description":"Question issuance not found","content":{"application/json":{"example":{"detail":"Question issuance not found"}}}},"409":{"description":"Issuance already closed (feed resolve, stale settlement, or retract) — answers are locked","content":{"application/json":{"example":{"detail":"Question issuance is already resolved"}}}},"410":{"description":"Answer window expired","content":{"application/json":{"example":{"detail":"Answer window has expired"}}}},"422":{"description":"Request body / field validation failed"}}}},"/api/user-feedback/form":{"get":{"tags":["user-feedback"],"summary":"Form catalog for user feedback","description":"Constrained ``subject_type`` values (with play history ``kind``) and per-type ``topic`` options. No auth. Clients must not hardcode these strings. Description is optional; max length is ``description_max_length``.","operationId":"user_feedback_form_get_api_user_feedback_form_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserFeedbackFormOut"}}}}}}},"/api/user-feedback":{"get":{"tags":["user-feedback"],"summary":"List user feedback","description":"Newest first. Players always see their own rows. Admins may filter by ``user_id``, ``created_from`` / ``created_to`` (UTC, half-open on ``created_at``), ``match_id``, ``subject_type``, and ``topic``. ``feedback_count`` is the filtered total (ignores offset/limit).","operationId":"user_feedback_list_api_user_feedback_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"match_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Optional internal match id filter","title":"Match Id"},"description":"Optional internal match id filter"},{"name":"user_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Admin only: filter by submitter user id","title":"User Id"},"description":"Admin only: filter by submitter user id"},{"name":"created_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Admin only: created_at >= this instant (UTC)","title":"Created From"},"description":"Admin only: created_at >= this instant (UTC)"},{"name":"created_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Admin only: created_at < this instant (UTC)","title":"Created To"},"description":"Admin only: created_at < this instant (UTC)"},{"name":"subject_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional subject_type filter","title":"Subject Type"},"description":"Optional subject_type filter"},{"name":"topic","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional topic filter","title":"Topic"},"description":"Optional topic filter"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Rows to skip (pagination)","default":0,"title":"Offset"},"description":"Rows to skip (pagination)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Max rows per page.","default":50,"title":"Limit"},"description":"Max rows per page."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserFeedbackListOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["user-feedback"],"summary":"Submit user feedback","description":"Player-allowed write. One row per answer owner + subject. Players may only report their own resolved answers. Admins may report any resolved answer (History); the row is stored against the answer owner. Take ``subject_type`` and ``topic`` from GET /form.","operationId":"user_feedback_create_api_user_feedback_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserFeedbackCreate"}}}},"responses":{"201":{"description":"Feedback created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserFeedbackOut"}}}},"404":{"description":"Subject not found or not owned by the caller","content":{"application/json":{"example":{"detail":"Question answer not found"}}}},"409":{"description":"Subject not resolved, or feedback already submitted","content":{"application/json":{"example":{"detail":"Feedback already submitted"}}}},"422":{"description":"Unknown subject_type or topic, or field validation"}}}},"/api/user-feedback/{feedback_id}":{"get":{"tags":["user-feedback"],"summary":"Get one user feedback row","description":"Owner or admin. Others receive 404.","operationId":"user_feedback_get_api_user_feedback__feedback_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feedback_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feedback Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserFeedbackOut"}}}},"404":{"description":"Feedback not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/push-settings":{"get":{"tags":["push"],"summary":"[Admin] Get push notification settings","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nOperator-tunable gates and message templates (``stored_settings`` key ``push_notification_settings``). Missing row returns code defaults.","operationId":"push_settings_get_api_push_settings_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushNotificationSettings"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."}},"security":[{"HTTPBearer":[]}]},"patch":{"tags":["push"],"summary":"[Admin] Update push notification settings","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nPartial update of push gates and ``{{…}}`` message templates. Changes apply to subsequent Celery sends without worker restart.","operationId":"push_settings_patch_api_push_settings_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushNotificationSettingsUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushNotificationSettings"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/push-settings/reset":{"post":{"tags":["push"],"summary":"[Admin] Reset push notification settings to defaults","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nRestore code defaults for all push settings fields.","operationId":"push_settings_reset_api_push_settings_reset_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushNotificationSettings"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."}},"security":[{"HTTPBearer":[]}]}},"/api/push-delivery-attempts":{"get":{"tags":["push"],"summary":"[Admin] Lookup push delivery attempts for a user","description":"**Admin only.** Requires a user/API key with ``is_admin=true``.\n\nProvide exactly one of ``user_id``, ``email``, or ``username``. Returns device health plus recent ``push_delivery_attempts`` (retention window).","operationId":"push_delivery_attempts_lookup_api_push_delivery_attempts_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Internal user id","title":"User Id"},"description":"Internal user id"},{"name":"email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Exact user email","title":"Email"},"description":"Exact user email"},{"name":"username","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Exact username","title":"Username"},"description":"Exact username"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Max attempts to return (default 50)","default":50,"title":"Limit"},"description":"Max attempts to return (default 50)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushDeliveryAttemptListOut"}}}},"401":{"description":"Missing or invalid Bearer API key"},"403":{"description":"Caller authenticated but not an admin (``User.is_admin``)."},"404":{"description":"User not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AnswerChoice-Input":{"properties":{"identifier":{"type":"string","title":"Identifier","description":"Unique identifier (the 'value') for this answer choice (e.g., 'team1', 'team2', 'neither')"},"text":{"type":"string","title":"Text","description":"The label text to display for this choice. Can be either: 1) A template string with JSONPath placeholders like {{$.team.name}} which will be replaced using jsonpath_replace, or 2) A direct JSONPath expression (starting with $) which will be extracted directly. Example: '{{$.team.name}}' or '$.players[0].name'"},"correct_condition":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Correct Condition","description":"Optional JSONPath condition to evaluate against resolution event to determine if this choice is correct. Uses jsonpath_condition_evaluate syntax with {{$.path}} placeholders. Example: '{{$.event.attribution.team.id}} == {{$.store_state.random_team_id}}'"},"is_correct":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Correct","description":"Static flag indicating if this choice is correct. None if not resolved yet."},"override_points":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Override Points","description":"Optional absolute whole points or *N multiplier of the question's effective points (definition→match→league; multipliers floor). None inherits that value."},"points":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Points","description":"Resolved whole points for this choice on an issuance (stamped at issue time). Not authored on definition templates; leave null there."},"outcome_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Outcome Text","description":"Optional on-field copy when this choice wins. Same JSONPath placeholders as ``text``. Blank or omitted = no play line."}},"type":"object","required":["identifier","text"],"title":"AnswerChoice","description":"A single answer choice for a multiple choice question.\n\nSupports JSONPath for dynamic text generation and correctness evaluation."},"AnswerChoice-Output":{"properties":{"identifier":{"type":"string","title":"Identifier","description":"Unique identifier (the 'value') for this answer choice (e.g., 'team1', 'team2', 'neither')"},"text":{"type":"string","title":"Text","description":"The label text to display for this choice. Can be either: 1) A template string with JSONPath placeholders like {{$.team.name}} which will be replaced using jsonpath_replace, or 2) A direct JSONPath expression (starting with $) which will be extracted directly. Example: '{{$.team.name}}' or '$.players[0].name'"},"correct_condition":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Correct Condition","description":"Optional JSONPath condition to evaluate against resolution event to determine if this choice is correct. Uses jsonpath_condition_evaluate syntax with {{$.path}} placeholders. Example: '{{$.event.attribution.team.id}} == {{$.store_state.random_team_id}}'"},"is_correct":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Correct","description":"Static flag indicating if this choice is correct. None if not resolved yet."},"override_points":{"anyOf":[{"type":"integer"},{"type":"string"},{"type":"null"}],"title":"Override Points","description":"Optional absolute whole points or *N multiplier of the question's effective points (definition→match→league; multipliers floor). None inherits that value."},"points":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Points","description":"Resolved whole points for this choice on an issuance (stamped at issue time). Not authored on definition templates; leave null there."},"outcome_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Outcome Text","description":"Optional on-field copy when this choice wins. Same JSONPath placeholders as ``text``. Blank or omitted = no play line."}},"type":"object","required":["identifier","text"],"title":"AnswerChoice","description":"A single answer choice for a multiple choice question.\n\nSupports JSONPath for dynamic text generation and correctness evaluation."},"AnswerChoiceList-Input":{"properties":{"choices":{"items":{"$ref":"#/components/schemas/AnswerChoice-Input"},"type":"array","title":"Choices","description":"List of answer choices for the question"}},"type":"object","required":["choices"],"title":"AnswerChoiceList","description":"A list of answer choices for a multiple choice question."},"AnswerChoiceList-Output":{"properties":{"choices":{"items":{"$ref":"#/components/schemas/AnswerChoice-Output"},"type":"array","title":"Choices","description":"List of answer choices for the question"}},"type":"object","required":["choices"],"title":"AnswerChoiceList","description":"A list of answer choices for a multiple choice question."},"AuthLoginRequest":{"properties":{"username":{"type":"string","maxLength":255,"minLength":1,"title":"Username","description":"Login username or email (field name kept for clients)."},"password":{"type":"string","maxLength":255,"minLength":1,"title":"Password","description":"Plaintext password."}},"type":"object","required":["username","password"],"title":"AuthLoginRequest","examples":[{"password":"secret","username":"jordan"},{"password":"secret","username":"jordan@example.com"}]},"AuthRegisterRequest":{"properties":{"username":{"type":"string","maxLength":100,"minLength":1,"title":"Username","description":"Unique login name."},"password":{"type":"string","maxLength":255,"minLength":1,"title":"Password","description":"Plaintext password."},"email":{"type":"string","maxLength":255,"minLength":3,"title":"Email","description":"Unique email address."},"first_name":{"type":"string","maxLength":100,"minLength":1,"title":"First Name","description":"Given name."},"last_name":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Last Name","description":"Family name."},"postal_code":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Postal Code","description":"Postal / ZIP code."},"date_of_birth":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date Of Birth","description":"Date of birth (YYYY-MM-DD, no time)."}},"type":"object","required":["username","password","email","first_name"],"title":"AuthRegisterRequest","examples":[{"date_of_birth":"1990-01-15","email":"jordan@example.com","first_name":"Jordan","last_name":"Lee","password":"secret","postal_code":"M5V2T6","username":"jordan"}]},"AuthTokenOut":{"properties":{"api_key":{"type":"string","title":"Api Key","description":"Bearer API key plaintext (shown once; store client-side)."},"user_id":{"type":"string","format":"uuid","title":"User Id","description":"Authenticated user id."},"display_name":{"type":"string","title":"Display Name","description":"Player-facing name (first + last)."},"is_admin":{"type":"boolean","title":"Is Admin","description":"Whether the user is an admin."}},"type":"object","required":["api_key","user_id","display_name","is_admin"],"title":"AuthTokenOut","description":"Returned once on register/login — copy ``api_key`` into Swagger Authorize."},"Body_brands_create_api_brands_post":{"properties":{"name":{"type":"string","title":"Name","description":"Unique display name"},"primary_color":{"type":"string","title":"Primary Color","description":"Primary color #RRGGBB"},"secondary_color":{"type":"string","title":"Secondary Color","description":"Secondary color #RRGGBB"},"logo":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"Logo","description":"Optional logo (png, jpeg, svg, webp)"}},"type":"object","required":["name","primary_color","secondary_color"],"title":"Body_brands_create_api_brands_post"},"Body_brands_patch_api_brands__brand_id__patch":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"primary_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Primary Color"},"secondary_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Secondary Color"},"clear_logo":{"type":"boolean","title":"Clear Logo","description":"When true, delete the S3 logo and clear logo_filename","default":false},"logo":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"Logo","description":"Optional replacement logo"}},"type":"object","title":"Body_brands_patch_api_brands__brand_id__patch"},"Body_import_definitions_endpoint_api_match_question_definitions_import_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"Export-shaped CSV file"}},"type":"object","required":["file"],"title":"Body_import_definitions_endpoint_api_match_question_definitions_import_post"},"Body_import_definitions_endpoint_api_question_definitions_import_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"Export-shaped CSV file"}},"type":"object","required":["file"],"title":"Body_import_definitions_endpoint_api_question_definitions_import_post"},"BrandListOut":{"properties":{"brands":{"items":{"$ref":"#/components/schemas/BrandOut"},"type":"array","title":"Brands","description":"Matching brands, ordered by name."},"brand_count":{"type":"integer","title":"Brand Count","description":"Number of brands in ``brands``."}},"type":"object","required":["brands","brand_count"],"title":"BrandListOut"},"BrandOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Internal brand id (primary key)."},"name":{"type":"string","title":"Name","description":"Display name for the brand."},"logo_filename":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Filename","description":"Basename of the logo under brands/{id}/ in S3, if any."},"logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Url","description":"Stable public HTTPS URL for the logo object under brands/, or null when no logo is stored."},"primary_color":{"type":"string","title":"Primary Color","description":"Primary brand color as #RRGGBB."},"secondary_color":{"type":"string","title":"Secondary Color","description":"Secondary brand color as #RRGGBB."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"When the brand row was created (UTC)."},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"When the brand row was last updated (UTC)."}},"type":"object","required":["id","name","primary_color","secondary_color"],"title":"BrandOut"},"BrandQuestionSponsorshipsAssign":{"properties":{"match_ids":{"items":{"type":"string","format":"uuid"},"type":"array","minItems":1,"title":"Match Ids","description":"Matches to assign these slots on (at least one)."},"slots":{"items":{"$ref":"#/components/schemas/QuestionSponsorshipSlotIn"},"type":"array","title":"Slots","description":"Slots to insert for this brand on each match. Empty with replace_existing_for_brand clears that brand's question slots (unless ``random_percent`` is set)."},"random_percent":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":1.0},{"type":"null"}],"title":"Random Percent","description":"When set, for each match insert ``round(question_max_count * percent / 100)`` random slots (clamped to capacity). Mutually exclusive with non-empty ``slots``. Count can differ across matches with different max questions."},"replace_existing_for_brand":{"type":"boolean","title":"Replace Existing For Brand","description":"When true (default), delete this brand's existing question sponsorship rows on each match before inserting ``slots``.","default":true}},"type":"object","required":["match_ids"],"title":"BrandQuestionSponsorshipsAssign","description":"Body for ``POST /api/brands/{brand_id}/question-sponsorships``.","examples":[{"match_ids":["00000000-0000-0000-0000-000000000001"],"replace_existing_for_brand":true,"slots":[{"strategy":"question_number","target":"3"},{"best_effort":true,"strategy":"period","target":"1"},{"strategy":"random"}]}]},"BrandQuestionSponsorshipsAssignOut":{"properties":{"brand_id":{"type":"string","format":"uuid","title":"Brand Id","description":"Brand that owns the assigned slots."},"match_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Match Ids","description":"Matches that were updated."},"slots_per_match":{"type":"integer","title":"Slots Per Match","description":"Slots written per match when the count is the same on every match. With ``random_percent`` and mixed ``question_max_count``, this is the count for the first match; use ``sponsorships`` for the full set."},"sponsorships":{"items":{"$ref":"#/components/schemas/QuestionSponsorshipOut"},"type":"array","title":"Sponsorships","description":"All slots written for this brand across the matches."}},"type":"object","required":["brand_id","match_ids","slots_per_match","sponsorships"],"title":"BrandQuestionSponsorshipsAssignOut","description":"Result of a bulk brand → question sponsorship assign."},"BrandQuestionSponsorshipsListOut":{"properties":{"brand_id":{"type":"string","format":"uuid","title":"Brand Id","description":"Brand whose slots were listed."},"sponsorships":{"items":{"$ref":"#/components/schemas/QuestionSponsorshipOut"},"type":"array","title":"Sponsorships","description":"Slots for this brand, optionally limited to ``match_ids``."}},"type":"object","required":["brand_id","sponsorships"],"title":"BrandQuestionSponsorshipsListOut","description":"Existing question sponsorship slots for one brand (optional match filter)."},"BrandSummaryOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Internal brand id (primary key)."},"name":{"type":"string","title":"Name","description":"Display name for the brand."},"primary_color":{"type":"string","title":"Primary Color","description":"Primary brand color as #RRGGBB."},"secondary_color":{"type":"string","title":"Secondary Color","description":"Secondary brand color as #RRGGBB."},"logo_filename":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Filename","description":"Basename of the logo under brands/{id}/ in S3, if any."},"logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Url","description":"Stable public HTTPS URL for the logo object under brands/, or null when no logo is stored."}},"type":"object","required":["id","name","primary_color","secondary_color"],"title":"BrandSummaryOut","description":"Slim brand embed for match/issuance/answer payloads."},"CellRole":{"type":"string","enum":["wins","also_applies","inherit","unused"],"title":"CellRole","description":"How this layer participates for one setting."},"CloneQuestionSponsorshipIn":{"properties":{"strategy":{"$ref":"#/components/schemas/QuestionSponsorshipStrategies","description":"``question_number`` (target = 1-based sequence string), ``period`` (target = period label), or ``random`` (target null)."},"target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target","description":"Required for question_number and period; must be null for random."},"best_effort":{"type":"boolean","title":"Best Effort","description":"Period only (default true): if the target period is missed, claim on the next available unused issuance. Forced false for other strategies.","default":true},"question_definition_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Question Definition Id","description":"Optional pin: when this slot would claim next, force issuance to this definition. Null means any definition may claim the slot."},"brand_id":{"type":"string","format":"uuid","title":"Brand Id","description":"Brand that owns this slot on the clone."}},"type":"object","required":["strategy","brand_id"],"title":"CloneQuestionSponsorshipIn","description":"One question sponsorship slot when cloning a match (includes brand)."},"CombineRule":{"type":"string","enum":["override","and","max"],"title":"CombineRule","description":"How layers combine for one setting."},"CompetitorFailOut":{"properties":{"definition_id":{"type":"string","format":"uuid","title":"Definition Id","description":"Competitor definition id."},"name":{"type":"string","title":"Name","description":"Definition name."},"href":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Href","description":"Admin definition path."},"config_source":{"$ref":"#/components/schemas/SnapshotSource","description":"pinned (prior issuance snapshot) or live (current row)."},"failed_step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Failed Step","description":"First closed step id, or null if still in the selection pool."},"reason":{"type":"string","title":"Reason","description":"Why this definition lost or stayed in the pool."}},"type":"object","required":["definition_id","name","config_source","reason"],"title":"CompetitorFailOut","description":"Why another definition did not publish on this issuance's event."},"ConditionEvaluationView":{"properties":{"kind":{"type":"string","enum":["resolution_trigger","answer_choice"],"title":"Kind"},"label":{"type":"string","title":"Label"},"choice_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Choice Text"},"condition":{"type":"string","title":"Condition"},"result":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Result"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"segments":{"items":{"$ref":"#/components/schemas/ConditionSegment"},"type":"array","title":"Segments"},"substituted":{"type":"string","title":"Substituted","default":""}},"type":"object","required":["kind","label","condition"],"title":"ConditionEvaluationView","description":"One condition evaluated against a resolution context."},"ConditionSegment":{"properties":{"kind":{"type":"string","enum":["text","path"],"title":"Kind"},"text":{"type":"string","title":"Text"},"value":{"anyOf":[{},{"type":"null"}],"title":"Value"}},"type":"object","required":["kind","text"],"title":"ConditionSegment","description":"One span of a condition string for highlighted rendering."},"CsvImportFieldChange":{"properties":{"field":{"type":"string","title":"Field","description":"Writable field name."},"before":{"title":"Before","description":"Current DB value; null on create."},"after":{"title":"After","description":"Value from the CSV row."}},"type":"object","required":["field"],"title":"CsvImportFieldChange","description":"One writable-field difference for the import preview modal."},"CsvImportPreview":{"properties":{"dry_run":{"type":"boolean","title":"Dry Run","description":"True when no writes were attempted."},"applied":{"type":"boolean","title":"Applied","description":"True after a successful apply commit.","default":false},"row_count":{"type":"integer","title":"Row Count","description":"Data rows parsed (blank rows skipped)."},"create_count":{"type":"integer","title":"Create Count","description":"Rows that would create a definition."},"update_count":{"type":"integer","title":"Update Count","description":"Rows that would change an existing definition."},"unchanged_count":{"type":"integer","title":"Unchanged Count","description":"Existing rows with no writable diffs."},"error_count":{"type":"integer","title":"Error Count","description":"Rows that failed validation."},"rows":{"items":{"$ref":"#/components/schemas/CsvImportRowResult"},"type":"array","title":"Rows","description":"Per-row results in file order."}},"type":"object","required":["dry_run","row_count","create_count","update_count","unchanged_count","error_count","rows"],"title":"CsvImportPreview","description":"Bulk-import preview (dry-run) or apply result.","examples":[{"applied":false,"create_count":1,"dry_run":true,"error_count":0,"row_count":2,"rows":[],"unchanged_count":0,"update_count":1}]},"CsvImportRowResult":{"properties":{"row_number":{"type":"integer","title":"Row Number","description":"1-based CSV line number (header is 1)."},"action":{"type":"string","enum":["create","update","unchanged","error"],"title":"Action","description":"create, update, unchanged, or error."},"id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Id","description":"Definition id when present."},"league":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"League","description":"League slug from the CSV."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Definition name when parsed."},"changes":{"items":{"$ref":"#/components/schemas/CsvImportFieldChange"},"type":"array","title":"Changes"},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"}},"type":"object","required":["row_number","action"],"title":"CsvImportRowResult","description":"Per-CSV-row preview: action, field diffs, and validation errors."},"CurrentAnswerOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Answer row id."},"selected_answer_identifier":{"type":"string","title":"Selected Answer Identifier","description":"Choice identifier the user currently has selected."},"answered_at":{"type":"string","format":"date-time","title":"Answered At","description":"When the answer was last written (UTC)."}},"type":"object","required":["id","selected_answer_identifier","answered_at"],"title":"CurrentAnswerOut"},"DefinitionOption":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Definition id."},"name":{"type":"string","title":"Name","description":"Definition name."},"kind":{"$ref":"#/components/schemas/InheritanceKind","description":"in_game or match."},"group_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Group Id","description":"Question group id."},"group_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group Slug","description":"Issuance group slug."},"is_active":{"type":"boolean","title":"Is Active","description":"Whether the definition is active."},"is_pivotal_moment":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Pivotal Moment","description":"In-game pivotal label; null for Match questions."},"allowlisted":{"type":"boolean","title":"Allowlisted","description":"True when the effective allowlist includes this definition."}},"type":"object","required":["id","name","kind","is_active","allowlisted"],"title":"DefinitionOption","description":"Picker row for a definition in this league."},"EventTypeCatalog":{"properties":{"event_type":{"type":"string","title":"Event Type","description":"Sportradar ``payload.event.type`` value."},"path_count":{"type":"integer","title":"Path Count","description":"Number of paths collected.","default":0},"paths":{"items":{"$ref":"#/components/schemas/PathEntry"},"type":"array","title":"Paths","description":"Discovered paths for this event type."},"sample_event":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Sample Event","description":"Representative sample event when ``include_samples`` is true."}},"type":"object","required":["event_type"],"title":"EventTypeCatalog","description":"Paths and a representative sample for one ``payload.event.type``."},"GateOut":{"properties":{"id":{"type":"string","title":"Id","description":"Stable step id, e.g. ``allowlist``."},"label":{"type":"string","title":"Label","description":"Operator label."},"layer":{"$ref":"#/components/schemas/LayerKey","description":"Layer that owns this step."},"status":{"$ref":"#/components/schemas/GateStatus","description":"open / closed / skipped."},"reason":{"type":"string","title":"Reason","description":"Why this status applies."},"used":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Used","description":"Consumed count when countable."},"cap":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cap","description":"Cap when countable."}},"type":"object","required":["id","label","layer","status","reason"],"title":"GateOut","description":"One issuance or resolution step."},"GateStatus":{"type":"string","enum":["open","closed","skipped"],"title":"GateStatus","description":"Evaluated or static gate state."},"GroupOption":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Question group id."},"slug":{"type":"string","title":"Slug","description":"Per-league concurrency key."},"name":{"type":"string","title":"Name","description":"Operator label."},"is_active":{"type":"boolean","title":"Is Active","description":"Inactive groups cannot receive issuances."},"href":{"type":"string","title":"Href","description":"Admin question-groups deep link."}},"type":"object","required":["id","slug","name","is_active","href"],"title":"GroupOption","description":"Picker / layer row for a question group."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"InheritanceKind":{"type":"string","enum":["in_game","match"],"title":"InheritanceKind","description":"Which product line to inspect."},"IssuanceDenialOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Denial row id."},"match_id":{"type":"string","format":"uuid","title":"Match Id","description":"Internal match id."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"When the listener persisted this row (UTC)."},"event_eid":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Eid","description":"Stream event id."},"event_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Event Ts","description":"Stream event ts."},"event_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Type","description":"Short sport-event type label."},"issued_in_period":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issued In Period","description":"Period / phase stamped from the event."},"failed_step":{"type":"string","title":"Failed Step","description":"First listener short-circuit gate id."},"reason":{"type":"string","title":"Reason","description":"Why this pass did not publish."},"definition_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Definition Id","description":"Nearest-miss definition id, if known."},"definition_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Definition Name","description":"Nearest-miss definition name at persist time."},"definition_href":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Definition Href","description":"Admin path for the nearest-miss definition."},"group_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Group Id","description":"Question group id of the nearest-miss definition."},"group_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group Name","description":"Question group operator label."},"group_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group Slug","description":"Issuance group slug of the nearest-miss definition."},"group_href":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group Href","description":"Admin question-groups path."},"issuance_steps":{"items":{"$ref":"#/components/schemas/GateOut"},"type":"array","title":"Issuance Steps","description":"Synthesized listener short-circuit path for this attempt."},"triggered":{"items":{"$ref":"#/components/schemas/IssuanceDenialTriggeredOut"},"type":"array","title":"Triggered","description":"Definitions that passed trigger on this event."},"probability":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Probability","description":"Probability-gate details when failed_step is probability."},"details":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Details","description":"Structured extras for the closed gate (used/cap, wait seconds). Null on older rows."}},"type":"object","required":["id","match_id","failed_step","reason"],"title":"IssuanceDenialOut","description":"One blocked in-game issuance attempt (trigger matched, nothing published)."},"IssuanceDenialTriggeredOut":{"properties":{"definition_id":{"type":"string","format":"uuid","title":"Definition Id","description":"Triggered definition id."},"name":{"type":"string","title":"Name","description":"Definition name at persist time."},"href":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Href","description":"Admin definition path."},"failed_step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Failed Step","description":"First closed step id, or null if still in the selection pool."},"reason":{"type":"string","title":"Reason","description":"Why this definition lost or stayed in the pool."}},"type":"object","required":["definition_id","name","reason"],"title":"IssuanceDenialTriggeredOut","description":"One definition that passed trigger on a blocked attempt."},"IssuanceTraceOut":{"properties":{"issuance_id":{"type":"string","format":"uuid","title":"Issuance Id","description":"Issuance id."},"definition_id":{"type":"string","format":"uuid","title":"Definition Id","description":"Winning definition id."},"definition_name":{"type":"string","title":"Definition Name","description":"Winning definition name."},"definition_href":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Definition Href","description":"Admin definition path."},"group_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Group Id","description":"Question group id when the winner has one."},"group_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group Name","description":"Question group operator label."},"group_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group Slug","description":"Issuance group slug stamped on the winner."},"group_href":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group Href","description":"Admin question-groups path."},"is_pivotal_moment":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Pivotal Moment","description":"In-game pivotal from the pinned snapshot; null for Match questions."},"period":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period","description":"issued_in_period, when stamped."},"issued_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Issued At","description":"Issuance created_at / issued_at (UTC)."},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At","description":"When the issuance closed, if it has."},"snapshot_source":{"$ref":"#/components/schemas/SnapshotSource","description":"Winner config: pinned snapshot or live fallback."},"question_text":{"type":"string","title":"Question Text","description":"Rendered question text."},"issuance_steps":{"items":{"$ref":"#/components/schemas/GateOut"},"type":"array","title":"Issuance Steps","description":"Trigger + listener gates for this issuance."},"competitors":{"items":{"$ref":"#/components/schemas/CompetitorFailOut"},"type":"array","title":"Competitors","description":"Other definitions and their first failing step."},"resolution_steps":{"items":{"$ref":"#/components/schemas/GateOut"},"type":"array","title":"Resolution Steps","description":"How this issuance closed (reason, conditions, choices)."},"resolution_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolution Reason","description":"Stored resolution_reason, if any."},"correct_choice_labels":{"items":{"type":"string"},"type":"array","title":"Correct Choice Labels","description":"Choice labels marked correct on the stored issuance."}},"type":"object","required":["issuance_id","definition_id","definition_name","snapshot_source","question_text","issuance_steps"],"title":"IssuanceTraceOut","description":"Decision reconstruct for one published issuance."},"LayerKey":{"type":"string","enum":["league","match","group","definition","choice"],"title":"LayerKey","description":"Configuration layer that owns a cell or gate."},"LayerSummary":{"properties":{"key":{"$ref":"#/components/schemas/LayerKey","description":"Layer key."},"id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Id","description":"Entity id when applicable."},"name":{"type":"string","title":"Name","description":"Operator label."},"href":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Href","description":"Admin edit/inspect path."}},"type":"object","required":["key","name"],"title":"LayerSummary","description":"Identity + admin href for one inheritance layer."},"LeagueListOut":{"properties":{"leagues":{"items":{"$ref":"#/components/schemas/LeagueOut"},"type":"array","title":"Leagues","description":"All leagues."},"league_count":{"type":"integer","title":"League Count","description":"Number of leagues in ``leagues``."}},"type":"object","required":["leagues","league_count"],"title":"LeagueListOut"},"LeagueOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Internal league id (primary key)."},"sr_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Sr Id","description":"Sportradar league id when known."},"name":{"$ref":"#/components/schemas/LeagueTypes","description":"League slug / enum value, e.g. ``mlb``."},"enabled":{"type":"boolean","title":"Enabled","description":"Whether this league is enabled for operations."},"default_question_max_count":{"type":"integer","title":"Default Question Max Count","description":"Default max questions per match when the match has no override."},"default_question_pivotal_max_count":{"type":"integer","title":"Default Question Pivotal Max Count","description":"Default max pivotal-moment issuances per match when the match has no override."},"default_question_min_interval":{"type":"integer","title":"Default Question Min Interval","description":"Default minimum seconds between issuances (match/definition can only lengthen via max())."},"default_question_period_distribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"}],"title":"Default Question Period Distribution","description":"Default caps keyed by period/inning label (e.g. ``\"1\"`` … ``\"9\"``). Values are ``[normal, pivotal]`` (bare int ⇒ pivotal 0). ``{}`` = Issue ASAP; ``[]`` / ``{\"dist\": \"even\"}`` = even auto-fill."},"default_question_points":{"type":"integer","minimum":0.0,"title":"Default Question Points","description":"Default whole points awarded for a correct answer."},"default_answer_window_seconds":{"type":"integer","title":"Default Answer Window Seconds","description":"Seconds after issuance ``created_at`` during which answers may be submitted or updated."},"default_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Default Question Definition Ids","description":"Default question-definition allowlist for matches; null = all active definitions; [] = none; non-empty = only those ids. Match override replaces this when set."},"default_match_question_max_count":{"type":"integer","minimum":0.0,"title":"Default Match Question Max Count","description":"Default max Match questions per match; independent of in-game question_max_count.","default":1},"default_match_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Default Match Question Definition Ids","description":"Default Match question definition allowlist; null = all active; [] = none; non-empty = only those ids."},"default_match_question_resolution_grace_seconds":{"type":"integer","minimum":0.0,"title":"Default Match Question Resolution Grace Seconds","description":"Seconds after first terminal observation to retry official Full Game resolution before stale/award-all. Postpone/cancel/unnecessary skip this wait and stamp those statuses as the close reason.","default":900},"default_match_question_earliest_issue_seconds":{"type":"integer","minimum":0.0,"title":"Default Match Question Earliest Issue Seconds","description":"Seconds before scheduled start that Match questions may first be issued. 0 means no lead-time gate (issue on the next ensure).","default":900},"default_resolve_success_copies":{"items":{"type":"string"},"type":"array","title":"Default Resolve Success Copies","description":"Phrases stamped as resolve_copy when the player is correct."},"default_resolve_failed_copies":{"items":{"type":"string"},"type":"array","title":"Default Resolve Failed Copies","description":"Phrases stamped as resolve_copy when the player is wrong."},"default_resolve_copy":{"type":"string","title":"Default Resolve Copy","description":"Template for the player-facing resolve line. Placeholders: ``{{resolve_copy}}`` and ``{{outcome_text}}``.","default":"{{resolve_copy}} - {{outcome_text}}"},"default_period_distribution_display":{"type":"string","title":"Default Period Distribution Display","readOnly":true}},"type":"object","required":["id","name","enabled","default_question_max_count","default_question_pivotal_max_count","default_question_min_interval","default_question_points","default_answer_window_seconds","default_period_distribution_display"],"title":"LeagueOut","description":"League row including question-default configuration."},"LeagueSampleCatalog":{"properties":{"league":{"type":"string","title":"League","description":"League slug, e.g. mlb."},"source_file":{"type":"string","title":"Source File","description":"Packaged sample feed filename."},"event_types":{"items":{"type":"string"},"type":"array","title":"Event Types","description":"Distinct event types found in the sample."},"by_event_type":{"additionalProperties":{"$ref":"#/components/schemas/EventTypeCatalog"},"type":"object","title":"By Event Type","description":"Per-event-type path catalog keyed by event type string."},"match_state_paths":{"items":{"$ref":"#/components/schemas/PathEntry"},"type":"array","title":"Match State Paths","description":"Read-only ``$.match_state.*`` keys the listener publishes for this league (code catalog, not sample-feed paths)."}},"type":"object","required":["league","source_file"],"title":"LeagueSampleCatalog","description":"Field browser catalog for one league sample feed."},"LeagueTypes":{"type":"string","enum":["nfl","nhl","mlb"],"title":"LeagueTypes","description":"Supported sports leagues."},"LeagueUpdate":{"properties":{"default_question_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Default Question Max Count","description":"Default max questions per match when the match has no override."},"default_question_pivotal_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Default Question Pivotal Max Count","description":"Default max pivotal-moment issuances per match when the match has no override."},"default_question_min_interval":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Default Question Min Interval","description":"Default minimum seconds between issuances (match/definition can only lengthen via max())."},"default_question_period_distribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"},{"type":"null"}],"title":"Default Question Period Distribution","description":"Default caps keyed by period/inning label. Values are ``[normal, pivotal]``. ``{}`` = Issue ASAP; ``[]`` / ``{\"dist\": \"even\"}`` = even auto-fill. Invalid shapes return 400 (not 422)."},"default_question_points":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Default Question Points","description":"Default whole points awarded for a correct answer."},"default_answer_window_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Default Answer Window Seconds","description":"Seconds after issuance ``created_at`` during which answers may be submitted or updated."},"default_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Default Question Definition Ids","description":"Question-definition allowlist; omit unchanged, null = all active, [] = none. Ids must belong to this league."},"default_match_question_max_count":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Default Match Question Max Count","description":"Default max Match questions per match; omit unchanged."},"default_match_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Default Match Question Definition Ids","description":"Match question definition allowlist; omit unchanged, null = all active, [] = none. Ids must belong to this league."},"default_match_question_resolution_grace_seconds":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Default Match Question Resolution Grace Seconds","description":"Match question official-resolution grace in seconds; omit unchanged."},"default_match_question_earliest_issue_seconds":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Default Match Question Earliest Issue Seconds","description":"Seconds before scheduled start that Match questions may first be issued; omit unchanged. 0 means no lead-time gate."},"default_resolve_success_copies":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Default Resolve Success Copies","description":"Phrases stamped as resolve_copy when the player is correct."},"default_resolve_failed_copies":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Default Resolve Failed Copies","description":"Phrases stamped as resolve_copy when the player is wrong."},"default_resolve_copy":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}],"title":"Default Resolve Copy","description":"Template for the player-facing resolve line. Placeholders: ``{{resolve_copy}}`` and ``{{outcome_text}}``."}},"type":"object","title":"LeagueUpdate","description":"Partial update for league question-default configuration.\n\nOmitted fields leave the row unchanged. All defaults may be set\ntogether or individually."},"MatchCloneOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Internal id of the new ``is_test`` clone."},"sr_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Sr Id","description":"Sportradar match id copied from the source."},"scheduled":{"type":"string","title":"Scheduled","description":"Clone scheduled kickoff (ISO-like string)."},"status":{"type":"string","title":"Status","description":"Initial status of the clone."},"is_test":{"type":"boolean","title":"Is Test","description":"Always true for clones from this endpoint."},"push_notifications_enabled":{"type":"boolean","title":"Push Notifications Enabled","description":"Whether push notifications are enabled for this clone."},"cloned_from_match_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cloned From Match Id","description":"Source internal match id."},"created_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Created By User Id","description":"Admin user id who created this test clone."},"listener_start_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Listener Start Settings","description":"Settings persisted for the enqueued listener."},"task_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Task Id","description":"Celery task id for ``start_match_listener``."},"display_label":{"type":"string","title":"Display Label","description":"Short away@home-style label.","default":""}},"type":"object","required":["id","scheduled","status","is_test","push_notifications_enabled"],"title":"MatchCloneOut","description":"Cloned match plus enqueued Celery task id."},"MatchCloneRequest":{"properties":{"scheduled_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled At","description":"Clone kickoff (Match.scheduled; default now UTC). When in the future, start_match_listener is Celery-delayed until this instant so one-shot (wait_for_listener) and continuous clones both wait."},"start_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start At","description":"srsim stream anchor to begin playback (e.g. ``1:10:00`` or MLB ``1:T`` / ``1:B``). Folded into listener_sr_request_append."},"end_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End At","description":"srsim stream anchor to end playback; see start_at formats."},"playback_speed":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Playback Speed","description":"srsim playback speed multiplier (0+)."},"default_event_delay_ms":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Default Event Delay Ms","description":"srsim default delay between events in milliseconds."},"max_ms_between_events":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Max Ms Between Events","description":"srsim cap on inter-event delay in milliseconds."},"skip_heartbeats":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Skip Heartbeats","description":"When true, srsim omits heartbeat events."},"heartbeat_ms_override":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Heartbeat Ms Override","description":"Override heartbeat interval in milliseconds."},"end_with_infinite_heartbeats":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"End With Infinite Heartbeats","description":"When true, keep heartbeats after the recording ends."},"skip_corrective_events":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Skip Corrective Events","description":"When true, srsim skips corrective events."},"rewrite_ts_strategy":{"anyOf":[{"type":"integer","maximum":2.0,"minimum":0.0},{"type":"null"}],"title":"Rewrite Ts Strategy","description":"srsim event ts rewrite: 0 keep archive ts, 1 real-time at emit, 2 sim clock advanced by paced inter-event delays.","default":0},"game_delay_at_event":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Game Delay At Event","description":"srsim game-delay-at-event parameter (stream slicing)."},"wait_for_listener":{"type":"boolean","title":"Wait For Listener","description":"When true, omit continuous-session ``session=`` so srsim uses one-shot replay (stream starts when the listener attaches). When false (default), inject ``session=<Match.id>`` for a Sportradar-like continuous session from scheduled kickoff.","default":false},"push_notifications_enabled":{"type":"boolean","title":"Push Notifications Enabled","description":"When true, push notifications may deliver for this clone (still subject to global/user gates). Default false so test clones do not notify the auto-followed creator.","default":false},"override_question_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Question Max Count","description":"Omit copies source; null clears to league default."},"override_question_pivotal_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Question Pivotal Max Count","description":"Omit copies source; null clears to league default."},"override_question_min_interval":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Question Min Interval","description":"Omit copies source; null clears to league default."},"override_question_points":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Override Question Points","description":"Omit copies source; null clears to league default."},"override_question_period_distribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"},{"type":"null"}],"title":"Override Question Period Distribution","description":"Omit copies source; null clears to league default. {} = Issue ASAP; [] = even auto-fill."},"override_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Override Question Definition Ids","description":"Omit copies source; null clears (all active league defs). [] = none; non-empty must be ids for this match's league."},"override_match_question_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Match Question Max Count","description":"Omit copies source; null clears to league default."},"override_match_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Override Match Question Definition Ids","description":"Omit copies source; null clears to league default. [] = none; non-empty must be ids for this match's league."},"override_match_question_resolution_grace_seconds":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Override Match Question Resolution Grace Seconds","description":"Omit copies source; null clears to league default."},"override_match_question_earliest_issue_seconds":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Override Match Question Earliest Issue Seconds","description":"Omit copies source; null clears to league default. 0 means no lead-time gate."},"sponsor_brand_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Sponsor Brand Id","description":"Whole-match sponsor brand id. Omit copies source; null clears."},"question_sponsorships":{"anyOf":[{"items":{"$ref":"#/components/schemas/CloneQuestionSponsorshipIn"},"type":"array"},{"type":"null"}],"title":"Question Sponsorships","description":"Question sponsorship slots for the clone. Omit copies source slots; [] clears; otherwise replaces with this list (any brands)."},"listener_timing_source":{"anyOf":[{"type":"string","enum":["realtime","ts"]},{"type":"null"}],"title":"Listener Timing Source","description":"Timed gates: realtime, or ts stream deltas (sim default).","default":"ts"},"listener_post_issuance_pause_seconds":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Listener Post Issuance Pause Seconds","description":"Real-time seconds to sleep after each successful question issuance before consuming the next stream event. Independent of timing source. Useful with fast playback; omit/0 for no pause."},"listener_log_level":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":0.0},{"type":"null"}],"title":"Listener Log Level","description":"Python logging level for the listener process (0–50)."},"listener_sr_url_environment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Listener Sr Url Environment","description":"Sportradar URL environment label for the listener."},"listener_sr_request_timeout":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Listener Sr Request Timeout","description":"HTTP timeout seconds for Sportradar/srsim requests."},"listener_max_consecutive_heartbeats":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Listener Max Consecutive Heartbeats","description":"Exit after this many consecutive heartbeats without events."},"listener_match_status_check_heartbeats":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Listener Match Status Check Heartbeats","description":"How often (in heartbeats) to re-check match status."},"listener_skip_processing_events":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Listener Skip Processing Events","description":"When true, consume the stream without issuing questions."},"listener_dry_run":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Listener Dry Run","description":"When true, run without persisting issuances/answers."},"listener_write_events_to_file":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Listener Write Events To File","description":"When true, write the event recording JSON."},"listener_write_logs_to_file":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Listener Write Logs To File","description":"When true, write the per-run text log."},"listener_force_exit_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Listener Force Exit Code","description":"Ops testing: force SystemExit with this code before stream work. Omit for normal runs."}},"type":"object","title":"MatchCloneRequest","description":"Body for ``POST /api/matches/{id}/clone``.\n\n``scheduled_at`` sets the clone's ``Match.scheduled`` (default: now UTC).\nsrsim_*-style fields become ``listener_sr_request_append`` query params.\n``listener_*`` fields are Celery/env overrides for the started listener.\n\nQuestion ``override_*`` fields: omitted copies the source match; explicit\n``null`` clears (league defaults); a value sets the clone override.\n\n``sponsor_brand_id`` / ``question_sponsorships``: omitted copies the source;\nexplicit ``null`` / ``[]`` clears; a value sets the clone sponsor or slots."},"MatchDetailLeagueOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Internal league id."},"name":{"type":"string","title":"Name","description":"League slug, e.g. mlb."},"default_question_max_count":{"type":"integer","title":"Default Question Max Count","description":"League default max questions per match."},"default_question_pivotal_max_count":{"type":"integer","title":"Default Question Pivotal Max Count","description":"League default max pivotal-moment issuances per match."},"default_question_min_interval":{"type":"integer","title":"Default Question Min Interval","description":"League default min interval after resolution (seconds)."},"default_question_period_distribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"}],"title":"Default Question Period Distribution","description":"League default period/inning caps. Values are [normal, pivotal]. {} = Issue ASAP; [] / {dist: even} = even auto-fill."},"default_question_points":{"type":"integer","minimum":0.0,"title":"Default Question Points","description":"League default whole points for a correct answer."},"default_answer_window_seconds":{"type":"integer","title":"Default Answer Window Seconds","description":"League default answer window (seconds)."},"default_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Default Question Definition Ids","description":"League default question-definition allowlist; null = all active."},"default_match_question_max_count":{"type":"integer","minimum":0.0,"title":"Default Match Question Max Count","description":"League default max Match questions per match.","default":1},"default_match_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Default Match Question Definition Ids","description":"League default Match question definition allowlist; null = all active."},"default_match_question_resolution_grace_seconds":{"type":"integer","minimum":0.0,"title":"Default Match Question Resolution Grace Seconds","description":"League default Match question official-resolution grace (seconds).","default":900},"default_match_question_earliest_issue_seconds":{"type":"integer","minimum":0.0,"title":"Default Match Question Earliest Issue Seconds","description":"League default seconds before scheduled start that Match questions may first be issued. 0 means no lead-time gate.","default":900},"default_resolve_success_copies":{"items":{"type":"string"},"type":"array","title":"Default Resolve Success Copies","description":"Phrases stamped as resolve_copy when the player is correct."},"default_resolve_failed_copies":{"items":{"type":"string"},"type":"array","title":"Default Resolve Failed Copies","description":"Phrases stamped as resolve_copy when the player is wrong."},"default_resolve_copy":{"type":"string","title":"Default Resolve Copy","description":"Template for the player-facing resolve line. Placeholders: {{resolve_copy}} and {{outcome_text}}.","default":"{{resolve_copy}} - {{outcome_text}}"}},"type":"object","required":["id","name","default_question_max_count","default_question_pivotal_max_count","default_question_min_interval","default_question_period_distribution","default_question_points","default_answer_window_seconds"],"title":"MatchDetailLeagueOut","description":"League summary with question defaults."},"MatchDetailOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Internal match id (``Match.id``)."},"sr_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Sr Id","description":"Sportradar match id (``Match.sr_id``)."},"scheduled":{"type":"string","title":"Scheduled","description":"Scheduled kickoff as stored (ISO-like string)."},"status":{"type":"string","title":"Status","description":"Match status: scheduled, inprogress, delayed, or closed."},"score":{"anyOf":[{"$ref":"#/components/schemas/MatchScoreOut"},{"type":"null"}],"description":"Last-known home/away totals from the live stream. Null before the listener sees both sides. Not a live ticker — refresh the detail."},"is_test":{"type":"boolean","title":"Is Test","description":"True for cloned/test matches."},"display_label":{"type":"string","title":"Display Label","description":"Short away@home-style label."},"display_title":{"type":"string","title":"Display Title","description":"Full market + team name headline."},"shortcode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shortcode","description":"``{sr_id[:8]}-{match_id[:8]}`` when ``sr_id`` is set."},"push_notifications_enabled":{"type":"boolean","title":"Push Notifications Enabled","description":"When False, push notification fan-out skips this match."},"auto_dispatch_listener":{"type":"boolean","title":"Auto Dispatch Listener","description":"When False, auto-dispatch skips this match."},"listener_events_archived":{"type":"boolean","title":"Listener Events Archived","description":"True when S3 gamedata archive is available."},"cloned_from_match_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cloned From Match Id","description":"Source internal match id when this row is a clone."},"cloned_from_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cloned From Label","description":"Short label for the clone source match when available."},"created_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Created By User Id","description":"Admin user id who cloned this test match; null for live matches and clones created before this field existed."},"created_by_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Label","description":"Display name for the admin who cloned this test match."},"override_question_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Question Max Count"},"override_question_pivotal_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Question Pivotal Max Count"},"override_question_min_interval":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Question Min Interval"},"override_question_period_distribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"},{"type":"null"}],"title":"Override Question Period Distribution"},"override_question_points":{"anyOf":[{"type":"integer"},{"type":"string"},{"type":"null"}],"title":"Override Question Points"},"override_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Override Question Definition Ids","description":"Per-match question-definition allowlist; null = all active league definitions; [] = none; non-empty = only those ids."},"override_match_question_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Match Question Max Count"},"override_match_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Override Match Question Definition Ids","description":"Per-match Match question definition allowlist; null uses league default."},"match_questions_locked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Match Questions Locked At"},"match_questions_ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Match Questions Ended At","description":"When Match question official resolution started (first terminal observation). Grace is measured from this stamp."},"override_match_question_resolution_grace_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Match Question Resolution Grace Seconds"},"effective_match_question_resolution_grace_seconds":{"type":"integer","minimum":0.0,"title":"Effective Match Question Resolution Grace Seconds","description":"Resolved Match question official-resolution grace (seconds).","default":900},"override_match_question_earliest_issue_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Match Question Earliest Issue Seconds","description":"Per-match Match question earliest-issue lead time (seconds); null uses league default."},"effective_match_question_earliest_issue_seconds":{"type":"integer","minimum":0.0,"title":"Effective Match Question Earliest Issue Seconds","description":"Resolved seconds before scheduled start that Match questions may first be issued.","default":900},"effective_question_max_count":{"type":"integer","title":"Effective Question Max Count","description":"Resolved in-game max questions (override or league default)."},"effective_question_pivotal_max_count":{"type":"integer","title":"Effective Question Pivotal Max Count","description":"Resolved max pivotal-moment issuances (override or league default)."},"effective_question_min_interval":{"type":"integer","title":"Effective Question Min Interval","description":"Resolved min interval seconds (override or league default)."},"effective_question_period_distribution":{"additionalProperties":{"type":"integer"},"type":"object","title":"Effective Question Period Distribution","description":"Resolved period caps (override or league default)."},"effective_question_points":{"type":"integer","minimum":0.0,"title":"Effective Question Points","description":"Resolved whole points for a correct answer (match level)."},"effective_answer_window_seconds":{"type":"integer","title":"Effective Answer Window Seconds","description":"Resolved answer window seconds (league default)."},"effective_match_question_max_count":{"type":"integer","minimum":0.0,"title":"Effective Match Question Max Count","description":"Resolved Match question cap (override or league default).","default":1},"match_question_issuances":{"items":{"$ref":"#/components/schemas/MatchQuestionIssuanceOut"},"type":"array","title":"Match Question Issuances","description":"Issued Match questions for this match."},"league":{"$ref":"#/components/schemas/MatchDetailLeagueOut","description":"Owning league with defaults."},"season":{"anyOf":[{"$ref":"#/components/schemas/MatchDetailSeasonOut"},{"type":"null"}],"description":"Season when loaded."},"home_team":{"$ref":"#/components/schemas/MatchDetailTeamOut","description":"Home team."},"away_team":{"$ref":"#/components/schemas/MatchDetailTeamOut","description":"Away team."},"listener_start_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Listener Start Settings","description":"Raw stored listener start settings (may include metadata)."},"listener_settings":{"items":{"$ref":"#/components/schemas/MatchListenerSettingOut"},"type":"array","title":"Listener Settings","description":"Effective listener_* settings for ops display (match override, model default, or match identity)."},"listeners":{"items":{"$ref":"#/components/schemas/MatchListenerRecordOut"},"type":"array","title":"Listeners","description":"All listener lifecycle rows for this match, newest first."},"listener_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Listener Status","description":"Latest listener derived status, or null when none."},"listener_is_running":{"type":"boolean","title":"Listener Is Running","description":"True when the latest open listener has a fresh heartbeat.","default":false},"overrides_editable":{"type":"boolean","title":"Overrides Editable","description":"False once a listener has started or the match is past scheduled."},"sponsor_brand":{"anyOf":[{"$ref":"#/components/schemas/BrandSummaryOut"},{"type":"null"}],"description":"Whole-match sponsor brand, if set."},"question_sponsorships":{"items":{"$ref":"#/components/schemas/QuestionSponsorshipOut"},"type":"array","title":"Question Sponsorships","description":"Pre-allocated per-question sponsorship slots for this match."},"sponsored_question_count":{"type":"integer","title":"Sponsored Question Count","description":"Number of question sponsorship slots on this match.","default":0},"follower_count":{"type":"integer","title":"Follower Count","description":"Number of users currently following this match.","default":0},"user_feedback_count":{"type":"integer","title":"User Feedback Count","description":"Number of user-feedback rows for this match.","default":0},"listener_state":{"type":"string","title":"Listener State","readOnly":true}},"type":"object","required":["id","scheduled","status","is_test","display_label","display_title","push_notifications_enabled","auto_dispatch_listener","listener_events_archived","effective_question_max_count","effective_question_pivotal_max_count","effective_question_min_interval","effective_question_period_distribution","effective_question_points","effective_answer_window_seconds","league","home_team","away_team","listener_settings","listeners","overrides_editable","listener_state"],"title":"MatchDetailOut","description":"Full ops read model for a single match."},"MatchDetailSeasonOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Internal season id."},"year":{"type":"integer","title":"Year","description":"Season year."},"type_code":{"type":"string","title":"Type Code","description":"Season type code, e.g. REG."},"type_name":{"type":"string","title":"Type Name","description":"Season type display name."},"status":{"type":"string","title":"Status","description":"Season status."}},"type":"object","required":["id","year","type_code","type_name","status"],"title":"MatchDetailSeasonOut","description":"Season summary nested on match detail."},"MatchDetailTeamOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Internal team id."},"name":{"type":"string","title":"Name","description":"Team name."},"market":{"type":"string","title":"Market","description":"Team market/city."},"alias":{"type":"string","title":"Alias","description":"Team short alias."}},"type":"object","required":["id","name","market","alias"],"title":"MatchDetailTeamOut","description":"Team summary nested on match detail."},"MatchEventTimelineOut":{"properties":{"match_id":{"type":"string","format":"uuid","title":"Match Id","description":"Internal match id (``Match.id``)."},"points":{"items":{"$ref":"#/components/schemas/MatchTimelinePointOut"},"type":"array","title":"Points","description":"Timeline markers in occurred_at order."},"period_marks":{"items":{"$ref":"#/components/schemas/MatchTimelinePeriodMarkOut"},"type":"array","title":"Period Marks","description":"First occurrence of each period_label (stream events when present, otherwise issuances / blocked attempts)."},"point_count":{"type":"integer","title":"Point Count","description":"len(points)."}},"type":"object","required":["match_id","points","period_marks","point_count"],"title":"MatchEventTimelineOut","description":"Scatter points plus period-change marks for one match."},"MatchFollowOut":{"properties":{"match_id":{"type":"string","format":"uuid","title":"Match Id","description":"Internal match id."},"following":{"type":"boolean","title":"Following","description":"Whether the caller follows this match."},"match_daily_follow_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Match Daily Follow Count","description":"User's daily non-test follow cap; null when the follow system is disabled for this user."},"follows_used_today":{"type":"integer","title":"Follows Used Today","description":"Non-test follows created in the user's current local calendar day (``User.match_follow_timezone``)."},"follows_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Follows Remaining","description":"Remaining non-test follow slots today; null when unrestricted."}},"type":"object","required":["match_id","following","match_daily_follow_count","follows_used_today","follows_remaining"],"title":"MatchFollowOut","description":"Follow state after POST/DELETE follow, plus daily quota snapshot."},"MatchListItemOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Internal match id (``Match.id``)."},"sr_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Sr Id","description":"Sportradar match id (``Match.sr_id``)."},"scheduled":{"type":"string","title":"Scheduled","description":"Scheduled kickoff as stored (ISO-like string)."},"status":{"type":"string","title":"Status","description":"Match status: scheduled, inprogress, delayed, or closed."},"score":{"anyOf":[{"$ref":"#/components/schemas/MatchScoreOut"},{"type":"null"}],"description":"Last-known home/away totals from the live stream. Null before the listener sees both sides. Not a live ticker — refresh the list."},"league_id":{"type":"string","format":"uuid","title":"League Id","description":"Internal league id."},"league_name":{"type":"string","title":"League Name","description":"League slug, e.g. mlb."},"home_team_id":{"type":"string","format":"uuid","title":"Home Team Id","description":"Internal home team id."},"home_team_name":{"type":"string","title":"Home Team Name","description":"Home team name.","default":""},"home_team_market":{"type":"string","title":"Home Team Market","description":"Home team market/city.","default":""},"home_team_alias":{"type":"string","title":"Home Team Alias","description":"Home team short alias."},"away_team_id":{"type":"string","format":"uuid","title":"Away Team Id","description":"Internal away team id."},"away_team_name":{"type":"string","title":"Away Team Name","description":"Away team name.","default":""},"away_team_market":{"type":"string","title":"Away Team Market","description":"Away team market/city.","default":""},"away_team_alias":{"type":"string","title":"Away Team Alias","description":"Away team short alias."},"is_test":{"type":"boolean","title":"Is Test","description":"True for cloned/test matches (srsim-capable).","default":false},"push_notifications_enabled":{"type":"boolean","title":"Push Notifications Enabled","description":"When False, push notification fan-out skips this match.","default":true},"display_label":{"type":"string","title":"Display Label","description":"Short away@home-style label."},"display_title":{"type":"string","title":"Display Title","description":"Full market + team name headline.","default":""},"shortcode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shortcode","description":"``{sr_id[:8]}-{match_id[:8]}`` when ``sr_id`` is set."},"override_question_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Question Max Count","description":"Per-match in-game max question override; null uses league default."},"override_question_pivotal_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Question Pivotal Max Count","description":"Per-match max pivotal-moment override; null uses league default."},"override_question_min_interval":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Question Min Interval","description":"Per-match min interval override (seconds); null uses league."},"override_question_period_distribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"},{"type":"null"}],"title":"Override Question Period Distribution","description":"Per-match period/inning caps; null uses league default. Values are [normal, pivotal] (bare int ⇒ pivotal 0). {} = Issue ASAP; [] / {dist: even} = even auto-fill at listener start."},"override_question_points":{"anyOf":[{"type":"integer"},{"type":"string"},{"type":"null"}],"title":"Override Question Points","description":"Per-match points override; null uses league default."},"override_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Override Question Definition Ids","description":"Per-match question-definition allowlist; null uses all active league definitions; [] = none; non-empty = only those definition ids."},"override_match_question_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Match Question Max Count","description":"Per-match Match question cap; null uses league default."},"override_match_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Override Match Question Definition Ids","description":"Per-match Match question definition allowlist; null uses league default; [] = none; non-empty = only those ids."},"match_questions_locked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Match Questions Locked At","description":"When Match question answers were committed (first pitch / inprogress+)."},"override_match_question_resolution_grace_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Match Question Resolution Grace Seconds","description":"Per-match Match question official-resolution grace (seconds); null uses league default."},"override_match_question_earliest_issue_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Match Question Earliest Issue Seconds","description":"Per-match seconds before scheduled start that Match questions may first be issued; null uses league default. 0 means no lead-time gate."},"auto_dispatch_listener":{"type":"boolean","title":"Auto Dispatch Listener","description":"When False, ``dispatch_upcoming_match_listeners`` skips this match.","default":true},"cloned_from_match_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cloned From Match Id","description":"Source internal match id when this row is a clone."},"listener_start_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Listener Start Settings","description":"Persisted listener env/srsim settings for the next start."},"listener_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listener Id","description":"Latest listener lifecycle row id when present."},"listener_created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Listener Created At","description":"Latest listener created_at (UTC)."},"listener_ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Listener Ended At","description":"Latest listener ended_at (UTC)."},"listener_exit_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Listener Exit Code","description":"Latest listener process exit code."},"listener_exit_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Listener Exit Message","description":"Latest listener exit message."},"listener_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Listener Status","description":"Same derived status as Match Listeners: running, stale, abandoned, stopped, or ended; null when no lifecycle row."},"listener_is_running":{"type":"boolean","title":"Listener Is Running","description":"True when the latest open listener has a fresh heartbeat (status running).","default":false},"overrides_editable":{"type":"boolean","title":"Overrides Editable","description":"False once a listener has started or the match is past scheduled.","default":true},"sponsor_brand":{"anyOf":[{"$ref":"#/components/schemas/BrandSummaryOut"},{"type":"null"}],"description":"Whole-match sponsor brand, if set."},"sponsored_question_count":{"type":"integer","title":"Sponsored Question Count","description":"Number of question sponsorship slots on this match (all brands).","default":0},"question_issuance_count":{"type":"integer","title":"Question Issuance Count","description":"Non-pivotal in-game questions issued for this match so far (excludes pivotal moments).","default":0},"pivotal_moment_issuance_count":{"type":"integer","title":"Pivotal Moment Issuance Count","description":"Pivotal-moment in-game questions issued for this match (from definition snapshot, else live definition; not included in question_issuance_count).","default":0},"listener_state":{"type":"string","title":"Listener State","description":"Filter-friendly alias of ``listener_status`` (or ``none``).","readOnly":true},"has_overrides":{"type":"boolean","title":"Has Overrides","readOnly":true},"period_distribution_form_value":{"type":"string","title":"Period Distribution Form Value","readOnly":true}},"type":"object","required":["id","scheduled","status","league_id","league_name","home_team_id","home_team_alias","away_team_id","away_team_alias","display_label","listener_state","has_overrides","period_distribution_form_value"],"title":"MatchListItemOut","description":"One match row for filtered list endpoints."},"MatchListOut":{"properties":{"matches":{"items":{"$ref":"#/components/schemas/MatchListItemOut"},"type":"array","title":"Matches","description":"Matching matches."},"match_count":{"type":"integer","title":"Match Count","description":"Number of matches in ``matches``."}},"type":"object","required":["matches","match_count"],"title":"MatchListOut"},"MatchListenerListOut":{"properties":{"groups":{"items":{"$ref":"#/components/schemas/MatchListenerMatchGroupOut"},"type":"array","title":"Groups","description":"Matches with at least ``min_runs`` listener rows."},"group_count":{"type":"integer","title":"Group Count","description":"Number of match groups."},"listener_count":{"type":"integer","title":"Listener Count","description":"Total listener rows across groups."}},"type":"object","required":["groups","group_count","listener_count"],"title":"MatchListenerListOut"},"MatchListenerLogOut":{"properties":{"available":{"type":"boolean","title":"Available","description":"False when the log file is missing or empty."},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"Log file path when known."},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content","description":"Log text (may be truncated); null if unavailable."},"truncated":{"type":"boolean","title":"Truncated","description":"True when ``content`` was size-capped.","default":false},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Why the log is unavailable when ``available`` is false."}},"type":"object","required":["available"],"title":"MatchListenerLogOut","description":"Text log payload for one listener run (may be unavailable)."},"MatchListenerMatchGroupOut":{"properties":{"match_id":{"type":"string","format":"uuid","title":"Match Id","description":"Internal match id (``Match.id``)."},"display_label":{"type":"string","title":"Display Label","description":"Short away@home-style label."},"display_title":{"type":"string","title":"Display Title","description":"Full market + team name headline.","default":""},"shortcode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shortcode","description":"``{sr_id[:8]}-{match_id[:8]}`` when ``sr_id`` is set."},"scheduled":{"type":"string","title":"Scheduled","description":"Scheduled kickoff as stored."},"status":{"type":"string","title":"Status","description":"Match status string."},"is_test":{"type":"boolean","title":"Is Test","description":"True for test/clone matches.","default":false},"sr_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Sr Id","description":"Sportradar match id when known."},"league_name":{"type":"string","title":"League Name","description":"League slug, e.g. mlb."},"enqueued_celery_task_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Enqueued Celery Task Id","description":"Bookkeeping id from Match.listener_start_settings['celery_task_id'] when a start was queued (may differ from a run's MatchListenerRecord.celery_task_id)"},"listeners":{"items":{"$ref":"#/components/schemas/MatchListenerOut"},"type":"array","title":"Listeners","description":"Lifecycle rows for this match (newest runs included)."},"listener_count":{"type":"integer","title":"Listener Count","description":"Number of listeners in ``listeners``."},"events_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Events Path","description":"Shared S3 events key when the match is archived."}},"type":"object","required":["match_id","display_label","scheduled","status","league_name","listeners","listener_count"],"title":"MatchListenerMatchGroupOut","description":"Listener runs for one match on the selected league/day."},"MatchListenerOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Listener lifecycle row id."},"match_id":{"type":"string","format":"uuid","title":"Match Id","description":"Internal match id (``Match.id``)."},"status":{"type":"string","enum":["running","stale","abandoned","stopped","ended"],"title":"Status","description":"Derived status: running, stale, abandoned, stopped, or ended."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"When the run started (UTC)."},"last_heartbeat_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Heartbeat At","description":"Last heartbeat timestamp (UTC)."},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At","description":"When the run ended (UTC); null if still open."},"exit_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Exit Code","description":"Process exit code."},"exit_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exit Message","description":"Exit / stop message."},"celery_task_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Celery Task Id","description":"Celery id for the long-running start_match_listener task when recorded on the lifecycle row (used to revoke/stop)"},"startup_params":{"items":{"$ref":"#/components/schemas/StartupParamOut"},"type":"array","title":"Startup Params","description":"Labeled startup settings for operator display."},"write_logs_to_file":{"type":"boolean","title":"Write Logs To File","description":"Whether this run wrote a text log file.","default":false},"log_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Log Path","description":"S3 object key for the text log when the match is archived (``listener_events_archived``)."},"events_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Events Path","description":"S3 object key for the event recording JSON when the match is archived."}},"type":"object","required":["id","match_id","status"],"title":"MatchListenerOut","description":"One ``match_listeners`` lifecycle row for admin/API."},"MatchListenerRecordOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Listener record id."},"celery_task_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Celery Task Id","description":"Celery task id when started via Celery."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"When the run started (UTC)."},"last_heartbeat_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Heartbeat At","description":"Last heartbeat (UTC)."},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At","description":"When the run ended (UTC)."},"exit_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Exit Code","description":"Process exit code."},"exit_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exit Message","description":"Exit reason summary."},"status":{"type":"string","title":"Status","description":"Derived status: running, stale, abandoned, stopped, or ended."},"startup_params":{"additionalProperties":true,"type":"object","title":"Startup Params","description":"Startup configuration snapshot recorded for this run."}},"type":"object","required":["id","status"],"title":"MatchListenerRecordOut","description":"One listener lifecycle row for a match."},"MatchListenerSettingOut":{"properties":{"key":{"type":"string","title":"Key","description":"Listener environment field name."},"value":{"title":"Value","description":"Effective value used for display."},"source":{"type":"string","enum":["match","default","match_identity"],"title":"Source","description":"Where the value comes from: stored match override, model default, or match identity injection (sr_id / match id / league)."}},"type":"object","required":["key","value","source"],"title":"MatchListenerSettingOut","description":"One effective listener setting for ops display."},"MatchQuestionDefinitionClone":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Clone name; default is '{source} (copy)'."}},"type":"object","title":"MatchQuestionDefinitionClone"},"MatchQuestionDefinitionCreate":{"properties":{"name":{"type":"string","title":"Name","description":"Unique name within the owning league."},"is_active":{"type":"boolean","title":"Is Active","description":"Inactive definitions are not issued onto new matches.","default":true},"question_text":{"type":"string","title":"Question Text","description":"Templated player-facing question text."},"folder_path":{"type":"string","maxLength":1024,"title":"Folder Path","description":"Slash-separated admin folder path (empty = unfiled). Organization only.","default":""},"issuance_weight":{"type":"number","minimum":0.0,"title":"Issuance Weight","description":"Relative weight when choosing among eligible Match question definitions.","default":1.0},"issuance_state_extract":{"additionalProperties":true,"type":"object","title":"Issuance State Extract","description":"Extra store_state keys from the match issue context."},"answer_choices_template":{"anyOf":[{"$ref":"#/components/schemas/AnswerChoiceList-Input"},{"type":"null"}],"description":"Multiple-choice template (required when active)."},"resolution_trigger_template":{"$ref":"#/components/schemas/QuestionTriggerConditionList","description":"OR'd stream close triggers; empty = official source only."},"resolution_source":{"type":"string","title":"Resolution Source","description":"Official payload key: stream, game_summary, game_boxscore, daily_schedule.","default":"game_summary"},"override_question_points":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Override Question Points","description":"Optional absolute points or *N of match/league points."}},"additionalProperties":false,"type":"object","required":["name","question_text"],"title":"MatchQuestionDefinitionCreate","description":"Create body."},"MatchQuestionDefinitionListOut":{"properties":{"league":{"type":"string","title":"League"},"league_id":{"type":"string","format":"uuid","title":"League Id"},"definitions":{"items":{"$ref":"#/components/schemas/MatchQuestionDefinitionSummary"},"type":"array","title":"Definitions"},"question_count":{"type":"integer","title":"Question Count"}},"type":"object","required":["league","league_id","definitions","question_count"],"title":"MatchQuestionDefinitionListOut"},"MatchQuestionDefinitionOut":{"properties":{"name":{"type":"string","title":"Name","description":"Unique name within the owning league."},"is_active":{"type":"boolean","title":"Is Active","description":"Inactive definitions are not issued onto new matches.","default":true},"question_text":{"type":"string","title":"Question Text","description":"Templated player-facing question text."},"folder_path":{"type":"string","maxLength":1024,"title":"Folder Path","description":"Slash-separated admin folder path (empty = unfiled). Organization only.","default":""},"issuance_weight":{"type":"number","minimum":0.0,"title":"Issuance Weight","description":"Relative weight when choosing among eligible Match question definitions.","default":1.0},"issuance_state_extract":{"additionalProperties":true,"type":"object","title":"Issuance State Extract","description":"Extra store_state keys from the match issue context."},"answer_choices_template":{"anyOf":[{"$ref":"#/components/schemas/AnswerChoiceList-Output"},{"type":"null"}],"description":"Multiple-choice template (required when active)."},"resolution_trigger_template":{"$ref":"#/components/schemas/QuestionTriggerConditionList","description":"OR'd stream close triggers; empty = official source only."},"resolution_source":{"type":"string","title":"Resolution Source","description":"Official payload key: stream, game_summary, game_boxscore, daily_schedule.","default":"game_summary"},"override_question_points":{"anyOf":[{"type":"integer"},{"type":"string"},{"type":"null"}],"title":"Override Question Points","description":"Optional absolute points or *N of match/league points."},"id":{"type":"string","format":"uuid","title":"Id"},"league_id":{"type":"string","format":"uuid","title":"League Id"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"can_delete":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Can Delete"}},"additionalProperties":false,"type":"object","required":["name","question_text","id","league_id"],"title":"MatchQuestionDefinitionOut"},"MatchQuestionDefinitionSummary":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"is_active":{"type":"boolean","title":"Is Active"},"folder_path":{"type":"string","title":"Folder Path","default":""},"issuance_weight":{"type":"number","title":"Issuance Weight"},"resolution_source":{"type":"string","title":"Resolution Source"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"can_delete":{"type":"boolean","title":"Can Delete","default":true}},"type":"object","required":["id","name","is_active","issuance_weight","resolution_source"],"title":"MatchQuestionDefinitionSummary"},"MatchQuestionDefinitionUpdate":{"properties":{"name":{"type":"string","title":"Name","description":"Unique name within the owning league."},"is_active":{"type":"boolean","title":"Is Active","description":"Inactive definitions are not issued onto new matches.","default":true},"question_text":{"type":"string","title":"Question Text","description":"Templated player-facing question text."},"folder_path":{"type":"string","maxLength":1024,"title":"Folder Path","description":"Slash-separated admin folder path (empty = unfiled). Organization only.","default":""},"issuance_weight":{"type":"number","minimum":0.0,"title":"Issuance Weight","description":"Relative weight when choosing among eligible Match question definitions.","default":1.0},"issuance_state_extract":{"additionalProperties":true,"type":"object","title":"Issuance State Extract","description":"Extra store_state keys from the match issue context."},"answer_choices_template":{"anyOf":[{"$ref":"#/components/schemas/AnswerChoiceList-Input"},{"type":"null"}],"description":"Multiple-choice template (required when active)."},"resolution_trigger_template":{"$ref":"#/components/schemas/QuestionTriggerConditionList","description":"OR'd stream close triggers; empty = official source only."},"resolution_source":{"type":"string","title":"Resolution Source","description":"Official payload key: stream, game_summary, game_boxscore, daily_schedule.","default":"game_summary"},"override_question_points":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Override Question Points","description":"Optional absolute points or *N of match/league points."}},"additionalProperties":false,"type":"object","required":["name","question_text"],"title":"MatchQuestionDefinitionUpdate","description":"Full replace of editable fields."},"MatchQuestionIssuanceOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Match question issuance id."},"match_question_definition_id":{"type":"string","format":"uuid","title":"Match Question Definition Id","description":"Source Match question definition id."},"definition_name":{"type":"string","title":"Definition Name","description":"Definition name at issue time."},"question_text":{"type":"string","title":"Question Text","description":"Rendered player-facing question text."},"resolution_source":{"type":"string","title":"Resolution Source","description":"Snapshotted official fetcher key."},"issued_at":{"type":"string","format":"date-time","title":"Issued At","description":"When the question was materialized (UTC)."},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At","description":"When the question closed (UTC)."},"resolution_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolution Reason","description":"resolved, stale (complete/closed leftover), postponed, cancelled, or unnecessary when closed."}},"type":"object","required":["id","match_question_definition_id","definition_name","question_text","resolution_source","issued_at"],"title":"MatchQuestionIssuanceOut","description":"Issued Match question on match detail (pre-game; not an in-game issuance)."},"MatchScoreOut":{"properties":{"home":{"type":"integer","title":"Home","description":"Home team total."},"away":{"type":"integer","title":"Away","description":"Away team total."}},"type":"object","required":["home","away"],"title":"MatchScoreOut","description":"Home/away totals (runs or points — sport-neutral ints)."},"MatchStatuses":{"type":"string","enum":["scheduled","created","inprogress","complete","closed","cancelled","delayed","postponed","time-tbd","if-necessary","unnecessary"],"title":"MatchStatuses","description":"Supported match statuses."},"MatchTimelinePeriodMarkOut":{"properties":{"occurred_at":{"type":"string","format":"date-time","title":"Occurred At","description":"First time this period_label appears (UTC ISO)."},"period_label":{"type":"string","title":"Period Label","description":"Period / phase label that starts at this instant."}},"type":"object","required":["occurred_at","period_label"],"title":"MatchTimelinePeriodMarkOut","description":"Vertical period / phase change on the timeline."},"MatchTimelinePointOut":{"properties":{"occurred_at":{"type":"string","format":"date-time","title":"Occurred At","description":"Event or issuance time (UTC ISO)."},"kind":{"type":"string","title":"Kind","description":"View kind: stream_event, stream_corrective, blocked, in_game_issued, in_game_resolved, match_question_issued, match_question_resolved."},"lane_label":{"type":"string","title":"Lane Label","description":"Operator-facing category Y label for this kind."},"event_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Type","description":"Stream event type when this row is a stream marker."},"period_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period Label","description":"Period / phase stamped on the event or issuance."},"situation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Situation","description":"Human game situation stamped on the stream event or issuance. Null for Match questions, blocked attempts, and events with no matching payload shape."},"clock":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Clock","description":"Countdown / remaining clock stamped on the stream event or issuance. Null when the payload has no clock."},"is_corrective":{"type":"boolean","title":"Is Corrective","description":"True when this stream marker is a corrective."},"source_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Source Id","description":"Issuance id when this row is an issue or resolve marker."}},"type":"object","required":["occurred_at","kind","lane_label","is_corrective"],"title":"MatchTimelinePointOut","description":"One marker on the match event timeline."},"MatchUpdate":{"properties":{"override_question_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Question Max Count","description":"In-game max questions override; omit unchanged, null clears to league."},"override_question_pivotal_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Question Pivotal Max Count","description":"Max pivotal-moment override; omit unchanged, null clears to league."},"override_question_min_interval":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Question Min Interval","description":"Min interval override (seconds); omit unchanged, null clears."},"override_question_points":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Override Question Points","description":"Points override; omit unchanged, null clears to league."},"override_question_period_distribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"},{"type":"null"}],"title":"Override Question Period Distribution","description":"Period/inning distribution override; omit unchanged, null clears. {} = Issue ASAP; [] = even auto-fill. Invalid shapes return 400 (not 422)."},"override_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Override Question Definition Ids","description":"Question-definition allowlist; omit unchanged, null clears (all active league defs). [] = none; non-empty must be ids for this match's league."},"override_match_question_max_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Override Match Question Max Count","description":"Match question cap; omit unchanged, null clears to league default."},"override_match_question_definition_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Override Match Question Definition Ids","description":"Match question definition allowlist; omit unchanged, null clears to league. [] = none; non-empty must be ids for this match's league."},"override_match_question_resolution_grace_seconds":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Override Match Question Resolution Grace Seconds","description":"Match question official-resolution grace (seconds); omit unchanged, null clears to league default."},"override_match_question_earliest_issue_seconds":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Override Match Question Earliest Issue Seconds","description":"Seconds before scheduled start that Match questions may first be issued; omit unchanged, null clears to league default. 0 means no lead-time gate."},"auto_dispatch_listener":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Auto Dispatch Listener","description":"When False, dispatch_upcoming_match_listeners skips this match. Manual / force start is unaffected. Omitted leaves unchanged."},"push_notifications_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Push Notifications Enabled","description":"When False, push notification fan-out skips this match. Omitted leaves unchanged. Editable mid-match."},"status":{"anyOf":[{"$ref":"#/components/schemas/MatchStatuses"},{"type":"null"}],"description":"Test matches only: set status to scheduled, inprogress, delayed, postponed, or closed."},"sponsor_brand_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Sponsor Brand Id","description":"Whole-match sponsor brand id; omit unchanged, null clears. Same editability gate as question overrides."}},"type":"object","title":"MatchUpdate","description":"Partial update for in-game and Match question overrides, listener dispatch,\nand/or test-match status.\n\nOverride fields: omitted leave unchanged; explicit ``null`` clears.\n``status`` is allowed only for ``is_test`` matches (see ops).\n``auto_dispatch_listener`` and ``push_notifications_enabled`` may be set on\nany match (always editable)."},"OpenQuestionListOut":{"properties":{"questions":{"items":{"$ref":"#/components/schemas/OpenQuestionOut"},"type":"array","title":"Questions","description":"Unresolved open questions on live or recently scheduled matches (not a UTC calendar day)."},"question_count":{"type":"integer","title":"Question Count","description":"Number of questions in ``questions``."}},"type":"object","required":["questions","question_count"],"title":"OpenQuestionListOut"},"OpenQuestionOut":{"properties":{"question_issuance_id":{"type":"string","format":"uuid","title":"Question Issuance Id","description":"Issuance id; pass to ``PUT /api/question-answers``."},"question_definition_id":{"type":"string","format":"uuid","title":"Question Definition Id","description":"Definition that produced this issuance."},"match_id":{"type":"string","format":"uuid","title":"Match Id","description":"Internal match id (``Match.id``)."},"match_label":{"type":"string","title":"Match Label","description":"Short away@home-style label for the match."},"match_shortcode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Match Shortcode","description":"Listener shortcode ``{sr_id[:8]}-{match_id[:8]}`` when ``sr_id`` is set."},"question_text":{"type":"string","title":"Question Text","description":"Rendered question text for the player."},"choices":{"items":{"$ref":"#/components/schemas/PublicAnswerChoice"},"type":"array","title":"Choices","description":"Selectable answers (no correctness until resolution)."},"issued_at":{"type":"string","format":"date-time","title":"Issued At","description":"When the issuance was created (UTC)."},"kind":{"type":"string","enum":["in_game","match"],"title":"Kind","description":"``in_game``: listener question with a timed answer window. ``match``: Match question locked at match start (no countdown).","default":"in_game"},"answer_locked":{"type":"boolean","title":"Answer Locked","description":"Match question only: true after first pitch / inprogress+. In-game questions stay false (window uses ``expires_at``).","default":false},"locks_at_match_start":{"type":"boolean","title":"Locks At Match Start","description":"True for Match questions (answers commit when the match starts).","default":false},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"Answer window end for in-game questions. Null for Match question (delayed games stay answerable until lock)."},"seconds_remaining":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Seconds Remaining","description":"Seconds left in the in-game answer window. Null for Match question."},"answer_window_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Answer Window Seconds","description":"Configured in-game answer window length. Null for Match question."},"current_answer":{"anyOf":[{"$ref":"#/components/schemas/CurrentAnswerOut"},{"type":"null"}],"description":"This user's answer if they already answered; else null."},"sponsor_brand":{"anyOf":[{"$ref":"#/components/schemas/BrandSummaryOut"},{"type":"null"}],"description":"Brand stamped on the issuance from a claimed sponsorship slot."},"match_sponsor_brand":{"anyOf":[{"$ref":"#/components/schemas/BrandSummaryOut"},{"type":"null"}],"description":"Whole-match sponsor brand (``Match.sponsor_brand``), if set."},"is_pivotal_moment":{"type":"boolean","title":"Is Pivotal Moment","description":"True when the definition was labeled a special high-stakes moment at issue time (from definition snapshot).","default":false},"issued_situation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issued Situation","description":"Human game situation from the issuing event (e.g. batter and bases, strength, down-and-distance). Null for Match questions and when the payload has no matching shape."},"issued_clock":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issued Clock","description":"Countdown / remaining clock from the issuing event. Null for Match questions and when the payload has no clock."},"issued_in_period":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issued In Period","description":"Period or phase label from the issuing event. Null for Match questions and when the payload has no period."},"issued_score":{"anyOf":[{"$ref":"#/components/schemas/MatchScoreOut"},{"type":"null"}],"description":"Home/away totals on the issuing event. Null for Match questions and when the payload has no both-side score. Frozen stamp — not a live ticker."}},"type":"object","required":["question_issuance_id","question_definition_id","match_id","match_label","question_text","choices","issued_at"],"title":"OpenQuestionOut","description":"An unresolved, unexpired issuance available for play."},"PathEntry":{"properties":{"path":{"type":"string","title":"Path","description":"JSONPath-like path within the sample event."},"value_type":{"type":"string","title":"Value Type","description":"Compact type label: string, integer, boolean, array, object, …"},"example":{"title":"Example","description":"Truncated representative value at this path."}},"type":"object","required":["path","value_type"],"title":"PathEntry","description":"One JSONPath-like path with a representative type and example value."},"PreviewRequest":{"properties":{"question_text":{"type":"string","title":"Question Text","description":"Template to render as the question.","default":""},"sample_event":{"additionalProperties":true,"type":"object","title":"Sample Event","description":"Sample Sportradar-shaped event used for placeholder context."},"store_state":{"additionalProperties":true,"type":"object","title":"Store State","description":"Optional pre-seeded store_state merged before extract."},"issuance_state_extract":{"additionalProperties":true,"type":"object","title":"Issuance State Extract","description":"Extract map applied to ``sample_event`` into store_state."}},"additionalProperties":false,"type":"object","title":"PreviewRequest","description":"Preview templated copy against a sample event and optional store_state.","examples":[{"issuance_state_extract":{},"question_text":"Will {{ batter }} get a hit?","sample_event":{"payload":{"event":{"type":"pitch"}}},"store_state":{}}]},"PreviewResponse":{"properties":{"question_text":{"type":"string","title":"Question Text","description":"Rendered question text."},"store_state":{"additionalProperties":true,"type":"object","title":"Store State","description":"store_state after extract / merge used for rendering."}},"type":"object","required":["question_text","store_state"],"title":"PreviewResponse","description":"Rendered copy fields plus the store_state used for placeholders."},"PublicAnswerChoice":{"properties":{"identifier":{"type":"string","title":"Identifier","description":"Stable choice id submitted as ``selected_answer_identifier``."},"text":{"type":"string","title":"Text","description":"Player-facing choice label."},"points":{"type":"integer","minimum":0.0,"title":"Points","description":"Whole points awarded if this choice is correct for this issuance (definition→match→league effective points, plus optional per-choice override; multipliers floor). Shown before the player answers."},"outcome_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Outcome Text","description":"On-field copy if this choice wins. Null when the definition did not author outcome copy. Not a correctness leak."}},"type":"object","required":["identifier","text","points"],"title":"PublicAnswerChoice","description":"Answer choice safe to show before resolution (no correctness fields)."},"PushDeliveryAttemptListOut":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id"},"email":{"type":"string","title":"Email"},"username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username"},"devices":{"items":{"$ref":"#/components/schemas/PushDeviceHealthOut"},"type":"array","title":"Devices"},"device_count":{"type":"integer","title":"Device Count"},"attempts":{"items":{"$ref":"#/components/schemas/PushDeliveryAttemptOut"},"type":"array","title":"Attempts"},"attempt_count":{"type":"integer","title":"Attempt Count"}},"type":"object","required":["user_id","email","devices","device_count","attempts","attempt_count"],"title":"PushDeliveryAttemptListOut","description":"Admin per-user delivery lookup response."},"PushDeliveryAttemptOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"},"push_device_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Push Device Id"},"client_device_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Device Id"},"match_id":{"type":"string","format":"uuid","title":"Match Id"},"question_issuance_id":{"type":"string","format":"uuid","title":"Question Issuance Id"},"event":{"type":"string","title":"Event"},"outcome":{"type":"string","title":"Outcome"},"skip_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Skip Reason"},"provider_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider Error"},"ticket_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ticket Id"},"is_pivotal_moment":{"type":"boolean","title":"Is Pivotal Moment","default":false},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"match_shortcode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Match Shortcode"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"body":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Body"}},"type":"object","required":["id","match_id","question_issuance_id","event","outcome"],"title":"PushDeliveryAttemptOut","description":"One delivery attempt row for admin lookup."},"PushDeviceCreate":{"properties":{"device_id":{"type":"string","maxLength":128,"minLength":1,"title":"Device Id","description":"Client-generated opaque install id (UUID v4). Upsert key; not auth."},"token":{"type":"string","maxLength":512,"minLength":1,"title":"Token","description":"Push token from Expo (or future APNs/FCM)"},"token_type":{"type":"string","enum":["expo","apns","fcm"],"title":"Token Type","description":"Token kind: expo | apns | fcm"},"platform":{"type":"string","enum":["ios","android"],"title":"Platform","description":"ios | android"},"environment":{"anyOf":[{"type":"string","enum":["development","production"]},{"type":"null"}],"title":"Environment","description":"APNs routing when token_type is apns"},"app_version":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"App Version"},"build_number":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Build Number"},"os_version":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Os Version"},"device_model":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Device Model"},"locale":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Locale"},"timezone":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Timezone"}},"type":"object","required":["device_id","token","token_type","platform"],"title":"PushDeviceCreate","description":"Register or refresh a push device for the authenticated user.","examples":[{"app_version":"1.0.1","build_number":"12","device_id":"b1e7c8f2-4a90-4d31-9f52-0c3a7e6d1b84","device_model":"iPhone16,2","environment":"production","locale":"en-CA","os_version":"18.5","platform":"ios","timezone":"America/Toronto","token":"ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]","token_type":"expo"}]},"PushDeviceHealthOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"device_id":{"type":"string","title":"Device Id"},"platform":{"type":"string","title":"Platform"},"token_type":{"type":"string","title":"Token Type"},"disabled_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Disabled At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"last_success_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Success At"}},"type":"object","required":["id","device_id","platform","token_type"],"title":"PushDeviceHealthOut","description":"Compact device row for admin triage."},"PushDeviceOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"device_id":{"type":"string","title":"Device Id"},"token":{"type":"string","title":"Token"},"token_type":{"type":"string","title":"Token Type"},"platform":{"type":"string","title":"Platform"},"environment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Environment"},"app_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"App Version"},"build_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Build Number"},"os_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Os Version"},"device_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device Model"},"locale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Locale"},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone"},"last_success_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Success At"},"disabled_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Disabled At"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","user_id","device_id","token","token_type","platform"],"title":"PushDeviceOut","description":"Stored push device row for API responses."},"PushNotificationSettings":{"properties":{"notify_on_issuance":{"type":"boolean","title":"Notify On Issuance","description":"Master switch for question-issuance pushes","default":true},"notify_on_resolve":{"type":"boolean","title":"Notify On Resolve","description":"Enable question-resolved pushes","default":false},"pivotal_only":{"type":"boolean","title":"Pivotal Only","description":"When true, issuance pushes only for pivotal moments","default":true},"min_seconds_between_device":{"type":"integer","maximum":3600.0,"minimum":0.0,"title":"Min Seconds Between Device","description":"Per-device cooldown seconds after a successful send","default":45},"max_issuances_per_user_per_match":{"type":"integer","maximum":1000.0,"minimum":0.0,"title":"Max Issuances Per User Per Match","description":"Max issuance pushes per user per match (0 = unlimited)","default":20},"max_resolves_per_user_per_match":{"type":"integer","maximum":1000.0,"minimum":0.0,"title":"Max Resolves Per User Per Match","description":"Max resolve pushes per user per match (0 = unlimited)","default":20},"attempt_retention_days":{"type":"integer","maximum":90.0,"minimum":1.0,"title":"Attempt Retention Days","description":"Days to retain push_delivery_attempts rows","default":7},"title_template":{"type":"string","maxLength":200,"minLength":1,"title":"Title Template","description":"Notification title template","default":"{{match_label}}"},"body_issuance_pivotal":{"type":"string","maxLength":400,"minLength":1,"title":"Body Issuance Pivotal","description":"Body for pivotal issuance pushes","default":"It's time to guess What Happens Next!"},"body_issuance_default":{"type":"string","maxLength":400,"minLength":1,"title":"Body Issuance Default","description":"Body for non-pivotal issuance pushes","default":"New question — answer now!"}},"type":"object","title":"PushNotificationSettings","description":"Operator-tunable push gates and message templates (StoredSetting JSON)."},"PushNotificationSettingsUpdate":{"properties":{"notify_on_issuance":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify On Issuance"},"notify_on_resolve":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify On Resolve"},"pivotal_only":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Pivotal Only"},"min_seconds_between_device":{"anyOf":[{"type":"integer","maximum":3600.0,"minimum":0.0},{"type":"null"}],"title":"Min Seconds Between Device"},"max_issuances_per_user_per_match":{"anyOf":[{"type":"integer","maximum":1000.0,"minimum":0.0},{"type":"null"}],"title":"Max Issuances Per User Per Match"},"max_resolves_per_user_per_match":{"anyOf":[{"type":"integer","maximum":1000.0,"minimum":0.0},{"type":"null"}],"title":"Max Resolves Per User Per Match"},"attempt_retention_days":{"anyOf":[{"type":"integer","maximum":90.0,"minimum":1.0},{"type":"null"}],"title":"Attempt Retention Days"},"title_template":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Title Template"},"body_issuance_pivotal":{"anyOf":[{"type":"string","maxLength":400,"minLength":1},{"type":"null"}],"title":"Body Issuance Pivotal"},"body_issuance_default":{"anyOf":[{"type":"string","maxLength":400,"minLength":1},{"type":"null"}],"title":"Body Issuance Default"}},"type":"object","title":"PushNotificationSettingsUpdate","description":"Partial update for push settings (all fields optional)."},"QuestionAnswerListItemOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Answer row id."},"question_issuance_id":{"type":"string","format":"uuid","title":"Question Issuance Id","description":"Issuance this answer belongs to."},"question_definition_id":{"type":"string","format":"uuid","title":"Question Definition Id","description":"Source question definition id."},"user_id":{"type":"string","format":"uuid","title":"User Id","description":"Internal user id."},"user_display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Display Name","description":"User display name when available."},"match_id":{"type":"string","format":"uuid","title":"Match Id","description":"Internal match id (``Match.id``)."},"match_label":{"type":"string","title":"Match Label","description":"Short away@home-style label."},"match_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Match Title","description":"Full market + team name (``Match.display_title``)."},"match_shortcode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Match Shortcode","description":"Listener shortcode ``{sr_id[:8]}-{match_id[:8]}`` when ``sr_id`` is set."},"match_scheduled":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Match Scheduled","description":"Match.scheduled as stored (UTC ISO-like string)."},"question_text":{"type":"string","title":"Question Text","description":"Question text at answer time."},"selected_answer_identifier":{"type":"string","title":"Selected Answer Identifier","description":"Selected choice identifier."},"selected_answer_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Selected Answer Text","description":"Resolved choice text when available."},"answered_at":{"type":"string","format":"date-time","title":"Answered At","description":"When the answer was last written (UTC)."},"is_correct":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Correct","description":"Null until scored. For ``resolved`` closes: true/false. For ``stale`` / ``retracted``: remains null (not a miss)."},"points_awarded":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Points Awarded","description":"Whole points after scoring. ``retracted`` → 0; ``stale`` / ``postponed`` / ``cancelled`` / ``unnecessary`` → selected-choice points; ``resolved`` → choice points when correct else 0."},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At","description":"When this answer was scored (UTC)."},"issuance_resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Issuance Resolved At","description":"When the issuance resolved (UTC)."},"issuance_resolution_reason":{"anyOf":[{"type":"string","enum":["resolved","stale","postponed","cancelled","unnecessary","retracted"]},{"type":"null"}],"title":"Issuance Resolution Reason","description":"Parent issuance close reason. When ``retracted``, label the row Retracted (0 points); do not show correct/incorrect. ``stale`` / ``postponed`` / ``cancelled`` / ``unnecessary`` are participation credit."},"resolved":{"type":"boolean","title":"Resolved","description":"True when the issuance has been resolved.","default":false},"correct_answer_identifiers":{"items":{"type":"string"},"type":"array","title":"Correct Answer Identifiers","description":"Correct choice ids after resolution (empty while open)."},"resolve_copy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolve Copy","description":"Stamped right/wrong phrase after a feed resolve. Null until scored True/False."},"outcome_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Outcome Text","description":"Winning choice’s on-field copy after resolve. Null while open, when no winner, or when that choice has no outcome_text."},"issuance_event_fields":{"additionalProperties":true,"type":"object","title":"Issuance Event Fields","description":"Snapshot of event fields captured at issuance."},"resolution_event_fields":{"additionalProperties":true,"type":"object","title":"Resolution Event Fields","description":"Snapshot of event fields captured at resolution."},"condition_evaluations":{"items":{"$ref":"#/components/schemas/ConditionEvaluationView"},"type":"array","title":"Condition Evaluations","description":"Per-condition evaluation detail for audit UIs."},"sponsor_brand":{"anyOf":[{"$ref":"#/components/schemas/BrandSummaryOut"},{"type":"null"}],"description":"Brand stamped on the related issuance, if any."},"match_sponsor_brand":{"anyOf":[{"$ref":"#/components/schemas/BrandSummaryOut"},{"type":"null"}],"description":"Whole-match sponsor brand (``Match.sponsor_brand``), if set."},"kind":{"type":"string","enum":["in_game","match"],"title":"Kind","description":"``in_game`` or ``match`` (Match question).","default":"in_game"},"issued_situation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issued Situation","description":"Human game situation from the issuing event. Null for Match questions and when the payload has no matching shape."},"issued_clock":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issued Clock","description":"Countdown / remaining clock from the issuing event. Null when the payload has no clock."},"issued_in_period":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issued In Period","description":"Period or phase label from the issuing event. Null for Match questions."},"issued_score":{"anyOf":[{"$ref":"#/components/schemas/MatchScoreOut"},{"type":"null"}],"description":"Home/away totals on the issuing event. Null for Match questions and when the payload has no both-side score. Frozen stamp — not a live ticker."},"answer_locked":{"type":"boolean","title":"Answer Locked","description":"Match question only: true after first pitch / inprogress+ (answers can no longer change). In-game answers stay false. Play pins locked-and-still-pending Match answers above the regular recent-history limit.","default":false}},"type":"object","required":["id","question_issuance_id","question_definition_id","user_id","match_id","match_label","question_text","selected_answer_identifier","answered_at"],"title":"QuestionAnswerListItemOut","description":"Answer row with match/question context for history/audit."},"QuestionAnswerListOut":{"properties":{"answers":{"items":{"$ref":"#/components/schemas/QuestionAnswerListItemOut"},"type":"array","title":"Answers","description":"Answer rows (newest first when ``limit`` is used). Locked pending Match answers are listed first and do not consume ``limit``."},"answer_count":{"type":"integer","title":"Answer Count","description":"Number of answers in ``answers``."}},"type":"object","required":["answers","answer_count"],"title":"QuestionAnswerListOut"},"QuestionAnswerOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Answer row id."},"question_issuance_id":{"type":"string","format":"uuid","title":"Question Issuance Id","description":"Issuance this answer belongs to."},"user_id":{"type":"string","format":"uuid","title":"User Id","description":"Internal user id."},"selected_answer_identifier":{"type":"string","title":"Selected Answer Identifier","description":"Choice identifier selected by the user."},"answered_at":{"type":"string","format":"date-time","title":"Answered At","description":"When the answer was last written (UTC)."},"is_correct":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Correct","description":"Null until scored. For ``resolved`` closes: true/false. For ``stale`` / ``retracted``: remains null (not a miss)."},"points_awarded":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Points Awarded","description":"Whole points after scoring. ``retracted`` → 0; ``stale`` / ``postponed`` / ``cancelled`` / ``unnecessary`` may credit choice points; ``resolved`` awards when correct."},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At","description":"When this answer was scored (UTC)."},"resolve_copy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolve Copy","description":"Stamped right/wrong phrase after a feed resolve. Null until scored True/False."},"issuance_resolution_reason":{"anyOf":[{"type":"string","enum":["resolved","stale","postponed","cancelled","unnecessary","retracted"]},{"type":"null"}],"title":"Issuance Resolution Reason","description":"Parent issuance close reason when known. ``retracted`` → show withdrawn/Retracted UI, 0 points. ``stale`` / ``postponed`` / ``cancelled`` / ``unnecessary`` → participation credit."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Row created_at (UTC)."},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Row updated_at (UTC)."},"sponsor_brand":{"anyOf":[{"$ref":"#/components/schemas/BrandSummaryOut"},{"type":"null"}],"description":"Brand stamped on the related issuance, if any."}},"type":"object","required":["id","question_issuance_id","user_id","selected_answer_identifier","answered_at"],"title":"QuestionAnswerOut"},"QuestionAnswerUpsert":{"properties":{"question_issuance_id":{"type":"string","format":"uuid","title":"Question Issuance Id","description":"Open issuance id from ``GET /api/question-answers/open``."},"selected_answer_identifier":{"type":"string","minLength":1,"title":"Selected Answer Identifier","description":"Must match one of the issuance ``choices[].identifier`` values."}},"type":"object","required":["question_issuance_id","selected_answer_identifier"],"title":"QuestionAnswerUpsert","examples":[{"question_issuance_id":"00000000-0000-0000-0000-000000000002","selected_answer_identifier":"yes"}]},"QuestionDefinitionClone":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"New name; defaults to '<original> (copy)'."}},"additionalProperties":false,"type":"object","title":"QuestionDefinitionClone","description":"Optional override when cloning; omit ``name`` to use ``'<original> (copy)'``."},"QuestionDefinitionCreate":{"properties":{"name":{"type":"string","title":"Name","description":"Unique name within the owning league."},"is_active":{"type":"boolean","title":"Is Active","description":"When true, included in league defaults for matches that inherit the league allowlist. Does not archive the row.","default":false},"question_text":{"type":"string","title":"Question Text","description":"Templated player-facing question text."},"folder_path":{"type":"string","maxLength":1024,"title":"Folder Path","description":"Slash-separated admin folder path (empty = unfiled). Organization only; not the issuance group.","default":""},"question_group_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Question Group Id","description":"Owning QuestionGroup id (preferred). When omitted, issuance_group must match an existing same-league group slug."},"issuance_group":{"type":"string","maxLength":64,"title":"Issuance Group","description":"Concurrency lane slug synced from the QuestionGroup. Write alias that must resolve to an existing same-league group.","default":"default"},"issuance_min_interval":{"type":"integer","minimum":0.0,"title":"Issuance Min Interval","description":"Seconds after this question resolves before another in the same group may issue. Combined via max() with the match floor and the live group interval. 0 uses those floors only.","default":300},"issuance_weight":{"type":"number","minimum":0.0,"title":"Issuance Weight","description":"Relative weight when choosing among eligible definitions.","default":1.0},"issuance_dynamic_weighting":{"type":"boolean","title":"Issuance Dynamic Weighting","description":"When true, effective selection weight decays per successful issuance in the listener session (weight * decay ** times_issued).","default":true},"issuance_weight_decay":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Issuance Weight Decay","description":"Per-issuance multiplier (0-1) when dynamic weighting is on. Ignored when issuance_dynamic_weighting is false.","default":0.5},"issuance_probability":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Issuance Probability","description":"Percent chance (0–100) to issue after this definition is selected. 100 always issues; 0 never issues unless max_false_streak forces.","default":100},"issuance_probability_max_false_streak":{"type":"integer","minimum":0.0,"title":"Issuance Probability Max False Streak","description":"Consecutive false probability rolls before forcing a true. 0 disables the pity timer.","default":0},"issuance_trigger_condition_list":{"$ref":"#/components/schemas/QuestionTriggerConditionList","description":"Conditions that must pass to issue this question."},"issuance_state_extract":{"additionalProperties":true,"type":"object","title":"Issuance State Extract","description":"Paths to extract into store_state at issuance time."},"issuance_subject_extract":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issuance Subject Extract","description":"JSONPath for the player/subject id this in-game question is about. Evaluated after store_state. Null = no subject (team/situation). At most one non-pivotal issue per subject per period, match-wide (not scoped to the question group)."},"answer_choices_template":{"anyOf":[{"$ref":"#/components/schemas/AnswerChoiceList-Input"},{"type":"null"}],"description":"Templated answer choices; null uses definition defaults."},"resolution_trigger_template":{"$ref":"#/components/schemas/QuestionTriggerConditionList","description":"Conditions evaluated to resolve an open issuance."},"override_question_points":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Override Question Points","description":"Whole-points override for this definition (absolute integer or *N multiplier, floored); null uses league/match."},"resolution_correction_window_seconds":{"type":"integer","minimum":0.0,"title":"Resolution Correction Window Seconds","description":"Seconds after provisional resolution during which corrective events may revise the outcome.","default":0},"resolution_start_on_corrective":{"type":"boolean","title":"Resolution Start On Corrective","description":"When true (default), a same-eid corrective that newly matches resolution conditions may start defer/resolve; when false, correctives only update an already-pending candidate.","default":true},"issuance_correction_window_seconds":{"type":"integer","minimum":0.0,"title":"Issuance Correction Window Seconds","description":"Seconds to wait for a same-eid corrective before creating an issuance. 0 issues immediately when selected.","default":0},"issuance_start_on_corrective":{"type":"boolean","title":"Issuance Start On Corrective","description":"When true, a same-eid corrective that newly matches issuance triggers may start a deferred or immediate issue; when false (default), correctives only refine an already-pending issue candidate.","default":false},"issuance_retract_on_corrective":{"type":"boolean","title":"Issuance Retract On Corrective","description":"When true, a same-eid corrective that no longer matches issuance triggers closes an open issuance from that event as retracted (0 points; excluded from period/max caps). Default false.","default":false},"issuance_period_distribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"}],"title":"Issuance Period Distribution","description":"Per-definition period/half caps (ints only). {} = no definition period caps; [] / {dist: even} = 1 per registered league key. unlisted: block treats omitted keys as 0. Pivotal skip of the match-wide period map does not skip this map."},"issuance_max_count":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Issuance Max Count","description":"Max published issuances of this definition per match. Null = unlimited; 0 = never. Retracted rows do not count. Independent of match question_max_count."},"is_pivotal_moment":{"type":"boolean","title":"Is Pivotal Moment","description":"High-stakes moment. Skips and does not consume match question_max_count and the match normal period cap; wins selection over non-pivotal on the same event. Still consumes and is blocked by match max pivotal and the period pivotal half; still AND with group/definition maps and issuance_max_count. Skips subject uniqueness and does not occupy the subject slot. Admin and play UIs decorate these questions.","default":false}},"additionalProperties":false,"type":"object","required":["name","question_text"],"title":"QuestionDefinitionCreate","description":"Create payload; owning league is selected via the ``league`` query param."},"QuestionDefinitionListOut":{"properties":{"league":{"type":"string","title":"League","description":"League slug that was queried."},"league_id":{"type":"string","format":"uuid","title":"League Id","description":"Resolved internal league id."},"definitions":{"items":{"$ref":"#/components/schemas/QuestionDefinitionSummary"},"type":"array","title":"Definitions","description":"Definitions for this league."},"question_count":{"type":"integer","title":"Question Count","description":"Number of definitions in ``definitions``."}},"type":"object","required":["league","league_id","definitions","question_count"],"title":"QuestionDefinitionListOut","description":"League-scoped list response."},"QuestionDefinitionOut":{"properties":{"name":{"type":"string","title":"Name","description":"Unique name within the owning league."},"is_active":{"type":"boolean","title":"Is Active","description":"When true, included in league defaults for matches that inherit the league allowlist. Does not archive the row.","default":false},"question_text":{"type":"string","title":"Question Text","description":"Templated player-facing question text."},"folder_path":{"type":"string","maxLength":1024,"title":"Folder Path","description":"Slash-separated admin folder path (empty = unfiled). Organization only; not the issuance group.","default":""},"question_group_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Question Group Id","description":"Owning QuestionGroup id (preferred). When omitted, issuance_group must match an existing same-league group slug."},"issuance_group":{"type":"string","maxLength":64,"title":"Issuance Group","description":"Concurrency lane slug synced from the QuestionGroup. Write alias that must resolve to an existing same-league group.","default":"default"},"issuance_min_interval":{"type":"integer","minimum":0.0,"title":"Issuance Min Interval","description":"Seconds after this question resolves before another in the same group may issue. Combined via max() with the match floor and the live group interval. 0 uses those floors only.","default":300},"issuance_weight":{"type":"number","minimum":0.0,"title":"Issuance Weight","description":"Relative weight when choosing among eligible definitions.","default":1.0},"issuance_dynamic_weighting":{"type":"boolean","title":"Issuance Dynamic Weighting","description":"When true, effective selection weight decays per successful issuance in the listener session (weight * decay ** times_issued).","default":true},"issuance_weight_decay":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Issuance Weight Decay","description":"Per-issuance multiplier (0-1) when dynamic weighting is on. Ignored when issuance_dynamic_weighting is false.","default":0.5},"issuance_probability":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Issuance Probability","description":"Percent chance (0–100) to issue after this definition is selected. 100 always issues; 0 never issues unless max_false_streak forces.","default":100},"issuance_probability_max_false_streak":{"type":"integer","minimum":0.0,"title":"Issuance Probability Max False Streak","description":"Consecutive false probability rolls before forcing a true. 0 disables the pity timer.","default":0},"issuance_trigger_condition_list":{"$ref":"#/components/schemas/QuestionTriggerConditionList","description":"Conditions that must pass to issue this question."},"issuance_state_extract":{"additionalProperties":true,"type":"object","title":"Issuance State Extract","description":"Paths to extract into store_state at issuance time."},"issuance_subject_extract":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issuance Subject Extract","description":"JSONPath for the player/subject id this in-game question is about. Evaluated after store_state. Null = no subject (team/situation). At most one non-pivotal issue per subject per period, match-wide (not scoped to the question group)."},"answer_choices_template":{"anyOf":[{"$ref":"#/components/schemas/AnswerChoiceList-Output"},{"type":"null"}],"description":"Templated answer choices; null uses definition defaults."},"resolution_trigger_template":{"$ref":"#/components/schemas/QuestionTriggerConditionList","description":"Conditions evaluated to resolve an open issuance."},"override_question_points":{"anyOf":[{"type":"integer"},{"type":"string"},{"type":"null"}],"title":"Override Question Points","description":"Whole-points override for this definition (absolute integer or *N multiplier, floored); null uses league/match."},"resolution_correction_window_seconds":{"type":"integer","minimum":0.0,"title":"Resolution Correction Window Seconds","description":"Seconds after provisional resolution during which corrective events may revise the outcome.","default":0},"resolution_start_on_corrective":{"type":"boolean","title":"Resolution Start On Corrective","description":"When true (default), a same-eid corrective that newly matches resolution conditions may start defer/resolve; when false, correctives only update an already-pending candidate.","default":true},"issuance_correction_window_seconds":{"type":"integer","minimum":0.0,"title":"Issuance Correction Window Seconds","description":"Seconds to wait for a same-eid corrective before creating an issuance. 0 issues immediately when selected.","default":0},"issuance_start_on_corrective":{"type":"boolean","title":"Issuance Start On Corrective","description":"When true, a same-eid corrective that newly matches issuance triggers may start a deferred or immediate issue; when false (default), correctives only refine an already-pending issue candidate.","default":false},"issuance_retract_on_corrective":{"type":"boolean","title":"Issuance Retract On Corrective","description":"When true, a same-eid corrective that no longer matches issuance triggers closes an open issuance from that event as retracted (0 points; excluded from period/max caps). Default false.","default":false},"issuance_period_distribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"}],"title":"Issuance Period Distribution","description":"Per-definition period/half caps (ints only). {} = no definition period caps; [] / {dist: even} = 1 per registered league key. unlisted: block treats omitted keys as 0. Pivotal skip of the match-wide period map does not skip this map."},"issuance_max_count":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Issuance Max Count","description":"Max published issuances of this definition per match. Null = unlimited; 0 = never. Retracted rows do not count. Independent of match question_max_count."},"is_pivotal_moment":{"type":"boolean","title":"Is Pivotal Moment","description":"High-stakes moment. Skips and does not consume match question_max_count and the match normal period cap; wins selection over non-pivotal on the same event. Still consumes and is blocked by match max pivotal and the period pivotal half; still AND with group/definition maps and issuance_max_count. Skips subject uniqueness and does not occupy the subject slot. Admin and play UIs decorate these questions.","default":false},"id":{"type":"string","format":"uuid","title":"Id","description":"Internal definition id."},"league_id":{"type":"string","format":"uuid","title":"League Id","description":"Owning internal league id."},"is_archived":{"type":"boolean","title":"Is Archived","description":"Hidden from the default admin tree; never issued."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Row created_at (UTC)."},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Row updated_at (UTC)."},"can_delete":{"type":"boolean","title":"Can Delete","description":"True when no issuances or sponsorship slots reference this definition (hard-delete is allowed).","default":false}},"type":"object","required":["name","question_text","id","league_id","is_archived"],"title":"QuestionDefinitionOut","description":"Full persisted row for the API and editor (writable fields + server keys)."},"QuestionDefinitionSummary":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Internal definition id."},"name":{"type":"string","title":"Name","description":"Definition name."},"is_active":{"type":"boolean","title":"Is Active","description":"Included in league defaults (matches that inherit)."},"is_archived":{"type":"boolean","title":"Is Archived","description":"Hidden from the default admin tree; never issued."},"is_pivotal_moment":{"type":"boolean","title":"Is Pivotal Moment","description":"Whether this definition is labeled a pivotal / high-stakes moment.","default":false},"question_group_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Question Group Id","description":"Owning QuestionGroup id."},"issuance_group":{"type":"string","title":"Issuance Group","description":"Concurrency lane slug."},"folder_path":{"type":"string","title":"Folder Path","description":"Slash-separated admin folder path (empty = unfiled).","default":""},"issuance_weight":{"type":"number","title":"Issuance Weight","description":"Selection weight."},"issuance_probability":{"type":"integer","title":"Issuance Probability","description":"Post-selection issue percent (0–100)."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Row created_at (UTC)."},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Row updated_at (UTC)."},"can_delete":{"type":"boolean","title":"Can Delete","description":"True when no issuances or sponsorship slots reference this definition (hard-delete is allowed).","default":false}},"type":"object","required":["id","name","is_active","is_archived","issuance_group","issuance_weight","issuance_probability"],"title":"QuestionDefinitionSummary","description":"Sidebar / list row for a definition."},"QuestionDefinitionUpdate":{"properties":{"name":{"type":"string","title":"Name","description":"Unique name within the owning league."},"is_active":{"type":"boolean","title":"Is Active","description":"When true, included in league defaults for matches that inherit the league allowlist. Does not archive the row.","default":false},"question_text":{"type":"string","title":"Question Text","description":"Templated player-facing question text."},"folder_path":{"type":"string","maxLength":1024,"title":"Folder Path","description":"Slash-separated admin folder path (empty = unfiled). Organization only; not the issuance group.","default":""},"question_group_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Question Group Id","description":"Owning QuestionGroup id (preferred). When omitted, issuance_group must match an existing same-league group slug."},"issuance_group":{"type":"string","maxLength":64,"title":"Issuance Group","description":"Concurrency lane slug synced from the QuestionGroup. Write alias that must resolve to an existing same-league group.","default":"default"},"issuance_min_interval":{"type":"integer","minimum":0.0,"title":"Issuance Min Interval","description":"Seconds after this question resolves before another in the same group may issue. Combined via max() with the match floor and the live group interval. 0 uses those floors only.","default":300},"issuance_weight":{"type":"number","minimum":0.0,"title":"Issuance Weight","description":"Relative weight when choosing among eligible definitions.","default":1.0},"issuance_dynamic_weighting":{"type":"boolean","title":"Issuance Dynamic Weighting","description":"When true, effective selection weight decays per successful issuance in the listener session (weight * decay ** times_issued).","default":true},"issuance_weight_decay":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Issuance Weight Decay","description":"Per-issuance multiplier (0-1) when dynamic weighting is on. Ignored when issuance_dynamic_weighting is false.","default":0.5},"issuance_probability":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Issuance Probability","description":"Percent chance (0–100) to issue after this definition is selected. 100 always issues; 0 never issues unless max_false_streak forces.","default":100},"issuance_probability_max_false_streak":{"type":"integer","minimum":0.0,"title":"Issuance Probability Max False Streak","description":"Consecutive false probability rolls before forcing a true. 0 disables the pity timer.","default":0},"issuance_trigger_condition_list":{"$ref":"#/components/schemas/QuestionTriggerConditionList","description":"Conditions that must pass to issue this question."},"issuance_state_extract":{"additionalProperties":true,"type":"object","title":"Issuance State Extract","description":"Paths to extract into store_state at issuance time."},"issuance_subject_extract":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issuance Subject Extract","description":"JSONPath for the player/subject id this in-game question is about. Evaluated after store_state. Null = no subject (team/situation). At most one non-pivotal issue per subject per period, match-wide (not scoped to the question group)."},"answer_choices_template":{"anyOf":[{"$ref":"#/components/schemas/AnswerChoiceList-Input"},{"type":"null"}],"description":"Templated answer choices; null uses definition defaults."},"resolution_trigger_template":{"$ref":"#/components/schemas/QuestionTriggerConditionList","description":"Conditions evaluated to resolve an open issuance."},"override_question_points":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Override Question Points","description":"Whole-points override for this definition (absolute integer or *N multiplier, floored); null uses league/match."},"resolution_correction_window_seconds":{"type":"integer","minimum":0.0,"title":"Resolution Correction Window Seconds","description":"Seconds after provisional resolution during which corrective events may revise the outcome.","default":0},"resolution_start_on_corrective":{"type":"boolean","title":"Resolution Start On Corrective","description":"When true (default), a same-eid corrective that newly matches resolution conditions may start defer/resolve; when false, correctives only update an already-pending candidate.","default":true},"issuance_correction_window_seconds":{"type":"integer","minimum":0.0,"title":"Issuance Correction Window Seconds","description":"Seconds to wait for a same-eid corrective before creating an issuance. 0 issues immediately when selected.","default":0},"issuance_start_on_corrective":{"type":"boolean","title":"Issuance Start On Corrective","description":"When true, a same-eid corrective that newly matches issuance triggers may start a deferred or immediate issue; when false (default), correctives only refine an already-pending issue candidate.","default":false},"issuance_retract_on_corrective":{"type":"boolean","title":"Issuance Retract On Corrective","description":"When true, a same-eid corrective that no longer matches issuance triggers closes an open issuance from that event as retracted (0 points; excluded from period/max caps). Default false.","default":false},"issuance_period_distribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"}],"title":"Issuance Period Distribution","description":"Per-definition period/half caps (ints only). {} = no definition period caps; [] / {dist: even} = 1 per registered league key. unlisted: block treats omitted keys as 0. Pivotal skip of the match-wide period map does not skip this map."},"issuance_max_count":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Issuance Max Count","description":"Max published issuances of this definition per match. Null = unlimited; 0 = never. Retracted rows do not count. Independent of match question_max_count."},"is_pivotal_moment":{"type":"boolean","title":"Is Pivotal Moment","description":"High-stakes moment. Skips and does not consume match question_max_count and the match normal period cap; wins selection over non-pivotal on the same event. Still consumes and is blocked by match max pivotal and the period pivotal half; still AND with group/definition maps and issuance_max_count. Skips subject uniqueness and does not occupy the subject slot. Admin and play UIs decorate these questions.","default":false}},"additionalProperties":false,"type":"object","required":["name","question_text"],"title":"QuestionDefinitionUpdate","description":"Full replace of editable fields for an existing definition."},"QuestionGroupCreate":{"properties":{"slug":{"type":"string","maxLength":64,"title":"Slug","description":"Immutable per-league key (e.g. atbat)."},"name":{"type":"string","maxLength":255,"title":"Name","description":"Operator label."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional notes."},"is_active":{"type":"boolean","title":"Is Active","default":true},"issuance_min_interval":{"type":"integer","minimum":0.0,"title":"Issuance Min Interval","default":0},"issuance_min_interval_after_groups":{"additionalProperties":{"type":"integer"},"type":"object","title":"Issuance Min Interval After Groups"},"period_distribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"}],"title":"Period Distribution"},"max_per_match":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Max Per Match"}},"additionalProperties":false,"type":"object","required":["slug","name"],"title":"QuestionGroupCreate"},"QuestionGroupDefinitionRef":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"is_active":{"type":"boolean","title":"Is Active"}},"type":"object","required":["id","name","is_active"],"title":"QuestionGroupDefinitionRef","description":"Compact member definition for group list/detail."},"QuestionGroupListOut":{"properties":{"league":{"type":"string","title":"League","description":"League slug that was queried."},"league_id":{"type":"string","format":"uuid","title":"League Id","description":"Resolved internal league id."},"groups":{"items":{"$ref":"#/components/schemas/QuestionGroupOut"},"type":"array","title":"Groups","description":"Groups for this league."},"group_count":{"type":"integer","title":"Group Count","description":"Number of groups in ``groups``."}},"type":"object","required":["league","league_id","groups","group_count"],"title":"QuestionGroupListOut"},"QuestionGroupOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Internal question group id."},"league_id":{"type":"string","format":"uuid","title":"League Id","description":"Owning internal league id."},"slug":{"type":"string","title":"Slug","description":"Immutable per-league concurrency key."},"name":{"type":"string","title":"Name","description":"Operator label."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional operator notes."},"is_active":{"type":"boolean","title":"Is Active","description":"Inactive groups cannot receive new issuances."},"issuance_min_interval":{"type":"integer","title":"Issuance Min Interval","description":"Live lane floor (seconds) after any question in this group resolves."},"issuance_min_interval_after_groups":{"additionalProperties":{"type":"integer"},"type":"object","title":"Issuance Min Interval After Groups","description":"Seconds to wait after each listed group issues before this group may issue. Clock starts at that group's last issuance, not resolution. Empty object = no cross-group issue waits."},"period_distribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"}],"title":"Period Distribution","description":"Per-group period/half caps (ints only). {} = no group period caps; [] / {dist: even} = 1 per registered league key when max_per_match is unset, else even-split that integer. unlisted: block treats omitted keys as 0."},"max_per_match":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Per Match","description":"Optional group-wide issuance ceiling per match. When period distribution is even, this integer is also split across registered keys."},"definition_count":{"type":"integer","title":"Definition Count","description":"Number of question definitions that reference this group.","default":0},"definitions":{"items":{"$ref":"#/components/schemas/QuestionGroupDefinitionRef"},"type":"array","title":"Definitions","description":"Member question definitions (id, name, active)."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Row created_at (UTC)."},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Row updated_at (UTC)."}},"type":"object","required":["id","league_id","slug","name","is_active","issuance_min_interval","period_distribution"],"title":"QuestionGroupOut"},"QuestionGroupUpdate":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"},"issuance_min_interval":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Issuance Min Interval"},"issuance_min_interval_after_groups":{"anyOf":[{"additionalProperties":{"type":"integer"},"type":"object"},{"type":"null"}],"title":"Issuance Min Interval After Groups"},"period_distribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"},{"type":"null"}],"title":"Period Distribution"},"max_per_match":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Max Per Match"},"clear_max_per_match":{"type":"boolean","title":"Clear Max Per Match","description":"When true, set max_per_match to null.","default":false}},"additionalProperties":false,"type":"object","title":"QuestionGroupUpdate","description":"Partial update; slug cannot change."},"QuestionInheritanceOut":{"properties":{"kind":{"$ref":"#/components/schemas/InheritanceKind","description":"in_game or match."},"league_id":{"type":"string","format":"uuid","title":"League Id","description":"Internal league id."},"league_name":{"type":"string","title":"League Name","description":"League slug, e.g. ``mlb``."},"match_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Match Id","description":"Internal match id when a match is selected."},"match_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Match Label","description":"Match display label when a match is selected."},"definition_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Definition Id","description":"Selected definition id, if any."},"layers":{"items":{"$ref":"#/components/schemas/LayerSummary"},"type":"array","title":"Layers","description":"Strip of participating layers."},"settings":{"items":{"$ref":"#/components/schemas/SettingRow"},"type":"array","title":"Settings","description":"Settings matrix rows."},"issuance_traces":{"items":{"$ref":"#/components/schemas/IssuanceTraceOut"},"type":"array","title":"Issuance Traces","description":"Per-issuance decision traces when a match is selected."},"definitions":{"items":{"$ref":"#/components/schemas/DefinitionOption"},"type":"array","title":"Definitions","description":"Definitions for the picker (this kind + league)."},"groups":{"items":{"$ref":"#/components/schemas/GroupOption"},"type":"array","title":"Groups","description":"Question groups for this league (in-game only)."}},"type":"object","required":["kind","league_id","league_name","layers","settings","definitions"],"title":"QuestionInheritanceOut","description":"Read-only inheritance inspect payload for admin matrix and traces."},"QuestionIssuanceDenialListOut":{"properties":{"denials":{"items":{"$ref":"#/components/schemas/IssuanceDenialOut"},"type":"array","title":"Denials","description":"Blocked attempts oldest first."},"denial_count":{"type":"integer","title":"Denial Count","description":"Number of denial rows returned."}},"type":"object","required":["denials","denial_count"],"title":"QuestionIssuanceDenialListOut","description":"Blocked issuance attempts for one match."},"QuestionIssuanceListOut":{"properties":{"issuances":{"items":{"$ref":"#/components/schemas/QuestionIssuanceOut"},"type":"array","title":"Issuances","description":"In-game questions issued for the match, oldest first."},"issuance_count":{"type":"integer","title":"Issuance Count","description":"Number of issued in-game questions."},"resolved_count":{"type":"integer","title":"Resolved Count","description":"Issuances with ``resolved_at`` set."},"open_count":{"type":"integer","title":"Open Count","description":"Issuances still unresolved."},"answer_count":{"type":"integer","title":"Answer Count","description":"Total player answers across issuances."},"correct_count":{"type":"integer","title":"Correct Count","description":"Total correct answers."},"incorrect_count":{"type":"integer","title":"Incorrect Count","description":"Total incorrect answers."},"pending_count":{"type":"integer","title":"Pending Count","description":"Total pending (unscored) answers."},"points_awarded":{"type":"integer","minimum":0.0,"title":"Points Awarded","description":"Sum of points awarded across all answers for the match."}},"type":"object","required":["issuances","issuance_count","resolved_count","open_count","answer_count","correct_count","incorrect_count","pending_count","points_awarded"],"title":"QuestionIssuanceListOut"},"QuestionIssuanceOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Internal question issuance id."},"sequence":{"type":"integer","title":"Sequence","description":"1-based issuance order for the match (by created_at)."},"question_definition_id":{"type":"string","format":"uuid","title":"Question Definition Id","description":"Definition that produced this issuance."},"definition_name":{"type":"string","title":"Definition Name","description":"Definition name from the pinned snapshot when present; otherwise \"—\" (legacy rows without a snapshot)."},"definition":{"anyOf":[{"$ref":"#/components/schemas/QuestionDefinitionOut"},{"type":"null"}],"description":"Pinned ``definition_snapshot`` at issue time. Null when this issuance has no snapshot (legacy rows) — matches UI does not fall back to the live definition row."},"definition_is_snapshot":{"type":"boolean","title":"Definition Is Snapshot","description":"True when ``definition`` is the JSON pinned at issue time; false when ``definition`` is null (no snapshot)."},"question_text":{"type":"string","title":"Question Text","description":"Rendered question text from the pinned snapshot template when present; otherwise \"—\" (legacy rows without a snapshot)."},"question_settings_snapshot":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Question Settings Snapshot","description":"Effective in-game question settings pinned at issue time. Null for legacy rows issued before this snapshot existed."},"issued_in_period":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issued In Period","description":"Period or inning label captured when the question was issued."},"issued_situation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issued Situation","description":"Human game situation extracted from the issuing event. Null for legacy rows and when the payload has no matching shape."},"issued_clock":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issued Clock","description":"Countdown / remaining clock from the issuing event. Null when the payload has no clock or for legacy rows."},"resolved_in_period":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolved In Period","description":"Period or inning from the resolution event when resolved; else null."},"issued_at":{"type":"string","format":"date-time","title":"Issued At","description":"When the question was issued (UTC)."},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At","description":"When the question resolved (UTC), or null while open."},"resolution_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolution Reason","description":"How the issuance closed: ``resolved`` (feed), ``stale`` (complete/closed leftover), ``postponed`` / ``cancelled`` / ``unnecessary`` (match will not continue), ``retracted`` (same-eid corrective), or null while open / legacy."},"answer_count":{"type":"integer","title":"Answer Count","description":"Number of player answers for this issuance."},"correct_count":{"type":"integer","title":"Correct Count","description":"Answers scored correct."},"incorrect_count":{"type":"integer","title":"Incorrect Count","description":"Answers scored incorrect."},"pending_count":{"type":"integer","title":"Pending Count","description":"Answers not yet scored (``resolved_at`` is null)."},"points_awarded":{"type":"integer","minimum":0.0,"title":"Points Awarded","description":"Sum of ``points_awarded`` across answers (0 when none)."},"sponsor_brand":{"anyOf":[{"$ref":"#/components/schemas/BrandSummaryOut"},{"type":"null"}],"description":"Brand stamped onto this issuance from a claimed slot, if any."},"correct_answer_identifiers":{"items":{"type":"string"},"type":"array","title":"Correct Answer Identifiers","description":"Correct choice ids after resolution (empty while open)."},"issuance_event_fields":{"additionalProperties":true,"type":"object","title":"Issuance Event Fields","description":"Debug fields from the issuing event (same as History)."},"resolution_event_fields":{"additionalProperties":true,"type":"object","title":"Resolution Event Fields","description":"Debug fields from the resolving event (same as History)."},"condition_evaluations":{"items":{"$ref":"#/components/schemas/ConditionEvaluationView"},"type":"array","title":"Condition Evaluations","description":"Resolution trigger / answer-choice condition audit (same as History)."}},"type":"object","required":["id","sequence","question_definition_id","definition_name","definition_is_snapshot","question_text","issued_at","answer_count","correct_count","incorrect_count","pending_count","points_awarded"],"title":"QuestionIssuanceOut","description":"One in-game question issued during a match, with answer metrics and definition."},"QuestionSponsorshipOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Sponsorship slot id."},"match_id":{"type":"string","format":"uuid","title":"Match Id","description":"Match this slot belongs to."},"brand_id":{"type":"string","format":"uuid","title":"Brand Id","description":"Sponsoring brand id."},"strategy":{"type":"string","enum":["question_number","period","random"],"title":"Strategy","description":"Claim strategy for this slot."},"target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target","description":"Strategy-dependent target, or null for random."},"best_effort":{"type":"boolean","title":"Best Effort","description":"When true on a period slot (default), claim on a later issuance if the target period is missed.","default":true},"question_definition_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Question Definition Id","description":"Optional pinned definition id; when set, claim only when that definition is issued (and issuance forces that def when this slot would claim)."},"question_definition_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question Definition Name","description":"Pinned definition name when loaded, else null."},"brand":{"$ref":"#/components/schemas/BrandSummaryOut","description":"Sponsoring brand summary."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"When the slot was created (UTC)."},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"When the slot was last updated (UTC)."}},"type":"object","required":["id","match_id","brand_id","strategy","brand"],"title":"QuestionSponsorshipOut","description":"One pre-allocated sponsored-question slot on a match."},"QuestionSponsorshipSlotIn":{"properties":{"strategy":{"$ref":"#/components/schemas/QuestionSponsorshipStrategies","description":"``question_number`` (target = 1-based sequence string), ``period`` (target = period label), or ``random`` (target null)."},"target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target","description":"Required for question_number and period; must be null for random."},"best_effort":{"type":"boolean","title":"Best Effort","description":"Period only (default true): if the target period is missed, claim on the next available unused issuance. Forced false for other strategies.","default":true},"question_definition_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Question Definition Id","description":"Optional pin: when this slot would claim next, force issuance to this definition. Null means any definition may claim the slot."}},"type":"object","required":["strategy"],"title":"QuestionSponsorshipSlotIn","description":"One slot to assign when bulk-applying a brand to matches."},"QuestionSponsorshipStrategies":{"type":"string","enum":["question_number","period","random"],"title":"QuestionSponsorshipStrategies","description":"How a per-question brand sponsorship slot is claimed at issue time."},"QuestionTriggerCondition":{"properties":{"condition":{"type":"string","title":"Condition","description":"The condition to evaluate to determine if the question is issuable or resolvable."}},"type":"object","required":["condition"],"title":"QuestionTriggerCondition","description":"A condition to evaluate to determine if the question is issuable or resolvable."},"QuestionTriggerConditionList":{"properties":{"conditions":{"items":{"$ref":"#/components/schemas/QuestionTriggerCondition"},"type":"array","title":"Conditions","description":"A list of conditions to evaluate to determine if the question is resolvable, evaluated using jsonpath_condition_evaluate"}},"type":"object","title":"QuestionTriggerConditionList","description":"A list of conditions to evaluate to determine if the question is resolvable."},"SettingCell":{"properties":{"value":{"title":"Value","description":"Raw JSON-serializable value at this layer, if any."},"display":{"type":"string","title":"Display","description":"Operator-facing text for this cell."},"is_set":{"type":"boolean","title":"Is Set","description":"True when this layer has an explicit value (not inherit)."},"role":{"$ref":"#/components/schemas/CellRole","description":"wins / also_applies / inherit / unused."}},"type":"object","required":["display","is_set","role"],"title":"SettingCell","description":"One layer contribution to a setting row."},"SettingRow":{"properties":{"key":{"type":"string","title":"Key","description":"Stable setting id, e.g. ``max_count``."},"label":{"type":"string","title":"Label","description":"Operator label."},"field_help_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Field Help Key","description":"Existing AdminFieldHelp catalog key, when one applies."},"combine":{"$ref":"#/components/schemas/CombineRule","description":"override (most specific wins), and (all apply), or max."},"why":{"type":"string","title":"Why","description":"One-line explanation of how this setting resolves."},"cells":{"additionalProperties":{"$ref":"#/components/schemas/SettingCell"},"type":"object","title":"Cells","description":"Layer key → cell (league / match / group / definition)."},"effective":{"title":"Effective","description":"Resolved value used at runtime for the current selection."},"effective_display":{"type":"string","title":"Effective Display","description":"Operator-facing effective text."},"effective_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Source","description":"Winning or combining layer key(s), e.g. ``match`` or ``max``."}},"type":"object","required":["key","label","combine","why","cells","effective_display"],"title":"SettingRow","description":"One setting across layers plus the resolved effective value."},"SnapshotSource":{"type":"string","enum":["pinned","live"],"title":"SnapshotSource","description":"Where a definition's inspect config came from."},"StartMatchListenerOut":{"properties":{"match_id":{"type":"string","format":"uuid","title":"Match Id","description":"Internal match id."},"task_id":{"type":"string","title":"Task Id","description":"Celery task id for the enqueued start."},"force":{"type":"boolean","title":"Force","description":"Whether ``force`` was applied to the enqueue.","default":true}},"type":"object","required":["match_id","task_id"],"title":"StartMatchListenerOut","description":"Result of enqueueing start_match_listener for one match."},"StartMatchListenerRequest":{"properties":{"force":{"type":"boolean","title":"Force","description":"Clear Redis start barriers and skip the open-row guard (operator launch default). Prefer stop first if a listener is live.","default":true}},"type":"object","title":"StartMatchListenerRequest","description":"Body for ``POST /api/matches/{id}/start-listener``."},"StartupParamOut":{"properties":{"key":{"type":"string","title":"Key","description":"Internal setting key."},"label":{"type":"string","title":"Label","description":"Human-readable label."},"value":{"title":"Value","description":"Resolved value shown to operators."}},"type":"object","required":["key","label","value"],"title":"StartupParamOut","description":"One labeled startup config field for admin display."},"StopMatchListenerOut":{"properties":{"match_id":{"type":"string","format":"uuid","title":"Match Id","description":"Internal match id that was stopped."},"revoked_task_ids":{"items":{"type":"string"},"type":"array","title":"Revoked Task Ids","description":"Celery task ids that were revoked."},"closed_record_count":{"type":"integer","title":"Closed Record Count","description":"Open lifecycle rows marked ended by this stop.","default":0},"auto_dispatch_listener":{"type":"boolean","title":"Auto Dispatch Listener","description":"Value of Match.auto_dispatch_listener after stop (always false — stop opts out of Beat re-enqueue).","default":false}},"type":"object","required":["match_id"],"title":"StopMatchListenerOut","description":"Result of stopping listeners for one match."},"UserCreate":{"properties":{"username":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Username","description":"Optional unique username; omit when login will use email only."},"password":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Password","description":"Required for local_password accounts that should be able to log in."},"email":{"type":"string","maxLength":255,"minLength":3,"title":"Email"},"first_name":{"type":"string","maxLength":100,"minLength":1,"title":"First Name"},"last_name":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Last Name"},"postal_code":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Postal Code"},"date_of_birth":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date Of Birth"},"is_admin":{"type":"boolean","title":"Is Admin","default":false},"is_active":{"type":"boolean","title":"Is Active","default":true},"notify_on_issuance":{"type":"boolean","title":"Notify On Issuance","default":true},"notify_on_resolve":{"type":"boolean","title":"Notify On Resolve","default":true},"match_daily_follow_count":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Match Daily Follow Count","description":"Daily non-test follow cap; omit for default 3; null disables follow restrictions.","default":3},"match_follow_timezone":{"type":"string","maxLength":64,"title":"Match Follow Timezone","description":"IANA timezone for match-follow daily quota windows and Live Following day's slate; blank/null → UTC.","default":"UTC"}},"type":"object","required":["email","first_name"],"title":"UserCreate","examples":[{"email":"ops@example.com","first_name":"Ops","is_admin":true,"password":"secret","username":"ops"}]},"UserFeedbackCreate":{"properties":{"subject_type":{"type":"string","title":"Subject Type","description":"From GET /api/user-feedback/form (do not hardcode)."},"subject_id":{"type":"string","format":"uuid","title":"Subject Id","description":"Subject row id (question-answer history ``id``)."},"topic":{"type":"string","title":"Topic","description":"From the matching form entry's ``topics``."},"description":{"anyOf":[{"type":"string","maxLength":250},{"type":"null"}],"title":"Description","description":"Optional note. Empty string is stored as null. Max 250 characters."}},"type":"object","required":["subject_type","subject_id","topic"],"title":"UserFeedbackCreate","examples":[{"description":"Home scored after the window.","subject_id":"11111111-1111-1111-1111-111111111111","subject_type":"in_game_question_answer","topic":"incorrect_resolution"}]},"UserFeedbackFormOut":{"properties":{"subject_types":{"items":{"$ref":"#/components/schemas/UserFeedbackSubjectTypeOut"},"type":"array","title":"Subject Types","description":"Constrained subject types and their topics."},"subject_type_count":{"type":"integer","title":"Subject Type Count","description":"Number of subject_types entries."},"description_max_length":{"type":"integer","title":"Description Max Length","description":"Max characters for optional ``description``."},"description_required":{"type":"boolean","title":"Description Required","description":"Whether ``description`` is required on create."}},"type":"object","required":["subject_types","subject_type_count","description_max_length","description_required"],"title":"UserFeedbackFormOut"},"UserFeedbackListOut":{"properties":{"feedback":{"items":{"$ref":"#/components/schemas/UserFeedbackOut"},"type":"array","title":"Feedback","description":"Page of feedback rows (newest first)."},"feedback_count":{"type":"integer","title":"Feedback Count","description":"Total matching rows (ignores offset/limit)."}},"type":"object","required":["feedback","feedback_count"],"title":"UserFeedbackListOut"},"UserFeedbackOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Feedback row id."},"user_id":{"type":"string","format":"uuid","title":"User Id","description":"Submitter user id."},"user_display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Display Name","description":"Submitter display name when available."},"subject_type":{"type":"string","title":"Subject Type","description":"Subject kind."},"subject_id":{"type":"string","format":"uuid","title":"Subject Id","description":"Subject row id."},"match_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Match Id","description":"Internal match id when the subject has a match."},"topic":{"type":"string","title":"Topic","description":"Submitted topic value."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional note."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"When the feedback was submitted (UTC)."},"question_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question Text","description":"Question text for question-answer subjects."},"selected_answer_identifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Selected Answer Identifier","description":"Player's selected choice id."},"selected_answer_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Selected Answer Text","description":"Player's selected choice text."},"is_correct":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Correct","description":"Answer score flag when known."},"issuance_resolution_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issuance Resolution Reason","description":"Parent issuance close reason."},"match_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Match Label","description":"Short away@home-style match label."},"match_shortcode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Match Shortcode","description":"Listener shortcode when available."},"kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kind","description":"Play history kind for question-answer subjects."},"question_issuance_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Question Issuance Id","description":"Parent issuance id for question-answer subjects."},"match_scheduled":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Match Scheduled","description":"Match scheduled time (UTC) when the subject has a match."},"match_league_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Match League Name","description":"League slug/name for Issuance Explorer deep-links."}},"type":"object","required":["id","user_id","subject_type","subject_id","topic"],"title":"UserFeedbackOut"},"UserFeedbackSubjectTypeOut":{"properties":{"subject_type":{"type":"string","title":"Subject Type","description":"Value to POST as ``subject_type``."},"kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kind","description":"Play history ``kind`` join key when this subject is a question answer (``in_game`` or ``match``). Null for later subject types."},"label":{"type":"string","title":"Label","description":"Player-facing subject label."},"topics":{"items":{"$ref":"#/components/schemas/UserFeedbackTopicOut"},"type":"array","title":"Topics","description":"Allowed topics for this subject type."}},"type":"object","required":["subject_type","label","topics"],"title":"UserFeedbackSubjectTypeOut"},"UserFeedbackTopicOut":{"properties":{"topic":{"type":"string","title":"Topic","description":"Value to POST as ``topic``."},"label":{"type":"string","title":"Label","description":"Player-facing dropdown label."}},"type":"object","required":["topic","label"],"title":"UserFeedbackTopicOut"},"UserListOut":{"properties":{"users":{"items":{"$ref":"#/components/schemas/UserOut"},"type":"array","title":"Users","description":"Page of matching users (after sort/offset/limit)."},"user_count":{"type":"integer","title":"User Count","description":"Total matching users (ignores limit/offset; for pagination)."}},"type":"object","required":["users","user_count"],"title":"UserListOut"},"UserMeUpdate":{"properties":{"email":{"anyOf":[{"type":"string","maxLength":255,"minLength":3},{"type":"null"}],"title":"Email"},"first_name":{"anyOf":[{"type":"string","maxLength":100,"minLength":1},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Last Name"},"postal_code":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Postal Code"},"date_of_birth":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date Of Birth"},"match_follow_timezone":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Match Follow Timezone","description":"IANA timezone for match-follow daily quota windows and Live Following day's slate; explicit null/blank → UTC."},"notify_on_issuance":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify On Issuance"},"notify_on_resolve":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify On Resolve"}},"type":"object","title":"UserMeUpdate","description":"Player self-service profile update (not is_admin / is_active)."},"UserOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Internal user id (primary key)."},"username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username","description":"Optional unique login username (email always works for login)."},"email":{"type":"string","title":"Email","description":"Unique email address."},"first_name":{"type":"string","title":"First Name","description":"Given name."},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name","description":"Family name."},"display_name":{"type":"string","title":"Display Name","description":"first_name + last_name (derived)."},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code","description":"Postal / ZIP code."},"date_of_birth":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date Of Birth","description":"Date of birth (YYYY-MM-DD)."},"auth_method":{"type":"string","title":"Auth Method","description":"Authentication method (e.g. local_password)."},"is_admin":{"type":"boolean","title":"Is Admin","description":"Admin portal / admin API access."},"is_active":{"type":"boolean","title":"Is Active","description":"Whether the account may authenticate."},"notify_on_issuance":{"type":"boolean","title":"Notify On Issuance","description":"Receive push notifications when a followed match issues a question (global push gates still apply)."},"notify_on_resolve":{"type":"boolean","title":"Notify On Resolve","description":"Receive push notifications when a question this user answered resolves (global push gates still apply)."},"match_daily_follow_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Match Daily Follow Count","description":"Max non-test matches the user may follow per local calendar day. Null disables follow quotas and answer gating for this user."},"match_follow_timezone":{"type":"string","title":"Match Follow Timezone","description":"IANA timezone for this user's match-follow daily quota window (e.g. America/Toronto). Live clients also use it for the Following day's slate (convert that calendar day to UTC scheduled_from/to)."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"When the user row was created (UTC)."},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"When the user row was last updated (UTC)."}},"type":"object","required":["id","email","first_name","display_name","auth_method","is_admin","is_active","notify_on_issuance","notify_on_resolve","match_daily_follow_count","match_follow_timezone"],"title":"UserOut"},"UserPointsOut":{"properties":{"all_time_points":{"type":"integer","minimum":0.0,"title":"All Time Points","description":"Sum of scored ``points_awarded`` for this user (all time)."},"period_points":{"type":"integer","minimum":0.0,"title":"Period Points","description":"Sum of scored ``points_awarded`` with ``resolved_at`` in ``[period_from, period_to)`` (UTC)."},"period_from":{"type":"string","format":"date-time","title":"Period From","description":"Inclusive UTC start of the period window (echo)."},"period_to":{"type":"string","format":"date-time","title":"Period To","description":"Exclusive UTC end of the period window (echo)."}},"type":"object","required":["all_time_points","period_points","period_from","period_to"],"title":"UserPointsOut","description":"Aggregated scored points for a user."},"UserUpdate":{"properties":{"username":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Username","description":"Unique username; empty string clears to null."},"password":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Password","description":"When set, replaces the password hash."},"email":{"anyOf":[{"type":"string","maxLength":255,"minLength":3},{"type":"null"}],"title":"Email"},"first_name":{"anyOf":[{"type":"string","maxLength":100,"minLength":1},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Last Name"},"postal_code":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Postal Code"},"date_of_birth":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date Of Birth"},"is_admin":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Admin"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"},"notify_on_issuance":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify On Issuance"},"notify_on_resolve":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify On Resolve"},"match_daily_follow_count":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Match Daily Follow Count","description":"Daily non-test follow cap. Explicit null clears restrictions (unrestricted). Omit to leave unchanged."},"match_follow_timezone":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Match Follow Timezone","description":"IANA timezone for match-follow daily quota windows and Live Following day's slate; explicit null/blank → UTC."}},"type":"object","title":"UserUpdate","description":"Admin partial update (all fields optional)."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"HTTPBearer":{"type":"http","description":"API key from ``POST /api/auth/login`` or ``POST /api/auth/register``. Operations summarized as ``[Admin]`` also require ``User.is_admin=true``.","scheme":"bearer"}}},"tags":[{"name":"brands","description":"Brand identity configuration: name, primary/secondary hex colors, and optional logo stored under ``AWS_S3_DEFAULT_BUCKET`` at ``brands/{id}/{filename}`` (publicly readable prefix). Writes are admin-only (``[Admin]``)."},{"name":"auth","description":"Register and login (``local_password``) to obtain a Bearer API key. Copy the returned ``api_key`` into Swagger Authorize."},{"name":"users","description":"Authenticated user profiles. ``/me`` is self-scoped (any Bearer). ``POST/DELETE /me/devices`` registers push tokens. List/create/get/patch/deactivate and per-user answers/points are admin-only (``[Admin]``)."},{"name":"push","description":"Admin push notification settings and per-user delivery-attempt lookup (``[Admin]``)."},{"name":"question-answers","description":"Open questions for play, submit/update answers within the answer window, and list answer history. Requires Bearer API key; scoped to the authenticated user. For live push see ``docs/guides/play_client.md`` (WebSocket is not in OpenAPI)."},{"name":"user-feedback","description":"Player feedback on a subject (question-answers first). ``GET /form`` is the catalog (no auth). POST and list require a Bearer API key. See ``docs/guides/play_client.md``."},{"name":"play","description":"Live play WebSocket (``WS /api/play/stream``). Not documented in Swagger — see MkDocs guide ``docs/guides/play_client.md``."},{"name":"leagues","description":"League configuration including default question caps, period distribution, points, and answer window. PATCH and question-inheritance inspect are admin-only (``[Admin]``)."},{"name":"matches","description":"Match schedule and status; question overrides; clone CLOSED matches as test replays; start/stop listeners. Mutations and question-inheritance inspect are admin-only (``[Admin]``); list/get stay open."},{"name":"match-listeners","description":"Listener lifecycle rows grouped by match, plus per-run text logs and event recording downloads."},{"name":"question-groups","description":"League-scoped in-game issuance groups (concurrency lanes, group min-interval, period caps, max-per-match). Admin-only (``[Admin]``)."},{"name":"question-definitions","description":"Author and manage question definitions (triggers, templates, resolution), including preview against sample events. Writes and preview are admin-only (``[Admin]``); list/get stay open."},{"name":"match-question-definitions","description":"Author and manage Match question (match-question) definitions. Issued before first pitch, locked at match start, resolved via stream JSONPath and/or a named official source. Writes are admin-only (``[Admin]``); list/get stay open."}]}