{"openapi":"3.1.0","info":{"title":"GAMPEON Platform API","version":"0.1.0","description":"The GAMPEON platform API: accounts, profiles, studios, projects, the server browser, the marketplace, the GAMPEONS wallet, the social layer (follows, friends, posts), jobs and communities with voice channels.\n\n**Status: Preview.** The API is in a closed test phase and can change without notice.\n\n## Conventions\n- Base URL: `https://api.gampeon.com`. All routes start with `/v1`.\n- Requests with a body send `Content-Type: application/json` (file uploads: the file type). Bodies are limited to 64 KB.\n- Times are Unix timestamps in **milliseconds** (UTC).\n- Errors have the shape `{ \"error\": \"code\", \"message\": \"optional detail\" }`. Codes are stable, messages are not.\n- Rate limits answer `429` with `Retry-After`.\n\n## Authentication\nLog in with `POST /v1/sessions` and send the token as `Authorization: Bearer <token>`. Sessions last 30 days. Game servers authenticate heartbeats with `x-server-key`.\n\n**Access tokens** (`gpat_…`, created in the portal or with `POST /v1/me/tokens`) are sent the same way, but only work on routes that list a scope in `x-gampeon-token-scope`, and only if the token has that scope (`any`: every valid token). Every other route, public ones included, answers `403 token_not_allowed` when called with an access token; a missing scope `403 insufficient_scope`. Tokens never see email addresses and can never moderate, administer, manage tokens, buy, pay, upload versions or delete. Limits per token: 120 requests per minute, 2000 per hour.\n\n## Errors on every route\n`400 invalid_json`, `400 body_must_be_object`, `400 invalid_field` (with a message naming the field), `404 not_found` for unknown paths, `405 method_not_allowed`, `413 body_too_large`, `415 unsupported_media_type`, `500 internal_error`.","contact":{"name":"GAMPEON","url":"https://create.gampeon.com/docs/","email":"hello@gampeon.com"}},"servers":[{"url":"https://api.gampeon.com","description":"Production"}],"tags":[{"name":"Accounts","description":"Sign up, log in (with a password, Steam or Discord), connected accounts, email confirmation and password reset."},{"name":"Profiles","description":"Public profiles and your own profile."},{"name":"Studios","description":"Teams that own projects together. Membership only by invitation."},{"name":"Projects","description":"Public pages of games: development stage, gallery, links, favorites, linked servers and marketplace items. New projects are drafts until the team publishes them."},{"name":"Servers","description":"Server browser and heartbeats from game servers."},{"name":"Marketplace","description":"Scripts, vehicles, maps and other content. Publishing requires the rights statement."},{"name":"Reports and moderation","description":"Notice and action under the Digital Services Act (Art. 16, 17, 20)."},{"name":"Achievements","description":"Achievements based on real activity."},{"name":"Access tokens","description":"Personal access tokens (`gpat_…`) for AI assistants, MCP clients and tools, with scopes, expiry and an activity log."},{"name":"GAMPEONS","description":"The platform currency: wallet, item purchases and creator payouts. Sandbox only: payments are simulated and no real money moves."},{"name":"Social","description":"Follows, friends, blocks, privacy settings, posts and the feed."},{"name":"Communities","description":"Optional communities of studios and projects in the launcher: channels in categories, roles with permissions, per-channel overrides, invites, kicks, bans, timeouts and an audit log. Reports on messages go to GAMPEON.\n\nPermissions are bitmasks. A member has the permissions of `everyone` plus all their roles (`administrator` means all). In a channel, the overrides of its category apply first, then its own: first `everyone`, then all of the member's roles together, denies before allows.\n\n| Name | Value | Meaning |\n|---|---|---|\n| `viewChannels` | 1 | See channels and read their messages. |\n| `sendMessages` | 2 | Write in text channels. |\n| `manageMessages` | 4 | Remove messages from others and ignore slow mode. |\n| `manageChannels` | 8 | Create, edit, reorder and delete channels and their permissions. |\n| `manageRoles` | 16 | Create and edit roles below their own highest role and assign them. |\n| `manageCommunity` | 32 | Change name, description, rules, who can join and the minimum age. |\n| `createInvites` | 64 | Create invite links. |\n| `kickMembers` | 128 | Remove members below their own highest role. They can join again. |\n| `banMembers` | 256 | Ban members below their own highest role and remove their recent messages. |\n| `timeoutMembers` | 512 | Mute members below their own highest role for a while. |\n| `viewAuditLog` | 1024 | See who changed what in this community. |\n| `administrator` | 2048 | Every permission in every channel. Give this only to people you trust. |\n| `connect` | 4096 | Join voice channels and listen. Voice is for people aged 16 and older. |\n| `speak` | 8192 | Talk in voice channels. |\n| `stream` | 16384 | Share a screen or a window with sound in voice channels. |\n| `muteMembers` | 32768 | Mute members below their own highest role in all voice channels. |\n| `moveMembers` | 65536 | Remove members below their own highest role from voice channels and join full ones. |"},{"name":"Voice","description":"Voice channels in communities: talk, share a screen or a window with sound, watch others. Sound and video go directly between the launcher and the GAMPEON voice server (LiveKit); GAMPEON does not record them. The API decides who may join and what they may send, and keeps only who was in which channel when (30 days) for reports.\n\nVoice is for people aged 16 and older during the closed test. Permissions: `connect` (join and listen), `speak`, `stream` (share a screen with sound), `muteMembers` and `moveMembers` (disconnect, join full channels)."},{"name":"Game packages","description":"Private game packages of a project (cooked Unreal content: maps, models, images for web interfaces). Only players of servers linked to the project get them, through the launcher when they press Play. Never in the marketplace and never downloadable in the portal."},{"name":"Jobs","description":"Find people for your projects: job posts, applications and a conversation per application. No money or GAMPEONS move through GAMPEON; compensation is only stated."},{"name":"Meta","description":"Health check, platform status and this description."}],"paths":{"/healthz":{"get":{"operationId":"getHealth","tags":["Meta"],"summary":"Health check","description":"Returns `{ \"ok\": true }` while the API is running. Used by monitoring.","security":[],"responses":{"200":{"description":"API is up","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true}},"required":["ok"]}}}}},"x-gampeon-auth":"none"}},"/v1/openapi.json":{"get":{"operationId":"getOpenApi","tags":["Meta"],"summary":"This API description","description":"The OpenAPI 3.1 description of this API. The developer docs and the GAMPEON MCP server are generated from it.","security":[],"responses":{"200":{"description":"OpenAPI document","content":{"application/json":{"schema":{"type":"object"}}}}},"x-gampeon-auth":"none"}},"/v1/signup":{"get":{"operationId":"getSignupMode","tags":["Accounts"],"summary":"Sign-up mode","description":"Tells clients whether anyone can sign up (`open`) or only invited email addresses (`invite`, closed test phase), and whether email verification and password reset by email are active.","security":[],"responses":{"200":{"description":"Sign-up settings","content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["open","invite"]},"emailVerification":{"type":"boolean"},"passwordReset":{"type":"boolean"}},"required":["mode","emailVerification","passwordReset"]}}}}},"x-gampeon-auth":"none"}},"/v1/accounts":{"post":{"operationId":"createAccount","tags":["Accounts"],"summary":"Create an account","description":"Creates an account. Without a wished `handle`, one is derived from the display name. When email is active, the account must confirm its address before the first login.\n\nThe minimum age is 13. Under 16, stricter privacy defaults apply (see `GET /v1/me/social-settings`). The birth month is only visible to the account itself.\n\n`acceptTerms` must be the current version from `GET /v1/legal/terms`: the person has to agree to the Terms of Use and the Community Guidelines (links in that answer). The Privacy Policy is information, not consent.\n\nRate limit: 5 per hour per IP.","security":[],"responses":{"201":{"description":"Account created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"email":{"type":"string"},"displayName":{"type":"string"},"handle":{"type":"string"},"verificationRequired":{"type":"boolean","description":"An email with a confirmation link was sent"}},"required":["id","email","displayName","handle","verificationRequired"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `signup_closed`, `too_young`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `email_taken`, `handle_taken`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `terms_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 5 per hour per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"5 per hour per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","maxLength":254},"displayName":{"type":"string","description":"3 to 32 letters, digits, spaces, `_` or `-`","minLength":3,"maxLength":32},"handle":{"type":"string","description":"Optional wished handle","pattern":"^$|^[a-z0-9_]{3,24}$"},"password":{"type":"string","description":"Password, 10 to 200 characters","minLength":10,"maxLength":200},"birthMonth":{"type":"string","description":"Birth month as `YYYY-MM`. Minimum age 13. Self-declared, only visible to the account itself.","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"},"acceptTerms":{"type":"string","description":"Current version from `GET /v1/legal/terms`. Sending it means the person accepts the Terms of Use and the Community Guidelines in that version.","maxLength":40}},"required":["email","displayName","password","birthMonth","acceptTerms"]}}}}}},"/v1/email/verify":{"post":{"operationId":"verifyEmail","tags":["Accounts"],"summary":"Confirm an email address","description":"Rate limit: 30 per hour per IP.","security":[],"responses":{"200":{"description":"Address confirmed","content":{"application/json":{"schema":{"type":"object","properties":{"verified":{"const":true}},"required":["verified"]}}}},"400":{"description":"Error codes: `invalid_field`, `invalid_token`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per hour per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"30 per hour per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"Token from the link in the email (the part after the last `/`)","minLength":20,"maxLength":100}},"required":["token"]}}}}}},"/v1/email/verify/resend":{"post":{"operationId":"resendVerification","tags":["Accounts"],"summary":"Send a new confirmation link","description":"Always answers `202`, whether or not an account exists for the address. At most 3 emails per address and hour.\n\nRate limit: 10 per hour per IP.","security":[],"responses":{"202":{"description":"Accepted","content":{"application/json":{"schema":{"type":"object","properties":{"accepted":{"const":true}},"required":["accepted"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"10 per hour per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"]}}}}}},"/v1/password/forgot":{"post":{"operationId":"forgotPassword","tags":["Accounts"],"summary":"Request a password reset link","description":"Always answers `202`, whether or not an account exists for the address. The link is valid for one hour.\n\nRate limit: 10 per hour per IP.","security":[],"responses":{"202":{"description":"Accepted","content":{"application/json":{"schema":{"type":"object","properties":{"accepted":{"const":true}},"required":["accepted"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"10 per hour per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"]}}}}}},"/v1/password/reset":{"post":{"operationId":"resetPassword","tags":["Accounts"],"summary":"Set a new password","description":"Sets a new password with the token from the reset email. Ends all sessions of the account.\n\nRate limit: 30 per hour per IP.","security":[],"responses":{"200":{"description":"Password changed","content":{"application/json":{"schema":{"type":"object","properties":{"reset":{"const":true}},"required":["reset"]}}}},"400":{"description":"Error codes: `invalid_field`, `invalid_token`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per hour per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"30 per hour per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"Token from the link in the email (the part after the last `/`)","minLength":20,"maxLength":100},"password":{"type":"string","description":"Password, 10 to 200 characters","minLength":10,"maxLength":200}},"required":["token","password"]}}}}}},"/v1/sessions":{"post":{"operationId":"login","tags":["Accounts"],"summary":"Log in","description":"Returns a bearer token for the `Authorization` header. Sessions last 30 days.\n\nRate limit: 5 failed attempts per email in 15 minutes, 30 attempts per IP in 15 minutes.","security":[],"responses":{"201":{"description":"Logged in","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"Bearer token. Shown once, store it securely."},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["token","expiresAt"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `invalid_credentials`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `email_unverified`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 5 failed attempts per email in 15 minutes, 30 attempts per IP in 15 minutes. Error codes: `rate_limited`, `too_many_attempts`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"5 failed attempts per email in 15 minutes, 30 attempts per IP in 15 minutes","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"password":{"type":"string"}},"required":["email","password"]}}}}}},"/v1/sessions/current":{"delete":{"operationId":"logout","tags":["Accounts"],"summary":"Log out","description":"Ends the session of the token in the request.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"204":{"description":"Logged out"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/legal/terms":{"get":{"operationId":"getTerms","tags":["Accounts"],"summary":"Current terms version","description":"The version of the Terms of Use and Community Guidelines that is in force, the documents it covers, and links to the other legal texts on gampeon.com/legal/ (Privacy Policy, Legal Notice, notice-and-action policy, monetization terms, short version for teens). English is the main version; `urlDe` is the German version.","security":[],"responses":{"200":{"description":"Terms version and links","content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"string"},"documents":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["terms","community-guidelines"]},"title":{"type":"string"},"url":{"type":"string","format":"uri"},"urlDe":{"type":"string","format":"uri"}},"required":["id","title","url","urlDe"]}},"links":{"type":"object","properties":{"privacy":{"type":"string"},"notice":{"type":"string"},"copyright":{"type":"string"},"monetization":{"type":"string"},"teens":{"type":"string"},"all":{"type":"string"}},"required":["privacy","notice","copyright","monetization","teens","all"]}},"required":["version","documents","links"]}}}}},"x-gampeon-auth":"none"}},"/v1/me/terms":{"post":{"operationId":"acceptTerms","tags":["Accounts"],"summary":"Accept the current terms","description":"For accounts that have not accepted the version in force yet (`terms.current` is `false` in `GET /v1/me`). Only with a portal session, not with an access token: an AI assistant cannot accept terms for a person.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Accepted","content":{"application/json":{"schema":{"type":"object","properties":{"version":{"oneOf":[{"type":"string","description":"Last accepted version, `null` if none yet (accounts created before the terms)"},{"type":"null"}]},"acceptedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"currentVersion":{"type":"string","description":"Version in force"},"current":{"type":"boolean","description":"`false`: show the terms and ask the person to accept them (`POST /v1/me/terms`)"}},"required":["version","acceptedAt","currentVersion","current"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `terms_outdated`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"string","description":"Current version from `GET /v1/legal/terms`","maxLength":40}},"required":["version"]}}}}}},"/v1/me":{"get":{"operationId":"getMe","tags":["Accounts"],"summary":"Your account","description":"Your account with the 50 newest notifications.\n\nAccess tokens: scope `profile:read`.","security":[{"session":[]},{"accessToken":["profile:read"]}],"responses":{"200":{"description":"Account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `insufficient_scope`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-token-scope":"profile:read"},"patch":{"operationId":"updateMe","tags":["Profiles"],"summary":"Change your profile","description":"Changes display name, handle, bio, country or profile links. Fields you leave out stay unchanged. Accounts created before the age check add their `birthMonth` once; after that it can only be changed through support.\n\n`links` replaces the whole list. Each entry takes the name on the platform or a link to the profile there; GAMPEON keeps only the name and builds the address itself, so links to other sites are rejected. Entries with an empty `handle` are dropped. Country and links appear on the public profile only from age 16.\n\nNot available with access tokens.\n\nRate limit: 120 edits per hour per account.","security":[{"session":[]}],"responses":{"200":{"description":"Updated profile","content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"bio":{"type":"string"},"birthMonth":{"oneOf":[{"type":"string"},{"type":"null"}]},"country":{"oneOf":[{"type":"string","description":"Country code (ISO 3166-1 alpha-2, for example `DE`). `null` when not set.","pattern":"^[A-Z]{2}$"},{"type":"null"}]},"links":{"type":"array","items":{"$ref":"#/components/schemas/ProfileLink"},"description":"Profiles on other platforms, at most one per platform (up to 10)."}},"required":["handle","displayName","bio","birthMonth","country","links"]}}}},"400":{"description":"Error codes: `invalid_field`, `invalid_country`, `invalid_link`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `too_young`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `handle_taken`, `birth_month_set`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 edits per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"120 edits per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"displayName":{"type":"string","minLength":3,"maxLength":32},"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"bio":{"type":"string","maxLength":500},"birthMonth":{"type":"string","description":"Birth month as `YYYY-MM`. Minimum age 13. Self-declared, only visible to the account itself.","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"},"country":{"oneOf":[{"type":"string","description":"Country code (ISO 3166-1 alpha-2, for example `DE`). `null` when not set.","pattern":"^[A-Z]{2}$"},{"type":"null"}]},"links":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["twitch","kick","youtube","tiktok","instagram","x","facebook","reddit","github","bluesky"]},"handle":{"type":"string","description":"Name on the platform or a link to the profile there. Empty removes it.","maxLength":300}},"required":["platform","handle"]},"description":"Profiles on other platforms, at most one per platform","maxItems":10}},"required":[]}}}}}},"/v1/profiles/{handle}":{"get":{"operationId":"getProfile","tags":["Profiles"],"summary":"Public profile","description":"Display name, bio, public marketplace items, servers online, studios, projects and achievements of an account. Never contains the email address.","parameters":[{"name":"handle","in":"path","required":true,"description":"Handle of the account","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[],"responses":{"200":{"description":"Profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none"}},"/v1/achievements":{"get":{"operationId":"listAchievements","tags":["Achievements"],"summary":"Achievement catalog","description":"All achievements with category, tier, points and rarity. When logged in, `summary`, `unlockedAt` and `progress` are filled for your account.\n\nAccess tokens: scope `profile:read`.","security":[{},{"session":[]},{"accessToken":["profile:read"]}],"responses":{"200":{"description":"Catalog","content":{"application/json":{"schema":{"type":"object","properties":{"categories":{"type":"array","items":{"$ref":"#/components/schemas/AchievementCategory"}},"tierPoints":{"type":"object","properties":{"bronze":{"type":"integer"},"silver":{"type":"integer"},"gold":{"type":"integer"},"platinum":{"type":"integer"}},"required":["bronze","silver","gold","platinum"]},"accounts":{"type":"integer","description":"Number of accounts (basis for `percent`)"},"achievements":{"type":"array","items":{"$ref":"#/components/schemas/Achievement"}},"total":{"type":"integer"},"maxPoints":{"type":"integer"},"summary":{"oneOf":[{"$ref":"#/components/schemas/AchievementSummary"},{"type":"null"}]}},"required":["categories","tierPoints","accounts","achievements","total","maxPoints","summary"]}}}},"403":{"description":"Error codes: `insufficient_scope`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional","x-gampeon-token-scope":"profile:read"}},"/v1/profiles/{handle}/achievements":{"get":{"operationId":"listProfileAchievements","tags":["Achievements"],"summary":"Achievements of a profile","description":"All achievements with status, date, progress and rarity for this account.","parameters":[{"name":"handle","in":"path","required":true,"description":"Handle of the account","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[],"responses":{"200":{"description":"Achievements","content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"categories":{"type":"array","items":{"$ref":"#/components/schemas/AchievementCategory"}},"tierPoints":{"type":"object","properties":{"bronze":{"type":"integer"},"silver":{"type":"integer"},"gold":{"type":"integer"},"platinum":{"type":"integer"}},"required":["bronze","silver","gold","platinum"]},"accounts":{"type":"integer","description":"Number of accounts (basis for `percent`)"},"achievements":{"type":"array","items":{"$ref":"#/components/schemas/Achievement"}},"summary":{"$ref":"#/components/schemas/AchievementSummary"}},"required":["handle","displayName","categories","tierPoints","accounts","achievements","summary"]}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none"}},"/v1/admin/achievements":{"post":{"operationId":"grantAchievement","tags":["Achievements"],"summary":"Grant a team achievement","description":"Admins grant achievements with `source: staff`, for example for a game jam or a confirmed bug report.\n\nRequires the role admin.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"201":{"description":"Granted","content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string"},"achievement":{"type":"string"}},"required":["handle","achievement"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_unlocked`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string"},"achievement":{"type":"string","description":"Achievement ID"}},"required":["handle","achievement"]}}}}}},"/v1/admin/achievements/{handle}/{id}":{"delete":{"operationId":"revokeAchievement","tags":["Achievements"],"summary":"Revoke an achievement","description":"For example after manipulation (fake heartbeats, bought downloads).\n\nRequires the role admin.\n\nNot available with access tokens.","parameters":[{"name":"handle","in":"path","required":true,"description":"Handle of the account","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}},{"name":"id","in":"path","required":true,"description":"Achievement ID","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Revoked"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"admin"}},"/v1/studios":{"post":{"operationId":"createStudio","tags":["Studios"],"summary":"Create a studio","description":"You become its owner. At most 5 studios per account.\n\nNot available with access tokens.\n\nRate limit: 5 per hour per account.","security":[{"session":[]}],"responses":{"201":{"description":"Studio created","content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"tagline":{"type":"string"},"description":{"type":"string"},"website":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","name","tagline","description","website"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `slug_taken`, `studio_limit_reached`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 5 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"5 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string","description":"3 to 32 characters `a-z`, `0-9`, `-`","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},"name":{"type":"string","minLength":2,"maxLength":48},"tagline":{"type":"string","maxLength":120},"description":{"type":"string","description":"Line breaks allowed","maxLength":4000},"website":{"type":"string","description":"Website. Only `https://` URLs, empty string removes it.","maxLength":200,"pattern":"^$|^https://[^\\s<>\"]+$"}},"required":["slug","name"]}}}}},"get":{"operationId":"listStudios","tags":["Studios"],"summary":"List studios","parameters":[{"name":"q","in":"query","required":false,"description":"Search in slug, name and tagline","schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"description":"Default: players","schema":{"type":"string","enum":["players","members","new","name"]}},{"name":"limit","in":"query","required":false,"description":"Page size, 1 to 100 (default 24)","schema":{"type":"integer","minimum":1,"maximum":100,"default":24}},{"name":"offset","in":"query","required":false,"description":"Number of entries to skip","schema":{"type":"integer","minimum":0,"default":0}}],"security":[],"responses":{"200":{"description":"Studios","content":{"application/json":{"schema":{"type":"object","properties":{"studios":{"type":"array","items":{"$ref":"#/components/schemas/Studio"}},"total":{"type":"integer"}},"required":["studios","total"]}}}}},"x-gampeon-auth":"none"}},"/v1/studios/{slug}":{"get":{"operationId":"getStudio","tags":["Studios"],"summary":"Studio page","description":"Members, projects and your role (`viewerRole`). Owners and admins also see open invites.\n\nAccess tokens: scope `projects:read`.","parameters":[{"name":"slug","in":"path","required":true,"description":"Studio slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{},{"session":[]},{"accessToken":["projects:read"]}],"responses":{"200":{"description":"Studio","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Studio"},{"type":"object","properties":{"description":{"type":"string"},"website":{"oneOf":[{"type":"string"},{"type":"null"}]},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"members":{"type":"array","items":{"$ref":"#/components/schemas/StudioMember"}},"memberCount":{"type":"integer"},"projects":{"type":"array","items":{"$ref":"#/components/schemas/Project"}},"projectCount":{"type":"integer"},"viewerRole":{"oneOf":[{"type":"string","enum":["owner","admin","member"]},{"type":"null"}]},"invites":{"type":"array","items":{"$ref":"#/components/schemas/StudioInvite"},"description":"Only for owners and admins"},"hidden":{"$ref":"#/components/schemas/Hidden"}},"required":["description","website","updatedAt","members","memberCount","projects","projectCount","viewerRole"]}]}}}},"403":{"description":"Error codes: `insufficient_scope`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional","x-gampeon-token-scope":"projects:read"},"patch":{"operationId":"updateStudio","tags":["Studios"],"summary":"Change a studio","description":"Owners and admins. Fields you leave out stay unchanged.\n\nNot available with access tokens.\n\nRate limit: 120 edits per hour per account.","parameters":[{"name":"slug","in":"path","required":true,"description":"Studio slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"tagline":{"type":"string"},"description":{"type":"string"},"website":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","name","tagline","description","website"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `studio_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 edits per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"120 edits per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":48},"tagline":{"type":"string","maxLength":120},"description":{"type":"string","maxLength":4000},"website":{"type":"string","description":"Website. Only `https://` URLs, empty string removes it.","maxLength":200,"pattern":"^$|^https://[^\\s<>\"]+$"}},"required":[]}}}}},"delete":{"operationId":"deleteStudio","tags":["Studios"],"summary":"Delete a studio","description":"Only the owner, and only while the studio has no projects.\n\nNot available with access tokens.","parameters":[{"name":"slug","in":"path","required":true,"description":"Studio slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `studio_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `studio_has_projects`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/studios/{slug}/invites":{"post":{"operationId":"inviteToStudio","tags":["Studios"],"summary":"Invite someone","description":"Owners and admins invite by handle. Only the owner can invite admins. Invites are valid for 14 days; the invited person accepts them. At most 50 members.\n\nNot available with access tokens.\n\nRate limit: 30 per hour per account.","parameters":[{"name":"slug","in":"path","required":true,"description":"Studio slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Invite sent","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"handle":{"type":"string"},"displayName":{"type":"string"},"role":{"type":"string"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","handle","displayName","role","expiresAt"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `studio_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`, `user_not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_member`, `invite_exists`, `invite_limit_reached`, `member_limit_reached`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string","description":"Handle, with or without `@`"},"role":{"type":"string","enum":["member","admin"],"description":"Default: member"}},"required":["handle"]}}}}}},"/v1/studios/{slug}/invites/{id}":{"delete":{"operationId":"cancelStudioInvite","tags":["Studios"],"summary":"Withdraw an invite","description":"Not available with access tokens.","parameters":[{"name":"slug","in":"path","required":true,"description":"Studio slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}},{"name":"id","in":"path","required":true,"description":"Invite ID","schema":{"type":"string","format":"uuid"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Withdrawn"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `studio_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/studios/{slug}/members/{handle}":{"patch":{"operationId":"setStudioRole","tags":["Studios"],"summary":"Change a member role","description":"Only the owner. The owner role itself cannot change.\n\nNot available with access tokens.","parameters":[{"name":"slug","in":"path","required":true,"description":"Studio slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}},{"name":"handle","in":"path","required":true,"description":"Handle of the account","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Role changed","content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string"},"role":{"type":"string"}},"required":["handle","role"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `studio_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `owner_role_fixed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["admin","member"]}},"required":["role"]}}}}},"delete":{"operationId":"removeStudioMember","tags":["Studios"],"summary":"Leave or remove a member","description":"Members can leave (not the owner). The owner removes anyone, admins remove members. Their own servers and marketplace items are unlinked from the studio projects.\n\nNot available with access tokens.","parameters":[{"name":"slug","in":"path","required":true,"description":"Studio slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}},{"name":"handle","in":"path","required":true,"description":"Handle of the account","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Removed"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `owner_cannot_leave`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/me/studios":{"get":{"operationId":"listMyStudios","tags":["Studios"],"summary":"Your studios","description":"Studios you belong to with your role, including hidden ones (`hidden: true`).\n\nAccess tokens: scope `profile:read`.","security":[{"session":[]},{"accessToken":["profile:read"]}],"responses":{"200":{"description":"Studios","content":{"application/json":{"schema":{"type":"object","properties":{"studios":{"type":"array","items":{"$ref":"#/components/schemas/StudioMembership"}}},"required":["studios"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `insufficient_scope`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-token-scope":"profile:read"}},"/v1/me/invites":{"get":{"operationId":"listMyInvites","tags":["Studios"],"summary":"Your open invites","description":"Not available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Invites","content":{"application/json":{"schema":{"type":"object","properties":{"invites":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"role":{"type":"string"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"studio":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"}},"required":["slug","name"]},"invitedBy":{"$ref":"#/components/schemas/UserRef"}},"required":["id","role","createdAt","expiresAt","studio","invitedBy"]}}},"required":["invites"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/me/invites/{id}":{"post":{"operationId":"answerInvite","tags":["Studios"],"summary":"Accept or decline an invite","description":"Not available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Invite ID","schema":{"type":"string","format":"uuid"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Answered","content":{"application/json":{"schema":{"type":"object","properties":{"joined":{"type":"boolean"},"studio":{"type":"string"},"role":{"type":"string"}},"required":["joined"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `member_limit_reached`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accept":{"type":"boolean"}},"required":["accept"]}}}}}},"/v1/projects":{"post":{"operationId":"createProject","tags":["Projects"],"summary":"Create a project","description":"A project is the public page of a game. With `studio`, the project belongs to that studio (owners and admins only). New projects are drafts that only the team sees, until they are published (`published: true` here or later with a change). At most 20 projects per account and 50 per studio.\n\nAccess tokens: scope `projects:write`.\n\nRate limit: 10 per hour per account.","security":[{"session":[]},{"accessToken":["projects:write"]}],"responses":{"201":{"description":"Project created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `insufficient_scope`, `token_not_allowed`, `forbidden`, `studio_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `studio_not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `slug_taken`, `project_limit_reached`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `publish_requirements`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-token-scope":"projects:write","x-gampeon-rate-limit":"10 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},"title":{"type":"string","minLength":2,"maxLength":64},"tagline":{"type":"string","maxLength":120},"description":{"type":"string","description":"Line breaks allowed","maxLength":8000},"genre":{"type":"string","enum":["roleplay","racing","shooter","survival","parkour","sandbox","minigames","simulation","other"]},"status":{"type":"string","enum":["concept","development","alpha","beta","released"],"description":"Default: development. `playtest` from older clients counts as beta"},"tags":{"type":"array","items":{"type":"string","pattern":"^[a-z0-9][a-z0-9\\-]{0,23}$"},"description":"Up to 10 lowercase tags (`a-z`, `0-9`, `-`, max. 24 characters each).","maxItems":10},"languages":{"type":"array","items":{"type":"string","enum":["en","de","fr","es","it","pt","nl","pl","cs","sk","hu","ro","bg","el","tr","ru","uk","sv","da","no","fi","ar","he","hi","th","vi","id","ja","ko","zh"]},"description":"Up to 10 languages (ISO 639-1)","maxItems":10},"links":{"$ref":"#/components/schemas/ProjectLinks"},"website":{"type":"string","description":"Website. Only `https://` URLs, empty string removes it.","maxLength":200,"pattern":"^$|^https://[^\\s<>\"]+$"},"studio":{"type":"string","description":"Studio slug (optional)"},"published":{"type":"boolean","description":"Publish right away. Needs a tagline and an about text with at least 100 characters. Default: draft"}},"required":["slug","title","genre"]}}}}},"get":{"operationId":"listProjects","tags":["Projects"],"summary":"List projects","description":"Published projects only. `facets` counts genres without the genre filter and statuses within the chosen genre.","parameters":[{"name":"q","in":"query","required":false,"description":"Search in slug, title, tagline, studio and owner","schema":{"type":"string"}},{"name":"genre","in":"query","required":false,"description":"Filter by genre","schema":{"type":"string","enum":["roleplay","racing","shooter","survival","parkour","sandbox","minigames","simulation","other"]}},{"name":"status","in":"query","required":false,"description":"Filter by status","schema":{"type":"string","enum":["concept","development","alpha","beta","released"]}},{"name":"studio","in":"query","required":false,"description":"Filter by studio slug","schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"description":"Default: players","schema":{"type":"string","enum":["players","updated","new","name"]}},{"name":"limit","in":"query","required":false,"description":"Page size, 1 to 100 (default 24)","schema":{"type":"integer","minimum":1,"maximum":100,"default":24}},{"name":"offset","in":"query","required":false,"description":"Number of entries to skip","schema":{"type":"integer","minimum":0,"default":0}}],"security":[],"responses":{"200":{"description":"Projects","content":{"application/json":{"schema":{"type":"object","properties":{"projects":{"type":"array","items":{"$ref":"#/components/schemas/Project"}},"total":{"type":"integer"},"genres":{"type":"array","items":{"type":"string"}},"statuses":{"type":"array","items":{"type":"string"}},"facets":{"type":"object","properties":{"genres":{"type":"object","additionalProperties":{"type":"integer"}},"status":{"type":"object","additionalProperties":{"type":"integer"}}},"required":["genres","status"]}},"required":["projects","total","genres","statuses","facets"]}}}}},"x-gampeon-auth":"none"}},"/v1/projects/{slug}":{"get":{"operationId":"getProject","tags":["Projects"],"summary":"Project page","description":"Gallery, links, linked servers, marketplace items and team. For studio projects, `owner` also has `members` and `projects` (published). `viewer` tells whether you may edit the project or link your servers and items to it, and whether it is one of your favorites. The team also gets the `checklist` for publishing. Drafts and hidden projects: only the team and moderation.\n\nAccess tokens: scope `projects:read`.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{},{"session":[]},{"accessToken":["projects:read"]}],"responses":{"200":{"description":"Project","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Project"},{"type":"object","properties":{"description":{"type":"string","description":"Markdown: headings, lists, quotes, bold, italic, links"},"website":{"oneOf":[{"type":"string"},{"type":"null"}]},"links":{"$ref":"#/components/schemas/ProjectLinks"},"gallery":{"type":"array","items":{"$ref":"#/components/schemas/GalleryItem"},"description":"Screenshots and videos in order"},"peakPlayers":{"type":"integer"},"servers":{"type":"array","items":{"$ref":"#/components/schemas/Server"}},"resources":{"type":"array","items":{"$ref":"#/components/schemas/ResourceListing"}},"team":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path (`/v1/media/…`)"},{"type":"null"}]},"role":{"type":"string"}},"required":["handle","displayName","avatar","role"]}},"viewer":{"type":"object","properties":{"canEdit":{"type":"boolean"},"canLink":{"type":"boolean"},"favorited":{"type":"boolean"}},"required":["canEdit","canLink","favorited"]},"community":{"oneOf":[{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"scope":{"type":"string","enum":["project","studio"],"description":"Community of the project itself, or of its studio"},"joinMode":{"type":"string","enum":["open","invite"]},"member":{"type":"boolean","description":"You are a member"}},"required":["id","name","scope","joinMode","member"],"description":"Community for the button on the game page: the project's own, otherwise the studio's. Only when you can see it (open, member or team)."},{"type":"null"}]},"checklist":{"type":"array","items":{"$ref":"#/components/schemas/ChecklistItem"},"description":"Only for the team"},"hidden":{"$ref":"#/components/schemas/Hidden"}},"required":["description","website","links","gallery","peakPlayers","servers","resources","team","viewer","community"]}]}}}},"403":{"description":"Error codes: `insufficient_scope`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional","x-gampeon-token-scope":"projects:read"},"patch":{"operationId":"updateProject","tags":["Projects"],"summary":"Change a project","description":"Owner of the project, or owners and admins of its studio. Fields you leave out stay unchanged; `links` only changes the links you send. `published: true` publishes a draft (needs a tagline and an about text with at least 100 characters), `false` turns it back into a draft.\n\nAccess tokens: scope `projects:write`.\n\nRate limit: 120 edits per hour per account.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]},{"accessToken":["projects:write"]}],"responses":{"200":{"description":"Updated project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `insufficient_scope`, `token_not_allowed`, `forbidden`, `project_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `publish_requirements`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 edits per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-token-scope":"projects:write","x-gampeon-rate-limit":"120 edits per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":2,"maxLength":64},"tagline":{"type":"string","maxLength":120},"description":{"type":"string","description":"Markdown","maxLength":8000},"genre":{"type":"string","enum":["roleplay","racing","shooter","survival","parkour","sandbox","minigames","simulation","other"]},"status":{"type":"string","enum":["concept","development","alpha","beta","released"]},"tags":{"type":"array","items":{"type":"string","pattern":"^[a-z0-9][a-z0-9\\-]{0,23}$"},"description":"Up to 10 lowercase tags (`a-z`, `0-9`, `-`, max. 24 characters each).","maxItems":10},"languages":{"type":"array","items":{"type":"string","enum":["en","de","fr","es","it","pt","nl","pl","cs","sk","hu","ro","bg","el","tr","ru","uk","sv","da","no","fi","ar","he","hi","th","vi","id","ja","ko","zh"]},"description":"Up to 10 languages (ISO 639-1)","maxItems":10},"links":{"$ref":"#/components/schemas/ProjectLinks"},"website":{"type":"string","description":"Website. Only `https://` URLs, empty string removes it.","maxLength":200,"pattern":"^$|^https://[^\\s<>\"]+$"},"published":{"type":"boolean"}},"required":[]}}}}},"delete":{"operationId":"deleteProject","tags":["Projects"],"summary":"Delete a project","description":"Removes the page. Linked servers and marketplace items stay, only the link is removed.\n\nNot available with access tokens.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `project_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/me/projects":{"get":{"operationId":"listMyProjects","tags":["Projects"],"summary":"Projects you work on","description":"Own projects and projects of your studios, with `canEdit`.\n\nAccess tokens: scope `projects:read`.","security":[{"session":[]},{"accessToken":["projects:read"]}],"responses":{"200":{"description":"Projects","content":{"application/json":{"schema":{"type":"object","properties":{"projects":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/Project"},{"type":"object","properties":{"canEdit":{"type":"boolean"},"hidden":{"type":"boolean"}},"required":["canEdit"]}]}}},"required":["projects"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `insufficient_scope`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-token-scope":"projects:read"}},"/v1/me/favorites":{"get":{"operationId":"listMyFavorites","tags":["Projects"],"summary":"Your favorite projects","description":"Public projects you marked as favorite, most recent first (up to 200). The launcher shows them in the library.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Projects","content":{"application/json":{"schema":{"type":"object","properties":{"projects":{"type":"array","items":{"$ref":"#/components/schemas/Project"}}},"required":["projects"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/servers":{"post":{"operationId":"createServer","tags":["Servers"],"summary":"Register a server","description":"Returns the server key **once**. The game server sends it as `x-server-key` with every heartbeat. At most 10 servers per account.\n\nNot available with access tokens.\n\nRate limit: 10 per hour per account.","security":[{"session":[]}],"responses":{"201":{"description":"Server registered","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"serverKey":{"type":"string","description":"Secret key. Shown once; store it on the game server only."}},"required":["id","name","serverKey"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `server_limit_reached`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"10 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":64}},"required":["name"]}}}}},"get":{"operationId":"listServers","tags":["Servers"],"summary":"Server browser","description":"Servers that are online, sorted by player count (up to 500).","parameters":[{"name":"q","in":"query","required":false,"description":"Search in the server name","schema":{"type":"string"}},{"name":"tag","in":"query","required":false,"description":"Filter by tag","schema":{"type":"string"}}],"security":[],"responses":{"200":{"description":"Servers","content":{"application/json":{"schema":{"type":"object","properties":{"servers":{"type":"array","items":{"$ref":"#/components/schemas/Server"}},"total":{"type":"integer"}},"required":["servers","total"]}}}}},"x-gampeon-auth":"none"}},"/v1/servers/{id}/heartbeat":{"post":{"operationId":"serverHeartbeat","tags":["Servers"],"summary":"Heartbeat","description":"Send every 30 seconds. Servers without a heartbeat for 90 seconds disappear from the server browser. Without `address`, the IP of the request is used (set `sv_publicAddress` in `server.cfg` to override it).\n\nRate limit: 20 per minute per server and IP.","parameters":[{"name":"id","in":"path","required":true,"description":"Server ID","schema":{"type":"string","format":"uuid"}},{"name":"x-server-key","in":"header","required":true,"description":"Key from registering the server","schema":{"type":"string"}}],"security":[{"serverKey":[]}],"responses":{"200":{"description":"Accepted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true},"nextHeartbeatInMs":{"type":"integer"}},"required":["ok","nextHeartbeatInMs"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `invalid_server_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 20 per minute per server and IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"serverKey","x-gampeon-rate-limit":"20 per minute per server and IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"players":{"type":"integer","description":"Players online (0 to `maxPlayers`)","minimum":0},"maxPlayers":{"type":"integer","minimum":1,"maximum":2048},"port":{"type":"integer","minimum":1,"maximum":65535},"address":{"type":"string","description":"Host name or IP","maxLength":253,"pattern":"^[A-Za-z0-9.\\-:]*$"},"tags":{"type":"array","items":{"type":"string"},"description":"Up to 10 tags, such as `roleplay` or `racing`","maxItems":10},"language":{"type":"string","description":"Language code such as `en` or `de-DE`","maxLength":8},"packages":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"}},"required":["name","version"]},"description":"Game packages the server has loaded, up to 8. Players get them through the launcher when they join; they must be ready in the project the server is linked to.","maxItems":8}},"required":["players","maxPlayers","port"]}}}}}},"/v1/servers/{id}":{"get":{"operationId":"getServer","tags":["Servers"],"summary":"Server details","parameters":[{"name":"id","in":"path","required":true,"description":"Server ID","schema":{"type":"string","format":"uuid"}}],"security":[],"responses":{"200":{"description":"Server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Server"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none"},"patch":{"operationId":"updateServer","tags":["Servers"],"summary":"Change a server","description":"Only the owner. Fields you leave out stay unchanged.\n\nNot available with access tokens.\n\nRate limit: 120 edits per hour per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Server ID","schema":{"type":"string","format":"uuid"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"website":{"oneOf":[{"type":"string"},{"type":"null"}]},"project":{"oneOf":[{"$ref":"#/components/schemas/ProjectRef"},{"type":"null"}]}},"required":["id","name","description","website","project"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`, `project_not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 edits per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"120 edits per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":64},"description":{"type":"string","maxLength":2000},"website":{"type":"string","description":"Website. Only `https://` URLs, empty string removes it.","maxLength":200,"pattern":"^$|^https://[^\\s<>\"]+$"},"project":{"oneOf":[{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},{"type":"null"},{"const":""}],"description":"Slug of a project you work on (owner, studio member). `null` or an empty string removes the link."}},"required":[]}}}}},"delete":{"operationId":"deleteServer","tags":["Servers"],"summary":"Delete a server","description":"Not available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Server ID","schema":{"type":"string","format":"uuid"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/me/servers":{"get":{"operationId":"listMyServers","tags":["Servers"],"summary":"Your servers","description":"All your servers, including offline ones. Never contains the server key.\n\nAccess tokens: scope `servers:read`.","security":[{"session":[]},{"accessToken":["servers:read"]}],"responses":{"200":{"description":"Servers","content":{"application/json":{"schema":{"type":"object","properties":{"servers":{"type":"array","items":{"$ref":"#/components/schemas/Server"}}},"required":["servers"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `insufficient_scope`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-token-scope":"servers:read"}},"/v1/legal/rights-statement":{"get":{"operationId":"getRightsStatement","tags":["Marketplace"],"summary":"Rights statement","description":"The exact text a creator must confirm before publishing a version. Send it back unchanged as `rightsStatement`.","security":[],"responses":{"200":{"description":"Statement","content":{"application/json":{"schema":{"type":"object","properties":{"statement":{"type":"string"}},"required":["statement"]}}}}},"x-gampeon-auth":"none"}},"/v1/resources":{"get":{"operationId":"searchMarketplace","tags":["Marketplace"],"summary":"Search the marketplace","description":"Only items with at least one version that is not blocked. `facets.kinds` counts per kind without the kind filter; `facets.tags` lists the most used tags within the kind.","parameters":[{"name":"q","in":"query","required":false,"description":"Search in name, title and description","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"description":"Filter by kind","schema":{"type":"string","enum":["script","vehicle","map","prop","clothing","gamemode","tool"]}},{"name":"tag","in":"query","required":false,"description":"Filter by tag","schema":{"type":"string"}},{"name":"owner","in":"query","required":false,"description":"Filter by owner handle","schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"description":"Default: recently updated","schema":{"type":"string","enum":["new","created","downloads","name"]}},{"name":"limit","in":"query","required":false,"description":"Page size, 1 to 100 (default 24)","schema":{"type":"integer","minimum":1,"maximum":100,"default":24}},{"name":"offset","in":"query","required":false,"description":"Number of entries to skip","schema":{"type":"integer","minimum":0,"default":0}}],"security":[],"responses":{"200":{"description":"Results","content":{"application/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","items":{"$ref":"#/components/schemas/ResourceListing"}},"total":{"type":"integer"},"kinds":{"type":"array","items":{"type":"string"}},"facets":{"type":"object","properties":{"kinds":{"type":"object","additionalProperties":{"type":"integer"}},"tags":{"type":"array","items":{"type":"object","properties":{"tag":{"type":"string"},"n":{"type":"integer"}},"required":["tag","n"]}}},"required":["kinds","tags"]}},"required":["resources","total","kinds","facets"]}}}}},"x-gampeon-auth":"none"},"post":{"operationId":"createResource","tags":["Marketplace"],"summary":"Create a marketplace item","description":"Creates the entry. It becomes visible once a version is published. New items are free; set a price in GAMPEONS later with `PATCH`.\n\nAccess tokens: scope `marketplace:write`.\n\nRate limit: 20 per hour per account.","security":[{"session":[]},{"accessToken":["marketplace:write"]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"kind":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}},"required":["name","title","description","kind","tags"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `insufficient_scope`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `name_taken`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 20 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-token-scope":"marketplace:write","x-gampeon-rate-limit":"20 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Unique name, `a-z`, `0-9`, `_`, `-`","pattern":"^[a-z0-9][a-z0-9_\\-]{1,47}$"},"title":{"type":"string","description":"Default: the name","maxLength":80},"description":{"type":"string","maxLength":2000},"kind":{"type":"string","enum":["script","vehicle","map","prop","clothing","gamemode","tool"],"description":"Default: script"},"tags":{"type":"array","items":{"type":"string","pattern":"^[a-z0-9][a-z0-9\\-]{0,23}$"},"description":"Up to 10 lowercase tags (`a-z`, `0-9`, `-`, max. 24 characters each).","maxItems":10}},"required":["name"]}}}}}},"/v1/resources/{name}":{"get":{"operationId":"getResource","tags":["Marketplace"],"summary":"Marketplace item","description":"With all versions that are not blocked. For paid items the version `url` is `null`; buyers get a download link from `…/download`. With a session, `owned` says whether you may download it.\n\nNot available with access tokens.","parameters":[{"name":"name","in":"path","required":true,"description":"Resource name","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9_\\-]{1,47}$"}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceDetail"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"},"patch":{"operationId":"updateResource","tags":["Marketplace"],"summary":"Change a marketplace item","description":"Only the owner. Fields you leave out stay unchanged. A price above 0 requires the seller terms (`POST /v1/wallet/seller-terms`) and an active GAMPEONS mode.\n\nAccess tokens: scope `marketplace:write`, without `price`.\n\nRate limit: 120 edits per hour per account.","parameters":[{"name":"name","in":"path","required":true,"description":"Resource name","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9_\\-]{1,47}$"}}],"security":[{"session":[]},{"accessToken":["marketplace:write"]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"kind":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"project":{"oneOf":[{"$ref":"#/components/schemas/ProjectRef"},{"type":"null"}]},"price":{"type":"integer"}},"required":["name","title","description","kind","tags","project","price"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `insufficient_scope`, `token_not_allowed`, `forbidden`, `seller_terms_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`, `project_not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 edits per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `payments_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-token-scope":"marketplace:write","x-gampeon-rate-limit":"120 edits per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"description":{"type":"string","maxLength":2000},"kind":{"type":"string","enum":["script","vehicle","map","prop","clothing","gamemode","tool"]},"tags":{"type":"array","items":{"type":"string","pattern":"^[a-z0-9][a-z0-9\\-]{0,23}$"},"description":"Up to 10 lowercase tags (`a-z`, `0-9`, `-`, max. 24 characters each).","maxItems":10},"project":{"oneOf":[{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},{"type":"null"},{"const":""}],"description":"Slug of a project you work on (owner, studio member). `null` or an empty string removes the link."},"price":{"type":"integer","description":"Price in GAMPEONS. 0 = free, otherwise 10 to 1,000,000","minimum":0,"maximum":1000000}},"required":[]}}}}}},"/v1/resources/{name}/versions":{"post":{"operationId":"createVersion","tags":["Marketplace"],"summary":"Announce a version","description":"Registers a version with size and checksum. **Requires the explicit rights confirmation by the creator**: `rightsConfirmed: true` and the exact current text from `GET /v1/legal/rights-statement`. Both are stored. Then upload the file with `PUT …/file`.\n\nNot available with access tokens.\n\nRate limit: 30 per hour per account.","parameters":[{"name":"name","in":"path","required":true,"description":"Resource name","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9_\\-]{1,47}$"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Version registered","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"},"sha256":{"type":"string"},"sizeBytes":{"type":"integer"}},"required":["name","version","sha256","sizeBytes"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `version_exists`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `rights_confirmation_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"string","description":"Semantic version, for example `1.0.0`","pattern":"^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z.\\-]+)?$"},"sha256":{"type":"string","description":"SHA-256 of the file (lowercase hex)","pattern":"^[a-f0-9]{64}$"},"sizeBytes":{"type":"integer","description":"File size in bytes","minimum":1},"rightsConfirmed":{"const":true},"rightsStatement":{"type":"string","description":"Exact text of the current rights statement"}},"required":["version","sha256","sizeBytes","rightsConfirmed","rightsStatement"]}}}}}},"/v1/resources/{name}/versions/{version}/download":{"get":{"operationId":"getDownloadInfo","tags":["Marketplace"],"summary":"Download information","description":"For paid items only the owner, moderators and buyers get an answer. Their `url` carries a `grant` that is valid for 10 minutes.\n\nNot available with access tokens.","parameters":[{"name":"name","in":"path","required":true,"description":"Resource name","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9_\\-]{1,47}$"}},{"name":"version","in":"path","required":true,"description":"Version","schema":{"type":"string","pattern":"^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z.\\-]+)?$"}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Checksum, size and file path","content":{"application/json":{"schema":{"type":"object","properties":{"sha256":{"type":"string"},"sizeBytes":{"type":"integer"},"url":{"oneOf":[{"type":"string","description":"Path relative to the API, `null` until uploaded"},{"type":"null"}]}},"required":["sha256","sizeBytes","url"]}}}},"403":{"description":"Error codes: `token_not_allowed`, `purchase_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"451":{"description":"Error codes: `unavailable_for_legal_reasons`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"}},"/v1/resources/{name}/versions/{version}/file":{"put":{"operationId":"uploadVersionFile","tags":["Marketplace"],"summary":"Upload the file of a version","description":"Only the owner, once per version. Size and SHA-256 must match the announced version. Default limits: 256 MB per file, 2 GB per account.\n\nNot available with access tokens.\n\nRate limit: 30 per hour per account.","parameters":[{"name":"name","in":"path","required":true,"description":"Resource name","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9_\\-]{1,47}$"}},{"name":"version","in":"path","required":true,"description":"Version","schema":{"type":"string","pattern":"^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z.\\-]+)?$"}},{"name":"x-file-name","in":"header","required":false,"description":"Optional file name for downloads (sanitised)","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Stored","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"},"sha256":{"type":"string"},"sizeBytes":{"type":"integer"},"url":{"type":"string"}},"required":["name","version","sha256","sizeBytes","url"]}}}},"400":{"description":"Error codes: `size_mismatch`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `file_exists`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error codes: `file_too_large`, `quota_exceeded`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Error codes: `unsupported_media_type`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `checksum_mismatch`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"451":{"description":"Error codes: `unavailable_for_legal_reasons`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `storage_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 per hour per account","requestBody":{"required":true,"description":"The file","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}}},"get":{"operationId":"downloadVersionFile","tags":["Marketplace"],"summary":"Download a version","description":"Counts at most one download per IP and version in 24 hours. Paid items need the `grant` from `…/download`.\n\nRate limit: 120 per hour per IP.","parameters":[{"name":"name","in":"path","required":true,"description":"Resource name","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9_\\-]{1,47}$"}},{"name":"version","in":"path","required":true,"description":"Version","schema":{"type":"string","pattern":"^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z.\\-]+)?$"}},{"name":"grant","in":"query","required":false,"description":"Download grant for paid items, from `…/download`","schema":{"type":"string"}}],"security":[],"responses":{"200":{"description":"The file as attachment","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"403":{"description":"Error codes: `purchase_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`, `file_missing`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 per hour per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"451":{"description":"Error codes: `unavailable_for_legal_reasons`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `storage_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"120 per hour per IP"}},"/v1/resources/{name}/image":{"put":{"operationId":"uploadResourceImage","tags":["Marketplace"],"summary":"Upload a preview image","description":"PNG, JPEG or WebP up to 2 MB. The type is checked against the first bytes of the file. No SVG.\n\nNot available with access tokens.\n\nRate limit: 30 per hour per account.","parameters":[{"name":"name","in":"path","required":true,"description":"Resource name","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9_\\-]{1,47}$"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Stored","content":{"application/json":{"schema":{"type":"object","properties":{"image":{"type":"string","description":"Path relative to the API"}},"required":["image"]}}}},"400":{"description":"Error codes: `invalid_image`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error codes: `file_too_large`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Error codes: `unsupported_media_type`, `invalid_image`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `storage_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 per hour per account","requestBody":{"required":true,"description":"The image","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}}}}}},"/v1/images/{file}":{"get":{"operationId":"getImage","tags":["Marketplace"],"summary":"Preview image","description":"Only delivered while the item has a version that is not blocked.","parameters":[{"name":"file","in":"path","required":true,"description":"`<sha256>.<png|jpg|webp>`","schema":{"type":"string"}}],"security":[],"responses":{"200":{"description":"The image","content":{"image/*":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `storage_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none"}},"/v1/me/resources":{"get":{"operationId":"listMyResources","tags":["Marketplace"],"summary":"Your marketplace items","description":"Including blocked versions, with storage used and quota.\n\nAccess tokens: scope `marketplace:read`.","security":[{"session":[]},{"accessToken":["marketplace:read"]}],"responses":{"200":{"description":"Items","content":{"application/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","items":{"$ref":"#/components/schemas/MyResource"}},"storage":{"oneOf":[{"type":"object","properties":{"usedBytes":{"type":"integer"},"quotaBytes":{"type":"integer"}},"required":["usedBytes","quotaBytes"]},{"type":"null"}]}},"required":["resources","storage"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `insufficient_scope`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-token-scope":"marketplace:read"}},"/v1/legal/report-categories":{"get":{"operationId":"getReportCategories","tags":["Reports and moderation"],"summary":"Report categories","security":[],"responses":{"200":{"description":"Categories","content":{"application/json":{"schema":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"string","enum":["copyright","trademark","illegal_content","malware","other"]}}},"required":["categories"]}}}}},"x-gampeon-auth":"none"}},"/v1/reports":{"post":{"operationId":"createReport","tags":["Reports and moderation"],"summary":"Report content","description":"Notice under Art. 16 DSA. Works without an account. The reporting person gets a confirmation and later the decision.\n\nRate limit: 10 per hour per IP.","security":[],"responses":{"201":{"description":"Report received","content":{"application/json":{"schema":{"type":"object","properties":{"reportId":{"type":"string"},"status":{"const":"open"}},"required":["reportId","status"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `good_faith_confirmation_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"10 per hour per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"resource":{"type":"string","pattern":"^[a-z0-9][a-z0-9_\\-]{1,47}$"},"version":{"type":"string","pattern":"^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z.\\-]+)?$"},"category":{"type":"string","enum":["copyright","trademark","illegal_content","malware","other"]},"explanation":{"type":"string","minLength":20,"maxLength":5000},"reporterName":{"type":"string","minLength":2,"maxLength":120},"reporterEmail":{"type":"string","format":"email","maxLength":254},"goodFaith":{"const":true,"description":"Confirms the report is made in good faith"}},"required":["resource","version","category","explanation","reporterName","reporterEmail","goodFaith"]}}}}}},"/v1/moderation/reports":{"get":{"operationId":"listReports","tags":["Reports and moderation"],"summary":"Reports","description":"Requires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"status","in":"query","required":false,"description":"Default: open","schema":{"type":"string","enum":["open","actioned","rejected"]}}],"security":[{"session":[]}],"responses":{"200":{"description":"Up to 200 reports, oldest first","content":{"application/json":{"schema":{"type":"object","properties":{"reports":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"category":{"type":"string"},"explanation":{"type":"string"},"reporterName":{"type":"string"},"status":{"type":"string"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"resource":{"type":"string"},"version":{"type":"string"},"blocked":{"type":"integer"}},"required":["id","category","explanation","reporterName","status","createdAt","resource","version","blocked"]}}},"required":["reports"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator"}},"/v1/moderation/reports/{id}/decision":{"post":{"operationId":"decideReport","tags":["Reports and moderation"],"summary":"Decide on a report","description":"`block` blocks the version and informs the creator with the statement of reasons (Art. 17 DSA). `reject` keeps it. The reporting person is informed either way.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Report ID","schema":{"type":"string","format":"uuid"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string"},"action":{"type":"string"}},"required":["decisionId","action"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_decided`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["block","reject"]},"statementOfReasons":{"type":"string","description":"Statement of reasons, 20 to 5000 characters. Shown to the people affected.","minLength":20,"maxLength":5000},"legalGround":{"type":"string","maxLength":500}},"required":["action","statementOfReasons"]}}}}}},"/v1/appeals":{"post":{"operationId":"createAppeal","tags":["Reports and moderation"],"summary":"Appeal a decision","description":"Complaint by the creator under Art. 20 DSA, one per decision.\n\nNot available with access tokens.\n\nRate limit: 10 per day per account.","security":[{"session":[]}],"responses":{"201":{"description":"Appeal received","content":{"application/json":{"schema":{"type":"object","properties":{"appealId":{"type":"string"},"status":{"const":"open"}},"required":["appealId","status"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `appeal_exists`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per day per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"10 per day per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string"},"text":{"type":"string","minLength":20,"maxLength":5000}},"required":["decisionId","text"]}}}}}},"/v1/me/appeals":{"get":{"operationId":"listMyAppeals","tags":["Reports and moderation"],"summary":"Your appeals","description":"Not available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Appeals","content":{"application/json":{"schema":{"type":"object","properties":{"appeals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"decisionId":{"type":"string"},"status":{"type":"string","enum":["open","upheld","reversed"]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"decidedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"outcomeReasons":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","decisionId","status","createdAt","decidedAt","outcomeReasons"]}}},"required":["appeals"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/moderation/appeals":{"get":{"operationId":"listAppeals","tags":["Reports and moderation"],"summary":"Appeals","description":"`ownDecision` shows whether you made the original decision yourself; appeals should be reviewed by someone else where possible.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"status","in":"query","required":false,"description":"Default: open","schema":{"type":"string","enum":["open","upheld","reversed"]}}],"security":[{"session":[]}],"responses":{"200":{"description":"Up to 200 appeals, oldest first","content":{"application/json":{"schema":{"type":"object","properties":{"appeals":{"type":"array","items":{"type":"object","properties":{"ownDecision":{"type":"boolean"},"blocked":{"type":"boolean"}}}}},"required":["appeals"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator"}},"/v1/moderation/appeals/{id}/decision":{"post":{"operationId":"decideAppeal","tags":["Reports and moderation"],"summary":"Decide on an appeal","description":"`reverse` unblocks the version if no other block applies. The creator gets the statement of reasons and the notice on Art. 21 DSA.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Appeal ID","schema":{"type":"string","format":"uuid"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"appealId":{"type":"string"},"outcome":{"type":"string"},"unblocked":{"type":"boolean"}},"required":["appealId","outcome","unblocked"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_decided`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","enum":["uphold","reverse"]},"statementOfReasons":{"type":"string","description":"Statement of reasons, 20 to 5000 characters. Shown to the people affected.","minLength":20,"maxLength":5000}},"required":["outcome","statementOfReasons"]}}}}}},"/v1/moderation/stats":{"get":{"operationId":"getModerationStats","tags":["Reports and moderation"],"summary":"Numbers for the transparency report","description":"Requires the role moderator or admin.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Counts","content":{"application/json":{"schema":{"type":"object","properties":{"reports":{"type":"array","items":{"type":"object"}},"decisions":{"type":"array","items":{"type":"object"}},"appeals":{"type":"array","items":{"type":"object"}}},"required":["reports","decisions","appeals"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator"}},"/v1/moderation/pages/{type}/{slug}":{"post":{"operationId":"moderatePage","tags":["Reports and moderation"],"summary":"Hide or restore a studio or project page","description":"With a statement of reasons (Art. 17 DSA). Owners and admins are informed, every decision is logged.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"type","in":"path","required":true,"description":"`studio` or `project`","schema":{"type":"string","enum":["studio","project"]}},{"name":"slug","in":"path","required":true,"description":"Slug of the page","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string"},"type":{"type":"string"},"slug":{"type":"string"},"action":{"type":"string"}},"required":["decisionId","type","slug","action"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_hidden`, `not_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["hide","restore"]},"statementOfReasons":{"type":"string","description":"Statement of reasons, 20 to 5000 characters. Shown to the people affected.","minLength":20,"maxLength":5000}},"required":["action","statementOfReasons"]}}}}}},"/v1/moderation/pages":{"get":{"operationId":"listHiddenPages","tags":["Reports and moderation"],"summary":"Hidden pages","description":"Requires the role moderator or admin.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Hidden studios and projects and decision counts","content":{"application/json":{"schema":{"type":"object","properties":{"hidden":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"hiddenAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["type","slug","title","hiddenAt","reason"]}},"decisions":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"action":{"type":"string"},"n":{"type":"integer"}},"required":["type","action","n"]}}},"required":["hidden","decisions"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator"}},"/v1/wallet/packages":{"get":{"operationId":"listCoinPackages","tags":["GAMPEONS"],"summary":"GAMPEONS packages and rules","description":"Packages with euro prices including VAT. `reference` is the basis for the euro value shown next to prices in GAMPEONS.","security":[],"responses":{"200":{"description":"Packages","content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["off","sandbox"],"description":"`off`: payments are switched off. `sandbox`: payments are simulated, no real money moves."},"provider":{"type":"string","enum":["sandbox","xsolla"],"description":"`sandbox`: simulated payment with `POST /v1/wallet/orders/:id/sandbox-pay`. `xsolla`: Xsolla test payment through `POST /v1/wallet/orders/:id/checkout`."},"currency":{"type":"string"},"packages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"priceCents":{"type":"integer","description":"Price including VAT","minimum":0}},"required":["id","coins","priceCents"]}},"reference":{"type":"object","properties":{"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"priceCents":{"type":"integer","description":"Euro cents","minimum":0}},"required":["coins","priceCents"]},"terms":{"type":"string","description":"Purchase terms"},"rules":{"type":"object","properties":{"creatorShareBps":{"type":"integer","description":"Creator share of each sale in basis points (7000 = 70 %)"},"payoutRateMicros":{"type":"integer","description":"Payout per earned GAMPEON in millionths of a euro (3800 = €0.0038)"},"payoutCurrency":{"type":"string"},"payoutMinCoins":{"type":"integer","description":"Minimum payout","minimum":0},"holdDays":{"type":"integer","description":"Days before a creator share can be spent or paid out"},"withdrawalDays":{"type":"integer","description":"Days to withdraw from an unused purchase"},"monthlyLimitCents":{"type":"integer","description":"Most an account can spend on GAMPEONS in 30 days","minimum":0},"minPrice":{"type":"integer","description":"Lowest price for an item","minimum":0},"maxPrice":{"type":"integer","description":"Highest price for an item","minimum":0}},"required":["creatorShareBps","payoutRateMicros","payoutCurrency","payoutMinCoins","holdDays","withdrawalDays","monthlyLimitCents","minPrice","maxPrice"]}},"required":["mode","provider","currency","packages","reference","terms","rules"]}}}}},"x-gampeon-auth":"none"}},"/v1/legal/wallet-terms":{"get":{"operationId":"getWalletTerms","tags":["GAMPEONS"],"summary":"Purchase, seller and payout terms","description":"Placeholders until legal review.","security":[],"responses":{"200":{"description":"Terms","content":{"application/json":{"schema":{"type":"object","properties":{"order":{"type":"string"},"seller":{"type":"string"},"payout":{"type":"string"}},"required":["order","seller","payout"]}}}}},"x-gampeon-auth":"none"}},"/v1/wallet":{"get":{"operationId":"getWallet","tags":["GAMPEONS"],"summary":"Your wallet","description":"Balances, status and rules. Unlocks creator shares whose holding period is over.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Wallet","content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["off","sandbox"],"description":"`off`: payments are switched off. `sandbox`: payments are simulated, no real money moves."},"balances":{"type":"object","properties":{"wallet":{"type":"integer","description":"Bought or gifted. Spendable, never paid out","minimum":0},"pending":{"type":"integer","description":"Earned, still in the holding period","minimum":0},"earned":{"type":"integer","description":"Earned. Spendable and can be paid out","minimum":0},"payoutHold":{"type":"integer","description":"Reserved for a payout request","minimum":0},"spendable":{"type":"integer","description":"wallet + earned","minimum":0}},"required":["wallet","pending","earned","payoutHold","spendable"]},"locked":{"type":"boolean","description":"Locked after a chargeback. Buying, spending and payouts are blocked"},"sellerTerms":{"type":"boolean","description":"Seller terms accepted, prices can be set"},"payoutProgram":{"type":"string","enum":["none","pending","approved","rejected","suspended"]},"upcoming":{"type":"array","items":{"type":"object","properties":{"availableAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0}},"required":["availableAt","coins"]},"description":"Creator shares that unlock next"},"limits":{"type":"object","properties":{"monthlyLimitCents":{"type":"integer","description":"Euro cents","minimum":0},"usedCents":{"type":"integer","description":"Spent or in open orders in the last 30 days","minimum":0}},"required":["monthlyLimitCents","usedCents"]},"rules":{"type":"object","properties":{"creatorShareBps":{"type":"integer","description":"Creator share of each sale in basis points (7000 = 70 %)"},"payoutRateMicros":{"type":"integer","description":"Payout per earned GAMPEON in millionths of a euro (3800 = €0.0038)"},"payoutCurrency":{"type":"string"},"payoutMinCoins":{"type":"integer","description":"Minimum payout","minimum":0},"holdDays":{"type":"integer","description":"Days before a creator share can be spent or paid out"},"withdrawalDays":{"type":"integer","description":"Days to withdraw from an unused purchase"},"monthlyLimitCents":{"type":"integer","description":"Most an account can spend on GAMPEONS in 30 days","minimum":0},"minPrice":{"type":"integer","description":"Lowest price for an item","minimum":0},"maxPrice":{"type":"integer","description":"Highest price for an item","minimum":0}},"required":["creatorShareBps","payoutRateMicros","payoutCurrency","payoutMinCoins","holdDays","withdrawalDays","monthlyLimitCents","minPrice","maxPrice"]}},"required":["mode","balances","locked","sellerTerms","payoutProgram","upcoming","limits","rules"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/wallet/transactions":{"get":{"operationId":"listWalletTransactions","tags":["GAMPEONS"],"summary":"Your transactions","description":"Newest first. `changes` holds only your own accounts; a sale never shows who bought.\n\nNot available with access tokens.","parameters":[{"name":"limit","in":"query","required":false,"description":"1 to 100, default 25","schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Skip this many","schema":{"type":"integer"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Transactions","content":{"application/json":{"schema":{"type":"object","properties":{"transactions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"kind":{"type":"string"},"memo":{"type":"string"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"changes":{"type":"object","additionalProperties":{"type":"integer"},"description":"Change per account (wallet, pending, earned, payout_hold)"}},"required":["id","kind","memo","createdAt","changes"]}}},"required":["transactions"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/wallet/orders":{"get":{"operationId":"listCoinOrders","tags":["GAMPEONS"],"summary":"Your GAMPEONS purchases","description":"Not available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Orders","content":{"application/json":{"schema":{"type":"object","properties":{"orders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"packageId":{"type":"string"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"priceCents":{"type":"integer","description":"Euro cents","minimum":0},"currency":{"type":"string"},"status":{"type":"string","enum":["pending","expired","paid","refunded","charged_back"]},"provider":{"type":"string","enum":["sandbox","xsolla"],"description":"`sandbox`: simulated payment with `POST /v1/wallet/orders/:id/sandbox-pay`. `xsolla`: Xsolla test payment through `POST /v1/wallet/orders/:id/checkout`."},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"paidAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"closedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"withdrawableUntil":{"oneOf":[{"type":"integer","format":"int64","description":"Set while the purchase can still be withdrawn"},{"type":"null"}]}},"required":["id","packageId","coins","priceCents","currency","status","provider","createdAt","expiresAt","paidAt","closedAt","withdrawableUntil"]}}},"required":["orders"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"},"post":{"operationId":"createCoinOrder","tags":["GAMPEONS"],"summary":"Start a GAMPEONS purchase","description":"The price comes from the server. The order expires after one hour.\n\nNot available with access tokens.\n\nRate limit: 20 per hour per account.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Required. 8 to 100 characters (`A-Z a-z 0-9 _ - : .`). The same key with the same body returns the stored answer (`replayed: true`) without booking again.","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Order","content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["off","sandbox"],"description":"`off`: payments are switched off. `sandbox`: payments are simulated, no real money moves."},"order":{"type":"object","properties":{"id":{"type":"string"},"packageId":{"type":"string"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"priceCents":{"type":"integer","description":"Euro cents","minimum":0},"currency":{"type":"string"},"status":{"type":"string","enum":["pending","expired","paid","refunded","charged_back"]},"provider":{"type":"string","enum":["sandbox","xsolla"],"description":"`sandbox`: simulated payment with `POST /v1/wallet/orders/:id/sandbox-pay`. `xsolla`: Xsolla test payment through `POST /v1/wallet/orders/:id/checkout`."},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"paidAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"closedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"withdrawableUntil":{"oneOf":[{"type":"integer","format":"int64","description":"Set while the purchase can still be withdrawn"},{"type":"null"}]}},"required":["id","packageId","coins","priceCents","currency","status","provider","createdAt","expiresAt","paidAt","closedAt","withdrawableUntil"]},"checkout":{"type":"object","properties":{"provider":{"type":"string","enum":["sandbox","xsolla"],"description":"`sandbox`: simulated payment with `POST /v1/wallet/orders/:id/sandbox-pay`. `xsolla`: Xsolla test payment through `POST /v1/wallet/orders/:id/checkout`."}},"required":["provider"]}},"required":["mode","order","checkout"]}}}},"400":{"description":"Error codes: `invalid_field`, `idempotency_key_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `wallet_locked`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `monthly_limit`, `idempotency_conflict`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `terms_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 20 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `payments_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"20 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"packageId":{"type":"string"},"terms":{"type":"string","description":"Exact current purchase terms"}},"required":["packageId","terms"]}}}}}},"/v1/wallet/orders/{id}/sandbox-pay":{"post":{"operationId":"sandboxPayCoinOrder","tags":["GAMPEONS"],"summary":"Sandbox: simulate a payment","description":"Only in sandbox mode with simulated payments (`provider: sandbox`). Stands in for the payment provider confirming the payment and credits the GAMPEONS.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Order ID (`ord_…`)","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Required. 8 to 100 characters (`A-Z a-z 0-9 _ - : .`). The same key with the same body returns the stored answer (`replayed: true`) without booking again.","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Paid","content":{"application/json":{"schema":{"type":"object","properties":{"order":{"type":"object","properties":{"id":{"type":"string"},"packageId":{"type":"string"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"priceCents":{"type":"integer","description":"Euro cents","minimum":0},"currency":{"type":"string"},"status":{"type":"string","enum":["pending","expired","paid","refunded","charged_back"]},"provider":{"type":"string","enum":["sandbox","xsolla"],"description":"`sandbox`: simulated payment with `POST /v1/wallet/orders/:id/sandbox-pay`. `xsolla`: Xsolla test payment through `POST /v1/wallet/orders/:id/checkout`."},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"paidAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"closedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"withdrawableUntil":{"oneOf":[{"type":"integer","format":"int64","description":"Set while the purchase can still be withdrawn"},{"type":"null"}]}},"required":["id","packageId","coins","priceCents","currency","status","provider","createdAt","expiresAt","paidAt","closedAt","withdrawableUntil"]},"wallet":{"type":"object","properties":{"mode":{"type":"string","enum":["off","sandbox"],"description":"`off`: payments are switched off. `sandbox`: payments are simulated, no real money moves."},"balances":{"type":"object","properties":{"wallet":{"type":"integer","description":"Bought or gifted. Spendable, never paid out","minimum":0},"pending":{"type":"integer","description":"Earned, still in the holding period","minimum":0},"earned":{"type":"integer","description":"Earned. Spendable and can be paid out","minimum":0},"payoutHold":{"type":"integer","description":"Reserved for a payout request","minimum":0},"spendable":{"type":"integer","description":"wallet + earned","minimum":0}},"required":["wallet","pending","earned","payoutHold","spendable"]},"locked":{"type":"boolean","description":"Locked after a chargeback. Buying, spending and payouts are blocked"},"sellerTerms":{"type":"boolean","description":"Seller terms accepted, prices can be set"},"payoutProgram":{"type":"string","enum":["none","pending","approved","rejected","suspended"]},"upcoming":{"type":"array","items":{"type":"object","properties":{"availableAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0}},"required":["availableAt","coins"]},"description":"Creator shares that unlock next"},"limits":{"type":"object","properties":{"monthlyLimitCents":{"type":"integer","description":"Euro cents","minimum":0},"usedCents":{"type":"integer","description":"Spent or in open orders in the last 30 days","minimum":0}},"required":["monthlyLimitCents","usedCents"]},"rules":{"type":"object","properties":{"creatorShareBps":{"type":"integer","description":"Creator share of each sale in basis points (7000 = 70 %)"},"payoutRateMicros":{"type":"integer","description":"Payout per earned GAMPEON in millionths of a euro (3800 = €0.0038)"},"payoutCurrency":{"type":"string"},"payoutMinCoins":{"type":"integer","description":"Minimum payout","minimum":0},"holdDays":{"type":"integer","description":"Days before a creator share can be spent or paid out"},"withdrawalDays":{"type":"integer","description":"Days to withdraw from an unused purchase"},"monthlyLimitCents":{"type":"integer","description":"Most an account can spend on GAMPEONS in 30 days","minimum":0},"minPrice":{"type":"integer","description":"Lowest price for an item","minimum":0},"maxPrice":{"type":"integer","description":"Highest price for an item","minimum":0}},"required":["creatorShareBps","payoutRateMicros","payoutCurrency","payoutMinCoins","holdDays","withdrawalDays","monthlyLimitCents","minPrice","maxPrice"]}},"required":["mode","balances","locked","sellerTerms","payoutProgram","upcoming","limits","rules"]}},"required":["order","wallet"]}}}},"400":{"description":"Error codes: `idempotency_key_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `wallet_locked`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `order_not_pending`, `order_expired`, `idempotency_conflict`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `payments_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/wallet/orders/{id}/checkout":{"post":{"operationId":"checkoutCoinOrder","tags":["GAMPEONS"],"summary":"Xsolla: payment page for an order","description":"Only with `provider: xsolla`. Returns the link to the Xsolla Pay Station in test mode (no real money). Asking again returns the same link. The GAMPEONS are credited when Xsolla confirms the payment, then `GET /v1/wallet/orders` shows the order as `paid`.\n\nNot available with access tokens.\n\nRate limit: 30 per hour per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Order ID (`ord_…`)","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Payment page","content":{"application/json":{"schema":{"type":"object","properties":{"order":{"type":"object","properties":{"id":{"type":"string"},"packageId":{"type":"string"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"priceCents":{"type":"integer","description":"Euro cents","minimum":0},"currency":{"type":"string"},"status":{"type":"string","enum":["pending","expired","paid","refunded","charged_back"]},"provider":{"type":"string","enum":["sandbox","xsolla"],"description":"`sandbox`: simulated payment with `POST /v1/wallet/orders/:id/sandbox-pay`. `xsolla`: Xsolla test payment through `POST /v1/wallet/orders/:id/checkout`."},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"paidAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"closedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"withdrawableUntil":{"oneOf":[{"type":"integer","format":"int64","description":"Set while the purchase can still be withdrawn"},{"type":"null"}]}},"required":["id","packageId","coins","priceCents","currency","status","provider","createdAt","expiresAt","paidAt","closedAt","withdrawableUntil"]},"checkout":{"type":"object","properties":{"provider":{"const":"xsolla"},"url":{"type":"string","description":"Xsolla Pay Station (test mode)"},"sandbox":{"const":true}},"required":["provider","url","sandbox"]}},"required":["order","checkout"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `wallet_locked`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `order_not_pending`, `order_expired`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Error codes: `payment_unreachable`, `payment_refused`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `payments_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 per hour per account"}},"/v1/payments/xsolla/webhook":{"post":{"operationId":"xsollaWebhook","tags":["GAMPEONS"],"summary":"Xsolla webhook (called by Xsolla only)","description":"Signed with `Authorization: Signature <sha1(body + secret)>`. Handles `user_validation`, `order_paid` (credits the GAMPEONS once) and `order_canceled` (takes them back like a chargeback). Payments that are not test payments are refused. Errors use Xsolla's format `{ \"error\": { \"code\": \"INVALID_SIGNATURE\" | \"INVALID_USER\" | \"INVALID_PARAMETER\", \"message\": \"…\" } }`. Only active in sandbox mode with `provider: xsolla`.","security":[],"responses":{"204":{"description":"Processed"},"400":{"description":"Error codes: `invalid_field`, `INVALID_USER`, `INVALID_PARAMETER`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `INVALID_SIGNATURE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error codes: `body_too_large`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notification_type":{"type":"string","description":"e.g. `user_validation`, `order_paid`, `order_canceled`"}},"required":["notification_type"]}}}}}},"/v1/wallet/orders/{id}/withdraw":{"post":{"operationId":"withdrawCoinOrder","tags":["GAMPEONS"],"summary":"Withdraw from a purchase","description":"Within 14 days, and only if no GAMPEONS from this purchase have been used.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Order ID (`ord_…`)","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Required. 8 to 100 characters (`A-Z a-z 0-9 _ - : .`). The same key with the same body returns the stored answer (`replayed: true`) without booking again.","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Withdrawn","content":{"application/json":{"schema":{"type":"object","properties":{"order":{"type":"object","properties":{"id":{"type":"string"},"packageId":{"type":"string"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"priceCents":{"type":"integer","description":"Euro cents","minimum":0},"currency":{"type":"string"},"status":{"type":"string","enum":["pending","expired","paid","refunded","charged_back"]},"provider":{"type":"string","enum":["sandbox","xsolla"],"description":"`sandbox`: simulated payment with `POST /v1/wallet/orders/:id/sandbox-pay`. `xsolla`: Xsolla test payment through `POST /v1/wallet/orders/:id/checkout`."},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"paidAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"closedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"withdrawableUntil":{"oneOf":[{"type":"integer","format":"int64","description":"Set while the purchase can still be withdrawn"},{"type":"null"}]}},"required":["id","packageId","coins","priceCents","currency","status","provider","createdAt","expiresAt","paidAt","closedAt","withdrawableUntil"]},"wallet":{"type":"object","properties":{"mode":{"type":"string","enum":["off","sandbox"],"description":"`off`: payments are switched off. `sandbox`: payments are simulated, no real money moves."},"balances":{"type":"object","properties":{"wallet":{"type":"integer","description":"Bought or gifted. Spendable, never paid out","minimum":0},"pending":{"type":"integer","description":"Earned, still in the holding period","minimum":0},"earned":{"type":"integer","description":"Earned. Spendable and can be paid out","minimum":0},"payoutHold":{"type":"integer","description":"Reserved for a payout request","minimum":0},"spendable":{"type":"integer","description":"wallet + earned","minimum":0}},"required":["wallet","pending","earned","payoutHold","spendable"]},"locked":{"type":"boolean","description":"Locked after a chargeback. Buying, spending and payouts are blocked"},"sellerTerms":{"type":"boolean","description":"Seller terms accepted, prices can be set"},"payoutProgram":{"type":"string","enum":["none","pending","approved","rejected","suspended"]},"upcoming":{"type":"array","items":{"type":"object","properties":{"availableAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0}},"required":["availableAt","coins"]},"description":"Creator shares that unlock next"},"limits":{"type":"object","properties":{"monthlyLimitCents":{"type":"integer","description":"Euro cents","minimum":0},"usedCents":{"type":"integer","description":"Spent or in open orders in the last 30 days","minimum":0}},"required":["monthlyLimitCents","usedCents"]},"rules":{"type":"object","properties":{"creatorShareBps":{"type":"integer","description":"Creator share of each sale in basis points (7000 = 70 %)"},"payoutRateMicros":{"type":"integer","description":"Payout per earned GAMPEON in millionths of a euro (3800 = €0.0038)"},"payoutCurrency":{"type":"string"},"payoutMinCoins":{"type":"integer","description":"Minimum payout","minimum":0},"holdDays":{"type":"integer","description":"Days before a creator share can be spent or paid out"},"withdrawalDays":{"type":"integer","description":"Days to withdraw from an unused purchase"},"monthlyLimitCents":{"type":"integer","description":"Most an account can spend on GAMPEONS in 30 days","minimum":0},"minPrice":{"type":"integer","description":"Lowest price for an item","minimum":0},"maxPrice":{"type":"integer","description":"Highest price for an item","minimum":0}},"required":["creatorShareBps","payoutRateMicros","payoutCurrency","payoutMinCoins","holdDays","withdrawalDays","monthlyLimitCents","minPrice","maxPrice"]}},"required":["mode","balances","locked","sellerTerms","payoutProgram","upcoming","limits","rules"]}},"required":["order","wallet"]}}}},"400":{"description":"Error codes: `idempotency_key_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `order_not_paid`, `withdrawal_period_over`, `already_used`, `idempotency_conflict`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `payments_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/resources/{name}/purchase":{"post":{"operationId":"purchaseResource","tags":["GAMPEONS"],"summary":"Buy a marketplace item","description":"Send the price you were shown as `expectedPrice`. Bought and gifted GAMPEONS are used first (oldest purchase first), then earned ones. The creator share is credited as `pending`.\n\nNot available with access tokens.\n\nRate limit: 60 per hour per account.","parameters":[{"name":"name","in":"path","required":true,"description":"Resource name","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9_\\-]{1,47}$"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Required. 8 to 100 characters (`A-Z a-z 0-9 _ - : .`). The same key with the same body returns the stored answer (`replayed: true`) without booking again.","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Bought","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"price":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"owned":{"const":true},"wallet":{"type":"object","properties":{"mode":{"type":"string","enum":["off","sandbox"],"description":"`off`: payments are switched off. `sandbox`: payments are simulated, no real money moves."},"balances":{"type":"object","properties":{"wallet":{"type":"integer","description":"Bought or gifted. Spendable, never paid out","minimum":0},"pending":{"type":"integer","description":"Earned, still in the holding period","minimum":0},"earned":{"type":"integer","description":"Earned. Spendable and can be paid out","minimum":0},"payoutHold":{"type":"integer","description":"Reserved for a payout request","minimum":0},"spendable":{"type":"integer","description":"wallet + earned","minimum":0}},"required":["wallet","pending","earned","payoutHold","spendable"]},"locked":{"type":"boolean","description":"Locked after a chargeback. Buying, spending and payouts are blocked"},"sellerTerms":{"type":"boolean","description":"Seller terms accepted, prices can be set"},"payoutProgram":{"type":"string","enum":["none","pending","approved","rejected","suspended"]},"upcoming":{"type":"array","items":{"type":"object","properties":{"availableAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0}},"required":["availableAt","coins"]},"description":"Creator shares that unlock next"},"limits":{"type":"object","properties":{"monthlyLimitCents":{"type":"integer","description":"Euro cents","minimum":0},"usedCents":{"type":"integer","description":"Spent or in open orders in the last 30 days","minimum":0}},"required":["monthlyLimitCents","usedCents"]},"rules":{"type":"object","properties":{"creatorShareBps":{"type":"integer","description":"Creator share of each sale in basis points (7000 = 70 %)"},"payoutRateMicros":{"type":"integer","description":"Payout per earned GAMPEON in millionths of a euro (3800 = €0.0038)"},"payoutCurrency":{"type":"string"},"payoutMinCoins":{"type":"integer","description":"Minimum payout","minimum":0},"holdDays":{"type":"integer","description":"Days before a creator share can be spent or paid out"},"withdrawalDays":{"type":"integer","description":"Days to withdraw from an unused purchase"},"monthlyLimitCents":{"type":"integer","description":"Most an account can spend on GAMPEONS in 30 days","minimum":0},"minPrice":{"type":"integer","description":"Lowest price for an item","minimum":0},"maxPrice":{"type":"integer","description":"Highest price for an item","minimum":0}},"required":["creatorShareBps","payoutRateMicros","payoutCurrency","payoutMinCoins","holdDays","withdrawalDays","monthlyLimitCents","minPrice","maxPrice"]}},"required":["mode","balances","locked","sellerTerms","payoutProgram","upcoming","limits","rules"]}},"required":["name","price","owned","wallet"]}}}},"400":{"description":"Error codes: `invalid_field`, `idempotency_key_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `wallet_locked`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `free_item`, `own_item`, `price_changed`, `already_owned`, `insufficient_funds`, `idempotency_conflict`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 60 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `payments_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"60 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"expectedPrice":{"type":"integer","description":"Price shown to the buyer","minimum":0}},"required":["expectedPrice"]}}}}}},"/v1/me/purchases":{"get":{"operationId":"listMyPurchases","tags":["GAMPEONS"],"summary":"Items you bought","description":"Not available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Items","content":{"application/json":{"schema":{"type":"object","properties":{"purchases":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/ResourceListing"},{"type":"object","properties":{"paid":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"boughtAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["paid","boughtAt"]}]}}},"required":["purchases"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/wallet/seller-terms":{"post":{"operationId":"acceptSellerTerms","tags":["GAMPEONS"],"summary":"Accept the seller terms","description":"Needed before setting a price with `PATCH /v1/resources/:name`.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Accepted","content":{"application/json":{"schema":{"type":"object","properties":{"sellerTerms":{"const":true}},"required":["sellerTerms"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `terms_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `payments_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"terms":{"type":"string","description":"Exact current text of the seller terms from `GET /v1/legal/wallet-terms`"}},"required":["terms"]}}}}}},"/v1/wallet/payout-program":{"post":{"operationId":"applyPayoutProgram","tags":["GAMPEONS"],"summary":"Apply for the payout program","description":"18 or older. In sandbox mode an admin decides; later the identity check of the payout provider does.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Application received","content":{"application/json":{"schema":{"type":"object","properties":{"payoutProgram":{"const":"pending"}},"required":["payoutProgram"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `payout_program_suspended`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `payout_program_pending`, `payout_program_approved`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `terms_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `payments_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"terms":{"type":"string","description":"Exact current text of the payout program terms from `GET /v1/legal/wallet-terms`"}},"required":["terms"]}}}}}},"/v1/wallet/payouts":{"get":{"operationId":"listPayouts","tags":["GAMPEONS"],"summary":"Your payouts","description":"Not available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Payouts","content":{"application/json":{"schema":{"type":"object","properties":{"payouts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"rateMicros":{"type":"integer","description":"Rate fixed when the payout was requested"},"currency":{"type":"string"},"amountCents":{"type":"integer","description":"Euro cents","minimum":0},"status":{"type":"string","enum":["requested","paid","rejected"]},"provider":{"type":"string"},"reason":{"oneOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"decidedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["id","coins","rateMicros","currency","amountCents","status","provider","reason","createdAt","decidedAt"]}}},"required":["payouts"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"},"post":{"operationId":"requestPayout","tags":["GAMPEONS"],"summary":"Request a payout","description":"Only earned GAMPEONS, from the minimum amount, one open request at a time. The rate is fixed at the time of the request.\n\nNot available with access tokens.\n\nRate limit: 5 per day per account.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Required. 8 to 100 characters (`A-Z a-z 0-9 _ - : .`). The same key with the same body returns the stored answer (`replayed: true`) without booking again.","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Requested","content":{"application/json":{"schema":{"type":"object","properties":{"payout":{"type":"object","properties":{"id":{"type":"string"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"rateMicros":{"type":"integer","description":"Rate fixed when the payout was requested"},"currency":{"type":"string"},"amountCents":{"type":"integer","description":"Euro cents","minimum":0},"status":{"type":"string","enum":["requested","paid","rejected"]},"provider":{"type":"string"},"reason":{"oneOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"decidedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["id","coins","rateMicros","currency","amountCents","status","provider","reason","createdAt","decidedAt"]},"wallet":{"type":"object","properties":{"mode":{"type":"string","enum":["off","sandbox"],"description":"`off`: payments are switched off. `sandbox`: payments are simulated, no real money moves."},"balances":{"type":"object","properties":{"wallet":{"type":"integer","description":"Bought or gifted. Spendable, never paid out","minimum":0},"pending":{"type":"integer","description":"Earned, still in the holding period","minimum":0},"earned":{"type":"integer","description":"Earned. Spendable and can be paid out","minimum":0},"payoutHold":{"type":"integer","description":"Reserved for a payout request","minimum":0},"spendable":{"type":"integer","description":"wallet + earned","minimum":0}},"required":["wallet","pending","earned","payoutHold","spendable"]},"locked":{"type":"boolean","description":"Locked after a chargeback. Buying, spending and payouts are blocked"},"sellerTerms":{"type":"boolean","description":"Seller terms accepted, prices can be set"},"payoutProgram":{"type":"string","enum":["none","pending","approved","rejected","suspended"]},"upcoming":{"type":"array","items":{"type":"object","properties":{"availableAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0}},"required":["availableAt","coins"]},"description":"Creator shares that unlock next"},"limits":{"type":"object","properties":{"monthlyLimitCents":{"type":"integer","description":"Euro cents","minimum":0},"usedCents":{"type":"integer","description":"Spent or in open orders in the last 30 days","minimum":0}},"required":["monthlyLimitCents","usedCents"]},"rules":{"type":"object","properties":{"creatorShareBps":{"type":"integer","description":"Creator share of each sale in basis points (7000 = 70 %)"},"payoutRateMicros":{"type":"integer","description":"Payout per earned GAMPEON in millionths of a euro (3800 = €0.0038)"},"payoutCurrency":{"type":"string"},"payoutMinCoins":{"type":"integer","description":"Minimum payout","minimum":0},"holdDays":{"type":"integer","description":"Days before a creator share can be spent or paid out"},"withdrawalDays":{"type":"integer","description":"Days to withdraw from an unused purchase"},"monthlyLimitCents":{"type":"integer","description":"Most an account can spend on GAMPEONS in 30 days","minimum":0},"minPrice":{"type":"integer","description":"Lowest price for an item","minimum":0},"maxPrice":{"type":"integer","description":"Highest price for an item","minimum":0}},"required":["creatorShareBps","payoutRateMicros","payoutCurrency","payoutMinCoins","holdDays","withdrawalDays","monthlyLimitCents","minPrice","maxPrice"]}},"required":["mode","balances","locked","sellerTerms","payoutProgram","upcoming","limits","rules"]}},"required":["payout","wallet"]}}}},"400":{"description":"Error codes: `invalid_field`, `idempotency_key_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `payout_program_required`, `wallet_locked`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `below_minimum`, `payout_open`, `insufficient_funds`, `idempotency_conflict`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 5 per day per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `payments_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"5 per day per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"coins":{"type":"integer","minimum":1}},"required":["coins"]}}}}}},"/v1/admin/payout-program":{"get":{"operationId":"listPayoutProgram","tags":["GAMPEONS"],"summary":"Payout program applications","description":"Requires the role admin.\n\nNot available with access tokens.","parameters":[{"name":"status","in":"query","required":false,"description":"Default `pending`","schema":{"type":"string","enum":["pending","approved","rejected","suspended","none"]}}],"security":[{"session":[]}],"responses":{"200":{"description":"Accounts","content":{"application/json":{"schema":{"type":"object","properties":{"accounts":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"status":{"type":"string"},"since":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["handle","displayName","status","since"]}}},"required":["accounts"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"admin"}},"/v1/admin/payout-program/{handle}":{"post":{"operationId":"decidePayoutProgram","tags":["GAMPEONS"],"summary":"Decide on a payout program application","description":"Never on your own account. `reject` and `suspend` need a reason.\n\nRequires the role admin.\n\nNot available with access tokens.","parameters":[{"name":"handle","in":"path","required":true,"description":"Handle of the account","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string"},"payoutProgram":{"type":"string"}},"required":["handle","payoutProgram"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`, `four_eyes_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `no_application`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `payments_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["approve","reject","suspend"]},"reason":{"type":"string","description":"Reason, 5 to 500 characters. Stored in the audit log.","minLength":5,"maxLength":500}},"required":["decision"]}}}}}},"/v1/admin/payouts":{"get":{"operationId":"listPayoutRequests","tags":["GAMPEONS"],"summary":"Payout requests","description":"Requires the role admin.\n\nNot available with access tokens.","parameters":[{"name":"status","in":"query","required":false,"description":"Default `requested`","schema":{"type":"string","enum":["requested","paid","rejected"]}}],"security":[{"session":[]}],"responses":{"200":{"description":"Payouts","content":{"application/json":{"schema":{"type":"object","properties":{"payouts":{"type":"array","items":{"allOf":[{"type":"object","properties":{"id":{"type":"string"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"rateMicros":{"type":"integer","description":"Rate fixed when the payout was requested"},"currency":{"type":"string"},"amountCents":{"type":"integer","description":"Euro cents","minimum":0},"status":{"type":"string","enum":["requested","paid","rejected"]},"provider":{"type":"string"},"reason":{"oneOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"decidedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["id","coins","rateMicros","currency","amountCents","status","provider","reason","createdAt","decidedAt"]},{"type":"object","properties":{"handle":{"type":"string"}},"required":["handle"]}]}}},"required":["payouts"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"admin"}},"/v1/admin/payouts/{id}/decision":{"post":{"operationId":"decidePayout","tags":["GAMPEONS"],"summary":"Approve or decline a payout","description":"Never your own request. In sandbox mode no money moves.\n\nRequires the role admin.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Payout ID (`pay_…`)","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Required. 8 to 100 characters (`A-Z a-z 0-9 _ - : .`). The same key with the same body returns the stored answer (`replayed: true`) without booking again.","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"payout":{"type":"object","properties":{"id":{"type":"string"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"rateMicros":{"type":"integer","description":"Rate fixed when the payout was requested"},"currency":{"type":"string"},"amountCents":{"type":"integer","description":"Euro cents","minimum":0},"status":{"type":"string","enum":["requested","paid","rejected"]},"provider":{"type":"string"},"reason":{"oneOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"decidedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["id","coins","rateMicros","currency","amountCents","status","provider","reason","createdAt","decidedAt"]}},"required":["payout"]}}}},"400":{"description":"Error codes: `invalid_field`, `idempotency_key_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`, `four_eyes_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `payout_not_open`, `idempotency_conflict`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `payments_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["approve","reject"]},"reason":{"type":"string","description":"Reason, 5 to 500 characters. Stored in the audit log.","minLength":5,"maxLength":500}},"required":["decision"]}}}}}},"/v1/admin/wallet/grants":{"post":{"operationId":"grantCoins","tags":["GAMPEONS"],"summary":"Gift GAMPEONS to an account","description":"Never to yourself. Gifted GAMPEONS can be spent but never paid out.\n\nRequires the role admin.\n\nNot available with access tokens.\n\nRate limit: 50 per hour per admin.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Required. 8 to 100 characters (`A-Z a-z 0-9 _ - : .`). The same key with the same body returns the stored answer (`replayed: true`) without booking again.","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Gifted","content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0}},"required":["handle","coins"]}}}},"400":{"description":"Error codes: `invalid_field`, `idempotency_key_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`, `four_eyes_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `idempotency_conflict`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 50 per hour per admin. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `payments_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"admin","x-gampeon-rate-limit":"50 per hour per admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string"},"coins":{"type":"integer","minimum":1,"maximum":100000},"reason":{"type":"string","description":"Reason, 5 to 500 characters. Stored in the audit log.","minLength":5,"maxLength":500}},"required":["handle","coins","reason"]}}}}}},"/v1/admin/wallet/orders/{id}/chargeback":{"post":{"operationId":"sandboxChargeback","tags":["GAMPEONS"],"summary":"Sandbox: simulate a chargeback","description":"Takes back the rest of the purchase, removes items bought with it, reverses creator shares still on hold and locks the wallet.\n\nRequires the role admin.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Order ID (`ord_…`)","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Required. 8 to 100 characters (`A-Z a-z 0-9 _ - : .`). The same key with the same body returns the stored answer (`replayed: true`) without booking again.","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Charged back","content":{"application/json":{"schema":{"type":"object","properties":{"order":{"type":"string"},"status":{"type":"string"},"clawedBack":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"revokedItems":{"type":"integer"}},"required":["order","status","clawedBack","revokedItems"]}}}},"400":{"description":"Error codes: `invalid_field`, `idempotency_key_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `order_not_paid`, `idempotency_conflict`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `payments_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Reason, 5 to 500 characters. Stored in the audit log.","minLength":5,"maxLength":500}},"required":["reason"]}}}}}},"/v1/admin/wallet/{handle}/unlock":{"post":{"operationId":"unlockWallet","tags":["GAMPEONS"],"summary":"Unlock a wallet","description":"Requires the role admin.\n\nNot available with access tokens.","parameters":[{"name":"handle","in":"path","required":true,"description":"Handle of the account","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Unlocked","content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string"},"locked":{"const":false}},"required":["handle","locked"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`, `four_eyes_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Reason, 5 to 500 characters. Stored in the audit log.","minLength":5,"maxLength":500}},"required":["reason"]}}}}}},"/v1/admin/wallet/{handle}":{"get":{"operationId":"getWalletForSupport","tags":["GAMPEONS"],"summary":"Wallet of an account (support)","description":"Requires the role admin.\n\nNot available with access tokens.","parameters":[{"name":"handle","in":"path","required":true,"description":"Handle of the account","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Wallet","content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string"},"balances":{"type":"object","properties":{"wallet":{"type":"integer","description":"Bought or gifted. Spendable, never paid out","minimum":0},"pending":{"type":"integer","description":"Earned, still in the holding period","minimum":0},"earned":{"type":"integer","description":"Earned. Spendable and can be paid out","minimum":0},"payoutHold":{"type":"integer","description":"Reserved for a payout request","minimum":0},"spendable":{"type":"integer","description":"wallet + earned","minimum":0}},"required":["wallet","pending","earned","payoutHold","spendable"]},"payoutProgram":{"type":"string"},"locked":{"type":"boolean"},"lockedReason":{"oneOf":[{"type":"string"},{"type":"null"}]},"orders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"packageId":{"type":"string"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"priceCents":{"type":"integer","description":"Euro cents","minimum":0},"currency":{"type":"string"},"status":{"type":"string","enum":["pending","expired","paid","refunded","charged_back"]},"provider":{"type":"string","enum":["sandbox","xsolla"],"description":"`sandbox`: simulated payment with `POST /v1/wallet/orders/:id/sandbox-pay`. `xsolla`: Xsolla test payment through `POST /v1/wallet/orders/:id/checkout`."},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"paidAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"closedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"withdrawableUntil":{"oneOf":[{"type":"integer","format":"int64","description":"Set while the purchase can still be withdrawn"},{"type":"null"}]}},"required":["id","packageId","coins","priceCents","currency","status","provider","createdAt","expiresAt","paidAt","closedAt","withdrawableUntil"]}},"payouts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"coins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"rateMicros":{"type":"integer","description":"Rate fixed when the payout was requested"},"currency":{"type":"string"},"amountCents":{"type":"integer","description":"Euro cents","minimum":0},"status":{"type":"string","enum":["requested","paid","rejected"]},"provider":{"type":"string"},"reason":{"oneOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"decidedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["id","coins","rateMicros","currency","amountCents","status","provider","reason","createdAt","decidedAt"]}}},"required":["handle","balances","payoutProgram","locked","lockedReason","orders","payouts"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"admin"}},"/v1/admin/ledger/verify":{"get":{"operationId":"verifyLedger","tags":["GAMPEONS"],"summary":"Check the books","description":"Every transaction sums to zero, balances match their entries, both hash chains are intact, no user account is negative, and each wallet matches its open purchases.\n\nRequires the role admin.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Report","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"transactions":{"type":"integer"},"entries":{"type":"integer"},"userCoins":{"type":"integer","description":"Amount in GAMPEONS","minimum":0},"issued":{"type":"integer","description":"Issued minus taken back"},"problems":{"type":"array","items":{"type":"string"}}},"required":["ok","transactions","entries","userCoins","issued","problems"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"admin"}},"/v1/admin/audit":{"get":{"operationId":"listAuditLog","tags":["GAMPEONS"],"summary":"Audit log","description":"Requires the role admin.\n\nNot available with access tokens.","parameters":[{"name":"limit","in":"query","required":false,"description":"1 to 200, default 50","schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Skip this many","schema":{"type":"integer"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Entries, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"actorId":{"oneOf":[{"type":"integer"},{"type":"null"}]},"action":{"type":"string"},"target":{"oneOf":[{"type":"string"},{"type":"null"}]},"details":{"type":"object","additionalProperties":{}},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","actorId","action","target","details","createdAt"]}}},"required":["entries"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"admin"}},"/v1/social/suggestions":{"get":{"operationId":"getSocialSuggestions","tags":["Social"],"summary":"Who to follow","description":"Creators with public content, studios and games, most followed first. Without the ones you already follow and accounts blocked in either direction.\n\nNot available with access tokens.","security":[{},{"session":[]}],"responses":{"200":{"description":"Suggestions","content":{"application/json":{"schema":{"type":"object","properties":{"creators":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"followers":{"type":"integer"}},"required":["handle","displayName","followers"]}},"studios":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"tagline":{"type":"string"},"followers":{"type":"integer"}},"required":["slug","name","tagline","followers"]}},"projects":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"tagline":{"type":"string"},"genre":{"type":"string"},"followers":{"type":"integer"}},"required":["slug","title","tagline","genre","followers"]}}},"required":["creators","studios","projects"]}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"}},"/v1/social/{type}/{key}":{"get":{"operationId":"getSocialSummary","tags":["Social"],"summary":"Follower counts and your relationship","description":"Counts are public. With login, `viewer` describes your relationship (follow, friendship, block). Hidden studios and projects count as not found.\n\nNot available with access tokens.","parameters":[{"name":"type","in":"path","required":true,"description":"`user`, `studio` or `project`","schema":{"type":"string","enum":["user","studio","project"]}},{"name":"key","in":"path","required":true,"description":"Handle (user) or slug (studio, project)","schema":{"type":"string"}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Summary","content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"},"followers":{"type":"integer"},"following":{"type":"integer","description":"Accounts only"},"friends":{"type":"integer","description":"Accounts only"},"viewer":{"oneOf":[{"type":"object","properties":{"self":{"type":"boolean","description":"This is your own account"},"following":{"type":"boolean"},"canFollow":{"type":"boolean"},"friend":{"oneOf":[{"type":"string","enum":["none","outgoing","incoming","friends"],"description":"Accounts only"},{"type":"null"}]},"blocked":{"type":"boolean","description":"You blocked this account"},"canFriend":{"type":"boolean","description":"A friend request (or accepting one) is possible"}},"required":["self","following","canFollow","friend","blocked","canFriend"]},{"type":"null"}]}},"required":["type","key","name","followers","viewer"]}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"}},"/v1/social/{type}/{key}/follow":{"put":{"operationId":"follow","tags":["Social"],"summary":"Follow an account, studio or game","description":"Idempotent. Accounts get a `new_follower` notification at most once per person and week.\n\nNot available with access tokens.\n\nRate limit: 60 follow changes per hour per account, 2,000 follows in total.","parameters":[{"name":"type","in":"path","required":true,"description":"`user`, `studio` or `project`","schema":{"type":"string","enum":["user","studio","project"]}},{"name":"key","in":"path","required":true,"description":"Handle (user) or slug (studio, project)","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Following","content":{"application/json":{"schema":{"type":"object","properties":{"following":{"const":true},"followers":{"type":"integer"}},"required":["following","followers"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `follow_limit`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 60 follow changes per hour per account, 2,000 follows in total. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"60 follow changes per hour per account, 2,000 follows in total"},"delete":{"operationId":"unfollow","tags":["Social"],"summary":"Unfollow","description":"Not available with access tokens.\n\nRate limit: 60 follow changes per hour per account.","parameters":[{"name":"type","in":"path","required":true,"description":"`user`, `studio` or `project`","schema":{"type":"string","enum":["user","studio","project"]}},{"name":"key","in":"path","required":true,"description":"Handle (user) or slug (studio, project)","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Not following","content":{"application/json":{"schema":{"type":"object","properties":{"following":{"const":false},"followers":{"type":"integer"}},"required":["following","followers"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 60 follow changes per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"60 follow changes per hour per account"}},"/v1/social/{type}/{key}/followers":{"get":{"operationId":"listFollowers","tags":["Social"],"summary":"Followers","description":"Up to 50 per page, newest first. For accounts: Visible if the account’s `showConnections` allows it (otherwise `403 private`). Other people only appear if their own setting allows you to see them; your own lists are complete. For studios and games, only people whose own setting allows it appear.\n\nNot available with access tokens.","parameters":[{"name":"type","in":"path","required":true,"description":"`user`, `studio` or `project`","schema":{"type":"string","enum":["user","studio","project"]}},{"name":"key","in":"path","required":true,"description":"Handle (user) or slug (studio, project)","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Entries to skip","schema":{"type":"integer","minimum":0,"default":0}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Followers","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer","description":"All followers, including hidden ones"},"followers":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"since":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"mutual":{"type":"boolean"}},"required":["handle","displayName","since","mutual"]}}},"required":["total","followers"]}}}},"403":{"description":"Error codes: `token_not_allowed`, `private`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"}},"/v1/social/{type}/{key}/following":{"get":{"operationId":"listFollowing","tags":["Social"],"summary":"What an account follows","description":"Accounts only (`type` = `user`). Visible if the account’s `showConnections` allows it (otherwise `403 private`). Other people only appear if their own setting allows you to see them; your own lists are complete.\n\nNot available with access tokens.","parameters":[{"name":"type","in":"path","required":true,"description":"`user`, `studio` or `project`","schema":{"type":"string","enum":["user","studio","project"]}},{"name":"key","in":"path","required":true,"description":"Handle (user) or slug (studio, project)","schema":{"type":"string"}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Followed accounts, studios and games","content":{"application/json":{"schema":{"type":"object","properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/SocialTarget"}},"studios":{"type":"array","items":{"$ref":"#/components/schemas/SocialTarget"}},"projects":{"type":"array","items":{"$ref":"#/components/schemas/SocialTarget"}}},"required":["users","studios","projects"]}}}},"403":{"description":"Error codes: `token_not_allowed`, `private`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"}},"/v1/social/{type}/{key}/friends":{"get":{"operationId":"listFriends","tags":["Social"],"summary":"Friends of an account","description":"Accounts only (`type` = `user`). Visible if the account’s `showConnections` allows it (otherwise `403 private`). Other people only appear if their own setting allows you to see them; your own lists are complete.\n\nNot available with access tokens.","parameters":[{"name":"type","in":"path","required":true,"description":"`user`, `studio` or `project`","schema":{"type":"string","enum":["user","studio","project"]}},{"name":"key","in":"path","required":true,"description":"Handle (user) or slug (studio, project)","schema":{"type":"string"}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Friends","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"friends":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"mutual":{"type":"boolean","description":"Also a friend of yours"}},"required":["handle","displayName","mutual"]}}},"required":["total","friends"]}}}},"403":{"description":"Error codes: `token_not_allowed`, `private`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"}},"/v1/me/friends":{"get":{"operationId":"getMyFriends","tags":["Social"],"summary":"Your friends, requests and blocks","description":"Not available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Lists","content":{"application/json":{"schema":{"type":"object","properties":{"friends":{"type":"array","items":{"allOf":[{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"since":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["handle","displayName","since"]},{"type":"object","properties":{"online":{"type":"boolean","description":"Active in the last 3 minutes, if this friend shows it"},"points":{"type":"integer","description":"Achievement points (level = points / 100 + 1)"}},"required":["online","points"]}]}},"incoming":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"since":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["handle","displayName","since"]}},"outgoing":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"since":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["handle","displayName","since"]}},"blocked":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"since":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["handle","displayName","since"]}},"limits":{"type":"object","properties":{"friends":{"type":"integer"},"pendingOutgoing":{"type":"integer"}},"required":["friends","pendingOutgoing"]}},"required":["friends","incoming","outgoing","blocked","limits"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/friends/requests":{"post":{"operationId":"sendFriendRequest","tags":["Social"],"summary":"Send a friend request","description":"If the other person already asked you, you are friends right away (`status: friends`). Blocks and the other person’s settings both answer `403 not_allowed`, so a block is not revealed.\n\nNot available with access tokens.\n\nRate limit: 20 per hour per account, 100 open requests, 1,000 friends.","security":[{"session":[]}],"responses":{"201":{"description":"Request sent (200 if it already existed or was accepted)","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["pending","friends"]}},"required":["status"]}}}},"400":{"description":"Error codes: `invalid_field`, `invalid_target`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_friends`, `too_many_pending`, `friend_limit`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 20 per hour per account, 100 open requests, 1,000 friends. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"20 per hour per account, 100 open requests, 1,000 friends","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string","description":"Handle, with or without @"}},"required":["handle"]}}}}}},"/v1/friends/requests/{handle}/accept":{"post":{"operationId":"acceptFriendRequest","tags":["Social"],"summary":"Accept a friend request","description":"Not available with access tokens.\n\nRate limit: 120 answers per hour per account.","parameters":[{"name":"handle","in":"path","required":true,"description":"Handle of the account","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Friends","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"const":"friends"}},"required":["status"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `friend_limit`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 answers per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"120 answers per hour per account"}},"/v1/friends/requests/{handle}":{"delete":{"operationId":"deleteFriendRequest","tags":["Social"],"summary":"Decline or cancel a friend request","description":"Not available with access tokens.\n\nRate limit: 120 answers per hour per account.","parameters":[{"name":"handle","in":"path","required":true,"description":"Handle of the account","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Removed"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 answers per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"120 answers per hour per account"}},"/v1/friends/{handle}":{"delete":{"operationId":"removeFriend","tags":["Social"],"summary":"Remove a friend","description":"Not available with access tokens.","parameters":[{"name":"handle","in":"path","required":true,"description":"Handle of the account","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Removed"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/blocks/{handle}":{"put":{"operationId":"blockAccount","tags":["Social"],"summary":"Block an account","description":"Removes friendship, open requests and follows in both directions and the account’s likes on your posts. The blocked account can no longer follow you, send requests or like your posts.\n\nNot available with access tokens.\n\nRate limit: 60 per hour per account.","parameters":[{"name":"handle","in":"path","required":true,"description":"Handle of the account","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Blocked","content":{"application/json":{"schema":{"type":"object","properties":{"blocked":{"const":true}},"required":["blocked"]}}}},"400":{"description":"Error codes: `invalid_target`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 60 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"60 per hour per account"},"delete":{"operationId":"unblockAccount","tags":["Social"],"summary":"Unblock an account","description":"Not available with access tokens.","parameters":[{"name":"handle","in":"path","required":true,"description":"Handle of the account","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Unblocked"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/me/social-settings":{"get":{"operationId":"getSocialSettings","tags":["Social"],"summary":"Your privacy settings","description":"Defaults: friend requests from `everyone`, connections visible to `friends`. Under 16 (and without a birth month): friend requests only from `friends_of_friends`, connections `private`, and only these stricter levels can be chosen. `options` lists what you can choose.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Settings","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"friendRequests":{"type":"string","enum":["everyone","friends_of_friends","nobody"],"description":"Who can send you friend requests"},"showConnections":{"type":"string","enum":["public","friends","private"],"description":"Who can see your friends and follows. Also decides whether you appear in other people’s lists"},"showOnline":{"type":"boolean","description":"Your friends see when you are online (active on the website or in the launcher in the last 3 minutes). Nobody else sees it"}},"required":["friendRequests","showConnections","showOnline"]},{"type":"object","properties":{"ageGroup":{"type":"string","enum":["protected","adult"]},"options":{"type":"object","properties":{"friendRequests":{"type":"array","items":{"type":"string"}},"showConnections":{"type":"array","items":{"type":"string"}}},"required":["friendRequests","showConnections"]}},"required":["ageGroup","options"]}]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"},"patch":{"operationId":"updateSocialSettings","tags":["Social"],"summary":"Change your privacy settings","description":"Not available with access tokens.\n\nRate limit: 120 changes per hour per account.","security":[{"session":[]}],"responses":{"200":{"description":"Saved","content":{"application/json":{"schema":{"type":"object","properties":{"friendRequests":{"type":"string","enum":["everyone","friends_of_friends","nobody"],"description":"Who can send you friend requests"},"showConnections":{"type":"string","enum":["public","friends","private"],"description":"Who can see your friends and follows. Also decides whether you appear in other people’s lists"},"showOnline":{"type":"boolean","description":"Your friends see when you are online (active on the website or in the launcher in the last 3 minutes). Nobody else sees it"}},"required":["friendRequests","showConnections","showOnline"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `age_restricted`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 changes per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"120 changes per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"friendRequests":{"type":"string","enum":["everyone","friends_of_friends","nobody"],"description":"Who can send you friend requests"},"showConnections":{"type":"string","enum":["public","friends","private"],"description":"Who can see your friends and follows. Also decides whether you appear in other people’s lists"},"showOnline":{"type":"boolean","description":"Your friends see when you are online (active on the website or in the launcher in the last 3 minutes). Nobody else sees it"}},"required":[]}}}}}},"/v1/posts":{"post":{"operationId":"createPost","tags":["Social"],"summary":"Write a post","description":"Text with up to 3 links, up to 4 photos (upload them first with `POST /v1/me/post-images`), a GIF (`gif`, from `GET /v1/gifs`) or a shared post (`share`). `audience` sets who sees it (default `public`, under 16 `friends`); studio and game posts are always public. `commentMode` sets who can comment. `@handle` mentions notify that account (under 16 only from friends). The first link gets a preview card (title and site name). `as` posts in the name of a studio (owner or admin) or a game (people who can edit it). Control and formatting characters are rejected; more than two empty lines are shortened.\n\nNot available with access tokens.\n\nRate limit: 10 per hour and 50 per day per account; 3 per day in the first 24 hours of an account; no identical text within 24 hours.","security":[{"session":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}},"400":{"description":"Error codes: `invalid_field`, `too_many_links`, `invalid_image_ref`, `invalid_gif`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `not_shareable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `duplicate_post`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour and 50 per day per account; 3 per day in the first 24 hours of an account; no identical text within 24 hours. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Error codes: `gifs_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `gifs_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"10 per hour and 50 per day per account; 3 per day in the first 24 hours of an account; no identical text within 24 hours","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"Up to 1,000 characters and 3 links. Required unless there are photos, a GIF or a share","maxLength":1000},"as":{"type":"string","description":"`studio:SLUG` or `project:SLUG`. Omit to post as yourself."},"audience":{"type":"string","enum":["public","friends","private"]},"commentMode":{"type":"string","enum":["everyone","friends","off"],"description":"`friends` only for your own posts"},"images":{"type":"array","items":{"type":"string","description":"File name from `POST /v1/me/post-images`"},"maxItems":4},"share":{"type":"integer","description":"ID of a public post to share. Shares of shares share the original"},"gif":{"type":"string","description":"GIF ID (`id` from `GET /v1/gifs`). Not together with photos or a share"}},"required":[]}}}}},"get":{"operationId":"listPosts","tags":["Social"],"summary":"Public posts","description":"With `author`: posts of one account, studio or game that you can see (audience, blocks). On the first page a pinned post comes separately in `pinned` and is left out of `posts`. Without `author`: news from all studios and games (not from single accounts).\n\nNot available with access tokens.","parameters":[{"name":"author","in":"query","required":false,"description":"`user:HANDLE`, `studio:SLUG` or `project:SLUG`","schema":{"type":"string"}},{"name":"before","in":"query","required":false,"description":"Cursor `next` from the previous page","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Page size, 1 to 50 (default 30)","schema":{"type":"integer","minimum":1,"maximum":50,"default":30}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Posts, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"pinned":{"oneOf":[{"$ref":"#/components/schemas/Post"},{"type":"null"}]},"posts":{"type":"array","items":{"$ref":"#/components/schemas/Post"}},"next":{"oneOf":[{"type":"string","description":"Cursor for the next page"},{"type":"null"}]}},"required":["pinned","posts","next"]}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"}},"/v1/me/post-images":{"post":{"operationId":"uploadPostImage","tags":["Social"],"summary":"Upload a photo for a post","description":"PNG, JPEG or WebP up to 2 MB and at least 64×64 pixels. Metadata (EXIF, GPS) is removed. The photo is only visible once it belongs to a post; photos that were never posted are deleted after 24 hours.\n\nNot available with access tokens.\n\nRate limit: 30 images per hour per account; up to 20 photos that aren’t posted yet.","security":[{"session":[]}],"responses":{"201":{"description":"Uploaded","content":{"application/json":{"schema":{"type":"object","properties":{"file":{"type":"string","description":"Use it in `images` of `POST /v1/posts`"},"url":{"type":"string"},"width":{"type":"integer"},"height":{"type":"integer"}},"required":["file","url","width","height"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `too_many_pending_images`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error codes: `file_too_large`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Error codes: `unsupported_media_type`, `invalid_image`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `image_too_small`, `invalid_aspect_ratio`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 images per hour per account; up to 20 photos that aren’t posted yet. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 images per hour per account; up to 20 photos that aren’t posted yet","requestBody":{"required":true,"description":"The image","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}}}}}},"/v1/me/post-images/{file}":{"delete":{"operationId":"discardPostImage","tags":["Social"],"summary":"Discard a photo you haven’t posted","description":"Not available with access tokens.","parameters":[{"name":"file","in":"path","required":true,"description":"File name from the upload","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Discarded"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `image_in_use`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/link-preview":{"get":{"operationId":"getLinkPreview","tags":["Social"],"summary":"Preview card for a link","description":"Title and site name of an https page, for the post form. We don’t load images or descriptions from other sites. Previews are kept for 7 days.\n\nNot available with access tokens.\n\nRate limit: 60 per hour per account.","parameters":[{"name":"url","in":"query","required":true,"description":"https link, up to 500 characters","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Card (title `null` if the page has none or can’t be reached)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkCard"}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 60 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"60 per hour per account"}},"/v1/gifs/status":{"get":{"operationId":"getGifStatus","tags":["Social"],"summary":"Whether GIFs are available","description":"GIFs come from KLIPY and are only on when the server has a KLIPY key. The portal hides the GIF button otherwise.","security":[],"responses":{"200":{"description":"Status","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"provider":{"oneOf":[{"type":"string","description":"`klipy`"},{"type":"null"}]}},"required":["enabled","provider"]}}}}},"x-gampeon-auth":"none"}},"/v1/gifs":{"get":{"operationId":"searchGifs","tags":["Social"],"summary":"Search GIFs","description":"Search KLIPY with `q`, or trending GIFs without it, 24 per page. Accounts under 16 get the strictest content filter. The API asks KLIPY on your behalf without your account ID, and images are delivered through `GET /v1/gifs/:id/:size`, so your browser never talks to KLIPY. Show “Search KLIPY” in the search field (KLIPY’s attribution rule).\n\nNot available with access tokens.\n\nRate limit: 300 per hour per account.","parameters":[{"name":"q","in":"query","required":false,"description":"Search words, up to 100 characters. Empty: trending","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"1 to 20","schema":{"type":"integer","minimum":1,"maximum":20}}],"security":[{"session":[]}],"responses":{"200":{"description":"GIFs","content":{"application/json":{"schema":{"type":"object","properties":{"gifs":{"type":"array","items":{"$ref":"#/components/schemas/GifResult"}},"next":{"oneOf":[{"type":"integer","description":"Next page"},{"type":"null"}]},"provider":{"type":"string","description":"`klipy`"}},"required":["gifs","next","provider"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 300 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Error codes: `gifs_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `gifs_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"300 per hour per account"}},"/v1/gifs/{slug}/{size}":{"get":{"operationId":"getGifImage","tags":["Social"],"summary":"GIF image","description":"The animated image (WebP, or GIF if KLIPY has no WebP) from KLIPY, delivered by the API. `sm` is the small preview for the picker, `md` the size in posts and comments. Only GIFs that came from a search or are attached to a post. Cached for a day.\n\nRate limit: 1,500 per 10 minutes per IP address.","parameters":[{"name":"slug","in":"path","required":true,"description":"GIF ID","schema":{"type":"string"}},{"name":"size","in":"path","required":true,"description":"`sm` or `md`","schema":{"type":"string","enum":["sm","md"]}}],"security":[],"responses":{"200":{"description":"The image","content":{"image/webp, image/gif":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 1,500 per 10 minutes per IP address. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"1,500 per 10 minutes per IP address"}},"/v1/posts/{id}":{"get":{"operationId":"getPost","tags":["Social"],"summary":"One post","description":"Removed posts are only visible to their author, with `removed` and the reason. Posts for friends or only the author count as not found for others.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Post","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"},"patch":{"operationId":"updatePost","tags":["Social"],"summary":"Edit a post","description":"Text, audience or who can comment. A new text sets `editedAt`, and only newly mentioned accounts are notified. Photos and shares stay as they are.\n\nNot available with access tokens.\n\nRate limit: 120 changes per hour per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}},"400":{"description":"Error codes: `invalid_field`, `too_many_links`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `post_removed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 changes per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"120 changes per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","maxLength":1000},"audience":{"type":"string","enum":["public","friends","private"]},"commentMode":{"type":"string","enum":["everyone","friends","off"]}},"required":[]}}}}},"delete":{"operationId":"deletePost","tags":["Social"],"summary":"Delete a post","description":"Author, studio owners and admins, or people who can edit the game. Deleting is final and takes photos, comments and reactions with it. A copy of reported text stays with the report for the moderation record. Shares of it show the original as unavailable.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/posts/{id}/pin":{"put":{"operationId":"pinPost","tags":["Social"],"summary":"Pin a post to the top of the timeline","description":"One pinned post per account, studio and game; pinning another one replaces it.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Pinned","content":{"application/json":{"schema":{"type":"object","properties":{"pinned":{"type":"boolean"}},"required":["pinned"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `post_removed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"},"delete":{"operationId":"unpinPost","tags":["Social"],"summary":"Unpin a post","description":"Not available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Not pinned","content":{"application/json":{"schema":{"type":"object","properties":{"pinned":{"type":"boolean"}},"required":["pinned"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/posts/{id}/reaction":{"put":{"operationId":"reactToPost","tags":["Social"],"summary":"React to a post","description":"One reaction per person; a new one replaces the old one. No notification is sent for reactions.\n\nNot available with access tokens.\n\nRate limit: 300 per hour per account (together with likes).","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Saved","content":{"application/json":{"schema":{"type":"object","properties":{"reaction":{"oneOf":[{"type":"string","enum":["like","love","haha","wow","sad","angry"]},{"type":"null"}]},"reactions":{"$ref":"#/components/schemas/Reactions"},"liked":{"type":"boolean","description":"Older field: any reaction"},"likes":{"type":"integer","description":"Older field: all reactions"}},"required":["reaction","reactions","liked","likes"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 300 per hour per account (together with likes). Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"300 per hour per account (together with likes)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reaction":{"type":"string","enum":["like","love","haha","wow","sad","angry"]}},"required":["reaction"]}}}}},"delete":{"operationId":"removePostReaction","tags":["Social"],"summary":"Remove your reaction","description":"Not available with access tokens.\n\nRate limit: 300 per hour per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Removed","content":{"application/json":{"schema":{"type":"object","properties":{"reaction":{"oneOf":[{"type":"string","enum":["like","love","haha","wow","sad","angry"]},{"type":"null"}]},"reactions":{"$ref":"#/components/schemas/Reactions"},"liked":{"type":"boolean","description":"Older field: any reaction"},"likes":{"type":"integer","description":"Older field: all reactions"}},"required":["reaction","reactions","liked","likes"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 300 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"300 per hour per account"}},"/v1/posts/{id}/like":{"put":{"operationId":"likePost","tags":["Social"],"summary":"Like a post","description":"Same as the reaction `like`.\n\nNot available with access tokens.\n\nRate limit: 300 per hour per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Liked","content":{"application/json":{"schema":{"type":"object","properties":{"reaction":{"oneOf":[{"type":"string","enum":["like","love","haha","wow","sad","angry"]},{"type":"null"}]},"reactions":{"$ref":"#/components/schemas/Reactions"},"liked":{"type":"boolean","description":"Older field: any reaction"},"likes":{"type":"integer","description":"Older field: all reactions"}},"required":["reaction","reactions","liked","likes"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 300 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"300 per hour per account"},"delete":{"operationId":"unlikePost","tags":["Social"],"summary":"Remove your like","description":"Removes any reaction.\n\nNot available with access tokens.\n\nRate limit: 300 per hour per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Not liked","content":{"application/json":{"schema":{"type":"object","properties":{"reaction":{"oneOf":[{"type":"string","enum":["like","love","haha","wow","sad","angry"]},{"type":"null"}]},"reactions":{"$ref":"#/components/schemas/Reactions"},"liked":{"type":"boolean","description":"Older field: any reaction"},"likes":{"type":"integer","description":"Older field: all reactions"}},"required":["reaction","reactions","liked","likes"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 300 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"300 per hour per account"}},"/v1/posts/{id}/reactions":{"get":{"operationId":"listPostReactions","tags":["Social"],"summary":"Who reacted to a post","description":"Counts are complete. People only appear if their own setting (`showConnections`) lets you see them. Up to 100, newest first.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}},{"name":"reaction","in":"query","required":false,"description":"Only this reaction","schema":{"type":"string","enum":["like","love","haha","wow","sad","angry"]}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Reactions","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Reactions"},{"type":"object","properties":{"people":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string"},{"type":"null"}]},"reaction":{"type":"string","enum":["like","love","haha","wow","sad","angry"]}},"required":["handle","displayName","avatar","reaction"]}}},"required":["people"]}]}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"}},"/v1/posts/{id}/comments":{"get":{"operationId":"listComments","tags":["Social"],"summary":"Comments on a post","description":"Top-level comments: newest page first (`before`), each page in reading order (oldest first). Replies (`parent`): oldest first, continue with `after`. Without blocked accounts; removed comments only for their author.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}},{"name":"parent","in":"query","required":false,"description":"Top-level comment ID: list its replies","schema":{"type":"integer"}},{"name":"before","in":"query","required":false,"description":"Top-level comments: `next` from the previous page","schema":{"type":"string"}},{"name":"after","in":"query","required":false,"description":"Replies: `next` from the previous page","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Page size, 1 to 50 (default 20)","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Comments","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer","description":"All visible comments and replies"},"comments":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}},"next":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["total","comments","next"]}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"},"post":{"operationId":"createComment","tags":["Social"],"summary":"Comment on a post","description":"Text, a GIF (`gif`, from `GET /v1/gifs`) or both. `parentId` answers a comment; answers to answers are placed under the top-level comment. Notifies the author of the post, the person you answer and mentioned accounts, each at most once. On posts of accounts under 16 only friends can comment.\n\nNot available with access tokens.\n\nRate limit: 30 per hour and 200 per day per account; 10 per day in the first 24 hours; no identical comment on the same post within an hour.","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Comment"}}}},"400":{"description":"Error codes: `invalid_field`, `too_many_links`, `invalid_gif`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `comments_off`, `not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `duplicate_comment`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per hour and 200 per day per account; 10 per day in the first 24 hours; no identical comment on the same post within an hour. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Error codes: `gifs_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `gifs_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 per hour and 200 per day per account; 10 per day in the first 24 hours; no identical comment on the same post within an hour","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"Up to 1,000 characters and 3 links. Required unless there is a GIF","maxLength":1000},"gif":{"type":"string","description":"GIF ID (`id` from `GET /v1/gifs`)"},"parentId":{"type":"integer"}},"required":[]}}}}}},"/v1/comments/{id}":{"patch":{"operationId":"updateComment","tags":["Social"],"summary":"Edit your comment","description":"Not available with access tokens.\n\nRate limit: 120 changes per hour per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Comment ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Comment"}}}},"400":{"description":"Error codes: `invalid_field`, `too_many_links`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `comment_removed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 changes per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"120 changes per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"Up to 1,000 characters. Can be empty if the comment has a GIF","maxLength":1000}},"required":["body"]}}}}},"delete":{"operationId":"deleteComment","tags":["Social"],"summary":"Delete a comment","description":"The person who wrote it, or whoever manages the post. Replies are deleted with it.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Comment ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/comments/{id}/reaction":{"put":{"operationId":"reactToComment","tags":["Social"],"summary":"React to a comment","description":"Not available with access tokens.\n\nRate limit: 300 per hour per account (together with post reactions).","parameters":[{"name":"id","in":"path","required":true,"description":"Comment ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Saved","content":{"application/json":{"schema":{"type":"object","properties":{"reaction":{"oneOf":[{"type":"string","enum":["like","love","haha","wow","sad","angry"]},{"type":"null"}]},"reactions":{"$ref":"#/components/schemas/Reactions"}},"required":["reaction","reactions"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 300 per hour per account (together with post reactions). Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"300 per hour per account (together with post reactions)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reaction":{"type":"string","enum":["like","love","haha","wow","sad","angry"]}},"required":["reaction"]}}}}},"delete":{"operationId":"removeCommentReaction","tags":["Social"],"summary":"Remove your reaction to a comment","description":"Not available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Comment ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Removed","content":{"application/json":{"schema":{"type":"object","properties":{"reaction":{"oneOf":[{"type":"string","enum":["like","love","haha","wow","sad","angry"]},{"type":"null"}]},"reactions":{"$ref":"#/components/schemas/Reactions"}},"required":["reaction","reactions"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/feed":{"get":{"operationId":"getFeed","tags":["Social"],"summary":"Your feed","description":"Chronological, without ranking: your posts, posts of friends and of accounts, studios and games you follow, and new versions of marketplace items by creators and games you follow. Without blocked accounts and hidden pages.\n\nNot available with access tokens.","parameters":[{"name":"before","in":"query","required":false,"description":"Cursor `next` from the previous page","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Page size, 1 to 50 (default 30)","schema":{"type":"integer","minimum":1,"maximum":50,"default":30}}],"security":[{"session":[]}],"responses":{"200":{"description":"Feed","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FeedItem"}},"next":{"oneOf":[{"type":"string"},{"type":"null"}]},"sources":{"type":"integer","description":"Number of follows and friends"}},"required":["items","next","sources"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/legal/social-report-categories":{"get":{"operationId":"getSocialReportCategories","tags":["Reports and moderation"],"summary":"Report categories for posts","security":[],"responses":{"200":{"description":"Categories","content":{"application/json":{"schema":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"string","enum":["illegal_content","harassment","hate_speech","violence_threat","child_safety","spam","copyright","other"]}},"anonymous":{"type":"array","items":{"type":"string"},"description":"Categories that need no name and email"}},"required":["categories","anonymous"]}}}}},"x-gampeon-auth":"none"}},"/v1/posts/{id}/reports":{"post":{"operationId":"reportPost","tags":["Reports and moderation"],"summary":"Report a post","description":"Notice under Art. 16 DSA, also without an account. Name and email are required except for `child_safety`; when logged in they come from your account. A copy of the text (and references to its photos) is kept with the report.\n\nNot available with access tokens.\n\nRate limit: 10 per hour per IP.","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}}],"security":[{},{"session":[]}],"responses":{"201":{"description":"Report received (200 if you already reported this post)","content":{"application/json":{"schema":{"type":"object","properties":{"reportId":{"type":"string"},"status":{"const":"open"}},"required":["reportId","status"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `good_faith_confirmation_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional","x-gampeon-rate-limit":"10 per hour per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"string","enum":["illegal_content","harassment","hate_speech","violence_threat","child_safety","spam","copyright","other"]},"explanation":{"type":"string","minLength":20,"maxLength":5000},"reporterName":{"type":"string","minLength":2,"maxLength":120},"reporterEmail":{"type":"string","format":"email","maxLength":254},"goodFaith":{"const":true,"description":"Confirms the report is made in good faith"}},"required":["category","explanation","goodFaith"]}}}}}},"/v1/comments/{id}/reports":{"post":{"operationId":"reportComment","tags":["Reports and moderation"],"summary":"Report a comment","description":"Same rules as reporting a post. A copy of the comment is kept with the report.\n\nNot available with access tokens.\n\nRate limit: 10 per hour per IP (together with other reports).","parameters":[{"name":"id","in":"path","required":true,"description":"Comment ID","schema":{"type":"integer","minimum":1}}],"security":[{},{"session":[]}],"responses":{"201":{"description":"Report received (200 if you already reported this comment)","content":{"application/json":{"schema":{"type":"object","properties":{"reportId":{"type":"string"},"status":{"const":"open"}},"required":["reportId","status"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `good_faith_confirmation_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour per IP (together with other reports). Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional","x-gampeon-rate-limit":"10 per hour per IP (together with other reports)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"string","enum":["illegal_content","harassment","hate_speech","violence_threat","child_safety","spam","copyright","other"]},"explanation":{"type":"string","minLength":20,"maxLength":5000},"reporterName":{"type":"string","minLength":2,"maxLength":120},"reporterEmail":{"type":"string","format":"email","maxLength":254},"goodFaith":{"const":true,"description":"Confirms the report is made in good faith"}},"required":["category","explanation","goodFaith"]}}}}}},"/v1/moderation/comments/{id}/decision":{"post":{"operationId":"moderateComment","tags":["Reports and moderation"],"summary":"Remove or restore a comment without a report","description":"Always with a statement of reasons, which the person who commented sees (Art. 17 DSA).\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Comment ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string"},"action":{"type":"string"}},"required":["decisionId","action"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_removed`, `not_removed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["remove","restore"]},"statementOfReasons":{"type":"string","description":"Statement of reasons, shown to the author (Art. 17 DSA)","minLength":20,"maxLength":5000},"legalGround":{"type":"string","maxLength":500}},"required":["action","statementOfReasons"]}}}}}},"/v1/moderation/social-reports":{"get":{"operationId":"listPostReports","tags":["Reports and moderation"],"summary":"Reports about posts, comments and images","description":"Up to 200, `urgent` ones (`child_safety`, `violence_threat`) first, then oldest first.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"status","in":"query","required":false,"description":"Default: open","schema":{"type":"string","enum":["open","actioned","rejected"]}}],"security":[{"session":[]}],"responses":{"200":{"description":"Reports","content":{"application/json":{"schema":{"type":"object","properties":{"reports":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["post","comment","media"]},"postId":{"oneOf":[{"type":"integer","description":"The post, also for comments"},{"type":"null"}]},"commentId":{"oneOf":[{"type":"integer"},{"type":"null"}]},"snapshot":{"type":"string","description":"Reported text"},"category":{"type":"string"},"explanation":{"type":"string"},"reporterName":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"authorHandle":{"oneOf":[{"type":"string"},{"type":"null"}]},"authorName":{"oneOf":[{"type":"string"},{"type":"null"}]},"removedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"deleted":{"type":"boolean","description":"Deleted by the author"},"urgent":{"type":"boolean"},"media":{"type":"object","properties":{"file":{"type":"string"},"slot":{"type":"string"},"url":{"type":"string","description":"View with a moderator session"}},"required":["file","slot","url"]}},"required":["id","kind","postId","commentId","snapshot","category","explanation","reporterName","status","createdAt","authorHandle","authorName","removedAt","deleted","urgent"]}}},"required":["reports"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator"}},"/v1/moderation/social-reports/{id}/decision":{"post":{"operationId":"decidePostReport","tags":["Reports and moderation"],"summary":"Decide on a report","description":"`remove` hides the post, comment or image, closes all open reports about it and informs the author (Art. 17 DSA) and the reporting people (Art. 16(5)). `reject` keeps it and informs the reporting person.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Report ID","schema":{"type":"string","format":"uuid"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string"},"action":{"type":"string"}},"required":["decisionId","action"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_decided`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["remove","reject"]},"statementOfReasons":{"type":"string","description":"Statement of reasons, shown to the author (Art. 17 DSA)","minLength":20,"maxLength":5000},"legalGround":{"type":"string","maxLength":500}},"required":["action","statementOfReasons"]}}}}}},"/v1/moderation/posts/{id}/decision":{"post":{"operationId":"moderatePost","tags":["Reports and moderation"],"summary":"Remove or restore a post without a report","description":"For example during a spam wave. Always with a statement of reasons, which the author sees.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Post ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string"},"action":{"type":"string"}},"required":["decisionId","action"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_removed`, `not_removed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["remove","restore"]},"statementOfReasons":{"type":"string","description":"Statement of reasons, shown to the author (Art. 17 DSA)","minLength":20,"maxLength":5000},"legalGround":{"type":"string","maxLength":500}},"required":["action","statementOfReasons"]}}}}}},"/v1/social/appeals":{"post":{"operationId":"appealPostRemoval","tags":["Reports and moderation"],"summary":"Appeal a removal","description":"One appeal per decision (Art. 20 DSA). Someone from moderation decides and explains the outcome.\n\nNot available with access tokens.\n\nRate limit: 10 per day per account.","security":[{"session":[]}],"responses":{"201":{"description":"Appeal received","content":{"application/json":{"schema":{"type":"object","properties":{"appealId":{"type":"string"},"status":{"const":"open"}},"required":["appealId","status"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `appeal_exists`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per day per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"10 per day per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string"},"text":{"type":"string","minLength":20,"maxLength":5000}},"required":["decisionId","text"]}}}}}},"/v1/me/social-decisions":{"get":{"operationId":"listMyPostDecisions","tags":["Reports and moderation"],"summary":"Removals of your posts, comments and images","description":"Not available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Up to 100, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"decisions":{"type":"array","items":{"type":"object","properties":{"decisionId":{"type":"string"},"kind":{"type":"string","enum":["post","comment","media"]},"postId":{"oneOf":[{"type":"integer"},{"type":"null"}]},"commentId":{"oneOf":[{"type":"integer"},{"type":"null"}]},"mediaFile":{"oneOf":[{"type":"string"},{"type":"null"}]},"snapshot":{"type":"string"},"statementOfReasons":{"type":"string"},"legalGround":{"oneOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"appealId":{"oneOf":[{"type":"string"},{"type":"null"}]},"appealStatus":{"oneOf":[{"type":"string","enum":["open","upheld","reversed"]},{"type":"null"}]},"outcomeReasons":{"oneOf":[{"type":"string"},{"type":"null"}]},"decidedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["decisionId","kind","postId","commentId","mediaFile","snapshot","statementOfReasons","legalGround","createdAt","appealId","appealStatus","outcomeReasons","decidedAt"]}}},"required":["decisions"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/moderation/social-appeals":{"get":{"operationId":"listPostAppeals","tags":["Reports and moderation"],"summary":"Appeals about posts and images","description":"`ownDecision` shows whether you removed the post or image yourself, so someone else can review it. Image appeals carry `media`.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"status","in":"query","required":false,"description":"Default: open","schema":{"type":"string","enum":["open","upheld","reversed"]}}],"security":[{"session":[]}],"responses":{"200":{"description":"Appeals","content":{"application/json":{"schema":{"type":"object","properties":{"appeals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"status":{"type":"string"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"decidedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"outcomeReasons":{"oneOf":[{"type":"string"},{"type":"null"}]},"decisionId":{"type":"string"},"kind":{"type":"string","enum":["post","comment","media"]},"snapshot":{"type":"string"},"statementOfReasons":{"type":"string"},"legalGround":{"oneOf":[{"type":"string"},{"type":"null"}]},"removedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"postId":{"oneOf":[{"type":"integer"},{"type":"null"}]},"commentId":{"oneOf":[{"type":"integer"},{"type":"null"}]},"authorHandle":{"type":"string"},"authorName":{"type":"string"},"ownDecision":{"type":"boolean"},"media":{"type":"object","properties":{"file":{"type":"string"},"slot":{"type":"string"},"url":{"type":"string","description":"View with a moderator session"}},"required":["file","slot","url"]}},"required":["id","text","status","createdAt","decidedAt","outcomeReasons","decisionId","kind","snapshot","statementOfReasons","legalGround","removedAt","postId","commentId","authorHandle","authorName","ownDecision"]}}},"required":["appeals"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator"}},"/v1/moderation/social-appeals/{id}/decision":{"post":{"operationId":"decidePostAppeal","tags":["Reports and moderation"],"summary":"Decide on an appeal about a post","description":"`reverse` restores the post unless another removal still applies. The author gets the reasons and the notice about out-of-court dispute settlement (Art. 21 DSA).\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Appeal ID","schema":{"type":"string","format":"uuid"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"appealId":{"type":"string"},"outcome":{"type":"string"},"restored":{"type":"boolean"}},"required":["appealId","outcome","restored"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_decided`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","enum":["uphold","reverse"]},"statementOfReasons":{"type":"string","description":"Statement of reasons, shown to the author (Art. 17 DSA)","minLength":20,"maxLength":5000}},"required":["outcome","statementOfReasons"]}}}}}},"/v1/moderation/social-stats":{"get":{"operationId":"getPostModerationStats","tags":["Reports and moderation"],"summary":"Numbers for the transparency report (posts)","description":"Requires the role moderator or admin.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Counts","content":{"application/json":{"schema":{"type":"object","properties":{"reports":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string"},"status":{"type":"string"},"n":{"type":"integer"}},"required":["category","status","n"]}},"decisions":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string"},"onNotice":{"type":"integer","description":"1 if based on a report"},"n":{"type":"integer"}},"required":["action","onNotice","n"]}},"appeals":{"type":"array","items":{"type":"object","properties":{"status":{"type":"string"},"n":{"type":"integer"}},"required":["status","n"]}}},"required":["reports","decisions","appeals"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator"}},"/v1/tokens/scopes":{"get":{"operationId":"listTokenScopes","tags":["Access tokens"],"summary":"Scopes and templates for access tokens","description":"All scopes an access token can have, the templates the portal offers and the limits. Which route needs which scope is in `x-gampeon-token-scope` on each operation. Routes without it can never be used with an access token.","security":[],"responses":{"200":{"description":"Scopes","content":{"application/json":{"schema":{"type":"object","properties":{"scopes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","enum":["profile:read","projects:read","projects:write","marketplace:read","marketplace:write","servers:read"],"description":"Scope"},"description":{"type":"string"}},"required":["name","description"]}},"templates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["profile:read","projects:read","projects:write","marketplace:read","marketplace:write","servers:read"],"description":"Scope"}}},"required":["id","title","scopes"]}},"defaultExpiresInDays":{"type":"integer"},"maxExpiresInDays":{"type":"integer"},"maxActiveTokens":{"type":"integer"}},"required":["scopes","templates","defaultExpiresInDays","maxExpiresInDays","maxActiveTokens"]}}}}},"x-gampeon-auth":"none"}},"/v1/token":{"get":{"operationId":"getCurrentToken","tags":["Access tokens"],"summary":"The access token you are using","description":"Name, scopes and expiry of the access token sent with this request. Works with every valid access token, whatever its scopes. MCP clients and tools use it to check a token and to offer only what it allows. With a portal session: `400 not_an_access_token`.\n\nAccess tokens: every valid token, no scope needed.","security":[{"session":[]},{"accessToken":[]}],"responses":{"200":{"description":"Token","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"prefix":{"type":"string","description":"First characters of the token"},"scopes":{"type":"array","items":{"type":"string","enum":["profile:read","projects:read","projects:write","marketplace:read","marketplace:write","servers:read"],"description":"Scope"}},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["name","prefix","scopes","createdAt","expiresAt"]}}}},"400":{"description":"Error codes: `not_an_access_token`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-token-scope":"any"}},"/v1/me/tokens":{"get":{"operationId":"listMyTokens","tags":["Access tokens"],"summary":"Your access tokens","description":"Active, expired and revoked tokens of the last 90 days. The token itself is never shown again. Only with a portal session. Access tokens cannot manage tokens (`403 token_not_allowed`).\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Tokens","content":{"application/json":{"schema":{"type":"object","properties":{"tokens":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Token ID, used to revoke it and to filter the activity log"},"name":{"type":"string"},"prefix":{"type":"string","description":"First characters of the token (`gpat_` and 4 more), to recognise it"},"scopes":{"type":"array","items":{"type":"string","enum":["profile:read","projects:read","projects:write","marketplace:read","marketplace:write","servers:read"],"description":"Scope"}},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"lastUsedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"revokedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"status":{"type":"string","enum":["active","expired","revoked"]}},"required":["id","name","prefix","scopes","createdAt","expiresAt","lastUsedAt","revokedAt","status"]}}},"required":["tokens"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"},"post":{"operationId":"createMyToken","tags":["Access tokens"],"summary":"Create an access token","description":"Creates a personal access token for an AI assistant, an MCP client or a tool. The answer contains the token **once**; only a hash is stored. A notification `token_created` is added to the account. Only with a portal session. Access tokens cannot manage tokens (`403 token_not_allowed`).\n\nNot available with access tokens.\n\nRate limit: 10 per hour per account.","security":[{"session":[]}],"responses":{"201":{"description":"Token created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"token":{"type":"string","description":"The token, `gpat_` and 43 characters. Shown only in this answer."},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["profile:read","projects:read","projects:write","marketplace:read","marketplace:write","servers:read"],"description":"Scope"}},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","name","token","prefix","scopes","expiresAt"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `token_limit_reached`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"10 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name to recognise the token, for example \"Claude Desktop\"","minLength":1,"maxLength":64},"scopes":{"type":"array","items":{"type":"string","enum":["profile:read","projects:read","projects:write","marketplace:read","marketplace:write","servers:read"],"description":"Scope"},"description":"At least one scope","minItems":1},"expiresInDays":{"type":"integer","description":"Validity in days, default 30","minimum":1,"maximum":365}},"required":["name","scopes"]}}}}}},"/v1/me/tokens/{id}":{"delete":{"operationId":"revokeMyToken","tags":["Access tokens"],"summary":"Revoke an access token","description":"The token stops working immediately. Only with a portal session. Access tokens cannot manage tokens (`403 token_not_allowed`).\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Token ID","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Revoked"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/me/token-events":{"get":{"operationId":"listMyTokenEvents","tags":["Access tokens"],"summary":"Activity of your access tokens","description":"What your tokens did in the last 90 days (\"AI activity\" in the portal): route, result, client and time. Never request or response contents. Repeated reads of the same route are logged at most every 10 minutes. `outcome: allowed` means the token passed the scope check. Only with a portal session. Access tokens cannot manage tokens (`403 token_not_allowed`).\n\nNot available with access tokens.","parameters":[{"name":"token","in":"query","required":false,"description":"Only events of this token ID","schema":{"type":"string"}},{"name":"before","in":"query","required":false,"description":"Event ID from `next` of the previous page","schema":{"type":"integer"}},{"name":"limit","in":"query","required":false,"description":"1 to 200, default 50","schema":{"type":"integer","minimum":1,"maximum":200}}],"security":[{"session":[]}],"responses":{"200":{"description":"Events, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"tokenId":{"type":"string"},"tokenName":{"oneOf":[{"type":"string"},{"type":"null"}]},"route":{"type":"string","description":"Route like `POST /v1/projects`, or `token.created` / `token.revoked`"},"target":{"oneOf":[{"type":"string","description":"Requested path"},{"type":"null"}]},"outcome":{"type":"string","enum":["allowed","denied"]},"reason":{"oneOf":[{"type":"string","description":"Why it was denied, for example `missing_scope:projects:write` or `route_not_allowed`"},{"type":"null"}]},"client":{"oneOf":[{"type":"string","description":"Client name as sent in `X-Gampeon-Client` or the user agent (self-reported)"},{"type":"null"}]},"tool":{"oneOf":[{"type":"string","description":"MCP tool as sent in `X-Gampeon-Tool` (self-reported)"},{"type":"null"}]},"ip":{"oneOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","tokenId","tokenName","route","target","outcome","reason","client","tool","ip","createdAt"]}},"next":{"oneOf":[{"type":"integer","description":"Pass as `before` for the next page"},{"type":"null"}]}},"required":["events","next"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/auth/providers":{"get":{"operationId":"listSignInProviders","tags":["Accounts"],"summary":"Sign-in providers","description":"Which providers can be used to log in and to connect accounts. Steam uses OpenID 2.0, Discord OAuth2 with the scope `identify`.","security":[],"responses":{"200":{"description":"Providers","content":{"application/json":{"schema":{"type":"object","properties":{"providers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["steam","discord"],"description":"Sign-in provider"},"name":{"type":"string"}},"required":["id","name"]},"description":"Providers that are switched on"}},"required":["providers"]}}}}},"x-gampeon-auth":"none"}},"/v1/auth/{provider}/start":{"post":{"operationId":"startSignIn","tags":["Accounts"],"summary":"Start a sign-in with Steam or Discord","description":"Returns the address to send the browser to. The provider redirects back to the portal with `state` (and `code` for Discord, `openid.*` parameters for Steam), and the portal completes the sign-in with `POST /v1/auth/{provider}/callback`. The sign-in is valid for 10 minutes and can be used once.\n\n`mode: \"link\"` connects the provider to the account you are logged in with (portal session required; access tokens are refused).\n\nNot available with access tokens.\n\nRate limit: 30 per 15 minutes per IP.","parameters":[{"name":"provider","in":"path","required":true,"description":"Sign-in provider: `steam` or `discord`","schema":{"type":"string","enum":["steam","discord"],"description":"Sign-in provider"}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Address at the provider","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["url","expiresAt"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `provider_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per 15 minutes per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional","x-gampeon-rate-limit":"30 per 15 minutes per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["login","link"],"description":"`login`: log in or sign up. `link`: connect to your account."},"nonce":{"type":"string","description":"Random value (22 to 128 characters `A-Z a-z 0-9 _ -`) that the client keeps in the browser session and sends again with the callback. Binds the sign-in to the browser that started it.","pattern":"^[A-Za-z0-9_-]{22,128}$"}},"required":["mode","nonce"]}}}}}},"/v1/auth/{provider}/callback":{"post":{"operationId":"completeSignIn","tags":["Accounts"],"summary":"Complete a sign-in with Steam or Discord","description":"Checks the answer of the provider and then, depending on the mode and on whether the provider account is already connected:\n\n- `result: \"login\"`: a session for the connected account.\n- `result: \"signup\"`: the provider account is not connected yet. Use `ticket` with `POST /v1/auth/signup` within 30 minutes. An existing account with the same email address is never connected automatically: log in to it and connect the provider instead.\n- `result: \"linked\"`: connected to your account (mode `link`, with the session of the same account).\n\nNo access tokens of the provider are stored. Discord tokens are revoked right after reading the user ID.\n\nNot available with access tokens.\n\nRate limit: 30 per 15 minutes per IP.","parameters":[{"name":"provider","in":"path","required":true,"description":"Sign-in provider: `steam` or `discord`","schema":{"type":"string","enum":["steam","discord"],"description":"Sign-in provider"}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Signed in, sign-up needed, or connected","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"result":{"const":"login"},"token":{"type":"string","description":"Bearer token for the `Authorization` header"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["result","token","expiresAt"]},{"type":"object","properties":{"result":{"const":"signup"},"ticket":{"type":"string","description":"One-time ticket for `POST /v1/auth/signup`"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"provider":{"type":"string","enum":["steam","discord"],"description":"Sign-in provider"},"name":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["result","ticket","expiresAt","provider","name"]},{"type":"object","properties":{"result":{"const":"linked"},"identity":{"type":"object","properties":{"provider":{"type":"string","enum":["steam","discord"],"description":"Sign-in provider"},"name":{"oneOf":[{"type":"string","description":"Name at the provider. Steam names need a Steam Web API key on the server; without it `null`."},{"type":"null"}]},"url":{"type":"string","description":"Profile page at the provider","format":"uri"},"showOnProfile":{"type":"boolean","description":"Shown on your public profile. Never for accounts under 16."},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"lastLoginAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["provider","name","url","showOnProfile","createdAt","lastLoginAt"]}},"required":["result","identity"]}]}}}},"400":{"description":"Error codes: `invalid_field`, `invalid_state`, `invalid_response`, `cancelled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `email_unverified`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `provider_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `identity_taken`, `already_linked`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per 15 minutes per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Error codes: `provider_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional","x-gampeon-rate-limit":"30 per 15 minutes per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","description":"`state` from the provider's redirect","pattern":"^[A-Za-z0-9_-]{43}$"},"nonce":{"type":"string","description":"Random value (22 to 128 characters `A-Z a-z 0-9 _ -`) that the client keeps in the browser session and sends again with the callback. Binds the sign-in to the browser that started it.","pattern":"^[A-Za-z0-9_-]{22,128}$"},"code":{"type":"string","description":"Discord only: `code` from the redirect"},"params":{"type":"object","additionalProperties":{"type":"string"},"description":"Steam only: all `openid.*` query parameters of the redirect, unchanged"}},"required":["state","nonce"]}}}}}},"/v1/auth/signup":{"post":{"operationId":"signUpWithProvider","tags":["Accounts"],"summary":"Create an account after a sign-in with a provider","description":"Creates an account connected to the provider account from the ticket. Same rules as `POST /v1/accounts` (minimum age 13, accepting the current terms, email confirmation), but without a password. A password can be set later with \"Forgot password\". When email confirmation is off, the answer also contains a session.\n\nRate limit: 5 per hour per IP (shared with `POST /v1/accounts`).","security":[],"responses":{"201":{"description":"Account created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"email":{"type":"string"},"displayName":{"type":"string"},"handle":{"type":"string"},"verificationRequired":{"type":"boolean","description":"An email with a confirmation link was sent"},"token":{"type":"string","description":"Only when no confirmation is needed"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","email","displayName","handle","verificationRequired"]}}}},"400":{"description":"Error codes: `invalid_field`, `invalid_ticket`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `signup_closed`, `too_young`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `email_taken`, `handle_taken`, `identity_taken`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `terms_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 5 per hour per IP (shared with `POST /v1/accounts`). Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"5 per hour per IP (shared with `POST /v1/accounts`)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ticket":{"type":"string","description":"`ticket` from `POST /v1/auth/{provider}/callback`","pattern":"^[A-Za-z0-9_-]{43}$"},"email":{"type":"string","format":"email","maxLength":254},"displayName":{"type":"string","description":"3 to 32 letters, digits, spaces, `_` or `-`","minLength":3,"maxLength":32},"handle":{"type":"string","description":"Optional wished handle","pattern":"^$|^[a-z0-9_]{3,24}$"},"birthMonth":{"type":"string","description":"Birth month as `YYYY-MM`. Minimum age 13.","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"},"acceptTerms":{"type":"string","description":"Current version from `GET /v1/legal/terms`. Sending it means the person accepts the Terms of Use and the Community Guidelines in that version.","maxLength":40}},"required":["ticket","email","displayName","birthMonth","acceptTerms"]}}}}}},"/v1/me/identities":{"get":{"operationId":"listMyIdentities","tags":["Accounts"],"summary":"Your connected accounts","description":"Steam and Discord accounts connected to your account, whether you have a password, and which providers can be connected.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Connected accounts","content":{"application/json":{"schema":{"type":"object","properties":{"identities":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string","enum":["steam","discord"],"description":"Sign-in provider"},"name":{"oneOf":[{"type":"string","description":"Name at the provider. Steam names need a Steam Web API key on the server; without it `null`."},{"type":"null"}]},"url":{"type":"string","description":"Profile page at the provider","format":"uri"},"showOnProfile":{"type":"boolean","description":"Shown on your public profile. Never for accounts under 16."},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"lastLoginAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["provider","name","url","showOnProfile","createdAt","lastLoginAt"]}},"hasPassword":{"type":"boolean"},"providers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["steam","discord"],"description":"Sign-in provider"},"name":{"type":"string"}},"required":["id","name"]},"description":"Providers that are switched on"},"ageGroup":{"type":"string","enum":["protected","adult"]}},"required":["identities","hasPassword","providers","ageGroup"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/me/identities/{provider}":{"patch":{"operationId":"updateMyIdentity","tags":["Accounts"],"summary":"Show a connected account on your profile","description":"Not available with access tokens.","parameters":[{"name":"provider","in":"path","required":true,"description":"Sign-in provider: `steam` or `discord`","schema":{"type":"string","enum":["steam","discord"],"description":"Sign-in provider"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","enum":["steam","discord"],"description":"Sign-in provider"},"name":{"oneOf":[{"type":"string","description":"Name at the provider. Steam names need a Steam Web API key on the server; without it `null`."},{"type":"null"}]},"url":{"type":"string","description":"Profile page at the provider","format":"uri"},"showOnProfile":{"type":"boolean","description":"Shown on your public profile. Never for accounts under 16."},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"lastLoginAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["provider","name","url","showOnProfile","createdAt","lastLoginAt"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `age_restricted`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"showOnProfile":{"type":"boolean"}},"required":["showOnProfile"]}}}}},"delete":{"operationId":"deleteMyIdentity","tags":["Accounts"],"summary":"Disconnect a connected account","description":"Refused with `409 last_login_method` if it is the only way to log in (no password and no other connected account).\n\nNot available with access tokens.","parameters":[{"name":"provider","in":"path","required":true,"description":"Sign-in provider: `steam` or `discord`","schema":{"type":"string","enum":["steam","discord"],"description":"Sign-in provider"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Disconnected"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `last_login_method`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/me/avatar":{"put":{"operationId":"uploadAvatar","tags":["Profiles"],"summary":"Upload your profile picture","description":"PNG, JPEG or WebP up to 2 MB, no animation. The server removes all metadata (EXIF including GPS position, XMP, IPTC, comments, embedded thumbnails) and gives the file a new random name. Replacing an image deletes the old one. At least 128×128 pixels, roughly square (crop before uploading).\n\nNot available with access tokens.\n\nRate limit: 30 uploads per hour per account.","security":[{"session":[]}],"responses":{"201":{"description":"Stored and set as the current image","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"Image path relative to the API (`/v1/media/…`)"},"width":{"type":"integer"},"height":{"type":"integer"}},"required":["url","width","height"]}}}},"400":{"description":"Error codes: `invalid_image`, `upload_incomplete`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"411":{"description":"Error codes: `length_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error codes: `file_too_large`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Error codes: `unsupported_media_type`, `invalid_image`, `animated_image`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `image_too_small`, `invalid_aspect_ratio`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 uploads per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `storage_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 uploads per hour per account","requestBody":{"required":true,"description":"The image","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}}}}},"delete":{"operationId":"deleteAvatar","tags":["Profiles"],"summary":"Remove your profile picture","description":"Removes the current image and deletes the file. Pages fall back to the default artwork.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"204":{"description":"Removed"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/me/cover":{"put":{"operationId":"uploadCover","tags":["Profiles"],"summary":"Upload your profile cover","description":"PNG, JPEG or WebP up to 2 MB, no animation. The server removes all metadata (EXIF including GPS position, XMP, IPTC, comments, embedded thumbnails) and gives the file a new random name. Replacing an image deletes the old one. At least 640×160 pixels, wide (1.5:1 to 8:1, for example 1920×480).\n\nNot available with access tokens.\n\nRate limit: 30 uploads per hour per account.","security":[{"session":[]}],"responses":{"201":{"description":"Stored and set as the current image","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"Image path relative to the API (`/v1/media/…`)"},"width":{"type":"integer"},"height":{"type":"integer"}},"required":["url","width","height"]}}}},"400":{"description":"Error codes: `invalid_image`, `upload_incomplete`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"411":{"description":"Error codes: `length_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error codes: `file_too_large`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Error codes: `unsupported_media_type`, `invalid_image`, `animated_image`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `image_too_small`, `invalid_aspect_ratio`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 uploads per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `storage_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 uploads per hour per account","requestBody":{"required":true,"description":"The image","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}}}}},"delete":{"operationId":"deleteCover","tags":["Profiles"],"summary":"Remove your profile cover","description":"Removes the current image and deletes the file. Pages fall back to the default artwork.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"204":{"description":"Removed"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/studios/{slug}/logo":{"put":{"operationId":"uploadStudioLogo","tags":["Studios"],"summary":"Upload the studio logo","description":"PNG, JPEG or WebP up to 2 MB, no animation. The server removes all metadata (EXIF including GPS position, XMP, IPTC, comments, embedded thumbnails) and gives the file a new random name. Replacing an image deletes the old one. At least 128×128 pixels, roughly square. Owner and admins only.\n\nNot available with access tokens.\n\nRate limit: 30 uploads per hour per account.","parameters":[{"name":"slug","in":"path","required":true,"description":"Slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Stored and set as the current image","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"Image path relative to the API (`/v1/media/…`)"},"width":{"type":"integer"},"height":{"type":"integer"}},"required":["url","width","height"]}}}},"400":{"description":"Error codes: `invalid_image`, `upload_incomplete`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `studio_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"411":{"description":"Error codes: `length_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error codes: `file_too_large`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Error codes: `unsupported_media_type`, `invalid_image`, `animated_image`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `image_too_small`, `invalid_aspect_ratio`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 uploads per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `storage_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 uploads per hour per account","requestBody":{"required":true,"description":"The image","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}}}}},"delete":{"operationId":"deleteStudioLogo","tags":["Studios"],"summary":"Remove the studio logo","description":"Removes the current image and deletes the file. Pages fall back to the default artwork.\n\nNot available with access tokens.","parameters":[{"name":"slug","in":"path","required":true,"description":"Slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Removed"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `studio_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/studios/{slug}/cover":{"put":{"operationId":"uploadStudioCover","tags":["Studios"],"summary":"Upload the studio cover","description":"PNG, JPEG or WebP up to 2 MB, no animation. The server removes all metadata (EXIF including GPS position, XMP, IPTC, comments, embedded thumbnails) and gives the file a new random name. Replacing an image deletes the old one. At least 640×160 pixels, wide (1.5:1 to 8:1). Owner and admins only.\n\nNot available with access tokens.\n\nRate limit: 30 uploads per hour per account.","parameters":[{"name":"slug","in":"path","required":true,"description":"Slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Stored and set as the current image","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"Image path relative to the API (`/v1/media/…`)"},"width":{"type":"integer"},"height":{"type":"integer"}},"required":["url","width","height"]}}}},"400":{"description":"Error codes: `invalid_image`, `upload_incomplete`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `studio_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"411":{"description":"Error codes: `length_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error codes: `file_too_large`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Error codes: `unsupported_media_type`, `invalid_image`, `animated_image`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `image_too_small`, `invalid_aspect_ratio`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 uploads per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `storage_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 uploads per hour per account","requestBody":{"required":true,"description":"The image","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}}}}},"delete":{"operationId":"deleteStudioCover","tags":["Studios"],"summary":"Remove the studio cover","description":"Removes the current image and deletes the file. Pages fall back to the default artwork.\n\nNot available with access tokens.","parameters":[{"name":"slug","in":"path","required":true,"description":"Slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Removed"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `studio_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/projects/{slug}/cover":{"put":{"operationId":"uploadProjectCover","tags":["Projects"],"summary":"Upload the project key art","description":"PNG, JPEG or WebP up to 2 MB, no animation. The server removes all metadata (EXIF including GPS position, XMP, IPTC, comments, embedded thumbnails) and gives the file a new random name. Replacing an image deletes the old one. At least 640×320 pixels, landscape (1.2:1 to 4:1, for example 1920×1080). Shown on the project page and on tiles. Everyone who can edit the project.\n\nNot available with access tokens.\n\nRate limit: 30 uploads per hour per account.","parameters":[{"name":"slug","in":"path","required":true,"description":"Slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Stored and set as the current image","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"Image path relative to the API (`/v1/media/…`)"},"width":{"type":"integer"},"height":{"type":"integer"}},"required":["url","width","height"]}}}},"400":{"description":"Error codes: `invalid_image`, `upload_incomplete`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `project_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"411":{"description":"Error codes: `length_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error codes: `file_too_large`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Error codes: `unsupported_media_type`, `invalid_image`, `animated_image`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `image_too_small`, `invalid_aspect_ratio`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 uploads per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `storage_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 uploads per hour per account","requestBody":{"required":true,"description":"The image","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}}}}},"delete":{"operationId":"deleteProjectCover","tags":["Projects"],"summary":"Remove the project key art","description":"Removes the current image and deletes the file. Pages fall back to the default artwork.\n\nNot available with access tokens.","parameters":[{"name":"slug","in":"path","required":true,"description":"Slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Removed"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `project_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/media/{file}":{"get":{"operationId":"getMedia","tags":["Profiles"],"summary":"Profile picture, cover, logo or key art","description":"Only delivered while the image is current and not removed by moderation. Cached for 10 minutes.","parameters":[{"name":"file","in":"path","required":true,"description":"`<32 hex characters>.<png|jpg|webp>`, from an image path like `avatar` or `cover`","schema":{"type":"string"}}],"security":[],"responses":{"200":{"description":"The image","content":{"image/*":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `storage_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none"}},"/v1/media/{file}/reports":{"post":{"operationId":"reportMedia","tags":["Reports and moderation"],"summary":"Report an image","description":"Notice under Art. 16 DSA for a profile picture, cover, studio logo or project key art, also without an account. Same rules as reporting a post.\n\nNot available with access tokens.\n\nRate limit: 10 per hour per IP.","parameters":[{"name":"file","in":"path","required":true,"description":"`<32 hex characters>.<png|jpg|webp>`, from an image path like `avatar` or `cover`","schema":{"type":"string"}}],"security":[{},{"session":[]}],"responses":{"201":{"description":"Report received (200 if you already reported this image)","content":{"application/json":{"schema":{"type":"object","properties":{"reportId":{"type":"string"},"status":{"const":"open"}},"required":["reportId","status"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `good_faith_confirmation_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional","x-gampeon-rate-limit":"10 per hour per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"string","enum":["illegal_content","harassment","hate_speech","violence_threat","child_safety","spam","copyright","other"]},"explanation":{"type":"string","minLength":20,"maxLength":5000},"reporterName":{"type":"string","minLength":2,"maxLength":120},"reporterEmail":{"type":"string","format":"email","maxLength":254},"goodFaith":{"const":true,"description":"Confirms the report is made in good faith"}},"required":["category","explanation","goodFaith"]}}}}}},"/v1/moderation/media/{file}/decision":{"post":{"operationId":"moderateMedia","tags":["Reports and moderation"],"summary":"Remove or restore an image without a report","description":"Removing takes the image off the profile, studio or project and stops delivering it; the file is kept for an appeal. Always with a statement of reasons, which the uploader sees.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"file","in":"path","required":true,"description":"`<32 hex characters>.<png|jpg|webp>`, from an image path like `avatar` or `cover`","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string"},"action":{"type":"string"}},"required":["decisionId","action"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_removed`, `not_removed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["remove","restore"]},"statementOfReasons":{"type":"string","description":"Statement of reasons, shown to the uploader (Art. 17 DSA)","minLength":20,"maxLength":5000},"legalGround":{"type":"string","maxLength":500}},"required":["action","statementOfReasons"]}}}}}},"/v1/moderation/media/{file}":{"get":{"operationId":"getMediaForModeration","tags":["Reports and moderation"],"summary":"View an image for moderation","description":"Also works for removed and replaced images that are still kept for a report or an appeal. Not cached.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"file","in":"path","required":true,"description":"`<32 hex characters>.<png|jpg|webp>`, from an image path like `avatar` or `cover`","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"200":{"description":"The image","content":{"image/*":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`, `file_missing`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `storage_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator"}},"/v1/jobs":{"get":{"operationId":"listJobs","tags":["Jobs"],"summary":"Open jobs","description":"Open jobs from accounts, studios and projects, newest first. Counts in `facets` ignore their own filter, so the portal can show them next to each option. Old applications and closed jobs are deleted after the retention periods in ADR 0018.","parameters":[{"name":"q","in":"query","required":false,"description":"Search in title and description","schema":{"type":"string","maxLength":64}},{"name":"role","in":"query","required":false,"description":"Role","schema":{"type":"string","enum":["scripter","ui_developer","mapper","modeler","animator","texture_artist","vehicle_artist","sound_designer","game_designer","writer","moderator","community_manager","server_admin","tester","translator","video_creator","other"]}},{"name":"compensation","in":"query","required":false,"description":"Compensation","schema":{"type":"string","enum":["volunteer","revenue_share","paid","negotiable"]}},{"name":"commitment","in":"query","required":false,"description":"Commitment","schema":{"type":"string","enum":["one_off","part_time","ongoing"]}},{"name":"language","in":"query","required":false,"description":"ISO 639-1 code","schema":{"type":"string","pattern":"^[a-z]{2}$"}},{"name":"skill","in":"query","required":false,"description":"Skill","schema":{"type":"string"}},{"name":"studio","in":"query","required":false,"description":"Studio slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}},{"name":"project","in":"query","required":false,"description":"Project slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}},{"name":"postedBy","in":"query","required":false,"description":"Handle of the person who posted","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}},{"name":"limit","in":"query","required":false,"description":"1 to 50 (default 24)","schema":{"type":"integer","minimum":1,"maximum":50}},{"name":"offset","in":"query","required":false,"description":"Entries to skip","schema":{"type":"integer","minimum":0}}],"security":[],"responses":{"200":{"description":"Jobs","content":{"application/json":{"schema":{"type":"object","properties":{"jobs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"role":{"type":"string","enum":["scripter","ui_developer","mapper","modeler","animator","texture_artist","vehicle_artist","sound_designer","game_designer","writer","moderator","community_manager","server_admin","tester","translator","video_creator","other"]},"description":{"type":"string"},"skills":{"type":"array","items":{"type":"string"}},"commitment":{"type":"string","enum":["one_off","part_time","ongoing"]},"languages":{"type":"array","items":{"type":"string"}},"links":{"type":"array","items":{"type":"string"}},"compensation":{"type":"string","enum":["volunteer","revenue_share","paid","negotiable"],"description":"What is offered. Only a statement: no money or GAMPEONS move through GAMPEON. `paid` is arranged in euros between the parties"},"compensationNote":{"type":"string","description":"Free text, for example the amount or the share"},"minAge":{"type":"integer","description":"Minimum age to apply: 16 for `volunteer`, 18 for everything else"},"status":{"type":"string","enum":["open","closed","expired","removed"],"description":"`expired`: open, but past `expiresAt`. `removed`: removed by moderation, only visible to the team and moderators"},"postedBy":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/`"},{"type":"null"}]}},"required":["handle","displayName","avatar"]},"studio":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"logo":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","name","logo"]},{"type":"null"}]},"project":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"cover":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","title","cover"]},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Jobs close 30 days after posting or renewing"},"removed":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"type":"string"}},"required":["at","reason"]}},"required":["id","title","role","description","skills","commitment","languages","links","compensation","compensationNote","minAge","status","postedBy","studio","project","createdAt","updatedAt","expiresAt"]}},"total":{"type":"integer"},"facets":{"type":"object","properties":{"role":{"type":"object","additionalProperties":{"type":"integer"}},"compensation":{"type":"object","additionalProperties":{"type":"integer"}},"commitment":{"type":"object","additionalProperties":{"type":"integer"}},"skills":{"type":"array","items":{"type":"object","properties":{"skill":{"type":"string"},"n":{"type":"integer"}},"required":["skill","n"]}}},"required":["role","compensation","commitment","skills"]},"options":{"type":"object","properties":{"roles":{"type":"array","items":{"type":"string"}},"compensation":{"type":"array","items":{"type":"string"}},"commitment":{"type":"array","items":{"type":"string"}},"limits":{"type":"object","additionalProperties":{"type":"integer"}}},"required":["roles","compensation","commitment","limits"]}},"required":["jobs","total","facets","options"]}}}}},"x-gampeon-auth":"none"},"post":{"operationId":"postJob","tags":["Jobs"],"summary":"Post a job","description":"For yourself, a studio (owner or admin) or a project you can edit (the project decides the studio). You must be 18 or older, have a confirmed email and an account at least 7 days old, and confirm the job posting rules (`acceptRules`): No jobs to rip or convert content from other games, no cheats or account trading, no gambling, no fees for applicants, no requests for passwords or downloads, no discrimination. At most 5 open jobs per account and 10 per studio.\n\nNot available with access tokens.\n\nRate limit: 20 per day per account.","security":[{"session":[]}],"responses":{"201":{"description":"Posted","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"role":{"type":"string","enum":["scripter","ui_developer","mapper","modeler","animator","texture_artist","vehicle_artist","sound_designer","game_designer","writer","moderator","community_manager","server_admin","tester","translator","video_creator","other"]},"description":{"type":"string"},"skills":{"type":"array","items":{"type":"string"}},"commitment":{"type":"string","enum":["one_off","part_time","ongoing"]},"languages":{"type":"array","items":{"type":"string"}},"links":{"type":"array","items":{"type":"string"}},"compensation":{"type":"string","enum":["volunteer","revenue_share","paid","negotiable"],"description":"What is offered. Only a statement: no money or GAMPEONS move through GAMPEON. `paid` is arranged in euros between the parties"},"compensationNote":{"type":"string","description":"Free text, for example the amount or the share"},"minAge":{"type":"integer","description":"Minimum age to apply: 16 for `volunteer`, 18 for everything else"},"status":{"type":"string","enum":["open","closed","expired","removed"],"description":"`expired`: open, but past `expiresAt`. `removed`: removed by moderation, only visible to the team and moderators"},"postedBy":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/`"},{"type":"null"}]}},"required":["handle","displayName","avatar"]},"studio":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"logo":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","name","logo"]},{"type":"null"}]},"project":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"cover":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","title","cover"]},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Jobs close 30 days after posting or renewing"},"removed":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"type":"string"}},"required":["at","reason"]}},"required":["id","title","role","description","skills","commitment","languages","links","compensation","compensationNote","minAge","status","postedBy","studio","project","createdAt","updatedAt","expiresAt"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `age_restricted`, `email_unverified`, `account_too_new`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `project_not_found`, `studio_not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `too_many_open_jobs`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `rules_confirmation_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 20 per day per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"20 per day per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":4,"maxLength":80},"role":{"type":"string","enum":["scripter","ui_developer","mapper","modeler","animator","texture_artist","vehicle_artist","sound_designer","game_designer","writer","moderator","community_manager","server_admin","tester","translator","video_creator","other"]},"description":{"type":"string","minLength":40,"maxLength":4000},"commitment":{"type":"string","enum":["one_off","part_time","ongoing"]},"compensation":{"type":"string","enum":["volunteer","revenue_share","paid","negotiable"]},"compensationNote":{"type":"string","maxLength":200},"skills":{"type":"array","items":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,23}$"},"description":"Up to 8 skills, lowercase (`a-z`, `0-9`, `-`)","maxItems":8},"languages":{"type":"array","items":{"type":"string","pattern":"^[a-z]{2}$"},"description":"Up to 5 ISO 639-1 language codes, for example `en`","maxItems":5},"links":{"type":"array","items":{"type":"string","pattern":"^https://","maxLength":308},"description":"Up to 3 `https://` links","maxItems":3},"studio":{"type":"string","description":"Studio slug","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},"project":{"type":"string","description":"Project slug","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},"acceptRules":{"const":true,"description":"Confirms the job posting rules"}},"required":["title","role","description","commitment","compensation","acceptRules"]}}}}}},"/v1/me/jobs":{"get":{"operationId":"listMyJobs","tags":["Jobs"],"summary":"Jobs you manage","description":"Your own jobs and those of studios you own or administer and projects you own, with application counts per status.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Up to 200, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"jobs":{"type":"array","items":{"allOf":[{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"role":{"type":"string","enum":["scripter","ui_developer","mapper","modeler","animator","texture_artist","vehicle_artist","sound_designer","game_designer","writer","moderator","community_manager","server_admin","tester","translator","video_creator","other"]},"description":{"type":"string"},"skills":{"type":"array","items":{"type":"string"}},"commitment":{"type":"string","enum":["one_off","part_time","ongoing"]},"languages":{"type":"array","items":{"type":"string"}},"links":{"type":"array","items":{"type":"string"}},"compensation":{"type":"string","enum":["volunteer","revenue_share","paid","negotiable"],"description":"What is offered. Only a statement: no money or GAMPEONS move through GAMPEON. `paid` is arranged in euros between the parties"},"compensationNote":{"type":"string","description":"Free text, for example the amount or the share"},"minAge":{"type":"integer","description":"Minimum age to apply: 16 for `volunteer`, 18 for everything else"},"status":{"type":"string","enum":["open","closed","expired","removed"],"description":"`expired`: open, but past `expiresAt`. `removed`: removed by moderation, only visible to the team and moderators"},"postedBy":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/`"},{"type":"null"}]}},"required":["handle","displayName","avatar"]},"studio":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"logo":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","name","logo"]},{"type":"null"}]},"project":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"cover":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","title","cover"]},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Jobs close 30 days after posting or renewing"},"removed":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"type":"string"}},"required":["at","reason"]}},"required":["id","title","role","description","skills","commitment","languages","links","compensation","compensationNote","minAge","status","postedBy","studio","project","createdAt","updatedAt","expiresAt"]},{"type":"object","properties":{"applications":{"type":"object","additionalProperties":{"type":"integer"}}},"required":["applications"]}]}}},"required":["jobs"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/jobs/{id}":{"get":{"operationId":"getJob","tags":["Jobs"],"summary":"A job","description":"Closed and expired jobs stay readable. Removed jobs and jobs of hidden studios or projects are only visible to the team and moderators. With login, `viewer` says whether you can apply and why not (`own_job`, `not_open`, `already_applied`, `not_allowed`, `age_16`, `age_18`).\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Job ID","schema":{"type":"integer","minimum":1}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Job","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"role":{"type":"string","enum":["scripter","ui_developer","mapper","modeler","animator","texture_artist","vehicle_artist","sound_designer","game_designer","writer","moderator","community_manager","server_admin","tester","translator","video_creator","other"]},"description":{"type":"string"},"skills":{"type":"array","items":{"type":"string"}},"commitment":{"type":"string","enum":["one_off","part_time","ongoing"]},"languages":{"type":"array","items":{"type":"string"}},"links":{"type":"array","items":{"type":"string"}},"compensation":{"type":"string","enum":["volunteer","revenue_share","paid","negotiable"],"description":"What is offered. Only a statement: no money or GAMPEONS move through GAMPEON. `paid` is arranged in euros between the parties"},"compensationNote":{"type":"string","description":"Free text, for example the amount or the share"},"minAge":{"type":"integer","description":"Minimum age to apply: 16 for `volunteer`, 18 for everything else"},"status":{"type":"string","enum":["open","closed","expired","removed"],"description":"`expired`: open, but past `expiresAt`. `removed`: removed by moderation, only visible to the team and moderators"},"postedBy":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/`"},{"type":"null"}]}},"required":["handle","displayName","avatar"]},"studio":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"logo":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","name","logo"]},{"type":"null"}]},"project":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"cover":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","title","cover"]},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Jobs close 30 days after posting or renewing"},"removed":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"type":"string"}},"required":["at","reason"]}},"required":["id","title","role","description","skills","commitment","languages","links","compensation","compensationNote","minAge","status","postedBy","studio","project","createdAt","updatedAt","expiresAt"]},{"type":"object","properties":{"viewer":{"oneOf":[{"type":"object","properties":{"canManage":{"type":"boolean"},"canApply":{"type":"boolean"},"applyBlockedReason":{"oneOf":[{"type":"string"},{"type":"null"}]},"application":{"oneOf":[{"type":"object","properties":{"id":{"type":"integer"},"status":{"type":"string","enum":["new","shortlisted","accepted","declined","withdrawn"]}},"required":["id","status"]},{"type":"null"}]},"applications":{"type":"integer","description":"Only for the team: applications that are not withdrawn"}},"required":["canManage","canApply","applyBlockedReason","application"]},{"type":"null"}]}},"required":["viewer"]}]}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"},"patch":{"operationId":"updateJob","tags":["Jobs"],"summary":"Edit a job","description":"Only for the person who posted it, studio owners and admins, and people who can edit the project. A `volunteer` job cannot change its compensation while people under 18 have open applications.\n\nNot available with access tokens.\n\nRate limit: 120 per hour per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Job ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"role":{"type":"string","enum":["scripter","ui_developer","mapper","modeler","animator","texture_artist","vehicle_artist","sound_designer","game_designer","writer","moderator","community_manager","server_admin","tester","translator","video_creator","other"]},"description":{"type":"string"},"skills":{"type":"array","items":{"type":"string"}},"commitment":{"type":"string","enum":["one_off","part_time","ongoing"]},"languages":{"type":"array","items":{"type":"string"}},"links":{"type":"array","items":{"type":"string"}},"compensation":{"type":"string","enum":["volunteer","revenue_share","paid","negotiable"],"description":"What is offered. Only a statement: no money or GAMPEONS move through GAMPEON. `paid` is arranged in euros between the parties"},"compensationNote":{"type":"string","description":"Free text, for example the amount or the share"},"minAge":{"type":"integer","description":"Minimum age to apply: 16 for `volunteer`, 18 for everything else"},"status":{"type":"string","enum":["open","closed","expired","removed"],"description":"`expired`: open, but past `expiresAt`. `removed`: removed by moderation, only visible to the team and moderators"},"postedBy":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/`"},{"type":"null"}]}},"required":["handle","displayName","avatar"]},"studio":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"logo":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","name","logo"]},{"type":"null"}]},"project":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"cover":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","title","cover"]},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Jobs close 30 days after posting or renewing"},"removed":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"type":"string"}},"required":["at","reason"]}},"required":["id","title","role","description","skills","commitment","languages","links","compensation","compensationNote","minAge","status","postedBy","studio","project","createdAt","updatedAt","expiresAt"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `removed`, `minor_applicants`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"120 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":4,"maxLength":80},"role":{"type":"string","enum":["scripter","ui_developer","mapper","modeler","animator","texture_artist","vehicle_artist","sound_designer","game_designer","writer","moderator","community_manager","server_admin","tester","translator","video_creator","other"]},"description":{"type":"string","minLength":40,"maxLength":4000},"commitment":{"type":"string","enum":["one_off","part_time","ongoing"]},"compensation":{"type":"string","enum":["volunteer","revenue_share","paid","negotiable"]},"compensationNote":{"type":"string","maxLength":200},"skills":{"type":"array","items":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,23}$"},"description":"Up to 8 skills, lowercase (`a-z`, `0-9`, `-`)","maxItems":8},"languages":{"type":"array","items":{"type":"string","pattern":"^[a-z]{2}$"},"description":"Up to 5 ISO 639-1 language codes, for example `en`","maxItems":5},"links":{"type":"array","items":{"type":"string","pattern":"^https://","maxLength":308},"description":"Up to 3 `https://` links","maxItems":3}},"required":[]}}}}},"delete":{"operationId":"deleteJob","tags":["Jobs"],"summary":"Delete a job","description":"Deletes the job with all applications and conversations. Reported versions stay as copies in the reports.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Job ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/jobs/{id}/close":{"post":{"operationId":"closeJob","tags":["Jobs"],"summary":"Close a job","description":"No new applications. Existing conversations continue.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Job ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Closed","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"role":{"type":"string","enum":["scripter","ui_developer","mapper","modeler","animator","texture_artist","vehicle_artist","sound_designer","game_designer","writer","moderator","community_manager","server_admin","tester","translator","video_creator","other"]},"description":{"type":"string"},"skills":{"type":"array","items":{"type":"string"}},"commitment":{"type":"string","enum":["one_off","part_time","ongoing"]},"languages":{"type":"array","items":{"type":"string"}},"links":{"type":"array","items":{"type":"string"}},"compensation":{"type":"string","enum":["volunteer","revenue_share","paid","negotiable"],"description":"What is offered. Only a statement: no money or GAMPEONS move through GAMPEON. `paid` is arranged in euros between the parties"},"compensationNote":{"type":"string","description":"Free text, for example the amount or the share"},"minAge":{"type":"integer","description":"Minimum age to apply: 16 for `volunteer`, 18 for everything else"},"status":{"type":"string","enum":["open","closed","expired","removed"],"description":"`expired`: open, but past `expiresAt`. `removed`: removed by moderation, only visible to the team and moderators"},"postedBy":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/`"},{"type":"null"}]}},"required":["handle","displayName","avatar"]},"studio":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"logo":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","name","logo"]},{"type":"null"}]},"project":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"cover":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","title","cover"]},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Jobs close 30 days after posting or renewing"},"removed":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"type":"string"}},"required":["at","reason"]}},"required":["id","title","role","description","skills","commitment","languages","links","compensation","compensationNote","minAge","status","postedBy","studio","project","createdAt","updatedAt","expiresAt"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/jobs/{id}/renew":{"post":{"operationId":"renewJob","tags":["Jobs"],"summary":"Reopen or extend a job","description":"Open for another 30 days from now. Counts against the open-job limits.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Job ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Open","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"role":{"type":"string","enum":["scripter","ui_developer","mapper","modeler","animator","texture_artist","vehicle_artist","sound_designer","game_designer","writer","moderator","community_manager","server_admin","tester","translator","video_creator","other"]},"description":{"type":"string"},"skills":{"type":"array","items":{"type":"string"}},"commitment":{"type":"string","enum":["one_off","part_time","ongoing"]},"languages":{"type":"array","items":{"type":"string"}},"links":{"type":"array","items":{"type":"string"}},"compensation":{"type":"string","enum":["volunteer","revenue_share","paid","negotiable"],"description":"What is offered. Only a statement: no money or GAMPEONS move through GAMPEON. `paid` is arranged in euros between the parties"},"compensationNote":{"type":"string","description":"Free text, for example the amount or the share"},"minAge":{"type":"integer","description":"Minimum age to apply: 16 for `volunteer`, 18 for everything else"},"status":{"type":"string","enum":["open","closed","expired","removed"],"description":"`expired`: open, but past `expiresAt`. `removed`: removed by moderation, only visible to the team and moderators"},"postedBy":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/`"},{"type":"null"}]}},"required":["handle","displayName","avatar"]},"studio":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"logo":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","name","logo"]},{"type":"null"}]},"project":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"cover":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","title","cover"]},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Jobs close 30 days after posting or renewing"},"removed":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"type":"string"}},"required":["at","reason"]}},"required":["id","title","role","description","skills","commitment","languages","links","compensation","compensationNote","minAge","status","postedBy","studio","project","createdAt","updatedAt","expiresAt"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `removed`, `page_hidden`, `too_many_open_jobs`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/jobs/{id}/applications":{"post":{"operationId":"applyForJob","tags":["Jobs"],"summary":"Apply for a job","description":"One application per job. From 16 for `volunteer` jobs, from 18 for everything else; accounts without a birth month count as under 16. The team gets a `job_application` notification (at most one per job every 30 minutes).\n\nNot available with access tokens.\n\nRate limit: 20 per day per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Job ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Applied","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"jobId":{"type":"integer"},"status":{"const":"new"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","jobId","status","createdAt"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `age_restricted`, `not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `own_job`, `not_open`, `already_applied`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 20 per day per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"20 per day per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","minLength":20,"maxLength":2000},"links":{"type":"array","items":{"type":"string","pattern":"^https://","maxLength":308},"description":"Up to 3 `https://` links","maxItems":3}},"required":["message"]}}}}},"get":{"operationId":"listJobApplications","tags":["Jobs"],"summary":"Applications for a job","description":"Only for the team. Withdrawn applications are not listed.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Job ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Applications, oldest first","content":{"application/json":{"schema":{"type":"object","properties":{"job":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"role":{"type":"string","enum":["scripter","ui_developer","mapper","modeler","animator","texture_artist","vehicle_artist","sound_designer","game_designer","writer","moderator","community_manager","server_admin","tester","translator","video_creator","other"]},"description":{"type":"string"},"skills":{"type":"array","items":{"type":"string"}},"commitment":{"type":"string","enum":["one_off","part_time","ongoing"]},"languages":{"type":"array","items":{"type":"string"}},"links":{"type":"array","items":{"type":"string"}},"compensation":{"type":"string","enum":["volunteer","revenue_share","paid","negotiable"],"description":"What is offered. Only a statement: no money or GAMPEONS move through GAMPEON. `paid` is arranged in euros between the parties"},"compensationNote":{"type":"string","description":"Free text, for example the amount or the share"},"minAge":{"type":"integer","description":"Minimum age to apply: 16 for `volunteer`, 18 for everything else"},"status":{"type":"string","enum":["open","closed","expired","removed"],"description":"`expired`: open, but past `expiresAt`. `removed`: removed by moderation, only visible to the team and moderators"},"postedBy":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/`"},{"type":"null"}]}},"required":["handle","displayName","avatar"]},"studio":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"logo":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","name","logo"]},{"type":"null"}]},"project":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"cover":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","title","cover"]},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Jobs close 30 days after posting or renewing"},"removed":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"type":"string"}},"required":["at","reason"]}},"required":["id","title","role","description","skills","commitment","languages","links","compensation","compensationNote","minAge","status","postedBy","studio","project","createdAt","updatedAt","expiresAt"]},"applications":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"message":{"type":"string"},"links":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["new","shortlisted","accepted","declined","withdrawn"]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"messages":{"type":"integer"},"lastMessageAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"applicant":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"}},"required":["handle","displayName"]}},"required":["id","message","links","status","createdAt","updatedAt","messages","lastMessageAt","applicant"]}}},"required":["job","applications"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/me/applications":{"get":{"operationId":"listMyApplications","tags":["Jobs"],"summary":"Your applications","description":"Not available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Up to 200, most recent activity first","content":{"application/json":{"schema":{"type":"object","properties":{"applications":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"status":{"type":"string","enum":["new","shortlisted","accepted","declined","withdrawn"]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"jobId":{"type":"integer"},"lastMessageAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"job":{"oneOf":[{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"role":{"type":"string","enum":["scripter","ui_developer","mapper","modeler","animator","texture_artist","vehicle_artist","sound_designer","game_designer","writer","moderator","community_manager","server_admin","tester","translator","video_creator","other"]},"description":{"type":"string"},"skills":{"type":"array","items":{"type":"string"}},"commitment":{"type":"string","enum":["one_off","part_time","ongoing"]},"languages":{"type":"array","items":{"type":"string"}},"links":{"type":"array","items":{"type":"string"}},"compensation":{"type":"string","enum":["volunteer","revenue_share","paid","negotiable"],"description":"What is offered. Only a statement: no money or GAMPEONS move through GAMPEON. `paid` is arranged in euros between the parties"},"compensationNote":{"type":"string","description":"Free text, for example the amount or the share"},"minAge":{"type":"integer","description":"Minimum age to apply: 16 for `volunteer`, 18 for everything else"},"status":{"type":"string","enum":["open","closed","expired","removed"],"description":"`expired`: open, but past `expiresAt`. `removed`: removed by moderation, only visible to the team and moderators"},"postedBy":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/`"},{"type":"null"}]}},"required":["handle","displayName","avatar"]},"studio":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"logo":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","name","logo"]},{"type":"null"}]},"project":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"cover":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","title","cover"]},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Jobs close 30 days after posting or renewing"},"removed":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"type":"string"}},"required":["at","reason"]}},"required":["id","title","role","description","skills","commitment","languages","links","compensation","compensationNote","minAge","status","postedBy","studio","project","createdAt","updatedAt","expiresAt"]},{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"status":{"const":"removed"}},"required":["id","title","status"]}]}},"required":["id","status","createdAt","updatedAt","jobId","lastMessageAt","job"]}}},"required":["applications"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/applications/{id}":{"get":{"operationId":"getApplication","tags":["Jobs"],"summary":"An application with its conversation","description":"Only for the applicant and the team. Messages are not scanned; either side can report a message. `safetyNotice` is true for viewers under 18 (or without a birth month), the portal then shows a fixed safety notice.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Application ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Application","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"status":{"type":"string","enum":["new","shortlisted","accepted","declined","withdrawn"]},"message":{"type":"string"},"links":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"applicant":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"}},"required":["handle","displayName"]},"job":{"oneOf":[{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"role":{"type":"string","enum":["scripter","ui_developer","mapper","modeler","animator","texture_artist","vehicle_artist","sound_designer","game_designer","writer","moderator","community_manager","server_admin","tester","translator","video_creator","other"]},"description":{"type":"string"},"skills":{"type":"array","items":{"type":"string"}},"commitment":{"type":"string","enum":["one_off","part_time","ongoing"]},"languages":{"type":"array","items":{"type":"string"}},"links":{"type":"array","items":{"type":"string"}},"compensation":{"type":"string","enum":["volunteer","revenue_share","paid","negotiable"],"description":"What is offered. Only a statement: no money or GAMPEONS move through GAMPEON. `paid` is arranged in euros between the parties"},"compensationNote":{"type":"string","description":"Free text, for example the amount or the share"},"minAge":{"type":"integer","description":"Minimum age to apply: 16 for `volunteer`, 18 for everything else"},"status":{"type":"string","enum":["open","closed","expired","removed"],"description":"`expired`: open, but past `expiresAt`. `removed`: removed by moderation, only visible to the team and moderators"},"postedBy":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/`"},{"type":"null"}]}},"required":["handle","displayName","avatar"]},"studio":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"logo":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","name","logo"]},{"type":"null"}]},"project":{"oneOf":[{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"cover":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["slug","title","cover"]},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Jobs close 30 days after posting or renewing"},"removed":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"type":"string"}},"required":["at","reason"]}},"required":["id","title","role","description","skills","commitment","languages","links","compensation","compensationNote","minAge","status","postedBy","studio","project","createdAt","updatedAt","expiresAt"]},{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"status":{"const":"removed"}},"required":["id","title","status"]}]},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"body":{"oneOf":[{"type":"string","description":"`null` if removed by moderation"},{"type":"null"}]},"removed":{"type":"boolean"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"author":{"oneOf":[{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"}},"required":["handle","displayName"]},{"type":"null"}]},"mine":{"type":"boolean"},"side":{"type":"string","enum":["applicant","team"]}},"required":["id","body","removed","createdAt","author","mine","side"]}},"viewer":{"type":"object","properties":{"side":{"type":"string","enum":["applicant","manager"]},"canMessage":{"type":"boolean"},"safetyNotice":{"type":"boolean"}},"required":["side","canMessage","safetyNotice"]}},"required":["id","status","message","links","createdAt","updatedAt","applicant","job","messages","viewer"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"},"patch":{"operationId":"updateApplication","tags":["Jobs"],"summary":"Change the status of an application","description":"The team sets `shortlisted`, `accepted` or `declined` (the applicant gets an `application_status` notification). The applicant can only set `withdrawn`. Withdrawn applications are deleted after 30 days.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Application ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"status":{"type":"string","enum":["new","shortlisted","accepted","declined","withdrawn"]}},"required":["id","status"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `withdrawn`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["new","shortlisted","accepted","declined","withdrawn"]}},"required":["status"]}}}}}},"/v1/applications/{id}/messages":{"post":{"operationId":"sendApplicationMessage","tags":["Jobs"],"summary":"Send a message about an application","description":"Text only, no attachments. Closed for withdrawn and declined applications and removed jobs. The other side gets an `application_message` notification (at most one every 30 minutes).\n\nNot available with access tokens.\n\nRate limit: 50 per day per account and conversation.","parameters":[{"name":"id","in":"path","required":true,"description":"Application ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Sent","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"body":{"type":"string"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","body","createdAt"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `conversation_closed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 50 per day per account and conversation. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"50 per day per account and conversation","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":2000}},"required":["body"]}}}}}},"/v1/legal/job-report-categories":{"get":{"operationId":"getJobReportCategories","tags":["Reports and moderation"],"summary":"Report categories for jobs and messages","security":[],"responses":{"200":{"description":"Categories","content":{"application/json":{"schema":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"string","enum":["scam","illegal_work","child_safety","harassment","hate_speech","spam","copyright","other"]}},"anonymous":{"type":"array","items":{"type":"string"},"description":"Categories that need no name and email"}},"required":["categories","anonymous"]}}}}},"x-gampeon-auth":"none"}},"/v1/jobs/{id}/reports":{"post":{"operationId":"reportJob","tags":["Reports and moderation"],"summary":"Report a job","description":"Notice under Art. 16 DSA, also without an account. Name and email are required except for `child_safety`. A copy of the job is kept with the report.\n\nNot available with access tokens.\n\nRate limit: 10 per hour per IP.","parameters":[{"name":"id","in":"path","required":true,"description":"Job ID","schema":{"type":"integer","minimum":1}}],"security":[{},{"session":[]}],"responses":{"201":{"description":"Report received (200 if you already reported it)","content":{"application/json":{"schema":{"type":"object","properties":{"reportId":{"type":"string"},"status":{"const":"open"}},"required":["reportId","status"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `good_faith_confirmation_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional","x-gampeon-rate-limit":"10 per hour per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"string","enum":["scam","illegal_work","child_safety","harassment","hate_speech","spam","copyright","other"]},"explanation":{"type":"string","minLength":20,"maxLength":5000},"reporterName":{"type":"string","minLength":2,"maxLength":120},"reporterEmail":{"type":"string","format":"email","maxLength":254},"goodFaith":{"const":true,"description":"Confirms the report is made in good faith"}},"required":["category","explanation","goodFaith"]}}}}}},"/v1/job-messages/{id}/reports":{"post":{"operationId":"reportJobMessage","tags":["Reports and moderation"],"summary":"Report a message in an application conversation","description":"Only people in the conversation can report, never their own message. A copy of the message is kept with the report.\n\nNot available with access tokens.\n\nRate limit: 10 per hour per IP.","parameters":[{"name":"id","in":"path","required":true,"description":"Message ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Report received (200 if you already reported it)","content":{"application/json":{"schema":{"type":"object","properties":{"reportId":{"type":"string"},"status":{"const":"open"}},"required":["reportId","status"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `own_message`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `good_faith_confirmation_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"10 per hour per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"string","enum":["scam","illegal_work","child_safety","harassment","hate_speech","spam","copyright","other"]},"explanation":{"type":"string","minLength":20,"maxLength":5000},"reporterName":{"type":"string","minLength":2,"maxLength":120},"reporterEmail":{"type":"string","format":"email","maxLength":254},"goodFaith":{"const":true,"description":"Confirms the report is made in good faith"}},"required":["category","explanation","goodFaith"]}}}}}},"/v1/moderation/job-reports":{"get":{"operationId":"listJobReports","tags":["Reports and moderation"],"summary":"Reports about jobs and messages","description":"Up to 200, `urgent` ones (`child_safety`) first, then oldest first.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"status","in":"query","required":false,"description":"Default: open","schema":{"type":"string","enum":["open","actioned","rejected"]}}],"security":[{"session":[]}],"responses":{"200":{"description":"Reports","content":{"application/json":{"schema":{"type":"object","properties":{"reports":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"targetType":{"type":"string","enum":["job","message"]},"jobId":{"oneOf":[{"type":"integer"},{"type":"null"}]},"messageId":{"oneOf":[{"type":"integer"},{"type":"null"}]},"snapshot":{"type":"string","description":"Reported text"},"category":{"type":"string"},"explanation":{"type":"string"},"reporterName":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"authorHandle":{"oneOf":[{"type":"string"},{"type":"null"}]},"authorName":{"oneOf":[{"type":"string"},{"type":"null"}]},"removedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"deleted":{"type":"boolean","description":"Deleted in the meantime"},"urgent":{"type":"boolean"}},"required":["id","targetType","jobId","messageId","snapshot","category","explanation","reporterName","status","createdAt","authorHandle","authorName","removedAt","deleted","urgent"]}}},"required":["reports"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator"}},"/v1/moderation/job-reports/{id}/decision":{"post":{"operationId":"decideJobReport","tags":["Reports and moderation"],"summary":"Decide on a report about a job or message","description":"`remove` removes the job or message, closes all open reports about it and informs the author (Art. 17 DSA) and the reporting people (Art. 16(5)). `reject` keeps it and informs the reporting person.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Report ID","schema":{"type":"string","format":"uuid"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string"},"action":{"type":"string"}},"required":["decisionId","action"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_decided`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["remove","reject"]},"statementOfReasons":{"type":"string","description":"Statement of reasons, shown to the author (Art. 17 DSA)","minLength":20,"maxLength":5000},"legalGround":{"type":"string","maxLength":500}},"required":["action","statementOfReasons"]}}}}}},"/v1/moderation/jobs/{id}/decision":{"post":{"operationId":"moderateJob","tags":["Reports and moderation"],"summary":"Remove or restore a job without a report","description":"Always with a statement of reasons, which the author sees.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Job ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string"},"action":{"type":"string"}},"required":["decisionId","action"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_removed`, `not_removed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["remove","restore"]},"statementOfReasons":{"type":"string","description":"Statement of reasons, shown to the author (Art. 17 DSA)","minLength":20,"maxLength":5000},"legalGround":{"type":"string","maxLength":500}},"required":["action","statementOfReasons"]}}}}}},"/v1/job-appeals":{"post":{"operationId":"appealJobRemoval","tags":["Reports and moderation"],"summary":"Appeal the removal of your job or message","description":"One appeal per decision (Art. 20 DSA). Someone from moderation decides and explains the outcome.\n\nNot available with access tokens.\n\nRate limit: 10 per day per account.","security":[{"session":[]}],"responses":{"201":{"description":"Appeal received","content":{"application/json":{"schema":{"type":"object","properties":{"appealId":{"type":"string"},"status":{"const":"open"}},"required":["appealId","status"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `appeal_exists`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per day per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"10 per day per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string"},"text":{"type":"string","minLength":20,"maxLength":5000}},"required":["decisionId","text"]}}}}}},"/v1/me/job-decisions":{"get":{"operationId":"listMyJobDecisions","tags":["Reports and moderation"],"summary":"Removals of your jobs and messages","description":"Not available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Up to 100, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"decisions":{"type":"array","items":{"type":"object","properties":{"decisionId":{"type":"string"},"targetType":{"type":"string","enum":["job","message"]},"jobId":{"oneOf":[{"type":"integer"},{"type":"null"}]},"snapshot":{"type":"string"},"statementOfReasons":{"type":"string"},"legalGround":{"oneOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"appealId":{"oneOf":[{"type":"string"},{"type":"null"}]},"appealStatus":{"oneOf":[{"type":"string","enum":["open","upheld","reversed"]},{"type":"null"}]},"outcomeReasons":{"oneOf":[{"type":"string"},{"type":"null"}]},"decidedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["decisionId","targetType","jobId","snapshot","statementOfReasons","legalGround","createdAt","appealId","appealStatus","outcomeReasons","decidedAt"]}}},"required":["decisions"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/moderation/job-appeals":{"get":{"operationId":"listJobAppeals","tags":["Reports and moderation"],"summary":"Appeals about jobs and messages","description":"`ownDecision` shows whether you made the removal yourself, so someone else can review it.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"status","in":"query","required":false,"description":"Default: open","schema":{"type":"string","enum":["open","upheld","reversed"]}}],"security":[{"session":[]}],"responses":{"200":{"description":"Appeals","content":{"application/json":{"schema":{"type":"object","properties":{"appeals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"status":{"type":"string"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"decidedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"outcomeReasons":{"oneOf":[{"type":"string"},{"type":"null"}]},"decisionId":{"type":"string"},"targetType":{"type":"string","enum":["job","message"]},"jobId":{"oneOf":[{"type":"integer"},{"type":"null"}]},"snapshot":{"type":"string"},"statementOfReasons":{"type":"string"},"legalGround":{"oneOf":[{"type":"string"},{"type":"null"}]},"removedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"authorHandle":{"type":"string"},"authorName":{"type":"string"},"ownDecision":{"type":"boolean"}},"required":["id","text","status","createdAt","decidedAt","outcomeReasons","decisionId","targetType","jobId","snapshot","statementOfReasons","legalGround","removedAt","authorHandle","authorName","ownDecision"]}}},"required":["appeals"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator"}},"/v1/moderation/job-appeals/{id}/decision":{"post":{"operationId":"decideJobAppeal","tags":["Reports and moderation"],"summary":"Decide on an appeal about a job or message","description":"`reverse` restores the job or message unless another removal still applies. The author gets the reasons and the notice about out-of-court dispute settlement (Art. 21 DSA).\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Appeal ID","schema":{"type":"string","format":"uuid"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"appealId":{"type":"string"},"outcome":{"type":"string"},"restored":{"type":"boolean"}},"required":["appealId","outcome","restored"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_decided`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","enum":["uphold","reverse"]},"statementOfReasons":{"type":"string","description":"Statement of reasons, shown to the author (Art. 17 DSA)","minLength":20,"maxLength":5000}},"required":["outcome","statementOfReasons"]}}}}}},"/v1/moderation/job-stats":{"get":{"operationId":"getJobModerationStats","tags":["Reports and moderation"],"summary":"Numbers for the transparency report (jobs)","description":"Requires the role moderator or admin.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Counts","content":{"application/json":{"schema":{"type":"object","properties":{"reports":{"type":"array","items":{"type":"object","properties":{"targetType":{"type":"string"},"category":{"type":"string"},"status":{"type":"string"},"n":{"type":"integer"}},"required":["targetType","category","status","n"]}},"decisions":{"type":"array","items":{"type":"object","properties":{"targetType":{"type":"string"},"action":{"type":"string"},"onNotice":{"type":"integer"},"n":{"type":"integer"}},"required":["targetType","action","onNotice","n"]}},"appeals":{"type":"array","items":{"type":"object","properties":{"status":{"type":"string"},"n":{"type":"integer"}},"required":["status","n"]}}},"required":["reports","decisions","appeals"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator"}},"/v1/projects/{slug}/views":{"post":{"operationId":"countProjectView","tags":["Projects"],"summary":"Count a page view","description":"The portal calls this once when the project page opens. Counted once per visitor and day; the team and drafts are not counted. Nothing about the visitor is stored, only a counter per project and day.\n\nNot available with access tokens.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{},{"session":[]}],"responses":{"204":{"description":"Received (counted or not)"},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"}},"/v1/projects/{slug}/favorite":{"put":{"operationId":"favoriteProject","tags":["Projects"],"summary":"Add a project to your favorites","description":"Published projects only. Calling it again changes nothing.\n\nNot available with access tokens.\n\nRate limit: 120 per hour per account.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Favorite","content":{"application/json":{"schema":{"type":"object","properties":{"favorited":{"type":"boolean"},"favorites":{"type":"integer","description":"Favorites of the project now"}},"required":["favorited","favorites"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"120 per hour per account"},"delete":{"operationId":"unfavoriteProject","tags":["Projects"],"summary":"Remove a project from your favorites","description":"Not available with access tokens.\n\nRate limit: 120 per hour per account.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Not a favorite any more","content":{"application/json":{"schema":{"type":"object","properties":{"favorited":{"type":"boolean"},"favorites":{"type":"integer","description":"Favorites of the project now"}},"required":["favorited","favorites"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"120 per hour per account"}},"/v1/projects/{slug}/stats":{"get":{"operationId":"getProjectStats","tags":["Projects"],"summary":"Views and favorites per day","description":"For the team: the owner and all members of the studio. Days in UTC, oldest first, days without activity included.\n\nAccess tokens: scope `projects:read`.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}},{"name":"days","in":"query","required":false,"description":"1 to 90 (default 30)","schema":{"type":"integer","minimum":1,"maximum":90,"default":30}}],"security":[{"session":[]},{"accessToken":["projects:read"]}],"responses":{"200":{"description":"Statistics","content":{"application/json":{"schema":{"type":"object","properties":{"days":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string","description":"YYYY-MM-DD"},"views":{"type":"integer"},"favorites":{"type":"integer","description":"Favorites added that day"}},"required":["day","views","favorites"]}},"totals":{"type":"object","properties":{"views":{"type":"integer"},"favorites":{"type":"integer"},"viewsInRange":{"type":"integer"},"favoritesInRange":{"type":"integer"}},"required":["views","favorites","viewsInRange","favoritesInRange"]},"storage":{"type":"object","properties":{"files":{"type":"integer","description":"Images of the project: key art and gallery"},"bytes":{"type":"integer"}},"required":["files","bytes"]},"gallery":{"type":"object","properties":{"items":{"type":"integer"},"max":{"type":"integer"}},"required":["items","max"]}},"required":["days","totals","storage","gallery"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `insufficient_scope`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-token-scope":"projects:read"}},"/v1/projects/{slug}/gallery/images":{"post":{"operationId":"uploadGalleryImage","tags":["Projects"],"summary":"Add a screenshot to the gallery","description":"Everyone who can edit the project (owner, or owners and admins of its studio). PNG, JPEG or WebP up to 2 MB, at least 480×270 pixels, no animation. The server removes all metadata (EXIF including GPS position, XMP, IPTC, comments) and gives the file a random name. At most 20 images and videos per project. Set a caption with the change route.\n\nNot available with access tokens.\n\nRate limit: 30 uploads per hour per account (all images together).","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Added at the end of the gallery","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GalleryItem"}}}},"400":{"description":"Error codes: `invalid_image`, `upload_incomplete`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `project_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `gallery_full`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"411":{"description":"Error codes: `length_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error codes: `file_too_large`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Error codes: `unsupported_media_type`, `invalid_image`, `animated_image`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `image_too_small`, `invalid_aspect_ratio`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 uploads per hour per account (all images together). Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `storage_disabled`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 uploads per hour per account (all images together)","requestBody":{"required":true,"description":"The image","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}}}}}},"/v1/projects/{slug}/gallery/videos":{"post":{"operationId":"addGalleryVideo","tags":["Projects"],"summary":"Add a YouTube video to the gallery","description":"Everyone who can edit the project (owner, or owners and admins of its studio). Links like `https://www.youtube.com/watch?v=…`, `https://youtu.be/…` or Shorts. The portal loads the video from youtube-nocookie.com only after a click.\n\nNot available with access tokens.\n\nRate limit: 30 per hour per account.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Added at the end of the gallery","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GalleryItem"}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `project_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `gallery_full`, `video_exists`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `unsupported_video_url`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"YouTube link","maxLength":300},"caption":{"type":"string","maxLength":140}},"required":["url"]}}}}}},"/v1/projects/{slug}/gallery/{id}":{"patch":{"operationId":"updateGalleryItem","tags":["Projects"],"summary":"Change caption or position","description":"Everyone who can edit the project (owner, or owners and admins of its studio). `position` moves the item (0 = first).\n\nNot available with access tokens.\n\nRate limit: 120 edits per hour per account.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}},{"name":"id","in":"path","required":true,"description":"Gallery item ID (16 hex characters)","schema":{"type":"string","pattern":"^[a-f0-9]{16}$"}}],"security":[{"session":[]}],"responses":{"200":{"description":"The whole gallery in the new order","content":{"application/json":{"schema":{"type":"object","properties":{"gallery":{"type":"array","items":{"$ref":"#/components/schemas/GalleryItem"}}},"required":["gallery"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `project_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 120 edits per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"120 edits per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"caption":{"type":"string","maxLength":140},"position":{"type":"integer","minimum":0}},"required":[]}}}}},"delete":{"operationId":"deleteGalleryItem","tags":["Projects"],"summary":"Remove an item from the gallery","description":"Everyone who can edit the project (owner, or owners and admins of its studio). Images are deleted, unless a report about them is still open or moderation removed them (kept for an appeal).\n\nNot available with access tokens.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"}},{"name":"id","in":"path","required":true,"description":"Gallery item ID (16 hex characters)","schema":{"type":"string","pattern":"^[a-f0-9]{16}$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Removed"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `project_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/status":{"get":{"operationId":"getStatus","tags":["Meta"],"summary":"Platform status","description":"What the status page in the portal shows: the state of the website, portal, web API, developer docs and MCP server, checked every minute from the GAMPEON server, with 90 days of daily history, incidents of the last 7 days and the community game servers that are online.\n\nThe checks run on the same server as the services. When that whole server is down, there is no data for that time, except for the web API, where missing minutes count as down. Answers are cached for 15 seconds.\n\nRate limit: 120 per minute per IP.","security":[],"responses":{"200":{"description":"Current status","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["operational","degraded","outage","unknown"],"description":"Summary over all services"},"monitoring":{"type":"boolean","description":"`false`: this API instance does not run checks (local development), `services` is empty"},"updatedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Time of the latest check"},{"type":"null"}]},"intervalMs":{"type":"integer","description":"How often the services are checked"},"services":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["website","portal","api","docs","mcp"]},"name":{"type":"string"},"description":{"type":"string"},"link":{"type":"string","description":"Page for people","format":"uri"},"state":{"type":"string","enum":["up","degraded","down","unknown"],"description":"`unknown`: no check in the last 3 minutes. A single failed check shows as `degraded`, two in a row as `down`."},"note":{"oneOf":[{"type":"string","description":"Short reason when not up, e.g. `Timed out`, `HTTP 502`, `Docs not loaded`"},{"type":"null"}]},"ms":{"oneOf":[{"type":"integer","description":"Response time of the latest check in milliseconds"},{"type":"null"}]},"checkedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Time of the latest check"},{"type":"null"}]},"uptime":{"type":"object","properties":{"day":{"oneOf":[{"type":"number","description":"Availability in percent (degraded counts as available), `null` without data"},{"type":"null"}]},"week":{"oneOf":[{"type":"number","description":"Availability in percent (degraded counts as available), `null` without data"},{"type":"null"}]},"days90":{"oneOf":[{"type":"number","description":"Availability in percent (degraded counts as available), `null` without data"},{"type":"null"}]}},"required":["day","week","days90"]},"days":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string","description":"UTC day `YYYY-MM-DD`"},"up":{"type":"integer","description":"Minutes up"},"degraded":{"type":"integer","description":"Minutes degraded"},"down":{"type":"integer","description":"Minutes down"}},"required":["day","up","degraded","down"]},"description":"90 days, oldest first. All zero: no data that day."}},"required":["id","name","description","link","state","note","ms","checkedAt","uptime","days"]}},"games":{"type":"object","properties":{"servers":{"type":"integer","description":"Community game servers online (heartbeat in the last 90 seconds)"},"players":{"type":"integer","description":"Players on those servers"},"top":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"players":{"type":"integer"},"maxPlayers":{"type":"integer"}},"required":["id","name","players","maxPlayers"]},"description":"Up to 5 servers with the most players"},"history":{"type":"array","items":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Start of the 15-minute step"},"players":{"type":"integer","description":"Most players in that step"},"servers":{"type":"integer"}},"required":["at","players","servers"]},"description":"Last 24 hours"}},"required":["servers","players","top","history"]},"incidents":{"type":"array","items":{"type":"object","properties":{"service":{"type":"string"},"name":{"type":"string"},"state":{"type":"string","enum":["degraded","down"]},"from":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"to":{"oneOf":[{"type":"integer","format":"int64","description":"`null`: still ongoing"},{"type":"null"}]},"minutes":{"type":"integer"},"note":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["service","name","state","from","to","minutes","note"]},"description":"Disruptions of 2 minutes or longer in the last 7 days, newest first (up to 20)"}},"required":["status","monitoring","updatedAt","intervalMs","services","games","incidents"]}}}},"429":{"description":"Limit: 120 per minute per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"120 per minute per IP"}},"/v1/communities":{"get":{"operationId":"listCommunities","tags":["Communities"],"summary":"Discover communities","description":"Open communities of published studios and projects, most members first (up to 50). Accounts under 16 do not see communities for 16+. With login, `joined` says whether you are a member.\n\nNot available with access tokens.","parameters":[{"name":"q","in":"query","required":false,"description":"Search in name and description","schema":{"type":"string","maxLength":64}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Communities","content":{"application/json":{"schema":{"type":"object","properties":{"communities":{"type":"array","items":{"allOf":[{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"description":{"type":"string"},"icon":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/` (studio logo or project key art)"},{"type":"null"}]},"cover":{"oneOf":[{"type":"string","description":"Banner image under `/v1/media/`: the cover of the studio or the project. `null` if there is none"},{"type":"null"}]},"owner":{"type":"object","properties":{"type":{"type":"string","enum":["studio","project"]},"slug":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},"name":{"type":"string"}},"required":["type","slug","name"]},"joinMode":{"type":"string","enum":["open","invite"],"description":"`open`: anyone who meets the minimum age can join. `invite`: only with an invite link"},"minAge":{"type":"integer","description":"13 or 16. Communities for 18+ come only with real age verification"},"members":{"type":"integer"},"players":{"type":"integer","description":"Players online right now on servers of the project (or of all projects of the studio)"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","name","description","icon","cover","owner","joinMode","minAge","members","players","createdAt"]},{"type":"object","properties":{"joined":{"type":"boolean"}},"required":["joined"]}]}}},"required":["communities"]}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"},"post":{"operationId":"createCommunity","tags":["Communities"],"summary":"Turn on the community of a studio or project","description":"Optional for every studio and project, at most one each. Studio owners and admins, or people who can edit the project. Starts with the roles `everyone` and `Moderator`, the categories Information (#welcome, #announcements, read-only) and Chat (#general, #help). Managers of the studio or project always have every permission and are members automatically.\n\nNot available with access tokens.\n\nRate limit: 5 per hour per account.","security":[{"session":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"}},"required":["id"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `studio_hidden`, `project_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `studio_not_found`, `project_not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `community_exists`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 5 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"5 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"studio":{"type":"string","description":"Studio slug","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},"project":{"type":"string","description":"Project slug","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},"joinMode":{"type":"string","enum":["open","invite"]},"description":{"type":"string","maxLength":500}},"required":[]}}}}}},"/v1/me/communities":{"get":{"operationId":"listMyCommunities","tags":["Communities"],"summary":"Your communities","description":"Communities you joined plus those of studios and projects you manage, oldest first, with `unread` and `mentions` over the channels you can see. `manageable` lists studios and projects you manage and their community ID (or `null`), for a create button. Poll every 30 seconds at most until real-time updates arrive.\n\nNot available with access tokens.","security":[{"session":[]}],"responses":{"200":{"description":"Communities","content":{"application/json":{"schema":{"type":"object","properties":{"communities":{"type":"array","items":{"allOf":[{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"description":{"type":"string"},"icon":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/` (studio logo or project key art)"},{"type":"null"}]},"cover":{"oneOf":[{"type":"string","description":"Banner image under `/v1/media/`: the cover of the studio or the project. `null` if there is none"},{"type":"null"}]},"owner":{"type":"object","properties":{"type":{"type":"string","enum":["studio","project"]},"slug":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},"name":{"type":"string"}},"required":["type","slug","name"]},"joinMode":{"type":"string","enum":["open","invite"],"description":"`open`: anyone who meets the minimum age can join. `invite`: only with an invite link"},"minAge":{"type":"integer","description":"13 or 16. Communities for 18+ come only with real age verification"},"members":{"type":"integer"},"players":{"type":"integer","description":"Players online right now on servers of the project (or of all projects of the studio)"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","name","description","icon","cover","owner","joinMode","minAge","members","players","createdAt"]},{"type":"object","properties":{"admin":{"type":"boolean"},"hidden":{"type":"boolean","description":"Hidden by GAMPEON or the studio or project is hidden"},"unread":{"type":"boolean"},"mentions":{"type":"integer"}},"required":["admin","hidden","unread","mentions"]}]}},"manageable":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["studio","project"]},"slug":{"type":"string"},"name":{"type":"string"},"icon":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/` (studio logo or project key art)"},{"type":"null"}]},"community":{"oneOf":[{"type":"integer"},{"type":"null"}]}},"required":["type","slug","name","icon","community"]}}},"required":["communities","manageable"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/communities/{id}":{"get":{"operationId":"getCommunity","tags":["Communities"],"summary":"A community","description":"Without membership only a preview of open communities. Members also get `me` (their permissions in the community, roles, timeout), the channels they can see with their permissions and unread state, and all roles. `permissions` are bitmasks, see `BITMASK` in the role schema.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{},{"session":[]}],"responses":{"200":{"description":"Community","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"description":{"type":"string"},"icon":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/` (studio logo or project key art)"},{"type":"null"}]},"cover":{"oneOf":[{"type":"string","description":"Banner image under `/v1/media/`: the cover of the studio or the project. `null` if there is none"},{"type":"null"}]},"owner":{"type":"object","properties":{"type":{"type":"string","enum":["studio","project"]},"slug":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},"name":{"type":"string"}},"required":["type","slug","name"]},"joinMode":{"type":"string","enum":["open","invite"],"description":"`open`: anyone who meets the minimum age can join. `invite`: only with an invite link"},"minAge":{"type":"integer","description":"13 or 16. Communities for 18+ come only with real age verification"},"members":{"type":"integer"},"players":{"type":"integer","description":"Players online right now on servers of the project (or of all projects of the studio)"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","name","description","icon","cover","owner","joinMode","minAge","members","players","createdAt"]},{"type":"object","properties":{"rules":{"type":"string"},"member":{"type":"boolean"},"banned":{"type":"boolean"},"hidden":{"oneOf":[{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"type":"string"}},"required":["at","reason"]},{"type":"null"}]},"servers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"players":{"type":"integer"},"maxPlayers":{"type":"integer"},"project":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"}},"required":["slug","title"]}},"required":["id","name","players","maxPlayers","project"]},"description":"Online servers, most players first (up to 10)"},"me":{"type":"object","properties":{"permissions":{"type":"integer","description":"Bitmask of permissions, see the table in the Communities section","minimum":0},"admin":{"type":"boolean"},"owner":{"type":"boolean"},"team":{"type":"boolean"},"roles":{"type":"array","items":{"type":"integer"}},"timeoutUntil":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"top":{"oneOf":[{"type":"integer","description":"Your highest role position, `null` for managers"},{"type":"null"}]}},"required":["permissions","admin","owner","team","roles","timeoutUntil","top"]},"channels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"kind":{"type":"string","enum":["category","text","announcement","voice"]},"name":{"type":"string"},"topic":{"type":"string"},"parentId":{"oneOf":[{"type":"integer","description":"Category"},{"type":"null"}]},"position":{"type":"integer"},"slowmode":{"type":"integer","description":"Seconds between two messages of the same person. 0 is off"},"permissions":{"type":"integer","description":"Your effective permissions in this channel (see `permissions` on the community)"},"lastMessageId":{"type":"integer"},"unread":{"type":"boolean"},"mentions":{"type":"integer","description":"Unread messages that mention you"},"userLimit":{"type":"integer","description":"Only voice channels: most people at once, 0 is no limit of the community"},"overrides":{"type":"array","items":{"type":"object","properties":{"roleId":{"type":"integer"},"allow":{"type":"integer","description":"Bits allowed in this channel"},"deny":{"type":"integer","description":"Bits denied in this channel"}},"required":["roleId","allow","deny"]},"description":"Only with `manageChannels`"}},"required":["id","kind","name","topic","parentId","position","slowmode","permissions","lastMessageId","unread","mentions"]}},"roles":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"color":{"oneOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"null"}]},"position":{"type":"integer","description":"Higher is more powerful. `everyone` is always 0"},"permissions":{"type":"integer","description":"Bitmask of permissions, see the table in the Communities section","minimum":0},"hoist":{"type":"boolean","description":"Shown as its own group in the member list"},"everyone":{"type":"boolean","description":"The default role every member has"},"members":{"type":"integer"}},"required":["id","name","color","position","permissions","hoist","everyone","members"]}}},"required":["rules","member","banned","hidden","servers"]}]}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"optional"},"patch":{"operationId":"updateCommunity","tags":["Communities"],"summary":"Change a community","description":"Needs `manageCommunity`.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Changed fields","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"array","items":{"type":"string"}}},"required":["updated"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`, `community_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":48},"description":{"type":"string","maxLength":500},"rules":{"type":"string","description":"Shown before joining. People must accept them to join","maxLength":2000},"joinMode":{"type":"string","enum":["open","invite"]},"minAge":{"type":"integer","enum":[13,16],"description":"Accounts under 16 cannot join or see communities for 16+"}},"required":[]}}}}},"delete":{"operationId":"deleteCommunity","tags":["Communities"],"summary":"Delete a community","description":"Only the owner of the studio or project. Deletes all channels, roles and messages. Copies in reports to GAMPEON stay.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/communities/{id}/members":{"post":{"operationId":"joinCommunity","tags":["Communities"],"summary":"Join an open community","description":"For `invite` communities use `POST /v1/community-invites/:code`. Messages from before joining count as read.\n\nNot available with access tokens.\n\nRate limit: 20 joins per hour per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Joined (200 if you already were a member)","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"joined":{"const":true}},"required":["id","joined"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `banned`, `age_restricted`, `invite_required`, `community_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `rules_not_accepted`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 20 joins per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"20 joins per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"acceptRules":{"const":true,"description":"Required when the community has rules"}},"required":[]}}}}},"get":{"operationId":"listCommunityMembers","tags":["Communities"],"summary":"Members","description":"Members only. Up to 1000, by display name. Online status comes with real-time updates.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"object","properties":{"members":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/` (studio logo or project key art)"},{"type":"null"}]},"joinedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"roles":{"type":"array","items":{"type":"integer"}},"admin":{"type":"boolean","description":"Manages the studio or project: has every permission, cannot be kicked, banned or timed out"},"team":{"type":"boolean","description":"Member of the studio or project team. Shown as a Team badge so nobody can pretend to be the team"},"owner":{"type":"boolean"},"timeoutUntil":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["handle","displayName","avatar","joinedAt","roles","admin","team","owner","timeoutUntil"]}},"total":{"type":"integer"}},"required":["members","total"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/communities/{id}/members/{handle}":{"patch":{"operationId":"updateCommunityMember","tags":["Communities"],"summary":"Change roles or time out a member","description":"`roles` (all role IDs the member should have, without `everyone`) needs `manageRoles`; you can only add or remove roles below your highest role. `timeoutMinutes` needs `timeoutMembers` and a highest role above theirs; 0 ends the timeout. Timed out members can only read. The person gets a notification with the reason.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"handle","in":"path","required":true,"description":"Handle of the member","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"200":{"description":"What changed","content":{"application/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","items":{"type":"integer"}},"timeoutUntil":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":[]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`, `role_hierarchy`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","items":{"type":"integer"}},"timeoutMinutes":{"type":"integer","minimum":0,"maximum":10080},"reason":{"type":"string","description":"Optional reason, shown to the person affected","maxLength":300}},"required":[]}}}}},"delete":{"operationId":"removeCommunityMember","tags":["Communities"],"summary":"Leave, or kick a member","description":"Your own handle: leave. Another handle: kick (needs `kickMembers` and a highest role above theirs). Kicked people can join again. Optional JSON body `{reason}` for the notification.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"handle","in":"path","required":true,"description":"Handle of the member","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Removed"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`, `role_hierarchy`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/communities/{id}/bans":{"get":{"operationId":"listCommunityBans","tags":["Communities"],"summary":"Bans","description":"Needs `banMembers`.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Up to 500, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"bans":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"reason":{"type":"string"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"bannedBy":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["handle","displayName","reason","createdAt","bannedBy"]}}},"required":["bans"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"},"post":{"operationId":"banCommunityMember","tags":["Communities"],"summary":"Ban someone","description":"Needs `banMembers` and a highest role above theirs. Removes them and blocks joining again, also with invites. `deleteMessagesHours` removes their messages of the last 1, 24 or 168 hours.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Banned","content":{"application/json":{"schema":{"type":"object","properties":{"banned":{"type":"string"}},"required":["banned"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`, `role_hierarchy`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"reason":{"type":"string","description":"Optional reason, shown to the person affected","maxLength":300},"deleteMessagesHours":{"type":"integer","description":"0, 1, 24 or 168"}},"required":["handle"]}}}}}},"/v1/communities/{id}/bans/{handle}":{"delete":{"operationId":"unbanCommunityMember","tags":["Communities"],"summary":"Lift a ban","description":"Needs `banMembers`.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"handle","in":"path","required":true,"description":"Handle of the member","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Lifted"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/communities/{id}/roles":{"post":{"operationId":"createCommunityRole","tags":["Communities"],"summary":"Create a role","description":"Needs `manageRoles`. New roles start at the bottom (position 1) with the permissions of `everyone`. You can only grant permissions you have. Up to 50 roles.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"color":{"oneOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"null"}]},"position":{"type":"integer","description":"Higher is more powerful. `everyone` is always 0"},"permissions":{"type":"integer","description":"Bitmask of permissions, see the table in the Communities section","minimum":0},"hoist":{"type":"boolean","description":"Shown as its own group in the member list"},"everyone":{"type":"boolean","description":"The default role every member has"},"members":{"type":"integer"}},"required":["id","name","color","position","permissions","hoist","everyone","members"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `role_limit_reached`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":32},"color":{"oneOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"null"}]},"permissions":{"type":"integer","description":"Bitmask of permissions, see the table in the Communities section","minimum":0},"hoist":{"type":"boolean"}},"required":["name"]}}}}}},"/v1/communities/{id}/roles/{roleId}":{"patch":{"operationId":"updateCommunityRole","tags":["Communities"],"summary":"Change a role","description":"Needs `manageRoles`, and the role must be below your highest role (except `everyone`). `position` moves it (1 is just above `everyone`); only below your highest role.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"roleId","in":"path","required":true,"description":"Role ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Role","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"color":{"oneOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"null"}]},"position":{"type":"integer","description":"Higher is more powerful. `everyone` is always 0"},"permissions":{"type":"integer","description":"Bitmask of permissions, see the table in the Communities section","minimum":0},"hoist":{"type":"boolean","description":"Shown as its own group in the member list"},"everyone":{"type":"boolean","description":"The default role every member has"},"members":{"type":"integer"}},"required":["id","name","color","position","permissions","hoist","everyone","members"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`, `role_hierarchy`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":32},"color":{"oneOf":[{"type":"string"},{"type":"null"}]},"permissions":{"type":"integer","description":"Bitmask of permissions, see the table in the Communities section","minimum":0},"hoist":{"type":"boolean"},"position":{"type":"integer","minimum":1}},"required":[]}}}}},"delete":{"operationId":"deleteCommunityRole","tags":["Communities"],"summary":"Delete a role","description":"Needs `manageRoles`, only roles below your highest role. `everyone` cannot be deleted.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"roleId","in":"path","required":true,"description":"Role ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`, `role_hierarchy`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/communities/{id}/channels":{"post":{"operationId":"createCommunityChannel","tags":["Communities"],"summary":"Create a channel or category","description":"Needs `manageChannels`. Text channel names are lowercase (spaces become `-`). Channels inherit the overrides of their category, then apply their own. Announcement channels start read-only for `everyone`. Voice channels have no messages; `userLimit` caps how many people can be in one at once. Only `viewChannels`, `sendMessages`, `manageMessages`, `connect`, `speak`, `stream` can be set per channel. Up to 100 channels.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"}},"required":["id"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `channel_limit_reached`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["category","text","announcement","voice"]},"name":{"type":"string","minLength":1,"maxLength":32},"topic":{"type":"string","maxLength":300},"parentId":{"oneOf":[{"type":"integer","description":"Category ID"},{"type":"null"}]},"overrides":{"type":"array","items":{"type":"object","properties":{"roleId":{"type":"integer"},"allow":{"type":"integer","description":"Bits allowed in this channel"},"deny":{"type":"integer","description":"Bits denied in this channel"}},"required":["roleId","allow","deny"]}},"userLimit":{"type":"integer","description":"Only voice channels. 0 is no limit","minimum":0,"maximum":99}},"required":["kind","name"]}}}}}},"/v1/communities/{id}/channels/{channelId}":{"patch":{"operationId":"updateCommunityChannel","tags":["Communities"],"summary":"Change a channel","description":"Needs `manageChannels`. `overrides` replaces all overrides of the channel. `position` is the index in the full channel list (categories included).\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"channelId","in":"path","required":true,"description":"Channel ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Changed fields","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"array","items":{"type":"string"}}},"required":["updated"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"topic":{"type":"string","maxLength":300},"slowmode":{"type":"integer","minimum":0,"maximum":21600},"parentId":{"oneOf":[{"type":"integer"},{"type":"null"}]},"overrides":{"type":"array","items":{"type":"object","properties":{"roleId":{"type":"integer"},"allow":{"type":"integer","description":"Bits allowed in this channel"},"deny":{"type":"integer","description":"Bits denied in this channel"}},"required":["roleId","allow","deny"]}},"position":{"type":"integer","minimum":0},"userLimit":{"type":"integer","description":"Only voice channels. 0 is no limit","minimum":0,"maximum":99}},"required":[]}}}}},"delete":{"operationId":"deleteCommunityChannel","tags":["Communities"],"summary":"Delete a channel","description":"Needs `manageChannels`. Deletes its messages. Channels in a deleted category move out of it.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"channelId","in":"path","required":true,"description":"Channel ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/communities/{id}/channels/{channelId}/messages":{"get":{"operationId":"listChannelMessages","tags":["Communities"],"summary":"Messages of a channel","description":"Without parameters the newest page (oldest first inside the page); `before` loads older pages. For updates, poll every 2 to 5 seconds with `updatedSince` set to `now` from the previous answer: you get new, edited and removed messages since then (removed ones as placeholders). Slow down or stop polling while the window is hidden.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"channelId","in":"path","required":true,"description":"Channel ID","schema":{"type":"integer","minimum":1}},{"name":"before","in":"query","required":false,"description":"Message ID: only older messages","schema":{"type":"integer","minimum":1}},{"name":"updatedSince","in":"query","required":false,"description":"Time from `now` of the last answer","schema":{"type":"integer","minimum":0}},{"name":"limit","in":"query","required":false,"description":"1 to 100 (default 50)","schema":{"type":"integer","minimum":1,"maximum":100}}],"security":[{"session":[]}],"responses":{"200":{"description":"Messages","content":{"application/json":{"schema":{"type":"object","properties":{"messages":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"integer"},"channelId":{"type":"integer"},"author":{"oneOf":[{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/` (studio logo or project key art)"},{"type":"null"}]}},"required":["handle","displayName","avatar"]},{"type":"null"}]},"body":{"type":"string"},"replyTo":{"oneOf":[{"oneOf":[{"type":"object","properties":{"id":{"type":"integer"},"author":{"oneOf":[{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"}},"required":["handle","displayName"]},{"type":"null"}]},"excerpt":{"type":"string"}},"required":["id","author","excerpt"]},{"type":"object","properties":{"id":{"type":"integer"},"removed":{"const":true}},"required":["id","removed"]}]},{"type":"null"}]},"mentions":{"type":"array","items":{"type":"string"},"description":"Handles mentioned with @"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"editedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["id","channelId","author","body","replyTo","mentions","createdAt","updatedAt","editedAt"]},{"type":"object","properties":{"id":{"type":"integer"},"channelId":{"type":"integer"},"removed":{"const":true},"removedBy":{"type":"string","enum":["author","community","platform"],"description":"Deleted by the author, removed by community moderators or by GAMPEON"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","channelId","removed","removedBy","createdAt","updatedAt"]}]}},"hasMore":{"type":"boolean"},"now":{"type":"integer","format":"int64","description":"Server time, use it for the next `updatedSince`"}},"required":["messages","hasMore","now"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"},"post":{"operationId":"sendChannelMessage","tags":["Communities"],"summary":"Send a message","description":"Needs `sendMessages` in the channel and no timeout. Up to 2000 characters and 5 links. `@handle` mentions members who can see the channel. Slow mode applies unless you have `manageMessages`.\n\nNot available with access tokens.\n\nRate limit: 10 per 10 seconds and 600 per hour per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"channelId","in":"path","required":true,"description":"Channel ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Sent","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"id":{"type":"integer"},"channelId":{"type":"integer"},"author":{"oneOf":[{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/` (studio logo or project key art)"},{"type":"null"}]}},"required":["handle","displayName","avatar"]},{"type":"null"}]},"body":{"type":"string"},"replyTo":{"oneOf":[{"oneOf":[{"type":"object","properties":{"id":{"type":"integer"},"author":{"oneOf":[{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"}},"required":["handle","displayName"]},{"type":"null"}]},"excerpt":{"type":"string"}},"required":["id","author","excerpt"]},{"type":"object","properties":{"id":{"type":"integer"},"removed":{"const":true}},"required":["id","removed"]}]},{"type":"null"}]},"mentions":{"type":"array","items":{"type":"string"},"description":"Handles mentioned with @"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"editedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["id","channelId","author","body","replyTo","mentions","createdAt","updatedAt","editedAt"]},{"type":"object","properties":{"id":{"type":"integer"},"channelId":{"type":"integer"},"removed":{"const":true},"removedBy":{"type":"string","enum":["author","community","platform"],"description":"Deleted by the author, removed by community moderators or by GAMPEON"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","channelId","removed","removedBy","createdAt","updatedAt"]}]}}}},"400":{"description":"Error codes: `invalid_field`, `too_many_links`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`, `timed_out`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per 10 seconds and 600 per hour per account. Error codes: `rate_limited`, `slowmode`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"10 per 10 seconds and 600 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":2000},"replyTo":{"oneOf":[{"type":"integer","description":"Message ID in the same channel"},{"type":"null"}]}},"required":["body"]}}}}}},"/v1/communities/{id}/channels/{channelId}/read":{"post":{"operationId":"markChannelRead","tags":["Communities"],"summary":"Mark a channel as read","description":"Up to `messageId` (default: the newest message). Never moves backwards.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"channelId","in":"path","required":true,"description":"Channel ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Read state","content":{"application/json":{"schema":{"type":"object","properties":{"lastReadId":{"type":"integer"}},"required":["lastReadId"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"messageId":{"type":"integer","minimum":0}},"required":[]}}}}}},"/v1/communities/{id}/messages/{messageId}":{"patch":{"operationId":"editChannelMessage","tags":["Communities"],"summary":"Edit your message","description":"Not available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"messageId","in":"path","required":true,"description":"Message ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Message","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"id":{"type":"integer"},"channelId":{"type":"integer"},"author":{"oneOf":[{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/` (studio logo or project key art)"},{"type":"null"}]}},"required":["handle","displayName","avatar"]},{"type":"null"}]},"body":{"type":"string"},"replyTo":{"oneOf":[{"oneOf":[{"type":"object","properties":{"id":{"type":"integer"},"author":{"oneOf":[{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"}},"required":["handle","displayName"]},{"type":"null"}]},"excerpt":{"type":"string"}},"required":["id","author","excerpt"]},{"type":"object","properties":{"id":{"type":"integer"},"removed":{"const":true}},"required":["id","removed"]}]},{"type":"null"}]},"mentions":{"type":"array","items":{"type":"string"},"description":"Handles mentioned with @"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"editedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["id","channelId","author","body","replyTo","mentions","createdAt","updatedAt","editedAt"]},{"type":"object","properties":{"id":{"type":"integer"},"channelId":{"type":"integer"},"removed":{"const":true},"removedBy":{"type":"string","enum":["author","community","platform"],"description":"Deleted by the author, removed by community moderators or by GAMPEON"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","channelId","removed","removedBy","createdAt","updatedAt"]}]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `forbidden`, `timed_out`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":2000}},"required":["body"]}}}}},"delete":{"operationId":"deleteChannelMessage","tags":["Communities"],"summary":"Delete or remove a message","description":"Your own: deleted right away (a placeholder stays). Others: needs `manageMessages` in the channel; the author gets a notification with the optional reason (JSON body `{reason}`). Messages of studio or project managers can only be removed by other managers or GAMPEON. The text of removed messages is deleted after 30 days unless a report is open.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"messageId","in":"path","required":true,"description":"Message ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"204":{"description":"Removed"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/communities/{id}/invites":{"post":{"operationId":"createCommunityInvite","tags":["Communities"],"summary":"Create an invite link","description":"Needs `createInvites`. Links last 1 to 30 days (default 7). `maxUses` 0 means no limit. Share `https://gampeon.com/invite/<code>` once the launcher handles invite links.\n\nNot available with access tokens.\n\nRate limit: 20 per hour per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Invite","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"maxUses":{"type":"integer"},"uses":{"type":"integer"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["code","maxUses","uses","expiresAt"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `invite_limit_reached`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 20 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"20 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"maxUses":{"type":"integer","minimum":0,"maximum":1000},"expiresInDays":{"type":"integer","minimum":1,"maximum":30}},"required":[]}}}}},"get":{"operationId":"listCommunityInvites","tags":["Communities"],"summary":"Active invite links","description":"All of them with `manageCommunity`, otherwise your own.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Invites","content":{"application/json":{"schema":{"type":"object","properties":{"invites":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"maxUses":{"type":"integer"},"uses":{"type":"integer"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"createdBy":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["code","maxUses","uses","expiresAt","createdAt","createdBy"]}}},"required":["invites"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/communities/{id}/invites/{code}":{"delete":{"operationId":"deleteCommunityInvite","tags":["Communities"],"summary":"Revoke an invite link","description":"Your own, or any with `manageCommunity`.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"code","in":"path","required":true,"description":"Invite code","schema":{"type":"string","pattern":"^[A-Za-z0-9]{8}$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Revoked"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/community-invites/{code}":{"get":{"operationId":"getCommunityInvite","tags":["Communities"],"summary":"Preview an invite","description":"Name, icon, members and rules of the community behind an invite link.\n\nRate limit: 60 per hour per IP.","parameters":[{"name":"code","in":"path","required":true,"description":"Invite code","schema":{"type":"string","pattern":"^[A-Za-z0-9]{8}$"}}],"security":[],"responses":{"200":{"description":"Invite","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"community":{"allOf":[{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"description":{"type":"string"},"icon":{"oneOf":[{"type":"string","description":"Image path under `/v1/media/` (studio logo or project key art)"},{"type":"null"}]},"cover":{"oneOf":[{"type":"string","description":"Banner image under `/v1/media/`: the cover of the studio or the project. `null` if there is none"},{"type":"null"}]},"owner":{"type":"object","properties":{"type":{"type":"string","enum":["studio","project"]},"slug":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},"name":{"type":"string"}},"required":["type","slug","name"]},"joinMode":{"type":"string","enum":["open","invite"],"description":"`open`: anyone who meets the minimum age can join. `invite`: only with an invite link"},"minAge":{"type":"integer","description":"13 or 16. Communities for 18+ come only with real age verification"},"members":{"type":"integer"},"players":{"type":"integer","description":"Players online right now on servers of the project (or of all projects of the studio)"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","name","description","icon","cover","owner","joinMode","minAge","members","players","createdAt"]},{"type":"object","properties":{"rules":{"type":"string"}},"required":["rules"]}]}},"required":["code","expiresAt","community"]}}}},"404":{"description":"Error codes: `invite_invalid`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 60 per hour per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"60 per hour per IP"},"post":{"operationId":"acceptCommunityInvite","tags":["Communities"],"summary":"Join with an invite","description":"Same rules as joining an open community: not banned, minimum age, rules accepted.\n\nNot available with access tokens.","parameters":[{"name":"code","in":"path","required":true,"description":"Invite code","schema":{"type":"string","pattern":"^[A-Za-z0-9]{8}$"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Joined (200 if you already were a member)","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"joined":{"const":true}},"required":["id","joined"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `banned`, `age_restricted`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `invite_invalid`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `rules_not_accepted`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"acceptRules":{"const":true,"description":"Required when the community has rules"}},"required":[]}}}}}},"/v1/communities/{id}/audit-log":{"get":{"operationId":"getCommunityAuditLog","tags":["Communities"],"summary":"Audit log","description":"Needs `viewAuditLog`. The last 200 changes: settings, channels, roles, kicks, bans, timeouts, removed messages, invites.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Entries, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"action":{"type":"string"},"target":{"type":"string"},"detail":{"type":"object","additionalProperties":{}},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"actor":{"oneOf":[{"type":"string"},{"type":"null"}]},"actorName":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","action","target","detail","createdAt","actor","actorName"]}}},"required":["entries"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/communities/{id}/messages/{messageId}/reports":{"post":{"operationId":"reportChannelMessage","tags":["Reports and moderation"],"summary":"Report a message to GAMPEON","description":"For illegal content or breaks of the GAMPEON terms (Art. 16 DSA), separate from the moderators of the community. GAMPEON keeps a copy of the message and the three before it. You get a confirmation and the result.\n\nNot available with access tokens.\n\nRate limit: 10 per hour per IP.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"messageId","in":"path","required":true,"description":"Message ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Report received (200 if you already reported it)","content":{"application/json":{"schema":{"type":"object","properties":{"reportId":{"type":"string"},"status":{"const":"open"}},"required":["reportId","status"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `good_faith_confirmation_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"10 per hour per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"string","enum":["illegal_content","harassment","hate_speech","violence_threat","child_safety","spam","copyright","other"]},"explanation":{"type":"string","minLength":20,"maxLength":5000},"reporterName":{"type":"string","description":"Defaults to your display name","maxLength":120},"reporterEmail":{"type":"string","description":"Defaults to your email address","format":"email","maxLength":254},"anonymous":{"type":"boolean","description":"Only for `child_safety`: report without name and email"},"goodFaith":{"const":true,"description":"Confirms the report is made in good faith"}},"required":["category","explanation","goodFaith"]}}}}}},"/v1/moderation/community-reports":{"get":{"operationId":"listCommunityReports","tags":["Reports and moderation"],"summary":"Reports on community messages","description":"Urgent categories (`child_safety`, `violence_threat`) first (Art. 18 DSA).\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"status","in":"query","required":false,"description":"Default `open`","schema":{"type":"string","enum":["open","actioned","rejected"]}}],"security":[{"session":[]}],"responses":{"200":{"description":"Up to 200","content":{"application/json":{"schema":{"type":"object","properties":{"reports":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["message","voice"],"description":"`voice`: a person in a voice channel; `context` lists who was there"},"messageId":{"oneOf":[{"type":"integer"},{"type":"null"}]},"communityId":{"oneOf":[{"type":"integer"},{"type":"null"}]},"community":{"oneOf":[{"type":"string"},{"type":"null"}]},"snapshot":{"type":"string"},"context":{"type":"string","description":"Community, channel and the three messages before"},"category":{"type":"string"},"explanation":{"type":"string"},"reporterName":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"authorHandle":{"oneOf":[{"type":"string"},{"type":"null"}]},"authorName":{"oneOf":[{"type":"string"},{"type":"null"}]},"removedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"deleted":{"type":"boolean"},"urgent":{"type":"boolean"}},"required":["id","kind","messageId","communityId","community","snapshot","context","category","explanation","reporterName","status","createdAt","authorHandle","authorName","removedAt","deleted","urgent"]}}},"required":["reports"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator"}},"/v1/moderation/community-reports/{id}/decision":{"post":{"operationId":"decideCommunityReport","tags":["Reports and moderation"],"summary":"Decide a report on a message","description":"`remove` hides the message for everyone and sends the statement of reasons to the author (Art. 17 DSA); all open reports on it close. For voice reports there is nothing to remove: `remove` marks the report as actioned. Reporters get the result.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Report ID","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string"},"action":{"type":"string"}},"required":["decisionId","action"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `already_decided`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["remove","reject"]},"statementOfReasons":{"type":"string","description":"Statement of reasons, shown to the people affected (Art. 17 DSA)","minLength":20,"maxLength":5000},"legalGround":{"type":"string","maxLength":500}},"required":["action","statementOfReasons"]}}}}}},"/v1/moderation/communities/{id}/decision":{"post":{"operationId":"decideCommunity","tags":["Reports and moderation"],"summary":"Hide or restore a community","description":"For communities that break the terms as a whole. Managers of the studio or project get the statement of reasons.\n\nRequires the role moderator or admin.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string"},"action":{"type":"string"}},"required":["decisionId","action"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `forbidden`, `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"moderator","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["hide","restore"]},"statementOfReasons":{"type":"string","description":"Statement of reasons, shown to the people affected (Art. 17 DSA)","minLength":20,"maxLength":5000},"legalGround":{"type":"string","maxLength":500}},"required":["action","statementOfReasons"]}}}}}},"/v1/communities/{id}/channels/{channelId}/voice":{"post":{"operationId":"joinVoiceChannel","tags":["Voice"],"summary":"Join a voice channel","description":"Needs `connect` in the channel, no timeout and an age of 16 or older. Returns the address of the voice server and a token for this channel only, valid for 10 minutes to connect (LiveKit keeps the connection alive after that). The token allows the microphone only with `speak` (and when not muted by moderators) and screen sharing with sound only with `stream`. You can be in one voice channel at a time: joining another one disconnects you from the first. Full channels (`userLimit`) can only be joined with `moveMembers`; at most 100 people per channel.\n\nNot available with access tokens.\n\nRate limit: 30 per 10 minutes per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"channelId","in":"path","required":true,"description":"Channel ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Token","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"WebSocket address of the voice server"},"token":{"type":"string","description":"Access token for the voice server"},"room":{"type":"string"},"identity":{"type":"string","description":"Your random ID on the voice server"},"expiresAt":{"type":"integer","format":"int64","description":"Connect before this"},"permissions":{"type":"integer","description":"Your permissions in this channel"},"muted":{"type":"boolean","description":"Muted by moderators of the community"},"canSpeak":{"type":"boolean"},"canStream":{"type":"boolean"}},"required":["url","token","room","identity","expiresAt","permissions","muted","canSpeak","canStream"]}}}},"400":{"description":"Error codes: `not_a_voice_channel`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `age_restricted`, `timed_out`, `missing_permission`, `banned`, `community_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `channel_full`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per 10 minutes per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `voice_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 per 10 minutes per account"}},"/v1/communities/{id}/voice":{"get":{"operationId":"getCommunityVoice","tags":["Voice"],"summary":"Who is in which voice channel","description":"All voice channels you can see, with the people in them. `allowed` is false for accounts under 16 (`reason: age_restricted`): they see voice channels but cannot join. `enabled` is false while the voice server is not set up. Poll every 10 to 15 seconds at most until real-time updates arrive.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"200":{"description":"Voice channels","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"allowed":{"type":"boolean"},"reason":{"type":"string","enum":["age_restricted"]},"channels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"userLimit":{"type":"integer","description":"0 is no limit"},"participants":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string"},{"type":"null"}]},"joinedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"streaming":{"type":"boolean","description":"Sharing a screen right now"},"muted":{"type":"boolean","description":"Muted by moderators"},"team":{"type":"boolean","description":"Member of the studio or project team"}},"required":["handle","displayName","avatar","joinedAt","streaming","muted","team"]}}},"required":["id","userLimit","participants"]}}},"required":["enabled","allowed","channels"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/hooks/livekit":{"post":{"operationId":"livekitWebhook","tags":["Voice"],"summary":"Voice server webhook (called by LiveKit only)","description":"Signed with `Authorization: <JWT>` from the API key of the voice server, with the SHA-256 of the raw body. Handles `participant_joined`, `participant_left`, `track_published`, `track_unpublished` (screen sharing) and `room_finished`. Unknown participants are removed. Only active when voice is set up.","security":[],"responses":{"200":{"description":"Processed","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true}},"required":["ok"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `invalid_signature`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error codes: `body_too_large`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","description":"e.g. `participant_joined`"}},"required":["event"]}}}}}},"/v1/communities/{id}/voice/members/{handle}":{"patch":{"operationId":"muteVoiceMember","tags":["Voice"],"summary":"Mute or unmute a member in voice","description":"Needs `muteMembers`, and their highest role must be below yours. Applies to all voice channels of the community until someone lifts it. Muting turns their microphone off right away; after unmuting they turn it on themselves. In the audit log.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"handle","in":"path","required":true,"description":"Handle of the member","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Muted state","content":{"application/json":{"schema":{"type":"object","properties":{"muted":{"type":"boolean"}},"required":["muted"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`, `role_hierarchy`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"muted":{"type":"boolean"}},"required":["muted"]}}}}},"delete":{"operationId":"disconnectVoiceMember","tags":["Voice"],"summary":"Disconnect a member from voice","description":"Your own handle: leave voice. Someone else: needs `moveMembers`, and their highest role must be below yours. They can join again (time them out or kick them to stop that). In the audit log.\n\nNot available with access tokens.","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"handle","in":"path","required":true,"description":"Handle of the member","schema":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Disconnected"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `missing_permission`, `role_hierarchy`, `forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`, `not_in_voice`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/communities/{id}/channels/{channelId}/voice/reports":{"post":{"operationId":"reportVoiceMember","tags":["Reports and moderation"],"summary":"Report someone in a voice channel to GAMPEON","description":"For illegal behaviour or breaks of the GAMPEON terms in voice (Art. 16 DSA), separate from the moderators of the community. There are no recordings, so GAMPEON adds who was in the channel around `at` (from two hours before to 15 minutes after). Urgent categories come first. You get a confirmation and the result.\n\nNot available with access tokens.\n\nRate limit: 10 per hour per IP (shared with message reports).","parameters":[{"name":"id","in":"path","required":true,"description":"Community ID","schema":{"type":"integer","minimum":1}},{"name":"channelId","in":"path","required":true,"description":"Voice channel ID","schema":{"type":"integer","minimum":1}}],"security":[{"session":[]}],"responses":{"201":{"description":"Report received (200 if you reported them in the last hour already)","content":{"application/json":{"schema":{"type":"object","properties":{"reportId":{"type":"string"},"status":{"const":"open"}},"required":["reportId","status"]}}}},"400":{"description":"Error codes: `invalid_field`, `not_a_voice_channel`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `good_faith_confirmation_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 10 per hour per IP (shared with message reports). Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"10 per hour per IP (shared with message reports)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string","description":"The person you report","pattern":"^[a-z0-9_]{3,24}$"},"at":{"type":"integer","format":"int64","description":"When it happened (default: now), within the last 7 days"},"category":{"type":"string","enum":["illegal_content","harassment","hate_speech","violence_threat","child_safety","spam","copyright","other"]},"explanation":{"type":"string","description":"What happened","minLength":20,"maxLength":5000},"reporterName":{"type":"string","description":"Defaults to your display name","maxLength":120},"reporterEmail":{"type":"string","description":"Defaults to your email address","format":"email","maxLength":254},"anonymous":{"type":"boolean","description":"Only for `child_safety`: report without name and email"},"goodFaith":{"const":true,"description":"Confirms the report is made in good faith"}},"required":["handle","category","explanation","goodFaith"]}}}}}},"/v1/auth/launcher/approve":{"post":{"operationId":"approveLauncherSignIn","tags":["Accounts"],"summary":"Approve a sign-in for the launcher","description":"Called by the portal page that the launcher opens in the system browser, after you confirm that you want to sign in to the launcher. Returns a one-time code that the portal hands to the launcher with the link `gampeon://auth?code=…&state=…`. The code is valid for 2 minutes and only together with the secret `verifier` behind `challenge`, which never leaves the launcher (PKCE, RFC 7636, method `S256`).\n\nNot available with access tokens.\n\nRate limit: 20 per 15 minutes per account.","security":[{"session":[]}],"responses":{"201":{"description":"One-time code","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","description":"One-time code, 43 characters"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["code","expiresAt"]}}}},"400":{"description":"Error codes: `invalid_field`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 20 per 15 minutes per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"20 per 15 minutes per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"challenge":{"type":"string","description":"`BASE64URL(SHA-256(verifier))` without padding, 43 characters","pattern":"^[A-Za-z0-9_-]{43}$"}},"required":["challenge"]}}}}}},"/v1/auth/launcher/token":{"post":{"operationId":"completeLauncherSignIn","tags":["Accounts"],"summary":"Complete a sign-in in the launcher","description":"Exchanges the one-time code from `gampeon://auth` and the `verifier` for a session of its own (30 days). The code can be used once; a wrong `verifier` uses it up as well.\n\nRate limit: 30 per 15 minutes per IP.","security":[],"responses":{"201":{"description":"Session","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"Bearer token for the `Authorization` header"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["token","expiresAt"]}}}},"400":{"description":"Error codes: `invalid_field`, `invalid_code`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per 15 minutes per IP. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"30 per 15 minutes per IP","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","description":"One-time code from the portal","pattern":"^[A-Za-z0-9_-]{43}$"},"verifier":{"type":"string","description":"Random secret of 43 to 128 characters `A-Z a-z 0-9 - . _ ~` that the launcher created for this sign-in","pattern":"^[A-Za-z0-9._~-]{43,128}$"}},"required":["code","verifier"]}}}}}},"/v1/servers/{id}/join":{"post":{"operationId":"joinServer","tags":["Servers"],"summary":"Get a join token for a server","description":"The launcher calls this right before it starts the game client and passes the token to the client in the environment variable `GAMPEON_JOIN_TOKEN`. The client sends it to the game server when it connects, and the game server checks it with `POST /v1/servers/{id}/join/verify`. Valid for 10 minutes, once, and only for this server.\n\nIf the server runs game packages of its project, `packages` lists their files and `packageGrant` allows downloading them with `GET /v1/packages/files/{sha256}` for 60 minutes. The launcher downloads missing files, checks their SHA-256 and starts the client with them.\n\nNot available with access tokens.\n\nRate limit: 30 per 10 minutes per account.","parameters":[{"name":"id","in":"path","required":true,"description":"Server ID","schema":{"type":"string","format":"uuid"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Join token","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"Join token, 43 characters"},"address":{"type":"string","description":"Host name or IP of the server"},"port":{"type":"integer"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"packages":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"},"engine":{"type":"string","description":"GAMPEON version the package needs"},"size":{"type":"integer","description":"Bytes of all files"},"files":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string","description":"Path inside the package, such as `GamCity.uplugin`, `Content/Paks/WindowsClient/GamCity….pak` or `Nui/icons/cash.png`"},"size":{"type":"integer","description":"Bytes","minimum":1},"sha256":{"type":"string","description":"SHA-256, 64 hex characters"}},"required":["path","size","sha256"]}}},"required":["name","version","engine","size","files"]},"description":"Game packages the server needs (empty without packages)"},"packageGrant":{"type":"string","description":"Download grant for `packages`, only when there are packages"},"packageGrantExpiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["token","address","port","expiresAt","packages"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `server_offline`, `server_full`, `package_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per 10 minutes per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 per 10 minutes per account"}},"/v1/servers/{id}/join/verify":{"post":{"operationId":"verifyJoinToken","tags":["Servers"],"summary":"Check a join token","description":"Called by the game server when a player connects with a join token. Answers who the player is and uses the token up. Unknown, expired, used tokens and tokens for another server are refused alike.\n\nRate limit: 1200 per minute per server.","parameters":[{"name":"id","in":"path","required":true,"description":"Server ID","schema":{"type":"string","format":"uuid"}},{"name":"x-server-key","in":"header","required":true,"description":"Key from registering the server","schema":{"type":"string"}}],"security":[{"serverKey":[]}],"responses":{"200":{"description":"Player","content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"object","properties":{"id":{"type":"integer","description":"Account ID. Stable, use it to keep the player's progress."},"handle":{"type":"string","description":"Handle, can change"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Path of the profile picture, relative to the API"},{"type":"null"}]}},"required":["id","handle","displayName","avatar"]},"issuedAt":{"type":"integer","format":"int64","description":"When the launcher asked for the token"}},"required":["account","issuedAt"]}}}},"400":{"description":"Error codes: `invalid_field`, `invalid_join_token`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `invalid_server_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 1200 per minute per server. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"serverKey","x-gampeon-rate-limit":"1200 per minute per server","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"Join token from the client","pattern":"^[A-Za-z0-9_-]{43}$"}},"required":["token"]}}}}}},"/v1/projects/{slug}/packages":{"get":{"operationId":"listProjectPackages","tags":["Game packages"],"summary":"Game packages of a project","description":"For people who can edit the project. Lists every version with its upload progress, the storage your project uses and the limits.\n\nNot available with access tokens.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Packages","content":{"application/json":{"schema":{"type":"object","properties":{"available":{"type":"boolean","description":"false if game packages are switched off on this server"},"packages":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"},"engine":{"type":"string"},"status":{"enum":["uploading","ready"],"description":"`ready` once every file is uploaded and `finish` was called. Only ready versions reach players."},"size":{"type":"integer","description":"Bytes of all files"},"received":{"type":"integer","description":"Bytes uploaded so far"},"files":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"size":{"type":"integer"},"sha256":{"type":"string"},"received":{"type":"integer","description":"Bytes of this file uploaded so far"},"done":{"type":"boolean"}},"required":["path","size","sha256","received","done"]}},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"readyAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["name","version","engine","status","size","received","files","createdAt","readyAt"]}},"usedBytes":{"type":"integer"},"quotaBytes":{"type":"integer"},"maxVersionBytes":{"type":"integer"},"chunkBytes":{"type":"integer","description":"Largest piece for one upload request"},"keepVersions":{"type":"integer","description":"Ready versions kept per package; `finish` deletes older ones"},"license":{"type":"object","properties":{"version":{"type":"string"},"text":{"type":"string","description":"The statement you confirm with every upload"}},"required":["version","text"]}},"required":["available","packages","usedBytes","quotaBytes","maxVersionBytes","chunkBytes","keepVersions","license"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `project_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"},"post":{"operationId":"createPackageVersion","tags":["Game packages"],"summary":"Start the upload of a package version","description":"Send the manifest from `gampeon-package.json`, which the GAMPEON cook command writes, and confirm your license (`licenseConfirmed: true`, text in `GET …/packages`). Only content: the `.uplugin` must not have code modules, and only cooked paks (`Content/Paks/<platform>/*.pak|utoc|ucas|sig`) and files for web interfaces (`Nui/…`) are allowed. Sending the same manifest again continues an unfinished upload.\n\nNot available with access tokens.\n\nRate limit: 30 per hour per account.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string"}}],"security":[{"session":[]}],"responses":{"201":{"description":"Version created (200: unfinished upload continued)","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"},"engine":{"type":"string"},"status":{"enum":["uploading","ready"],"description":"`ready` once every file is uploaded and `finish` was called. Only ready versions reach players."},"size":{"type":"integer","description":"Bytes of all files"},"received":{"type":"integer","description":"Bytes uploaded so far"},"files":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"size":{"type":"integer"},"sha256":{"type":"string"},"received":{"type":"integer","description":"Bytes of this file uploaded so far"},"done":{"type":"boolean"}},"required":["path","size","sha256","received","done"]}},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"readyAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["name","version","engine","status","size","received","files","createdAt","readyAt"]}}}},"400":{"description":"Error codes: `invalid_field`, `invalid_package`, `invalid_package_file`, `license_not_confirmed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`, `project_hidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `version_exists`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error codes: `package_too_large`, `quota_exceeded`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 30 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `packages_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"30 per hour per account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"manifest":{"type":"object","properties":{"name":{"type":"string","description":"Package name, the name of the content plugin","pattern":"^[A-Za-z][A-Za-z0-9_]{1,47}$"},"version":{"type":"string","description":"Version, such as `1.0.0`. Each upload needs a new version.","pattern":"^\\d{1,4}\\.\\d{1,4}\\.\\d{1,6}$"},"engine":{"type":"string","description":"The GAMPEON version the package was cooked for","pattern":"^[A-Za-z0-9][A-Za-z0-9._+-]{0,63}$"},"files":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string","description":"Path inside the package, such as `GamCity.uplugin`, `Content/Paks/WindowsClient/GamCity….pak` or `Nui/icons/cash.png`"},"size":{"type":"integer","description":"Bytes","minimum":1},"sha256":{"type":"string","description":"SHA-256, 64 hex characters"}},"required":["path","size","sha256"]},"description":"All files of the package, 1 to 256","minItems":1,"maxItems":256}},"required":["name","version","engine","files"]},"licenseConfirmed":{"const":true,"description":"You confirm the license statement"}},"required":["manifest","licenseConfirmed"]}}}}}},"/v1/projects/{slug}/packages/{name}/{version}/files/{sha256}":{"put":{"operationId":"uploadPackageChunk","tags":["Game packages"],"summary":"Upload a piece of a package file","description":"Send the file in pieces of at most `chunkBytes` (64 MB) in order. `offset` must equal the bytes the server has (`received`); after an interruption, read `GET …/packages` and continue there. With the last piece the server checks the SHA-256 and, for the `.uplugin`, that it has no code modules. Files that GAMPEON already has from an earlier version answer `done: true` right away.\n\nNot available with access tokens.\n\nRate limit: 2000 per hour per account.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string"}},{"name":"name","in":"path","required":true,"description":"Package name, as the Unreal plugin","schema":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_]{1,47}$"}},{"name":"version","in":"path","required":true,"description":"Package version, such as `1.0.0`","schema":{"type":"string","pattern":"^\\d{1,4}\\.\\d{1,4}\\.\\d{1,6}$"}},{"name":"sha256","in":"path","required":true,"description":"SHA-256 of the file, 64 lowercase hex characters","schema":{"type":"string","pattern":"^[a-f0-9]{64}$"}},{"name":"offset","in":"query","required":true,"description":"Byte position of this piece in the file","schema":{"type":"integer","minimum":0}}],"security":[{"session":[]}],"responses":{"200":{"description":"Piece stored","content":{"application/json":{"schema":{"type":"object","properties":{"received":{"type":"integer"},"size":{"type":"integer"},"done":{"type":"boolean"}},"required":["received","size","done"]}}}},"400":{"description":"Error codes: `upload_aborted`, `upload_incomplete`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `offset_mismatch`, `version_ready`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"411":{"description":"Error codes: `length_required`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Error codes: `chunk_too_large`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Error codes: `checksum_mismatch`, `invalid_package`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 2000 per hour per account. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `packages_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"507":{"description":"Error codes: `storage_full`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user","x-gampeon-rate-limit":"2000 per hour per account","requestBody":{"required":true,"description":"The bytes of this piece","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}}}},"/v1/projects/{slug}/packages/{name}/{version}/finish":{"post":{"operationId":"finishPackageVersion","tags":["Game packages"],"summary":"Make a package version playable","description":"Checks that every file is uploaded and marks the version `ready`. From then on, players of your project's servers that run this version get it when they press Play. Keeps the newest 3 ready versions of the package and deletes older ones.\n\nNot available with access tokens.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string"}},{"name":"name","in":"path","required":true,"description":"Package name, as the Unreal plugin","schema":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_]{1,47}$"}},{"name":"version","in":"path","required":true,"description":"Package version, such as `1.0.0`","schema":{"type":"string","pattern":"^\\d{1,4}\\.\\d{1,4}\\.\\d{1,6}$"}}],"security":[{"session":[]}],"responses":{"200":{"description":"Version is ready","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"},"engine":{"type":"string"},"status":{"enum":["uploading","ready"],"description":"`ready` once every file is uploaded and `finish` was called. Only ready versions reach players."},"size":{"type":"integer","description":"Bytes of all files"},"received":{"type":"integer","description":"Bytes uploaded so far"},"files":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"size":{"type":"integer"},"sha256":{"type":"string"},"received":{"type":"integer","description":"Bytes of this file uploaded so far"},"done":{"type":"boolean"}},"required":["path","size","sha256","received","done"]}},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"readyAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]}},"required":["name","version","engine","status","size","received","files","createdAt","readyAt"]}}}},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error codes: `upload_incomplete`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `packages_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/projects/{slug}/packages/{name}/{version}":{"delete":{"operationId":"deletePackageVersion","tags":["Game packages"],"summary":"Delete a package version","description":"Removes the version and every file no other version uses. Servers that still run it can no longer be joined until they load another ready version.\n\nNot available with access tokens.","parameters":[{"name":"slug","in":"path","required":true,"description":"Project slug","schema":{"type":"string"}},{"name":"name","in":"path","required":true,"description":"Package name, as the Unreal plugin","schema":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_]{1,47}$"}},{"name":"version","in":"path","required":true,"description":"Package version, such as `1.0.0`","schema":{"type":"string","pattern":"^\\d{1,4}\\.\\d{1,4}\\.\\d{1,6}$"}}],"security":[{"session":[]}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Error codes: `unauthorized`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error codes: `token_not_allowed`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"user"}},"/v1/packages/files/{sha256}":{"get":{"operationId":"downloadPackageFile","tags":["Game packages"],"summary":"Download a file of a game package","description":"For the launcher. Needs the `packageGrant` from `POST /v1/servers/{id}/join` in the header `x-package-grant` (60 minutes, only for the packages of that join). Supports `Range: bytes=start-` to continue an interrupted download. Check the SHA-256 after downloading.\n\nRate limit: 600 per hour per grant.","parameters":[{"name":"sha256","in":"path","required":true,"description":"SHA-256 of the file, 64 lowercase hex characters","schema":{"type":"string","pattern":"^[a-f0-9]{64}$"}},{"name":"x-package-grant","in":"header","required":true,"description":"Download grant from the join","schema":{"type":"string"}},{"name":"range","in":"header","required":false,"description":"Optional single range, `bytes=start-` or `bytes=start-end`","schema":{"type":"string"}}],"security":[],"responses":{"200":{"description":"The file (206 for a range)","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Error codes: `invalid_package_grant`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error codes: `not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"416":{"description":"Error codes: `range_not_satisfiable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Limit: 600 per hour per grant. Error codes: `rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error codes: `packages_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-gampeon-auth":"none","x-gampeon-rate-limit":"600 per hour per grant"}}},"components":{"securitySchemes":{"session":{"type":"http","scheme":"bearer","description":"Session token from `POST /v1/sessions`."},"serverKey":{"type":"apiKey","in":"header","name":"x-server-key","description":"Server key from `POST /v1/servers`. Only for heartbeats."},"accessToken":{"type":"http","scheme":"bearer","bearerFormat":"gpat_","description":"Personal access token from the portal or `POST /v1/me/tokens`. Only for routes with `x-gampeon-token-scope`; the listed scope is required."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","description":"Machine-readable error code, for example `not_found` or `rate_limited`."},"message":{"type":"string","description":"Human-readable detail. Only present for some errors."}},"required":["error"]},"UserRef":{"type":"object","properties":{"handle":{"type":"string","description":"Unique handle","pattern":"^[a-z0-9_]{3,24}$"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]}},"required":["handle","displayName"]},"Me":{"type":"object","properties":{"id":{"type":"integer","description":"Account ID"},"email":{"type":"string","description":"Email address. Only visible to the account itself with a portal session, never with an access token.","format":"email"},"displayName":{"type":"string"},"handle":{"type":"string","pattern":"^[a-z0-9_]{3,24}$"},"bio":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]},"cover":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]},"role":{"type":"string","enum":["user","moderator","admin"]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"emailVerified":{"type":"boolean"},"birthMonth":{"oneOf":[{"type":"string","description":"`YYYY-MM`. `null` for accounts created before the age check; they should add it with `PATCH /v1/me`. Like the email address, only visible with a portal session, never with an access token."},{"type":"null"}]},"country":{"oneOf":[{"type":"string","description":"Country code (ISO 3166-1 alpha-2, for example `DE`). `null` when not set.","pattern":"^[A-Z]{2}$"},{"type":"null"}]},"links":{"type":"array","items":{"$ref":"#/components/schemas/ProfileLink"},"description":"Profiles on other platforms, at most one per platform (up to 10)."},"ageGroup":{"type":"string","enum":["protected","adult"],"description":"`protected`: under 16 or birth month unknown. Stricter privacy defaults apply."},"terms":{"type":"object","properties":{"version":{"oneOf":[{"type":"string","description":"Last accepted version of the Terms of Use and Community Guidelines, `null` if none yet"},{"type":"null"}]},"acceptedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"currentVersion":{"type":"string","description":"Version in force"},"current":{"type":"boolean","description":"`false`: show the terms and ask the person to accept them (`POST /v1/me/terms`)"}},"required":["version","acceptedAt","currentVersion","current"]},"notifications":{"type":"array","items":{"$ref":"#/components/schemas/Notification"},"description":"The 50 newest notifications"}},"required":["id","displayName","handle","bio","avatar","cover","role","createdAt","emailVerified","country","links","terms","notifications"]},"Notification":{"type":"object","properties":{"kind":{"type":"string","description":"For example `achievement_unlocked`, `content_blocked`, `studio_invite`, `appeal_decided`, `page_hidden`, `token_created`."},"body":{"type":"string","description":"JSON-encoded details. The shape depends on `kind`."},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["kind","body","createdAt"]},"Profile":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"bio":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]},"cover":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]},"staff":{"type":"boolean","description":"True for moderators and admins"},"joinedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"resources":{"type":"array","items":{"$ref":"#/components/schemas/ResourceListing"},"description":"Public marketplace items (up to 100)"},"servers":{"type":"array","items":{"$ref":"#/components/schemas/Server"},"description":"Servers that are online right now"},"studios":{"type":"array","items":{"$ref":"#/components/schemas/StudioMembership"}},"projects":{"type":"array","items":{"$ref":"#/components/schemas/Project"},"description":"Own projects and projects of their studios (up to 100)"},"achievements":{"$ref":"#/components/schemas/AchievementShowcase"},"connections":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string","enum":["steam","discord"]},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"url":{"type":"string","description":"Profile page at the provider","format":"uri"}},"required":["provider","name","url"]},"description":"Steam and Discord accounts the person chose to show. Always empty for accounts under 16."},"country":{"oneOf":[{"type":"string","description":"Country the person says they are from (ISO 3166-1 alpha-2). Always `null` for accounts under 16.","pattern":"^[A-Z]{2}$"},{"type":"null"}]},"links":{"type":"array","items":{"$ref":"#/components/schemas/ProfileLink"},"description":"Profiles on other platforms the person entered themselves (not verified). Always empty for accounts under 16."}},"required":["handle","displayName","bio","avatar","cover","staff","joinedAt","resources","servers","studios","projects","achievements","connections","country","links"]},"ProfileLink":{"type":"object","properties":{"platform":{"type":"string","enum":["twitch","kick","youtube","tiktok","instagram","x","facebook","reddit","github","bluesky"]},"handle":{"type":"string","description":"Name on the platform. YouTube uses `@name` or `channel/<id>`, Facebook a username or a numeric profile ID."},"url":{"type":"string","description":"Profile page, built by GAMPEON from the name. Never a link the person entered.","format":"uri"}},"required":["platform","handle","url"]},"Server":{"type":"object","properties":{"id":{"type":"string","description":"Server ID","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"website":{"oneOf":[{"type":"string"},{"type":"null"}]},"owner":{"$ref":"#/components/schemas/UserRef"},"online":{"type":"boolean","description":"Sent a heartbeat in the last 90 seconds"},"address":{"oneOf":[{"type":"string","description":"Host name or IP address players connect to"},{"type":"null"}]},"port":{"oneOf":[{"type":"integer"},{"type":"null"}]},"players":{"type":"integer"},"maxPlayers":{"type":"integer"},"tags":{"type":"array","items":{"type":"string"}},"language":{"oneOf":[{"type":"string","description":"Language code such as `en` or `de-DE`"},{"type":"null"}]},"lastSeen":{"type":"integer","format":"int64","description":"Last heartbeat (Unix time in milliseconds)"},"peakPlayers":{"type":"integer","description":"Highest player count reported over two consecutive heartbeats"},"project":{"oneOf":[{"$ref":"#/components/schemas/ProjectRef"},{"type":"null"}]}},"required":["id","name","description","website","owner","online","address","port","players","maxPlayers","tags","language","lastSeen","peakPlayers","project"]},"ProjectRef":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"}},"required":["slug","title"]},"ResourceListing":{"type":"object","properties":{"name":{"type":"string","description":"Unique resource name","pattern":"^[a-z0-9][a-z0-9_\\-]{1,47}$"},"title":{"type":"string"},"description":{"type":"string"},"kind":{"type":"string","enum":["script","vehicle","map","prop","clothing","gamemode","tool"]},"tags":{"type":"array","items":{"type":"string"}},"owner":{"$ref":"#/components/schemas/UserRef"},"latestVersion":{"oneOf":[{"type":"string","description":"Newest version that is not blocked"},{"type":"null"}]},"image":{"oneOf":[{"type":"string","description":"Path of the preview image, relative to the API, for example `/v1/images/<sha256>.webp`"},{"type":"null"}]},"downloads":{"type":"integer","description":"Downloads of all versions"},"price":{"type":"integer","description":"Price in GAMPEONS, 0 = free"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["name","title","description","kind","tags","owner","latestVersion","image","downloads","price","createdAt","updatedAt"]},"ResourceVersion":{"type":"object","properties":{"version":{"type":"string","description":"Semantic version","pattern":"^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z.\\-]+)?$"},"sha256":{"type":"string","description":"SHA-256 of the file (hex)"},"sizeBytes":{"type":"integer"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"downloads":{"type":"integer"},"hasFile":{"type":"boolean","description":"The file has been uploaded"},"url":{"oneOf":[{"type":"string","description":"Download path relative to the API, once the file is uploaded"},{"type":"null"}]}},"required":["version","sha256","sizeBytes","createdAt","downloads","hasFile","url"]},"ResourceDetail":{"allOf":[{"$ref":"#/components/schemas/ResourceListing"},{"type":"object","properties":{"owner":{"type":"string","description":"Display name of the owner (kept for compatibility; see `ownerProfile`)"},"ownerProfile":{"$ref":"#/components/schemas/UserRef"},"project":{"oneOf":[{"$ref":"#/components/schemas/ProjectRef"},{"type":"null"}]},"versions":{"type":"array","items":{"$ref":"#/components/schemas/ResourceVersion"},"description":"Versions that are not blocked, newest first"},"requiresPurchase":{"type":"boolean","description":"The item costs GAMPEONS"},"owned":{"type":"boolean","description":"You may download it: free, your own, or bought. `false` without a session for paid items"}},"required":["owner","ownerProfile","project","versions","requiresPurchase","owned"]}]},"MyResource":{"allOf":[{"$ref":"#/components/schemas/ResourceListing"},{"type":"object","properties":{"versions":{"type":"array","items":{"type":"object","properties":{"version":{"type":"string"},"sizeBytes":{"type":"integer"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"downloads":{"type":"integer"},"blocked":{"type":"boolean","description":"Blocked after a report (DSA Art. 17). Not delivered any more."},"hasFile":{"type":"boolean"}},"required":["version","sizeBytes","createdAt","downloads","blocked","hasFile"]},"description":"All versions including blocked ones, newest first"}},"required":["versions"]}]},"Studio":{"type":"object","properties":{"slug":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},"name":{"type":"string"},"tagline":{"type":"string"},"logo":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]},"cover":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]},"members":{"type":"integer","description":"Number of members"},"projects":{"type":"integer","description":"Number of visible projects"},"players":{"type":"integer","description":"Players on online servers of all projects"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["slug","name","tagline","logo","cover","members","projects","players","createdAt"]},"StudioMembership":{"allOf":[{"$ref":"#/components/schemas/Studio"},{"type":"object","properties":{"role":{"type":"string","enum":["owner","admin","member"]},"hidden":{"type":"boolean","description":"Hidden by moderation (only in `/v1/me/studios`)"}},"required":["role"]}]},"StudioMember":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]},"role":{"type":"string","enum":["owner","admin","member"]},"joinedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["handle","displayName","avatar","role","joinedAt"]},"StudioInvite":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"handle":{"type":"string"},"displayName":{"type":"string"},"role":{"type":"string","enum":["admin","member"]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"expiresAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"}},"required":["id","handle","displayName","role","createdAt","expiresAt"]},"Hidden":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"When moderation hid the page"},"reason":{"oneOf":[{"type":"string","description":"Statement of reasons (DSA Art. 17)"},{"type":"null"}]}},"required":["at","reason"]},"Project":{"type":"object","properties":{"slug":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$"},"title":{"type":"string"},"tagline":{"type":"string"},"genre":{"type":"string","enum":["roleplay","racing","shooter","survival","parkour","sandbox","minigames","simulation","other"]},"tags":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["concept","development","alpha","beta","released"],"description":"Development stage, in this order: concept, development, alpha, beta, released"},"languages":{"type":"array","items":{"type":"string","enum":["en","de","fr","es","it","pt","nl","pl","cs","sk","hu","ro","bg","el","tr","ru","uk","sv","da","no","fi","ar","he","hi","th","vi","id","ja","ko","zh"]},"description":"Languages of the game (ISO 639-1), up to 10"},"cover":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]},"owner":{"oneOf":[{"type":"object","properties":{"type":{"const":"studio"},"slug":{"type":"string"},"name":{"type":"string"},"logo":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]}},"required":["type","slug","name"]},{"type":"object","properties":{"type":{"const":"user"},"handle":{"type":"string"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]}},"required":["type","handle","displayName"]}]},"players":{"type":"integer","description":"Players on linked servers that are online"},"online":{"type":"integer","description":"Linked servers that are online"},"items":{"type":"integer","description":"Linked marketplace items with at least one free version"},"favorites":{"type":"integer","description":"Accounts that marked the project as a favorite"},"views":{"type":"integer","description":"Page views (counted once per visitor and day, the team not included)"},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"updatedAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"releasedAt":{"oneOf":[{"type":"integer","format":"int64","description":"First time the status was set to `released`"},{"type":"null"}]},"publishedAt":{"oneOf":[{"type":"integer","format":"int64","description":"When the project was published. `null`: draft, only the team sees it"},{"type":"null"}]}},"required":["slug","title","tagline","genre","tags","status","languages","cover","owner","players","online","items","favorites","views","createdAt","updatedAt","releasedAt","publishedAt"]},"ProjectLinks":{"type":"object","properties":{"discord":{"type":"string"},"youtube":{"type":"string"},"x":{"type":"string"},"twitch":{"type":"string"},"tiktok":{"type":"string"},"steam":{"type":"string"}},"required":[],"description":"Links besides the website: Discord invite, YouTube channel, X, Twitch, TikTok profile, Steam store page. Only `https://`. In a change, an empty string removes a link."},"GalleryItem":{"oneOf":[{"type":"object","properties":{"id":{"type":"string"},"type":{"const":"image"},"url":{"oneOf":[{"type":"string","description":"Image path (`/v1/media/…`). `null` only for the team when moderation removed the image"},{"type":"null"}]},"width":{"type":"integer"},"height":{"type":"integer"},"caption":{"type":"string"},"removed":{"type":"boolean","description":"Only for the team: removed by moderation"}},"required":["id","type","url","width","height","caption"]},{"type":"object","properties":{"id":{"type":"string"},"type":{"const":"video"},"provider":{"const":"youtube"},"videoId":{"type":"string","description":"YouTube video ID (11 characters)"},"caption":{"type":"string"}},"required":["id","type","provider","videoId","caption"]}]},"ChecklistItem":{"type":"object","properties":{"id":{"type":"string","enum":["tagline","description","cover","gallery","tags","languages","links"]},"done":{"type":"boolean"},"required":{"type":"boolean","description":"Needed to publish. Required: a tagline and an about text with at least 100 characters"}},"required":["id","done","required"]},"Achievement":{"type":"object","properties":{"id":{"type":"string"},"category":{"type":"string","enum":["start","creator","operator","studios","projects","veteran","community","secret","play"]},"tier":{"type":"string","enum":["bronze","silver","gold","platinum"]},"points":{"type":"integer"},"title":{"type":"string","description":"Hidden achievements show a placeholder until unlocked"},"description":{"type":"string"},"icon":{"type":"string","description":"Icon name"},"source":{"type":"string","enum":["platform","staff","game"],"description":"`platform`: from real numbers. `staff`: granted by the team. `game`: comes with the launcher."},"hidden":{"type":"boolean","description":"Still hidden for this viewer"},"percent":{"type":"number","description":"Share of all accounts that unlocked it, in percent"},"unlockedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"progress":{"oneOf":[{"type":"object","properties":{"value":{"type":"integer"},"goal":{"type":"integer"}},"required":["value","goal"]},{"type":"null"}]}},"required":["id","category","tier","points","title","description","icon","source","hidden","percent","unlockedAt","progress"]},"AchievementSummary":{"type":"object","properties":{"unlocked":{"type":"integer"},"total":{"type":"integer"},"points":{"type":"integer"},"maxPoints":{"type":"integer"}},"required":["unlocked","total","points","maxPoints"]},"AchievementShowcase":{"allOf":[{"$ref":"#/components/schemas/AchievementSummary"},{"type":"object","properties":{"showcase":{"type":"array","items":{"$ref":"#/components/schemas/Achievement"},"description":"The 6 rarest unlocked achievements (without `progress`)"}},"required":["showcase"]}]},"AchievementCategory":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"}},"required":["id","title"]},"SocialTarget":{"type":"object","properties":{"type":{"type":"string","enum":["user","studio","project"]},"key":{"type":"string","description":"Handle or slug"},"name":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]},"since":{"type":"integer","format":"int64","description":"When the follow started"}},"required":["type","key","name","avatar","since"]},"Reactions":{"type":"object","properties":{"total":{"type":"integer","description":"All reactions together"},"top":{"type":"array","items":{"type":"string","enum":["like","love","haha","wow","sad","angry"]},"description":"Up to three most frequent reactions, most frequent first (for the icons)"},"counts":{"type":"object","additionalProperties":{"type":"integer"},"description":"Number per reaction, only reactions that occur"}},"required":["total","top","counts"]},"LinkCard":{"type":"object","properties":{"url":{"type":"string"},"domain":{"type":"string","description":"Host without www."},"title":{"oneOf":[{"type":"string","description":"Page title (og:title or <title>), up to 200 characters. `null` until the preview has been fetched"},{"type":"null"}]},"siteName":{"oneOf":[{"type":"string","description":"og:site_name"},{"type":"null"}]},"youtube":{"oneOf":[{"type":"string","description":"YouTube video ID, for a click-to-play embed"},{"type":"null"}]}},"required":["url","domain","title","siteName","youtube"]},"PostImage":{"type":"object","properties":{"url":{"type":"string","description":"Image path relative to the API (`/v1/media/…`)"},"width":{"type":"integer"},"height":{"type":"integer"}},"required":["url","width","height"]},"Gif":{"type":"object","properties":{"id":{"type":"string","description":"GIF ID at KLIPY"},"title":{"type":"string","description":"Description from KLIPY, for alt text"},"url":{"type":"string","description":"Image path relative to the API (`/v1/gifs/…/md`)"},"width":{"type":"integer"},"height":{"type":"integer"},"provider":{"type":"string","description":"`klipy`. Show “via KLIPY” on the GIF"}},"required":["id","title","url","width","height","provider"]},"GifResult":{"type":"object","properties":{"id":{"type":"string","description":"GIF ID, send it as `gif` with a post or comment"},"title":{"type":"string"},"url":{"type":"string","description":"`/v1/gifs/…/md`"},"width":{"type":"integer"},"height":{"type":"integer"},"preview":{"type":"object","properties":{"url":{"type":"string","description":"`/v1/gifs/…/sm`, for the picker"},"width":{"type":"integer"},"height":{"type":"integer"}},"required":["url","width","height"]}},"required":["id","title","url","width","height","preview"]},"Comment":{"type":"object","properties":{"id":{"type":"integer"},"postId":{"type":"integer"},"parentId":{"oneOf":[{"type":"integer","description":"Top-level comment this replies to"},{"type":"null"}]},"body":{"type":"string","description":"Plain text, up to 1,000 characters. Can be empty if there is a GIF"},"gif":{"oneOf":[{"$ref":"#/components/schemas/Gif"},{"type":"null"}]},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"editedAt":{"oneOf":[{"type":"integer","format":"int64","description":"Unix time in milliseconds"},{"type":"null"}]},"author":{"$ref":"#/components/schemas/UserRef"},"mentions":{"type":"array","items":{"type":"string"},"description":"Mentioned handles that exist (`@handle` in the text)"},"reactions":{"$ref":"#/components/schemas/Reactions"},"myReaction":{"oneOf":[{"type":"string","enum":["like","love","haha","wow","sad","angry"]},{"type":"null"}]},"replyCount":{"type":"integer","description":"Replies (top-level comments only)"},"canEdit":{"type":"boolean"},"canDelete":{"type":"boolean","description":"You wrote it or manage the post"},"removed":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"oneOf":[{"type":"string","description":"Statement of reasons"},{"type":"null"}]}},"required":["at","reason"]}},"required":["id","postId","parentId","body","gif","createdAt","editedAt","author","mentions","reactions","myReaction","replyCount","canEdit","canDelete"]},"Post":{"type":"object","properties":{"id":{"type":"integer"},"body":{"type":"string","description":"Plain text, up to 1,000 characters. Can be empty for photo and GIF posts and shares."},"createdAt":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"editedAt":{"oneOf":[{"type":"integer","format":"int64","description":"When the text was last changed"},{"type":"null"}]},"author":{"oneOf":[{"type":"object","properties":{"type":{"const":"user"},"handle":{"type":"string"},"displayName":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]}},"required":["type","handle","displayName","avatar"]},{"type":"object","properties":{"type":{"const":"studio"},"slug":{"type":"string"},"name":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]}},"required":["type","slug","name","avatar"]},{"type":"object","properties":{"type":{"const":"project"},"slug":{"type":"string"},"name":{"type":"string"},"avatar":{"oneOf":[{"type":"string","description":"Image path relative to the API (`/v1/media/…`). `null` without an image."},{"type":"null"}]}},"required":["type","slug","name","avatar"]}]},"postedBy":{"oneOf":[{"$ref":"#/components/schemas/UserRef"},{"type":"null"}]},"audience":{"type":"string","enum":["public","friends","private"],"description":"Who can see it. Studio and game posts are always public"},"images":{"type":"array","items":{"$ref":"#/components/schemas/PostImage"},"description":"Up to 4 photos"},"gif":{"oneOf":[{"$ref":"#/components/schemas/Gif"},{"type":"null"}]},"link":{"oneOf":[{"$ref":"#/components/schemas/LinkCard"},{"type":"null"}]},"mentions":{"type":"array","items":{"type":"string"},"description":"Mentioned handles that exist"},"shared":{"oneOf":[{"type":"object","properties":{"available":{"type":"boolean","description":"false if the original was deleted, removed or isn’t visible to you"},"post":{"description":"The original post (without comments and permissions)","type":"object"}},"required":["available"]},{"type":"null"}]},"commentMode":{"type":"string","enum":["everyone","friends","off"],"description":"Who can comment, as it applies (under 16: at most friends)"},"pinned":{"type":"boolean","description":"Pinned to the top of the timeline"},"reactions":{"$ref":"#/components/schemas/Reactions"},"myReaction":{"oneOf":[{"type":"string","enum":["like","love","haha","wow","sad","angry"]},{"type":"null"}]},"likes":{"type":"integer","description":"All reactions (older field)"},"liked":{"type":"boolean","description":"Whether you reacted (older field)"},"commentCount":{"type":"integer"},"shareCount":{"type":"integer"},"latestComments":{"type":"array","items":{"$ref":"#/components/schemas/Comment"},"description":"The two newest top-level comments, oldest first"},"canEdit":{"type":"boolean"},"canDelete":{"type":"boolean","description":"Whether you may delete it"},"canPin":{"type":"boolean"},"canComment":{"type":"boolean"},"canShare":{"type":"boolean"},"removed":{"type":"object","properties":{"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"reason":{"oneOf":[{"type":"string","description":"Statement of reasons"},{"type":"null"}]}},"required":["at","reason"]}},"required":["id","body","createdAt","editedAt","author","postedBy","audience","images","gif","link","mentions","reactions","myReaction","likes","liked","canDelete"]},"FeedItem":{"oneOf":[{"type":"object","properties":{"kind":{"const":"post"},"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"post":{"$ref":"#/components/schemas/Post"}},"required":["kind","at","post"]},{"type":"object","properties":{"kind":{"const":"release"},"at":{"type":"integer","format":"int64","description":"Unix time in milliseconds"},"release":{"type":"object","properties":{"resource":{"type":"object","properties":{"name":{"type":"string"},"title":{"type":"string"},"kind":{"type":"string"},"image":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["name","title","kind","image"]},"version":{"type":"string"},"owner":{"$ref":"#/components/schemas/UserRef"},"project":{"oneOf":[{"$ref":"#/components/schemas/ProjectRef"},{"type":"null"}]}},"required":["resource","version","owner","project"]}},"required":["kind","at","release"]}]}}}}