{"openapi":"3.0.0","paths":{"/v1/users/me/settings":{"get":{"operationId":"MeSettingsController_get","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSettingsResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["users"]},"patch":{"description":"Partial update. Also while platform-banned, but then only to restrict what others see: turning `profilePublic` or `leaderboardVisible` on is 403 `USER_BANNED` (`details[].field`).","operationId":"MeSettingsController_update","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserSettingsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSettingsResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Change your privacy settings","tags":["users"]}},"/v1/users/me":{"get":{"operationId":"UsersController_me","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Users"]}},"/v1/users/info":{"patch":{"operationId":"UsersController_updateInfo","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdateInfoDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`, `FORBIDDEN`, `USER_BANNED`, `REAUTHENTICATION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `USERNAME_TAKEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Users"]}},"/v1/users/password":{"patch":{"operationId":"UsersController_updatePassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdatePasswordBodyDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `INVALID_CREDENTIALS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`, `FORBIDDEN`, `USER_BANNED`, `REAUTHENTICATION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `TOO_MANY_ATTEMPTS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Users"]}},"/v1/users/avatar":{"patch":{"operationId":"UsersController_updateAvatar","parameters":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["avatar"],"properties":{"avatar":{"type":"string","format":"binary","description":"JPEG, PNG, GIF or WebP, at most 5 MB."}}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponseDto"}}}},"400":{"description":"Error codes: `BAD_REQUEST`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Users"]}},"/v1/auth/register":{"post":{"operationId":"AuthController_register","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptedResponseDto"}}}},"403":{"description":"Error codes: `REGISTRATION_CLOSED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `USERNAME_TAKEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `REGISTRATION_NOT_ELIGIBLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["auth"]}},"/v1/auth/registration":{"get":{"operationId":"AuthController_registrationStatus","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationStatusResponseDto"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Registration mode","tags":["auth"]}},"/v1/auth/login":{"post":{"operationId":"AuthController_login","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignedInResponseDto"}}}},"401":{"description":"Error codes: `INVALID_CREDENTIALS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`, `EMAIL_NOT_VERIFIED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `TOO_MANY_ATTEMPTS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["auth"]}},"/v1/auth/token/refresh":{"post":{"operationId":"AuthController_refresh","parameters":[],"responses":{"204":{"description":"New auth cookies are set."},"401":{"description":"Error codes: `REFRESH_TOKEN_INVALID`, `REFRESH_TOKEN_REUSED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `REFRESH_CONFLICT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["auth"]}},"/v1/auth/logout":{"post":{"operationId":"AuthController_logout","parameters":[],"responses":{"204":{"description":"Cookies cleared."},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["auth"]}},"/v1/auth/verify-email":{"post":{"operationId":"AuthController_verifyEmail","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailResponseDto"}}}},"400":{"description":"Error codes: `AUTH_TOKEN_INVALID`, `AUTH_TOKEN_EXPIRED`, `AUTH_TOKEN_USED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `INVALID_CREDENTIALS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["auth"]}},"/v1/auth/confirm-email-change":{"post":{"operationId":"AuthController_confirmEmailChange","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmEmailChangeResponseDto"}}}},"400":{"description":"Error codes: `AUTH_TOKEN_INVALID`, `AUTH_TOKEN_EXPIRED`, `AUTH_TOKEN_USED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["auth"]}},"/v1/auth/verify-email/resend":{"post":{"operationId":"AuthController_resendVerification","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailRequestDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptedResponseDto"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["auth"]}},"/v1/auth/forgot-password":{"post":{"operationId":"AuthController_forgotPassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailRequestDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptedResponseDto"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["auth"]}},"/v1/auth/reset-password":{"post":{"operationId":"AuthController_resetPassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordDto"}}}},"responses":{"204":{"description":"Password changed; all sessions revoked."},"400":{"description":"Error codes: `AUTH_TOKEN_INVALID`, `AUTH_TOKEN_EXPIRED`, `AUTH_TOKEN_USED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["auth"]}},"/v1/auth/sso/google":{"post":{"operationId":"AuthController_ssoGoogle","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginSSODto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoogleSignInResponseDto"}}}},"401":{"description":"Error codes: `GOOGLE_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `GOOGLE_EMAIL_NOT_VERIFIED`, `LINK_REQUIRES_SIGN_IN`, `ACCOUNT_DISABLED`, `REGISTRATION_CLOSED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `IDENTITY_ALREADY_LINKED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["auth"]}},"/v1/auth/sso/google/complete":{"post":{"operationId":"AuthController_completeGoogle","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteGoogleRegistrationDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignedInResponseDto"}}}},"400":{"description":"Error codes: `REGISTRATION_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`, `REGISTRATION_CLOSED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `USERNAME_TAKEN`, `IDENTITY_ALREADY_LINKED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `REGISTRATION_NOT_ELIGIBLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["auth"]}},"/v1/users/me/sessions":{"get":{"operationId":"MeSessionsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionPageResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["sessions"]}},"/v1/users/me/sessions/revoke-others":{"post":{"operationId":"MeSessionsController_revokeOthers","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokedCountResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["sessions"]}},"/v1/users/me/sessions/{id}":{"delete":{"operationId":"MeSessionsController_revoke","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Session revoked."},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SESSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["sessions"]}},"/v1/users/me/devices":{"get":{"operationId":"MeDevicesController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevicePageResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["sessions"]}},"/v1/users/me/devices/{id}":{"delete":{"operationId":"MeDevicesController_revoke","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Device revoked."},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `DEVICE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["sessions"]}},"/v1/users/me/identities":{"get":{"operationId":"MeIdentitiesController_list","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdentityListResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["sessions"]}},"/v1/users/me/identities/google":{"post":{"operationId":"MeIdentitiesController_linkGoogle","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkGoogleDto"}}}},"responses":{"204":{"description":"Google account linked."},"401":{"description":"Error codes: `UNAUTHENTICATED`, `GOOGLE_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`, `GOOGLE_EMAIL_NOT_VERIFIED`, `REAUTHENTICATION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `IDENTITY_IN_USE`, `IDENTITY_ALREADY_LINKED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["sessions"]},"delete":{"operationId":"MeIdentitiesController_unlinkGoogle","parameters":[],"responses":{"204":{"description":"Google account unlinked."},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`, `REAUTHENTICATION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `IDENTITY_NOT_LINKED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `LAST_LOGIN_METHOD`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["sessions"]}},"/v1/users/me/reauthenticate":{"post":{"operationId":"MeReauthController_reauthenticate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReauthenticateDto"}}}},"responses":{"204":{"description":"The session may make sensitive changes for 5 minutes."},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `INVALID_CREDENTIALS`, `GOOGLE_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`, `GOOGLE_EMAIL_NOT_VERIFIED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `TOO_MANY_ATTEMPTS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["sessions"]}},"/v1/storage/local/uploads":{"put":{"operationId":"LocalStorageController_upload","parameters":[],"responses":{"204":{"description":""},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["LocalStorage"]}},"/v1/storage/local/objects":{"get":{"operationId":"LocalStorageController_download","parameters":[],"responses":{"200":{"description":""},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["LocalStorage"]}},"/v1/storage/local/public/{key}":{"get":{"operationId":"LocalStorageController_publicObject","parameters":[],"responses":{"200":{"description":""},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["LocalStorage"]}},"/v1/health":{"get":{"operationId":"HealthController_get","parameters":[],"responses":{"200":{"description":""},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Health"]}},"/v1/openapi.json":{"get":{"operationId":"OpenApiController_get","parameters":[],"responses":{"503":{"description":"Error codes: `SERVICE_UNAVAILABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["OpenApi"]}},"/v1/permissions":{"get":{"operationId":"PermissionsController_all","parameters":[],"responses":{"200":{"description":""},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Permissions"]}},"/v1/entitlements":{"get":{"operationId":"EntitlementsController_get","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntitlementsResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Entitlements"]}},"/v1/usage":{"get":{"operationId":"UsageController_get","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Usage"]}},"/v1/billing/subscription":{"get":{"operationId":"BillingController_getSubscription","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Billing"]}},"/v1/billing/checkout-sessions":{"post":{"operationId":"BillingController_createCheckoutSession","parameters":[{"name":"idempotency-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Required; a retry with the same key returns the same session.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCheckoutSessionDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSessionResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `IDEMPOTENCY_KEY_REQUIRED`, `IDEMPOTENCY_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `SUBSCRIPTION_ALREADY_ACTIVE`, `IDEMPOTENCY_KEY_IN_USE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `PLAN_PRICE_NOT_CONFIGURED`, `IDEMPOTENCY_KEY_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Error codes: `BILLING_NOT_CONFIGURED`, `STRIPE_UNAVAILABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Billing"]}},"/v1/billing/portal-sessions":{"post":{"operationId":"BillingController_createPortalSession","parameters":[],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalSessionResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `BILLING_CUSTOMER_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Error codes: `BILLING_NOT_CONFIGURED`, `STRIPE_UNAVAILABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Billing"]}},"/v1/webhooks/stripe":{"post":{"description":"Signed by Stripe (`Stripe-Signature`); idempotent on the event id. Not for API clients.","operationId":"StripeWebhookController_receive","parameters":[{"name":"stripe-signature","required":true,"in":"header","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeWebhookResponseDto"}}}},"400":{"description":"Error codes: `STRIPE_SIGNATURE_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Error codes: `BILLING_NOT_CONFIGURED`, `STRIPE_UNAVAILABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Stripe webhook (called by Stripe only)","tags":["StripeWebhook"]}},"/v1/organizations":{"post":{"operationId":"OrganizationsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrganizationDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Error codes: `QUOTA_EXCEEDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ORGANIZATION_SLUG_TAKEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]},"get":{"operationId":"OrganizationsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}":{"get":{"operationId":"OrganizationsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]},"patch":{"operationId":"OrganizationsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganizationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/members":{"get":{"operationId":"OrganizationMembersController_list","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/members/{userId}":{"patch":{"operationId":"OrganizationMembersController_changeRole","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeMemberRoleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `BAD_REQUEST`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`, `ROLE_ESCALATION_DENIED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `MEMBER_NOT_FOUND`, `ORG_ROLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `OWNER_MEMBERSHIP_LOCKED`, `ROLE_NOT_ASSIGNABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]},"delete":{"operationId":"OrganizationMembersController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"400":{"description":"Error codes: `BAD_REQUEST`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`, `ROLE_ESCALATION_DENIED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `MEMBER_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `OWNER_MEMBERSHIP_LOCKED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/leave":{"post":{"operationId":"OrganizationMembersController_leave","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `OWNER_MEMBERSHIP_LOCKED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/invitations":{"post":{"operationId":"OrganizationInvitationsController_create","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInvitationDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Error codes: `QUOTA_EXCEEDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`, `ROLE_ESCALATION_DENIED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `ORG_ROLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ALREADY_MEMBER`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `ROLE_NOT_ASSIGNABLE`, `PENDING_INVITATIONS_LIMIT`, `INVITEE_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `INVITATION_RESEND_TOO_SOON`, `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]},"get":{"operationId":"OrganizationInvitationsController_list","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/invitations/{invitationId}":{"delete":{"operationId":"OrganizationInvitationsController_revoke","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"invitationId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"400":{"description":"Error codes: `BAD_REQUEST`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`, `ROLE_ESCALATION_DENIED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `INVITATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/roles":{"get":{"operationId":"OrganizationRolesController_list","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgRoleListResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]},"post":{"operationId":"OrganizationRolesController_create","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrgRoleDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgRoleResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`, `ROLE_ESCALATION_DENIED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ROLE_NAME_TAKEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `CUSTOM_ROLES_LIMIT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/roles/{roleId}":{"patch":{"operationId":"OrganizationRolesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"roleId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrgRoleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgRoleResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`, `ROLE_ESCALATION_DENIED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `ORG_ROLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ROLE_NAME_TAKEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `SYSTEM_ROLE_IMMUTABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]},"delete":{"operationId":"OrganizationRolesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"roleId","required":true,"in":"path","schema":{"type":"string"}},{"name":"reassignTo","required":false,"in":"query","description":"Role that takes over the deleted role's members and pending invitations (required while it is in use).","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":""},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`, `ROLE_ESCALATION_DENIED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `ORG_ROLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ROLE_IN_USE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `SYSTEM_ROLE_IMMUTABLE`, `ROLE_NOT_ASSIGNABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/settings":{"get":{"operationId":"OrganizationSettingsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"headers":{"ETag":{"description":"The settings revision, for If-Match."}},"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationSettingsResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]},"patch":{"operationId":"OrganizationSettingsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"If-Match","in":"header","description":"The ETag of the settings being changed.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganizationSettingsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationSettingsResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"412":{"description":"Error codes: `PRECONDITION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"428":{"description":"Error codes: `PRECONDITION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/ownership-transfer":{"get":{"operationId":"OrganizationOwnershipTransferController_current","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentOwnershipTransferResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]},"post":{"operationId":"OrganizationOwnershipTransferController_offer","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferOwnershipTransferDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnershipTransferResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `MEMBER_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `OWNER_PLAN_REQUIRED`, `OWNERSHIP_TRANSFER_TO_SELF`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]},"delete":{"operationId":"OrganizationOwnershipTransferController_cancel","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Canceled (or there was none)."},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/ownership-transfer/accept":{"post":{"operationId":"OrganizationOwnershipTransferController_accept","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnswerOwnershipTransferDto"}}}},"responses":{"200":{"description":"The organization, now owned by the caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Error codes: `QUOTA_EXCEEDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `OWNERSHIP_TRANSFER_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `OWNER_PLAN_REQUIRED`, `OWNER_ACCOUNT_INACTIVE`, `OWNERSHIP_TRANSFER_EXPIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/ownership-transfer/decline":{"post":{"operationId":"OrganizationOwnershipTransferController_decline","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnswerOwnershipTransferDto"}}}},"responses":{"204":{"description":""},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `OWNERSHIP_TRANSFER_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/claim":{"post":{"operationId":"OrganizationLifecycleController_claim","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"The organization, active again and owned by the caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Error codes: `QUOTA_EXCEEDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ORGANIZATION_NOT_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `OWNER_PLAN_REQUIRED`, `OWNER_ACCOUNT_INACTIVE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/usage":{"get":{"operationId":"OrganizationUsageController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/invitations/preview":{"post":{"operationId":"InvitationsController_preview","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationTokenDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationPreviewResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `EMAIL_NOT_VERIFIED`, `INVITATION_EMAIL_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `INVITATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `INVITATION_EXPIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/invitations/accept":{"post":{"operationId":"InvitationsController_accept","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationTokenDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Error codes: `QUOTA_EXCEEDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `EMAIL_NOT_VERIFIED`, `INVITATION_EMAIL_MISMATCH`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `INVITATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ALREADY_MEMBER`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `INVITATION_EXPIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/invitations/reject":{"post":{"operationId":"InvitationsController_reject","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationTokenDto"}}}},"responses":{"204":{"description":""},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `EMAIL_NOT_VERIFIED`, `INVITATION_EMAIL_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `INVITATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `INVITATION_EXPIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/admin/organizations":{"get":{"operationId":"AdminOrganizationsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[q]","required":false,"in":"query","description":"Slug or name prefix (case-insensitive).","schema":{"type":"string"}},{"name":"filter[status]","required":false,"in":"query","schema":{"type":"string","enum":["active","frozen","deleted"]}},{"name":"filter[type]","required":false,"in":"query","schema":{"type":"string","enum":["standard","school"]}},{"name":"filter[owner]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminOrganizationPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]}},"/v1/admin/organizations/{id}":{"get":{"operationId":"AdminOrganizationsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminOrganizationDetailResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `BAD_REQUEST`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]}},"/v1/admin/organizations/{id}/disable":{"post":{"operationId":"AdminOrganizationsController_disable","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffReasonDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminOrganizationResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `BAD_REQUEST`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]}},"/v1/admin/organizations/{id}/enable":{"post":{"operationId":"AdminOrganizationsController_enable","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffReasonDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminOrganizationResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `BAD_REQUEST`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]}},"/v1/admin/organizations/{id}/rename":{"post":{"operationId":"AdminOrganizationsController_rename","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffRenameOrganizationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminOrganizationResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `BAD_REQUEST`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ORGANIZATION_SLUG_TAKEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]}},"/v1/organizations/{id}/school-setup":{"post":{"description":"Accepts the current DPA for the school and changes the organization type to `school` (school mode: comments off). Schools stay schools.","operationId":"OrganizationSchoolController_setUp","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchoolSetupDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ORGANIZATION_ALREADY_SCHOOL`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `DPA_VERSION_OUTDATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Turn the organization into a school","tags":["organizations"]}},"/v1/organizations/{id}/dpa-acceptances":{"post":{"description":"For schools whose accepted version is no longer current.","operationId":"OrganizationSchoolController_renew","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptDpaDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DpaAcceptanceResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `DPA_ALREADY_ACCEPTED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `DPA_VERSION_OUTDATED`, `ORGANIZATION_NOT_SCHOOL`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Accept the current DPA version for a school","tags":["organizations"]},"get":{"operationId":"OrganizationSchoolController_history","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DpaAcceptancePageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ORGANIZATION_FROZEN`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The organization's DPA acceptances, newest first","tags":["organizations"]}},"/v1/school-dpa":{"get":{"description":"Send `version` back in `dpa.version` when creating a school or accepting the DPA.","operationId":"SchoolDpaController_current","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchoolDpaResponseDto"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The data processing agreement schools accept now","tags":["organizations"]}},"/v1/puzzles":{"post":{"operationId":"PuzzlesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePuzzleDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PuzzleResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Error codes: `QUOTA_EXCEEDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `COVER_ASSET_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]},"get":{"operationId":"PuzzlesController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"ownerOrgId","required":false,"in":"query","description":"List this organization; omit for your personal workspace.","schema":{"format":"uuid","type":"string"}},{"name":"filter[gameType]","required":false,"in":"query","schema":{"example":"sudoku","type":"string"}},{"name":"filter[language]","required":false,"in":"query","schema":{"example":"es","type":"string"}},{"name":"filter[difficulty]","required":false,"in":"query","schema":{"type":"string","enum":["easy","medium","hard","expert"]}},{"name":"filter[tag]","required":false,"in":"query","description":"Puzzles carrying this tag (case-insensitive).","schema":{"type":"string"}},{"name":"filter[q]","required":false,"in":"query","description":"Full-text search over title, tags and description (accents ignored).","schema":{"type":"string"}},{"name":"sort","required":false,"in":"query","schema":{"default":"-createdAt","type":"string","enum":["-createdAt","createdAt","-updatedAt","updatedAt"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PuzzlePageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]}},"/v1/puzzles/{id}":{"get":{"operationId":"PuzzlesController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PuzzleResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]},"patch":{"operationId":"PuzzlesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePuzzleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PuzzleResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `COVER_ASSET_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]},"delete":{"operationId":"PuzzlesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]}},"/v1/puzzles/{id}/draft":{"get":{"operationId":"PuzzleDraftsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"headers":{"ETag":{"description":"The draft revision, for If-Match."}},"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DraftResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]},"put":{"operationId":"PuzzleDraftsController_save","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"If-Match","in":"header","description":"The ETag of the draft being replaced.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveDraftDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DraftResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `BAD_REQUEST`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"412":{"description":"Error codes: `PRECONDITION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Error codes: `PAYLOAD_TOO_LARGE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `GAME_TYPE_UNAVAILABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"428":{"description":"Error codes: `PRECONDITION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]}},"/v1/puzzles/{id}/validate":{"post":{"operationId":"PuzzleDraftsController_validate","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DraftValidationResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `GAME_TYPE_UNAVAILABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]}},"/v1/puzzles/{id}/versions":{"post":{"operationId":"PuzzleVersionsController_save","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveVersionDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedVersionResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `DRAFT_REVISION_MISMATCH`, `VERSION_UNCHANGED`, `SOLUTION_CHANGE_UNACKNOWLEDGED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `DRAFT_EMPTY`, `PUZZLE_INVALID`, `GAME_TYPE_UNAVAILABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]},"get":{"operationId":"PuzzleVersionsController_list","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VersionPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]}},"/v1/puzzles/{id}/versions/{versionId}":{"get":{"operationId":"PuzzleVersionsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"versionId","required":true,"in":"path","schema":{"type":"string"}},{"name":"include","required":false,"in":"query","description":"Include the solution; requires `puzzle:read-solution` (403 otherwise).","schema":{"type":"string","enum":["solution"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VersionResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`, `PUZZLE_VERSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]}},"/v1/uploads":{"post":{"operationId":"UploadsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUploadDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `TOO_MANY_PENDING_UPLOADS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["assets"]}},"/v1/assets":{"post":{"operationId":"AssetsController_register","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterAssetDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Error codes: `QUOTA_EXCEEDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `UPLOAD_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `UPLOAD_PROCESSING`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `UPLOAD_NOT_RECEIVED`, `UPLOAD_TOO_LARGE`, `ASSET_CONTENT_MISMATCH`, `ASSET_UNSUPPORTED_IMAGE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["assets"]},"get":{"operationId":"AssetsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"ownerOrgId","required":false,"in":"query","description":"List this organization; omit for your personal workspace.","schema":{"format":"uuid","type":"string"}},{"name":"filter[purpose]","required":false,"in":"query","schema":{"type":"string","enum":["puzzle_cover","puzzle_image","brand_image"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["assets"]}},"/v1/assets/{id}":{"get":{"operationId":"AssetsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ASSET_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["assets"]},"delete":{"operationId":"AssetsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"purpose","required":false,"in":"query","description":"Declare an organization brand image, to delete it with `organization:settings:manage`.","schema":{"enum":["brand_image"],"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ASSET_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ASSET_IN_USE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["assets"]}},"/v1/series":{"post":{"operationId":"SeriesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSeriesDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeriesResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `SERIES_SLUG_TAKEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["series"]},"get":{"operationId":"SeriesController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"ownerOrgId","required":false,"in":"query","description":"List this organization; omit for your personal workspace.","schema":{"format":"uuid","type":"string"}},{"name":"filter[gameType]","required":false,"in":"query","schema":{"example":"crossword","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeriesPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["series"]}},"/v1/series/{id}":{"get":{"operationId":"SeriesController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeriesResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SERIES_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["series"]},"patch":{"operationId":"SeriesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSeriesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeriesResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SERIES_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `SERIES_SLUG_TAKEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["series"]},"delete":{"operationId":"SeriesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SERIES_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["series"]}},"/v1/series/{id}/editions/{date}":{"put":{"operationId":"SeriesController_putEdition","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"date","required":true,"in":"path","schema":{"type":"string"}},{"name":"If-Match","in":"header","description":"The ETag of the existing puzzle's draft, to replace a draft that has changes not saved as a version.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PutEditionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PutEditionResponseDto"}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PutEditionResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `BAD_REQUEST`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Error codes: `QUOTA_EXCEEDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SERIES_NOT_FOUND`, `PUZZLE_NOT_FOUND`, `PUZZLE_VERSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `SOLUTION_CHANGE_UNACKNOWLEDGED`, `DRAFT_HAS_UNSAVED_CHANGES`, `PUZZLE_TAKEN_DOWN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"412":{"description":"Error codes: `PRECONDITION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Error codes: `PAYLOAD_TOO_LARGE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `PUZZLE_INVALID`, `GAME_TYPE_UNAVAILABLE`, `DRAFT_EMPTY`, `PUZZLE_HAS_NO_VERSION`, `SOURCE_GAME_TYPE_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Error codes: `TRANSIENT_CONFLICT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["series"]}},"/v1/series/{id}/editions":{"get":{"operationId":"SeriesController_listEditions","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"from","required":false,"in":"query","schema":{"format":"date","example":"2026-10-01","type":"string"}},{"name":"to","required":false,"in":"query","schema":{"format":"date","example":"2026-10-31","type":"string"}},{"name":"sort","required":false,"in":"query","schema":{"default":"-date","type":"string","enum":["-date","date"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditionPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SERIES_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["series"]}},"/v1/puzzles/import":{"post":{"operationId":"PuzzleConversionsController_importNew","parameters":[{"name":"format","required":true,"in":"query","description":"Engine format id of the game: crossword and cryptic `puz`, `ipuz`, `jpz`, `json`; sudoku `txt`, `sdk`, `json`.","schema":{"example":"puz","type":"string"}},{"name":"ownerOrgId","required":false,"in":"query","description":"Import into this organization; omit for your personal workspace (Creator plan).","schema":{"format":"uuid","type":"string"}},{"name":"gameType","required":true,"in":"query","schema":{"example":"crossword","type":"string"}},{"name":"title","required":false,"in":"query","description":"Default: the file's title, else `Imported <format> puzzle`.","schema":{"maxLength":200,"type":"string"}},{"name":"language","required":false,"in":"query","schema":{"pattern":"^[a-z]{2,3}(-[A-Za-z0-9]{2,8}){0,2}$","default":"en","example":"en","type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"description":"The file itself (at most 2 MiB), as `application/octet-stream`.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `IMPORT_FILE_EMPTY`, `IDEMPOTENCY_KEY_REQUIRED`, `IDEMPOTENCY_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Error codes: `QUOTA_EXCEEDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `IDEMPOTENCY_KEY_IN_USE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Error codes: `PAYLOAD_TOO_LARGE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"415":{"description":"Error codes: `UNSUPPORTED_MEDIA_TYPE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `IMPORT_FAILED`, `IDEMPOTENCY_KEY_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]}},"/v1/puzzles/{id}/import":{"post":{"operationId":"PuzzleConversionsController_importIntoDraft","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"format","required":true,"in":"query","description":"Engine format id of the game: crossword and cryptic `puz`, `ipuz`, `jpz`, `json`; sudoku `txt`, `sdk`, `json`.","schema":{"example":"puz","type":"string"}},{"name":"If-Match","in":"header","description":"The ETag of the draft being replaced.","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"description":"The file itself (at most 2 MiB), as `application/octet-stream`.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `IMPORT_FILE_EMPTY`, `IDEMPOTENCY_KEY_REQUIRED`, `IDEMPOTENCY_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `IDEMPOTENCY_KEY_IN_USE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"412":{"description":"Error codes: `PRECONDITION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Error codes: `PAYLOAD_TOO_LARGE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"415":{"description":"Error codes: `UNSUPPORTED_MEDIA_TYPE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `IMPORT_FAILED`, `IDEMPOTENCY_KEY_MISMATCH`, `GAME_TYPE_UNAVAILABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"428":{"description":"Error codes: `PRECONDITION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]}},"/v1/puzzles/{id}/versions/{versionId}/export":{"get":{"operationId":"PuzzleConversionsController_export","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"versionId","required":true,"in":"path","schema":{"type":"string"}},{"name":"format","required":true,"in":"query","description":"Engine format id of the game: crossword and cryptic `puz`, `ipuz`, `jpz`, `json`; sudoku `txt`, `sdk`, `json`.","schema":{"example":"puz","type":"string"}}],"responses":{"200":{"headers":{"Content-Disposition":{"description":"attachment; filename=\"…\""},"Puzzle-Export-Warnings":{"description":"Comma-separated warning codes, when the export is lossy."}},"description":"","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/octet-stream":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/octet-stream":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`","content":{"application/octet-stream":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`, `PUZZLE_VERSION_NOT_FOUND`","content":{"application/octet-stream":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PUZZLE_TAKEN_DOWN`","content":{"application/octet-stream":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `EXPORT_FAILED`, `GAME_TYPE_UNAVAILABLE`","content":{"application/octet-stream":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]}},"/v1/puzzles/{id}/clone":{"post":{"operationId":"PuzzleClonesController_clone","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClonePuzzleDto"}}}},"responses":{"201":{"headers":{"ETag":{"description":"The new draft revision."}},"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloneResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Error codes: `QUOTA_EXCEEDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `INSUFFICIENT_SCOPE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`, `PUZZLE_VERSION_NOT_FOUND`, `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PUZZLE_TAKEN_DOWN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `PUZZLE_HAS_NO_VERSION`, `PUZZLE_INVALID`, `GAME_TYPE_UNAVAILABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["puzzles"]}},"/v1/games":{"get":{"operationId":"GamesController_list","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameListResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["games"]}},"/v1/puzzles/{id}/publications":{"post":{"operationId":"PuzzlePublicationsController_create","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePublicationDto"}}}},"responses":{"201":{"headers":{"ETag":{"description":"The publication revision."}},"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PUBLICATION_ALREADY_EXISTS`, `PUZZLE_TAKEN_DOWN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `SETTINGS_LOOSENED`, `GAME_TYPE_UNAVAILABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["publications"]},"get":{"operationId":"PuzzlePublicationsController_list","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationPageResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["publications"]}},"/v1/publications":{"get":{"operationId":"PublicationsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"ownerOrgId","required":false,"in":"query","description":"List this organization; omit for your personal workspace.","schema":{"format":"uuid","type":"string"}},{"name":"filter[status]","required":false,"in":"query","schema":{"type":"string","enum":["unpublished","published","archived"]}},{"name":"filter[visibility]","required":false,"in":"query","schema":{"type":"string","enum":["public","unlisted","private"]}},{"name":"sort","required":false,"in":"query","schema":{"default":"-createdAt","type":"string","enum":["-createdAt","createdAt","-updatedAt","updatedAt"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["publications"]}},"/v1/publications/{id}":{"get":{"operationId":"PublicationsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"headers":{"ETag":{"description":"The publication revision, for If-Match."}},"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["publications"]},"patch":{"operationId":"PublicationsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"If-Match","in":"header","description":"The ETag of the publication being changed.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePublicationDto"}}}},"responses":{"200":{"headers":{"ETag":{"description":"The publication revision, for If-Match."}},"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PUBLICATION_MODE_LOCKED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"412":{"description":"Error codes: `PRECONDITION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `SETTINGS_LOOSENED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"428":{"description":"Error codes: `PRECONDITION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["publications"]}},"/v1/publications/{id}/publish":{"post":{"operationId":"PublicationsController_publish","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"headers":{"ETag":{"description":"The publication revision, for If-Match."}},"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Error codes: `QUOTA_EXCEEDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PUBLICATION_INVALID_TRANSITION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `PUBLICATION_HAS_NO_VERSION`, `PUBLICATION_TAKEN_DOWN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["publications"]}},"/v1/publications/{id}/unpublish":{"post":{"operationId":"PublicationsController_unpublish","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"headers":{"ETag":{"description":"The publication revision, for If-Match."}},"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PUBLICATION_INVALID_TRANSITION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["publications"]}},"/v1/publications/{id}/archive":{"post":{"operationId":"PublicationsController_archive","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"headers":{"ETag":{"description":"The publication revision, for If-Match."}},"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["publications"]}},"/v1/publications/{id}/restore":{"post":{"operationId":"PublicationsController_restore","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"headers":{"ETag":{"description":"The publication revision, for If-Match."}},"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PUBLICATION_INVALID_TRANSITION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["publications"]}},"/v1/publications/{id}/play":{"get":{"description":"The current version, runtime settings and embed data (`embed.frameAncestors` for the play document's CSP). Caching: public and unlisted responses without a token are shared-cacheable. After the publication switches to private, starts requiring embed tokens, is unpublished or is taken down, copies cached before the change can still be served by the edge until they expire: up to 60 s for the pointer and up to 1 h for payloads (5 min in browsers), until the instant purge of E13-T02. Responses with a token, and responses for private or token-required publications, are `private, no-store`. A personal owner who is suspended or deleted stops serving their publications: 404 like an unknown publication (`no-store`), with an edge purge queued on the change; restoring the account serves them again. Organization state never matters here.","operationId":"PlayController_pointer","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Embed-Parent-Origin","in":"header","description":"Optional. The parent page origin the play host observed. Not required; when sent, it must match the token’s origin exactly (403 `EMBED_ORIGIN_MISMATCH`).","required":false,"schema":{"type":"string"}},{"name":"X-Embed-Token","in":"header","description":"The embed token of the iframe URL (`?et=`), for embeds (E09-T05). Required for embed-only publications whose policy requires tokens; with it the response is `private, no-store`. An expired token is 401 `EMBED_TOKEN_EXPIRED` with `details: { origin }`, the token’s own origin (only when its signature verified).","required":false,"schema":{"type":"string"}}],"responses":{"200":{"headers":{"Cache-Control":{"description":"Public and unlisted publications: shared-cacheable (see the operation); private ones, token embeds and publications requiring tokens `private, no-store`."},"Vary":{"description":"`x-embed-token, x-embed-parent-origin, authorization` (student tokens, E20-T02)."}},"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayPointerResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `EMBED_TOKEN_EXPIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `EMBED_TOKEN_REQUIRED`, `EMBED_TOKEN_INVALID`, `EMBED_ORIGIN_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Error codes: `PUBLICATION_REMOVED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Play pointer of a publication","tags":["play"]}},"/v1/versions/{versionId}/payload":{"get":{"description":"The public definition and, for casual play with access to them, the checks; never the solution. Caching: public and unlisted responses without a token are shared-cacheable. After the publication switches to private, starts requiring embed tokens, is unpublished or is taken down, copies cached before the change can still be served by the edge until they expire: up to 60 s for the pointer and up to 1 h for payloads (5 min in browsers), until the instant purge of E13-T02. Responses with a token, and responses for private or token-required publications, are `private, no-store`. A personal owner who is suspended or deleted stops serving their publications: 404 like an unknown publication (`no-store`), with an edge purge queued on the change; restoring the account serves them again. Organization state never matters here.","operationId":"PlayController_payload","parameters":[{"name":"versionId","required":true,"in":"path","schema":{"type":"string"}},{"name":"mode","required":false,"in":"query","description":"The publication's mode. Another value is 409 `PLAY_MODE_MISMATCH`: the server, not the client, decides whether checks are served.","schema":{"default":"casual","type":"string","enum":["casual","competitive"]}},{"name":"X-Embed-Parent-Origin","in":"header","description":"Optional. The parent page origin the play host observed. Not required; when sent, it must match the token’s origin exactly (403 `EMBED_ORIGIN_MISMATCH`).","required":false,"schema":{"type":"string"}},{"name":"X-Embed-Token","in":"header","description":"The embed token of the iframe URL (`?et=`), for embeds (E09-T05). Required for embed-only publications whose policy requires tokens; with it the response is `private, no-store`. An expired token is 401 `EMBED_TOKEN_EXPIRED` with `details: { origin }`, the token’s own origin (only when its signature verified).","required":false,"schema":{"type":"string"}}],"responses":{"200":{"headers":{"Cache-Control":{"description":"Public and unlisted publications: shared-cacheable (see the operation); private ones, token embeds and publications requiring tokens `private, no-store`."},"Vary":{"description":"`x-embed-token, x-embed-parent-origin, authorization` (student tokens, E20-T02)."}},"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VersionPayloadResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `EMBED_TOKEN_EXPIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `EMBED_TOKEN_REQUIRED`, `EMBED_TOKEN_INVALID`, `EMBED_ORIGIN_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_VERSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PLAY_MODE_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Error codes: `PUBLICATION_REMOVED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Version payload for play","tags":["play"]}},"/v1/public-urls/resolve":{"get":{"operationId":"PublicUrlsController_resolve","parameters":[{"name":"path","required":true,"in":"query","description":"A public URL path: `/@<handle>/<game>/<slug>` or `/@<handle>/<game>/<series>/<YYYY-MM-DD>`.","schema":{"maxLength":300,"example":"/@acme/crossword/sunday-special","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicUrlResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Error codes: `PUBLICATION_REMOVED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["publications"]}},"/v1/publications/{id}/embed-tokens":{"post":{"operationId":"EmbedTokensController_create","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmbedTokenDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbedTokenResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `API_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Error codes: `QUOTA_EXCEEDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `API_KEY_REQUIRED`, `INSUFFICIENT_SCOPE`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `PUBLICATION_NOT_EMBEDDABLE`, `EMBED_ORIGIN_INVALID`, `EMBED_ORIGIN_NOT_ALLOWED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Error codes: `EMBED_TOKENS_NOT_CONFIGURED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["embeds"]}},"/v1/embed-tokens/jwks":{"get":{"operationId":"EmbedTokensController_jwks","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbedTokenJwksResponseDto"}}}},"503":{"description":"Error codes: `EMBED_TOKENS_NOT_CONFIGURED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["embeds"]}},"/v1/publications/{id}/access-grants":{"post":{"operationId":"AccessGrantsController_create","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccessGrantDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessGrantResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ACCESS_GRANT_ALREADY_EXISTS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `ACCESS_GRANTEE_NOT_FOUND`, `ACCESS_GRANT_EXPIRY_INVALID`, `ACCESS_GRANTS_LIMIT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["publications"]},"get":{"operationId":"AccessGrantsController_list","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessGrantPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["publications"]}},"/v1/access-grants/{id}":{"delete":{"operationId":"AccessGrantsController_revoke","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ACCESS_GRANT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["publications"]}},"/v1/search":{"get":{"description":"Public, published puzzles by text (full-text per language, typo-tolerant titles, accents ignored) and filters. Never returns content, checks or solutions.","operationId":"SearchController_puzzles","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"q","required":false,"in":"query","description":"Text over title, tags and description: full-text per puzzle language (English, Spanish, Portuguese stemming; any language word by word), accents ignored, typo-tolerant on titles (3+ characters). Omit to browse.","schema":{"maxLength":100,"type":"string"}},{"name":"filter[gameType]","required":false,"in":"query","schema":{"example":"crossword","type":"string"}},{"name":"filter[language]","required":false,"in":"query","description":"A primary language (`pt`) matches its regional variants (`pt-PT`, `pt-BR`); a tag with a region matches exactly.","schema":{"example":"es","type":"string"}},{"name":"filter[difficulty]","required":false,"in":"query","schema":{"type":"string","enum":["easy","medium","hard","expert"]}},{"name":"filter[tag]","required":false,"in":"query","description":"Puzzles carrying this tag (case-insensitive).","schema":{"type":"string"}},{"name":"sort","required":false,"in":"query","description":"Default `relevance` with `q`, else `-publishedAt` (newest first); `relevance` without `q` is `-publishedAt`.","schema":{"type":"string","enum":["relevance","-publishedAt","publishedAt","title"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PuzzleSearchPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Search public puzzles","tags":["search"]}},"/v1/search/profiles":{"get":{"description":"Users with a public profile and organizations that have at least one public, published puzzle, by handle (prefix) or name (typo-tolerant).","operationId":"SearchController_profiles","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"q","required":true,"in":"query","description":"Handle or name; a handle prefix matches, names are typo-tolerant (3+ characters), accents ignored.","schema":{"minLength":2,"maxLength":100,"type":"string"}},{"name":"filter[kind]","required":false,"in":"query","schema":{"type":"string","enum":["user","org"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileSearchPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Search creators and organizations","tags":["search"]}},"/v1/admin/impersonations":{"post":{"description":"Support and super admins only, from their own session reauthenticated within the last 5 minutes. Opens a separate session for the user (at most 30 minutes; tokens carry an `act` claim) and sets it as the auth cookies; the staff refresh token is kept aside so `DELETE /v1/users/me/impersonation` returns to it. In that session credential, billing, delete and staff operations answer 403 `IMPERSONATION_FORBIDDEN`. Audited.","operationId":"ImpersonationsController_start","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartImpersonationDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImpersonationResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `REAUTHENTICATION_REQUIRED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `USER_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `IMPERSONATION_TARGET_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Start impersonating a user","tags":["admin"]}},"/v1/users/me/impersonation":{"get":{"description":"For the impersonation banner: `active` with the session details while a staff member impersonates the signed-in user, else `active: false`.","operationId":"MeImpersonationController_current","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentImpersonationResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Whether this session is an impersonation","tags":["admin"]},"delete":{"description":"Closes the impersonation this session belongs to and revokes its session (audited), then signs the staff member back into their own session from the staff refresh cookie set at the start (`staffSessionRestored`); otherwise the auth cookies are cleared.","operationId":"MeImpersonationController_end","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndImpersonationResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `IMPERSONATION_NOT_ACTIVE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"End the impersonation","tags":["admin"]}},"/v1/admin/users":{"get":{"operationId":"AdminUsersController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[q]","required":false,"in":"query","description":"An exact email address (contains `@`), or a username / display name prefix.","schema":{"type":"string"}},{"name":"filter[status]","required":false,"in":"query","schema":{"type":"string","enum":["active","suspended"]}},{"name":"filter[staffRole]","required":false,"in":"query","schema":{"type":"string","enum":["support","moderator","super_admin"]}},{"name":"filter[deleted]","required":false,"in":"query","description":"Only deleted (`true`) or only live (`false`) accounts.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]}},"/v1/admin/users/{id}":{"get":{"operationId":"AdminUsersController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserDetailDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `USER_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]}},"/v1/admin/users/{id}/suspend":{"post":{"description":"Signs out every session of the user (impersonations included); suspended accounts get 403 `ACCOUNT_DISABLED`. Idempotent; never your own account. Audited with the reason.","operationId":"AdminUsersController_suspend","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReasonDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserSummaryDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `USER_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `STAFF_SELF_ACTION`, `LAST_SUPER_ADMIN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Suspend a user","tags":["admin"]}},"/v1/admin/users/{id}/restore":{"post":{"operationId":"AdminUsersController_restore","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReasonDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserSummaryDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `USER_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `STAFF_SELF_ACTION`, `LAST_SUPER_ADMIN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Restore a suspended user (idempotent, audited)","tags":["admin"]}},"/v1/admin/users/{id}/staff-roles":{"put":{"description":"Super admins only, never on their own account (422 `STAFF_SELF_ACTION`); the last active super admin keeps the role (422 `LAST_SUPER_ADMIN`). Audited with the reason, the roles granted and revoked.","operationId":"AdminUsersController_setStaffRoles","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetStaffRolesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserSummaryDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `USER_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `STAFF_SELF_ACTION`, `LAST_SUPER_ADMIN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Replace a user’s staff roles","tags":["admin"]}},"/v1/admin/settings":{"get":{"operationId":"AdminSettingsController_get","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformSettingsResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]},"patch":{"description":"Partial: only the fields sent change. Audited with the reason and the field names (never the addresses; the registration allow-list only by its size).","operationId":"AdminSettingsController_update","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePlatformSettingsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformSettingsResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Change global settings","tags":["admin"]}},"/v1/admin/audit-logs":{"get":{"operationId":"AdminAuditLogsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[action]","required":false,"in":"query","schema":{"example":"organization.disabled","type":"string"}},{"name":"filter[resource]","required":false,"in":"query","description":"Every action of one resource (the part before the first dot).","schema":{"example":"organization","type":"string"}},{"name":"filter[actor]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"filter[impersonator]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"filter[targetType]","required":false,"in":"query","schema":{"example":"user","type":"string"}},{"name":"filter[targetId]","required":false,"in":"query","schema":{"type":"string"}},{"name":"filter[from]","required":false,"in":"query","schema":{"format":"date-time","type":"string"}},{"name":"filter[to]","required":false,"in":"query","schema":{"format":"date-time","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditLogPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]}},"/v1/admin/audit-logs/{id}":{"get":{"operationId":"AdminAuditLogsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditLogResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `AUDIT_LOG_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]}},"/v1/admin/plans":{"get":{"operationId":"AdminPlansController_list","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanListResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]}},"/v1/admin/plans/{key}":{"patch":{"description":"Lowering limits never deletes content; consumers restrict. Audited with the reason and each changed value.","operationId":"AdminPlansController_update","parameters":[{"name":"key","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePlanDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PLAN_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `PLAN_NOT_SELLABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Change a plan’s entitlements or availability","tags":["admin"]}},"/v1/admin/entitlement-overrides":{"get":{"operationId":"AdminEntitlementOverridesController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[subjectType]","required":false,"in":"query","schema":{"type":"string","enum":["user","org"]}},{"name":"filter[subjectId]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"filter[key]","required":false,"in":"query","schema":{"type":"string","enum":["personal_puzzles_create","personal_drafts_max","personal_published_puzzles_max","orgs_owned_max","org_published_puzzles_max","org_members_max","org_devices_max","asset_storage_bytes","embeds_enabled","api_keys_enabled","api_calls_monthly_included","api_calls_metered","analytics_enabled","analytics_extended","analytics_raw_retention_days","analytics_aggregated_retention_months","support_tickets"]}},{"name":"filter[active]","required":false,"in":"query","description":"Only unexpired overrides.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntitlementOverridePageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]},"post":{"description":"The newest unexpired override of a key wins over the plan value. The subject must exist (404 `SUBJECT_NOT_FOUND`). Audited.","operationId":"AdminEntitlementOverridesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEntitlementOverrideDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntitlementOverrideResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SUBJECT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Grant an entitlement override","tags":["admin"]}},"/v1/admin/entitlement-overrides/{id}/revoke":{"post":{"operationId":"AdminEntitlementOverridesController_revoke","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReasonDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntitlementOverrideResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ENTITLEMENT_OVERRIDE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `OVERRIDE_ALREADY_EXPIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Revoke (expire now) an override; audited","tags":["admin"]}},"/v1/api-keys":{"post":{"description":"Returns the key once (`secret`); only its SHA-256 is stored. Use it as `Authorization: Bearer <key>` without cookies.","operationId":"ApiKeysController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyWithSecretResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`, `SCOPE_ESCALATION_DENIED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `API_KEYS_LIMIT`, `API_KEY_EXPIRY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Create an API key","tags":["api-keys"]},"get":{"operationId":"ApiKeysController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"ownerOrgId","required":false,"in":"query","description":"List this organization; omit for your personal workspace.","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["api-keys"]}},"/v1/api-keys/{id}":{"get":{"operationId":"ApiKeysController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `API_KEY_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["api-keys"]},"delete":{"operationId":"ApiKeysController_revoke","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Revoked."},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `API_KEY_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["api-keys"]}},"/v1/api-keys/{id}/rotate":{"post":{"description":"Issues a new key with the same name, scopes and expiry (shown once) acting as you; the old key is revoked, or keeps working for `overlapMinutes`.","operationId":"ApiKeysController_rotate","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RotateApiKeyDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyWithSecretResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`, `SCOPE_ESCALATION_DENIED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `API_KEY_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `API_KEY_NOT_ACTIVE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `API_KEYS_LIMIT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Rotate an API key","tags":["api-keys"]}},"/v1/webhook-endpoints":{"post":{"description":"Returns the signing secret once (`secret`); it is stored encrypted.\n\nEndpoints receive `POST` JSON bodies `{ id, type, version: \"1\", createdAt, workspace, data }` signed with `Puzzle-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, \"<t>.<raw body>\")>` (headers `Puzzle-Event-Id`, `Puzzle-Event-Type`, `Puzzle-Delivery-Id`), for the events they subscribe to in their own workspace. Retries: first attempt + 8 over ~21.6 h; deduplicate on `id`. Payloads carry ids and public publication settings only: never solutions, play states, comment bodies or who played or commented.\n\n| Event | Body schema | Sent when |\n|---|---|---|\n| `publication.published` | `PublicationPublishedWebhookDto` | A publication was published (it is playable unless moderation took it down). |\n| `publication.unpublished` | `PublicationUnpublishedWebhookDto` | A published publication stopped being published: unpublished by the workspace, or closed because its puzzle was deleted (`reason`). |\n| `publication.archived` | `PublicationArchivedWebhookDto` | A publication was archived (`wasPublished`: it was published until then). |\n| `completion.created` | `CompletionCreatedWebhookDto` | A player completed a publication (verified against the solution on the server). Anonymous: no player identity. Not sent for school students. |\n| `comment.created` | `CommentCreatedWebhookDto` | A comment or reply was posted on a publication. Ids only: read the comment through the API. |\n| `moderation.publication_taken_down` | `PublicationTakenDownWebhookDto` | Platform moderation took the publication down: it is no longer served until restored. |\n| `moderation.publication_restored` | `PublicationRestoredWebhookDto` | Platform moderation restored a publication it had taken down (`status` tells whether it is published). |","operationId":"WebhookEndpointsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookEndpointDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointWithSecretResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `WEBHOOK_URL_INVALID`, `WEBHOOK_ENDPOINTS_LIMIT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Error codes: `WEBHOOKS_NOT_CONFIGURED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Register a webhook endpoint","tags":["webhooks"]},"get":{"operationId":"WebhookEndpointsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"ownerOrgId","required":false,"in":"query","description":"List this organization; omit for your personal workspace.","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["webhooks"]}},"/v1/webhook-endpoints/{id}":{"get":{"operationId":"WebhookEndpointsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `WEBHOOK_ENDPOINT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["webhooks"]},"patch":{"description":"URL, subscriptions, description; `enabled: false|true` disables or re-enables it (re-enabling resets the failure count).","operationId":"WebhookEndpointsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookEndpointDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `WEBHOOK_ENDPOINT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `WEBHOOK_URL_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Update a webhook endpoint","tags":["webhooks"]},"delete":{"operationId":"WebhookEndpointsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted."},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `WEBHOOK_ENDPOINT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["webhooks"]}},"/v1/webhook-endpoints/{id}/rotate-secret":{"post":{"description":"Replaces the secret at once and returns the new one (once); later attempts are signed with it.","operationId":"WebhookEndpointsController_rotateSecret","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointWithSecretResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `WEBHOOK_ENDPOINT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Error codes: `WEBHOOKS_NOT_CONFIGURED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Rotate the signing secret","tags":["webhooks"]}},"/v1/webhook-endpoints/{id}/test":{"post":{"description":"Queues one `webhook.ping` delivery (a single attempt, no retries); follow it in the delivery log.","operationId":"WebhookEndpointsController_test","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponseDto"}}}},"400":{"description":"Error codes: `IDEMPOTENCY_KEY_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `WEBHOOK_ENDPOINT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `WEBHOOK_ENDPOINT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Error codes: `WEBHOOKS_NOT_CONFIGURED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Send a test event","tags":["webhooks"]}},"/v1/webhook-endpoints/{id}/deliveries":{"get":{"operationId":"WebhookEndpointsController_deliveriesOf","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[status]","required":false,"in":"query","schema":{"type":"string","enum":["pending","succeeded","failed"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `WEBHOOK_ENDPOINT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Delivery log of an endpoint (last 30 days)","tags":["webhooks"]}},"/v1/webhook-deliveries/{id}":{"get":{"operationId":"WebhookDeliveriesController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryDetailResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `WEBHOOK_DELIVERY_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"A delivery with its body and attempts","tags":["webhooks"]}},"/v1/webhook-deliveries/{id}/redeliver":{"post":{"description":"Queues one more attempt with the same event id and body (receivers deduplicate on `Puzzle-Event-Id`).","operationId":"WebhookDeliveriesController_redeliver","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponseDto"}}}},"400":{"description":"Error codes: `IDEMPOTENCY_KEY_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ENTITLEMENT_REQUIRED`, `ORGANIZATION_FROZEN`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `WEBHOOK_DELIVERY_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `WEBHOOK_DELIVERY_IN_PROGRESS`, `WEBHOOK_ENDPOINT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Error codes: `WEBHOOKS_NOT_CONFIGURED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Redeliver","tags":["webhooks"]}},"/v1/publications/{id}/comments":{"get":{"operationId":"PublicationCommentsController_list","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"sort","required":false,"in":"query","description":"Newest first (default) or oldest first.","schema":{"default":"-createdAt","type":"string","enum":["-createdAt","createdAt"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["comments"]},"post":{"operationId":"PublicationCommentsController_create","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `COMMENTS_DISABLED`, `COMMENTS_LOCKED`, `COMMENT_PARENT_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `COMMENT_RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["comments"]}},"/v1/comments/{id}":{"get":{"operationId":"CommentsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `COMMENT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["comments"]},"patch":{"operationId":"CommentsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCommentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `COMMENT_NOT_FOUND`, `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `COMMENT_EDIT_WINDOW_CLOSED`, `COMMENT_NOT_EDITABLE`, `COMMENTS_DISABLED`, `COMMENTS_LOCKED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["comments"]},"delete":{"operationId":"CommentsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `COMMENT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["comments"]}},"/v1/comments/{id}/replies":{"get":{"operationId":"CommentsController_replies","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplyPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `COMMENT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["comments"]}},"/v1/comments/{id}/hide":{"post":{"operationId":"CommentsController_hide","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HideCommentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `COMMENT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["comments"]}},"/v1/comments/{id}/restore":{"post":{"operationId":"CommentsController_restore","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `COMMENT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `COMMENT_HIDDEN_BY_STAFF`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["comments"]}},"/v1/notifications":{"get":{"description":"Types and their payloads:\n- `comment.reply` (community): Someone replied to your comment. Payload: `publicationId`, `commentId` (the reply), `parentCommentId`, `puzzleTitle`.\n- `comment.hidden` (moderation): A moderator of the publication (or platform staff) hid your comment. Payload: `publicationId`, `commentId`, `puzzleTitle`, `source` (`workspace`|`staff`).\n- `moderation.publication_taken_down` (moderation): Platform moderation took down a puzzle of yours (or of an organization you own) and its publication: it is no longer played, discussed, copied, published or listed. Payload: `publicationId` (null for puzzles without a publication), `puzzleId`, `puzzleTitle`, `violation` (a report reason, or null), `followedCopy` (true when it was taken down as a copy of other taken-down content), `ownerOrgId` (null for personal content).\n- `moderation.publication_restored` (moderation): Platform moderation restored a puzzle of yours (and its publication) that was taken down. Payload: `publicationId` (or null), `puzzleId`, `puzzleTitle`, `ownerOrgId`.\n- `moderation.warning` (moderation): Platform moderation warned you about your behaviour. Payload: `actionId`, `violation` (a report reason).\n- `moderation.banned` (moderation): You were banned (E13-T02): by the platform's moderators (`scope` `platform`: everything but reading your bans, your data rights and your notifications; `comments`, `ratings` or `publishing`: that feature everywhere) or by an organization (`scope` `org`: its workspace, membership and content). Never says who decided or who reported. Payload: `banId`, `scope`, `orgId` and `orgName` (org bans, else null), `violation` (a report reason), `expiresAt` (ISO date-time, null = permanent).\n- `moderation.ban_revoked` (moderation): A ban of yours was lifted before it expired. Payload: `banId`, `scope`, `orgId`, `orgName`.\n- `moderation.ban_expired` (moderation): A temporary ban of yours ended. Payload: `banId`, `scope`, `orgId`, `orgName`.\n- `moderation.appeal_submitted` (moderation): Your appeal was received (E13-T03). Payload: `appealId`, `kind` (`ban`|`takedown`|`comment_hide`|`warning`), `level` (`organization`: the organization that banned you reviews it first; `platform`: platform moderation), `banId` or `actionId` (the decision; the other is null), `orgId` and `orgName` (organization bans and organization content, else null).\n- `moderation.appeal_received` (moderation): Sent to an organization's owner: someone the organization banned appealed the ban, and the organization's admins (`organization:bans:manage`) review it first (E13-T03). Never the appellant's text. Payload: `appealId`, `banId`, `orgId`, `orgName`.\n- `moderation.appeal_accepted` (moderation): Your appeal was accepted and the decision reversed (the ban lifted, the content restored, the comment shown again; a warning is withdrawn). Never says who reviewed it; the answer is on the appeal (`GET /v1/users/me/appeals/:id`). Payload: `appealId`, `kind`, `level`, `banId`, `actionId`, `orgId`, `orgName`, `reversed` (false when the decision had already ended).\n- `moderation.appeal_rejected` (moderation): Your appeal was rejected; the decision stands. Never says who reviewed it; the answer is on the appeal. Payload: `appealId`, `kind`, `level`, `banId`, `actionId`, `orgId`, `orgName`, `escalatableUntil` (organization-level rejections: until when platform moderation can be asked to review it, ISO date-time; else null).\n- `moderation.report_closed` (moderation): A report you filed was closed. Never says what was done to whom. Payload: `reportId`, `targetType`, `status` (`resolved`|`dismissed`).\n- `organization.invitation` (organizations): You were invited to an organization (your verified address). Payload: `orgId`, `orgName`, `invitationId`.\n- `organization.ownership_transfer_offered` (organizations): An organization's owner offered you its ownership. Payload: `orgId`, `orgName`, `transferId`.\n- `organization.frozen` (organizations): An organization you belong to was frozen. Payload: `orgId`, `orgName`, `freezeDeadline`.\n- `support.ticket_status_changed` (support): Support moved your ticket to another status (also when it was closed automatically). Payload: `ticketId`, `status`.\n- `support.ticket_replied` (support): Support replied on your ticket (never internal notes; the reply itself is not in the payload). Payload: `ticketId`, `messageId`.\n- `integrations.webhook_endpoint_disabled` (account): A webhook endpoint you manage was disabled after repeated failed deliveries. Payload: `endpointId`, `ownerOrgId` (null for personal endpoints), `endpointLabel` (its description, else its host), `failedDeliveries`.\n- `analytics.export_ready` (account): An analytics export you requested is ready to download (E16-T04; the analytics module mails it too). Payload: `exportId`, `ownerOrgId` (null for your personal workspace), `report` (`overview`|`publications`|`publication`|`puzzle`|`series`), `format` (`csv`|`json`), `expiresAt` (ISO date-time).\n- `account.password_changed` (account): Your password was changed. Payload: none.","operationId":"NotificationsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[unread]","required":false,"in":"query","description":"Only unread notifications.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"List your notifications, newest first.","tags":["notifications"]}},"/v1/notifications/unread-count":{"get":{"operationId":"NotificationsController_unreadCount","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnreadCountResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["notifications"]}},"/v1/notifications/preferences":{"get":{"operationId":"NotificationsController_preferences","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["notifications"]},"patch":{"operationId":"NotificationsController_updatePreferences","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNotificationPreferencesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["notifications"]}},"/v1/notifications/read-all":{"post":{"operationId":"NotificationsController_markAllRead","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkAllReadResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["notifications"]}},"/v1/notifications/unsubscribe":{"post":{"operationId":"NotificationsController_unsubscribe","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnsubscribeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnsubscribeResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `UNSUBSCRIBE_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["notifications"]}},"/v1/notifications/{id}/read":{"post":{"operationId":"NotificationsController_markRead","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `NOTIFICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["notifications"]}},"/v1/reports":{"post":{"description":"Reports only what you can see (404 `REPORT_TARGET_NOT_FOUND` otherwise, whatever the type). One open report per target: repeating it answers 200 with the existing report (`created: false`). At most 5 reports a minute, 20 an hour and 50 a day (429 `REPORT_RATE_LIMITED`). The reported party never learns who reported them.","operationId":"ReportsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportDto"}}}},"responses":{"200":{"description":"You already had an open report on this target.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportResponseDto"}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `REPORT_TARGET_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `REPORT_TARGET_INVALID`, `REPORT_DETAILS_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `REPORT_RATE_LIMITED`, `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Report content or an account","tags":["reports"]}},"/v1/publications/{id}/ratings/summary":{"get":{"description":"Count, plain mean, Bayesian `weightedAverage` and distribution. Cached at the edge for 60 s (`public, s-maxage=60`) unless an `X-Embed-Token` is sent (embed-only publications that require tokens need one; then `private, no-store`).","operationId":"PublicationRatingsController_summary","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RatingSummaryResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"A publication's rating summary","tags":["ratings"]}},"/v1/publications/{id}/ratings/me":{"get":{"operationId":"PublicationRatingsController_mine","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MyRatingResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Your rating of a publication","tags":["ratings"]},"delete":{"description":"Idempotent: 204 whether or not you had rated it. Counts against the rating write limit (429 `RATING_RATE_LIMITED`).","operationId":"PublicationRatingsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATING_RATE_LIMITED`, `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Remove your rating","tags":["ratings"]}},"/v1/publications/{id}/ratings":{"post":{"description":"One rating per player and publication: 201 when created, 200 when changed or repeated. Only after starting the publication (422 `RATING_REQUIRES_PLAY`), never for your own workspace (422 `RATING_OWN_CONTENT`). At most 10 rating writes (sets, repeats and removals) a minute and 60 an hour (429 `RATING_RATE_LIMITED`).","operationId":"PublicationRatingsController_rate","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RatePublicationDto"}}}},"responses":{"200":{"description":"You had already rated this publication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RatingWriteResponseDto"}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RatingWriteResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `RATING_OWN_CONTENT`, `RATING_REQUIRES_PLAY`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATING_RATE_LIMITED`, `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Rate a publication (or change your rating)","tags":["ratings"]}},"/v1/profiles/{handle}":{"get":{"description":"`handle` is a username or an organization slug (a leading `@` is accepted). No query parameters (any is 400). At most 20 requests a minute per IP. Users: display name, avatar, public statistics, achieved achievements, best-players positions and newest public puzzles, only while their profile is public. Organizations (never schools, and only with at least one public puzzle): name, brand image and newest public puzzles. No emails or account data. Private, unknown, deleted and suspended handles are one 404.","operationId":"ProfilesController_profile","parameters":[{"name":"handle","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicProfileResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PROFILE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"A public profile","tags":["profiles"]}},"/v1/profiles/{handle}/puzzles":{"get":{"description":"Discoverable puzzles (public, published, not taken down, playable standalone) of the user or organization, newest first by default; listing cards only, never content. Unknown query parameters are 400; at most 20 requests a minute per IP.","operationId":"ProfilesController_puzzles","parameters":[{"name":"handle","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[gameType]","required":false,"in":"query","schema":{"example":"crossword","type":"string"}},{"name":"sort","required":false,"in":"query","schema":{"default":"-publishedAt","type":"string","enum":["-publishedAt","publishedAt","title"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilePuzzlesPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PROFILE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"A public profile's puzzles","tags":["profiles"]}},"/v1/play-sessions":{"post":{"description":"Pins the publication’s current version and mode and starts from the engine’s initial state. Casual sessions need `serverProgressEnabled` in the player’s settings (422 `SERVER_PROGRESS_DISABLED`: casual play then stays on the device). Private publications need `puzzle:read` (404 otherwise); taken-down ones are 410. Multiple attempts are allowed, at most 10 open (active or paused) per publication and mode. School students (`Authorization: Bearer ppst_…`, no cookies) start sessions on their class’s assignments only (anything else is 404; competitive publications only when the teacher assigned them as competitive); their progress is always kept on the server.","operationId":"PlaySessionsController_create","parameters":[{"name":"Idempotency-Key","in":"header","description":"Required; a retry with the same key returns the same session.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlaySessionDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaySessionResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `IDEMPOTENCY_KEY_REQUIRED`, `IDEMPOTENCY_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `TOO_MANY_OPEN_PLAY_SESSIONS`, `IDEMPOTENCY_KEY_IN_USE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Error codes: `PUBLICATION_REMOVED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `SERVER_PROGRESS_DISABLED`, `GAME_TYPE_UNAVAILABLE`, `IDEMPOTENCY_KEY_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Start a play session of a publication.","tags":["play-sessions"]}},"/v1/play-sessions/{id}":{"get":{"description":"The `ETag` is the session’s `revision` (the `If-Match` / `baseRevision` of the next progress sync).","operationId":"PlaySessionsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaySessionResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PLAY_SESSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Read one of your play sessions.","tags":["play-sessions"]}},"/v1/play-sessions/{id}/progress":{"put":{"description":"Optimistic concurrency on the session’s `revision` (`baseRevision` or `If-Match`; one is required, 428): a stale base is 409 `PLAY_SESSION_REVISION_CONFLICT` with the server copy in `details.session` and `details.revision`; let the player choose a copy and resend with `baseRevision = details.revision`. Re-sending the last applied `clientMutationId` returns the session unchanged. The state is validated by the engine (`PLAY_STATE_INVALID`, `PLAY_STATE_MAJOR_UNSUPPORTED`). When the publication moved to a newer minor version the server migrates the state (`migrated: true`, new `versionId`). `revealsUsed`, `hintsUsed` and `assisted` never go down. Competitive states must be for the session’s `versionId` (409 `PLAY_SESSION_VERSION_MISMATCH`; only the server migrates them). Casual sessions need `serverProgressEnabled`. The response `ETag` is the new revision.","operationId":"PlaySessionsController_progress","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"If-Match","in":"header","description":"Alternative to `baseRevision`: the session’s ETag (`\"<revision>\"`).","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Required; a retry with the same key returns the same result.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncProgressDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaySessionSyncResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `IDEMPOTENCY_KEY_REQUIRED`, `IDEMPOTENCY_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PLAY_SESSION_NOT_FOUND`, `PUBLICATION_NOT_FOUND`, `PUZZLE_VERSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PLAY_SESSION_REVISION_CONFLICT`, `PLAY_SESSION_ENDED`, `PLAY_SESSION_VERSION_MISMATCH`, `IDEMPOTENCY_KEY_IN_USE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Error codes: `PUBLICATION_REMOVED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"412":{"description":"Error codes: `PRECONDITION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `PLAY_STATE_INVALID`, `PLAY_STATE_MAJOR_UNSUPPORTED`, `GAME_TYPE_UNAVAILABLE`, `SERVER_PROGRESS_DISABLED`, `IDEMPOTENCY_KEY_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"428":{"description":"Error codes: `PRECONDITION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Save the progress of an open play session.","tags":["play-sessions"]}},"/v1/play-sessions/{id}/complete":{"post":{"description":"The server checks the state with the engine against the stored solution (422 `COMPLETION_NOT_SOLVED`: nothing recorded). Casual completions are never verified (`verificationNote: casual`) and a wrong casual state leaves the session open; when the caller’s payload has no checks, every attempt is a server probe: refused before the state is evaluated past the casual check budgets (409 `CHECK_LIMIT_REACHED`, `details { limit, scope: session|daily, retryAfterSeconds? }`, solved or not) and throttled to one per session every 3 s and 30 a minute per client IP (429 `PLAY_RATE_LIMITED`); a wrong state counts one check (`details.checksRemaining`, `sessionEnded: false`). Competitive ones use the session’s `versionId` (409 `PLAY_SESSION_VERSION_MISMATCH` for another), are timed by the server (start of the session to now, no pauses) and verified unless the publication changed mode, answers were revealed, it is not the player’s first attempt at the publication (`repeat_attempt`: any other competitive session of theirs on it, earlier or later, that was completed, saved progress, or was checked or failed a completion, also once deleted), more than 24 h passed or the time is below the game’s plausible minimum (`verificationNote`). A wrong competitive state uses one of the player’s 3 checks on the publication, shared by all their sessions of it (`details.checksRemaining`); with none left the session is abandoned (`details.sessionEnded`, `endedReason: too_many_attempts`). At most 10 checks and completions per minute per player and session (429 `PLAY_RATE_LIMITED`, `details.retryAfterSeconds`). A completed session answers its completion again. With `serverProgressEnabled` off a casual completion is still recorded, but the session keeps no final state (`state: null`).","operationId":"PlaySessionsController_complete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Required; a retry with the same key returns the same completion.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletePlaySessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletionResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `IDEMPOTENCY_KEY_REQUIRED`, `IDEMPOTENCY_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PLAY_SESSION_NOT_FOUND`, `PUBLICATION_NOT_FOUND`, `PUZZLE_VERSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PLAY_SESSION_ENDED`, `PLAY_SESSION_VERSION_MISMATCH`, `CLIENT_COMPLETION_ID_CONFLICT`, `IDEMPOTENCY_KEY_IN_USE`, `CHECK_LIMIT_REACHED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Error codes: `PUBLICATION_REMOVED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `PLAY_STATE_INVALID`, `PLAY_STATE_MAJOR_UNSUPPORTED`, `GAME_TYPE_UNAVAILABLE`, `COMPLETION_NOT_SOLVED`, `IDEMPOTENCY_KEY_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `PLAY_RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Complete an open play session with its final state.","tags":["play-sessions"]}},"/v1/play-sessions/{id}/check":{"post":{"description":"Answers only whether the state solves the puzzle (`solved`), never which entries are wrong. **Competitive** (payloads carry no checks): each check uses one of the player’s 3 on the publication, shared by all their competitive sessions of it and kept when sessions are deleted (`checksRemaining`; failed completions use them too); then 409 `CHECK_LIMIT_REACHED` on every session of the publication. Probing another session also makes this one a repeat attempt (never verified). The state must be for the session’s `versionId` (409 `PLAY_SESSION_VERSION_MISMATCH`). Throttled like completions (429 `PLAY_RATE_LIMITED`). **Casual**: only when the caller’s payload has no checks (`protection: null`: private publications played by grantees, school students or members without `puzzle:read-solution`); with checks the runtime checks locally (422 `CHECKS_AVAILABLE_LOCALLY`, nothing counted). Bounded before the state is evaluated (no refusal depends on the answer): 50 per session (`checksRemaining`; failed completions of such sessions count too, never ending it), then 409 `CHECK_LIMIT_REACHED` with `details { limit: 50, scope: session }` (start a new session); 100 per player and publication over the casual sessions started in the last 24 h, then 409 `CHECK_LIMIT_REACHED` with `details { limit: 100, scope: daily, retryAfterSeconds }`; one per session every 3 s, 10 a minute per player and session, and 30 a minute per client IP (429 `PLAY_RATE_LIMITED`, `details.retryAfterSeconds`). When `solved` is true, complete the session with `POST …/complete` (the server checks the state again). The state defaults to the session’s `versionId`; casual sessions may send a newer minor.","operationId":"PlaySessionsController_check","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckPlaySessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckPlaySessionResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PLAY_SESSION_NOT_FOUND`, `PUBLICATION_NOT_FOUND`, `PUZZLE_VERSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PLAY_SESSION_ENDED`, `CHECK_LIMIT_REACHED`, `PLAY_SESSION_VERSION_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Error codes: `PUBLICATION_REMOVED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `PLAY_STATE_INVALID`, `PLAY_STATE_MAJOR_UNSUPPORTED`, `GAME_TYPE_UNAVAILABLE`, `CHECKS_AVAILABLE_LOCALLY`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `PLAY_RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Check a session’s grid on the server (competitive, or casual without checks).","tags":["play-sessions"]}},"/v1/play-sessions/{id}/pause":{"post":{"operationId":"PlaySessionsController_pause","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaySessionResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PLAY_SESSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PLAY_SESSION_INVALID_TRANSITION`, `PLAY_SESSION_NOT_PAUSABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `SERVER_PROGRESS_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["play-sessions"]}},"/v1/play-sessions/{id}/resume":{"post":{"operationId":"PlaySessionsController_resume","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaySessionResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PLAY_SESSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PLAY_SESSION_INVALID_TRANSITION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `SERVER_PROGRESS_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["play-sessions"]}},"/v1/play-sessions/{id}/abandon":{"post":{"operationId":"PlaySessionsController_abandon","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaySessionResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PLAY_SESSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PLAY_SESSION_INVALID_TRANSITION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `SERVER_PROGRESS_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["play-sessions"]}},"/v1/device/publications/{id}/check":{"post":{"description":"For publications the device plays without checks (private ones): whether the state solves the version (`solved`), never which entries are wrong; each check is logged as a probe (no state). Publications the device may not play are 404 like the play pointer; taken down 410. Competitive publications need a play session, which devices don’t have (422 `COMPETITIVE_REQUIRES_SESSION`); payloads with checks are checked on the device (422 `CHECKS_AVAILABLE_LOCALLY`). At most 100 checks per device and publication in 24 h, refused before the state is compared (409 `CHECK_LIMIT_REACHED`, `details { limit: 100, scope: daily, retryAfterSeconds }`). Throttled (429 `PLAY_RATE_LIMITED`, `details.retryAfterSeconds`): one check per device and publication every 3 s, 60 per hour, and 30 a minute per client IP.","operationId":"DeviceSolvedCheckController_check","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceSolvedCheckDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceSolvedCheckResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `CONFLICTING_CREDENTIALS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `DEVICE_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`, `PUZZLE_VERSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `CHECK_LIMIT_REACHED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Error codes: `PUBLICATION_REMOVED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `PLAY_STATE_INVALID`, `PLAY_STATE_MAJOR_UNSUPPORTED`, `GAME_TYPE_UNAVAILABLE`, `COMPETITIVE_REQUIRES_SESSION`, `CHECKS_AVAILABLE_LOCALLY`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `PLAY_RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Check a device’s grid on the server (casual, without checks).","tags":["device-auth"]}},"/v1/completions":{"post":{"description":"Idempotent per player on `clientCompletionId` (a known one answers 200 with the stored completion; the same id for another publication is 409 `CLIENT_COMPLETION_ID_CONFLICT`). The final state is checked by the engine against the solution of `versionId` (422 `COMPLETION_NOT_SOLVED`); unknown versions or versions of a retired major line are 404 `PUZZLE_VERSION_NOT_FOUND`. Completes the open session named by `playSessionId`, else records a new completed session. Device times must be plausible (422 `COMPLETION_TIME_IMPLAUSIBLE`, checked before the state is compared). When the caller’s payload has no checks (private publications played without `puzzle:read-solution`, students), every upload is a server probe like `POST /v1/play-sessions/:id/check`: refused before the state is compared past the casual check budgets (409 `CHECK_LIMIT_REACHED`, `details { limit, scope: session|daily, retryAfterSeconds? }`: 50 per named session, 100 per player and publication in 24 h, solved or not), throttled to one every 3 s per session (or per player and publication without one) and 30 a minute per client IP (429 `PLAY_RATE_LIMITED`); a wrong state is logged as a probe (`details.checksRemaining` when it named a session). Always unverified (`verificationNote: offline`). Competitive publications and sessions are refused before the state is checked (422 `COMPETITIVE_REQUIRES_SESSION`): complete them online with `POST /v1/play-sessions/:id/complete`. Accepted whatever `serverProgressEnabled` says (FR-PLAY-07); with it off, the session recorded for the completion keeps no game state (`state: null`). New uploads are limited to 10 a minute per player and 3 a minute per player and publication (429 `PLAY_RATE_LIMITED`, `details.retryAfterSeconds`); replays of a known `clientCompletionId` don't count. School students must name one of their own open sessions in `playSessionId` (422 `PLAY_SESSION_REQUIRED` without one; 409 `PLAY_SESSION_ENDED` once it was abandoned: start a new session).","operationId":"CompletionsController_upload","parameters":[{"name":"Idempotency-Key","in":"header","description":"Required; a retry with the same key returns the same result.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadCompletionDto"}}}},"responses":{"200":{"description":"Already recorded (same `clientCompletionId`, or the session was completed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletionResponseDto"}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletionResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `IDEMPOTENCY_KEY_REQUIRED`, `IDEMPOTENCY_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PLAY_SESSION_NOT_FOUND`, `PUBLICATION_NOT_FOUND`, `PUZZLE_VERSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `CLIENT_COMPLETION_ID_CONFLICT`, `PLAY_SESSION_ENDED`, `IDEMPOTENCY_KEY_IN_USE`, `CHECK_LIMIT_REACHED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Error codes: `PUBLICATION_REMOVED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `PLAY_STATE_INVALID`, `PLAY_STATE_MAJOR_UNSUPPORTED`, `GAME_TYPE_UNAVAILABLE`, `COMPLETION_NOT_SOLVED`, `COMPLETION_TIME_IMPLAUSIBLE`, `COMPETITIVE_REQUIRES_SESSION`, `PLAY_SESSION_MISMATCH`, `PLAY_SESSION_REQUIRED`, `IDEMPOTENCY_KEY_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `PLAY_RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Upload a completion made offline.","tags":["completions"]}},"/v1/publications/{id}/reveal":{"post":{"description":"Returns only the requested positions’ answers (a cell or an entry, never every answer at once) and, for cryptic crosswords, the annotations of clues this request revealed completely. Online only. Refused with 403 `REVEAL_DISABLED` (`details.reason`: `competitive`, or `disabled` when the pointer’s `settings.reveal.enabled` is false). With `playSessionId` the signed-in player’s open casual session counts one reveal and becomes `assisted` (FR-PLAY-06). Every reveal by a signed-in player is also logged for the publication (with or without a session, kept when progress is deleted), and such players never appear on its casual leaderboards.","operationId":"RevealController_reveal","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Embed-Parent-Origin","in":"header","description":"Optional. The parent page origin the play host observed; when sent it must equal the token’s origin (403 `EMBED_ORIGIN_MISMATCH`).","required":false,"schema":{"type":"string"}},{"name":"X-Embed-Token","in":"header","description":"Embedded play (E09-T05): the embed token, checked exactly like the play pointer (an embed-only publication requiring tokens needs it; it also opens private publications, without reveal since they carry no checks). Expired: 401 `EMBED_TOKEN_EXPIRED` with `details: { origin }`.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevealRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevealResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `EMBED_TOKEN_EXPIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `REVEAL_DISABLED`, `ACCOUNT_DISABLED`, `IMPERSONATION_FORBIDDEN`, `FORBIDDEN`, `EMBED_TOKEN_REQUIRED`, `EMBED_TOKEN_INVALID`, `EMBED_ORIGIN_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`, `PUZZLE_VERSION_NOT_FOUND`, `PLAY_SESSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `PLAY_SESSION_ENDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Error codes: `PUBLICATION_REMOVED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `REVEAL_POSITIONS_INVALID`, `REVEAL_UNSUPPORTED`, `PLAY_SESSION_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Reveal the answers of some positions (casual play only).","tags":["play"]}},"/v1/players/me/sessions":{"get":{"description":"Newest first by default. `filter[status]=open` lists saved games to resume (active or paused). `publicationIds` (comma-separated, at most 100) answers the offline sync prompt (architecture §12.3): the server copies of the device’s local games, to compare `revision`/`updatedAt` with the device copies. Entries carry no engine state: read `GET /v1/play-sessions/:id` for it. Sessions of other players never appear.","operationId":"PlayerHistoryController_sessionsList","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"publicationIds","required":false,"in":"query","description":"Comma-separated publication ids (at most 100): only sessions of these publications. The offline sync prompt sends the publications of its local games (architecture §12.3).","schema":{"example":"0192f0a0-0000-7000-8000-000000000001,0192f0a0-0000-7000-8000-000000000002","type":"string"}},{"name":"filter[status]","required":false,"in":"query","description":"`open` = active or paused (saved games to resume).","schema":{"type":"string","enum":["active","paused","completed","abandoned","open"]}},{"name":"filter[mode]","required":false,"in":"query","schema":{"type":"string","enum":["casual","competitive"]}},{"name":"sort","required":false,"in":"query","description":"By start (creation) time: newest first (default) or oldest first.","schema":{"default":"-createdAt","type":"string","enum":["-createdAt","createdAt"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayerSessionPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"List your play sessions (saved games and history).","tags":["players"]}},"/v1/players/me/completions":{"get":{"description":"Every completion you made (casual, offline and competitive; unverified ones included, FR-PLAY-07), newest first by default, filterable by game type, mode, verification and publication. Never a state or a solution.","operationId":"PlayerHistoryController_completionsList","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[gameType]","required":false,"in":"query","description":"A game type (`GET /v1/games`), e.g. `sudoku`.","schema":{"type":"string"}},{"name":"filter[mode]","required":false,"in":"query","schema":{"type":"string","enum":["casual","competitive"]}},{"name":"filter[verified]","required":false,"in":"query","description":"Only verified (or only unverified) completions.","schema":{"type":"boolean"}},{"name":"filter[publicationId]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"sort","required":false,"in":"query","description":"By the time the server recorded it: newest first (default) or oldest first.","schema":{"default":"-createdAt","type":"string","enum":["-createdAt","createdAt"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayerCompletionPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"List your completions.","tags":["players"]}},"/v1/players/me/statistics":{"get":{"description":"Session counts, completion counts, daily streaks and, per game type, completions, average and best times (without revealed answers) and the best verified time. Streak days are calendar days in `timeZone` (IANA name, default UTC); a streak stays current until a whole day passes without a completion.","operationId":"PlayerHistoryController_statisticsOf","parameters":[{"name":"timeZone","required":false,"in":"query","description":"IANA time zone the streak days are counted in (the player’s local calendar); default UTC. Offsets such as `+01:00` are refused.","schema":{"default":"UTC","example":"Europe/Madrid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayerStatisticsResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Your play statistics.","tags":["players"]}},"/v1/players/me/achievements":{"get":{"description":"Every achievement of the catalog (E12-T06) with your progress, computed from your statistics (streak days in UTC), whether or not your profile is public. Others see the achieved ones on your public profile (`GET /v1/profiles/:handle`) while `profilePublic` is on.","operationId":"PlayerHistoryController_achievementsOf","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayerAchievementsResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Your achievements.","tags":["players"]}},"/v1/players/me/progress":{"delete":{"description":"Deletes every unfinished casual session (active, paused, abandoned) with its stored game state (FR-PRIV-02; e.g. after turning `serverProgressEnabled` off). Completed sessions and completions stay (your history), and so do competitive attempts (server-timed and verified). Idempotent. Allowed while banned (it only removes your data); refused while impersonating. Turning `serverProgressEnabled` off does the same automatically.","operationId":"PlayerHistoryController_deleteProgress","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerProgressDeletionResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Delete your server progress.","tags":["players"]}},"/v1/rankings/puzzles":{"get":{"description":"Most played, trending, top rated and most commented discoverable puzzles (public, published, not taken down, not a school’s), with their listing card (no content). Recomputed hourly; `public, max-age=0, s-maxage=60`.","operationId":"RankingsController_puzzles","parameters":[{"name":"list","required":true,"in":"query","description":"`most_played` (distinct signed-in players from server-side sessions and completions; weekly, monthly), `trending` (weekly), `top_rated` (Bayesian average, all time), `most_commented` (weekly, monthly).","schema":{"type":"string","enum":["most_played","trending","top_rated","most_commented"]}},{"name":"window","required":false,"in":"query","description":"Rolling window ending with the last closed UTC day. Default: the list’s first window (`weekly`; `all_time` for `top_rated`). A window the list doesn’t have is 400 `VALIDATION_FAILED`.","schema":{"type":"string","enum":["weekly","monthly","all_time"]}},{"name":"filter[gameType]","required":false,"in":"query","schema":{"example":"crossword","type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LandingRankingResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Landing rankings of public puzzles","tags":["rankings"]}},"/v1/rankings/players":{"get":{"description":"Casual results: client-timed, **unverified** (label them so): online casual completions without hints, reveals or assists, a player's best per publication. Best players of discoverable publications (never schools’), per game type (`filter[gameType]`) or every type, by results counted, then the game’s scoring over the sums. Entries show username, display name and avatar only. Public and the same for every caller: `public, max-age=0, s-maxage=60`; boards are rebuilt hourly.","operationId":"RankingsController_casualPlayers","parameters":[{"name":"window","required":false,"in":"query","description":"UTC periods: a day, an ISO week (Monday), a calendar month, or all time.","schema":{"default":"all_time","type":"string","enum":["daily","weekly","monthly","all_time"]}},{"name":"periodStart","required":false,"in":"query","description":"First UTC day of the period (`YYYY-MM-DD`): the day, the Monday, the first of the month; `1970-01-01` for all time. Default: the current period. Days that start no period, or future ones, are 400 `VALIDATION_FAILED`. Closed periods are kept 31 (daily), 92 (weekly) and 400 (monthly) days.","schema":{"example":"2026-10-19","type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":100,"type":"number"}},{"name":"filter[gameType]","required":false,"in":"query","description":"One game type; omit for every type (ranked by completions).","schema":{"example":"sudoku","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaderboardResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `LEADERBOARD_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Best players (casual, unverified)","tags":["rankings"]}},"/v1/rankings/players/competitive":{"get":{"description":"Verified competitive results only: each player's server-timed first attempt per publication. Best players of discoverable publications (never schools’), per game type (`filter[gameType]`) or every type, by results counted, then the game’s scoring over the sums. Entries show username, display name and avatar only. Public and the same for every caller: `public, max-age=0, s-maxage=60`; boards are rebuilt hourly.","operationId":"RankingsController_competitivePlayers","parameters":[{"name":"window","required":false,"in":"query","description":"UTC periods: a day, an ISO week (Monday), a calendar month, or all time.","schema":{"default":"all_time","type":"string","enum":["daily","weekly","monthly","all_time"]}},{"name":"periodStart","required":false,"in":"query","description":"First UTC day of the period (`YYYY-MM-DD`): the day, the Monday, the first of the month; `1970-01-01` for all time. Default: the current period. Days that start no period, or future ones, are 400 `VALIDATION_FAILED`. Closed periods are kept 31 (daily), 92 (weekly) and 400 (monthly) days.","schema":{"example":"2026-10-19","type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":100,"type":"number"}},{"name":"filter[gameType]","required":false,"in":"query","description":"One game type; omit for every type (ranked by completions).","schema":{"example":"sudoku","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaderboardResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `LEADERBOARD_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Best players (competitive, verified)","tags":["rankings"]}},"/v1/rankings/publications/{id}":{"get":{"description":"Only for live, published, public or unlisted publications that aren’t taken down or owned by a school; private ones never have a public board. Embed-only publications that require tokens need their `X-Embed-Token` (then `private, no-store`); otherwise `public, max-age=0, s-maxage=60` (`Vary: x-embed-token`). Default kind: the publication’s play mode. Everything else is 404 `LEADERBOARD_NOT_FOUND`.","operationId":"RankingsController_publication","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"window","required":false,"in":"query","description":"UTC periods: a day, an ISO week (Monday), a calendar month, or all time.","schema":{"default":"all_time","type":"string","enum":["daily","weekly","monthly","all_time"]}},{"name":"periodStart","required":false,"in":"query","description":"First UTC day of the period (`YYYY-MM-DD`): the day, the Monday, the first of the month; `1970-01-01` for all time. Default: the current period. Days that start no period, or future ones, are 400 `VALIDATION_FAILED`. Closed periods are kept 31 (daily), 92 (weekly) and 400 (monthly) days.","schema":{"example":"2026-10-19","type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":100,"type":"number"}},{"name":"kind","required":false,"in":"query","description":"`competitive`: verified first attempts (server-timed). `casual`: unverified best times without hints, reveals or assists; label them. Default: the publication’s play mode (publications), `competitive` (series).","schema":{"type":"string","enum":["competitive","casual"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaderboardResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `LEADERBOARD_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"A publication's leaderboard","tags":["rankings"]}},"/v1/rankings/series/{id}":{"get":{"description":"Results on the series’ public and unlisted editions, by results counted, with the series title (`seriesTitle`). Only for series whose owner is live (an active user, or an organization neither disabled, deleted nor a school) with at least one public, playable edition; else 404 `LEADERBOARD_NOT_FOUND`. Default kind `competitive`. `public, max-age=0, s-maxage=60`.","operationId":"RankingsController_series","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"window","required":false,"in":"query","description":"UTC periods: a day, an ISO week (Monday), a calendar month, or all time.","schema":{"default":"all_time","type":"string","enum":["daily","weekly","monthly","all_time"]}},{"name":"periodStart","required":false,"in":"query","description":"First UTC day of the period (`YYYY-MM-DD`): the day, the Monday, the first of the month; `1970-01-01` for all time. Default: the current period. Days that start no period, or future ones, are 400 `VALIDATION_FAILED`. Closed periods are kept 31 (daily), 92 (weekly) and 400 (monthly) days.","schema":{"example":"2026-10-19","type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":100,"type":"number"}},{"name":"kind","required":false,"in":"query","description":"`competitive`: verified first attempts (server-timed). `casual`: unverified best times without hints, reveals or assists; label them. Default: the publication’s play mode (publications), `competitive` (series).","schema":{"type":"string","enum":["competitive","casual"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaderboardResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `LEADERBOARD_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"A series' leaderboard","tags":["rankings"]}},"/v1/rankings/me":{"get":{"description":"Your row on one board period (`board` = a board key), with the board’s own rules: the board must be one you may see (token-only embeds need `X-Embed-Token`), and `entry` is null when you aren’t in the stored top 100 or wouldn’t be shown (leaderboard visibility off, banned). Signed-in users only; students, devices and API keys are refused.","operationId":"RankingsController_mine","parameters":[{"name":"window","required":false,"in":"query","description":"UTC periods: a day, an ISO week (Monday), a calendar month, or all time.","schema":{"default":"all_time","type":"string","enum":["daily","weekly","monthly","all_time"]}},{"name":"periodStart","required":false,"in":"query","description":"First UTC day of the period (`YYYY-MM-DD`): the day, the Monday, the first of the month; `1970-01-01` for all time. Default: the current period. Days that start no period, or future ones, are 400 `VALIDATION_FAILED`. Closed periods are kept 31 (daily), 92 (weekly) and 400 (monthly) days.","schema":{"example":"2026-10-19","type":"string"}},{"name":"board","required":true,"in":"query","description":"Board key: `publication:<id>:<kind>`, `series:<id>:<kind>`, `players:<gameType>:<kind>` or `players:all:<kind>`, kind `competitive` or `casual` (the `board` of a board response).","schema":{"example":"publication:0192f1c4-0000-7000-8000-000000000000:competitive","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MyRankingResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `LEADERBOARD_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Your place on a leaderboard","tags":["rankings"]}},"/v1/moderation/queue":{"get":{"operationId":"ModerationQueueController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[status]","required":false,"in":"query","description":"`open`: targets with open reports (dates, keys and reasons count the open ones); `closed`: targets whose reports are all closed; `all`.","schema":{"default":"open","type":"string","enum":["open","closed","all"]}},{"name":"filter[targetType]","required":false,"in":"query","schema":{"type":"string","enum":["comment","publication","puzzle","user","org"]}},{"name":"filter[reason]","required":false,"in":"query","schema":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"]}},{"name":"filter[subjectUser]","required":false,"in":"query","description":"Reports about this user or their content.","schema":{"format":"uuid","type":"string"}},{"name":"filter[subjectOrg]","required":false,"in":"query","description":"Reports about this organization or its content.","schema":{"format":"uuid","type":"string"}},{"name":"sort","required":false,"in":"query","description":"`oldest`: the longest-waiting first; `newest`: the latest report first; `-openReports`: most open reports first.","schema":{"default":"oldest","type":"string","enum":["oldest","newest","-openReports"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModerationQueuePageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The moderation queue: reports grouped by target","tags":["moderation"]}},"/v1/moderation/targets/{targetType}/{targetId}":{"get":{"operationId":"ModerationQueueController_target","parameters":[{"name":"targetType","required":true,"in":"path","schema":{"enum":["comment","publication","puzzle","user","org"],"type":"string"}},{"name":"targetId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModerationTargetDetailResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"A reported target: what it is now, its reports and history","tags":["moderation"]}},"/v1/moderation/reports":{"get":{"operationId":"ModerationQueueController_reportList","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[targetType]","required":false,"in":"query","schema":{"type":"string","enum":["comment","publication","puzzle","user","org"]}},{"name":"filter[targetId]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"filter[status]","required":false,"in":"query","schema":{"type":"string","enum":["open","resolved","dismissed"]}},{"name":"filter[reason]","required":false,"in":"query","schema":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"]}},{"name":"filter[reporter]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffReportPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Reports, newest first (with their reporters)","tags":["moderation"]}},"/v1/moderation/actions":{"get":{"operationId":"ModerationQueueController_actions","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[action]","required":false,"in":"query","schema":{"type":"string","enum":["comment.hide","comment.restore","publication.take_down","publication.restore","puzzle.take_down","puzzle.restore","report.resolve","report.dismiss","user.warn","ban.create","ban.revoke","appeal.accept","appeal.reject"]}},{"name":"filter[targetType]","required":false,"in":"query","schema":{"type":"string","enum":["comment","publication","puzzle","user","org","ban","appeal"]}},{"name":"filter[targetId]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"filter[actor]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"filter[subjectUser]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"filter[subjectOrg]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"filter[report]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModerationActionPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The moderation history, newest first","tags":["moderation"]}},"/v1/moderation/reports/{id}/resolve":{"post":{"description":"Closes the report and, unless `onlyThisReport`, every open report on its target. Reporters are notified (`moderation.report_closed`); the reported party never learns who reported.","operationId":"ModerationQueueController_resolve","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloseReportRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModerationActionResultResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `REPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `REPORT_NOT_OPEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Resolve a report without acting on the content","tags":["moderation"]}},"/v1/moderation/reports/{id}/dismiss":{"post":{"description":"Like resolve, with status `dismissed`: closes the report and, unless `onlyThisReport`, every open report on its target.","operationId":"ModerationQueueController_dismiss","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloseReportRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModerationActionResultResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `REPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `REPORT_NOT_OPEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Dismiss a report (no violation found)","tags":["moderation"]}},"/v1/moderation/comments/{id}/hide":{"post":{"description":"The author is notified (`comment.hidden`, `source: 'staff'`, never who); the publication's own moderators can't restore it (a workspace hide is taken over). Resolves the open reports on the comment.","operationId":"ModerationContentController_hideComment","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModerationActionRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentActionResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `COMMENT_NOT_FOUND`, `REPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Hide a comment (platform moderation)","tags":["moderation"]}},"/v1/moderation/comments/{id}/restore":{"post":{"description":"Restores hides by staff or by the workspace.","operationId":"ModerationContentController_restoreComment","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModerationActionRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentActionResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `COMMENT_NOT_FOUND`, `REPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Restore a hidden comment","tags":["moderation"]}},"/v1/moderation/publications/{id}/copies":{"get":{"operationId":"ModerationContentController_copies","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PuzzleCopiesResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The puzzle's copies, to offer following them in a takedown","tags":["moderation"]}},"/v1/moderation/publications/{id}/takedown":{"post":{"description":"Takedowns act on the puzzle (`takenDownAt`, also for never-published puzzles) and its live publication: it is no longer played (410 `PUBLICATION_REMOVED`), discussed, rated, embedded, listed, resolved, copied (clone, export, edition source: 409 `PUZZLE_TAKEN_DOWN`) or published (422), until restored. Owners still see it in Studio. The owner is notified (`moderation.publication_taken_down`); open reports on the publication and its puzzle (and on `reportId`'s target) are resolved and their reporters notified. Never on your own content or your organization's (422 `MODERATION_SELF_ACTION`). Edge caches: a purge of the affected URLs is queued; until the owner configures the Cloudflare purge, cached copies expire on their own (pointers, URL resolution, rating summaries and search within 60 s, payloads within 1 h, 5 min in browsers). `includeCopies` also takes down every copy of the puzzle, with or without a publication (each owner notified). Repeating it changes nothing (`changed: false`, no action).","operationId":"ModerationContentController_takeDownPublication","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TakedownRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TakedownResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`, `REPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Take down a publication","tags":["moderation"]}},"/v1/moderation/publications/{id}/restore":{"post":{"description":"Restores the puzzle and its publication; its status is kept (a published one is playable again at once). The owner is notified (`moderation.publication_restored`). `includeCopies` restores the copies the puzzle's current takedown followed.","operationId":"ModerationContentController_restorePublication","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TakedownRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TakedownResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`, `REPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Restore a taken-down publication","tags":["moderation"]}},"/v1/moderation/puzzles/{id}/takedown":{"post":{"description":"Takedowns act on the puzzle (`takenDownAt`, also for never-published puzzles) and its live publication: it is no longer played (410 `PUBLICATION_REMOVED`), discussed, rated, embedded, listed, resolved, copied (clone, export, edition source: 409 `PUZZLE_TAKEN_DOWN`) or published (422), until restored. Owners still see it in Studio. The owner is notified (`moderation.publication_taken_down`); open reports on the publication and its puzzle (and on `reportId`'s target) are resolved and their reporters notified. Never on your own content or your organization's (422 `MODERATION_SELF_ACTION`). Edge caches: a purge of the affected URLs is queued; until the owner configures the Cloudflare purge, cached copies expire on their own (pointers, URL resolution, rating summaries and search within 60 s, payloads within 1 h, 5 min in browsers). `includeCopies` also takes down every copy of the puzzle, with or without a publication (each owner notified). Repeating it changes nothing (`changed: false`, no action).","operationId":"ModerationContentController_takeDownPuzzle","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TakedownRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TakedownResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`, `REPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Take down a puzzle (and its live publication)","tags":["moderation"]}},"/v1/moderation/puzzles/{id}/restore":{"post":{"operationId":"ModerationContentController_restorePuzzle","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TakedownRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TakedownResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`, `REPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Restore a taken-down puzzle (and its live publication)","tags":["moderation"]}},"/v1/moderation/users/{id}/warn":{"post":{"description":"Notifies the user (`moderation.warning` with the `violation`, never who decided or who reported). Resolves the open reports on the user (and on `reportId`'s target).","operationId":"ModerationUsersController_warn","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WarnUserRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModerationActionResultResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `USER_NOT_FOUND`, `REPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Warn a user","tags":["moderation"]}},"/v1/moderation/users/{id}/bans":{"post":{"description":"Takes effect at once on every request (`USER_BANNED`). A `platform` ban also signs the user out everywhere; they can sign in again but only read their bans (`GET /v1/users/me/bans`), exercise their data rights (exports, account deletion, consent) and manage their notifications. Notifies the user (`moderation.banned`: scope, violation, expiry; never who decided or reported) and resolves the open reports on the user (and on `reportId`'s target).","operationId":"ModerationBansController_ban","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlatformBanRequestDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformBanResultResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `USER_NOT_FOUND`, `REPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `BAN_ALREADY_ACTIVE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`, `BAN_TARGET_PROTECTED`, `BAN_EXPIRY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Ban a user (platform-wide or from one feature)","tags":["moderation"]}},"/v1/moderation/bans":{"get":{"operationId":"ModerationBansController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[status]","required":false,"in":"query","schema":{"default":"all","type":"string","enum":["active","ended","all"]}},{"name":"filter[user]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"filter[scope]","required":false,"in":"query","schema":{"type":"string","enum":["platform","comments","ratings","publishing","org"]}},{"name":"filter[org]","required":false,"in":"query","description":"One organization's bans.","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BanPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Every ban, newest first","tags":["moderation"]}},"/v1/moderation/bans/{banId}":{"get":{"operationId":"ModerationBansController_get","parameters":[{"name":"banId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BanResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `BAN_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["moderation"]}},"/v1/moderation/bans/{banId}/revoke":{"post":{"description":"Platform and organization bans. Notifies the user (`moderation.ban_revoked`). Refused for bans about yourself or an organization you belong to.","operationId":"ModerationBansController_revoke","parameters":[{"name":"banId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeBanRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BanRevocationResultResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `BAN_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `BAN_NOT_ACTIVE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Lift a ban early","tags":["moderation"]}},"/v1/organizations/{id}/bans":{"get":{"operationId":"OrganizationBansController_list","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[status]","required":false,"in":"query","schema":{"default":"all","type":"string","enum":["active","ended","all"]}},{"name":"filter[user]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BanPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The organization's bans, newest first","tags":["organizations"]},"post":{"description":"Takes effect at once: the user can't act in the organization (a member keeps the membership, but every permission there answers `USER_BANNED`), be invited or join, or comment on, rate or open its content. Only current members, pending invitees and users who commented on, rated or reported the organization's content in the last 90 days (anyone else, unknown users included: 404 `BAN_TARGET_NOT_FOUND`). Never yourself, platform staff or the owner; banning a member needs every permission of their role. At most 20 bans per hour and 3 of the same user per day (429 `BAN_RATE_LIMITED`, `details.retryAfterSeconds`). Notifies the user (`moderation.banned` naming the organization, never who decided; mailed to members only, in-app for others).","operationId":"OrganizationBansController_ban","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrganizationBanRequestDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BanResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`, `ROLE_ESCALATION_DENIED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `BAN_TARGET_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `BAN_ALREADY_ACTIVE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`, `BAN_TARGET_PROTECTED`, `BAN_EXPIRY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `BAN_RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Ban a user from the organization","tags":["organizations"]}},"/v1/organizations/{id}/bans/{banId}":{"get":{"operationId":"OrganizationBansController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"banId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BanResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `BAN_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/bans/{banId}/revoke":{"post":{"description":"Notifies the user (`moderation.ban_revoked`).","operationId":"OrganizationBansController_revoke","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"banId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeBanRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BanResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `BAN_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `BAN_NOT_ACTIVE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Lift an organization ban early","tags":["organizations"]}},"/v1/users/me/bans":{"get":{"description":"Active ones by default. Works while platform-banned: when any other route answers 403 `USER_BANNED`, show these (scope, organization, rule broken, expiry) with their appeal (`appeal`, `appealable`: appeal with `POST /v1/users/me/appeals`).","operationId":"OwnBansController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[status]","required":false,"in":"query","description":"`active` (default), `ended` (expired or revoked) or `all`.","schema":{"default":"active","type":"string","enum":["active","ended","all"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnBanWithAppealPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Your bans","tags":["users"]}},"/v1/users/me/appeals":{"post":{"description":"A ban of yours (any scope; works while platform-banned), a takedown of your content (or of an organization you own), a platform moderator hiding your comment, or a warning. Once per decision and reviewer, within 30 days of the decision, while it still applies. Organization bans go to that organization’s admins first; once they reject it, appeal the same ban again within 30 days to go to platform moderation. Your text is plain text. You get `moderation.appeal_submitted`, then `moderation.appeal_accepted|appeal_rejected`.","operationId":"OwnAppealsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAppealRequestDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnAppealResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `APPEAL_DECISION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `APPEAL_ALREADY_EXISTS`, `APPEAL_DECISION_ENDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `APPEAL_WINDOW_CLOSED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Appeal a moderation decision","tags":["users"]},"get":{"operationId":"OwnAppealsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[status]","required":false,"in":"query","description":"`open`, `resolved` (accepted or rejected) or `all`.","schema":{"default":"all","type":"string","enum":["open","resolved","all"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnAppealPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Your appeals, newest first","tags":["users"]}},"/v1/users/me/appeals/{id}":{"get":{"operationId":"OwnAppealsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnAppealResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `APPEAL_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["users"]}},"/v1/users/me/moderation-decisions":{"get":{"description":"Warnings, platform hides of your comments and takedowns of your content (or of organizations you own), newest first, each with whether it still applies, its newest appeal and whether a new one can go now. Bans are in `GET /v1/users/me/bans`.","operationId":"OwnAppealsController_decisions","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnModerationDecisionPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Moderation decisions about you that can be appealed","tags":["users"]}},"/v1/moderation/appeals":{"get":{"description":"`filter[status]` defaults to `open`. Organization-level appeals (first level of organization bans) are their organization’s to resolve; staff may answer one from its `staffResolvableAt` (open 14 days, or the organization disabled or deleted), and that answer is final.","operationId":"ModerationAppealsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[status]","required":false,"in":"query","schema":{"default":"open","type":"string","enum":["open","resolved","all"]}},{"name":"filter[user]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"sort","required":false,"in":"query","description":"`oldest`: the longest-waiting first; `newest`.","schema":{"default":"oldest","type":"string","enum":["oldest","newest"]}},{"name":"filter[level]","required":false,"in":"query","description":"`platform`: staff resolve these; `organization`: first-level appeals of organization bans (read-only for staff).","schema":{"type":"string","enum":["organization","platform"]}},{"name":"filter[kind]","required":false,"in":"query","schema":{"type":"string","enum":["ban","takedown","comment_hide","warning"]}},{"name":"filter[org]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffAppealPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Appeals, the oldest open first","tags":["moderation"]}},"/v1/moderation/appeals/{appealId}":{"get":{"description":"The ban (with its internal reason) or the moderation action, whether it still applies, and the organization-level appeal an escalation follows.","operationId":"ModerationAppealsController_get","parameters":[{"name":"appealId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffAppealDetailResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `APPEAL_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"An appeal with the decision it contests","tags":["moderation"]}},"/v1/moderation/appeals/{appealId}/accept":{"post":{"description":"Lifts the ban, restores the content (with the copies its takedown followed) or the comment, or withdraws the warning, through the usual moderation action (with `note` as its reason). Notifies the appellant (`moderation.appeal_accepted`), never naming you. Not on your own decisions, appeals about you or organizations you belong to, or escalations whose first level you answered. Organization-level appeals only from `staffResolvableAt` (else 409 `APPEAL_ORGANIZATION_LEVEL`).","operationId":"ModerationAppealsController_accept","parameters":[{"name":"appealId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveAppealRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppealResolutionResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `APPEAL_NOT_FOUND`, `APPEAL_DECISION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `APPEAL_NOT_OPEN`, `APPEAL_ORGANIZATION_LEVEL`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Accept an appeal and reverse the decision","tags":["moderation"]}},"/v1/moderation/appeals/{appealId}/reject":{"post":{"description":"The decision stands; the appellant gets `moderation.appeal_rejected` and reads `note` on the appeal. A platform rejection is final.","operationId":"ModerationAppealsController_reject","parameters":[{"name":"appealId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveAppealRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppealResolutionResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `APPEAL_NOT_FOUND`, `APPEAL_DECISION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `APPEAL_NOT_OPEN`, `APPEAL_ORGANIZATION_LEVEL`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Reject an appeal","tags":["moderation"]}},"/v1/organizations/{id}/appeals":{"get":{"operationId":"OrganizationAppealsController_list","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[status]","required":false,"in":"query","schema":{"default":"open","type":"string","enum":["open","resolved","all"]}},{"name":"filter[user]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"sort","required":false,"in":"query","description":"`oldest`: the longest-waiting first; `newest`.","schema":{"default":"oldest","type":"string","enum":["oldest","newest"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffAppealPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Appeals of the organization's bans, the oldest open first","tags":["organizations"]}},"/v1/organizations/{id}/appeals/{appealId}":{"get":{"operationId":"OrganizationAppealsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"appealId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationAppealDetailResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `APPEAL_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["organizations"]}},"/v1/organizations/{id}/appeals/{appealId}/accept":{"post":{"description":"Audited `organization.appeal_accepted` and `organization.ban_revoked` (with `note` as the revoke reason of the ban; audit entries keep only its length). Notifies the appellant (`moderation.appeal_accepted`), never naming you.","operationId":"OrganizationAppealsController_accept","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"appealId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveAppealRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationAppealResolutionResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `APPEAL_NOT_FOUND`, `APPEAL_DECISION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `APPEAL_NOT_OPEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Accept an appeal and lift the ban","tags":["organizations"]}},"/v1/organizations/{id}/appeals/{appealId}/reject":{"post":{"description":"The ban stands. The appellant gets `moderation.appeal_rejected` and may ask platform moderation within 30 days.","operationId":"OrganizationAppealsController_reject","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"appealId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveAppealRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationAppealResolutionResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `APPEAL_NOT_FOUND`, `APPEAL_DECISION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `APPEAL_NOT_OPEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `MODERATION_SELF_ACTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Reject an appeal","tags":["organizations"]}},"/v1/support/tickets":{"post":{"description":"Needs an active paid plan (Creator or Organization Owner; 403 `ENTITLEMENT_REQUIRED` otherwise). The description becomes the first message; the support list is mailed. At most 10 unresolved tickets and 10 new ones per 24 hours (422 `TICKET_LIMIT_REACHED`).","operationId":"SupportTicketsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTicketDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`, `ENTITLEMENT_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `TICKET_LIMIT_REACHED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Open a support ticket","tags":["support"]},"get":{"operationId":"SupportTicketsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[status]","required":false,"in":"query","schema":{"type":"string","enum":["open","in_progress","waiting_on_user","resolved","closed"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["support"]}},"/v1/support/tickets/{id}":{"get":{"operationId":"SupportTicketsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `TICKET_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["support"]}},"/v1/support/tickets/{id}/messages":{"post":{"description":"Only while the ticket is open, in progress or waiting on you (409 `TICKET_NOT_OPEN`); a ticket waiting on you goes back in progress.","operationId":"SupportTicketsController_reply","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketMessageDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `TICKET_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `TICKET_NOT_OPEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `TICKET_MESSAGES_LIMIT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Reply on your ticket","tags":["support"]}},"/v1/support/tickets/{id}/close":{"post":{"description":"resolved → closed (409 `TICKET_INVALID_TRANSITION` from any other status; closing a closed ticket is a no-op).","operationId":"SupportTicketsController_close","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `TICKET_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `TICKET_INVALID_TRANSITION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Close your resolved ticket","tags":["support"]}},"/v1/support/tickets/{id}/uploads":{"post":{"description":"Private bucket only. Images (JPEG, PNG, WebP, AVIF, GIF…) up to 10 MB, videos (MP4, WebM, QuickTime) up to 50 MB. At most 5 attachments per ticket, pending uploads included (422 `TICKET_ATTACHMENTS_LIMIT`). Then `PUT` the file and register it with `POST /v1/support/tickets/:id/attachments`.","operationId":"SupportTicketsController_createUpload","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTicketUploadDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketUploadResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `TICKET_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `TICKET_NOT_OPEN`, `TOO_MANY_PENDING_UPLOADS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `TICKET_ATTACHMENTS_LIMIT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Get a signed upload URL for an attachment","tags":["support"]}},"/v1/support/tickets/{id}/attachments":{"post":{"description":"The server checks the bytes against the declared type; images are re-encoded, videos stored as uploaded. Rejected files are discarded (422).","operationId":"SupportTicketsController_register","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterTicketAttachmentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketAttachmentResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `TICKET_NOT_FOUND`, `UPLOAD_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `TICKET_NOT_OPEN`, `UPLOAD_PROCESSING`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `UPLOAD_NOT_RECEIVED`, `UPLOAD_TOO_LARGE`, `ASSET_CONTENT_MISMATCH`, `ASSET_UNSUPPORTED_IMAGE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Register an uploaded attachment","tags":["support"]}},"/v1/admin/tickets":{"get":{"operationId":"AdminTicketsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[status]","required":false,"in":"query","schema":{"type":"string","enum":["open","in_progress","waiting_on_user","resolved","closed"]}},{"name":"filter[category]","required":false,"in":"query","schema":{"type":"string","enum":["bug","billing","account","other"]}},{"name":"filter[assignee]","required":false,"in":"query","description":"A staff user id, `me` or `none` (unassigned).","schema":{"type":"string"}},{"name":"filter[requester]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffTicketPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]}},"/v1/admin/tickets/{id}":{"get":{"operationId":"AdminTicketsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffTicketResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `TICKET_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["admin"]},"patch":{"description":"open → in_progress ⇄ waiting_on_user → resolved → closed (in_progress and waiting_on_user may both resolve). Closed tickets are read-only (409 `TICKET_NOT_OPEN`). Assignees must be active support staff.","operationId":"AdminTicketsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTicketDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffTicketResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `TICKET_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `TICKET_INVALID_TRANSITION`, `TICKET_NOT_OPEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `TICKET_ASSIGNEE_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Change a ticket’s status or assignment","tags":["admin"]}},"/v1/admin/tickets/{id}/messages":{"post":{"description":"A public reply is mailed to the requester and starts work on an open ticket; an internal note is visible to staff only.","operationId":"AdminTicketsController_postMessage","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffTicketMessageDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffTicketResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `TICKET_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `TICKET_NOT_OPEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `TICKET_MESSAGES_LIMIT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Reply or add an internal note","tags":["admin"]}},"/v1/privacy/consents":{"get":{"description":"Signed in: the account's records. Signed out: those of `anonymousId` (400 `ANONYMOUS_ID_REQUIRED` without it). `current: null` means no choice yet: optional categories are off.","operationId":"PrivacyConsentsController_get","parameters":[{"name":"anonymousId","required":false,"in":"query","description":"Signed-out callers only: the device's anonymous id.","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsentStateResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `ANONYMOUS_ID_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`, `CONSENT_NOT_ALLOWED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Read your consent and its history","tags":["privacy"]},"put":{"description":"Records a new version when the choice differs from the current one (the same choice again only confirms it). Withdrawal is a choice with `analytics: false`; it takes effect for the next analytics batch. The player's choice wins: an `embed_sdk` choice made while the current record is a `banner` or `settings` withdrawal is stored in the history but never becomes `current` (analytics stay off until the player grants through the banner or settings). `anonymousId` is a device secret: whoever knows it can read and change that device's consent, so keep it on the device and never put it in URLs that are shared or logged. Anonymous choices lapse when not confirmed for `retention.consentRecordsDays` (3 years). At most 20 new anonymous ids per IP per hour (429 `CONSENT_RATE_LIMITED`).","operationId":"PrivacyConsentsController_put","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PutConsentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsentStateResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `ANONYMOUS_ID_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ACCOUNT_DISABLED`, `CONSENT_NOT_ALLOWED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`, `CONSENT_RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Record a consent choice (grant or withdraw)","tags":["privacy"]}},"/v1/privacy/exports":{"post":{"description":"Queues the archive (profile, settings, sessions, devices, sign-in methods, comments, support tickets without internal notes, consents, memberships and your puzzles' metadata; never other people's data). One at a time (409 `EXPORT_IN_PROGRESS`), one per 24 hours (429 `EXPORT_RATE_LIMITED`, `details.retryAfterSeconds`; failed ones don't count). You get an email when it is ready.","operationId":"PrivacyExportsController_create","parameters":[],"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataExportResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `EXPORT_IN_PROGRESS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `EXPORT_RATE_LIMITED`, `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Request an export of your personal data","tags":["privacy"]},"get":{"operationId":"PrivacyExportsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataExportPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["privacy"]}},"/v1/privacy/exports/{id}":{"get":{"operationId":"PrivacyExportsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataExportResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `EXPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["privacy"]}},"/v1/privacy/exports/{id}/download":{"post":{"description":"A signed URL valid for 5 minutes (ask again for a new one). 409 `EXPORT_NOT_READY` while pending, processing or failed; 410 `EXPORT_EXPIRED` once deleted.","operationId":"PrivacyExportsController_download","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataExportDownloadResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `EXPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `EXPORT_NOT_READY`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Error codes: `EXPORT_EXPIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Get a download link for a ready export","tags":["privacy"]}},"/v1/organizations/{id}/exports":{"post":{"operationId":"OrganizationExportsController_create","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataExportResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `EXPORT_IN_PROGRESS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `EXPORT_RATE_LIMITED`, `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Request an export of the organization's data","tags":["privacy"]},"get":{"operationId":"OrganizationExportsController_list","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataExportPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["privacy"]}},"/v1/organizations/{id}/exports/{exportId}":{"get":{"operationId":"OrganizationExportsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"exportId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataExportResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `EXPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["privacy"]}},"/v1/organizations/{id}/exports/{exportId}/download":{"post":{"description":"A signed URL valid for 5 minutes.","operationId":"OrganizationExportsController_download","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"exportId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataExportDownloadResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `EXPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `EXPORT_NOT_READY`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Error codes: `EXPORT_EXPIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Get a download link for a ready organization export","tags":["privacy"]}},"/v1/privacy/account-deletion":{"post":{"description":"Soft-deletes the account now (every session is signed out, owned organizations are frozen for their members to claim, API keys are revoked, webhooks disabled, subscriptions canceled) and purges its personal data after `retention.deletedAccountsDays` (30 days by default): personal puzzles are deleted, organization content stays with the organization, comments stay shown as a deleted user, completed play stays anonymised. Needs a sign-in within the last 5 minutes. There is no undo.","operationId":"AccountDeletionController_delete","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletionConfirmationDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletionRequestResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`, `REAUTHENTICATION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `DELETION_CONFIRMATION_MISMATCH`, `LAST_SUPER_ADMIN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Delete your account","tags":["privacy"]}},"/v1/organizations/{id}/deletion":{"post":{"description":"Owner only. Freezes the organization now (reason `deletion_requested`: content becomes read-only, members are notified, nobody can claim it; published puzzles keep serving) and soft-deletes it at the freeze deadline, 14 days later (an earlier deadline of a freeze for a lost plan is kept), unless the owner cancels. Its members, invitations and unpublished content are purged `retention.deletedOrganizationsDays` (90) after the deletion; published puzzles stay while published. Needs a sign-in within the last 5 minutes.","operationId":"OrganizationDeletionController_schedule","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletionConfirmationDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletionRequestResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`, `REAUTHENTICATION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ORGANIZATION_DELETION_SCHEDULED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `DELETION_CONFIRMATION_MISMATCH`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Schedule the deletion of the organization","tags":["privacy"]},"get":{"operationId":"OrganizationDeletionController_state","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationDeletionStateResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The organization's latest deletion request","tags":["privacy"]},"delete":{"description":"Owner only, before the deadline, with a sign-in within the last 5 minutes. The organization is active again when the owner holds the Organization Owner plan; otherwise it stays frozen for the lost plan with the same deadline (members holding the plan can then claim it).","operationId":"OrganizationDeletionController_cancel","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletionRequestResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `USER_BANNED`, `ORGANIZATION_DISABLED`, `IMPERSONATION_FORBIDDEN`, `REAUTHENTICATION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ORGANIZATION_DELETION_NOT_SCHEDULED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Cancel the scheduled deletion","tags":["privacy"]}},"/v1/analytics/events":{"post":{"description":"At most 50 events, 64 KiB. Without analytics consent (the current consent record of the account, or of `anonymousId` when signed out) events are stored without any player identifier. Events are kept only about publications the caller could play: published public or unlisted ones that aren't embed-only; embed-only and private ones with a valid `embedToken` for them; private ones for signed-in members with `puzzle:read`, access grantees and organization devices in scope. Events about school organizations' publications never carry a player identifier. Others, invalid events and events older than 30 days (or the raw retention) are dropped alike (`rejected`), so the counts never reveal which publications exist.","operationId":"AnalyticsEventsController_ingest","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsEventBatchDto"}},"text/plain":{"schema":{"$ref":"#/components/schemas/AnalyticsEventBatchDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsIngestResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `BAD_REQUEST`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Error codes: `PAYLOAD_TOO_LARGE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Send a batch of play events","tags":["analytics"]}},"/v1/analytics/overview":{"get":{"description":"Counts only (no player identifiers). Range: inclusive UTC days clamped to the plan's aggregated retention and today; today and days not aggregated yet are computed live. Unique players: consenting players only, exact while raw events are kept; counts of 1–4 are suppressed; never collected for school organizations. Origins are indicative only: events of publications played without an embed token carry the origin the client claims (`embedOrigin`), which nobody verifies; only token embeds record the token's verified origin. API keys with the `analytics:read` scope may call it. `private, no-store`.","operationId":"AnalyticsReportsController_overview","parameters":[{"name":"from","required":false,"in":"query","description":"First UTC day (inclusive). Default: 30 days ending at `to`. Clamped to the plan's aggregated retention (`range.clamped`).","schema":{"format":"date","example":"2026-10-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last UTC day (inclusive). Default and maximum: today (computed live).","schema":{"format":"date","example":"2026-10-24","type":"string"}},{"name":"origin","required":false,"in":"query","description":"Only plays from this embedding origin (`scheme://host[:port]`), `direct` (outside an embed) or `other` (origins beyond each day's top 25). Origin reports carry views, starts, completions, abandons and (except `other`) unique players only.","schema":{"maxLength":255,"example":"https://news.example.com","type":"string"}},{"name":"ownerOrgId","required":false,"in":"query","description":"Report on this organization; omit for your personal workspace.","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsReportResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `ANALYTICS_RANGE_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `API_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `INSUFFICIENT_SCOPE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `ANALYTICS_RANGE_OUTSIDE_RETENTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Workspace analytics report","tags":["analytics"]}},"/v1/analytics/publications":{"get":{"description":"Publications with numbers in the range (deleted ones included, `publication: null` once gone), sorted by `sort` then id. Counts only (no player identifiers). Range: inclusive UTC days clamped to the plan's aggregated retention and today; today and days not aggregated yet are computed live. Unique players: consenting players only, exact while raw events are kept; counts of 1–4 are suppressed; never collected for school organizations. Origins are indicative only: events of publications played without an embed token carry the origin the client claims (`embedOrigin`), which nobody verifies; only token embeds record the token's verified origin. API keys with the `analytics:read` scope may call it. `private, no-store`.","operationId":"AnalyticsReportsController_publications","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"ownerOrgId","required":false,"in":"query","description":"List this organization; omit for your personal workspace.","schema":{"format":"uuid","type":"string"}},{"name":"from","required":false,"in":"query","description":"First UTC day (inclusive). Default: 30 days ending at `to`. Clamped to the plan's aggregated retention (`range.clamped`).","schema":{"format":"date","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last UTC day (inclusive). Default and maximum: today (computed live).","schema":{"format":"date","type":"string"}},{"name":"sort","required":false,"in":"query","schema":{"default":"-views","type":"string","enum":["-views","-starts","-completions","views","starts","completions"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsPublicationPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `ANALYTICS_RANGE_INVALID`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `API_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `INSUFFICIENT_SCOPE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `ANALYTICS_RANGE_OUTSIDE_RETENTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Per-publication totals of a workspace's analytics","tags":["analytics"]}},"/v1/analytics/publications/{id}":{"get":{"description":"Counts only (no player identifiers). Range: inclusive UTC days clamped to the plan's aggregated retention and today; today and days not aggregated yet are computed live. Unique players: consenting players only, exact while raw events are kept; counts of 1–4 are suppressed; never collected for school organizations. Origins are indicative only: events of publications played without an embed token carry the origin the client claims (`embedOrigin`), which nobody verifies; only token embeds record the token's verified origin. API keys with the `analytics:read` scope may call it. `private, no-store`.","operationId":"AnalyticsReportsController_publication","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"from","required":false,"in":"query","description":"First UTC day (inclusive). Default: 30 days ending at `to`. Clamped to the plan's aggregated retention (`range.clamped`).","schema":{"format":"date","example":"2026-10-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last UTC day (inclusive). Default and maximum: today (computed live).","schema":{"format":"date","example":"2026-10-24","type":"string"}},{"name":"origin","required":false,"in":"query","description":"Only plays from this embedding origin (`scheme://host[:port]`), `direct` (outside an embed) or `other` (origins beyond each day's top 25). Origin reports carry views, starts, completions, abandons and (except `other`) unique players only.","schema":{"maxLength":255,"example":"https://news.example.com","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsReportResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `ANALYTICS_RANGE_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `API_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `INSUFFICIENT_SCOPE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUBLICATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `ANALYTICS_RANGE_OUTSIDE_RETENTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Publication analytics report","tags":["analytics"]}},"/v1/analytics/puzzles/{id}":{"get":{"description":"Counts only (no player identifiers). Range: inclusive UTC days clamped to the plan's aggregated retention and today; today and days not aggregated yet are computed live. Unique players: consenting players only, exact while raw events are kept; counts of 1–4 are suppressed; never collected for school organizations. Origins are indicative only: events of publications played without an embed token carry the origin the client claims (`embedOrigin`), which nobody verifies; only token embeds record the token's verified origin. API keys with the `analytics:read` scope may call it. `private, no-store`.","operationId":"AnalyticsReportsController_puzzle","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"from","required":false,"in":"query","description":"First UTC day (inclusive). Default: 30 days ending at `to`. Clamped to the plan's aggregated retention (`range.clamped`).","schema":{"format":"date","example":"2026-10-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last UTC day (inclusive). Default and maximum: today (computed live).","schema":{"format":"date","example":"2026-10-24","type":"string"}},{"name":"origin","required":false,"in":"query","description":"Only plays from this embedding origin (`scheme://host[:port]`), `direct` (outside an embed) or `other` (origins beyond each day's top 25). Origin reports carry views, starts, completions, abandons and (except `other`) unique players only.","schema":{"maxLength":255,"example":"https://news.example.com","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsReportResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `ANALYTICS_RANGE_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `API_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `INSUFFICIENT_SCOPE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `PUZZLE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `ANALYTICS_RANGE_OUTSIDE_RETENTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Puzzle analytics report (all its publications)","tags":["analytics"]}},"/v1/analytics/series/{id}":{"get":{"description":"Counts only (no player identifiers). Range: inclusive UTC days clamped to the plan's aggregated retention and today; today and days not aggregated yet are computed live. Unique players: consenting players only, exact while raw events are kept; counts of 1–4 are suppressed; never collected for school organizations. Origins are indicative only: events of publications played without an embed token carry the origin the client claims (`embedOrigin`), which nobody verifies; only token embeds record the token's verified origin. API keys with the `analytics:read` scope may call it. `private, no-store`.","operationId":"AnalyticsReportsController_series","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"from","required":false,"in":"query","description":"First UTC day (inclusive). Default: 30 days ending at `to`. Clamped to the plan's aggregated retention (`range.clamped`).","schema":{"format":"date","example":"2026-10-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last UTC day (inclusive). Default and maximum: today (computed live).","schema":{"format":"date","example":"2026-10-24","type":"string"}},{"name":"origin","required":false,"in":"query","description":"Only plays from this embedding origin (`scheme://host[:port]`), `direct` (outside an embed) or `other` (origins beyond each day's top 25). Origin reports carry views, starts, completions, abandons and (except `other`) unique players only.","schema":{"maxLength":255,"example":"https://news.example.com","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsReportResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `ANALYTICS_RANGE_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `API_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `INSUFFICIENT_SCOPE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SERIES_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `ANALYTICS_RANGE_OUTSIDE_RETENTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Series analytics report (its editions' publications)","tags":["analytics"]}},"/v1/analytics/exports":{"post":{"description":"Queues a CSV or JSON file of one report, with exactly the rules of the query API (counts only; unique players rounded down to multiples of 5 and suppressed below 5; details suppressed below 5 starts; ranges clamped to the plan's retention; live days lag an hour). Built asynchronously into private storage: poll `GET /v1/analytics/exports/{id}` (or wait for the `analytics.export_ready` notification and mail), then `POST …/download` for a 5-minute link. Files are kept for the platform's export retention (7 days by default). Per workspace: 3 building at once and 20 per rolling 24 hours (429 `ANALYTICS_EXPORT_RATE_LIMITED`, `details { reason: concurrent|daily, limit, retryAfterSeconds }`). `publications` exports hold at most 10000 rows (`truncated`). CSV cells that start with `=`, `+`, `-`, `@`, a tab or a carriage return are prefixed with `'`. API keys with the `analytics:read` scope may call it. Refused under staff impersonation (403 `IMPERSONATION_FORBIDDEN`); listing, reading and downloading stay allowed.","operationId":"AnalyticsExportsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAnalyticsExportDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsExportResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `ANALYTICS_RANGE_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `API_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `INSUFFICIENT_SCOPE`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`, `PUBLICATION_NOT_FOUND`, `PUZZLE_NOT_FOUND`, `SERIES_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `ANALYTICS_RANGE_OUTSIDE_RETENTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `ANALYTICS_EXPORT_RATE_LIMITED`, `RATE_LIMITED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Request an analytics export (CSV or JSON)","tags":["analytics"]},"get":{"description":"Every export of the workspace (whoever asked), all statuses. Keyset by id.","operationId":"AnalyticsExportsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"ownerOrgId","required":false,"in":"query","description":"List this organization's exports; omit for your personal workspace.","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsExportPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `API_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `INSUFFICIENT_SCOPE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"A workspace's analytics exports, newest first","tags":["analytics"]}},"/v1/analytics/exports/{id}":{"get":{"operationId":"AnalyticsExportsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsExportResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `API_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `INSUFFICIENT_SCOPE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ANALYTICS_EXPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"One analytics export and its status","tags":["analytics"]}},"/v1/analytics/exports/{id}/download":{"post":{"description":"A signed URL of the private file, valid for 5 minutes (`attachment; filename=\"analytics-<report>-<from>-<to>.<format>\"`); ask again for a new one. Audited.","operationId":"AnalyticsExportsController_download","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsExportDownloadResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `API_KEY_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `ENTITLEMENT_REQUIRED`, `INSUFFICIENT_SCOPE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ANALYTICS_EXPORT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ANALYTICS_EXPORT_NOT_READY`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"Error codes: `ANALYTICS_EXPORT_EXPIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Get a download link for a ready analytics export","tags":["analytics"]}},"/v1/organizations/{id}/device-pairings":{"post":{"description":"Returns a single-use code (once) to enter on the device within 10 minutes; then approve the claimed pairing. Never `Idempotency-Key`: the code is not stored.","operationId":"OrganizationDevicesController_create","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevicePairingWithCodeResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `DEVICE_PAIRINGS_LIMIT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Start pairing a device","tags":["devices"]},"get":{"operationId":"OrganizationDevicesController_listPairings","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevicePairingPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Open pairings (pending, claimed, approved), newest first","tags":["devices"]}},"/v1/organizations/{id}/devices":{"get":{"operationId":"OrganizationDevicesController_listDevices","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[status]","required":false,"in":"query","description":"`live`: not revoked (active, lapsed or awaiting pairing).","schema":{"type":"string","enum":["live","revoked"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgDevicePageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The organization's devices, newest first","tags":["devices"]}},"/v1/device-pairings/{id}/approve":{"post":{"description":"Needs the `confirmationCode` shown on the claiming device. Creates the device (it counts against the plan’s `org_devices_max`), or re-pairs the rotated device the pairing was opened for. The device then picks its credential up.","operationId":"DevicePairingsController_approve","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveDevicePairingDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgDeviceResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Error codes: `QUOTA_EXCEEDED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `DEVICE_PAIRING_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `DEVICE_PAIRING_NOT_CLAIMED`, `DEVICE_PAIRING_CLOSED`, `ORG_DEVICE_REVOKED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `DEVICE_PAIRING_EXPIRED`, `DEVICE_PAIRING_CONFIRMATION_MISMATCH`, `DEVICE_SCOPE_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Approve a claimed pairing","tags":["devices"]}},"/v1/device-pairings/{id}/reject":{"post":{"operationId":"DevicePairingsController_reject","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevicePairingResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `DEVICE_PAIRING_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `DEVICE_PAIRING_CLOSED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Reject or cancel a pairing (idempotent)","tags":["devices"]}},"/v1/org-devices/{id}":{"get":{"operationId":"OrgDevicesController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgDeviceResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORG_DEVICE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["devices"]},"patch":{"operationId":"OrgDevicesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgDeviceSettingsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgDeviceResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORG_DEVICE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ORG_DEVICE_REVOKED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `DEVICE_SCOPE_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Rename a device, change its scope or offline window","tags":["devices"]}},"/v1/org-devices/{id}/revoke":{"post":{"description":"Its credential and access tokens stop working at once and its plan slot is freed. Content it already cached stays playable until its `offlineUntil` (FR-DEV-ORG-02). `devices:revoke`: also in frozen organizations.","operationId":"OrgDevicesController_revoke","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Revoked."},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORG_DEVICE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Revoke a device (idempotent)","tags":["devices"]}},"/v1/org-devices/{id}/rotate":{"post":{"description":"The current credential stops working now; the returned code (shown once) pairs the same device again, keeping its name, scope and plan slot.","operationId":"OrgDevicesController_rotate","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgDeviceRotationResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORG_DEVICE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ORG_DEVICE_REVOKED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `DEVICE_PAIRINGS_LIMIT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Rotate a device credential","tags":["devices"]}},"/v1/org-devices/{id}/reauthorize":{"post":{"description":"For a device that stayed offline past `offlineUntil` (status `lapsed`): it may sign in again within a new offline window.","operationId":"OrgDevicesController_reauthorize","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgDeviceResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORG_DEVICE_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `ORG_DEVICE_REVOKED`, `ORG_DEVICE_NOT_LAPSED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Reauthorize a lapsed device","tags":["devices"]}},"/v1/device-auth/pair":{"post":{"description":"Rate-limited like sign-in; after too many failed claims platform-wide, every claim answers 429 `DEVICE_PAIRING_PAUSED` for a minute. Single use: the code stops working once claimed. Show `confirmationCode` on the device (the admin types it to approve) and poll `POST /v1/device-auth/credential` with the returned token until an admin decides.","operationId":"DeviceAuthController_pair","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimDevicePairingDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevicePairingClaimResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `DEVICE_PAIRING_CODE_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`, `DEVICE_PAIRING_PAUSED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Claim a pairing code on the device","tags":["device-auth"]}},"/v1/device-auth/credential":{"post":{"operationId":"DeviceAuthController_credential","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PairingCredentialRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PairingCredentialResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `DEVICE_PAIRING_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Poll a claimed pairing; get the device credential once approved","tags":["device-auth"]}},"/v1/device-auth/token":{"post":{"description":"Also restarts the offline window (`device.offlineUntil`). Use the token as `Authorization: Bearer <accessToken>` without cookies.","operationId":"DeviceAuthController_token","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceCredentialDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceTokenResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `DEVICE_CREDENTIAL_INVALID`, `DEVICE_REAUTHORIZATION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Exchange the device credential for a 1-hour access token","tags":["device-auth"]}},"/v1/device-auth/rotate":{"post":{"description":"The old credential and its access tokens stop working; store the new one before discarding the old.","operationId":"DeviceAuthController_rotate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceCredentialDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceCredentialResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `DEVICE_CREDENTIAL_INVALID`, `DEVICE_REAUTHORIZATION_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Replace the device credential","tags":["device-auth"]}},"/v1/device/me":{"get":{"operationId":"DeviceController_me","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceSelfResponseDto"}}}},"400":{"description":"Error codes: `CONFLICTING_CREDENTIALS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `DEVICE_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The calling device","tags":["device-auth"]}},"/v1/device/publications":{"get":{"description":"The organization's published, standalone-playable publications within the device's scope, private ones included (the device plays them without checks). Load each through its `playPath` with the device's token.","operationId":"DeviceController_publications","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevicePublicationPageResponseDto"}}}},"400":{"description":"Error codes: `CONFLICTING_CREDENTIALS`, `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `DEVICE_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Publications the device may play, newest first","tags":["device-auth"]}},"/v1/organizations/{id}/classes":{"post":{"description":"School organizations with a current DPA only. The join code is in this response only (stored hashed); never `Idempotency-Key`, so it is not stored for replays.","operationId":"OrganizationClassesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateClassDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedClassResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `ORGANIZATION_NOT_SCHOOL`, `DPA_RENEWAL_REQUIRED`, `CLASSES_LIMIT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Create a class with its first join code","tags":["schools"]},"get":{"operationId":"OrganizationClassesController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[status]","required":false,"in":"query","schema":{"type":"string","enum":["active","archived"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchoolClassPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `ORGANIZATION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The organization's classes, newest first","tags":["schools"]}},"/v1/classes/join":{"post":{"description":"No account, email or other personal data. Returns the student token once (`ppst_…`): keep it on the device and send it as `Authorization: Bearer` without cookies. After too many wrong codes from one network, joins from it answer 429 `CLASS_JOIN_PAUSED` for up to 10 minutes.","operationId":"ClassJoinController_join","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinClassDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassJoinResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `CLASS_JOIN_CODE_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `STUDENT_NICKNAME_TAKEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `STUDENT_NICKNAME_INVALID`, `CLASS_FULL`, `CLASS_JOIN_UNAVAILABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Error codes: `RATE_LIMITED`, `CLASS_JOIN_PAUSED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Join a class with its code and a nickname","tags":["schools"]}},"/v1/classes/{id}":{"get":{"operationId":"ClassesController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchoolClassResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SCHOOL_CLASS_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"A class (never its join code)","tags":["schools"]},"patch":{"operationId":"ClassesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateClassDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchoolClassResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SCHOOL_CLASS_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Rename a class","tags":["schools"]}},"/v1/classes/{id}/archive":{"post":{"description":"Idempotent. Clears the join code; the class's student tokens stop working until it is restored.","operationId":"ClassesController_archive","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchoolClassResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SCHOOL_CLASS_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Archive a class","tags":["schools"]}},"/v1/classes/{id}/restore":{"post":{"description":"Idempotent. Its students play again; rotate the join code to let new ones join.","operationId":"ClassesController_restore","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchoolClassResponseDto"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SCHOOL_CLASS_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `ORGANIZATION_NOT_SCHOOL`, `DPA_RENEWAL_REQUIRED`, `CLASSES_LIMIT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Restore an archived class","tags":["schools"]}},"/v1/classes/{id}/join-code":{"post":{"description":"A new code, shown only in this response; the previous one stops working. Never `Idempotency-Key`.","operationId":"ClassesController_rotateJoinCode","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RotateJoinCodeDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinCodeResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SCHOOL_CLASS_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `SCHOOL_CLASS_ARCHIVED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `ORGANIZATION_NOT_SCHOOL`, `DPA_RENEWAL_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Rotate the join code","tags":["schools"]},"delete":{"description":"Idempotent. Nobody can join until a new code is rotated.","operationId":"ClassesController_disableJoinCode","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SCHOOL_CLASS_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Turn the join code off","tags":["schools"]}},"/v1/classes/{id}/students":{"get":{"operationId":"ClassesController_listStudents","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}},{"name":"filter[status]","required":false,"in":"query","schema":{"type":"string","enum":["active","revoked"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudentPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SCHOOL_CLASS_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The class's students, in join order","tags":["schools"]}},"/v1/classes/{id}/progress":{"get":{"description":"For each student and each of the class's current assignments they started: status, attempts, completion, time, hints and reveals (E20-T03). Sparse: pairs without an entry were not started. Active students and revoked ones whose play is still retained. `filter[publicationId]` (an assignment of the class, else 404 `CLASS_ASSIGNMENT_NOT_FOUND`) and `filter[studentId]` (a student of the class, else 404 `STUDENT_NOT_FOUND`) narrow it.","operationId":"ClassesController_classProgress","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"filter[publicationId]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"filter[studentId]","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassProgressResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SCHOOL_CLASS_NOT_FOUND`, `CLASS_ASSIGNMENT_NOT_FOUND`, `STUDENT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The class's progress per student and assignment","tags":["schools"]}},"/v1/classes/{id}/analytics":{"get":{"description":"Totals, per-assignment completion and medians, and sessions and completions per UTC day (E20-T04), counted over the class's current, unrevoked students and current assignments only; no student identifiers. Sessions count by their server start, completions by the time the server recorded them, and each assignment only from its `assignedAt` on (earlier play isn't class work): per-assignment figures, `days` and `totals` alike. `medianTimeMs`/`medianHints` (each completer's first completion in the range) are null when fewer than 3 students completed. `from`/`to` are inclusive UTC days: default the last 30 days ending today, at most 366 days (400 `ANALYTICS_RANGE_INVALID`), clamped to the organization plan's analytics retention and to today (`range.clamped`); nothing left is 422 `ANALYTICS_RANGE_OUTSIDE_RETENTION`. Works in frozen organizations.","operationId":"ClassesController_classAnalytics","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"from","required":false,"in":"query","description":"First UTC day (inclusive). Default: 30 days ending at `to`. Clamped to the plan's aggregated retention (`range.clamped`).","schema":{"format":"date","example":"2026-10-01","type":"string"}},{"name":"to","required":false,"in":"query","description":"Last UTC day (inclusive). Default and maximum: today (computed live).","schema":{"format":"date","example":"2026-10-24","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassAnalyticsResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `ANALYTICS_RANGE_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SCHOOL_CLASS_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `ANALYTICS_RANGE_OUTSIDE_RETENTION`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The class's analytics","tags":["schools"]}},"/v1/classes/{id}/publications":{"get":{"operationId":"ClassesController_listAssignments","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassAssignmentPageResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SCHOOL_CLASS_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The class's assigned publications, newest first","tags":["schools"]},"post":{"description":"One of the organization's own publications; its students may then play it while it is published. Students play only casual publications unless `competitive` is set (a competitive publication assigned without it is not playable for them). 201 when assigned, 200 when it already was (`competitive`, when sent, is changed).","operationId":"ClassesController_assign","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignPublicationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassAssignmentResponseDto"}}}},"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassAssignmentResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SCHOOL_CLASS_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `SCHOOL_CLASS_ARCHIVED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `CLASS_ASSIGNMENT_INVALID`, `CLASS_ASSIGNMENTS_LIMIT`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Assign a publication to the class","tags":["schools"]}},"/v1/classes/{id}/publications/{publicationId}":{"delete":{"operationId":"ClassesController_unassign","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"publicationId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `SCHOOL_CLASS_NOT_FOUND`, `CLASS_ASSIGNMENT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Remove a publication from the class","tags":["schools"]}},"/v1/students/{id}":{"patch":{"description":"Same nickname rules as joining; revoked students are 404.","operationId":"StudentsController_rename","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameStudentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudentResponseDto"}}}},"400":{"description":"Error codes: `VALIDATION_FAILED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `ORGANIZATION_FROZEN`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `STUDENT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Error codes: `STUDENT_NICKNAME_TAKEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Error codes: `STUDENT_NICKNAME_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Rename a student (moderate a nickname)","tags":["schools"]}},"/v1/students/{id}/revoke":{"post":{"description":"Idempotent; works in frozen organizations. The student's token stops working at once and the nickname is freed; their play history stays.","operationId":"StudentsController_revoke","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":"Error codes: `UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ACCOUNT_DISABLED`, `ORGANIZATION_DISABLED`, `USER_BANNED`, `IMPERSONATION_FORBIDDEN`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Error codes: `STUDENT_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Revoke a student","tags":["schools"]}},"/v1/student/me":{"get":{"operationId":"StudentController_me","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudentSelfResponseDto"}}}},"400":{"description":"Error codes: `CONFLICTING_CREDENTIALS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The student: nickname, class and school","tags":["schools"]}},"/v1/student/publications":{"get":{"description":"Published, not taken down and standalone-playable, of any visibility (private ones play without checks). Load each through its `playPath` with the student token; nothing else is playable with it.","operationId":"StudentController_publications","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque `nextCursor` from the previous page.","schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudentPublicationPageResponseDto"}}}},"400":{"description":"Error codes: `CONFLICTING_CREDENTIALS`, `VALIDATION_FAILED`, `INVALID_CURSOR`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"The class's assigned publications playable now, newest first","tags":["schools"]}},"/v1/student/progress":{"get":{"description":"One entry per assigned publication you started (none: not started), with `openSessionId` to resume (`GET /v1/play-sessions/:id` with the student token). Play itself uses the play-session routes with the student token; progress is always saved on the server.","operationId":"StudentController_progress","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudentOwnProgressResponseDto"}}}},"400":{"description":"Error codes: `CONFLICTING_CREDENTIALS`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Error codes: `UNAUTHENTICATED`, `STUDENT_TOKEN_INVALID`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Error codes: `FORBIDDEN`, `ORGANIZATION_DISABLED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"summary":"Your own progress on your class’s assignments","tags":["schools"]}}},"info":{"title":"Puzzle Platform API","description":"REST API of the Puzzle Platform (architecture §9).\n\n- JSON in camelCase; timestamps are ISO 8601 UTC; IDs are strings.\n- Lists use cursor pagination: `?limit=25&cursor=<opaque>` → `{ data, nextCursor }` (maximum `limit` 100).\n- POSTs that must not run twice accept an `Idempotency-Key` header (replayed for 24 h).\n- Drafts and settings return an `ETag`; updates require `If-Match` (428 without it, 412 on mismatch).\n\n## Errors\n\nEvery error has the body `{ \"error\": { \"code\", \"message\", \"requestId\", \"details\" } }`. Codes are stable `UPPER_SNAKE_CASE` strings; endpoints document their own codes in addition to these common ones:\n\n| Code | Status | Meaning |\n|---|---|---|\n| `VALIDATION_FAILED` | 400 | The request body, query or parameters are invalid. |\n| `BAD_REQUEST` | 400 | The request is malformed. |\n| `INVALID_CURSOR` | 400 | The pagination cursor is malformed or expired. |\n| `IDEMPOTENCY_KEY_REQUIRED` | 400 | This operation requires an `Idempotency-Key` header. |\n| `CONFLICTING_CREDENTIALS` | 400 | An API key was sent together with session cookies; API-key requests are cookie-less (E18-T01). |\n| `IDEMPOTENCY_KEY_INVALID` | 400 | The `Idempotency-Key` header must be 1–255 printable ASCII characters. |\n| `UNAUTHENTICATED` | 401 | Authentication is missing or invalid. |\n| `API_KEY_INVALID` | 401 | The API key (`Authorization: Bearer pp_…`) is malformed, unknown, expired or revoked. |\n| `QUOTA_EXCEEDED` | 402 | A plan quota is exhausted; `details.entitlement` names the entitlement. |\n| `FORBIDDEN` | 403 | The caller may not perform this operation. |\n| `INSUFFICIENT_SCOPE` | 403 | The API key's scopes don't include the permission the operation needs; `details.requiredScope` names it. |\n| `IMPERSONATION_FORBIDDEN` | 403 | Not available while a staff member impersonates the user (credential, billing, delete and staff operations). |\n| `CSRF_REJECTED` | 403 | A cookie-authenticated mutation came from an origin that is not allowed (cross-site request). |\n| `ACCOUNT_DISABLED` | 403 | The signed-in account is suspended or closed (any authenticated route). |\n| `NOT_FOUND` | 404 | The resource does not exist or is not visible to the caller. |\n| `METHOD_NOT_ALLOWED` | 405 | The method is not supported on this resource. |\n| `CONFLICT` | 409 | The request conflicts with the current state. |\n| `ALREADY_EXISTS` | 409 | A resource with the same unique values exists; `details[].field` names them. |\n| `IDEMPOTENCY_KEY_IN_USE` | 409 | A request with this `Idempotency-Key` is still running. |\n| `PRECONDITION_FAILED` | 412 | `If-Match` does not match the current `ETag`. |\n| `PAYLOAD_TOO_LARGE` | 413 | The body is too large. |\n| `UNSUPPORTED_MEDIA_TYPE` | 415 | The content type is not supported. |\n| `UNPROCESSABLE` | 422 | The request is valid but breaks a domain rule. |\n| `IDEMPOTENCY_KEY_MISMATCH` | 422 | The `Idempotency-Key` was already used with a different request. |\n| `PRECONDITION_REQUIRED` | 428 | This update requires an `If-Match` header. |\n| `RATE_LIMITED` | 429 | Too many requests. |\n| `INTERNAL_ERROR` | 500 | Unexpected server error; quote the `requestId`. |\n| `SERVICE_UNAVAILABLE` | 503 | A dependency is temporarily unavailable. |\n","version":"1","contact":{}},"tags":[],"servers":[],"components":{"schemas":{"UserSettingsResponseDto":{"type":"object","properties":{"serverProgressEnabled":{"type":"boolean","description":"Sync game progress to the server."},"analyticsEnabled":{"type":"boolean","description":"Optional analytics identifiers: mirrors the current consent record (read-only here; change it with `PUT /v1/privacy/consents`, source `settings`)."},"leaderboardVisible":{"type":"boolean","description":"Appear on leaderboards."},"profilePublic":{"type":"boolean","description":"Public profile page."}},"required":["serverProgressEnabled","analyticsEnabled","leaderboardVisible","profilePublic"]},"UpdateUserSettingsDto":{"type":"object","properties":{"serverProgressEnabled":{"type":"boolean"},"leaderboardVisible":{"type":"boolean"},"profilePublic":{"type":"boolean"}}},"MePlatformBanDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The ban (`GET /v1/users/me/bans`, appeals)."},"endsAt":{"type":"string","format":"date-time","nullable":true,"description":"When it ends; null for a permanent ban."}},"required":["id","endsAt"]},"MeResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"username":{"type":"string"},"displayName":{"type":"string"},"avatarUrl":{"type":"string","format":"uri","nullable":true},"locale":{"type":"string","enum":["en","es","pt-PT"]},"status":{"type":"string","enum":["active","suspended"]},"staffRoles":{"type":"array","description":"Platform staff roles, in catalog order; empty for players.","items":{"type":"string","enum":["support","moderator","super_admin"]}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"birthDate":{"type":"string","format":"date","nullable":true},"emailVerifiedAt":{"type":"string","format":"date-time","nullable":true},"platformBan":{"nullable":true,"description":"The active platform ban, or null. While banned only the limited session works (own account and bans, appeals, notifications, privacy rights; organization owners also export and delete their organizations); every other route answers 403 `USER_BANNED`.","type":"object","allOf":[{"$ref":"#/components/schemas/MePlatformBanDto"}]}},"required":["id","email","username","displayName","avatarUrl","locale","status","staffRoles","createdAt","updatedAt","birthDate","emailVerifiedAt","platformBan"]},"UserUpdateInfoDto":{"type":"object","properties":{"email":{"type":"string","format":"email"},"username":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[A-Za-z][A-Za-z0-9_-]{1,28}[A-Za-z0-9]$","description":"Letters, digits and single `_`/`-`; starts with a letter, ends with a letter or digit; reserved words are refused."},"displayName":{"type":"string","maxLength":64},"locale":{"type":"string","enum":["en","es","pt-PT"]}}},"UserResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"username":{"type":"string"},"displayName":{"type":"string"},"avatarUrl":{"type":"string","format":"uri","nullable":true},"locale":{"type":"string","enum":["en","es","pt-PT"]},"status":{"type":"string","enum":["active","suspended"]},"staffRoles":{"type":"array","description":"Platform staff roles, in catalog order; empty for players.","items":{"type":"string","enum":["support","moderator","super_admin"]}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","email","username","displayName","avatarUrl","locale","status","staffRoles","createdAt","updatedAt"]},"UserUpdatePasswordBodyDto":{"type":"object","properties":{"password":{"type":"string","format":"password","minLength":8,"description":"At least 8 characters and at most 72 UTF-8 bytes."},"passwordConfirm":{"type":"string","format":"password","description":"Equal to `password`."},"currentPassword":{"type":"string","format":"password","description":"The current password. Required unless the session signed in or reauthenticated in the last 5 minutes."}},"required":["password","passwordConfirm"]},"RegisterDto":{"type":"object","properties":{"email":{"type":"string","format":"email","maxLength":254},"password":{"type":"string","format":"password","minLength":8,"description":"At least 8 characters and at most 72 UTF-8 bytes."},"username":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[A-Za-z][A-Za-z0-9_-]{1,28}[A-Za-z0-9]$","description":"Letters, digits and single `_`/`-`; starts with a letter, ends with a letter or digit; reserved words are refused."},"birthDate":{"type":"string","format":"date","example":"2000-01-31","description":"Age screen: registrations below the minimum age are refused with `REGISTRATION_NOT_ELIGIBLE` and nothing is stored."},"displayName":{"type":"string","maxLength":64,"description":"Defaults to the username."},"locale":{"type":"string","enum":["en","es","pt-PT"]}},"required":["email","password","username","birthDate"]},"AcceptedResponseDto":{"type":"object","properties":{"message":{"type":"string","example":"If the details are valid, we sent you an email."}},"required":["message"]},"RegistrationStatusResponseDto":{"type":"object","properties":{"mode":{"type":"string","enum":["open","allowlist"],"description":"`open`: anyone may create an account. `allowlist`: only invited addresses; others get 403 `REGISTRATION_CLOSED`."}},"required":["mode"]},"LoginDto":{"type":"object","properties":{"appInstanceId":{"type":"string","format":"uuid","description":"Random UUID the client keeps per browser or app install."},"platform":{"type":"string","enum":["ios","android","web"],"default":"web"},"deviceName":{"type":"string","maxLength":64,"description":"Shown in the device list; derived from the User-Agent when omitted."},"email":{"type":"string","format":"email"},"password":{"type":"string","format":"password"}},"required":["email","password"]},"SignedInResponseDto":{"type":"object","properties":{"status":{"type":"string","enum":["signed_in"]},"user":{"$ref":"#/components/schemas/MeResponseDto"}},"required":["status","user"]},"VerifyEmailDto":{"type":"object","properties":{"token":{"type":"string","description":"The `token` query parameter of the emailed link."},"password":{"type":"string","format":"password","description":"The password chosen at registration. Without it (or for an account whose password is not confirmed yet), verifying removes that password and mails a reset link: the link alone does not prove who chose it."}},"required":["token"]},"VerifyEmailResponseDto":{"type":"object","properties":{"emailVerifiedAt":{"type":"string","format":"date-time"},"passwordRemoved":{"type":"boolean","description":"The password chosen before verification was removed (it was not sent with the request); a reset link was mailed to set a new one."}},"required":["emailVerifiedAt","passwordRemoved"]},"TokenDto":{"type":"object","properties":{"token":{"type":"string","description":"The `token` query parameter of the emailed link."}},"required":["token"]},"ConfirmEmailChangeResponseDto":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"The account email now."}},"required":["email"]},"EmailRequestDto":{"type":"object","properties":{"email":{"type":"string","format":"email","maxLength":254}},"required":["email"]},"ResetPasswordDto":{"type":"object","properties":{"token":{"type":"string","description":"The `token` query parameter of the emailed link."},"password":{"type":"string","format":"password","minLength":8,"description":"At least 8 characters and at most 72 UTF-8 bytes."}},"required":["token","password"]},"LoginSSODto":{"type":"object","properties":{"appInstanceId":{"type":"string","format":"uuid","description":"Random UUID the client keeps per browser or app install."},"platform":{"type":"string","enum":["ios","android","web"],"default":"web"},"deviceName":{"type":"string","maxLength":64,"description":"Shown in the device list; derived from the User-Agent when omitted."},"idToken":{"type":"string","description":"Google ID token (JWT)."}},"required":["idToken"]},"PendingGoogleRegistrationDto":{"type":"object","properties":{"registrationToken":{"type":"string","description":"Send it to `POST /v1/auth/sso/google/complete`."},"email":{"type":"string","format":"email"},"displayName":{"type":"string","nullable":true},"suggestedUsername":{"type":"string","description":"A free username derived from the Google profile."},"expiresAt":{"type":"string","format":"date-time"}},"required":["registrationToken","email","displayName","suggestedUsername","expiresAt"]},"GoogleSignInResponseDto":{"type":"object","properties":{"status":{"type":"string","enum":["signed_in","registration_required"]},"user":{"$ref":"#/components/schemas/MeResponseDto"},"registration":{"$ref":"#/components/schemas/PendingGoogleRegistrationDto"}},"required":["status"]},"CompleteGoogleRegistrationDto":{"type":"object","properties":{"appInstanceId":{"type":"string","format":"uuid","description":"Random UUID the client keeps per browser or app install."},"platform":{"type":"string","enum":["ios","android","web"],"default":"web"},"deviceName":{"type":"string","maxLength":64,"description":"Shown in the device list; derived from the User-Agent when omitted."},"registrationToken":{"type":"string","description":"`registration.registrationToken` from `POST /v1/auth/sso/google`."},"birthDate":{"type":"string","format":"date","example":"2000-01-31"},"username":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[A-Za-z][A-Za-z0-9_-]{1,28}[A-Za-z0-9]$"},"displayName":{"type":"string","maxLength":64,"description":"Defaults to the Google name, else the username."},"locale":{"type":"string","enum":["en","es","pt-PT"]}},"required":["registrationToken","birthDate","username"]},"SessionDeviceDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["ios","android","web"]},"name":{"type":"string","nullable":true}},"required":["id","kind","name"]},"SessionResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time","description":"When the user signed in."},"lastUsedAt":{"type":"string","format":"date-time","nullable":true,"description":"Last token refresh; null until the first one."},"expiresAt":{"type":"string","format":"date-time"},"ip":{"type":"string","nullable":true,"description":"Null for impersonation sessions (the staff member's)."},"userAgent":{"type":"string","nullable":true,"description":"Null for impersonation sessions (the staff member's)."},"device":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/SessionDeviceDto"}]},"current":{"type":"boolean","description":"The session making this request."},"impersonated":{"type":"boolean","description":"A support staff member opened this session to impersonate you (time-limited and audited); revoking it ends the impersonation."}},"required":["id","createdAt","lastUsedAt","expiresAt","ip","userAgent","device","current","impersonated"]},"SessionPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SessionResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"RevokedCountResponseDto":{"type":"object","properties":{"revoked":{"type":"integer"}},"required":["revoked"]},"DeviceResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["ios","android","web"]},"name":{"type":"string","nullable":true},"lastSeenAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"current":{"type":"boolean","description":"The device of the session making this request."}},"required":["id","kind","name","lastSeenAt","createdAt","current"]},"DevicePageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DeviceResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"IdentityResponseDto":{"type":"object","properties":{"provider":{"type":"string","enum":["password","google"]},"linkedAt":{"type":"string","format":"date-time"},"lastLoginAt":{"type":"string","format":"date-time","nullable":true}},"required":["provider","linkedAt","lastLoginAt"]},"IdentityListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/IdentityResponseDto"}}},"required":["data"]},"LinkGoogleDto":{"type":"object","properties":{"idToken":{"type":"string","description":"Google ID token (JWT)."}},"required":["idToken"]},"ReauthenticateDto":{"type":"object","properties":{"password":{"type":"string","format":"password"},"idToken":{"type":"string","description":"Google ID token (JWT)."}}},"EntitlementDto":{"type":"object","properties":{"key":{"type":"string","enum":["personal_puzzles_create","personal_drafts_max","personal_published_puzzles_max","orgs_owned_max","org_published_puzzles_max","org_members_max","org_devices_max","asset_storage_bytes","embeds_enabled","api_keys_enabled","api_calls_monthly_included","api_calls_metered","analytics_enabled","analytics_extended","analytics_raw_retention_days","analytics_aggregated_retention_months","support_tickets"],"description":"Stable catalog key (also used in `QUOTA_EXCEEDED` details)."},"kind":{"type":"string","enum":["flag","limit"]},"unit":{"type":"string","enum":["count","bytes","days","months"],"nullable":true},"value":{"oneOf":[{"type":"boolean"},{"type":"integer","minimum":0}],"nullable":true,"description":"Flags: boolean. Limits: a non-negative integer, or null for unlimited."},"source":{"type":"string","enum":["plan","override","default"]},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"Set when an override provides the value and expires."}},"required":["key","kind","unit","value","source","expiresAt"]},"EntitlementsResponseDto":{"type":"object","properties":{"plan":{"type":"string","enum":["free","creator","org_owner"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/EntitlementDto"}}},"required":["plan","data"]},"UsageItemDto":{"type":"object","properties":{"metric":{"type":"string","enum":["personal_drafts","personal_published_puzzles","orgs_owned","org_published_puzzles","org_members","org_devices","asset_storage_bytes","api_calls"]},"period":{"type":"string","enum":["month","none"],"description":"`month`: resets each calendar month (UTC); `none`: a running total."},"periodStart":{"type":"string","format":"date-time","nullable":true,"description":"Start of the current period; null for running totals."},"value":{"type":"integer","minimum":0},"entitlement":{"type":"string","enum":["personal_drafts_max","personal_published_puzzles_max","orgs_owned_max","org_published_puzzles_max","org_members_max","org_devices_max","asset_storage_bytes","api_calls_monthly_included","analytics_raw_retention_days","analytics_aggregated_retention_months"],"description":"The entitlement that caps this metric."},"limit":{"type":"integer","minimum":0,"nullable":true,"description":"Null = unlimited."}},"required":["metric","period","periodStart","value","entitlement","limit"]},"UsageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UsageItemDto"}}},"required":["data"]},"InvoiceAmountsDto":{"type":"object","properties":{"currency":{"type":"string","example":"eur","description":"Lower-case ISO 4217 code."},"total":{"type":"number","description":"What the customer pays, taxes included, in minor units (cents). Show this amount."},"tax":{"type":"number","nullable":true,"description":"Taxes included in `total` (minor units); null when Stripe computed no tax."},"totalExcludingTax":{"type":"number","nullable":true}},"required":["currency","total","tax","totalExcludingTax"]},"SubscriptionDto":{"type":"object","properties":{"status":{"type":"string","description":"Stripe status, verbatim: `active`, `trialing`, `past_due` (plan kept until `graceUntil`), `canceled`, `unpaid`, `incomplete`, `incomplete_expired`, `paused`."},"plan":{"type":"string","enum":["free","creator","org_owner"],"nullable":true,"description":"Null when its price is not configured on any plan."},"interval":{"type":"string","enum":["monthly","annual"],"nullable":true},"currentPeriodEnd":{"type":"string","format":"date-time","nullable":true},"cancelAt":{"type":"string","format":"date-time","nullable":true},"cancelAtPeriodEnd":{"type":"boolean"},"graceUntil":{"type":"string","format":"date-time","nullable":true,"description":"While `past_due`: the plan is kept until this instant (7-day grace), then the account is downgraded."},"automaticTax":{"type":"boolean","description":"Stripe Tax computes the tax of this subscription."},"latestInvoice":{"nullable":true,"description":"The latest invoice (null until Stripe sent one). Renewals usually charge the same `total`.","type":"object","allOf":[{"$ref":"#/components/schemas/InvoiceAmountsDto"}]}},"required":["status","plan","interval","currentPeriodEnd","cancelAt","cancelAtPeriodEnd","graceUntil","automaticTax","latestInvoice"]},"SubscriptionResponseDto":{"type":"object","properties":{"plan":{"type":"string","enum":["free","creator","org_owner"],"description":"The plan held now (grace period included); entitlements follow it."},"subscription":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/SubscriptionDto"}]}},"required":["plan","subscription"]},"CreateCheckoutSessionDto":{"type":"object","properties":{"plan":{"type":"string","enum":["creator","org_owner"]},"interval":{"type":"string","enum":["monthly","annual"]}},"required":["plan","interval"]},"CheckoutSessionResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Stripe Checkout session id (`cs_…`)."},"url":{"type":"string","format":"uri","description":"Stripe-hosted Checkout page; redirect the browser to it."}},"required":["id","url"]},"PortalSessionResponseDto":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"Stripe Customer Portal page (plan changes, payment methods, cancellation); short-lived, open it right away."}},"required":["url"]},"StripeWebhookResponseDto":{"type":"object","properties":{"received":{"type":"boolean","enum":[true]}},"required":["received"]},"AcceptDpaDto":{"type":"object","properties":{"version":{"type":"string","example":"2026-10-24","description":"The DPA version accepted; must be the current one (`GET /v1/school-dpa`)."},"accepted":{"type":"boolean","enum":[true],"description":"Explicit acceptance; must be true."},"signerName":{"type":"string","minLength":1,"maxLength":200,"description":"Full name of the person signing for the school (an authorized adult representative)."},"signerTitle":{"type":"string","minLength":1,"maxLength":200,"example":"Head teacher","description":"The signer's role at the school."}},"required":["version","accepted","signerName","signerTitle"]},"CreateOrganizationDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"slug":{"type":"string","example":"acme-games","description":"Public handle (`/@slug`): 3–30 letters, digits, single `_` or `-`; starts with a letter. Case-insensitive, unique among organizations and usernames."},"type":{"type":"string","enum":["standard","school"],"default":"standard","description":"`school` enables classes and students and requires `dpa` (E20-T01)."},"dpa":{"description":"Schools only (and required for them): acceptance of the current data processing agreement.","allOf":[{"$ref":"#/components/schemas/AcceptDpaDto"}]}},"required":["name","slug"]},"OrganizationSchoolDto":{"type":"object","properties":{"dpaVersion":{"type":"string","description":"The DPA version accepted last."},"dpaAcceptedAt":{"type":"string"},"dpaCurrent":{"type":"boolean","description":"Whether that is the current version; when false the owner accepts the new one (`POST …/dpa-acceptances`)."}},"required":["dpaVersion","dpaAcceptedAt","dpaCurrent"]},"OrgRoleResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string","enum":["owner","admin","editor","contributor","analyst","viewer"],"nullable":true,"description":"System role key; null for custom roles."},"name":{"type":"string"},"isSystem":{"type":"boolean"},"permissions":{"description":"Workspace permission keys.","type":"array","items":{"type":"string"}}},"required":["id","key","name","isSystem","permissions"]},"OwnMembershipDto":{"type":"object","properties":{"role":{"$ref":"#/components/schemas/OrgRoleResponseDto"},"joinedAt":{"type":"string"}},"required":["role","joinedAt"]},"OrganizationResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["standard","school"]},"status":{"type":"string","enum":["active","frozen","deleted"]},"disabled":{"type":"boolean","description":"Disabled by staff: nothing can be managed."},"frozenAt":{"type":"string","nullable":true},"freezeDeadline":{"type":"string","nullable":true,"description":"Frozen organizations are soft-deleted at this instant unless a member holding the Organization Owner plan claims them (or, for `deletion_requested`, the owner cancels the deletion)."},"freezeReason":{"type":"string","enum":["owner_plan_lost","owner_deleted","deletion_requested"],"nullable":true,"description":"Why it is frozen: the owner lost the Organization Owner plan, deleted their account, or asked for the deletion (`deletion_requested`: nobody can claim it; the owner can cancel with `DELETE /v1/organizations/{id}/deletion`)."},"ownerUserId":{"type":"string","format":"uuid"},"school":{"nullable":true,"description":"Schools only (E20-T01): the data processing agreement.","type":"object","allOf":[{"$ref":"#/components/schemas/OrganizationSchoolDto"}]},"membership":{"$ref":"#/components/schemas/OwnMembershipDto"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","slug","name","type","status","disabled","frozenAt","freezeDeadline","freezeReason","ownerUserId","school","membership","createdAt","updatedAt"]},"OrganizationPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"UpdateOrganizationDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100}}},"MemberUserDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"username":{"type":"string"},"displayName":{"type":"string"}},"required":["id","username","displayName"]},"MemberResponseDto":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/MemberUserDto"},"role":{"$ref":"#/components/schemas/OrgRoleResponseDto"},"isOwner":{"type":"boolean"},"joinedAt":{"type":"string"}},"required":["user","role","isOwner","joinedAt"]},"MemberPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MemberResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"ChangeMemberRoleDto":{"type":"object","properties":{"roleId":{"type":"string","format":"uuid","description":"A system role (not `owner`) or a custom role of this organization."}},"required":["roleId"]},"CreateInvitationDto":{"type":"object","properties":{"email":{"type":"string","format":"email","maxLength":254},"roleId":{"type":"string","format":"uuid","description":"A system role (not `owner`) or a custom role of this organization."},"locale":{"type":"string","enum":["en","es","pt-PT"],"description":"Language of the invitation mail; defaults to the invitee's account language, else yours."}},"required":["email","roleId"]},"InvitationResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"orgId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"role":{"$ref":"#/components/schemas/OrgRoleResponseDto"},"status":{"type":"string","enum":["pending","accepted","rejected","revoked"]},"expired":{"type":"boolean"},"expiresAt":{"type":"string"},"invitedBy":{"type":"string","format":"uuid"},"createdAt":{"type":"string"}},"required":["id","orgId","email","role","status","expired","expiresAt","invitedBy","createdAt"]},"InvitationPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InvitationResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"OrgRoleListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrgRoleResponseDto"}}},"required":["data"]},"CreateOrgRoleDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":60},"permissions":{"type":"array","description":"Workspace permissions (owner-only ones excluded). `organization:read` is always included.","items":{"type":"string","enum":["puzzle:create","puzzle:read","puzzle:read-solution","puzzle:edit","puzzle:delete","puzzle:publish","puzzle:unpublish","publication:grants:manage","publication:grants:read","publication:grants:revoke","embed-tokens:create","comment:moderate","organization:read","organization:update","organization:settings:manage","organization:members:invite","organization:members:manage","organization:roles:manage","analytics:read","api-keys:manage","webhooks:manage","devices:manage","devices:read","devices:revoke","classes:manage","classes:read","students:revoke","organization:bans:manage"]}}},"required":["name","permissions"]},"UpdateOrgRoleDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":60},"permissions":{"type":"array","description":"Workspace permissions (owner-only ones excluded). `organization:read` is always included.","items":{"type":"string","enum":["puzzle:create","puzzle:read","puzzle:read-solution","puzzle:edit","puzzle:delete","puzzle:publish","puzzle:unpublish","publication:grants:manage","publication:grants:read","publication:grants:revoke","embed-tokens:create","comment:moderate","organization:read","organization:update","organization:settings:manage","organization:members:invite","organization:members:manage","organization:roles:manage","analytics:read","api-keys:manage","webhooks:manage","devices:manage","devices:read","devices:revoke","classes:manage","classes:read","students:revoke","organization:bans:manage"]}}}},"ThemeSettingsDto":{"type":"object","properties":{"accentColor":{"type":"string","nullable":true,"example":"#1d4ed8"},"colorScheme":{"type":"string","enum":["auto","light","dark"]},"brandImageAssetId":{"type":"string","format":"uuid","nullable":true,"description":"The brand image asset (`brand_image`), or null."},"brandImageUrl":{"type":"string","nullable":true,"description":"Public URL of the brand image, published when the settings were saved; null without one."}},"required":["accentColor","colorScheme","brandImageAssetId","brandImageUrl"]},"OrganizationSettingsDto":{"type":"object","properties":{"commentsEnabled":{"type":"boolean"},"commentsOpen":{"type":"boolean","description":"New comments and replies allowed; false locks threads (comments stay readable)."},"hintsEnabled":{"type":"boolean"},"timerVisible":{"type":"boolean"},"embedDomains":{"nullable":true,"description":"Sites allowed to embed publications (`*.example.com` for subdomains); null = any site, [] = none.","type":"array","items":{"type":"string"}},"theme":{"$ref":"#/components/schemas/ThemeSettingsDto"}},"required":["commentsEnabled","commentsOpen","hintsEnabled","timerVisible","embedDomains","theme"]},"OrganizationSettingsResponseDto":{"type":"object","properties":{"settings":{"$ref":"#/components/schemas/OrganizationSettingsDto"},"revision":{"type":"number","description":"Also sent as the ETag."}},"required":["settings","revision"]},"ThemeSettingsPatchDto":{"type":"object","properties":{"accentColor":{"type":"string","nullable":true,"example":"#1d4ed8"},"colorScheme":{"type":"string","enum":["auto","light","dark"]},"brandImageAssetId":{"type":"string","format":"uuid","nullable":true,"description":"A ready `brand_image` asset of this organization: saving publishes it and sets `brandImageUrl`. null removes the brand image."}}},"UpdateOrganizationSettingsDto":{"type":"object","properties":{"commentsEnabled":{"type":"boolean"},"commentsOpen":{"type":"boolean","description":"false locks comment threads: existing comments stay readable, nothing new is posted."},"hintsEnabled":{"type":"boolean"},"timerVisible":{"type":"boolean"},"embedDomains":{"nullable":true,"maxItems":50,"description":"Lower-case host names, `*.example.com` for subdomains; null = any site, [] = none.","type":"array","items":{"type":"string"}},"theme":{"$ref":"#/components/schemas/ThemeSettingsPatchDto"}}},"TransferUserDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"username":{"type":"string"},"displayName":{"type":"string"}},"required":["id","username","displayName"]},"OwnershipTransferResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"orgId":{"type":"string","format":"uuid"},"fromUser":{"description":"The owner.","allOf":[{"$ref":"#/components/schemas/TransferUserDto"}]},"toUser":{"description":"The recipient.","allOf":[{"$ref":"#/components/schemas/TransferUserDto"}]},"status":{"type":"string","enum":["pending","accepted","declined","canceled","expired"],"description":"`expired`: pending past `expiresAt`; it can no longer be accepted."},"expiresAt":{"type":"string"},"respondedAt":{"type":"string","nullable":true},"createdAt":{"type":"string"}},"required":["id","orgId","fromUser","toUser","status","expiresAt","respondedAt","createdAt"]},"CurrentOwnershipTransferResponseDto":{"type":"object","properties":{"transfer":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/OwnershipTransferResponseDto"}]}},"required":["transfer"]},"OfferOwnershipTransferDto":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","description":"The member offered the ownership. They must hold the Organization Owner plan."}},"required":["userId"]},"AnswerOwnershipTransferDto":{"type":"object","properties":{"transferId":{"type":"string","format":"uuid","description":"The pending offer’s `id`."}},"required":["transferId"]},"InvitationTokenDto":{"type":"object","properties":{"token":{"type":"string","description":"The `token` query parameter of the invitation link."}},"required":["token"]},"InvitedOrganizationDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"}},"required":["id","slug","name"]},"InvitationPreviewResponseDto":{"type":"object","properties":{"organization":{"$ref":"#/components/schemas/InvitedOrganizationDto"},"role":{"$ref":"#/components/schemas/OrgRoleResponseDto"},"expiresAt":{"type":"string"}},"required":["organization","role","expiresAt"]},"AdminOrganizationResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["standard","school"]},"status":{"type":"string","enum":["active","frozen","deleted"]},"disabledAt":{"type":"string","nullable":true},"frozenAt":{"type":"string","nullable":true},"freezeDeadline":{"type":"string","nullable":true},"freezeReason":{"type":"string","enum":["owner_plan_lost","owner_deleted","deletion_requested"],"nullable":true},"ownerUserId":{"type":"string","format":"uuid"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"deletedAt":{"type":"string","nullable":true}},"required":["id","slug","name","type","status","disabledAt","frozenAt","freezeDeadline","freezeReason","ownerUserId","createdAt","updatedAt","deletedAt"]},"AdminOrganizationPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AdminOrganizationResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"AdminOrganizationOwnerDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"username":{"type":"string"},"displayName":{"type":"string"}},"required":["id","username","displayName"]},"AdminOrganizationDetailResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["standard","school"]},"status":{"type":"string","enum":["active","frozen","deleted"]},"disabledAt":{"type":"string","nullable":true},"frozenAt":{"type":"string","nullable":true},"freezeDeadline":{"type":"string","nullable":true},"freezeReason":{"type":"string","enum":["owner_plan_lost","owner_deleted","deletion_requested"],"nullable":true},"ownerUserId":{"type":"string","format":"uuid"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"deletedAt":{"type":"string","nullable":true},"owner":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/AdminOrganizationOwnerDto"}]},"memberCount":{"type":"number"}},"required":["id","slug","name","type","status","disabledAt","frozenAt","freezeDeadline","freezeReason","ownerUserId","createdAt","updatedAt","deletedAt","owner","memberCount"]},"StaffReasonDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500}},"required":["reason"]},"StaffRenameOrganizationDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500},"name":{"type":"string","minLength":1,"maxLength":100},"slug":{"type":"string","example":"acme-games-2","description":"New public handle. Must be free among organizations and usernames, and not quarantined (a handle given up in the last 90 days stays reserved for its previous holder) unless `reclaimQuarantinedHandle`. The old one is quarantined for this organization."},"reclaimQuarantinedHandle":{"type":"boolean","default":false,"description":"Trademark reclaim: take `slug` even while it is quarantined for whoever gave it up. A slug currently held stays 409. The audit entry records the bypass (`quarantineOverridden`, `reclaimedFrom`) with the reason."}},"required":["reason"]},"SchoolSetupDto":{"type":"object","properties":{"dpa":{"$ref":"#/components/schemas/AcceptDpaDto"}},"required":["dpa"]},"DpaAcceptanceResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"version":{"type":"string"},"acceptedByUserId":{"type":"string","format":"uuid","nullable":true,"description":"The member who accepted it (null once that account is purged)."},"signerName":{"type":"string"},"signerTitle":{"type":"string"},"acceptedAt":{"type":"string"}},"required":["id","version","acceptedByUserId","signerName","signerTitle","acceptedAt"]},"DpaAcceptancePageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DpaAcceptanceResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"SchoolDpaResponseDto":{"type":"object","properties":{"version":{"type":"string","example":"2026-10-24"},"documentPath":{"type":"string","example":"/legal/dpa","description":"Web page with the text of this version."}},"required":["version","documentPath"]},"CreatePuzzleDto":{"type":"object","properties":{"ownerOrgId":{"type":"string","format":"uuid","description":"Create in this organization; omit for your personal workspace (Creator plan)."},"gameType":{"type":"string","example":"crossword","description":"A served game type."},"title":{"type":"string","maxLength":200},"language":{"type":"string","example":"en","pattern":"^[a-z]{2,3}(-[A-Za-z0-9]{2,8}){0,2}$"},"description":{"type":"string","maxLength":2000,"nullable":true},"difficulty":{"type":"string","enum":["easy","medium","hard","expert"],"nullable":true},"tags":{"maxItems":20,"description":"Trimmed, lowercased and de-duplicated; each 1–32 characters.","type":"array","items":{"type":"string"}},"coverAssetId":{"type":"string","format":"uuid","nullable":true,"description":"Cover image: a `puzzle_cover` asset of the puzzle's workspace (`POST /v1/assets`); null removes it."}},"required":["gameType","title","language"]},"WorkspaceRefDto":{"type":"object","properties":{"type":{"type":"string","enum":["user","org"]},"id":{"type":"string","format":"uuid"}},"required":["type","id"]},"PuzzleResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"owner":{"$ref":"#/components/schemas/WorkspaceRefDto"},"gameType":{"type":"string","example":"crossword"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"language":{"type":"string","example":"en"},"difficulty":{"type":"string","enum":["easy","medium","hard","expert"],"nullable":true},"tags":{"type":"array","items":{"type":"string"}},"coverAssetId":{"type":"string","format":"uuid","nullable":true},"createdBy":{"type":"string","format":"uuid"},"takenDownAt":{"type":"string","format":"date-time","nullable":true,"description":"When platform moderation took the puzzle down (E13-T01): it can no longer be published, copied or exported until moderation restores it."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","owner","gameType","title","description","language","difficulty","tags","coverAssetId","createdBy","takenDownAt","createdAt","updatedAt"]},"PuzzlePageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PuzzleResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"UpdatePuzzleDto":{"type":"object","properties":{"title":{"type":"string","maxLength":200},"language":{"type":"string","example":"en","pattern":"^[a-z]{2,3}(-[A-Za-z0-9]{2,8}){0,2}$"},"description":{"type":"string","maxLength":2000,"nullable":true},"difficulty":{"type":"string","enum":["easy","medium","hard","expert"],"nullable":true},"tags":{"maxItems":20,"description":"Trimmed, lowercased and de-duplicated; each 1–32 characters.","type":"array","items":{"type":"string"}},"coverAssetId":{"type":"string","format":"uuid","nullable":true,"description":"Cover image: a `puzzle_cover` asset of the puzzle's workspace (`POST /v1/assets`); null removes it."}}},"DraftResponseDto":{"type":"object","properties":{"puzzleId":{"type":"string","format":"uuid"},"gameType":{"type":"string","example":"crossword"},"revision":{"type":"number","minimum":1},"definition":{"type":"object","additionalProperties":true,"nullable":true,"description":"Null until the first save."},"solution":{"type":"object","additionalProperties":true,"nullable":true,"description":"Null until solved; may be incomplete (see `POST …/validate`)."},"updatedBy":{"type":"string","format":"uuid","nullable":true},"updatedAt":{"type":"string"}},"required":["puzzleId","gameType","revision","definition","solution","updatedBy","updatedAt"]},"SaveDraftDto":{"type":"object","properties":{"definition":{"type":"object","additionalProperties":true,"description":"The public definition, in the game's definition schema."},"solution":{"type":"object","additionalProperties":true,"nullable":true,"description":"The solution in the game's solution schema, a partial one, or null/absent while it is not solved yet."}},"required":["definition"]},"ValidationIssueDto":{"type":"object","properties":{"code":{"type":"string","example":"crossword.unchecked_cell"},"message":{"type":"string"},"severity":{"type":"string","enum":["error","warning"]},"path":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"}]}}},"required":["code","message","severity"]},"SolutionChangeWarningDto":{"type":"object","properties":{"solutionChanged":{"type":"boolean"},"competitiveCompletions":{"type":"boolean","description":"The puzzle has competitive completions (reported once E11-T04 lands)."}},"required":["solutionChanged","competitiveCompletions"]},"DraftValidationResponseDto":{"type":"object","properties":{"revision":{"type":"number","description":"Draft revision that was validated."},"valid":{"type":"boolean","description":"True when no issue has severity `error`."},"issues":{"type":"array","items":{"$ref":"#/components/schemas/ValidationIssueDto"}},"warning":{"description":"FR-VER-04: whether saving this draft as a version changes answers of the latest version, and whether competitive completions exist.","allOf":[{"$ref":"#/components/schemas/SolutionChangeWarningDto"}]}},"required":["revision","valid","issues","warning"]},"SaveVersionDto":{"type":"object","properties":{"draftRevision":{"type":"number","minimum":1,"description":"The draft revision (its ETag) the client is versioning; 409 `DRAFT_REVISION_MISMATCH` when the draft changed."},"acknowledgeSolutionChange":{"type":"boolean","default":false,"description":"Confirms saving a version that changes answers of a puzzle with competitive completions (FR-VER-04)."}},"required":["draftRevision"]},"ProtectedChecksDto":{"type":"object","properties":{"scheme":{"type":"string","example":"hmac-sha256-64"},"salt":{"type":"string"},"checks":{"type":"object","additionalProperties":{"type":"string"},"description":"Check hash per answer position."}},"required":["scheme","salt","checks"]},"SavedVersionResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"major":{"type":"number","minimum":1},"minor":{"type":"number","minimum":0},"label":{"type":"string","example":"1.0"},"engineVersion":{"type":"string","example":"0.4.0"},"solutionChanged":{"type":"boolean","description":"Some answer differs from the previous version of the line."},"createdBy":{"type":"string","format":"uuid"},"createdAt":{"type":"string"},"definition":{"type":"object","additionalProperties":true},"checks":{"nullable":true,"description":"`puzzle:read-solution` only; null for games without protection.","type":"object","allOf":[{"$ref":"#/components/schemas/ProtectedChecksDto"}]},"contentHash":{"type":"string","description":"`puzzle:read-solution` only."},"solution":{"type":"object","additionalProperties":true,"description":"`puzzle:read-solution` only, with `?include=solution`."},"warning":{"$ref":"#/components/schemas/SolutionChangeWarningDto"}},"required":["id","puzzleId","major","minor","label","engineVersion","solutionChanged","createdBy","createdAt","definition","warning"]},"VersionSummaryDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"major":{"type":"number","minimum":1},"minor":{"type":"number","minimum":0},"label":{"type":"string","example":"1.0"},"engineVersion":{"type":"string","example":"0.4.0"},"solutionChanged":{"type":"boolean","description":"Some answer differs from the previous version of the line."},"createdBy":{"type":"string","format":"uuid"},"createdAt":{"type":"string"}},"required":["id","puzzleId","major","minor","label","engineVersion","solutionChanged","createdBy","createdAt"]},"VersionPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/VersionSummaryDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"VersionResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"major":{"type":"number","minimum":1},"minor":{"type":"number","minimum":0},"label":{"type":"string","example":"1.0"},"engineVersion":{"type":"string","example":"0.4.0"},"solutionChanged":{"type":"boolean","description":"Some answer differs from the previous version of the line."},"createdBy":{"type":"string","format":"uuid"},"createdAt":{"type":"string"},"definition":{"type":"object","additionalProperties":true},"checks":{"nullable":true,"description":"`puzzle:read-solution` only; null for games without protection.","type":"object","allOf":[{"$ref":"#/components/schemas/ProtectedChecksDto"}]},"contentHash":{"type":"string","description":"`puzzle:read-solution` only."},"solution":{"type":"object","additionalProperties":true,"description":"`puzzle:read-solution` only, with `?include=solution`."}},"required":["id","puzzleId","major","minor","label","engineVersion","solutionChanged","createdBy","createdAt","definition"]},"CreateUploadDto":{"type":"object","properties":{"ownerOrgId":{"type":"string","format":"uuid","description":"Upload into this organization; omit for your personal workspace."},"purpose":{"type":"string","enum":["puzzle_cover","puzzle_image","brand_image"],"description":"Decides the accepted types, the size limit, the re-encoding and the bucket of the processed asset."},"contentType":{"type":"string","example":"image/png","description":"Exact type the upload must be sent with. The bytes are checked against it on registration."},"size":{"type":"number","minimum":1,"maximum":10485760,"description":"Size of the file in bytes; the upload may not be larger."}},"required":["purpose","contentType","size"]},"SignedUploadDto":{"type":"object","properties":{"method":{"type":"string","enum":["PUT"]},"url":{"type":"string","description":"Upload the file body here."},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Send every header exactly as given (they are signed)."},"expiresAt":{"type":"string"}},"required":["method","url","headers","expiresAt"]},"UploadResponseDto":{"type":"object","properties":{"uploadId":{"type":"string","format":"uuid"},"purpose":{"type":"string","enum":["puzzle_cover","puzzle_image","brand_image","ticket_attachment"]},"contentType":{"type":"string"},"maxBytes":{"type":"number","description":"Largest accepted body in bytes."},"upload":{"$ref":"#/components/schemas/SignedUploadDto"}},"required":["uploadId","purpose","contentType","maxBytes","upload"]},"RegisterAssetDto":{"type":"object","properties":{"uploadId":{"type":"string","format":"uuid","description":"From `POST /v1/uploads`."},"purpose":{"type":"string","enum":["puzzle_cover","puzzle_image","brand_image"],"description":"The upload’s purpose. Send `brand_image` to register an organization brand image with `organization:settings:manage` (otherwise `puzzle:edit` is required); it is checked against the upload."}},"required":["uploadId"]},"AssetResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"owner":{"$ref":"#/components/schemas/WorkspaceRefDto"},"purpose":{"type":"string","enum":["puzzle_cover","puzzle_image","brand_image","ticket_attachment"]},"contentType":{"type":"string","example":"image/webp"},"bytes":{"type":"number"},"width":{"type":"number","nullable":true},"height":{"type":"number","nullable":true},"public":{"type":"boolean","description":"Whether published content made a public copy of the asset (`AssetsService.publish`)."},"createdBy":{"type":"string","format":"uuid"},"createdAt":{"type":"string"},"url":{"type":"string","description":"A short-lived signed URL of the private asset (do not store it)."},"urlExpiresAt":{"type":"string","nullable":true,"description":"When the signed `url` stops working."}},"required":["id","owner","purpose","contentType","bytes","width","height","public","createdBy","createdAt","url","urlExpiresAt"]},"AssetSummaryDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"owner":{"$ref":"#/components/schemas/WorkspaceRefDto"},"purpose":{"type":"string","enum":["puzzle_cover","puzzle_image","brand_image","ticket_attachment"]},"contentType":{"type":"string","example":"image/webp"},"bytes":{"type":"number"},"width":{"type":"number","nullable":true},"height":{"type":"number","nullable":true},"public":{"type":"boolean","description":"Whether published content made a public copy of the asset (`AssetsService.publish`)."},"createdBy":{"type":"string","format":"uuid"},"createdAt":{"type":"string"}},"required":["id","owner","purpose","contentType","bytes","width","height","public","createdBy","createdAt"]},"AssetPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AssetSummaryDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"CreateSeriesDto":{"type":"object","properties":{"ownerOrgId":{"type":"string","format":"uuid","description":"Create in this organization; omit for your personal workspace (Creator plan)."},"slug":{"type":"string","example":"daily-crossword","maxLength":64,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","description":"Unique within the workspace."},"gameType":{"type":"string","example":"crossword","description":"A served game type; every edition is of this type."},"title":{"type":"string","maxLength":200},"language":{"type":"string","example":"en","pattern":"^[a-z]{2,3}(-[A-Za-z0-9]{2,8}){0,2}$","description":"Language of the puzzles its editions create."},"description":{"type":"string","maxLength":2000,"nullable":true}},"required":["slug","gameType","title","language"]},"SeriesResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"owner":{"$ref":"#/components/schemas/WorkspaceRefDto"},"slug":{"type":"string","example":"daily-crossword"},"gameType":{"type":"string","example":"crossword"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"language":{"type":"string","example":"en"},"createdBy":{"type":"string","format":"uuid"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","owner","slug","gameType","title","description","language","createdBy","createdAt","updatedAt"]},"SeriesPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SeriesResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"UpdateSeriesDto":{"type":"object","properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"title":{"type":"string","maxLength":200},"language":{"type":"string","pattern":"^[a-z]{2,3}(-[A-Za-z0-9]{2,8}){0,2}$"},"description":{"type":"string","maxLength":2000,"nullable":true}}},"PutEditionDto":{"type":"object","properties":{"definition":{"type":"object","additionalProperties":true,"description":"The public definition, in the game's definition schema (with `solution`; not with `sourcePuzzleId`)."},"solution":{"type":"object","additionalProperties":true,"description":"The full solution, in the game's solution schema (with `definition`)."},"sourcePuzzleId":{"type":"string","format":"uuid","description":"Copy the content from this puzzle instead: its current draft (needs `puzzle:read-solution` on it) or `sourceVersionId`. Needs `puzzle:read` on it; its solution is copied only with `puzzle:read-solution` (`solutionCopied`); taken-down sources are refused."},"sourceVersionId":{"type":"string","format":"uuid","description":"A version of `sourcePuzzleId` to copy instead of its draft."},"title":{"type":"string","maxLength":200,"description":"Title of the puzzle a new edition creates (default: \"<series title> <date>\"); ignored for existing editions."},"acknowledgeSolutionChange":{"type":"boolean","description":"Confirms a solution change on a puzzle with competitive completions (FR-VER-04)."}}},"EditionResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"seriesId":{"type":"string","format":"uuid"},"date":{"type":"string","example":"2026-10-24","format":"date"},"puzzleId":{"type":"string","format":"uuid"},"title":{"type":"string","description":"The puzzle's title."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","seriesId","date","puzzleId","title","createdAt","updatedAt"]},"PutEditionResponseDto":{"type":"object","properties":{"edition":{"$ref":"#/components/schemas/EditionResponseDto"},"editionCreated":{"type":"boolean","description":"The date had no (live) edition before."},"versionCreated":{"type":"boolean","description":"A version was saved; false when the content equals the latest version."},"version":{"nullable":true,"description":"The latest version (with checks and content hash); null when a source copy without solution created a new puzzle (no version is saved without a solution).","type":"object","allOf":[{"$ref":"#/components/schemas/VersionResponseDto"}]},"warning":{"$ref":"#/components/schemas/SolutionChangeWarningDto"},"solutionCopied":{"type":"boolean","description":"Source copies only: whether the source solution was copied (needs `puzzle:read-solution` on the source). Without it the draft holds the definition and no version is saved (`versionCreated: false`)."}},"required":["edition","editionCreated","versionCreated","version","warning"]},"EditionPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EditionResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"ConversionWarningDto":{"type":"object","properties":{"code":{"type":"string","example":"puz.circles_dropped"},"message":{"type":"string"},"path":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"integer"}]}}},"required":["code","message"]},"ImportResponseDto":{"type":"object","properties":{"puzzle":{"$ref":"#/components/schemas/PuzzleResponseDto"},"draftRevision":{"type":"number"},"format":{"type":"string","example":"puz"},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/ConversionWarningDto"}},"issues":{"description":"Schema and `validateForPublish` issues; any `error` must be fixed before a version can be saved.","type":"array","items":{"$ref":"#/components/schemas/ValidationIssueDto"}}},"required":["puzzle","draftRevision","format","warnings","issues"]},"ClonePuzzleDto":{"type":"object","properties":{"ownerOrgId":{"type":"string","format":"uuid","description":"Create the copy in this organization; omit for your personal workspace (Creator plan)."},"versionId":{"type":"string","format":"uuid","description":"The source version; defaults to the newest version."},"title":{"type":"string","maxLength":200,"description":"The copy's title; defaults to the source's."}}},"CloneResponseDto":{"type":"object","properties":{"puzzle":{"$ref":"#/components/schemas/PuzzleResponseDto"},"draftRevision":{"type":"number"},"sourcePuzzleId":{"type":"string","format":"uuid"},"sourceVersionId":{"type":"string","format":"uuid"},"solutionCopied":{"type":"boolean","description":"Whether the draft got the source solution. Only callers who may read the source solution (`puzzle:read-solution`) get it; others get the definition with an empty solution."}},"required":["puzzle","draftRevision","sourcePuzzleId","sourceVersionId","solutionCopied"]},"GameImportFormatDto":{"type":"object","properties":{"format":{"type":"string","example":"puz"},"label":{"type":"string","example":"Across Lite (.puz)"},"extensions":{"example":["puz"],"type":"array","items":{"type":"string"}},"mediaTypes":{"type":"array","items":{"type":"string"}}},"required":["format","label","extensions","mediaTypes"]},"GameExportFormatDto":{"type":"object","properties":{"format":{"type":"string","example":"puz"},"label":{"type":"string","example":"Across Lite (.puz)"},"extensions":{"example":["puz"],"type":"array","items":{"type":"string"}},"mediaTypes":{"type":"array","items":{"type":"string"}},"includesSolution":{"type":"boolean","description":"The file contains the solution: exporting needs `puzzle:read-solution`."}},"required":["format","label","extensions","mediaTypes","includesSolution"]},"GameResponseDto":{"type":"object","properties":{"type":{"type":"string","example":"crossword"},"major":{"type":"number","example":1,"description":"Engine generation (major line)."},"creatable":{"type":"boolean","description":"Whether the caller's plan lets them create puzzles of this type in their personal workspace (organization workspaces depend on the member's role)."},"importFormats":{"type":"array","items":{"$ref":"#/components/schemas/GameImportFormatDto"}},"exportFormats":{"type":"array","items":{"$ref":"#/components/schemas/GameExportFormatDto"}}},"required":["type","major","creatable","importFormats","exportFormats"]},"GameListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameResponseDto"}}},"required":["data"]},"PublicationThemeDto":{"type":"object","properties":{"accentColor":{"type":"string","nullable":true,"example":"#1d4ed8"},"colorScheme":{"type":"string","enum":["auto","light","dark"]}}},"PublicationSettingsDto":{"type":"object","properties":{"commentsEnabled":{"type":"boolean","description":"Comments (E12); only `false` restricts."},"commentsOpen":{"type":"boolean","description":"Comment threads open for new comments (E12); only `false` (locked) restricts."},"hintsEnabled":{"type":"boolean","description":"Hints and reveals while playing."},"timerVisible":{"type":"boolean","description":"Show the timer while playing."},"embedDomains":{"nullable":true,"maxItems":50,"description":"Sites that may embed it: lower-case host names, `*.example.com` for subdomains; [] = none; null or omitted = what the levels above allow. Must stay within them.","type":"array","items":{"type":"string"}},"theme":{"$ref":"#/components/schemas/PublicationThemeDto"}}},"EmbedPolicyDto":{"type":"object","properties":{"requireToken":{"type":"boolean","description":"Embeds need an embed token minted by your backend (`POST /v1/publications/:id/embed-tokens`). With `accessMode: embed` every play needs one; with `both` standalone play stays open and only token embeds can frame it."}},"required":["requireToken"]},"CreatePublicationDto":{"type":"object","properties":{"visibility":{"type":"string","enum":["public","unlisted","private"]},"accessMode":{"type":"string","enum":["standalone","embed","both"],"default":"standalone","description":"`embed` and `both` need the `embeds_enabled` entitlement."},"mode":{"type":"string","enum":["casual","competitive"],"default":"casual","description":"Competitive payloads carry no check hashes; checking is server-side."},"settings":{"$ref":"#/components/schemas/PublicationSettingsDto"},"embedPolicy":{"description":"Embed policy (E09-T05). Sites allowed to embed are `settings.embedDomains`.","allOf":[{"$ref":"#/components/schemas/EmbedPolicyDto"}]},"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":80,"description":"URL slug (`/@owner/<game>/<slug>`); default: generated from the puzzle title, unique per owner and game type. 409 `PUBLICATION_SLUG_TAKEN`, 422 `PUBLICATION_SLUG_RESERVED`."}},"required":["visibility"]},"PublicationOwnerDto":{"type":"object","properties":{"type":{"type":"string","enum":["user","org"]},"id":{"type":"string","format":"uuid"}},"required":["type","id"]},"PublicationVersionRefDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"major":{"type":"number"},"minor":{"type":"number"},"label":{"type":"string","example":"1.3"}},"required":["id","major","minor","label"]},"EffectiveThemeDto":{"type":"object","properties":{"accentColor":{"type":"string","nullable":true},"colorScheme":{"type":"string","enum":["auto","light","dark"]},"brandImageAssetId":{"type":"string","format":"uuid","nullable":true,"description":"The organization's brand image asset (set in its settings only; a publication can't override it), or null."},"brandImageUrl":{"type":"string","nullable":true,"description":"Public URL of the brand image; null without one."}},"required":["accentColor","colorScheme","brandImageAssetId","brandImageUrl"]},"EffectivePlaySettingsDto":{"type":"object","properties":{"commentsEnabled":{"type":"boolean"},"commentsOpen":{"type":"boolean"},"hintsEnabled":{"type":"boolean"},"timerVisible":{"type":"boolean"},"embedDomains":{"nullable":true,"description":"null = any site; [] = none (also when the plan has no embeds).","type":"array","items":{"type":"string"}},"theme":{"$ref":"#/components/schemas/EffectiveThemeDto"}},"required":["commentsEnabled","commentsOpen","hintsEnabled","timerVisible","embedDomains","theme"]},"LockedSettingsDto":{"type":"object","properties":{"commentsEnabled":{"type":"boolean"},"commentsOpen":{"type":"boolean"},"hintsEnabled":{"type":"boolean"},"timerVisible":{"type":"boolean"},"embedDomains":{"type":"boolean"}},"required":["commentsEnabled","commentsOpen","hintsEnabled","timerVisible","embedDomains"]},"EffectiveSettingsDto":{"type":"object","properties":{"settings":{"$ref":"#/components/schemas/EffectivePlaySettingsDto"},"locked":{"description":"Restrictions fixed by a level above: a locked boolean cannot be turned on, a locked embed list can only narrow.","allOf":[{"$ref":"#/components/schemas/LockedSettingsDto"}]}},"required":["settings","locked"]},"PublicationResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"owner":{"$ref":"#/components/schemas/PublicationOwnerDto"},"status":{"type":"string","enum":["unpublished","published","archived"]},"moderationStatus":{"type":"string","enum":["ok","taken_down"]},"visibility":{"type":"string","enum":["public","unlisted","private"]},"accessMode":{"type":"string","enum":["standalone","embed","both"]},"mode":{"type":"string","enum":["casual","competitive"]},"currentMajor":{"type":"number","description":"The engine major line the pointer follows."},"currentVersion":{"nullable":true,"description":"The pointer: the newest version of the current major line (moves on every version save); null until the puzzle has one.","type":"object","allOf":[{"$ref":"#/components/schemas/PublicationVersionRefDto"}]},"settings":{"description":"This publication’s own settings (only the fields it sets).","allOf":[{"$ref":"#/components/schemas/PublicationSettingsDto"}]},"embedPolicy":{"$ref":"#/components/schemas/EmbedPolicyDto"},"slug":{"type":"string","nullable":true,"description":"Canonical URL slug (`/@owner/<game>/<slug>`); old slugs redirect to it."},"revision":{"type":"number","description":"Also sent as the ETag (for PATCH)."},"publishedAt":{"type":"string","nullable":true},"archivedAt":{"type":"string","nullable":true},"createdBy":{"type":"string","format":"uuid"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"effectiveSettings":{"$ref":"#/components/schemas/EffectiveSettingsDto"},"canonicalPath":{"type":"string","nullable":true,"example":"/@acme/crossword/sunday-special","description":"The canonical human URL path (whatever the status; it resolves publicly only while published and public): the series/date URL for edition puzzles. null when the owner has no live handle."}},"required":["id","puzzleId","owner","status","moderationStatus","visibility","accessMode","mode","currentMajor","currentVersion","settings","embedPolicy","slug","revision","publishedAt","archivedAt","createdBy","createdAt","updatedAt","effectiveSettings","canonicalPath"]},"PublicationSummaryDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"owner":{"$ref":"#/components/schemas/PublicationOwnerDto"},"status":{"type":"string","enum":["unpublished","published","archived"]},"moderationStatus":{"type":"string","enum":["ok","taken_down"]},"visibility":{"type":"string","enum":["public","unlisted","private"]},"accessMode":{"type":"string","enum":["standalone","embed","both"]},"mode":{"type":"string","enum":["casual","competitive"]},"currentMajor":{"type":"number","description":"The engine major line the pointer follows."},"currentVersion":{"nullable":true,"description":"The pointer: the newest version of the current major line (moves on every version save); null until the puzzle has one.","type":"object","allOf":[{"$ref":"#/components/schemas/PublicationVersionRefDto"}]},"settings":{"description":"This publication’s own settings (only the fields it sets).","allOf":[{"$ref":"#/components/schemas/PublicationSettingsDto"}]},"embedPolicy":{"$ref":"#/components/schemas/EmbedPolicyDto"},"slug":{"type":"string","nullable":true,"description":"Canonical URL slug (`/@owner/<game>/<slug>`); old slugs redirect to it."},"revision":{"type":"number","description":"Also sent as the ETag (for PATCH)."},"publishedAt":{"type":"string","nullable":true},"archivedAt":{"type":"string","nullable":true},"createdBy":{"type":"string","format":"uuid"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","puzzleId","owner","status","moderationStatus","visibility","accessMode","mode","currentMajor","currentVersion","settings","embedPolicy","slug","revision","publishedAt","archivedAt","createdBy","createdAt","updatedAt"]},"PublicationPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicationSummaryDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"UpdatePublicationDto":{"type":"object","properties":{"visibility":{"type":"string","enum":["public","unlisted","private"]},"accessMode":{"type":"string","enum":["standalone","embed","both"],"description":"`embed` and `both` need the `embeds_enabled` entitlement."},"mode":{"type":"string","enum":["casual","competitive"]},"settings":{"description":"Replaces the publication's settings as a whole (omitted fields inherit).","allOf":[{"$ref":"#/components/schemas/PublicationSettingsDto"}]},"embedPolicy":{"description":"Embed policy (E09-T05). Sites allowed to embed are `settings.embedDomains`.","allOf":[{"$ref":"#/components/schemas/EmbedPolicyDto"}]},"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":80,"description":"New URL slug; the previous one keeps redirecting (301). 409 `PUBLICATION_SLUG_TAKEN`, 422 `PUBLICATION_SLUG_RESERVED`."}}},"PlayChecksSettingsDto":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether this caller's payload carries check hashes (`protection`), so entries are checked and completion detected locally. False in competitive mode, for games without checks, and on private publications for players without `puzzle:read-solution` (they play without local checks)."}},"required":["enabled"]},"PlayHintsSettingsDto":{"type":"object","properties":{"enabled":{"type":"boolean"},"maxPerPlay":{"type":"number","nullable":true,"description":"null = unlimited."}},"required":["enabled","maxPerPlay"]},"PlayRevealSettingsDto":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Casual reveal (`POST /v1/publications/:id/reveal`, online only). Follows `hintsEnabled`; false in competitive mode and whenever `checks.enabled` is false."}},"required":["enabled"]},"PlaySettingsResponseDto":{"type":"object","properties":{"showTimer":{"type":"boolean","description":"Show the running timer (time is measured either way)."},"allowPause":{"type":"boolean","description":"Always false in competitive mode."},"allowRestart":{"type":"boolean","description":"Always false in competitive mode."},"allowAbandon":{"type":"boolean"},"checks":{"$ref":"#/components/schemas/PlayChecksSettingsDto"},"hints":{"description":"Hints need the checks: off whenever `checks.enabled` is.","allOf":[{"$ref":"#/components/schemas/PlayHintsSettingsDto"}]},"reveal":{"$ref":"#/components/schemas/PlayRevealSettingsDto"},"highlightConflicts":{"type":"boolean","description":"Highlight cells that break the rules (needs no solution)."}},"required":["showTimer","allowPause","allowRestart","allowAbandon","checks","hints","reveal","highlightConflicts"]},"PlayThemeDto":{"type":"object","properties":{"accentColor":{"type":"string","nullable":true,"example":"#1d4ed8"},"colorScheme":{"type":"string","enum":["auto","light","dark"]},"brandImageUrl":{"type":"string","nullable":true}},"required":["accentColor","colorScheme","brandImageUrl"]},"PlayEmbedTokenDto":{"type":"object","properties":{"origin":{"type":"string","example":"https://news.example.com"},"path":{"type":"string","example":"/puzzles/today"},"expiresAt":{"type":"string","format":"date-time"}},"required":["origin","path","expiresAt"]},"PlayEmbedDto":{"type":"object","properties":{"requireToken":{"type":"boolean","description":"The publication requires embed tokens (`embedPolicy.requireToken`)."},"frameAncestors":{"example":["'none'"],"description":"The play document's `Content-Security-Policy: frame-ancestors` sources, joined with spaces: `'none'` (standalone-only, no allowed site, or a token is required but none was sent), `*` (any site), allowed host sources (`news.example.com`, `*.example.com`), or exactly the verified token's origin.","type":"array","items":{"type":"string"}},"token":{"nullable":true,"description":"The verified `X-Embed-Token` binding; null without one.","type":"object","allOf":[{"$ref":"#/components/schemas/PlayEmbedTokenDto"}]}},"required":["requireToken","frameAncestors","token"]},"PlayPointerResponseDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"versionId":{"type":"string","format":"uuid","description":"The version the publication points at now (moves on every version save)."},"versionLabel":{"type":"string","example":"1.3"},"gameType":{"type":"string","example":"crossword"},"engineMajor":{"type":"number","description":"Engine major of the version (state compatibility line)."},"mode":{"type":"string","enum":["casual","competitive"]},"title":{"type":"string"},"contentLanguage":{"type":"string","description":"BCP 47 language of the content."},"settings":{"$ref":"#/components/schemas/PlaySettingsResponseDto"},"visibility":{"type":"string","enum":["public","unlisted","private"]},"accessMode":{"type":"string","enum":["standalone","embed","both"],"description":"Where it may be played: the play host enforces it (E09-T07)."},"embedDomains":{"nullable":true,"description":"Effective embed allow-list for `frame-ancestors`: null = any site, [] = none.","type":"array","items":{"type":"string"}},"theme":{"$ref":"#/components/schemas/PlayThemeDto"},"canonicalPath":{"type":"string","nullable":true,"example":"/@acme/crossword/sunday-special","description":"Canonical human URL path; null unless the publication is public."},"payloadPath":{"type":"string","example":"/v1/versions/0192…/payload","description":"Path of the version payload for this publication's mode (`?mode=competitive` for competitive ones)."},"embed":{"$ref":"#/components/schemas/PlayEmbedDto"}},"required":["publicationId","versionId","versionLabel","gameType","engineMajor","mode","title","contentLanguage","settings","visibility","accessMode","embedDomains","theme","canonicalPath","payloadPath","embed"]},"PayloadProtectionDto":{"type":"object","properties":{"scheme":{"type":"string","example":"hmac-sha256-64"},"salt":{"type":"string","description":"Salt of the major line (not a secret)."},"checks":{"type":"object","additionalProperties":{"type":"string"},"description":"Check hash per answer position (decimal index)."}},"required":["scheme","salt","checks"]},"VersionPayloadResponseDto":{"type":"object","properties":{"versionId":{"type":"string","format":"uuid"},"versionLabel":{"type":"string","example":"1.3"},"gameType":{"type":"string","example":"crossword"},"engineMajor":{"type":"number"},"mode":{"type":"string","enum":["casual","competitive"]},"definition":{"type":"object","additionalProperties":true,"description":"The public definition; parse it with the game's `definitionSchema`."},"protection":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/PayloadProtectionDto"}]},"contentLanguage":{"type":"string"}},"required":["versionId","versionLabel","gameType","engineMajor","mode","definition","protection","contentLanguage"]},"PublicPuzzlePageDto":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string","nullable":true},"gameType":{"type":"string"},"contentLanguage":{"type":"string"},"difficulty":{"type":"string","enum":["easy","medium","hard","expert"],"nullable":true},"publishedAt":{"type":"string"}},"required":["title","description","gameType","contentLanguage","difficulty","publishedAt"]},"PublicUrlResponseDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"canonicalPath":{"type":"string","example":"/@acme/crossword/sunday-special"},"redirect":{"type":"boolean","description":"The requested path is an old or non-canonical one (old slug, old handle, other casing): answer it with a 301 to `canonicalPath`."},"page":{"$ref":"#/components/schemas/PublicPuzzlePageDto"}},"required":["publicationId","canonicalPath","redirect","page"]},"CreateEmbedTokenDto":{"type":"object","properties":{"origin":{"type":"string","example":"https://news.example.com","maxLength":2048,"description":"The exact origin of the page that will embed the puzzle (`scheme://host[:port]`, lower case, no default port, no path). https only in production. Its host must be allowed by the publication’s effective `embedDomains`; the iframe will only render under this origin."},"path":{"type":"string","example":"/puzzles/today","maxLength":512,"description":"The publisher page path the token is for (no query or fragment). Browsers can’t enforce it: it records the page the publisher’s backend chose to mint the token on."},"expiresInSeconds":{"type":"number","minimum":60,"maximum":600,"default":300,"description":"Token lifetime in seconds (at most 10 minutes)."}},"required":["origin","path"]},"EmbedTokenResponseDto":{"type":"object","properties":{"token":{"type":"string","description":"ES256 JWT (`iss`, `aud` = `puzzle-platform:embed`, `sub` = publication id, `origin`, `path`, `iat`, `exp`, `jti`). Verify with `GET /v1/embed-tokens/jwks`."},"publicationId":{"type":"string","format":"uuid"},"origin":{"type":"string","example":"https://news.example.com"},"path":{"type":"string","example":"/puzzles/today"},"expiresAt":{"type":"string","format":"date-time"}},"required":["token","publicationId","origin","path","expiresAt"]},"EmbedTokenJwkDto":{"type":"object","properties":{"kty":{"type":"string","enum":["EC"]},"crv":{"type":"string","enum":["P-256"]},"x":{"type":"string"},"y":{"type":"string"},"kid":{"type":"string","description":"RFC 7638 thumbprint; the token header’s `kid`."},"alg":{"type":"string","enum":["ES256"]},"use":{"type":"string","enum":["sig"]}},"required":["kty","crv","x","y","kid","alg","use"]},"EmbedTokenJwksResponseDto":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/EmbedTokenJwkDto"}}},"required":["keys"]},"CreateAccessGrantDto":{"type":"object","properties":{"handle":{"type":"string","example":"ada","description":"The `@handle` (a leading `@` is ignored) of the account, or of the organization whose current members get access."},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"When the access ends (future, at most 5 years); omit or null for no expiry."}},"required":["handle"]},"AccessGranteeDto":{"type":"object","properties":{"type":{"type":"string","enum":["user","org"]},"id":{"type":"string","format":"uuid"},"handle":{"type":"string","nullable":true,"description":"Current username or organization slug."}},"required":["type","id","handle"]},"AccessGrantResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"publicationId":{"type":"string","format":"uuid"},"grantee":{"$ref":"#/components/schemas/AccessGranteeDto"},"expiresAt":{"type":"string","format":"date-time","nullable":true},"active":{"type":"boolean","description":"false once expired."},"createdBy":{"type":"string","format":"uuid"},"createdAt":{"type":"string"}},"required":["id","publicationId","grantee","expiresAt","active","createdBy","createdAt"]},"AccessGrantPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AccessGrantResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"SearchOwnerDto":{"type":"object","properties":{"kind":{"type":"string","enum":["user","org"]},"handle":{"type":"string","description":"The `/@handle` of the user or organization."},"displayName":{"type":"string","nullable":true,"description":"The organization name or the user display name; null when the user keeps their profile private."}},"required":["kind","handle","displayName"]},"PuzzleSearchResultDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"canonicalPath":{"type":"string","example":"/@ana/crossword/sunday-special"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"gameType":{"type":"string"},"language":{"type":"string","description":"The puzzle language (BCP 47)."},"difficulty":{"type":"string","enum":["easy","medium","hard","expert"],"nullable":true},"tags":{"type":"array","items":{"type":"string"}},"publishedAt":{"type":"string","format":"date-time"},"owner":{"$ref":"#/components/schemas/SearchOwnerDto"}},"required":["publicationId","canonicalPath","title","description","gameType","language","difficulty","tags","publishedAt","owner"]},"PuzzleSearchPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PuzzleSearchResultDto"}},"nextCursor":{"type":"string","nullable":true,"description":"Opaque cursor of the next page (null on the last). Cursors belong to the sort they came from (another sort answers 400 `INVALID_CURSOR`)."}},"required":["data","nextCursor"]},"ProfileSearchResultDto":{"type":"object","properties":{"kind":{"type":"string","enum":["user","org"]},"id":{"type":"string","format":"uuid"},"handle":{"type":"string"},"displayName":{"type":"string","description":"Display name or organization name."},"avatarUrl":{"type":"string","nullable":true},"profilePath":{"type":"string","example":"/@ana"}},"required":["kind","id","handle","displayName","avatarUrl","profilePath"]},"ProfileSearchPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProfileSearchResultDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"StartImpersonationDto":{"type":"object","properties":{"targetUserId":{"type":"string","format":"uuid","description":"The user to act as."},"reason":{"type":"string","minLength":10,"maxLength":500,"description":"Why (e.g. the support ticket). Required; stored with the session and in the audit log."},"durationMinutes":{"type":"number","minimum":1,"maximum":30,"default":30,"description":"Lifetime in minutes (at most 30)."}},"required":["targetUserId","reason"]},"ImpersonationResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"staffUserId":{"type":"string","format":"uuid"},"targetUserId":{"type":"string","format":"uuid"},"reason":{"type":"string"},"startedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time","description":"The session stops working at this time (at most 30 minutes after the start)."},"endedAt":{"type":"string","format":"date-time","nullable":true},"endReason":{"type":"string","enum":["ended","session_ended","expired"],"nullable":true}},"required":["id","staffUserId","targetUserId","reason","startedAt","expiresAt","endedAt","endReason"]},"CurrentImpersonationResponseDto":{"type":"object","properties":{"active":{"type":"boolean"},"impersonation":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ImpersonationResponseDto"}]}},"required":["active","impersonation"]},"EndImpersonationResponseDto":{"type":"object","properties":{"staffSessionRestored":{"type":"boolean","description":"Whether the staff member is signed back into their own session (from the staff refresh cookie set at the start). False: they must sign in again."}},"required":["staffSessionRestored"]},"AdminUserSummaryDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"username":{"type":"string"},"displayName":{"type":"string"},"status":{"type":"string","enum":["active","suspended"]},"staffRoles":{"type":"array","items":{"type":"string","enum":["support","moderator","super_admin"]}},"createdAt":{"type":"string"},"deletedAt":{"type":"string","nullable":true}},"required":["id","username","displayName","status","staffRoles","createdAt","deletedAt"]},"AdminUserPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AdminUserSummaryDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"AdminUserDetailDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"username":{"type":"string"},"displayName":{"type":"string"},"status":{"type":"string","enum":["active","suspended"]},"staffRoles":{"type":"array","items":{"type":"string","enum":["support","moderator","super_admin"]}},"createdAt":{"type":"string"},"deletedAt":{"type":"string","nullable":true},"email":{"type":"string"},"emailVerifiedAt":{"type":"string","nullable":true},"locale":{"type":"string","enum":["en","es","pt-PT"]},"updatedAt":{"type":"string"},"billing":{"description":"The plan held now and the relevant subscription (no Stripe ids).","allOf":[{"$ref":"#/components/schemas/SubscriptionResponseDto"}]}},"required":["id","username","displayName","status","staffRoles","createdAt","deletedAt","email","emailVerifiedAt","locale","updatedAt","billing"]},"AdminReasonDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500}},"required":["reason"]},"SetStaffRolesDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500},"roles":{"type":"array","description":"Replaces every staff role of the user; [] removes them all.","items":{"type":"string","enum":["support","moderator","super_admin"]}}},"required":["reason","roles"]},"RetentionSettingsResponseDto":{"type":"object","properties":{"analyticsEventsDays":{"type":"number"},"inactivePlaySessionsDays":{"type":"number"},"deletedAccountsDays":{"type":"number"},"hiddenCommentsDays":{"type":"number"},"moderationRecordsDays":{"type":"number"},"supportTicketsDays":{"type":"number"},"supportAttachmentsDays":{"type":"number"},"auditLogsDays":{"type":"number"},"webhookDeliveriesDays":{"type":"number"},"expiredSessionsDays":{"type":"number"},"exportsDays":{"type":"number"},"consentRecordsDays":{"type":"number"},"deletedOrganizationsDays":{"type":"number"},"revokedStudentsDays":{"type":"number"},"closedInvitationsDays":{"type":"number"},"notificationsDays":{"type":"number"}},"required":["analyticsEventsDays","inactivePlaySessionsDays","deletedAccountsDays","hiddenCommentsDays","moderationRecordsDays","supportTicketsDays","supportAttachmentsDays","auditLogsDays","webhookDeliveriesDays","expiredSessionsDays","exportsDays","consentRecordsDays","deletedOrganizationsDays","revokedStudentsDays","closedInvitationsDays","notificationsDays"]},"RegistrationSettingsResponseDto":{"type":"object","properties":{"mode":{"type":"string","enum":["open","allowlist"]},"allowedEmails":{"type":"array","items":{"type":"string"}}},"required":["mode","allowedEmails"]},"PlatformSettingsResponseDto":{"type":"object","properties":{"supportNotificationEmails":{"type":"array","items":{"type":"string"}},"retention":{"$ref":"#/components/schemas/RetentionSettingsResponseDto"},"registration":{"$ref":"#/components/schemas/RegistrationSettingsResponseDto"}},"required":["supportNotificationEmails","retention","registration"]},"RetentionSettingsDto":{"type":"object","properties":{"analyticsEventsDays":{"type":"number","minimum":1,"maximum":3650},"inactivePlaySessionsDays":{"type":"number","minimum":1,"maximum":3650},"deletedAccountsDays":{"type":"number","minimum":1,"maximum":3650},"hiddenCommentsDays":{"type":"number","minimum":1,"maximum":3650},"moderationRecordsDays":{"type":"number","minimum":1,"maximum":3650},"supportTicketsDays":{"type":"number","minimum":1,"maximum":3650},"supportAttachmentsDays":{"type":"number","minimum":1,"maximum":3650},"auditLogsDays":{"type":"number","minimum":365,"maximum":3650},"webhookDeliveriesDays":{"type":"number","minimum":1,"maximum":3650},"expiredSessionsDays":{"type":"number","minimum":1,"maximum":3650},"exportsDays":{"type":"number","minimum":1,"maximum":3650},"consentRecordsDays":{"type":"number","minimum":1,"maximum":3650},"deletedOrganizationsDays":{"type":"number","minimum":1,"maximum":3650},"revokedStudentsDays":{"type":"number","minimum":30,"maximum":3650},"closedInvitationsDays":{"type":"number","minimum":1,"maximum":3650},"notificationsDays":{"type":"number","minimum":1,"maximum":3650}}},"RegistrationSettingsDto":{"type":"object","properties":{"mode":{"type":"string","enum":["open","allowlist"],"description":"`open`: anyone may create an account. `allowlist`: only the addresses in `allowedEmails`."},"allowedEmails":{"maxItems":500,"description":"Replaces the allow-list (stored trimmed, lowercased and without duplicates).","type":"array","items":{"type":"string"}}}},"UpdatePlatformSettingsDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500},"supportNotificationEmails":{"maxItems":20,"description":"Replaces the list new support tickets are mailed to.","type":"array","items":{"type":"string"}},"retention":{"$ref":"#/components/schemas/RetentionSettingsDto"},"registration":{"$ref":"#/components/schemas/RegistrationSettingsDto"}},"required":["reason"]},"AuditLogSummaryDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"action":{"type":"string"},"actorUserId":{"type":"string","nullable":true,"format":"uuid"},"impersonatorUserId":{"type":"string","nullable":true,"format":"uuid"},"targetType":{"type":"string","nullable":true},"targetId":{"type":"string","nullable":true},"metadata":{"type":"object","additionalProperties":true,"description":"Sanitized when written: no secrets, tokens, emails or solutions."},"requestId":{"type":"string","nullable":true},"createdAt":{"type":"string"}},"required":["id","action","actorUserId","impersonatorUserId","targetType","targetId","metadata","requestId","createdAt"]},"AuditLogPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogSummaryDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"AuditLogResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"action":{"type":"string"},"actorUserId":{"type":"string","nullable":true,"format":"uuid"},"impersonatorUserId":{"type":"string","nullable":true,"format":"uuid"},"targetType":{"type":"string","nullable":true},"targetId":{"type":"string","nullable":true},"metadata":{"type":"object","additionalProperties":true,"description":"Sanitized when written: no secrets, tokens, emails or solutions."},"requestId":{"type":"string","nullable":true},"createdAt":{"type":"string"},"ip":{"type":"string","nullable":true}},"required":["id","action","actorUserId","impersonatorUserId","targetType","targetId","metadata","requestId","createdAt","ip"]},"PlanResponseDto":{"type":"object","properties":{"key":{"type":"string","enum":["free","creator","org_owner"]},"active":{"type":"boolean"},"entitlements":{"type":"object","additionalProperties":true},"pricedIntervals":{"description":"Billing intervals with a configured Stripe price (ids are never shown).","type":"array","items":{"type":"string"}},"updatedAt":{"type":"string"}},"required":["key","active","entitlements","pricedIntervals","updatedAt"]},"PlanListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PlanResponseDto"}}},"required":["data"]},"UpdatePlanDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500},"entitlements":{"type":"object","additionalProperties":{"type":"object","additionalProperties":true},"example":{"user":{"personal_drafts_max":200},"org":{"org_members_max":150}},"description":"Values to set per subject type (`user`, `org`); keys not named keep their value. Flags take booleans, limits non-negative integers or null (unlimited). Validated against the entitlement catalog."},"active":{"type":"boolean","description":"Paid plans only: whether Checkout sells it."}},"required":["reason"]},"EntitlementOverrideResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subjectType":{"type":"string","enum":["user","org"]},"subjectId":{"type":"string","format":"uuid"},"key":{"type":"string"},"value":{"oneOf":[{"type":"boolean"},{"type":"integer"}],"nullable":true},"reason":{"type":"string"},"grantedById":{"type":"string","format":"uuid","nullable":true},"expiresAt":{"type":"string","nullable":true},"active":{"type":"boolean","description":"Unexpired now."},"createdAt":{"type":"string"}},"required":["id","subjectType","subjectId","key","value","reason","grantedById","expiresAt","active","createdAt"]},"EntitlementOverridePageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EntitlementOverrideResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"CreateEntitlementOverrideDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500},"subjectType":{"type":"string","enum":["user","org"]},"subjectId":{"type":"string","format":"uuid","description":"A user or organization id."},"key":{"type":"string","enum":["personal_puzzles_create","personal_drafts_max","personal_published_puzzles_max","orgs_owned_max","org_published_puzzles_max","org_members_max","org_devices_max","asset_storage_bytes","embeds_enabled","api_keys_enabled","api_calls_monthly_included","api_calls_metered","analytics_enabled","analytics_extended","analytics_raw_retention_days","analytics_aggregated_retention_months","support_tickets"]},"value":{"oneOf":[{"type":"boolean"},{"type":"integer","minimum":0}],"nullable":true,"description":"Flags: boolean. Limits: a non-negative integer, or null for unlimited."},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"In the future, within 5 years; null or omitted: no expiry."}},"required":["reason","subjectType","subjectId","key","value"]},"CreateApiKeyDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"scopes":{"type":"array","description":"Permissions the key may use. You must hold each of them in the workspace; the key never grants more than you hold when it is used.","items":{"type":"string","enum":["puzzle:read","analytics:read","embed-tokens:create"]}},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"When the key stops working (at most two years); omit or null for no expiry."},"ownerOrgId":{"type":"string","format":"uuid","description":"Create an organization key; omit for a personal key."}},"required":["name","scopes"]},"ApiKeyUsageDto":{"type":"object","properties":{"periodStart":{"type":"string","format":"date-time"},"requests":{"type":"number"}},"required":["periodStart","requests"]},"ApiKeyResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"prefix":{"type":"string","description":"The key's public lookup prefix."},"maskedKey":{"type":"string","example":"pp_0123456789ab_…","description":"For display."},"scopes":{"type":"array","items":{"type":"string","enum":["puzzle:read","analytics:read","embed-tokens:create"]}},"status":{"type":"string","enum":["active","expired","revoked"]},"ownerOrgId":{"type":"string","format":"uuid","nullable":true},"createdById":{"type":"string","format":"uuid","description":"The user the key acts as: its permissions bound the key."},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time","nullable":true},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"revokedAt":{"type":"string","format":"date-time","nullable":true},"rotatedFromId":{"type":"string","format":"uuid","nullable":true},"replacedById":{"type":"string","format":"uuid","nullable":true},"usage":{"$ref":"#/components/schemas/ApiKeyUsageDto"}},"required":["id","name","prefix","maskedKey","scopes","status","ownerOrgId","createdById","createdAt","expiresAt","lastUsedAt","revokedAt","rotatedFromId","replacedById","usage"]},"ApiKeyWithSecretResponseDto":{"type":"object","properties":{"apiKey":{"$ref":"#/components/schemas/ApiKeyResponseDto"},"secret":{"type":"string","example":"pp_0123456789ab_0123…","description":"The whole key, `pp_<prefix>_<secret>`. Shown only in this response; send it as `Authorization: Bearer <key>`."}},"required":["apiKey","secret"]},"ApiKeyPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"RotateApiKeyDto":{"type":"object","properties":{"overlapMinutes":{"type":"number","minimum":0,"maximum":10080,"default":0,"description":"Minutes the old key keeps working next to the new one, so deployments can switch over (0: revoked at once; at most 7 days)."}}},"WebhookWorkspaceDto":{"type":"object","properties":{"ownerUserId":{"type":"string","format":"uuid","nullable":true,"description":"Set for personal workspaces."},"ownerOrgId":{"type":"string","format":"uuid","nullable":true,"description":"Set for organization workspaces."}},"required":["ownerUserId","ownerOrgId"]},"PublicationPublishedWebhookDataDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"versionId":{"type":"string","format":"uuid","nullable":true,"description":"The version the publication points at (null before its puzzle has a version)."},"visibility":{"type":"string","enum":["public","unlisted","private"]},"accessMode":{"type":"string","enum":["standalone","embed","both"]},"mode":{"type":"string","enum":["casual","competitive"]},"publishedAt":{"type":"string","format":"date-time"}},"required":["publicationId","puzzleId","versionId","visibility","accessMode","mode","publishedAt"]},"PublicationPublishedWebhookDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The event id, also `Puzzle-Event-Id`: the same on every retry and redelivery. Deduplicate on it."},"version":{"type":"string","enum":["1"],"description":"Contract version: fields are only added within it; anything breaking gets a new version."},"createdAt":{"type":"string","format":"date-time","description":"When the event happened."},"workspace":{"$ref":"#/components/schemas/WebhookWorkspaceDto"},"type":{"type":"string","enum":["publication.published"],"description":"A publication was published (it is playable unless moderation took it down)."},"data":{"$ref":"#/components/schemas/PublicationPublishedWebhookDataDto"}},"required":["id","version","createdAt","workspace","type","data"]},"PublicationUnpublishedWebhookDataDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"versionId":{"type":"string","format":"uuid","nullable":true,"description":"The version the publication points at (null before its puzzle has a version)."},"visibility":{"type":"string","enum":["public","unlisted","private"]},"accessMode":{"type":"string","enum":["standalone","embed","both"]},"mode":{"type":"string","enum":["casual","competitive"]},"reason":{"type":"string","enum":["unpublished","puzzle_deleted"],"description":"`unpublished` by the workspace, or `puzzle_deleted` (the publication is gone)."},"unpublishedAt":{"type":"string","format":"date-time"}},"required":["publicationId","puzzleId","versionId","visibility","accessMode","mode","reason","unpublishedAt"]},"PublicationUnpublishedWebhookDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The event id, also `Puzzle-Event-Id`: the same on every retry and redelivery. Deduplicate on it."},"version":{"type":"string","enum":["1"],"description":"Contract version: fields are only added within it; anything breaking gets a new version."},"createdAt":{"type":"string","format":"date-time","description":"When the event happened."},"workspace":{"$ref":"#/components/schemas/WebhookWorkspaceDto"},"type":{"type":"string","enum":["publication.unpublished"],"description":"A published publication stopped being published: unpublished by the workspace, or closed because its puzzle was deleted (`reason`)."},"data":{"$ref":"#/components/schemas/PublicationUnpublishedWebhookDataDto"}},"required":["id","version","createdAt","workspace","type","data"]},"PublicationArchivedWebhookDataDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"versionId":{"type":"string","format":"uuid","nullable":true,"description":"The version the publication points at (null before its puzzle has a version)."},"visibility":{"type":"string","enum":["public","unlisted","private"]},"accessMode":{"type":"string","enum":["standalone","embed","both"]},"mode":{"type":"string","enum":["casual","competitive"]},"wasPublished":{"type":"boolean","description":"It was published until archived (archiving unpublishes)."},"archivedAt":{"type":"string","format":"date-time"}},"required":["publicationId","puzzleId","versionId","visibility","accessMode","mode","wasPublished","archivedAt"]},"PublicationArchivedWebhookDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The event id, also `Puzzle-Event-Id`: the same on every retry and redelivery. Deduplicate on it."},"version":{"type":"string","enum":["1"],"description":"Contract version: fields are only added within it; anything breaking gets a new version."},"createdAt":{"type":"string","format":"date-time","description":"When the event happened."},"workspace":{"$ref":"#/components/schemas/WebhookWorkspaceDto"},"type":{"type":"string","enum":["publication.archived"],"description":"A publication was archived (`wasPublished`: it was published until then)."},"data":{"$ref":"#/components/schemas/PublicationArchivedWebhookDataDto"}},"required":["id","version","createdAt","workspace","type","data"]},"CompletionCreatedWebhookDataDto":{"type":"object","properties":{"completionId":{"type":"string","format":"uuid"},"publicationId":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"versionId":{"type":"string","format":"uuid","description":"The version played."},"mode":{"type":"string","enum":["casual","competitive"]},"verified":{"type":"boolean","description":"Competitive completions verified on the server clock (rankings)."},"verificationNote":{"type":"string","enum":["casual","offline","too_fast","deadline_passed","mode_mismatch","assisted","repeat_attempt"],"nullable":true,"description":"Why it is not verified (null when verified)."},"elapsedMs":{"type":"integer","minimum":0},"score":{"type":"number","nullable":true},"hintsUsed":{"type":"integer","minimum":0},"revealsUsed":{"type":"integer","minimum":0},"assisted":{"type":"boolean","description":"Hints or reveals were used."},"completedAt":{"type":"string","format":"date-time","description":"When the player finished (offline uploads: the device clock, checked for plausibility)."}},"required":["completionId","publicationId","puzzleId","versionId","mode","verified","verificationNote","elapsedMs","score","hintsUsed","revealsUsed","assisted","completedAt"]},"CompletionCreatedWebhookDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The event id, also `Puzzle-Event-Id`: the same on every retry and redelivery. Deduplicate on it."},"version":{"type":"string","enum":["1"],"description":"Contract version: fields are only added within it; anything breaking gets a new version."},"createdAt":{"type":"string","format":"date-time","description":"When the event happened."},"workspace":{"$ref":"#/components/schemas/WebhookWorkspaceDto"},"type":{"type":"string","enum":["completion.created"],"description":"A player completed a publication (verified against the solution on the server). Anonymous: no player identity. Not sent for school students."},"data":{"$ref":"#/components/schemas/CompletionCreatedWebhookDataDto"}},"required":["id","version","createdAt","workspace","type","data"]},"CommentCreatedWebhookDataDto":{"type":"object","properties":{"commentId":{"type":"string","format":"uuid"},"publicationId":{"type":"string","format":"uuid"},"parentCommentId":{"type":"string","format":"uuid","nullable":true,"description":"The comment replied to (null for top-level comments)."},"createdAt":{"type":"string","format":"date-time"}},"required":["commentId","publicationId","parentCommentId","createdAt"]},"CommentCreatedWebhookDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The event id, also `Puzzle-Event-Id`: the same on every retry and redelivery. Deduplicate on it."},"version":{"type":"string","enum":["1"],"description":"Contract version: fields are only added within it; anything breaking gets a new version."},"createdAt":{"type":"string","format":"date-time","description":"When the event happened."},"workspace":{"$ref":"#/components/schemas/WebhookWorkspaceDto"},"type":{"type":"string","enum":["comment.created"],"description":"A comment or reply was posted on a publication. Ids only: read the comment through the API."},"data":{"$ref":"#/components/schemas/CommentCreatedWebhookDataDto"}},"required":["id","version","createdAt","workspace","type","data"]},"PublicationTakenDownWebhookDataDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"versionId":{"type":"string","format":"uuid","nullable":true,"description":"The version the publication points at (null before its puzzle has a version)."},"visibility":{"type":"string","enum":["public","unlisted","private"]},"accessMode":{"type":"string","enum":["standalone","embed","both"]},"mode":{"type":"string","enum":["casual","competitive"]},"status":{"type":"string","enum":["unpublished","published","archived"],"description":"The lifecycle status, which moderation leaves unchanged."},"takenDownAt":{"type":"string","format":"date-time"}},"required":["publicationId","puzzleId","versionId","visibility","accessMode","mode","status","takenDownAt"]},"PublicationTakenDownWebhookDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The event id, also `Puzzle-Event-Id`: the same on every retry and redelivery. Deduplicate on it."},"version":{"type":"string","enum":["1"],"description":"Contract version: fields are only added within it; anything breaking gets a new version."},"createdAt":{"type":"string","format":"date-time","description":"When the event happened."},"workspace":{"$ref":"#/components/schemas/WebhookWorkspaceDto"},"type":{"type":"string","enum":["moderation.publication_taken_down"],"description":"Platform moderation took the publication down: it is no longer served until restored."},"data":{"$ref":"#/components/schemas/PublicationTakenDownWebhookDataDto"}},"required":["id","version","createdAt","workspace","type","data"]},"PublicationRestoredWebhookDataDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"versionId":{"type":"string","format":"uuid","nullable":true,"description":"The version the publication points at (null before its puzzle has a version)."},"visibility":{"type":"string","enum":["public","unlisted","private"]},"accessMode":{"type":"string","enum":["standalone","embed","both"]},"mode":{"type":"string","enum":["casual","competitive"]},"status":{"type":"string","enum":["unpublished","published","archived"],"description":"`published`: playable again."},"restoredAt":{"type":"string","format":"date-time"}},"required":["publicationId","puzzleId","versionId","visibility","accessMode","mode","status","restoredAt"]},"PublicationRestoredWebhookDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The event id, also `Puzzle-Event-Id`: the same on every retry and redelivery. Deduplicate on it."},"version":{"type":"string","enum":["1"],"description":"Contract version: fields are only added within it; anything breaking gets a new version."},"createdAt":{"type":"string","format":"date-time","description":"When the event happened."},"workspace":{"$ref":"#/components/schemas/WebhookWorkspaceDto"},"type":{"type":"string","enum":["moderation.publication_restored"],"description":"Platform moderation restored a publication it had taken down (`status` tells whether it is published)."},"data":{"$ref":"#/components/schemas/PublicationRestoredWebhookDataDto"}},"required":["id","version","createdAt","workspace","type","data"]},"CreateWebhookEndpointDto":{"type":"object","properties":{"url":{"type":"string","maxLength":2048,"example":"https://hooks.example.com/puzzles","description":"Where events are POSTed. https only (http is accepted outside production); no credentials, internal host names, private addresses or system ports. Redirects are never followed."},"events":{"type":"array","items":{"type":"string","enum":["publication.published","publication.unpublished","publication.archived","completion.created","comment.created","moderation.publication_taken_down","moderation.publication_restored"]}},"description":{"type":"string","nullable":true,"maxLength":200},"ownerOrgId":{"type":"string","format":"uuid","description":"Register it for an organization; omit for your personal workspace."}},"required":["url","events"]},"WebhookEndpointResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"type":"string","nullable":true},"events":{"type":"array","items":{"type":"string","enum":["publication.published","publication.unpublished","publication.archived","completion.created","comment.created","moderation.publication_taken_down","moderation.publication_restored"]}},"status":{"type":"string","enum":["active","disabled"]},"disabledReason":{"type":"string","enum":["manual","failing","owner_deleted"],"nullable":true,"description":"`manual`: disabled by a manager; `failing`: disabled after repeated failed deliveries."},"disabledAt":{"type":"string","format":"date-time","nullable":true},"consecutiveFailedDeliveries":{"type":"number","description":"Deliveries in a row that failed every attempt (reset by any success)."},"lastSuccessAt":{"type":"string","format":"date-time","nullable":true},"lastFailureAt":{"type":"string","format":"date-time","nullable":true},"ownerOrgId":{"type":"string","format":"uuid","nullable":true},"createdById":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","url","description","events","status","disabledReason","disabledAt","consecutiveFailedDeliveries","lastSuccessAt","lastFailureAt","ownerOrgId","createdById","createdAt","updatedAt"]},"WebhookEndpointWithSecretResponseDto":{"type":"object","properties":{"endpoint":{"$ref":"#/components/schemas/WebhookEndpointResponseDto"},"secret":{"type":"string","example":"whsec_…","description":"The signing secret. Shown only in this response. Verify `Puzzle-Signature: t=<unix>,v1=<hex>` as HMAC-SHA256(secret, \"<t>.<raw body>\"), compared in constant time, refusing timestamps more than 5 minutes old."}},"required":["endpoint","secret"]},"WebhookEndpointPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpointResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"UpdateWebhookEndpointDto":{"type":"object","properties":{"url":{"type":"string","maxLength":2048},"events":{"type":"array","items":{"type":"string","enum":["publication.published","publication.unpublished","publication.archived","completion.created","comment.created","moderation.publication_taken_down","moderation.publication_restored"]}},"description":{"type":"string","nullable":true,"maxLength":200},"enabled":{"type":"boolean","description":"false disables the endpoint (no deliveries); true enables it again and resets its failure count."}}},"WebhookDeliveryResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"endpointId":{"type":"string","format":"uuid"},"eventId":{"type":"string","format":"uuid","description":"The event id (`Puzzle-Event-Id`, the body `id`): the same on every attempt and redelivery; deduplicate on it."},"eventType":{"type":"string","example":"publication.published"},"status":{"type":"string","enum":["pending","succeeded","failed"],"description":"`pending` while an attempt is scheduled or running, then `succeeded` or `failed`."},"attempts":{"type":"number"},"maxAttempts":{"type":"number"},"responseCode":{"type":"number","nullable":true},"lastError":{"type":"string","enum":["http_status","redirect","timeout","dns","blocked_address","connection","tls","response_too_large","invalid_url","signing_failed","endpoint_disabled","workspace_inactive"],"nullable":true},"nextAttemptAt":{"type":"string","format":"date-time","nullable":true},"deliveredAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","endpointId","eventId","eventType","status","attempts","maxAttempts","responseCode","lastError","nextAttemptAt","deliveredAt","createdAt"]},"WebhookDeliveryPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"WebhookDeliveryAttemptDto":{"type":"object","properties":{"attempt":{"type":"number"},"manual":{"type":"boolean","description":"A manual redelivery or test."},"succeeded":{"type":"boolean"},"statusCode":{"type":"number","nullable":true},"error":{"type":"string","enum":["http_status","redirect","timeout","dns","blocked_address","connection","tls","response_too_large","invalid_url","signing_failed","endpoint_disabled","workspace_inactive"],"nullable":true},"durationMs":{"type":"number"},"attemptedAt":{"type":"string","format":"date-time"}},"required":["attempt","manual","succeeded","statusCode","error","durationMs","attemptedAt"]},"WebhookDeliveryDetailResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"endpointId":{"type":"string","format":"uuid"},"eventId":{"type":"string","format":"uuid","description":"The event id (`Puzzle-Event-Id`, the body `id`): the same on every attempt and redelivery; deduplicate on it."},"eventType":{"type":"string","example":"publication.published"},"status":{"type":"string","enum":["pending","succeeded","failed"],"description":"`pending` while an attempt is scheduled or running, then `succeeded` or `failed`."},"attempts":{"type":"number"},"maxAttempts":{"type":"number"},"responseCode":{"type":"number","nullable":true},"lastError":{"type":"string","enum":["http_status","redirect","timeout","dns","blocked_address","connection","tls","response_too_large","invalid_url","signing_failed","endpoint_disabled","workspace_inactive"],"nullable":true},"nextAttemptAt":{"type":"string","format":"date-time","nullable":true},"deliveredAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"payload":{"type":"object","additionalProperties":true,"description":"The envelope sent: `{ id, type, version, createdAt, workspace: { ownerUserId, ownerOrgId }, data }`."},"attemptLog":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryAttemptDto"}}},"required":["id","endpointId","eventId","eventType","status","attempts","maxAttempts","responseCode","lastError","nextAttemptAt","deliveredAt","createdAt","payload","attemptLog"]},"PublicProfileDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"username":{"type":"string"},"displayName":{"type":"string","nullable":true,"description":"null when the user keeps their profile private."},"avatarUrl":{"type":"string","nullable":true,"description":"null without an avatar or when the profile is private."}},"required":["id","username","displayName","avatarUrl"]},"CommentResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"publicationId":{"type":"string","format":"uuid"},"parentId":{"type":"string","format":"uuid","nullable":true,"description":"The top-level comment this replies to; null for top-level ones."},"author":{"nullable":true,"description":"null for removed comments and deleted accounts (\"deleted user\").","type":"object","allOf":[{"$ref":"#/components/schemas/PublicProfileDto"}]},"body":{"type":"string","nullable":true,"description":"Plain text: render as text, never as HTML. null for removed comments."},"spoiler":{"type":"boolean","description":"Hide behind a \"show spoiler\" control."},"status":{"type":"string","enum":["visible","hidden","deleted"]},"createdAt":{"type":"string","format":"date-time"},"editedAt":{"type":"string","format":"date-time","nullable":true},"replyCount":{"type":"number","description":"Visible replies (top-level comments; always 0 for replies)."},"editableUntil":{"type":"string","format":"date-time","nullable":true,"description":"Until when the author may edit it (only in the author's own write responses; null elsewhere)."}},"required":["id","publicationId","parentId","author","body","spoiler","status","createdAt","editedAt","replyCount","editableUntil"]},"CommentPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CommentResponseDto"}},"nextCursor":{"type":"string","nullable":true},"state":{"type":"string","enum":["open","locked","disabled"],"description":"`open`: post and reply; `locked`: read only; `disabled`: comments are off (no data)."}},"required":["data","nextCursor","state"]},"CreateCommentDto":{"type":"object","properties":{"body":{"type":"string","maxLength":4000,"description":"Plain text (never HTML: tags are removed, clients render it as text). 1–2000 characters after sanitising."},"parentId":{"type":"string","format":"uuid","description":"Reply to this top-level comment (one reply level). Omit for a top-level comment."},"spoiler":{"type":"boolean","default":false,"description":"The comment reveals answers: clients hide it until the reader opens it."}},"required":["body"]},"ReplyPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CommentResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"UpdateCommentDto":{"type":"object","properties":{"body":{"type":"string","maxLength":4000,"description":"Plain text, sanitised like new comments."},"spoiler":{"type":"boolean"}}},"HideCommentDto":{"type":"object","properties":{"reason":{"type":"string","maxLength":500}}},"NotificationResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["comment.reply","comment.hidden","moderation.publication_taken_down","moderation.publication_restored","moderation.warning","moderation.banned","moderation.ban_revoked","moderation.ban_expired","moderation.appeal_submitted","moderation.appeal_received","moderation.appeal_accepted","moderation.appeal_rejected","moderation.report_closed","organization.invitation","organization.ownership_transfer_offered","organization.frozen","support.ticket_status_changed","support.ticket_replied","integrations.webhook_endpoint_disabled","analytics.export_ready","account.password_changed"]},"category":{"type":"string","enum":["account","community","organizations","moderation","support"]},"payload":{"type":"object","additionalProperties":true,"description":"Ids and short labels for the type (see the type list in the endpoint description); never personal data or content."},"actor":{"nullable":true,"description":"Who caused it, when it was a user (null for system events or deleted accounts).","type":"object","allOf":[{"$ref":"#/components/schemas/PublicProfileDto"}]},"readAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","type","category","payload","actor","readAt","createdAt"]},"NotificationPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NotificationResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"UnreadCountResponseDto":{"type":"object","properties":{"unread":{"type":"number","description":"Unread notifications, capped at 1000."}},"required":["unread"]},"EmailPreferencesDto":{"type":"object","properties":{"account":{"type":"boolean","description":"Account and security notices (always on)."},"community":{"type":"boolean","description":"Replies to your comments (a daily digest)."},"organizations":{"type":"boolean","description":"Invitations, ownership offers, freeze notices (always on)."},"moderation":{"type":"boolean","description":"Moderation outcomes (always on)."},"support":{"type":"boolean","description":"Support ticket updates."}},"required":["account","community","organizations","moderation","support"]},"NotificationPreferencesResponseDto":{"type":"object","properties":{"email":{"$ref":"#/components/schemas/EmailPreferencesDto"},"configurable":{"description":"Categories whose email can be turned off.","type":"array","items":{"type":"string"}}},"required":["email","configurable"]},"UpdateEmailPreferencesDto":{"type":"object","properties":{"community":{"type":"boolean"},"support":{"type":"boolean"}}},"UpdateNotificationPreferencesDto":{"type":"object","properties":{"email":{"$ref":"#/components/schemas/UpdateEmailPreferencesDto"}}},"MarkAllReadResponseDto":{"type":"object","properties":{"updated":{"type":"number","description":"Notifications marked read by this call."}},"required":["updated"]},"UnsubscribeDto":{"type":"object","properties":{"token":{"type":"string","maxLength":200}},"required":["token"]},"UnsubscribeResponseDto":{"type":"object","properties":{"category":{"type":"string","description":"The category whose email is now off."}},"required":["category"]},"CreateReportDto":{"type":"object","properties":{"targetType":{"type":"string","enum":["comment","publication","puzzle","user","org"]},"targetId":{"type":"string","format":"uuid","description":"The comment, publication, puzzle, user or organization id (`org`)."},"reason":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"]},"details":{"type":"string","nullable":true,"maxLength":2000,"description":"Plain text for moderators (tags are removed), at most 1000 characters after sanitising. Required when `reason` is `other`."}},"required":["targetType","targetId","reason"]},"ReportResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"targetType":{"type":"string","enum":["comment","publication","puzzle","user","org"]},"targetId":{"type":"string","format":"uuid"},"reason":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"]},"details":{"type":"string","nullable":true},"status":{"type":"string","enum":["open","resolved","dismissed"]},"created":{"type":"boolean","description":"false when you already had an open report on this target: that report is returned (200) and nothing changed."},"createdAt":{"type":"string","format":"date-time"}},"required":["id","targetType","targetId","reason","details","status","created","createdAt"]},"RatingDistributionDto":{"type":"object","properties":{"1":{"type":"integer"},"2":{"type":"integer"},"3":{"type":"integer"},"4":{"type":"integer"},"5":{"type":"integer"}},"required":["1","2","3","4","5"]},"RatingPriorDto":{"type":"object","properties":{"mean":{"type":"number"},"weight":{"type":"integer"}},"required":["mean","weight"]},"RatingSummaryResponseDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"count":{"type":"integer"},"average":{"type":"number","nullable":true,"description":"Plain mean (two decimals); null without ratings."},"weightedAverage":{"type":"number","description":"Bayesian average: (prior.weight × prior.mean + sum) / (prior.weight + count), two decimals. Use it to rank; show `average` and `count` next to it."},"distribution":{"$ref":"#/components/schemas/RatingDistributionDto"},"prior":{"$ref":"#/components/schemas/RatingPriorDto"}},"required":["publicationId","count","average","weightedAverage","distribution","prior"]},"RatingResponseDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"value":{"type":"integer","minimum":1,"maximum":5},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["publicationId","value","createdAt","updatedAt"]},"MyRatingResponseDto":{"type":"object","properties":{"rating":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/RatingResponseDto"}]},"eligible":{"type":"boolean","description":"Whether you may rate: you started this publication (a play session; casual play needs server progress on)."}},"required":["rating","eligible"]},"RatePublicationDto":{"type":"object","properties":{"value":{"type":"integer","minimum":1,"maximum":5}},"required":["value"]},"RatingWriteResponseDto":{"type":"object","properties":{"rating":{"$ref":"#/components/schemas/RatingResponseDto"},"created":{"type":"boolean","description":"true when this request created the rating (201); false when it changed or repeated it (200)."},"summary":{"$ref":"#/components/schemas/RatingSummaryResponseDto"}},"required":["rating","created","summary"]},"CompletionCountsDto":{"type":"object","properties":{"total":{"type":"number"},"casual":{"type":"number"},"competitive":{"type":"number"},"verified":{"type":"number","description":"Server-verified competitive completions (FR-PLAY-08)."},"assisted":{"type":"number","description":"Completions with revealed answers."},"distinctPublications":{"type":"number","description":"Different publications completed."}},"required":["total","casual","competitive","verified","assisted","distinctPublications"]},"StreakDto":{"type":"object","properties":{"current":{"type":"number","description":"Consecutive days with a completion ending today or yesterday (in `timeZone`); 0 once a whole day passed without one."},"longest":{"type":"number","description":"The longest run of consecutive days."},"lastCompletedOn":{"type":"string","format":"date","nullable":true,"description":"The last day with a completion (`YYYY-MM-DD`)."}},"required":["current","longest","lastCompletedOn"]},"GameTypeStatisticsDto":{"type":"object","properties":{"gameType":{"type":"string","description":"e.g. `sudoku`."},"completions":{"$ref":"#/components/schemas/CompletionCountsDto"},"averageElapsedMs":{"type":"number","nullable":true,"description":"Average play time (ms) of completions without revealed answers; null without any."},"bestElapsedMs":{"type":"number","nullable":true,"description":"Best (lowest) play time (ms) of a completion without revealed answers, any mode."},"bestVerifiedElapsedMs":{"type":"number","nullable":true,"description":"Best play time (ms) of a verified competitive completion."},"lastCompletedAt":{"type":"string","format":"date-time","nullable":true},"streak":{"$ref":"#/components/schemas/StreakDto"}},"required":["gameType","completions","averageElapsedMs","bestElapsedMs","bestVerifiedElapsedMs","lastCompletedAt","streak"]},"PublicStatisticsDto":{"type":"object","properties":{"timeZone":{"type":"string","example":"UTC"},"today":{"type":"string","example":"2026-10-25"},"completions":{"$ref":"#/components/schemas/CompletionCountsDto"},"streak":{"$ref":"#/components/schemas/StreakDto"},"gameTypes":{"type":"array","items":{"$ref":"#/components/schemas/GameTypeStatisticsDto"}}},"required":["timeZone","today","completions","streak","gameTypes"]},"PlayerAchievementDto":{"type":"object","properties":{"id":{"type":"string","enum":["first-completion","completions-10","completions-100","completions-500","streak-3","streak-7","streak-30","streak-100","game-type-10","game-type-50","game-type-100","first-verified","verified-10","verified-50","all-rounder"],"description":"Stable id (translate it in the UI); never renamed."},"metric":{"type":"string","enum":["completions","longest_streak","game_type_completions","verified_completions","game_types"]},"gameType":{"type":"string","nullable":true,"description":"The game type of per-game achievements, else null."},"threshold":{"type":"number"},"progress":{"type":"number","description":"The current value of the metric."},"achieved":{"type":"boolean"}},"required":["id","metric","gameType","threshold","progress","achieved"]},"PlayerPositionDto":{"type":"object","properties":{"board":{"type":"string","example":"players:all:competitive"},"kind":{"type":"string","enum":["competitive","casual"]},"verified":{"type":"boolean"},"gameType":{"type":"string","nullable":true},"window":{"type":"string","enum":["daily","weekly","monthly","all_time"]},"periodStart":{"type":"string"},"rank":{"type":"number"},"completions":{"type":"number"}},"required":["board","kind","verified","gameType","window","periodStart","rank","completions"]},"PublicProfileResponseDto":{"type":"object","properties":{"kind":{"type":"string","enum":["user","org"]},"handle":{"type":"string","description":"The current username or organization slug."},"displayName":{"type":"string","description":"Display name or organization name."},"avatarUrl":{"type":"string","nullable":true,"description":"User avatar or organization brand image."},"profilePath":{"type":"string","example":"/@ana"},"statistics":{"nullable":true,"description":"Users: statistics from their completions (school organizations’ puzzles left out). Organizations: null.","type":"object","allOf":[{"$ref":"#/components/schemas/PublicStatisticsDto"}]},"achievements":{"description":"Achieved achievements only (users; empty for organizations).","type":"array","items":{"$ref":"#/components/schemas/PlayerAchievementDto"}},"rankings":{"description":"Places on best-players boards in the current period of each window (users who keep leaderboard visibility; empty otherwise).","type":"array","items":{"$ref":"#/components/schemas/PlayerPositionDto"}},"puzzles":{"description":"Newest discoverable puzzles (at most 6); the rest through `GET /v1/profiles/:handle/puzzles`.","type":"array","items":{"$ref":"#/components/schemas/PuzzleSearchResultDto"}},"morePuzzles":{"type":"boolean"}},"required":["kind","handle","displayName","avatarUrl","profilePath","statistics","achievements","rankings","puzzles","morePuzzles"]},"ProfilePuzzlesPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PuzzleSearchResultDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"CreatePlaySessionDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid","description":"The publication to play. The session pins its current version and mode."},"clientStartedAt":{"type":"string","format":"date-time","description":"When play started on the device (informational; competitive timing always uses the server clock)."}},"required":["publicationId"]},"PlaySessionResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"publicationId":{"type":"string","format":"uuid"},"versionId":{"type":"string","format":"uuid","description":"The version being played. Fetch its payload from the pointer’s `payloadPath` pattern (`/v1/versions/:versionId/payload`)."},"mode":{"type":"string","enum":["casual","competitive"]},"status":{"type":"string","enum":["active","paused","completed","abandoned"],"description":"`active ⇄ paused → completed / abandoned`."},"stateSchemaMajor":{"type":"number","description":"The game major the state belongs to (`TaggedState.stateSchemaMajor`)."},"state":{"type":"object","additionalProperties":true,"nullable":true,"description":"The engine play state (the game’s `stateSchema`). Holds only what the player entered and the answers the server revealed to them. Null only on completed sessions recorded while the player’s server progress was off (the completion is kept, the state is not)."},"revision":{"type":"number","description":"Progress revision: the `baseRevision` of the next sync."},"elapsedMs":{"type":"number"},"hintsUsed":{"type":"number"},"revealsUsed":{"type":"number"},"assisted":{"type":"boolean","description":"The server revealed answers in this session (FR-PLAY-06)."},"checksUsed":{"type":"number","description":"Competitive \"solved or not?\" probes this session used (server checks and failed completions). The budget of 3 is per player and publication, shared by all their competitive sessions of it; always 0 in casual play."},"checksRemaining":{"type":"number","nullable":true,"minimum":0,"description":"Competitive only: the competitive checks the player has left on the publication (3 per player and publication, shared by all their competitive sessions of it; server checks and failed completions use them), as of this response. Null for casual sessions (`POST …/check` reports their budget)."},"serverStartedAt":{"type":"string","format":"date-time"},"clientStartedAt":{"type":"string","format":"date-time","nullable":true},"lastSyncedAt":{"type":"string","format":"date-time","nullable":true},"pausedAt":{"type":"string","format":"date-time","nullable":true,"description":"Start of the current pause (only while `paused`)."},"endedAt":{"type":"string","format":"date-time","nullable":true,"description":"When it was completed or abandoned."},"endedReason":{"type":"string","enum":["mode_changed","too_many_attempts"],"nullable":true,"description":"Set when the server ended the session: `mode_changed` (the publication switched between casual and competitive; start a new session) or `too_many_attempts` (a competitive completion failed after every check was used). Null for the player’s own actions."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","publicationId","versionId","mode","status","stateSchemaMajor","state","revision","elapsedMs","hintsUsed","revealsUsed","assisted","checksUsed","checksRemaining","serverStartedAt","clientStartedAt","lastSyncedAt","pausedAt","endedAt","endedReason","createdAt","updatedAt"]},"SyncProgressDto":{"type":"object","properties":{"stateSchemaMajor":{"type":"number","minimum":1,"description":"The game major the state belongs to (`TaggedState.stateSchemaMajor`); must be the game’s current major."},"state":{"type":"object","additionalProperties":true,"description":"The engine play state (the game’s `stateSchema`, validated by the engine)."},"versionId":{"type":"string","format":"uuid","description":"The version the state was played on (default: the session’s `versionId`). Must be a version of the publication’s current major line."},"baseRevision":{"type":"number","minimum":1,"description":"The server revision this state was based on (the session’s `revision`). Alternatively send `If-Match: \"<revision>\"`; one of the two is required (428), and both must agree."},"clientMutationId":{"type":"string","minLength":1,"maxLength":100,"description":"Client id of this change. Re-sending the last applied one returns the session unchanged (a retry), whatever `baseRevision` says."},"deviceId":{"type":"string","format":"uuid","description":"The device’s `appInstanceId` (the one sent at sign-in). Recorded as the session’s last device when it is one of the player’s live devices; unknown ids are ignored. Without it (the play host can’t read the `appInstanceId`), the device the signed-in session was opened on is recorded, when there is one."}},"required":["stateSchemaMajor","state","clientMutationId"]},"PlaySessionSyncResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"publicationId":{"type":"string","format":"uuid"},"versionId":{"type":"string","format":"uuid","description":"The version being played. Fetch its payload from the pointer’s `payloadPath` pattern (`/v1/versions/:versionId/payload`)."},"mode":{"type":"string","enum":["casual","competitive"]},"status":{"type":"string","enum":["active","paused","completed","abandoned"],"description":"`active ⇄ paused → completed / abandoned`."},"stateSchemaMajor":{"type":"number","description":"The game major the state belongs to (`TaggedState.stateSchemaMajor`)."},"state":{"type":"object","additionalProperties":true,"nullable":true,"description":"The engine play state (the game’s `stateSchema`). Holds only what the player entered and the answers the server revealed to them. Null only on completed sessions recorded while the player’s server progress was off (the completion is kept, the state is not)."},"revision":{"type":"number","description":"Progress revision: the `baseRevision` of the next sync."},"elapsedMs":{"type":"number"},"hintsUsed":{"type":"number"},"revealsUsed":{"type":"number"},"assisted":{"type":"boolean","description":"The server revealed answers in this session (FR-PLAY-06)."},"checksUsed":{"type":"number","description":"Competitive \"solved or not?\" probes this session used (server checks and failed completions). The budget of 3 is per player and publication, shared by all their competitive sessions of it; always 0 in casual play."},"checksRemaining":{"type":"number","nullable":true,"minimum":0,"description":"Competitive only: the competitive checks the player has left on the publication (3 per player and publication, shared by all their competitive sessions of it; server checks and failed completions use them), as of this response. Null for casual sessions (`POST …/check` reports their budget)."},"serverStartedAt":{"type":"string","format":"date-time"},"clientStartedAt":{"type":"string","format":"date-time","nullable":true},"lastSyncedAt":{"type":"string","format":"date-time","nullable":true},"pausedAt":{"type":"string","format":"date-time","nullable":true,"description":"Start of the current pause (only while `paused`)."},"endedAt":{"type":"string","format":"date-time","nullable":true,"description":"When it was completed or abandoned."},"endedReason":{"type":"string","enum":["mode_changed","too_many_attempts"],"nullable":true,"description":"Set when the server ended the session: `mode_changed` (the publication switched between casual and competitive; start a new session) or `too_many_attempts` (a competitive completion failed after every check was used). Null for the player’s own actions."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"migrated":{"type":"boolean","description":"The publication moved to a newer minor version and the server carried the state over (`migrateState`: entries whose answer changed were cleared). Load the payload of the new `versionId`, replace the local state with `state` and tell the player the puzzle was updated (FR-VER-03)."}},"required":["id","publicationId","versionId","mode","status","stateSchemaMajor","state","revision","elapsedMs","hintsUsed","revealsUsed","assisted","checksUsed","checksRemaining","serverStartedAt","clientStartedAt","lastSyncedAt","pausedAt","endedAt","endedReason","createdAt","updatedAt","migrated"]},"CompletePlaySessionDto":{"type":"object","properties":{"stateSchemaMajor":{"type":"number","minimum":1,"description":"The game major the state belongs to (`TaggedState.stateSchemaMajor`); must be the game’s current major."},"state":{"type":"object","additionalProperties":true,"description":"The engine play state (the game’s `stateSchema`, validated by the engine)."},"versionId":{"type":"string","format":"uuid","description":"The version the state was played on (default: the session’s `versionId`). Must be a version of the publication’s current major line."},"clientCompletionId":{"type":"string","minLength":1,"maxLength":100,"description":"The client’s id for this completion (idempotent per player, shared with `POST /v1/completions`): send the same one if the completion may also be queued for an offline upload."}},"required":["stateSchemaMajor","state"]},"CompletionResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"playSessionId":{"type":"string","format":"uuid"},"publicationId":{"type":"string","format":"uuid"},"versionId":{"type":"string","format":"uuid","description":"The exact version played (FR-VER-05)."},"mode":{"type":"string","enum":["casual","competitive"]},"verified":{"type":"boolean","description":"Server-verified (FR-PLAY-08): competitive, server-created session, state solved per the engine, server-measured plausible time within 24 h. Only verified completions count for competitive rankings."},"verificationNote":{"type":"string","enum":["casual","offline","too_fast","deadline_passed","mode_mismatch","assisted","repeat_attempt"],"nullable":true,"description":"Why it is not verified (null when verified): `casual`, `offline` (uploaded later), `too_fast` (below the game’s plausible minimum), `deadline_passed` (more than 24 h after the server start), `mode_mismatch` (the publication changed mode), `assisted` (answers revealed)."},"elapsedMs":{"type":"number","description":"Play time in ms: measured by the server for competitive sessions, from the state otherwise."},"score":{"type":"number","nullable":true,"description":"The game’s score, for games that have one."},"hintsUsed":{"type":"number"},"revealsUsed":{"type":"number"},"assisted":{"type":"boolean","description":"The server revealed answers during the attempt."},"completedAt":{"type":"string","format":"date-time","description":"When it was completed: the server clock, or the device’s for offline uploads."},"receivedAt":{"type":"string","format":"date-time"},"clientCompletionId":{"type":"string","nullable":true}},"required":["id","playSessionId","publicationId","versionId","mode","verified","verificationNote","elapsedMs","score","hintsUsed","revealsUsed","assisted","completedAt","receivedAt","clientCompletionId"]},"CheckPlaySessionDto":{"type":"object","properties":{"stateSchemaMajor":{"type":"number","minimum":1,"description":"The game major the state belongs to (`TaggedState.stateSchemaMajor`); must be the game’s current major."},"state":{"type":"object","additionalProperties":true,"description":"The engine play state (the game’s `stateSchema`, validated by the engine)."},"versionId":{"type":"string","format":"uuid","description":"The version the state was played on (default: the session’s `versionId`). Must be a version of the publication’s current major line."}},"required":["stateSchemaMajor","state"]},"CheckPlaySessionResponseDto":{"type":"object","properties":{"solved":{"type":"boolean","description":"Whether the state solves the puzzle. Wrong entries are never identified (that would leak answers); submit with `POST …/complete` when true."},"checksRemaining":{"type":"number","description":"Server checks left in this session. Competitive: out of 3 (failed completions use them too); at 0, checks answer 409 `CHECK_LIMIT_REACHED` and a wrong completion ends the attempt. Casual without local checks: out of 50 (failed completions count too, never ending the session); at 0, checks and completion attempts answer 409 `CHECK_LIMIT_REACHED` (`scope: session`: start a new session). A daily budget of 100 per publication across your sessions applies too (`scope: daily`)."}},"required":["solved","checksRemaining"]},"DeviceSolvedCheckDto":{"type":"object","properties":{"stateSchemaMajor":{"type":"number","minimum":1,"description":"The game major the state belongs to (`TaggedState.stateSchemaMajor`); must be the game’s current major."},"state":{"type":"object","additionalProperties":true,"description":"The engine play state (the game’s `stateSchema`, validated by the engine)."},"versionId":{"type":"string","format":"uuid","description":"The version the state was played on (the payload’s `versionId`): a version of the publication’s current major line."}},"required":["stateSchemaMajor","state","versionId"]},"DeviceSolvedCheckResponseDto":{"type":"object","properties":{"solved":{"type":"boolean","description":"Whether the state solves the puzzle. Wrong entries are never identified. Devices hold no play sessions, so nothing is recorded."}},"required":["solved"]},"UploadCompletionDto":{"type":"object","properties":{"stateSchemaMajor":{"type":"number","minimum":1,"description":"The game major the state belongs to (`TaggedState.stateSchemaMajor`); must be the game’s current major."},"state":{"type":"object","additionalProperties":true,"description":"The final engine state (the game’s `stateSchema`); it must solve the version (422 `COMPLETION_NOT_SOLVED`)."},"clientCompletionId":{"type":"string","minLength":1,"maxLength":100,"description":"The client’s id for this completion: re-uploading the same one returns the stored completion (idempotent per player)."},"publicationId":{"type":"string","format":"uuid"},"versionId":{"type":"string","format":"uuid","description":"The version played (FR-VER-05): a version of the publication’s current major line (404 `PUZZLE_VERSION_NOT_FOUND` otherwise)."},"playSessionId":{"type":"string","format":"uuid","description":"The player’s server session of this game, when it had one: it is completed. Without it (or when it was abandoned meanwhile) a completed session is created."},"completedAt":{"type":"string","format":"date-time","description":"When the device completed the game. Device clocks are trusted within 5 minutes: not in the future, not older than 90 days, not before the version (or session) existed."},"startedAt":{"type":"string","format":"date-time","description":"When play started on the device; the state’s `elapsedMs` must fit between it and `completedAt`."},"deviceId":{"type":"string","format":"uuid","description":"The device’s `appInstanceId` (as in the progress sync)."}},"required":["stateSchemaMajor","state","clientCompletionId","publicationId","versionId","completedAt"]},"RevealRequestDto":{"type":"object","properties":{"versionId":{"type":"string","format":"uuid","description":"The version being played: one of the publication’s current major line (older minors still reveal)."},"positions":{"minItems":1,"maxItems":64,"uniqueItems":true,"example":["12","13","14"],"description":"Answer positions to reveal, keyed like the payload's `protection.checks` (decimal indexes): a cell or an entry, at most 64, never every answer at once.","type":"array","items":{"type":"string"}},"playSessionId":{"type":"string","format":"uuid","description":"The signed-in player’s open casual session of this publication: it counts the reveal and becomes `assisted`. Needs the session cookie (401 without it)."}},"required":["versionId","positions"]},"TextSpanDto":{"type":"object","properties":{"start":{"type":"number"},"end":{"type":"number"}},"required":["start","end"]},"RevealedAnnotationDto":{"type":"object","properties":{"direction":{"type":"string","enum":["across","down"]},"number":{"type":"number"},"explanation":{"type":"string","nullable":true},"definitionSpans":{"description":"The definition part(s) of the clue text (UTF-16 offsets).","type":"array","items":{"$ref":"#/components/schemas/TextSpanDto"}}},"required":["direction","number","explanation","definitionSpans"]},"RevealResponseDto":{"type":"object","properties":{"answers":{"type":"object","additionalProperties":{"type":"string"},"example":{"12":"A","13":"B"},"description":"The normalized answer of each requested position (what the payload’s checks hash), and nothing else."},"annotations":{"description":"Cryptic crosswords: annotations of the clues whose every cell this request revealed. Empty otherwise.","type":"array","items":{"$ref":"#/components/schemas/RevealedAnnotationDto"}}},"required":["answers","annotations"]},"HistoryPublicationDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"gameType":{"type":"string","description":"The game played, e.g. `sudoku`."},"title":{"type":"string","nullable":true,"description":"The puzzle’s title, only while you may still open it: published, not taken down and public/unlisted, or private and still readable by you; null otherwise."},"available":{"type":"boolean","description":"You may open it now (exactly when `title` is shown)."}},"required":["id","gameType","title","available"]},"PlayerSessionSummaryDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"publication":{"$ref":"#/components/schemas/HistoryPublicationDto"},"versionId":{"type":"string","format":"uuid","description":"The version being played."},"mode":{"type":"string","enum":["casual","competitive"]},"status":{"type":"string","enum":["active","paused","completed","abandoned"]},"stateSchemaMajor":{"type":"number","description":"The game major of the stored state (`TaggedState.stateSchemaMajor`)."},"revision":{"type":"number","description":"Progress revision: compare it with the device copy’s, and use it as the `baseRevision` of the next sync."},"elapsedMs":{"type":"number"},"hintsUsed":{"type":"number"},"revealsUsed":{"type":"number"},"assisted":{"type":"boolean"},"checksUsed":{"type":"number"},"serverStartedAt":{"type":"string","format":"date-time"},"lastSyncedAt":{"type":"string","format":"date-time","nullable":true},"pausedAt":{"type":"string","format":"date-time","nullable":true},"endedAt":{"type":"string","format":"date-time","nullable":true},"endedReason":{"type":"string","enum":["mode_changed","too_many_attempts"],"nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","publication","versionId","mode","status","stateSchemaMajor","revision","elapsedMs","hintsUsed","revealsUsed","assisted","checksUsed","serverStartedAt","lastSyncedAt","pausedAt","endedAt","endedReason","createdAt","updatedAt"]},"PlayerSessionPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PlayerSessionSummaryDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"PlayerCompletionDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"playSessionId":{"type":"string","format":"uuid"},"publicationId":{"type":"string","format":"uuid"},"versionId":{"type":"string","format":"uuid","description":"The exact version played (FR-VER-05)."},"mode":{"type":"string","enum":["casual","competitive"]},"verified":{"type":"boolean","description":"Server-verified (FR-PLAY-08): competitive, server-created session, state solved per the engine, server-measured plausible time within 24 h. Only verified completions count for competitive rankings."},"verificationNote":{"type":"string","enum":["casual","offline","too_fast","deadline_passed","mode_mismatch","assisted","repeat_attempt"],"nullable":true,"description":"Why it is not verified (null when verified): `casual`, `offline` (uploaded later), `too_fast` (below the game’s plausible minimum), `deadline_passed` (more than 24 h after the server start), `mode_mismatch` (the publication changed mode), `assisted` (answers revealed)."},"elapsedMs":{"type":"number","description":"Play time in ms: measured by the server for competitive sessions, from the state otherwise."},"score":{"type":"number","nullable":true,"description":"The game’s score, for games that have one."},"hintsUsed":{"type":"number"},"revealsUsed":{"type":"number"},"assisted":{"type":"boolean","description":"The server revealed answers during the attempt."},"completedAt":{"type":"string","format":"date-time","description":"When it was completed: the server clock, or the device’s for offline uploads."},"receivedAt":{"type":"string","format":"date-time"},"clientCompletionId":{"type":"string","nullable":true},"gameType":{"type":"string","description":"The game played, e.g. `sudoku`."},"publication":{"$ref":"#/components/schemas/HistoryPublicationDto"}},"required":["id","playSessionId","publicationId","versionId","mode","verified","verificationNote","elapsedMs","score","hintsUsed","revealsUsed","assisted","completedAt","receivedAt","clientCompletionId","gameType","publication"]},"PlayerCompletionPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PlayerCompletionDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"SessionCountsDto":{"type":"object","properties":{"started":{"type":"number","description":"Every server session started."},"inProgress":{"type":"number","description":"Active or paused (saved games)."},"completed":{"type":"number"},"abandoned":{"type":"number"}},"required":["started","inProgress","completed","abandoned"]},"PlayerStatisticsResponseDto":{"type":"object","properties":{"timeZone":{"type":"string","description":"The IANA time zone streak days use."},"today":{"type":"string","format":"date","description":"Today in `timeZone` (`YYYY-MM-DD`)."},"sessions":{"$ref":"#/components/schemas/SessionCountsDto"},"completions":{"$ref":"#/components/schemas/CompletionCountsDto"},"streak":{"description":"Days with a completion of any game.","allOf":[{"$ref":"#/components/schemas/StreakDto"}]},"gameTypes":{"description":"One entry per game type completed at least once, by name.","type":"array","items":{"$ref":"#/components/schemas/GameTypeStatisticsDto"}}},"required":["timeZone","today","sessions","completions","streak","gameTypes"]},"PlayerAchievementsResponseDto":{"type":"object","properties":{"data":{"description":"Every catalog achievement, achieved or not (per-game ones for each game type played), in catalog order.","type":"array","items":{"$ref":"#/components/schemas/PlayerAchievementDto"}}},"required":["data"]},"ServerProgressDeletionResponseDto":{"type":"object","properties":{"deletedSessions":{"type":"number","description":"Unfinished casual sessions deleted (active, paused and abandoned: their stored game states)."}},"required":["deletedSessions"]},"LandingRankingEntryDto":{"type":"object","properties":{"rank":{"type":"number"},"value":{"type":"number","description":"Distinct signed-in players who started or completed it (`most_played`; server-side sessions and completions, never client analytics events), trend ratio of those players (`trending`), Bayesian average (`top_rated`) or visible comments (`most_commented`)."},"puzzle":{"$ref":"#/components/schemas/PuzzleSearchResultDto"}},"required":["rank","value","puzzle"]},"LandingRankingResponseDto":{"type":"object","properties":{"list":{"type":"string","enum":["most_played","trending","top_rated","most_commented"]},"window":{"type":"string","enum":["weekly","monthly","all_time"]},"gameType":{"type":"string","nullable":true},"computedAt":{"type":"string","format":"date-time","nullable":true},"entries":{"description":"Only publications that are discoverable now; ranks may skip ones that stopped being so since the hourly run.","type":"array","items":{"$ref":"#/components/schemas/LandingRankingEntryDto"}}},"required":["list","window","gameType","computedAt","entries"]},"LeaderboardPlayerDto":{"type":"object","properties":{"username":{"type":"string"},"displayName":{"type":"string","nullable":true,"description":"Null when the player keeps their profile private."},"avatarUrl":{"type":"string","nullable":true}},"required":["username","displayName","avatarUrl"]},"LeaderboardEntryDto":{"type":"object","properties":{"rank":{"type":"number","description":"Dense rank (1…n), ties broken deterministically."},"player":{"$ref":"#/components/schemas/LeaderboardPlayerDto"},"completions":{"type":"number","description":"Results counted (1 on publication boards)."},"elapsedMs":{"type":"number","description":"Time in ms: server-measured on competitive boards, client-measured (unverified) on casual ones; summed over the results on series and player boards."},"score":{"type":"number","nullable":true},"hintsUsed":{"type":"number"},"revealsUsed":{"type":"number"},"completedAt":{"type":"string","format":"date-time"}},"required":["rank","player","completions","elapsedMs","score","hintsUsed","revealsUsed","completedAt"]},"LeaderboardResponseDto":{"type":"object","properties":{"board":{"type":"string","example":"players:sudoku:competitive"},"kind":{"type":"string","enum":["competitive","casual"]},"verified":{"type":"boolean","description":"True on competitive boards (verified, server-timed first attempts). Casual boards are unverified: show them labelled so."},"window":{"type":"string","enum":["daily","weekly","monthly","all_time"]},"periodStart":{"type":"string","example":"2026-10-19"},"computedAt":{"type":"string","format":"date-time","nullable":true,"description":"When the board was last recomputed (hourly); null without entries."},"gameType":{"type":"string","nullable":true,"description":"The game type ranked; null for every type (`players:all`)."},"publicationId":{"type":"string","format":"uuid","nullable":true},"seriesId":{"type":"string","format":"uuid","nullable":true,"description":"Series boards: the series. Publication boards: the series this edition belongs to (its board is `GET /v1/rankings/series/:id`), else null."},"seriesTitle":{"type":"string","nullable":true,"description":"Series boards: the series title (series boards exist only for series with a live, non-school owner and a public, playable edition). Null on every other board."},"entries":{"type":"array","items":{"$ref":"#/components/schemas/LeaderboardEntryDto"}}},"required":["board","kind","verified","window","periodStart","computedAt","gameType","publicationId","seriesId","seriesTitle","entries"]},"MyRankingResponseDto":{"type":"object","properties":{"board":{"type":"string"},"kind":{"type":"string","enum":["competitive","casual"]},"verified":{"type":"boolean"},"window":{"type":"string","enum":["daily","weekly","monthly","all_time"]},"periodStart":{"type":"string"},"entry":{"nullable":true,"description":"Null when you aren’t in the stored top 100, or wouldn’t be shown (leaderboard visibility off, banned).","type":"object","allOf":[{"$ref":"#/components/schemas/LeaderboardEntryDto"}]}},"required":["board","kind","verified","window","periodStart","entry"]},"ReportReasonCountsDto":{"type":"object","properties":{"spam":{"type":"integer"},"harassment":{"type":"integer"},"hate":{"type":"integer"},"sexual_content":{"type":"integer"},"violence":{"type":"integer"},"self_harm":{"type":"integer"},"illegal":{"type":"integer"},"copyright":{"type":"integer"},"impersonation":{"type":"integer"},"spoiler":{"type":"integer"},"other":{"type":"integer"}}},"ReportContextDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"authorUserId":{"type":"string","format":"uuid"}}},"ModerationOwnerDto":{"type":"object","properties":{"kind":{"type":"string","enum":["user","org"]},"id":{"type":"string","format":"uuid"},"label":{"type":"string","description":"The owner's username, or the organization's name."}},"required":["kind","id","label"]},"ModerationQueueItemResponseDto":{"type":"object","properties":{"targetType":{"type":"string","enum":["comment","publication","puzzle","user","org"]},"targetId":{"type":"string","format":"uuid"},"openReports":{"type":"integer"},"totalReports":{"type":"integer"},"reasons":{"description":"Counted reports per reason (open ones in the open queue, else all).","allOf":[{"$ref":"#/components/schemas/ReportReasonCountsDto"}]},"firstReportedAt":{"type":"string","format":"date-time"},"lastReportedAt":{"type":"string","format":"date-time"},"subjectUserId":{"type":"string","format":"uuid","nullable":true},"subjectOrgId":{"type":"string","format":"uuid","nullable":true},"context":{"$ref":"#/components/schemas/ReportContextDto"},"label":{"type":"string","nullable":true,"description":"A short label of the target: the publication's or puzzle's title, a comment excerpt (at most 140 code points, ending in `…` when cut; hidden comments included: render as text), the username or the organization's name. Null when the target is gone or its text was purged."},"owner":{"nullable":true,"description":"Publications and puzzles: their owner. Null otherwise.","type":"object","allOf":[{"$ref":"#/components/schemas/ModerationOwnerDto"}]}},"required":["targetType","targetId","openReports","totalReports","reasons","firstReportedAt","lastReportedAt","subjectUserId","subjectOrgId","context","label","owner"]},"ModerationQueuePageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ModerationQueueItemResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"ModerationPersonDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"username":{"type":"string"},"displayName":{"type":"string","nullable":true},"avatarUrl":{"type":"string","nullable":true}},"required":["id","username","displayName","avatarUrl"]},"StaffCommentDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"publicationId":{"type":"string","format":"uuid"},"parentId":{"type":"string","format":"uuid","nullable":true},"authorUserId":{"type":"string","format":"uuid"},"author":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ModerationPersonDto"}]},"body":{"type":"string","nullable":true},"spoiler":{"type":"boolean"},"status":{"type":"string","enum":["visible","hidden","deleted"]},"hiddenSource":{"type":"string","enum":["workspace","staff"],"nullable":true},"hiddenReason":{"type":"string","nullable":true},"hiddenAt":{"type":"string","format":"date-time","nullable":true},"editedAt":{"type":"string","format":"date-time","nullable":true},"deletedAt":{"type":"string","format":"date-time","nullable":true},"purgedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","publicationId","parentId","authorUserId","author","body","spoiler","status","hiddenSource","hiddenReason","hiddenAt","editedAt","deletedAt","purgedAt","createdAt"]},"StaffPublicationDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"ownerUserId":{"type":"string","format":"uuid","nullable":true},"ownerOrgId":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","enum":["unpublished","published","archived"]},"moderationStatus":{"type":"string","enum":["ok","taken_down"]},"visibility":{"type":"string","enum":["public","unlisted","private"]},"accessMode":{"type":"string","enum":["standalone","embed","both"]},"title":{"type":"string","nullable":true},"publishedAt":{"type":"string","format":"date-time","nullable":true},"canonicalPath":{"type":"string","nullable":true}},"required":["id","puzzleId","ownerUserId","ownerOrgId","status","moderationStatus","visibility","accessMode","title","publishedAt","canonicalPath"]},"StaffPublicationStateDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"puzzleId":{"type":"string","format":"uuid"},"ownerUserId":{"type":"string","format":"uuid","nullable":true},"ownerOrgId":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","enum":["unpublished","published","archived"]},"moderationStatus":{"type":"string","enum":["ok","taken_down"]},"visibility":{"type":"string","enum":["public","unlisted","private"]},"accessMode":{"type":"string","enum":["standalone","embed","both"]}},"required":["id","puzzleId","ownerUserId","ownerOrgId","status","moderationStatus","visibility","accessMode"]},"StaffPuzzleDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"ownerUserId":{"type":"string","format":"uuid","nullable":true},"ownerOrgId":{"type":"string","format":"uuid","nullable":true},"takenDownAt":{"type":"string","format":"date-time","nullable":true},"publication":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/StaffPublicationStateDto"}]}},"required":["id","title","ownerUserId","ownerOrgId","takenDownAt","publication"]},"StaffOrganizationDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"},"disabled":{"type":"boolean"}},"required":["id","slug","name","status","disabled"]},"ModerationTargetSummaryDto":{"type":"object","properties":{"exists":{"type":"boolean","description":"false when the target is gone (deleted)."},"label":{"type":"string","nullable":true,"description":"A short label of the target: the publication's or puzzle's title, a comment excerpt (at most 140 code points, ending in `…` when cut; hidden comments included: render as text), the username or the organization's name. Null when the target is gone or its text was purged."},"owner":{"nullable":true,"description":"Publications and puzzles: their owner. Null otherwise.","type":"object","allOf":[{"$ref":"#/components/schemas/ModerationOwnerDto"}]},"comment":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/StaffCommentDto"}]},"publication":{"nullable":true,"description":"The reported publication, or the commented one.","type":"object","allOf":[{"$ref":"#/components/schemas/StaffPublicationDto"}]},"puzzle":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/StaffPuzzleDto"}]},"user":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ModerationPersonDto"}]},"org":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/StaffOrganizationDto"}]}},"required":["exists","label","owner","comment","publication","puzzle","user","org"]},"StaffReportResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"targetType":{"type":"string","enum":["comment","publication","puzzle","user","org"]},"targetId":{"type":"string","format":"uuid"},"reason":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"]},"details":{"type":"string","nullable":true,"description":"Plain text; render as text."},"status":{"type":"string","enum":["open","resolved","dismissed"]},"reporterUserId":{"type":"string","format":"uuid"},"reporter":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ModerationPersonDto"}]},"subjectUserId":{"type":"string","format":"uuid","nullable":true},"subjectOrgId":{"type":"string","format":"uuid","nullable":true},"context":{"$ref":"#/components/schemas/ReportContextDto"},"resolvedAt":{"type":"string","format":"date-time","nullable":true},"resolvedById":{"type":"string","format":"uuid","nullable":true},"resolutionActionId":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","targetType","targetId","reason","details","status","reporterUserId","reporter","subjectUserId","subjectOrgId","context","resolvedAt","resolvedById","resolutionActionId","createdAt"]},"ModerationActionResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"action":{"type":"string","enum":["comment.hide","comment.restore","publication.take_down","publication.restore","puzzle.take_down","puzzle.restore","report.resolve","report.dismiss","user.warn","ban.create","ban.revoke","appeal.accept","appeal.reject"]},"targetType":{"type":"string","enum":["comment","publication","puzzle","user","org","ban","appeal"]},"targetId":{"type":"string","format":"uuid"},"reason":{"type":"string","description":"The internal reason (staff only)."},"violation":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"],"nullable":true},"reportId":{"type":"string","format":"uuid","nullable":true},"parentActionId":{"type":"string","format":"uuid","nullable":true,"description":"The takedown or restore this one followed (copies)."},"subjectUserId":{"type":"string","format":"uuid","nullable":true},"subjectOrgId":{"type":"string","format":"uuid","nullable":true},"metadata":{"type":"object","additionalProperties":true,"description":"Ids and counts (`puzzleId`, `reportsClosed`, `copiesTakenDown`, `purgedUrls`, …)."},"actorUserId":{"type":"string","format":"uuid"},"actor":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ModerationPersonDto"}]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","action","targetType","targetId","reason","violation","reportId","parentActionId","subjectUserId","subjectOrgId","metadata","actorUserId","actor","createdAt"]},"ModerationTargetDetailResponseDto":{"type":"object","properties":{"targetType":{"type":"string","enum":["comment","publication","puzzle","user","org"]},"targetId":{"type":"string","format":"uuid"},"group":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ModerationQueueItemResponseDto"}]},"target":{"$ref":"#/components/schemas/ModerationTargetSummaryDto"},"reports":{"description":"Newest first, at most 50 (more with `GET /v1/moderation/reports?filter[targetType]&filter[targetId]`).","type":"array","items":{"$ref":"#/components/schemas/StaffReportResponseDto"}},"actions":{"description":"Newest first, at most 50.","type":"array","items":{"$ref":"#/components/schemas/ModerationActionResponseDto"}}},"required":["targetType","targetId","group","target","reports","actions"]},"StaffReportPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaffReportResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"ModerationActionPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ModerationActionResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"CloseReportRequestDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500},"onlyThisReport":{"type":"boolean","description":"Optional, default false. Close only this report. By default every open report on the same target closes (the queue groups by target)."}},"required":["reason"]},"ModerationActionResultResponseDto":{"type":"object","properties":{"action":{"$ref":"#/components/schemas/ModerationActionResponseDto"},"reportsClosed":{"type":"integer"}},"required":["action","reportsClosed"]},"ModerationActionRequestDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Internal note: why. Never shown to the affected user or the reporters."},"violation":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"],"nullable":true,"description":"The rule broken, shown to the affected owner in takedown and warning notices."},"reportId":{"type":"string","format":"uuid","nullable":true,"description":"The report the action was taken from: every open report on its target is resolved too."}},"required":["reason"]},"CommentActionResponseDto":{"type":"object","properties":{"comment":{"$ref":"#/components/schemas/StaffCommentDto"},"changed":{"type":"boolean","description":"false when the comment already was in that state: nothing was recorded."},"action":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ModerationActionResponseDto"}]},"reportsClosed":{"type":"integer"}},"required":["comment","changed","action","reportsClosed"]},"PuzzleCopyResponseDto":{"type":"object","properties":{"puzzleId":{"type":"string","format":"uuid"},"takenDownAt":{"type":"string","format":"date-time","nullable":true},"publication":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/StaffPublicationStateDto"}]}},"required":["puzzleId","takenDownAt","publication"]},"PuzzleCopiesResponseDto":{"type":"object","properties":{"data":{"description":"Live copies (transitively), at most 200.","type":"array","items":{"$ref":"#/components/schemas/PuzzleCopyResponseDto"}}},"required":["data"]},"TakedownRequestDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Internal note: why. Never shown to the affected user or the reporters."},"violation":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"],"nullable":true,"description":"The rule broken, shown to the affected owner in takedown and warning notices."},"reportId":{"type":"string","format":"uuid","nullable":true,"description":"The report the action was taken from: every open report on its target is resolved too."},"includeCopies":{"type":"boolean","description":"Optional, default false. Takedown: also take down the live publications of every copy of the puzzle (clones, edition copies, transitively; see `GET /v1/moderation/publications/:id/copies`). Restore: also restore the copies the latest takedown followed (unless taken down again on their own since)."}},"required":["reason"]},"CopiesOutcomeDto":{"type":"object","properties":{"changed":{"description":"Copy puzzles changed by this request.","type":"array","items":{"type":"string"}},"unchanged":{"type":"integer"},"withoutPublication":{"type":"integer","description":"Changed copies without a publication (taken down at puzzle level only)."},"truncated":{"type":"boolean","description":"More copies than one request follows (200): repeat it to continue."}},"required":["changed","unchanged","withoutPublication","truncated"]},"TakedownResponseDto":{"type":"object","properties":{"puzzle":{"description":"The taken-down (or restored) puzzle.","allOf":[{"$ref":"#/components/schemas/StaffPuzzleDto"}]},"publication":{"nullable":true,"description":"The puzzle's live publication, or null when it has none.","type":"object","allOf":[{"$ref":"#/components/schemas/StaffPublicationDto"}]},"changed":{"type":"boolean","description":"false when the puzzle already was in that state (copies may still have changed)."},"action":{"nullable":true,"description":"null when nothing changed.","type":"object","allOf":[{"$ref":"#/components/schemas/ModerationActionResponseDto"}]},"copies":{"nullable":true,"description":"Set when `includeCopies` was sent.","type":"object","allOf":[{"$ref":"#/components/schemas/CopiesOutcomeDto"}]},"reportsClosed":{"type":"integer"}},"required":["puzzle","publication","changed","action","copies","reportsClosed"]},"WarnUserRequestDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Internal note: why. Never shown to the user."},"violation":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"],"description":"The rule broken, shown to the user."},"reportId":{"type":"string","format":"uuid","nullable":true}},"required":["reason","violation"]},"CreatePlatformBanRequestDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Internal note: why. Never shown to the banned user (staff or the organization’s admins only)."},"violation":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"],"description":"The rule broken (violation category), shown to the banned user."},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"When a temporary ban ends: at least a minute and at most 3650 days ahead (422 `BAN_EXPIRY_INVALID`). Null or absent: permanent."},"scope":{"type":"string","enum":["platform","comments","ratings","publishing"],"description":"`platform`: everything (the user is signed out everywhere and can only read their bans); `comments`, `ratings`, `publishing`: that feature everywhere."},"reportId":{"type":"string","format":"uuid","nullable":true,"description":"The report the ban was decided from: the open reports on the user and on that report's target are resolved."}},"required":["reason","violation","scope"]},"BanResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"scope":{"type":"string","enum":["platform","comments","ratings","publishing","org"],"description":"`platform`: everything but this list (and appeals); `comments`, `ratings`, `publishing`: that feature everywhere; `org`: the organization `orgId` (its workspace, membership and content)."},"orgId":{"type":"string","format":"uuid","nullable":true},"organizationName":{"type":"string","nullable":true},"violation":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"],"description":"The rule broken."},"status":{"type":"string","enum":["active","expired","revoked"]},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"Null: permanent."},"revokedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"userId":{"type":"string","format":"uuid"},"user":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ModerationPersonDto"}]},"issuer":{"type":"string","enum":["platform","organization"],"description":"`platform`: platform moderation; `organization`: the admins of `orgId`."},"reason":{"type":"string","description":"The internal reason."},"createdById":{"type":"string","format":"uuid","nullable":true,"description":"Null in organization views when platform moderation issued it (`createdByPlatform`)."},"createdBy":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ModerationPersonDto"}]},"createdByPlatform":{"type":"boolean","description":"Issued by platform moderation (organization views never name platform staff)."},"reportId":{"type":"string","format":"uuid","nullable":true},"revokedById":{"type":"string","format":"uuid","nullable":true,"description":"Null in organization views when platform moderation revoked it (`revokedByPlatform`)."},"revokedBy":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ModerationPersonDto"}]},"revokedByPlatform":{"type":"boolean","description":"Revoked by platform moderation rather than the organization admins (organization views never name platform staff)."},"revokeReason":{"type":"string","nullable":true}},"required":["id","scope","orgId","organizationName","violation","status","expiresAt","revokedAt","createdAt","userId","user","issuer","reason","createdById","createdBy","createdByPlatform","reportId","revokedById","revokedBy","revokedByPlatform","revokeReason"]},"PlatformBanResultResponseDto":{"type":"object","properties":{"ban":{"$ref":"#/components/schemas/BanResponseDto"},"action":{"$ref":"#/components/schemas/ModerationActionResponseDto"},"reportsClosed":{"type":"integer"},"sessionsRevoked":{"type":"integer","description":"Sessions signed out (platform bans only)."}},"required":["ban","action","reportsClosed","sessionsRevoked"]},"BanPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BanResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"RevokeBanRequestDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Internal note: why the ban is lifted early."}},"required":["reason"]},"BanRevocationResultResponseDto":{"type":"object","properties":{"ban":{"$ref":"#/components/schemas/BanResponseDto"},"action":{"$ref":"#/components/schemas/ModerationActionResponseDto"}},"required":["ban","action"]},"CreateOrganizationBanRequestDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Internal note: why. Never shown to the banned user (staff or the organization’s admins only)."},"violation":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"],"description":"The rule broken (violation category), shown to the banned user."},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"When a temporary ban ends: at least a minute and at most 3650 days ahead (422 `BAN_EXPIRY_INVALID`). Null or absent: permanent."},"userId":{"type":"string","format":"uuid","description":"The user to ban."}},"required":["reason","violation","userId"]},"OwnAppealResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["ban","takedown","comment_hide","warning"],"description":"`ban`, `takedown` (your content, or your organization’s), `comment_hide` (a platform moderator hid your comment) or `warning`."},"decisionType":{"type":"string","enum":["ban","moderation_action"]},"decisionId":{"type":"string","format":"uuid","description":"The ban or action id."},"banId":{"type":"string","format":"uuid","nullable":true},"actionId":{"type":"string","format":"uuid","nullable":true},"level":{"type":"string","enum":["organization","platform"],"description":"`organization`: the organization’s admins review it; `platform`: platform moderation (also the second level of organization bans)."},"parentAppealId":{"type":"string","format":"uuid","nullable":true,"description":"The rejected organization-level appeal this one escalates."},"orgId":{"type":"string","format":"uuid","nullable":true},"organizationName":{"type":"string","nullable":true},"message":{"type":"string","description":"Your text (plain text: render it as text)."},"status":{"type":"string","enum":["open","accepted","rejected"]},"resolutionNote":{"type":"string","nullable":true,"description":"The reviewer’s answer (plain text), once resolved."},"createdAt":{"type":"string","format":"date-time"},"resolvedAt":{"type":"string","format":"date-time","nullable":true},"escalatableUntil":{"type":"string","format":"date-time","nullable":true,"description":"An organization rejected it: until then you can ask platform moderation (a new appeal of the same ban). Null otherwise."}},"required":["id","kind","decisionType","decisionId","banId","actionId","level","parentAppealId","orgId","organizationName","message","status","resolutionNote","createdAt","resolvedAt","escalatableUntil"]},"AppealabilityDto":{"type":"object","properties":{"level":{"type":"string","enum":["organization","platform"],"description":"`organization`: the organization that banned you reviews it; `platform`: platform moderation."},"until":{"type":"string","format":"date-time","description":"The appeal window closes then."}},"required":["level","until"]},"OwnBanWithAppealResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"scope":{"type":"string","enum":["platform","comments","ratings","publishing","org"],"description":"`platform`: everything but this list (and appeals); `comments`, `ratings`, `publishing`: that feature everywhere; `org`: the organization `orgId` (its workspace, membership and content)."},"orgId":{"type":"string","format":"uuid","nullable":true},"organizationName":{"type":"string","nullable":true},"violation":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"],"description":"The rule broken."},"status":{"type":"string","enum":["active","expired","revoked"]},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"Null: permanent."},"revokedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"appeal":{"nullable":true,"description":"Its newest appeal (any level), or null.","type":"object","allOf":[{"$ref":"#/components/schemas/OwnAppealResponseDto"}]},"appealable":{"nullable":true,"description":"Null when it can’t be appealed now (ended, already appealed, window closed).","type":"object","allOf":[{"$ref":"#/components/schemas/AppealabilityDto"}]}},"required":["id","scope","orgId","organizationName","violation","status","expiresAt","revokedAt","createdAt","appeal","appealable"]},"OwnBanWithAppealPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OwnBanWithAppealResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"CreateAppealRequestDto":{"type":"object","properties":{"decisionType":{"type":"string","enum":["ban","moderation_action"],"description":"`ban`: one of your bans (`GET /v1/users/me/bans`); `moderation_action`: a warning, a hide of your comment or a takedown of your content (`GET /v1/users/me/moderation-decisions`)."},"decisionId":{"type":"string","format":"uuid","description":"The ban or action id."},"message":{"type":"string","minLength":1,"maxLength":2000,"description":"Why the decision should be reversed. Plain text: markup is removed (render it as text)."}},"required":["decisionType","decisionId","message"]},"OwnAppealPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OwnAppealResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"OwnModerationDecisionResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The action id (`decisionId`)."},"kind":{"type":"string","enum":["ban","takedown","comment_hide","warning"]},"action":{"type":"string","enum":["comment.hide","comment.restore","publication.take_down","publication.restore","puzzle.take_down","puzzle.restore","report.resolve","report.dismiss","user.warn","ban.create","ban.revoke","appeal.accept","appeal.reject"]},"targetType":{"type":"string","enum":["comment","publication","puzzle","user","org","ban","appeal"]},"targetId":{"type":"string","format":"uuid"},"violation":{"type":"string","enum":["spam","harassment","hate","sexual_content","violence","self_harm","illegal","copyright","impersonation","spoiler","other"],"nullable":true},"orgId":{"type":"string","format":"uuid","nullable":true,"description":"Takedowns of an organization’s content: that organization."},"organizationName":{"type":"string","nullable":true},"inForce":{"type":"boolean","description":"Whether it still applies (content still taken down, comment still hidden; warnings always)."},"createdAt":{"type":"string","format":"date-time"},"appeal":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/OwnAppealResponseDto"}]},"appealable":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/AppealabilityDto"}]}},"required":["id","kind","action","targetType","targetId","violation","orgId","organizationName","inForce","createdAt","appeal","appealable"]},"OwnModerationDecisionPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OwnModerationDecisionResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"StaffAppealResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["ban","takedown","comment_hide","warning"],"description":"`ban`, `takedown` (your content, or your organization’s), `comment_hide` (a platform moderator hid your comment) or `warning`."},"decisionType":{"type":"string","enum":["ban","moderation_action"]},"decisionId":{"type":"string","format":"uuid","description":"The ban or action id."},"banId":{"type":"string","format":"uuid","nullable":true},"actionId":{"type":"string","format":"uuid","nullable":true},"level":{"type":"string","enum":["organization","platform"],"description":"`organization`: the organization’s admins review it; `platform`: platform moderation (also the second level of organization bans)."},"parentAppealId":{"type":"string","format":"uuid","nullable":true,"description":"The rejected organization-level appeal this one escalates."},"orgId":{"type":"string","format":"uuid","nullable":true},"organizationName":{"type":"string","nullable":true},"message":{"type":"string","description":"Your text (plain text: render it as text)."},"status":{"type":"string","enum":["open","accepted","rejected"]},"resolutionNote":{"type":"string","nullable":true,"description":"The reviewer’s answer (plain text), once resolved."},"createdAt":{"type":"string","format":"date-time"},"resolvedAt":{"type":"string","format":"date-time","nullable":true},"escalatableUntil":{"type":"string","format":"date-time","nullable":true,"description":"An organization rejected it: until then you can ask platform moderation (a new appeal of the same ban). Null otherwise."},"userId":{"type":"string","format":"uuid"},"user":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ModerationPersonDto"}]},"resolvedById":{"type":"string","format":"uuid","nullable":true},"resolvedBy":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ModerationPersonDto"}]},"resolutionActionId":{"type":"string","format":"uuid","nullable":true,"description":"The `appeal.accept|reject` moderation action (staff resolutions)."},"resolvedByPlatform":{"type":"boolean","description":"Resolved by platform staff (organization views never name them: `resolvedById` and `resolvedBy` are null there)."},"staffResolvableAt":{"type":"string","format":"date-time","nullable":true,"description":"Open appeals: from when platform staff may resolve it (platform level: at once; organization level: 14 days after it was filed, or at once when the organization is disabled or deleted; their answer is then final). Null once resolved and in organization views."}},"required":["id","kind","decisionType","decisionId","banId","actionId","level","parentAppealId","orgId","organizationName","message","status","resolutionNote","createdAt","resolvedAt","escalatableUntil","userId","user","resolvedById","resolvedBy","resolutionActionId","resolvedByPlatform","staffResolvableAt"]},"StaffAppealPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaffAppealResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"AppealDecisionDetailDto":{"type":"object","properties":{"inForce":{"type":"boolean","description":"Whether it still applies."},"ban":{"nullable":true,"description":"Ban appeals.","type":"object","allOf":[{"$ref":"#/components/schemas/BanResponseDto"}]},"action":{"nullable":true,"description":"Appeals of a warning, comment hide or takedown (staff only).","type":"object","allOf":[{"$ref":"#/components/schemas/ModerationActionResponseDto"}]}},"required":["inForce","ban","action"]},"StaffAppealDetailResponseDto":{"type":"object","properties":{"appeal":{"$ref":"#/components/schemas/StaffAppealResponseDto"},"decision":{"$ref":"#/components/schemas/AppealDecisionDetailDto"},"parent":{"nullable":true,"description":"The rejected organization-level appeal this one escalates.","type":"object","allOf":[{"$ref":"#/components/schemas/StaffAppealResponseDto"}]}},"required":["appeal","decision","parent"]},"ResolveAppealRequestDto":{"type":"object","properties":{"note":{"type":"string","minLength":1,"maxLength":500,"description":"The answer, shown to the appellant (never who wrote it) and kept as the reason of the reversal. Plain text."}},"required":["note"]},"AppealResolutionResponseDto":{"type":"object","properties":{"appeal":{"$ref":"#/components/schemas/StaffAppealResponseDto"},"action":{"description":"The `appeal.accept|reject` action.","allOf":[{"$ref":"#/components/schemas/ModerationActionResponseDto"}]},"reversed":{"type":"boolean","description":"Accepted: the decision was undone now (false when it had already ended). Always false for rejections."},"reversalActionId":{"type":"string","format":"uuid","nullable":true,"description":"The action that undid it (`ban.revoke`, `publication.restore`, `puzzle.restore`, `comment.restore`); null for warnings and when nothing was undone."}},"required":["appeal","action","reversed","reversalActionId"]},"OrganizationAppealDetailResponseDto":{"type":"object","properties":{"appeal":{"$ref":"#/components/schemas/StaffAppealResponseDto"},"ban":{"nullable":true,"description":"The appealed ban (organization view).","type":"object","allOf":[{"$ref":"#/components/schemas/BanResponseDto"}]}},"required":["appeal","ban"]},"OrganizationAppealResolutionResponseDto":{"type":"object","properties":{"appeal":{"$ref":"#/components/schemas/StaffAppealResponseDto"},"ban":{"nullable":true,"description":"The appealed ban (organization view).","type":"object","allOf":[{"$ref":"#/components/schemas/BanResponseDto"}]},"reversed":{"type":"boolean","description":"Accepted: the ban was lifted now (false when it had already ended)."}},"required":["appeal","ban","reversed"]},"TicketContextDto":{"type":"object","properties":{"url":{"type":"string","maxLength":2048,"description":"The page the problem happened on (http or https)."},"puzzleId":{"type":"string","format":"uuid"},"publicationId":{"type":"string","format":"uuid"},"organizationId":{"type":"string","format":"uuid"}}},"CreateTicketDto":{"type":"object","properties":{"category":{"type":"string","enum":["bug","billing","account","other"],"description":"Requests to raise the organization cap or quotas (FR-SUP-04) use `billing`."},"subject":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","minLength":10,"maxLength":10000,"description":"The first message of the ticket."},"context":{"$ref":"#/components/schemas/TicketContextDto"}},"required":["category","subject","description"]},"TicketContextResponseDto":{"type":"object","properties":{"url":{"type":"string"},"puzzleId":{"type":"string","format":"uuid"},"publicationId":{"type":"string","format":"uuid"},"organizationId":{"type":"string","format":"uuid"}}},"TicketMessageResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"fromSupport":{"type":"boolean","description":"Written by support staff (else by you)."},"body":{"type":"string"},"createdAt":{"type":"string"}},"required":["id","fromSupport","body","createdAt"]},"TicketAttachmentResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"contentType":{"type":"string"},"bytes":{"type":"number"},"url":{"type":"string","description":"Signed URL, valid for a few minutes."},"urlExpiresAt":{"type":"string","nullable":true},"createdAt":{"type":"string"}},"required":["id","contentType","bytes","url","urlExpiresAt","createdAt"]},"TicketResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"category":{"type":"string","enum":["bug","billing","account","other"]},"subject":{"type":"string"},"status":{"type":"string","enum":["open","in_progress","waiting_on_user","resolved","closed"]},"context":{"$ref":"#/components/schemas/TicketContextResponseDto"},"resolvedAt":{"type":"string","nullable":true},"closedAt":{"type":"string","nullable":true},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/TicketMessageResponseDto"}},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/TicketAttachmentResponseDto"}}},"required":["id","category","subject","status","context","resolvedAt","closedAt","createdAt","updatedAt","messages","attachments"]},"TicketSummaryDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"category":{"type":"string","enum":["bug","billing","account","other"]},"subject":{"type":"string"},"status":{"type":"string","enum":["open","in_progress","waiting_on_user","resolved","closed"]},"context":{"$ref":"#/components/schemas/TicketContextResponseDto"},"resolvedAt":{"type":"string","nullable":true},"closedAt":{"type":"string","nullable":true},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","category","subject","status","context","resolvedAt","closedAt","createdAt","updatedAt"]},"TicketPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TicketSummaryDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"TicketMessageDto":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000}},"required":["body"]},"CreateTicketUploadDto":{"type":"object","properties":{"contentType":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/gif","image/avif","video/mp4","video/webm","video/quicktime"],"description":"Exact type the upload must be sent with; the bytes are checked against it on registration. Images up to 10 MB, videos up to 50 MB."},"size":{"type":"number","minimum":1,"maximum":52428800}},"required":["contentType","size"]},"TicketSignedUploadDto":{"type":"object","properties":{"method":{"type":"string","enum":["PUT"]},"url":{"type":"string","description":"Upload the file body here."},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Send every header exactly as given (they are signed)."},"expiresAt":{"type":"string"}},"required":["method","url","headers","expiresAt"]},"TicketUploadResponseDto":{"type":"object","properties":{"uploadId":{"type":"string","format":"uuid"},"contentType":{"type":"string"},"maxBytes":{"type":"number","description":"Largest accepted body in bytes."},"upload":{"$ref":"#/components/schemas/TicketSignedUploadDto"}},"required":["uploadId","contentType","maxBytes","upload"]},"RegisterTicketAttachmentDto":{"type":"object","properties":{"uploadId":{"type":"string","format":"uuid","description":"From `POST /v1/support/tickets/:id/uploads`."}},"required":["uploadId"]},"TicketUserDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"username":{"type":"string"},"displayName":{"type":"string"}},"required":["id","username","displayName"]},"StaffTicketSummaryDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"category":{"type":"string","enum":["bug","billing","account","other"]},"subject":{"type":"string"},"status":{"type":"string","enum":["open","in_progress","waiting_on_user","resolved","closed"]},"context":{"$ref":"#/components/schemas/TicketContextResponseDto"},"resolvedAt":{"type":"string","nullable":true},"closedAt":{"type":"string","nullable":true},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"requester":{"$ref":"#/components/schemas/TicketUserDto"},"assignedTo":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/TicketUserDto"}]},"lastActivityAt":{"type":"string","description":"Last activity of any kind (internal notes and assignments included); `updatedAt` is what the requester sees."}},"required":["id","category","subject","status","context","resolvedAt","closedAt","createdAt","updatedAt","requester","assignedTo","lastActivityAt"]},"StaffTicketPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaffTicketSummaryDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"StaffTicketMessageResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"author":{"$ref":"#/components/schemas/TicketUserDto"},"fromStaff":{"type":"boolean","description":"Written by staff (else by the requester)."},"internal":{"type":"boolean","description":"Staff-only note, never shown to the requester."},"body":{"type":"string"},"createdAt":{"type":"string"}},"required":["id","author","fromStaff","internal","body","createdAt"]},"StaffTicketResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"category":{"type":"string","enum":["bug","billing","account","other"]},"subject":{"type":"string"},"status":{"type":"string","enum":["open","in_progress","waiting_on_user","resolved","closed"]},"context":{"$ref":"#/components/schemas/TicketContextResponseDto"},"resolvedAt":{"type":"string","nullable":true},"closedAt":{"type":"string","nullable":true},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"requester":{"$ref":"#/components/schemas/TicketUserDto"},"assignedTo":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/TicketUserDto"}]},"lastActivityAt":{"type":"string","description":"Last activity of any kind (internal notes and assignments included); `updatedAt` is what the requester sees."},"messages":{"type":"array","items":{"$ref":"#/components/schemas/StaffTicketMessageResponseDto"}},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/TicketAttachmentResponseDto"}}},"required":["id","category","subject","status","context","resolvedAt","closedAt","createdAt","updatedAt","requester","assignedTo","lastActivityAt","messages","attachments"]},"UpdateTicketDto":{"type":"object","properties":{"status":{"type":"string","enum":["open","in_progress","waiting_on_user","resolved","closed"],"description":"Allowed moves: open → in_progress; in_progress → waiting_on_user | resolved; waiting_on_user → in_progress | resolved; resolved → closed. The requester is mailed."},"assignedToUserId":{"type":"string","format":"uuid","nullable":true,"description":"An active support staff member, or null to unassign."}}},"StaffTicketMessageDto":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000},"internal":{"type":"boolean","default":false,"description":"An internal note: visible to staff only, never to the requester, and never mailed."}},"required":["body"]},"ConsentCategoriesResponseDto":{"type":"object","properties":{"essential":{"type":"boolean","enum":[true],"description":"Always true: essential storage needs no consent."},"analytics":{"type":"boolean"}},"required":["essential","analytics"]},"ConsentRecordResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"version":{"type":"number","description":"Increments with every new choice of the subject."},"categories":{"$ref":"#/components/schemas/ConsentCategoriesResponseDto"},"policyVersion":{"type":"string"},"source":{"type":"string","enum":["banner","settings","embed_sdk"]},"recordedAt":{"type":"string"},"supersededAt":{"type":"string","nullable":true,"description":"When a later choice replaced it; null for the current one."}},"required":["id","version","categories","policyVersion","source","recordedAt","supersededAt"]},"ConsentStateResponseDto":{"type":"object","properties":{"current":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ConsentRecordResponseDto"}]},"history":{"description":"Newest first, current included; at most 50.","type":"array","items":{"$ref":"#/components/schemas/ConsentRecordResponseDto"}}},"required":["current","history"]},"ConsentCategoriesDto":{"type":"object","properties":{"analytics":{"type":"boolean","description":"Analytics identifiers (a pseudonymous player key on play events). Never pre-ticked: false unless the person chose it."}},"required":["analytics"]},"PutConsentDto":{"type":"object","properties":{"anonymousId":{"type":"string","format":"uuid","description":"Signed-out callers only: the device's random anonymous id (the web's IndexedDB `deviceId`). A device secret: anyone who knows it can read and change this device's consent. Ignored for signed-in users, whose choice is recorded on the account."},"categories":{"$ref":"#/components/schemas/ConsentCategoriesDto"},"policyVersion":{"type":"string","maxLength":100,"example":"cookies-2026-10-23-draft.1","description":"The cookie policy version the choice was made under."},"source":{"type":"string","enum":["banner","settings","embed_sdk"]}},"required":["categories","policyVersion","source"]},"DataExportResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","processing","ready","failed","expired"],"description":"`pending` → `processing` → `ready` (downloadable until `expiresAt`) → `expired`; or `failed` (request a new one)."},"createdAt":{"type":"string"},"completedAt":{"type":"string","nullable":true},"expiresAt":{"type":"string","nullable":true,"description":"When the archive is (or was) deleted."},"bytes":{"type":"number","nullable":true,"description":"Archive size in bytes."}},"required":["id","status","createdAt","completedAt","expiresAt","bytes"]},"DataExportPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DataExportResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"DataExportDownloadResponseDto":{"type":"object","properties":{"url":{"type":"string","description":"Signed URL; valid for 5 minutes."},"expiresAt":{"type":"string"}},"required":["url","expiresAt"]},"DeletionConfirmationDto":{"type":"object","properties":{"confirmation":{"type":"string","minLength":1,"maxLength":100,"description":"The handle typed by the person: the account username (account deletion) or the organization handle (organization deletion), case-insensitive, a leading `@` allowed. Anything else is 422 `DELETION_CONFIRMATION_MISMATCH`.","example":"ada"}},"required":["confirmation"]},"DeletionRequestResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subjectType":{"type":"string","enum":["user","org"]},"status":{"type":"string","enum":["scheduled","completed","canceled"],"description":"Accounts: `scheduled` (soft-deleted; personal data purged at `scheduledFor`) → `completed` (purged). Organizations: `scheduled` (frozen; deleted at `scheduledFor` unless canceled) → `completed` (deleted) or `canceled`."},"requestedAt":{"type":"string"},"scheduledFor":{"type":"string","description":"Accounts: when the purge is due. Organizations: the freeze deadline when it was requested (the organization’s `freezeDeadline` is authoritative: staff disablement pauses it)."},"completedAt":{"type":"string","nullable":true},"canceledAt":{"type":"string","nullable":true}},"required":["id","subjectType","status","requestedAt","scheduledFor","completedAt","canceledAt"]},"OrganizationDeletionStateResponseDto":{"type":"object","properties":{"deletion":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/DeletionRequestResponseDto"}]}},"required":["deletion"]},"AnalyticsEventDto":{"type":"object","properties":{"type":{"type":"string","enum":["view","start","complete","hint","reveal","abandon","client_error"]},"occurredAt":{"type":"string","format":"date-time"},"publicationId":{"type":"string","format":"uuid"},"data":{"type":"object","additionalProperties":true,"description":"Per type (strict; unknown keys drop the event): `view` {}; `start` { mode?, resumed? }; `complete` { elapsedMs, hintsUsed?, revealsUsed?, assisted?, mode? }; `hint` { count? }; `reveal` { scope? cell|word|puzzle, count? }; `abandon` { elapsedMs?, mode? }; `client_error` { source, name, message, gameType? } (stored as an allow-listed `name` or `other`, and a 16-hex `messageHash` instead of the message)."}},"required":["type","occurredAt","publicationId"]},"AnalyticsEventBatchDto":{"type":"object","properties":{"events":{"minItems":1,"maxItems":50,"type":"array","items":{"$ref":"#/components/schemas/AnalyticsEventDto"}},"anonymousId":{"type":"string","format":"uuid","description":"Signed-out players only: the device's random anonymous id (a device secret). It becomes a pseudonymous player key only while that id's consent record grants analytics; otherwise it is ignored and nothing identifies the player."},"embedOrigin":{"type":"string","maxLength":2048,"description":"Embedded play: the embedding page's origin as the runtime validated it (only `scheme://host[:port]` is kept). Client-claimed and unverified for publications played without an embed token, so origin breakdowns built on it are indicative only; with a valid `embedToken` the token's origin is recorded instead."},"embedToken":{"type":"string","maxLength":4096,"description":"Embedded play (E09-T05): the embed token from the iframe URL. Sent in the body because `navigator.sendBeacon` cannot set headers (`X-Embed-Token` is not read here). Needed for events about embed-only publications, and lets token embeds report about private ones; checked like play does (current embed policy, and `embedOrigin` when sent must equal the token origin). Its origin is what the events record."}},"required":["events"]},"AnalyticsIngestResponseDto":{"type":"object","properties":{"accepted":{"type":"number"},"rejected":{"type":"number"}},"required":["accepted","rejected"]},"AnalyticsTargetDto":{"type":"object","properties":{"type":{"type":"string","enum":["workspace","publication","puzzle","series"]},"id":{"type":"string","format":"uuid","nullable":true},"title":{"type":"string","nullable":true,"description":"The target's title: the publication's or puzzle's puzzle title, the series title (deleted ones keep theirs; '' once an account purge scrubbed it); null for the workspace."},"ownerType":{"type":"string","enum":["user","org"]},"ownerId":{"type":"string","format":"uuid"}},"required":["type","id","title","ownerType","ownerId"]},"AnalyticsReportRangeDto":{"type":"object","properties":{"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"requestedFrom":{"type":"string","format":"date"},"requestedTo":{"type":"string","format":"date"},"clamped":{"type":"boolean","description":"Whether the plan's retention or today cut the requested range."},"retentionMonths":{"type":"number","nullable":true,"description":"The plan’s aggregated retention in months (null = unlimited)."},"earliestAvailable":{"type":"string","format":"date","nullable":true},"today":{"type":"string","format":"date","description":"Today (UTC)."},"liveFrom":{"type":"string","format":"date","nullable":true,"description":"First day computed live from raw events (today and days not aggregated yet)."},"rawRetainedFrom":{"type":"string","format":"date","description":"First day whose raw events are kept (exact unique counts)."}},"required":["from","to","requestedFrom","requestedTo","clamped","retentionMonths","earliestAvailable","today","liveFrom","rawRetainedFrom"]},"MedianBucketDto":{"type":"object","properties":{"fromMs":{"type":"number"},"toMs":{"type":"number","nullable":true,"description":"null: open-ended last bucket."}},"required":["fromMs","toMs"]},"UniqueCountDto":{"type":"object","properties":{"value":{"type":"number","nullable":true,"description":"Distinct consenting players; null unless `status` is `reported`."},"status":{"type":"string","enum":["reported","suppressed","not_collected","outside_raw_retention","unavailable"],"description":"`reported`; `suppressed` (below 5, 0 included: small counts are hidden); `not_collected` (school organizations: no player identifiers); `outside_raw_retention` (a range reaching past the raw event retention: distinct counts don't add up across days); `unavailable` (no exact source: older days of several publications, the `other` origin)."}},"required":["value","status"]},"AnalyticsTotalsDto":{"type":"object","properties":{"views":{"type":"number"},"starts":{"type":"number"},"completions":{"type":"number"},"abandons":{"type":"number"},"assistedCompletions":{"type":"number","nullable":true,"description":"null in origin reports."},"hints":{"type":"number","nullable":true},"reveals":{"type":"number","nullable":true},"detailSuppressed":{"type":"boolean","description":"Fewer than 5 starts: completion times, histogram, hints, reveals and assisted completions are null (and a report's origin rows empty). Event counts stay."},"completionRate":{"type":"number","nullable":true,"description":"completions / starts."},"abandonRate":{"type":"number","nullable":true,"description":"abandons / starts."},"averageElapsedMs":{"type":"number","nullable":true},"medianElapsedMs":{"nullable":true,"description":"The completion-time bucket holding the median.","type":"object","allOf":[{"$ref":"#/components/schemas/MedianBucketDto"}]},"elapsedHistogram":{"nullable":true,"description":"Completions per time bucket; bucket i ≥ bound i−1 and < bound i of `elapsedHistogramBoundsMs`.","type":"array","items":{"type":"number"}},"uniquePlayers":{"$ref":"#/components/schemas/UniqueCountDto"},"uniqueCompleters":{"$ref":"#/components/schemas/UniqueCountDto"}},"required":["views","starts","completions","abandons","assistedCompletions","hints","reveals","detailSuppressed","completionRate","abandonRate","averageElapsedMs","medianElapsedMs","elapsedHistogram","uniquePlayers","uniqueCompleters"]},"AnalyticsDayDto":{"type":"object","properties":{"views":{"type":"number"},"starts":{"type":"number"},"completions":{"type":"number"},"abandons":{"type":"number"},"assistedCompletions":{"type":"number","nullable":true,"description":"null in origin reports."},"hints":{"type":"number","nullable":true},"reveals":{"type":"number","nullable":true},"day":{"type":"string","format":"date"},"detailSuppressed":{"type":"boolean","description":"Fewer than 5 starts: completion times, histogram, hints, reveals and assisted completions are null (and a report's origin rows empty). Event counts stay."},"averageElapsedMs":{"type":"number","nullable":true},"live":{"type":"boolean","description":"Computed live (not aggregated yet; events younger than 1 hour are not counted)."},"uniquePlayers":{"$ref":"#/components/schemas/UniqueCountDto"},"uniqueCompleters":{"$ref":"#/components/schemas/UniqueCountDto"}},"required":["views","starts","completions","abandons","assistedCompletions","hints","reveals","day","detailSuppressed","averageElapsedMs","live","uniquePlayers","uniqueCompleters"]},"AnalyticsOriginDto":{"type":"object","properties":{"origin":{"type":"string","description":"`direct`, `other` or `scheme://host[:port]`. Indicative only: without an embed token the origin is the one the client claimed (`embedOrigin`, unverified); token embeds record the token's verified origin."},"views":{"type":"number"},"starts":{"type":"number"},"completions":{"type":"number"},"abandons":{"type":"number"}},"required":["origin","views","starts","completions","abandons"]},"AnalyticsReportResponseDto":{"type":"object","properties":{"target":{"$ref":"#/components/schemas/AnalyticsTargetDto"},"range":{"$ref":"#/components/schemas/AnalyticsReportRangeDto"},"origin":{"type":"string","nullable":true,"description":"The origin filter applied."},"publicationIds":{"nullable":true,"description":"Publications counted (null = the whole workspace).","type":"array","items":{"type":"string"}},"elapsedHistogramBoundsMs":{"description":"Lower bounds (ms) of histogram buckets 1…n.","type":"array","items":{"type":"number"}},"totals":{"$ref":"#/components/schemas/AnalyticsTotalsDto"},"daily":{"description":"Every day of the range, oldest first.","type":"array","items":{"$ref":"#/components/schemas/AnalyticsDayDto"}},"origins":{"description":"`direct`, the top 25 origins by views and `other`; empty in origin reports and when the report has fewer than 5 starts.","type":"array","items":{"$ref":"#/components/schemas/AnalyticsOriginDto"}}},"required":["target","range","origin","publicationIds","elapsedHistogramBoundsMs","totals","daily","origins"]},"AnalyticsPublicationLabelDto":{"type":"object","properties":{"puzzleId":{"type":"string","format":"uuid"},"title":{"type":"string"},"gameType":{"type":"string"},"status":{"type":"string"},"visibility":{"type":"string"},"mode":{"type":"string"},"deleted":{"type":"boolean"}},"required":["puzzleId","title","gameType","status","visibility","mode","deleted"]},"AnalyticsPublicationTotalsDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"publication":{"nullable":true,"description":"null when the publication no longer exists.","type":"object","allOf":[{"$ref":"#/components/schemas/AnalyticsPublicationLabelDto"}]},"views":{"type":"number"},"starts":{"type":"number"},"completions":{"type":"number"},"abandons":{"type":"number"},"completionRate":{"type":"number","nullable":true}},"required":["publicationId","publication","views","starts","completions","abandons","completionRate"]},"AnalyticsRangeDto":{"type":"object","properties":{"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"requestedFrom":{"type":"string","format":"date"},"requestedTo":{"type":"string","format":"date"},"clamped":{"type":"boolean","description":"Whether the plan's retention or today cut the requested range."},"retentionMonths":{"type":"number","nullable":true,"description":"The plan’s aggregated retention in months (null = unlimited)."},"earliestAvailable":{"type":"string","format":"date","nullable":true},"today":{"type":"string","format":"date","description":"Today (UTC)."},"liveFrom":{"type":"string","format":"date","nullable":true,"description":"First day computed live from raw events (today and days not aggregated yet)."}},"required":["from","to","requestedFrom","requestedTo","clamped","retentionMonths","earliestAvailable","today","liveFrom"]},"AnalyticsPublicationPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsPublicationTotalsDto"}},"nextCursor":{"type":"string","nullable":true},"range":{"$ref":"#/components/schemas/AnalyticsRangeDto"}},"required":["data","nextCursor","range"]},"CreateAnalyticsExportDto":{"type":"object","properties":{"report":{"type":"string","enum":["overview","publications","publication","puzzle","series"],"description":"The report, named like its query route: `overview` (`GET /v1/analytics/overview`), `publications` (`GET /v1/analytics/publications`, every page), `publication` / `puzzle` / `series` (`GET /v1/analytics/{report}s/{targetId}`; `series` → `/series/{targetId}`)."},"format":{"type":"string","enum":["csv","json"]},"targetId":{"type":"string","format":"uuid","description":"The publication, puzzle or series (required for those reports, refused otherwise). Its workspace is the export’s."},"ownerOrgId":{"type":"string","format":"uuid","description":"`overview` and `publications` only: export this organization; omit for your personal workspace."},"from":{"type":"string","format":"date","example":"2026-10-01","description":"First UTC day (inclusive). Default: 30 days ending at `to`. Clamped to the plan's aggregated retention, like the reports."},"to":{"type":"string","format":"date","example":"2026-10-24","description":"Last UTC day (inclusive). Default and maximum: today (computed live when the file is built)."},"origin":{"type":"string","maxLength":255,"description":"Report exports only (not `publications`): `direct`, `other` or `scheme://host[:port]`, like the reports."},"sort":{"type":"string","enum":["-views","-starts","-completions","views","starts","completions"],"default":"-views","description":"`publications` only: the row order."}},"required":["report","format"]},"AnalyticsExportParametersDto":{"type":"object","properties":{"from":{"type":"string","format":"date","nullable":true},"to":{"type":"string","format":"date","nullable":true},"origin":{"type":"string","nullable":true},"sort":{"type":"string","nullable":true}},"required":["from","to","origin","sort"]},"AnalyticsExportRangeDto":{"type":"object","properties":{"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"clamped":{"type":"boolean","description":"Whether the plan's retention or today cut the requested range."}},"required":["from","to","clamped"]},"AnalyticsExportResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","processing","ready","failed","expired"],"description":"`pending` → `processing` → `ready` (downloadable until `expiresAt`) → `expired`; or `failed` (request a new one)."},"report":{"type":"string","enum":["overview","publications","publication","puzzle","series"]},"format":{"type":"string","enum":["csv","json"]},"targetId":{"type":"string","format":"uuid","nullable":true,"description":"The publication, puzzle or series of a targeted report."},"targetTitle":{"type":"string","nullable":true,"description":"The target's title now (the publication's or puzzle's puzzle title, the series title); null for workspace reports and targets the workspace no longer has."},"ownerType":{"type":"string","enum":["user","org"]},"ownerId":{"type":"string","format":"uuid"},"parameters":{"description":"As requested.","allOf":[{"$ref":"#/components/schemas/AnalyticsExportParametersDto"}]},"range":{"nullable":true,"description":"The days the file covers (set once built).","type":"object","allOf":[{"$ref":"#/components/schemas/AnalyticsExportRangeDto"}]},"rowCount":{"type":"number","nullable":true,"description":"Data rows: days of a report, or publications of a `publications` export."},"truncated":{"type":"boolean","description":"A `publications` export stopped at 10,000 rows (the busiest first with the default sort)."},"bytes":{"type":"number","nullable":true,"description":"File size in bytes."},"createdAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time","nullable":true},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"When the file is (or was) deleted."}},"required":["id","status","report","format","targetId","targetTitle","ownerType","ownerId","parameters","range","rowCount","truncated","bytes","createdAt","completedAt","expiresAt"]},"AnalyticsExportPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsExportResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"AnalyticsExportDownloadResponseDto":{"type":"object","properties":{"url":{"type":"string","description":"Signed URL; valid for 5 minutes."},"expiresAt":{"type":"string","format":"date-time"}},"required":["url","expiresAt"]},"ClaimedDeviceDto":{"type":"object","properties":{"name":{"type":"string","nullable":true},"platform":{"type":"string","nullable":true},"ipPrefix":{"type":"string","nullable":true,"example":"203.0.113.0/24","description":"Network the claim came from (IPv4 /24, IPv6 /48)."},"userAgent":{"type":"string","nullable":true}},"required":["name","platform","ipPrefix","userAgent"]},"DevicePairingResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"orgId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","claimed","approved","completed","rejected","expired"],"description":"`pending`: waiting for a device to claim the code; `claimed`: waiting for approval; `approved`: waiting for the device to pick its credential up."},"expiresAt":{"type":"string"},"claimedAt":{"type":"string","nullable":true},"claimedDevice":{"nullable":true,"description":"What the device reported when claiming; check it before approving.","type":"object","allOf":[{"$ref":"#/components/schemas/ClaimedDeviceDto"}]},"orgDeviceId":{"type":"string","format":"uuid","nullable":true,"description":"The device it pairs: set at approval, or from the start when re-pairing a rotated device."},"createdAt":{"type":"string"}},"required":["id","orgId","status","expiresAt","claimedAt","claimedDevice","orgDeviceId","createdAt"]},"DevicePairingWithCodeResponseDto":{"type":"object","properties":{"pairing":{"$ref":"#/components/schemas/DevicePairingResponseDto"},"code":{"type":"string","example":"K7QM-2XPA","description":"Enter it on the device within 10 minutes. Single use; only its keyed hash is stored."}},"required":["pairing","code"]},"DevicePairingPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DevicePairingResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"DeviceScopeResponseDto":{"type":"object","properties":{"publicationIds":{"type":"array","items":{"type":"string","format":"uuid"}},"seriesIds":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["publicationIds","seriesIds"]},"OrgDeviceResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"orgId":{"type":"string","format":"uuid"},"name":{"type":"string"},"platform":{"type":"string","nullable":true},"status":{"type":"string","enum":["awaiting_pairing","active","lapsed","revoked"],"description":"`awaiting_pairing`: approved or rotated, the device has not picked its credential up; `lapsed`: offline past `offlineUntil`, needs `reauthorize`."},"maskedCredential":{"type":"string","nullable":true,"example":"ppdc_0123456789ab_…","description":"For display; null while awaiting pairing."},"scope":{"nullable":true,"description":"null: all of the organization's published content.","type":"object","allOf":[{"$ref":"#/components/schemas/DeviceScopeResponseDto"}]},"offlineDays":{"type":"number"},"offlineUntil":{"type":"string","nullable":true,"description":"The device must sign in again before this instant (moves forward on every sign-in)."},"lastSeenAt":{"type":"string","nullable":true},"credentialIssuedAt":{"type":"string","nullable":true},"revokedAt":{"type":"string","nullable":true},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","orgId","name","platform","status","maskedCredential","scope","offlineDays","offlineUntil","lastSeenAt","credentialIssuedAt","revokedAt","createdAt","updatedAt"]},"OrgDevicePageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrgDeviceResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"DeviceScopeDto":{"type":"object","properties":{"publicationIds":{"maxItems":100,"type":"array","items":{"type":"string","format":"uuid"}},"seriesIds":{"maxItems":20,"type":"array","items":{"type":"string","format":"uuid"}}}},"ApproveDevicePairingDto":{"type":"object","properties":{"name":{"type":"string","maxLength":64},"scope":{"nullable":true,"description":"null: all of the organization's published content; otherwise only what it lists.","type":"object","allOf":[{"$ref":"#/components/schemas/DeviceScopeDto"}]},"offlineDays":{"type":"number","minimum":1,"maximum":30,"default":7,"description":"Days the device may stay offline before it must sign in again (FR-DEV-ORG-02)."},"confirmationCode":{"type":"string","example":"K7Q2XP","description":"The 6-character confirmation code shown on the device being paired (case, spaces and dashes ignored). Ask the person at the device to read it; never copy it from elsewhere."}},"required":["confirmationCode"]},"OrgDeviceSettingsDto":{"type":"object","properties":{"name":{"type":"string","maxLength":64},"scope":{"nullable":true,"description":"null: all of the organization's published content; otherwise only what it lists.","type":"object","allOf":[{"$ref":"#/components/schemas/DeviceScopeDto"}]},"offlineDays":{"type":"number","minimum":1,"maximum":30,"default":7,"description":"Days the device may stay offline before it must sign in again (FR-DEV-ORG-02)."}}},"OrgDeviceRotationResponseDto":{"type":"object","properties":{"device":{"$ref":"#/components/schemas/OrgDeviceResponseDto"},"pairing":{"$ref":"#/components/schemas/DevicePairingResponseDto"},"code":{"type":"string","example":"K7QM-2XPA","description":"Shown once."}},"required":["device","pairing","code"]},"ClaimDevicePairingDto":{"type":"object","properties":{"code":{"type":"string","example":"K7QM-2XPA","description":"The pairing code; case, spaces and dashes are ignored."},"deviceName":{"type":"string","maxLength":64,"description":"A name the admin sees when approving (e.g. \"Library kiosk\")."},"platform":{"type":"string","maxLength":32,"example":"web"}},"required":["code"]},"DevicePairingClaimResponseDto":{"type":"object","properties":{"pairingId":{"type":"string","format":"uuid"},"pairingToken":{"type":"string","description":"Secret for polling `POST /v1/device-auth/credential`; keep it until the credential arrives. Shown once."},"confirmationCode":{"type":"string","example":"K7Q2XP","description":"Show it on the device: the admin types it to approve this device (and no other)."},"expiresAt":{"type":"string","description":"The admin must approve before this instant."}},"required":["pairingId","pairingToken","confirmationCode","expiresAt"]},"PairingCredentialRequestDto":{"type":"object","properties":{"pairingId":{"type":"string","format":"uuid"},"pairingToken":{"type":"string","description":"The `pairingToken` the claim returned."}},"required":["pairingId","pairingToken"]},"DeviceSelfResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"orgId":{"type":"string","format":"uuid"},"name":{"type":"string"},"scope":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/DeviceScopeResponseDto"}]},"offlineDays":{"type":"number"},"offlineUntil":{"type":"string","nullable":true,"description":"Cached content may be played offline until then; the device must sign in again before it (FR-DEV-ORG-02)."}},"required":["id","orgId","name","scope","offlineDays","offlineUntil"]},"PairingCredentialResponseDto":{"type":"object","properties":{"status":{"type":"string","enum":["pending","approved","rejected","expired"],"description":"`pending`: poll again in a few seconds; `approved`: `credential` is here (once); `rejected`/`expired`: start over with a new code."},"credential":{"type":"string","example":"ppdc_0123456789ab_0123…","description":"Only with `approved`, once. Store it in the device; exchange it for access tokens."},"device":{"$ref":"#/components/schemas/DeviceSelfResponseDto"}},"required":["status"]},"DeviceCredentialDto":{"type":"object","properties":{"credential":{"type":"string","example":"ppdc_0123456789ab_0123…"}},"required":["credential"]},"DeviceTokenResponseDto":{"type":"object","properties":{"accessToken":{"type":"string","example":"ppdt_eyJ…","description":"Send as `Authorization: Bearer <accessToken>`, without cookies."},"tokenType":{"type":"string","enum":["Bearer"]},"expiresIn":{"type":"number","example":3600},"expiresAt":{"type":"string"},"device":{"$ref":"#/components/schemas/DeviceSelfResponseDto"}},"required":["accessToken","tokenType","expiresIn","expiresAt","device"]},"DeviceCredentialResponseDto":{"type":"object","properties":{"credential":{"type":"string","example":"ppdc_0123456789ab_0123…","description":"Shown once."},"device":{"$ref":"#/components/schemas/DeviceSelfResponseDto"}},"required":["credential","device"]},"DevicePublicationResponseDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"title":{"type":"string"},"gameType":{"type":"string"},"language":{"type":"string"},"visibility":{"type":"string","enum":["public","unlisted"]},"mode":{"type":"string","enum":["casual","competitive"]},"publishedAt":{"type":"string","nullable":true},"playPath":{"type":"string","example":"/v1/publications/0190…/play","description":"The play pointer to load."}},"required":["publicationId","title","gameType","language","visibility","mode","publishedAt","playPath"]},"DevicePublicationPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DevicePublicationResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"CreateClassDto":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"example":"Year 5 — Blue"},"joinCodeTtlMinutes":{"type":"number","minimum":15,"maximum":43200,"default":1440,"description":"How long the join code works, in minutes (15 minutes to 30 days; default one day)."}},"required":["name"]},"ClassJoinCodeStateDto":{"type":"object","properties":{"active":{"type":"boolean"},"expiresAt":{"type":"string","nullable":true,"format":"date-time"},"rotatedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["active","expiresAt","rotatedAt"]},"SchoolClassResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"organizationId":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["active","archived"]},"joinCode":{"$ref":"#/components/schemas/ClassJoinCodeStateDto"},"activeStudents":{"type":"number","description":"Students not revoked."},"assignedPublications":{"type":"number"},"createdByUserId":{"type":"string","nullable":true,"format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"archivedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","organizationId","name","status","joinCode","activeStudents","assignedPublications","createdByUserId","createdAt","updatedAt","archivedAt"]},"JoinCodeResponseDto":{"type":"object","properties":{"code":{"type":"string","example":"K7QM-2XPA","description":"Shown only in this response: stored hashed, never readable again. Rotate to get a new one."},"expiresAt":{"type":"string","format":"date-time"}},"required":["code","expiresAt"]},"CreatedClassResponseDto":{"type":"object","properties":{"class":{"$ref":"#/components/schemas/SchoolClassResponseDto"},"joinCode":{"$ref":"#/components/schemas/JoinCodeResponseDto"}},"required":["class","joinCode"]},"SchoolClassPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SchoolClassResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"JoinClassDto":{"type":"object","properties":{"joinCode":{"type":"string","example":"K7QM-2XPA","description":"The class code from the teacher (case, spaces and dashes ignored)."},"nickname":{"type":"string","example":"Blue Fox","description":"2–20 letters, digits, spaces, `'`, `-` or `_`, with at least one letter and at most 3 digits; no real names needed. Unique within the class."}},"required":["joinCode","nickname"]},"StudentClassDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":["id","name"]},"StudentSchoolDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":["id","name"]},"StudentSelfResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"nickname":{"type":"string"},"class":{"$ref":"#/components/schemas/StudentClassDto"},"organization":{"$ref":"#/components/schemas/StudentSchoolDto"}},"required":["id","nickname","class","organization"]},"ClassJoinResponseDto":{"type":"object","properties":{"studentToken":{"type":"string","example":"ppst_0123456789ab_…","description":"Shown once. Keep it on the device (IndexedDB) and send it as `Authorization: Bearer <studentToken>` without cookies. It works until the teacher revokes the student or archives the class."},"tokenType":{"type":"string","enum":["Bearer"]},"student":{"$ref":"#/components/schemas/StudentSelfResponseDto"}},"required":["studentToken","tokenType","student"]},"UpdateClassDto":{"type":"object","properties":{"name":{"type":"string","maxLength":100}},"required":["name"]},"RotateJoinCodeDto":{"type":"object","properties":{"ttlMinutes":{"type":"number","minimum":15,"maximum":43200,"default":1440,"description":"How long the join code works, in minutes (15 minutes to 30 days; default one day)."}}},"StudentResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"classId":{"type":"string","format":"uuid"},"nickname":{"type":"string"},"status":{"type":"string","enum":["active","revoked"]},"joinedAt":{"type":"string","format":"date-time"},"lastSeenAt":{"type":"string","nullable":true,"format":"date-time"},"revokedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","classId","nickname","status","joinedAt","lastSeenAt","revokedAt"]},"StudentPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StudentResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"ClassProgressAssignmentDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"competitive":{"type":"boolean"},"assignedAt":{"type":"string","format":"date-time"}},"required":["publicationId","competitive","assignedAt"]},"ClassProgressStudentDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"nickname":{"type":"string"},"status":{"type":"string","enum":["active","revoked"]}},"required":["id","nickname","status"]},"ClassProgressEntryDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["in_progress","completed","abandoned"],"description":"`completed` once any attempt was completed; else `in_progress` while one is open, `abandoned` when every attempt was abandoned. Publications without an entry were not started."},"attempts":{"type":"number","description":"Attempts (play sessions) started."},"completions":{"type":"number"},"completedAt":{"type":"string","nullable":true,"format":"date-time","description":"The first completion."},"elapsedMs":{"type":"number","description":"Active play time in ms: the first completion's, else the latest attempt's."},"hintsUsed":{"type":"number"},"revealsUsed":{"type":"number"},"assisted":{"type":"boolean","description":"Answers were revealed."},"mode":{"type":"string","enum":["casual","competitive"]},"verified":{"type":"boolean","nullable":true,"description":"The first completion's server verification (competitive only); null before completing."},"verificationNote":{"type":"string","nullable":true,"enum":["casual","offline","too_fast","deadline_passed","mode_mismatch","assisted","repeat_attempt"],"description":"Why the first completion isn't verified (`casual`, `offline` for an uploaded one, …); null when verified or not completed."},"lastPlayedAt":{"type":"string","format":"date-time"},"studentId":{"type":"string","format":"uuid"}},"required":["publicationId","status","attempts","completions","completedAt","elapsedMs","hintsUsed","revealsUsed","assisted","mode","verified","verificationNote","lastPlayedAt","studentId"]},"ClassProgressResponseDto":{"type":"object","properties":{"classId":{"type":"string","format":"uuid"},"assignments":{"description":"The class's current assignments, newest first.","type":"array","items":{"$ref":"#/components/schemas/ClassProgressAssignmentDto"}},"students":{"description":"Active students in join order, then revoked students whose progress is still retained.","type":"array","items":{"$ref":"#/components/schemas/ClassProgressStudentDto"}},"entries":{"description":"One entry per student and assignment they started (sparse: a missing pair was not started).","type":"array","items":{"$ref":"#/components/schemas/ClassProgressEntryDto"}}},"required":["classId","assignments","students","entries"]},"ClassAnalyticsRangeDto":{"type":"object","properties":{"from":{"type":"string","format":"date","description":"First UTC day (inclusive)."},"to":{"type":"string","format":"date","description":"Last UTC day (inclusive)."},"clamped":{"type":"boolean","description":"Whether the plan's analytics retention or today cut the requested range."}},"required":["from","to","clamped"]},"ClassAnalyticsTotalsDto":{"type":"object","properties":{"students":{"type":"number","description":"The class's current (unrevoked) students."},"activeStudents":{"type":"number","description":"Of those, students who started a session or completed an assignment in the range."},"assignments":{"type":"number","description":"The class's current assignments."},"sessions":{"type":"number","description":"Sessions those students started on the class's assignments in the range."},"completions":{"type":"number","description":"Those students' completions of the class's assignments recorded in the range."}},"required":["students","activeStudents","assignments","sessions","completions"]},"ClassAnalyticsAssignmentDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"title":{"type":"string","description":"The publication's current title (empty when unknown)."},"competitive":{"type":"boolean"},"assignedAt":{"type":"string","format":"date-time"},"studentsStarted":{"type":"number","description":"Students who started a session in the range, at or after `assignedAt`."},"studentsCompleted":{"type":"number","description":"Students with a completion recorded in the range, at or after `assignedAt`."},"completionRate":{"type":"number","description":"`studentsCompleted / totals.students` (0–1, 4 decimals); 0 without students."},"medianTimeMs":{"type":"number","nullable":true,"description":"Median active time of each completer's first completion in the range, in ms; null when fewer than 3 students completed."},"medianHints":{"type":"number","nullable":true,"description":"Median hints of the same completions; null when fewer than 3 students completed."}},"required":["publicationId","title","competitive","assignedAt","studentsStarted","studentsCompleted","completionRate","medianTimeMs","medianHints"]},"ClassAnalyticsDayDto":{"type":"object","properties":{"date":{"type":"string","format":"date","description":"UTC day."},"sessions":{"type":"number"},"completions":{"type":"number"}},"required":["date","sessions","completions"]},"ClassAnalyticsResponseDto":{"type":"object","properties":{"range":{"$ref":"#/components/schemas/ClassAnalyticsRangeDto"},"totals":{"$ref":"#/components/schemas/ClassAnalyticsTotalsDto"},"assignments":{"description":"The class's current assignments, newest first.","type":"array","items":{"$ref":"#/components/schemas/ClassAnalyticsAssignmentDto"}},"days":{"description":"Every UTC day of the range (at most 366), oldest first.","type":"array","items":{"$ref":"#/components/schemas/ClassAnalyticsDayDto"}}},"required":["range","totals","assignments","days"]},"ClassAssignmentResponseDto":{"type":"object","properties":{"classId":{"type":"string","format":"uuid"},"publicationId":{"type":"string","format":"uuid"},"competitive":{"type":"boolean","description":"Students may play it in competitive mode; otherwise only casual publications are playable for them."},"assignedByUserId":{"type":"string","nullable":true,"format":"uuid"},"assignedAt":{"type":"string","format":"date-time"}},"required":["classId","publicationId","competitive","assignedByUserId","assignedAt"]},"ClassAssignmentPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ClassAssignmentResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"AssignPublicationDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"competitive":{"type":"boolean","description":"Let the class play it in competitive mode (server-timed, no reveals). Students play only casual publications unless this is set; default false. Sent for an existing assignment, it changes it."}},"required":["publicationId"]},"RenameStudentDto":{"type":"object","properties":{"nickname":{"type":"string","example":"Blue Fox","description":"Same rules as joining."}},"required":["nickname"]},"StudentPublicationResponseDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"title":{"type":"string"},"gameType":{"type":"string"},"language":{"type":"string"},"visibility":{"type":"string","enum":["public","unlisted","private"]},"mode":{"type":"string","enum":["casual","competitive"]},"publishedAt":{"type":"string","nullable":true},"playPath":{"type":"string","example":"/v1/publications/0190…/play","description":"The play pointer to load with the student token."}},"required":["publicationId","title","gameType","language","visibility","mode","publishedAt","playPath"]},"StudentPublicationPageResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StudentPublicationResponseDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["data","nextCursor"]},"StudentOwnProgressDto":{"type":"object","properties":{"publicationId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["in_progress","completed","abandoned"],"description":"`completed` once any attempt was completed; else `in_progress` while one is open, `abandoned` when every attempt was abandoned. Publications without an entry were not started."},"attempts":{"type":"number","description":"Attempts (play sessions) started."},"completions":{"type":"number"},"completedAt":{"type":"string","nullable":true,"format":"date-time","description":"The first completion."},"elapsedMs":{"type":"number","description":"Active play time in ms: the first completion's, else the latest attempt's."},"hintsUsed":{"type":"number"},"revealsUsed":{"type":"number"},"assisted":{"type":"boolean","description":"Answers were revealed."},"mode":{"type":"string","enum":["casual","competitive"]},"verified":{"type":"boolean","nullable":true,"description":"The first completion's server verification (competitive only); null before completing."},"verificationNote":{"type":"string","nullable":true,"enum":["casual","offline","too_fast","deadline_passed","mode_mismatch","assisted","repeat_attempt"],"description":"Why the first completion isn't verified (`casual`, `offline` for an uploaded one, …); null when verified or not completed."},"lastPlayedAt":{"type":"string","format":"date-time"},"openSessionId":{"type":"string","nullable":true,"format":"uuid","description":"The most recently active open session, to resume with `GET /v1/play-sessions/:id`."}},"required":["publicationId","status","attempts","completions","completedAt","elapsedMs","hintsUsed","revealsUsed","assisted","mode","verified","verificationNote","lastPlayedAt","openSessionId"]},"StudentOwnProgressResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StudentOwnProgressDto"}}},"required":["data"]},"CommonErrorCode":{"type":"string","description":"Common error codes. Endpoints may return their own codes too.","enum":["VALIDATION_FAILED","BAD_REQUEST","INVALID_CURSOR","IDEMPOTENCY_KEY_REQUIRED","CONFLICTING_CREDENTIALS","IDEMPOTENCY_KEY_INVALID","UNAUTHENTICATED","API_KEY_INVALID","QUOTA_EXCEEDED","FORBIDDEN","INSUFFICIENT_SCOPE","IMPERSONATION_FORBIDDEN","CSRF_REJECTED","ACCOUNT_DISABLED","NOT_FOUND","METHOD_NOT_ALLOWED","CONFLICT","ALREADY_EXISTS","IDEMPOTENCY_KEY_IN_USE","PRECONDITION_FAILED","PAYLOAD_TOO_LARGE","UNSUPPORTED_MEDIA_TYPE","UNPROCESSABLE","IDEMPOTENCY_KEY_MISMATCH","PRECONDITION_REQUIRED","RATE_LIMITED","INTERNAL_ERROR","SERVICE_UNAVAILABLE"]},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","requestId","details"],"properties":{"code":{"type":"string","pattern":"^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$","description":"A stable code: one of CommonErrorCode or an endpoint-specific code.","example":"NOT_FOUND"},"message":{"type":"string","description":"Human-readable, not localized."},"requestId":{"type":"string","nullable":true,"description":"Echo of the `X-Request-Id` response header."},"details":{"description":"Field problems (`[{ field, issue, message }]`) or structured context (e.g. `{ entitlement }` for `QUOTA_EXCEEDED`).","oneOf":[{"type":"array","items":{"type":"object","required":["issue"],"properties":{"field":{"type":"string"},"issue":{"type":"string"},"message":{"type":"string"}}}},{"type":"object","additionalProperties":true}]}}}}}}}}