{"openapi":"3.1.0","info":{"title":"Player Two","version":"1.0.0","description":"Player Two (playertwo.lol) is a game store and a launchpad. This is its API for agents and games:\n- Agents: a player's own agent submits and edits that player's games, uploads their pictures, trailers and web builds, and defines a hosted game's trophies and leaderboards, with the player's agent key. The same as tools: the MCP server at /api/mcp.\n- SDK: a hosted game's own calls while it is played (trophies, stats, leaderboards, saves, presence, invites, identity, add-ons), with its play session's token. Games use them through the SDK script (https://playertwo.lol/docs/sdk), or bundled from npm: playertwo-sdk (init() and the SDK's TypeScript types; room.d.ts for a room's code). A new game from a starter: npm create playertwo-game@latest my-game.\n- Rooms: multiplayer with no server of the game's own (p2.rooms): a seat's ticket, the rooms open now, replays. The rooms themselves are WebSockets on the rooms service the ticket names.\n- Game servers: a game's own server gives trophies and trusted scores and checks who is playing, with the game's key.\n- Studio: a game's services for its developer signed in (its multiplayer among them).\n- Public: the store's games, one game, players in each game now, badges, players' and studios' public pages. No key.\nTimes are milliseconds since 1970 and money is dollars unless a field says otherwise. A refusal is JSON: { error, code? }.\nMore: https://playertwo.lol/llms.txt, https://playertwo.lol/docs#agents, https://playertwo.lol/api/v1/agent/guide.","contact":{"name":"Player Two","url":"https://playertwo.lol/help"}},"servers":[{"url":"https://playertwo.lol"}],"externalDocs":{"description":"The game SDK, rooms included","url":"https://playertwo.lol/docs/sdk"},"tags":[{"name":"Agents","description":"Submit and edit a player's games, with their agent key (p2_agent_...)."},{"name":"MCP","description":"The same, as MCP tools."},{"name":"SDK","description":"A hosted game's calls while it is played, with its play session (p2s_...). npm: playertwo-sdk.","externalDocs":{"url":"https://www.npmjs.com/package/playertwo-sdk"}},{"name":"Rooms","description":"Multiplayer with no server of the game's own: seats in its rooms, its rooms open now and its replays, with its play session (p2s_...)."},{"name":"Game servers","description":"A game's own server, with the game's key (p2g_...)."},{"name":"Studio","description":"A game's services, for its developer signed in on playertwo.lol."},{"name":"Public","description":"What anyone may read."}],"paths":{"/api/v1/agent/guide":{"get":{"operationId":"agentGuide","tags":["Agents"],"summary":"How to submit a game","description":"Every field of a game's page, its limits, the rules, the steps, and an example store game and raise. Anyone may read it.","security":[],"responses":{"200":{"description":"How to submit a game: every field, its limits, the rules, the steps, and an example of each kind.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Guide"}}}}}}},"/api/v1/agent/games/check":{"post":{"operationId":"checkDraft","tags":["Agents"],"summary":"Check a draft","description":"The draft as it would be kept, and what is still missing before it can go live. Saves nothing.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DraftBody"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DraftChecked"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/agent/games":{"post":{"operationId":"submitGame","tags":["Agents"],"summary":"Submit a game","description":"For the store (kind store) or a raise (kind raise): live at once, or kept as a draft in the studio with publish false. A raise takes no money until its human developer checks their identity in their studio; an agent can't. Five a day.","security":[{"agentKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitBody"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameSubmitted"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/agent/games/{slug}":{"get":{"operationId":"getOwnGame","tags":["Agents"],"summary":"Read one of the player's games","description":"As stored (drafts too), with its raise if it has one.","security":[{"agentKey":[]}],"parameters":[{"name":"slug","in":"path","description":"The game's address on Player Two (playertwo.lol/game/{slug}).","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnGame"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"patch":{"operationId":"editGame","tags":["Agents"],"summary":"Change a game's page","description":"Only the fields given change. A raise's terms (goal, smallest stake, share, days, planned price, stages) stand once it is open.","security":[{"agentKey":[]}],"parameters":[{"name":"slug","in":"path","description":"The game's address on Player Two (playertwo.lol/game/{slug}).","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DraftBody"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameEdited"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Not allowed: not this player's, a demo, or the game's server only.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/agent/games/{slug}/trophies":{"get":{"operationId":"listTrophies","tags":["Agents"],"summary":"A hosted game's trophies","description":"Every trophy (retired ones too), how many players hold each, the XP budget left of 1,000, and whether the game counts toward players' levels yet.","security":[{"agentKey":[]}],"parameters":[{"name":"slug","in":"path","description":"The game's address on Player Two (playertwo.lol/game/{slug}).","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrophyDefs"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"operationId":"defineTrophy","tags":["Agents"],"summary":"Add or change a trophy","description":"By its key. Once a player has earned one, its tier, stat, target and server-only setting stay. The completion trophy (key complete) takes only a sign. The game earns a trophy with the SDK's trophies.unlock(key).","security":[{"agentKey":[]}],"parameters":[{"name":"slug","in":"path","description":"The game's address on Player Two (playertwo.lol/game/{slug}).","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrophyInput"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrophyDefs"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"It can't be done in the state things are in (code says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/agent/games/{slug}/boards":{"get":{"operationId":"listBoards","tags":["Agents"],"summary":"A hosted game's leaderboards","security":[{"agentKey":[]}],"parameters":[{"name":"slug","in":"path","description":"The game's address on Player Two (playertwo.lol/game/{slug}).","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardDefs"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"operationId":"defineBoard","tags":["Agents"],"summary":"Add or change a leaderboard","description":"By its key, up to 20 a game. The game fills it with the SDK's scores.submit(key, value).","security":[{"agentKey":[]}],"parameters":[{"name":"slug","in":"path","description":"The game's address on Player Two (playertwo.lol/game/{slug}).","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardInput"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardDefs"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"It can't be done in the state things are in (code says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/agent/games/{slug}/web":{"post":{"operationId":"pushStart","tags":["Agents"],"summary":"Push a web build: its manifest","description":"The first of a push's three calls (tools/cli/p2.mjs makes them: https://playertwo.lol/docs/hosting#push-calls): the build's files by path, size and sha256, gzipped if you like (Content-Encoding: gzip). Answered with where to PUT each file the store doesn't hold yet (streamed); then done.","security":[{"agentKey":[]}],"parameters":[{"name":"slug","in":"path","description":"The game's address on Player Two (playertwo.lol/game/{slug}).","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushManifest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushStarted"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"413":{"description":"Too big.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/agent/games/{slug}/web/{build}/done":{"post":{"operationId":"pushDone","tags":["Agents"],"summary":"Push a web build: done","description":"Every file is read back for its hash and size, and the build becomes the game's, playing at https://{slug}.playertwo.cc/. Asked again, it says the same.","security":[{"agentKey":[]}],"parameters":[{"name":"slug","in":"path","description":"The game's address on Player Two (playertwo.lol/game/{slug}).","required":true,"schema":{"type":"string"}},{"name":"build","in":"path","description":"The build's key, from the manifest's answer.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushDone"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"It can't be done in the state things are in (code says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/agent/media":{"post":{"operationId":"uploadMedia","tags":["Agents"],"summary":"Upload a picture, a trailer or a font","description":"Pictures PNG, JPEG or WebP up to 12 MB; trailers and gameplay videos MP4 or WebM up to 80 MB; fonts WOFF2, WOFF, TTF or OTF up to 2 MB. Its address goes in the draft. 100 a day.","security":[{"agentKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileUpload"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaKept"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"413":{"description":"Too big.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"415":{"description":"Not a kind of file Player Two takes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/agent/builds":{"post":{"operationId":"uploadBuild","tags":["Agents"],"summary":"Upload a web build","description":"A .zip with index.html at its top (up to 100 MB), or one .html page (10 MB). Its address goes in the draft's build. Bigger builds are pushed. 20 a day.","security":[{"agentKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileUpload"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildKept"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"413":{"description":"Too big.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"415":{"description":"Not a kind of file Player Two takes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/agent/studio":{"get":{"operationId":"agentStudio","tags":["Agents"],"summary":"The player's studio","description":"Its games and where each stands, and whether the player's identity is checked (needed for raises only).","security":[{"agentKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentStudio"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/mcp":{"post":{"operationId":"mcp","tags":["MCP"],"summary":"The MCP server","description":"Model Context Protocol over Streamable HTTP, one JSON-RPC 2.0 message (or a batch) a request. Its tools (get_submission_guide, check_game, upload_media, upload_web_build, submit_game, update_game, get_game, my_studio, list_trophies, define_trophy, list_boards, define_board) take the agent API's bodies above and do what it does; the agent key goes in Authorization as for the agent API. claude mcp add --transport http player-two https://playertwo.lol/api/mcp --header \"Authorization: Bearer p2_agent_...\"","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpMessage"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpMessage"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/games/{slug}/session":{"post":{"operationId":"openSession","tags":["SDK"],"summary":"Start a play session","description":"As a hosted game starts, for the signed-in player: on the web (Player Two's player does it), or from the Player Two app on a computer (with a launch ticket). Its token is the game's Bearer for the calls below.","security":[{"session":[]}],"parameters":[{"name":"slug","in":"path","description":"The game's address on Player Two (playertwo.lol/game/{slug}).","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionStart"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionOpened"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"402":{"description":"It costs money: buy it first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Not allowed: not this player's, a demo, or the game's server only.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"It can't be done in the state things are in (code says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/me":{"get":{"operationId":"sdkMe","tags":["SDK"],"summary":"Who is playing","description":"The session's player (their public face and their id for this game), its game, and whether it is a test or a demo.","security":[{"playSession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/beat":{"post":{"operationId":"sdkBeat","tags":["SDK"],"summary":"Still playing","description":"Once a minute, and whenever the game sets its presence: the line friends see, and what they join the player with.","security":[{"playSession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Beat"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Done"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/end":{"post":{"operationId":"sdkEnd","tags":["SDK"],"summary":"The game was closed","description":"The session ends, its time counted.","security":[{"playSession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Done"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/event":{"post":{"operationId":"sdkEvent","tags":["SDK"],"summary":"What the game is doing","description":"loading.done, gameplay.start, gameplay.stop: heard, nothing kept yet.","security":[{"playSession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameEvent"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventHeard"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/identity":{"get":{"operationId":"sdkIdentity","tags":["SDK"],"summary":"A signed identity for the game's servers","description":"SDK p2.identity(): a JWT for this game only, good for ten minutes, that the game's own servers can trust.","security":[{"playSession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdentityToken"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/invite":{"post":{"operationId":"sdkInvite","tags":["SDK"],"summary":"A join link","description":"SDK p2.invite(params): the game's page on Player Two, which opens it with the params for whoever follows the link.","security":[{"playSession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invite"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteLink"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/trophies":{"get":{"operationId":"sdkTrophies","tags":["SDK"],"summary":"The game's trophies for its player","description":"Each with whether they hold it and its rarity (a hidden one they don't hold shows no name or way to earn it), and their XP and level.","security":[{"playSession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrophyList"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/trophies/{key}":{"post":{"operationId":"sdkUnlock","tags":["SDK"],"summary":"Earn a trophy","description":"SDK trophies.unlock(key): numbered, with the completion trophy if that is due, and the XP it brought. Not in a session's first ten seconds, nor in a demo, nor a server-only one.","security":[{"playSession":[]}],"parameters":[{"name":"key","in":"path","description":"The trophy's key, as its developer defined it.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrophyEarned"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Not allowed: not this player's, a demo, or the game's server only.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"It can't be done in the state things are in (code says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/stats":{"get":{"operationId":"sdkStats","tags":["SDK"],"summary":"The player's stats","security":[{"playSession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Stats"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"operationId":"sdkWriteStats","tags":["SDK"],"summary":"Set or add to stats","description":"Whole numbers by lowercase key, each key once a call; earns any trophy waiting on a stat that reached its target.","security":[{"playSession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatsSend"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatsWritten"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"It can't be done in the state things are in (code says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/boards/{key}":{"get":{"operationId":"sdkScores","tags":["SDK"],"summary":"A leaderboard","security":[{"playSession":[]}],"parameters":[{"name":"key","in":"path","description":"The leaderboard's key, as its developer defined it.","required":true,"schema":{"type":"string"}},{"name":"around","in":"query","description":"top (the default) or me: the scores around the player.","required":false,"schema":{"type":"string","enum":["top","me"]}},{"name":"friends","in":"query","description":"1: the player and their friends.","required":false,"schema":{"type":"string","enum":["1"]}},{"name":"limit","in":"query","description":"Rows, 10 by default, up to 100.","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Scores"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"operationId":"sdkSubmitScore","tags":["SDK"],"summary":"Send a score","description":"Kept if it is the player's best. A trusted board takes scores from the game's own server only.","security":[{"playSession":[]}],"parameters":[{"name":"key","in":"path","description":"The leaderboard's key, as its developer defined it.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScoreSend"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScoreKept"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Not allowed: not this player's, a demo, or the game's server only.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/saves":{"get":{"operationId":"sdkSaves","tags":["SDK"],"summary":"The player's save slots","description":"Each slot's size, version and when it was saved: 8 slots of up to 1 MB. Listing them counts as reading them.","security":[{"playSession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveList"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/saves/{slot}":{"get":{"operationId":"sdkSave","tags":["SDK"],"summary":"Read a save","security":[{"playSession":[]}],"parameters":[{"name":"slot","in":"path","description":"The slot's name.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveRead"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"put":{"operationId":"sdkPutSave","tags":["SDK"],"summary":"Save","description":"A slot holding a save must be read in this session first (409 read-first); with version, a save made elsewhere since is refused (409 version).","security":[{"playSession":[]}],"parameters":[{"name":"slot","in":"path","description":"The slot's name.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveSend"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveKept"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"It can't be done in the state things are in (code says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"413":{"description":"Too big.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"operationId":"sdkDeleteSave","tags":["SDK"],"summary":"Empty a save slot","security":[{"playSession":[]}],"parameters":[{"name":"slot","in":"path","description":"The slot's name.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveGone"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/mirror/{which}":{"get":{"operationId":"sdkMirror","tags":["SDK"],"summary":"The kept copy of a hosted game's browser storage","description":"The SDK's auto mode on the games host: local (its localStorage) or idb (its IndexedDB).","security":[{"playSession":[]}],"parameters":[{"name":"which","in":"path","description":"local or idb.","required":true,"schema":{"type":"string","enum":["local","idb"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirrorRead"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"put":{"operationId":"sdkPutMirror","tags":["SDK"],"summary":"Keep a copy of a hosted game's browser storage","security":[{"playSession":[]}],"parameters":[{"name":"which","in":"path","description":"local or idb.","required":true,"schema":{"type":"string","enum":["local","idb"]}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirrorSend"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveKept"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"It can't be done in the state things are in (code says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"413":{"description":"Too big.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/addons":{"get":{"operationId":"sdkAddons","tags":["SDK"],"summary":"The game's add-ons","description":"Those on sale, each with whether the player has it, and the keys of every add-on they have.","security":[{"playSession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddonList"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/addons/{key}":{"get":{"operationId":"sdkAddon","tags":["SDK"],"summary":"Whether the player has an add-on","security":[{"playSession":[]}],"parameters":[{"name":"key","in":"path","description":"The add-on's key, as its developer defined it.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddonOwned"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/cloud":{"get":{"operationId":"sdkCloud","tags":["SDK"],"summary":"A desktop game's saves in the cloud","description":"For the Player Two app: the save folders to sync on this system and the copy kept, with a link to download it.","security":[{"playSession":[]}],"parameters":[{"name":"platform","in":"query","description":"Which system.","required":true,"schema":{"type":"string","enum":["windows","mac","linux"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloudSave"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"operationId":"sdkCloudSend","tags":["SDK"],"summary":"Upload a desktop game's saves","description":"{ size }: where to PUT a new copy (a zip, up to 100 MB). Then { done, size }: it arrived.","security":[{"playSession":[]}],"parameters":[{"name":"platform","in":"query","description":"Which system.","required":true,"schema":{"type":"string","enum":["windows","mac","linux"]}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloudSend"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloudKept"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"It can't be done in the state things are in (code says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"413":{"description":"Too big.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/rooms/ticket":{"post":{"operationId":"sdkRoomSeat","tags":["Rooms"],"summary":"A seat in one of the game's rooms","description":"SDK p2.rooms.join, .create, .party, .world, .watch: the rooms service's address and a ticket good for two minutes, to open the room's WebSocket with. For games hosted on Player Two whose multiplayer is rooms. Refused: 409 rooms-hosted-only (a game on its own site), rooms-off (its multiplayer is none or its own servers), no-party, old-build (the page's build is no longer kept, or a world's page isn't on the live build); 422 bad-code, bad-room; 503 rooms-stopped (Player Two stopped its rooms). https://playertwo.lol/docs/sdk#rooms","security":[{"playSession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeatAsk"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Seat"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"It can't be done in the state things are in (code says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"Stopped for now.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/rooms/live":{"get":{"operationId":"sdkRoomsLive","tags":["Rooms"],"summary":"The game's public rooms open now","description":"SDK p2.rooms.live: fullest first, of a mode or every mode, to watch one (p2.rooms.watch).","security":[{"playSession":[]}],"parameters":[{"name":"mode","in":"query","description":"Only rooms of this mode.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomsLive"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/rooms/replays":{"get":{"operationId":"sdkReplays","tags":["Rooms"],"summary":"The game's replays","description":"SDK p2.rooms.replays: rooms kept by room.record (or asked to be by their first player), newest first.","security":[{"playSession":[]}],"parameters":[{"name":"limit","in":"query","description":"How many, 30 by default, up to 100.","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Replays"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/rooms/replay":{"post":{"operationId":"sdkReplay","tags":["Rooms"],"summary":"Where to fetch a replay","description":"SDK p2.rooms.replay: the rooms service's address and a ticket good for two minutes, for the page to fetch the replay with.","security":[{"playSession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplayAsk"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Seat"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/server/session":{"get":{"operationId":"serverSession","tags":["Game servers"],"summary":"Who is in a play session","description":"Who is in the session a client says it is in, and whether it is live. A session of another game is none here.","security":[{"gameKey":[]}],"parameters":[{"name":"x-player-session","in":"header","description":"The play session token (p2s_...) the game's client sent its server.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerSession"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/server/addons":{"get":{"operationId":"serverAddons","tags":["Game servers"],"summary":"The add-ons a player has","description":"By the player's id for this game (?player=), or by the session token a computer's client sends.","security":[{"gameKey":[]}],"parameters":[{"name":"player","in":"query","description":"The player's id for this game.","required":false,"schema":{"type":"string"}},{"name":"x-player-session","in":"header","description":"The play session token (p2s_...) the game's client sent its server.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerAddons"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/server/boards/{key}":{"post":{"operationId":"serverScore","tags":["Game servers"],"summary":"Send a player's score","description":"The only way onto a trusted board; kept if it is their best.","security":[{"gameKey":[]}],"parameters":[{"name":"key","in":"path","description":"The leaderboard's key, as its developer defined it.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerScore"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScoreKept"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/server/trophies/{key}":{"post":{"operationId":"serverUnlock","tags":["Game servers"],"summary":"Give a player a trophy","description":"Server-only ones too, naming the player by their id for this game.","security":[{"gameKey":[]}],"parameters":[{"name":"key","in":"path","description":"The trophy's key, as its developer defined it.","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerTrophy"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrophyEarned"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Not allowed: not this player's, a demo, or the game's server only.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/sdk/server/identity":{"post":{"operationId":"serverIdentity","tags":["Game servers"],"summary":"Check an identity","description":"Whether an identity a client sent is good for this game, and who it names. Answered whatever the token is: read valid.","security":[{"gameKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdentityCheck"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdentityChecked"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/games/{slug}/services":{"get":{"operationId":"getServices","tags":["Studio"],"summary":"A game's services","description":"For its developer and their team: its trophies with the XP budget, its leaderboards, its game keys, Connect, and its multiplayer: whether rooms are on, the live build's room code, the rooms open now.","security":[{"session":[]}],"parameters":[{"name":"slug","in":"path","description":"The game's address on Player Two (playertwo.lol/game/{slug}).","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServicesView"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Not allowed: not this player's, a demo, or the game's server only.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"operationId":"changeServices","tags":["Studio"],"summary":"Change a game's services","description":"One change a request: a trophy or a leaderboard, a game key, Connect, or its multiplayer ({ do: \"multiplayer\", value: \"rooms\" | \"none\" | \"own\" }). Answered with the services as they are now. An agent sets multiplayer in the draft instead.","security":[{"session":[]}],"parameters":[{"name":"slug","in":"path","description":"The game's address on Player Two (playertwo.lol/game/{slug}).","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAct"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServicesView"}}}},"400":{"description":"The body didn't match its schema (issues says where), or something it needs is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No key or token, or one that isn't good.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Not allowed: not this player's, a demo, or the game's server only.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"It can't be done in the state things are in (code says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"A value isn't right (field or missing says which).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/games":{"get":{"operationId":"listGames","tags":["Public"],"summary":"Every game","description":"Every game in the store and every raise, as their pages show them. The same for everyone; kept half a minute at the edge.","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameList"}}}}}}},"/api/v1/games/{slug}":{"get":{"operationId":"getGame","tags":["Public"],"summary":"One game","description":"Its page as its developer wrote it (draft) and its state on the platform (real). An archived game only for those who may open it.","security":[{"session":[]},{}],"parameters":[{"name":"slug","in":"path","description":"The game's address on Player Two (playertwo.lol/game/{slug}).","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameRead"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/live":{"get":{"operationId":"liveCounts","tags":["Public"],"summary":"Players in each game now","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LiveCounts"}}}}}}},"/api/v1/badge/{slug}":{"get":{"operationId":"gameBadge","tags":["Public"],"summary":"A game's badge","description":"A picture (SVG) with its live figure, for a README or a press kit, linking to its page.","security":[],"parameters":[{"name":"slug","in":"path","description":"The game's address on Player Two (playertwo.lol/game/{slug}).","required":true,"schema":{"type":"string"}},{"name":"kind","in":"query","description":"What it says, as the embedded card's.","required":false,"schema":{"type":"string"}},{"name":"theme","in":"query","description":"light for a light badge.","required":false,"schema":{"type":"string","enum":["light"]}}],"responses":{"200":{"description":"The badge.","content":{"image/svg+xml":{"schema":{"type":"string"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/players/{handle}":{"get":{"operationId":"getPlayer","tags":["Public"],"summary":"A player's public page","description":"Their name, level, standing unless they keep off the leaderboards, who follows them, and what they did lately unless they keep it private. Never an email, a wallet or an id.","security":[{"session":[]},{}],"parameters":[{"name":"handle","in":"path","description":"Their handle.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayerPublic"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too many: wait a little.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/studios/{handle}":{"get":{"operationId":"getStudio","tags":["Public"],"summary":"A studio","description":"Its profile, GitHub activity and followers. Its games are in /api/v1/games.","security":[],"parameters":[{"name":"handle","in":"path","description":"The studio's handle.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioRead"}}}},"404":{"description":"There is no such thing (or it isn't this player's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}}},"components":{"schemas":{"ApiError":{"type":"object","properties":{"error":{"type":"string","description":"What was wrong, in words a person can read."},"code":{"description":"A stable code for what was wrong, when there is one (session-ended, unknown-board, read-first...).","type":"string"},"issues":{"description":"A body that didn't match its schema: each problem, as path: message.","type":"array","items":{"type":"string"}},"field":{"description":"The field at fault.","type":"string"}},"required":["error"],"additionalProperties":{}},"GamePlayer":{"type":"object","properties":{"id":{"type":"string","description":"The player's id for this game only: the same every session, different in every game."},"handle":{"type":"string"},"name":{"type":"string"},"picture":{"type":["string","null"]},"creature":{"type":"string","description":"The seed of their pixel creature (their handle, unless they chose another)."},"level":{"type":"integer"}},"required":["id","handle","name","picture","creature","level"]},"Draft":{"type":"object","properties":{"v":{"type":"number","const":1},"kind":{"description":"\"store\": sold (or free) and played or downloaded from its page. \"raise\": players back a game being made. Default raise.","type":"string","enum":["store","raise"]},"title":{"type":"string","maxLength":60,"description":"The game's name. Up to 60 characters; longer is cut."},"tagline":{"type":"string","maxLength":90,"description":"One line about it. Up to 90 characters; longer is cut."},"pitch":{"type":"string","maxLength":700,"description":"What it is, in a paragraph. Up to 700 characters; longer is cut."},"more":{"type":"string","maxLength":700,"description":"A second paragraph. Up to 700 characters; longer is cut."},"qualifier":{"type":"string","maxLength":40,"description":"A short note after the tagline, like \"an unofficial fan game\". Up to 40 characters; longer is cut."},"genres":{"description":"Up to 10, the main ones first (a game shows its first four), each up to 24 characters. The store's: Action, Adventure, Arcade, Arena, Casual, Co-op, Fighting, Horror, Multiplayer, Platformer, Puzzle, Racing, Roguelite, RPG, Shooter, Simulation, Social, Sports, Strategy, Survival.","type":"array","items":{"type":"string"}},"modes":{"description":"Up to 10 short words (Duel, Co-op...), the main ones first.","type":"array","items":{"type":"string"}},"platforms":{"description":"Where it plays.","type":"array","items":{"type":"string","enum":["Browser","Windows","Mac","Linux","Mobile"]}},"controller":{"description":"\"full\": it all plays with a gamepad. \"partial\": some of it needs a keyboard or mouse.","type":"string","enum":["full","partial",""]},"requirements":{"description":"What a computer needs for its downloads: the least, and what plays it best.","type":"object","properties":{"min":{"type":"object","properties":{"os":{"type":"string","maxLength":80,"description":"Operating system. Up to 80 characters; longer is cut."},"cpu":{"type":"string","maxLength":80,"description":"Processor. Up to 80 characters; longer is cut."},"gpu":{"type":"string","maxLength":80,"description":"Graphics. Up to 80 characters; longer is cut."},"ram":{"type":"string","maxLength":80,"description":"Memory. Up to 80 characters; longer is cut."},"storage":{"type":"string","maxLength":80,"description":"Disk space. Up to 80 characters; longer is cut."},"notes":{"type":"string","maxLength":200,"description":"Anything else. Up to 200 characters; longer is cut."}}},"rec":{"type":"object","properties":{"os":{"type":"string","maxLength":80,"description":"Operating system. Up to 80 characters; longer is cut."},"cpu":{"type":"string","maxLength":80,"description":"Processor. Up to 80 characters; longer is cut."},"gpu":{"type":"string","maxLength":80,"description":"Graphics. Up to 80 characters; longer is cut."},"ram":{"type":"string","maxLength":80,"description":"Memory. Up to 80 characters; longer is cut."},"storage":{"type":"string","maxLength":80,"description":"Disk space. Up to 80 characters; longer is cut."},"notes":{"type":"string","maxLength":200,"description":"Anything else. Up to 200 characters; longer is cut."}}}}},"age":{"description":"Who it is for. Sexual content or nudity in content makes it 18 whatever is given.","type":"string","enum":["13","16","18","all",""]},"content":{"description":"What it shows, for players and parents.","type":"array","items":{"type":"string","enum":["Violence","Blood and gore","Sexual content","Nudity","Strong language","Drugs, alcohol or tobacco","Gambling-style play","Frightening scenes","Talking with strangers online"]}},"languages":{"description":"The languages it comes in: its words on screen (ui), voices (audio), subtitles (subs).","type":"array","items":{"type":"object","properties":{"lang":{"type":"string","enum":["English","Spanish","Spanish (Latin America)","Portuguese (Brazil)","Portuguese","French","German","Italian","Dutch","Polish","Russian","Ukrainian","Turkish","Arabic","Hebrew","Hindi","Bengali","Thai","Vietnamese","Indonesian","Malay","Filipino","Japanese","Korean","Chinese (Simplified)","Chinese (Traditional)","Swedish","Norwegian","Danish","Finnish","Czech","Slovak","Hungarian","Romanian","Bulgarian","Greek","Persian"]},"ui":{"type":"boolean"},"audio":{"type":"boolean"},"subs":{"type":"boolean"}},"required":["lang"]}},"access":{"description":"What it does for players with a disability.","type":"array","items":{"type":"string","enum":["Subtitles","Captions for sounds","Adjustable text size","Colour-blind options","High contrast","Remappable controls","One-handed play","No timed inputs needed","Adjustable difficulty","Save anytime","Separate volume controls","Narrated menus","Camera comfort options","Mouse only","Keyboard only","Touch only"]}},"name":{"type":"string","maxLength":28,"description":"The name as lettered on the card (uppercase); the title when empty. Up to 28 characters; longer is cut."},"sub":{"type":"string","maxLength":28,"description":"A line under the name. Up to 28 characters; longer is cut."},"font":{"description":"How the name is lettered.","anyOf":[{"type":"string","description":"A template (anton, bungee, bangers, cinzel, syncopate, kanit, pixel, archivo, chakra), or a font's address from upload_media."},{"type":"object","properties":{"google":{"type":"string"},"weight":{"type":"number"},"italic":{"type":"boolean"}},"required":["google"],"description":"A Google Fonts family at one of its weights: its files are kept in Player Two's own store."}]},"face":{"description":"The typeface the name is lettered in, as Player Two keeps it (made from font).","type":"object","properties":{"from":{"type":"string","enum":["google","own"]},"family":{"type":"string"},"weight":{"type":"number"},"italic":{"type":"boolean"},"files":{"type":"array","items":{"type":"object","properties":{"src":{"type":"string"},"range":{"type":"string"}},"required":["src"],"additionalProperties":{}}}},"required":["from","family","weight","italic","files"],"additionalProperties":{}},"size":{"description":"The lettering's size, 0.5 to 1.6.","type":"number"},"spacing":{"type":"string","maxLength":10,"description":"Letter spacing, as CSS. Up to 10 characters; longer is cut."},"glow":{"pattern":"^#[0-9a-fA-F]{6}$","description":"The game's colour, #rrggbb.","type":"string"},"art":{"type":"string","description":"The key art from upload_media, required: square, 2400 by 2400 at best, no title on it. The game's card (its middle two-thirds), its page's first screen in 3D and its wide picture in the store."},"tall":{"type":"string","description":"An older listing's vertical poster (2:3): its card while it has no key art."},"depth":{"type":"string","description":"The key art's depth map, made by Player Two."},"poster":{"type":"string","description":"An older listing's main poster (16:9)."},"clip":{"type":"string","description":"The launch trailer from upload_media, required (MP4 or WebM)."},"sound":{"description":"Whether the trailer's sound may play.","type":"boolean"},"videos":{"description":"Up to 4 gameplay videos from upload_media, after the trailer, in this order.","type":"array","items":{"type":"string"}},"shots":{"description":"Up to 8 screenshots from upload_media.","type":"array","items":{"type":"string"}},"copies":{"description":"The pictures' smaller copies, by each picture's address (made by Player Two).","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"w":{"type":"number"},"at":{"type":"array","items":{"type":"object","properties":{"w":{"type":"number"},"src":{"type":"string"}},"required":["w","src"]}}},"required":["w","at"]}},"clipCopies":{"description":"The trailer's lighter copies (made by Player Two).","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"object","properties":{"h":{"type":"number"},"src":{"type":"string"}},"required":["h","src"]}}},"stills":{"description":"A still of each feature's video (made by Player Two).","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"playUrl":{"type":"string","description":"The https address where the game is played on its own site."},"build":{"type":"string","description":"The address upload_web_build returned: a web build Player Two keeps, played at https://<slug>.playertwo.cc."},"follow":{"description":"With playUrl: Player Two serves the site from https://<slug>.playertwo.cc, so saves follow players and the SDK is in its pages.","type":"boolean"},"multiplayer":{"description":"For a game hosted on Player Two: Player Two's rooms through p2.rooms (the default), single-player, or its own servers.","type":"string","enum":["rooms","none","own"]},"agentNotes":{"$ref":"#/components/schemas/AgentNotes"},"price":{"minimum":0,"maximum":500,"description":"Store: dollars, 0 is free.","type":"number"},"demo":{"description":"Store: this is a free demo, not the finished game.","type":"boolean"},"trial":{"enum":[0,15,30,60,90,120],"description":"Store, for a game that costs money and plays in the browser: a free trial in minutes, once for each player who doesn't own it (0: none).","type":"number"},"features":{"description":"Store: up to 6.","type":"array","items":{"anyOf":[{"type":"string","maxLength":90,"description":"A feature with neither picture nor video: words on the page, in the game's colour. Up to 90 characters; longer is cut."},{"type":"object","properties":{"text":{"type":"string","maxLength":90,"description":"The feature, in a line. Up to 90 characters; longer is cut."},"art":{"type":"string","description":"A picture's address from upload_media, shown wide (16:9)."},"clip":{"type":"string","description":"Or a video's address from upload_media (a picture wins when both are given)."}}}]}},"goal":{"minimum":1,"maximum":10000000,"description":"Raise: dollars asked.","type":"number"},"minTicket":{"description":"Raise: the smallest stake, dollars.","type":"number"},"backers":{"description":"Raise: what backers get, a share of every sale or rewards only.","type":"string","enum":["share","rewards"]},"rewards":{"description":"Raise with backers \"rewards\": up to 8, by the least put in for each.","type":"array","items":{"type":"object","properties":{"min":{"type":"number"},"title":{"type":"string","maxLength":60,"description":"What they get. Up to 60 characters; longer is cut."},"body":{"type":"string","maxLength":240,"description":"A line more. Up to 240 characters; longer is cut."}},"required":["min","title"]}},"share":{"minimum":0.4,"maximum":0.85,"description":"Raise with backers \"share\": the backers' share of every sale.","type":"number"},"days":{"minimum":3,"maximum":120,"description":"Raise: how long it is open.","type":"number"},"opens":{"description":"Raise: when it opens to backers (milliseconds since 1970), up to 60 days ahead.","type":"number"},"plannedPrice":{"description":"Raise: the price it will sell at, dollars.","type":"number"},"today":{"description":"Raise: where the game is today.","type":"string","enum":["concept","prototype","demo","early"]},"todayLine":{"type":"string","maxLength":90,"description":"Raise: where it is today, in a line. Up to 90 characters; longer is cut."},"why":{"type":"string","maxLength":300,"description":"Raise: why back it. Up to 300 characters; longer is cut."},"stages":{"description":"Raise: 1 to 8 stages.","type":"array","items":{"type":"object","properties":{"title":{"type":"string","maxLength":60,"description":"The stage. Up to 60 characters; longer is cut."},"proof":{"type":"string","maxLength":240,"description":"What backers will see. Up to 240 characters; longer is cut."},"share":{"description":"Its share of the raise, 0 to 1; all add up to 1.","type":"number"},"days":{"description":"Due this many days after the raise is funded.","type":"number"}},"required":["title"]}},"branches":{"description":"Raise: what the money builds, up to 4 branches of up to 3 goals.","type":"array","items":{"type":"object","properties":{"name":{"type":"string","maxLength":30,"description":"A branch of work. Up to 30 characters; longer is cut."},"goals":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"now":{"type":"string"},"next":{"type":"string"},"cost":{"type":"number"},"stage":{"type":"number"},"shot":{"type":"number"}},"required":["title"]}}},"required":["name","goals"]}},"studio":{"type":"string","maxLength":40,"description":"The studio's name, required. Up to 40 characters; longer is cut."},"site":{"type":"string","description":"Its website."},"base":{"type":"string","maxLength":40,"description":"What it is, like \"Independent studio\". Up to 40 characters; longer is cut."},"note":{"type":"string","maxLength":900,"description":"A note to players. Up to 900 characters; longer is cut."},"sign":{"type":"string","maxLength":40,"description":"How it signs off. Up to 40 characters; longer is cut."},"x":{"description":"X handle or link.","type":"string"},"discord":{"description":"Discord invite.","type":"string"},"youtube":{"description":"YouTube channel.","type":"string"},"postTitle":{"type":"string","maxLength":80,"description":"The first post's title. Up to 80 characters; longer is cut."},"postBody":{"type":"string","maxLength":600,"description":"The first post. Up to 600 characters; longer is cut."}},"additionalProperties":{}},"DraftKept":{"type":"object","properties":{"v":{"type":"number","const":1},"kind":{"description":"\"store\": sold (or free) and played or downloaded from its page. \"raise\": players back a game being made. Default raise.","type":"string","enum":["store","raise"]},"title":{"type":"string","maxLength":60,"description":"The game's name. Up to 60 characters; longer is cut."},"tagline":{"type":"string","maxLength":90,"description":"One line about it. Up to 90 characters; longer is cut."},"pitch":{"type":"string","maxLength":700,"description":"What it is, in a paragraph. Up to 700 characters; longer is cut."},"more":{"type":"string","maxLength":700,"description":"A second paragraph. Up to 700 characters; longer is cut."},"qualifier":{"type":"string","maxLength":40,"description":"A short note after the tagline, like \"an unofficial fan game\". Up to 40 characters; longer is cut."},"genres":{"description":"Up to 10, the main ones first (a game shows its first four), each up to 24 characters. The store's: Action, Adventure, Arcade, Arena, Casual, Co-op, Fighting, Horror, Multiplayer, Platformer, Puzzle, Racing, Roguelite, RPG, Shooter, Simulation, Social, Sports, Strategy, Survival.","type":"array","items":{"type":"string"}},"modes":{"description":"Up to 10 short words (Duel, Co-op...), the main ones first.","type":"array","items":{"type":"string"}},"platforms":{"description":"Where it plays.","type":"array","items":{"type":"string","enum":["Browser","Windows","Mac","Linux","Mobile"]}},"controller":{"description":"\"full\": it all plays with a gamepad. \"partial\": some of it needs a keyboard or mouse.","type":"string","enum":["full","partial",""]},"requirements":{"description":"What a computer needs for its downloads: the least, and what plays it best.","type":"object","properties":{"min":{"type":"object","properties":{"os":{"type":"string","maxLength":80,"description":"Operating system. Up to 80 characters; longer is cut."},"cpu":{"type":"string","maxLength":80,"description":"Processor. Up to 80 characters; longer is cut."},"gpu":{"type":"string","maxLength":80,"description":"Graphics. Up to 80 characters; longer is cut."},"ram":{"type":"string","maxLength":80,"description":"Memory. Up to 80 characters; longer is cut."},"storage":{"type":"string","maxLength":80,"description":"Disk space. Up to 80 characters; longer is cut."},"notes":{"type":"string","maxLength":200,"description":"Anything else. Up to 200 characters; longer is cut."}}},"rec":{"type":"object","properties":{"os":{"type":"string","maxLength":80,"description":"Operating system. Up to 80 characters; longer is cut."},"cpu":{"type":"string","maxLength":80,"description":"Processor. Up to 80 characters; longer is cut."},"gpu":{"type":"string","maxLength":80,"description":"Graphics. Up to 80 characters; longer is cut."},"ram":{"type":"string","maxLength":80,"description":"Memory. Up to 80 characters; longer is cut."},"storage":{"type":"string","maxLength":80,"description":"Disk space. Up to 80 characters; longer is cut."},"notes":{"type":"string","maxLength":200,"description":"Anything else. Up to 200 characters; longer is cut."}}}}},"age":{"description":"Who it is for. Sexual content or nudity in content makes it 18 whatever is given.","type":"string","enum":["13","16","18","all",""]},"content":{"description":"What it shows, for players and parents.","type":"array","items":{"type":"string","enum":["Violence","Blood and gore","Sexual content","Nudity","Strong language","Drugs, alcohol or tobacco","Gambling-style play","Frightening scenes","Talking with strangers online"]}},"languages":{"description":"The languages it comes in: its words on screen (ui), voices (audio), subtitles (subs).","type":"array","items":{"type":"object","properties":{"lang":{"type":"string","enum":["English","Spanish","Spanish (Latin America)","Portuguese (Brazil)","Portuguese","French","German","Italian","Dutch","Polish","Russian","Ukrainian","Turkish","Arabic","Hebrew","Hindi","Bengali","Thai","Vietnamese","Indonesian","Malay","Filipino","Japanese","Korean","Chinese (Simplified)","Chinese (Traditional)","Swedish","Norwegian","Danish","Finnish","Czech","Slovak","Hungarian","Romanian","Bulgarian","Greek","Persian"]},"ui":{"type":"boolean"},"audio":{"type":"boolean"},"subs":{"type":"boolean"}},"required":["lang"]}},"access":{"description":"What it does for players with a disability.","type":"array","items":{"type":"string","enum":["Subtitles","Captions for sounds","Adjustable text size","Colour-blind options","High contrast","Remappable controls","One-handed play","No timed inputs needed","Adjustable difficulty","Save anytime","Separate volume controls","Narrated menus","Camera comfort options","Mouse only","Keyboard only","Touch only"]}},"name":{"type":"string","maxLength":28,"description":"The name as lettered on the card (uppercase); the title when empty. Up to 28 characters; longer is cut."},"sub":{"type":"string","maxLength":28,"description":"A line under the name. Up to 28 characters; longer is cut."},"font":{"description":"How the name is lettered.","anyOf":[{"type":"string","description":"A template (anton, bungee, bangers, cinzel, syncopate, kanit, pixel, archivo, chakra), or a font's address from upload_media."},{"type":"object","properties":{"google":{"type":"string"},"weight":{"type":"number"},"italic":{"type":"boolean"}},"required":["google"],"description":"A Google Fonts family at one of its weights: its files are kept in Player Two's own store."}]},"face":{"description":"The typeface the name is lettered in, as Player Two keeps it (made from font).","type":"object","properties":{"from":{"type":"string","enum":["google","own"]},"family":{"type":"string"},"weight":{"type":"number"},"italic":{"type":"boolean"},"files":{"type":"array","items":{"type":"object","properties":{"src":{"type":"string"},"range":{"type":"string"}},"required":["src"],"additionalProperties":{}}}},"required":["from","family","weight","italic","files"],"additionalProperties":{}},"size":{"description":"The lettering's size, 0.5 to 1.6.","type":"number"},"spacing":{"type":"string","maxLength":10,"description":"Letter spacing, as CSS. Up to 10 characters; longer is cut."},"glow":{"pattern":"^#[0-9a-fA-F]{6}$","description":"The game's colour, #rrggbb.","type":"string"},"art":{"type":"string","description":"The key art from upload_media, required: square, 2400 by 2400 at best, no title on it. The game's card (its middle two-thirds), its page's first screen in 3D and its wide picture in the store."},"tall":{"type":"string","description":"An older listing's vertical poster (2:3): its card while it has no key art."},"depth":{"type":"string","description":"The key art's depth map, made by Player Two."},"poster":{"type":"string","description":"An older listing's main poster (16:9)."},"clip":{"type":"string","description":"The launch trailer from upload_media, required (MP4 or WebM)."},"sound":{"description":"Whether the trailer's sound may play.","type":"boolean"},"videos":{"description":"Up to 4 gameplay videos from upload_media, after the trailer, in this order.","type":"array","items":{"type":"string"}},"shots":{"description":"Up to 8 screenshots from upload_media.","type":"array","items":{"type":"string"}},"copies":{"description":"The pictures' smaller copies, by each picture's address (made by Player Two).","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"w":{"type":"number"},"at":{"type":"array","items":{"type":"object","properties":{"w":{"type":"number"},"src":{"type":"string"}},"required":["w","src"]}}},"required":["w","at"]}},"clipCopies":{"description":"The trailer's lighter copies (made by Player Two).","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"object","properties":{"h":{"type":"number"},"src":{"type":"string"}},"required":["h","src"]}}},"stills":{"description":"A still of each feature's video (made by Player Two).","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"playUrl":{"type":"string","description":"The https address where the game is played on its own site."},"build":{"type":"string","description":"The address upload_web_build returned: a web build Player Two keeps, played at https://<slug>.playertwo.cc."},"follow":{"description":"With playUrl: Player Two serves the site from https://<slug>.playertwo.cc, so saves follow players and the SDK is in its pages.","type":"boolean"},"multiplayer":{"description":"For a game hosted on Player Two: Player Two's rooms through p2.rooms (the default), single-player, or its own servers.","type":"string","enum":["rooms","none","own"]},"agentNotes":{"$ref":"#/components/schemas/AgentNotes"},"price":{"minimum":0,"maximum":500,"description":"Store: dollars, 0 is free.","type":"number"},"demo":{"description":"Store: this is a free demo, not the finished game.","type":"boolean"},"trial":{"enum":[0,15,30,60,90,120],"description":"Store, for a game that costs money and plays in the browser: a free trial in minutes, once for each player who doesn't own it (0: none).","type":"number"},"features":{"description":"Store: up to 6.","type":"array","items":{"anyOf":[{"type":"string","maxLength":90,"description":"A feature with neither picture nor video: words on the page, in the game's colour. Up to 90 characters; longer is cut."},{"type":"object","properties":{"text":{"type":"string","maxLength":90,"description":"The feature, in a line. Up to 90 characters; longer is cut."},"art":{"type":"string","description":"A picture's address from upload_media, shown wide (16:9)."},"clip":{"type":"string","description":"Or a video's address from upload_media (a picture wins when both are given)."}}}]}},"goal":{"minimum":1,"maximum":10000000,"description":"Raise: dollars asked.","type":"number"},"minTicket":{"description":"Raise: the smallest stake, dollars.","type":"number"},"backers":{"description":"Raise: what backers get, a share of every sale or rewards only.","type":"string","enum":["share","rewards"]},"rewards":{"description":"Raise with backers \"rewards\": up to 8, by the least put in for each.","type":"array","items":{"type":"object","properties":{"min":{"type":"number"},"title":{"type":"string","maxLength":60,"description":"What they get. Up to 60 characters; longer is cut."},"body":{"type":"string","maxLength":240,"description":"A line more. Up to 240 characters; longer is cut."}},"required":["min","title"]}},"share":{"minimum":0.4,"maximum":0.85,"description":"Raise with backers \"share\": the backers' share of every sale.","type":"number"},"days":{"minimum":3,"maximum":120,"description":"Raise: how long it is open.","type":"number"},"opens":{"description":"Raise: when it opens to backers (milliseconds since 1970), up to 60 days ahead.","type":"number"},"plannedPrice":{"description":"Raise: the price it will sell at, dollars.","type":"number"},"today":{"description":"Raise: where the game is today.","type":"string","enum":["concept","prototype","demo","early"]},"todayLine":{"type":"string","maxLength":90,"description":"Raise: where it is today, in a line. Up to 90 characters; longer is cut."},"why":{"type":"string","maxLength":300,"description":"Raise: why back it. Up to 300 characters; longer is cut."},"stages":{"description":"Raise: 1 to 8 stages.","type":"array","items":{"type":"object","properties":{"title":{"type":"string","maxLength":60,"description":"The stage. Up to 60 characters; longer is cut."},"proof":{"type":"string","maxLength":240,"description":"What backers will see. Up to 240 characters; longer is cut."},"share":{"description":"Its share of the raise, 0 to 1; all add up to 1.","type":"number"},"days":{"description":"Due this many days after the raise is funded.","type":"number"}},"required":["title"]}},"branches":{"description":"Raise: what the money builds, up to 4 branches of up to 3 goals.","type":"array","items":{"type":"object","properties":{"name":{"type":"string","maxLength":30,"description":"A branch of work. Up to 30 characters; longer is cut."},"goals":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"now":{"type":"string"},"next":{"type":"string"},"cost":{"type":"number"},"stage":{"type":"number"},"shot":{"type":"number"}},"required":["title"]}}},"required":["name","goals"]}},"studio":{"type":"string","maxLength":40,"description":"The studio's name, required. Up to 40 characters; longer is cut."},"site":{"type":"string","description":"Its website."},"base":{"type":"string","maxLength":40,"description":"What it is, like \"Independent studio\". Up to 40 characters; longer is cut."},"note":{"type":"string","maxLength":900,"description":"A note to players. Up to 900 characters; longer is cut."},"sign":{"type":"string","maxLength":40,"description":"How it signs off. Up to 40 characters; longer is cut."},"x":{"description":"X handle or link.","type":"string"},"discord":{"description":"Discord invite.","type":"string"},"youtube":{"description":"YouTube channel.","type":"string"},"postTitle":{"type":"string","maxLength":80,"description":"The first post's title. Up to 80 characters; longer is cut."},"postBody":{"type":"string","maxLength":600,"description":"The first post. Up to 600 characters; longer is cut."}},"required":["kind","title"],"additionalProperties":{}},"AgentNotes":{"type":"object","properties":{"controls":{"type":"string","maxLength":400,"description":"The controls: keys, mouse, touch or gamepad, and what each does. Up to 400 characters; longer is cut."},"goals":{"type":"string","maxLength":400,"description":"What a player is trying to do, and how a run or a round ends. Up to 400 characters; longer is cut."}},"description":"How to play, in the developer's words: shown to agents reading the game's page (a hidden section), never to players."},"FileUpload":{"type":"object","properties":{"url":{"description":"The file's https address (preferred).","type":"string","maxLength":2000,"format":"uri"},"data":{"description":"Or the file itself in base64, up to 3 MB.","type":"string","maxLength":4500000},"filename":{"description":"Its name, when sent as data.","type":"string","maxLength":120}}},"DraftBody":{"type":"object","properties":{"draft":{"$ref":"#/components/schemas/Draft"}},"required":["draft"]},"SubmitBody":{"type":"object","properties":{"draft":{"$ref":"#/components/schemas/Draft"},"publish":{"default":true,"description":"false keeps it as a draft in the studio; default true.","type":"boolean"}},"required":["draft"]},"BoardInput":{"type":"object","properties":{"key":{"type":"string","maxLength":60,"description":"a-z, 0-9 and dashes, up to 40: what the game's code fills it by."},"name":{"type":"string","maxLength":40,"description":"Up to 40 characters."},"order":{"description":"Which way is better.","type":"string","enum":["high","low"]},"format":{"description":"How a score reads: a number, a time in milliseconds, or points.","type":"string","enum":["number","time","points"]},"min":{"description":"The lowest score it takes.","type":["number","null"]},"max":{"description":"The highest score it takes.","type":["number","null"]},"cooldown":{"minimum":0,"maximum":86400,"description":"Seconds a player waits between scores.","type":"number"},"trusted":{"description":"Only the game's own server sends its scores.","type":"boolean"}},"required":["key","name"]},"TrophyInput":{"type":"object","properties":{"key":{"type":"string","maxLength":60,"description":"a-z, 0-9 and dashes, up to 40: what the game's code earns it by. \"complete\" is the completion trophy."},"name":{"default":"","maxLength":40,"description":"Up to 40 characters.","type":"string"},"how":{"maxLength":120,"description":"How to earn it, up to 120 characters.","type":"string"},"tier":{"default":0,"minimum":1,"maximum":4,"description":"1 to 4, worth 10, 25, 50 and 100 XP; a game's trophies add up to 1,000 XP at most.","type":"integer"},"hidden":{"description":"Show only that there is one until it is earned.","type":"boolean"},"art":{"description":"A picture from upload_media.","type":"string","maxLength":600},"sign":{"description":"The small picture its relic (a sculpture of cubes) is built from: rows of # (a cube) and . (none) from the top, up to 16 by 16, as one string separated by / or a list of rows; or a library sign's name (crown, rocket, gem, pad, bell, lantern, flag, fist, star, bolt, key, sword, shield, heart, moon, flame, hourglass, anchor, tower, joystick, gift). Left out, it keeps its sign; empty, Player Two picks one by its key.","anyOf":[{"anyOf":[{"type":"string","maxLength":600},{"maxItems":40,"type":"array","items":{"type":"string","maxLength":64}}]},{"type":"null"}]},"stat":{"description":"Earned by itself when this stat reaches target.","anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"target":{"description":"A whole number, 1 or more.","type":["number","null"]},"serverOnly":{"description":"Only the game's own server can give it, with a game key.","type":"boolean"}},"required":["key"]},"PushManifest":{"type":"object","properties":{"entry":{"description":"The page that starts the game; index.html by default.","type":"string"},"files":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string","description":"Inside the folder, forward slashes."},"size":{"type":"integer","minimum":0,"description":"Bytes, up to 512 MB a file."},"sha256":{"type":"string","pattern":"^[0-9a-f]{64}$"},"type":{"description":"Its media type, if the tool knows it.","type":"string"}},"required":["path","size","sha256"]},"description":"Up to 20,000 files and 5 GB."}},"required":["files"]},"MediaKept":{"type":"object","properties":{"url":{"type":"string","description":"Its address, for the draft."},"type":{"type":"string"},"size":{"type":"integer"},"use":{"type":"string","description":"Where in the draft it goes."},"font":{"type":"object","properties":{"family":{"type":"string"},"weight":{"type":"number"},"italic":{"type":"boolean"}},"required":["family","weight","italic"]}},"required":["url","type","size","use"]},"BuildKept":{"type":"object","properties":{"build":{"type":"string","description":"The address to put in the draft's build."},"files":{"type":"integer"},"kind":{"type":"string","enum":["zip","html"]}},"required":["build","kind"]},"DraftChecked":{"type":"object","properties":{"ok":{"type":"boolean","description":"Nothing is missing."},"missing":{"type":"array","items":{"type":"string"},"description":"What still has to be filled in, in the form's order."},"draft":{"description":"The draft as it would be kept.","$ref":"#/components/schemas/DraftKept"},"font":{"description":"The font asked for, as it will be kept.","type":"string"}},"required":["ok","missing","draft"]},"GameSubmitted":{"type":"object","properties":{"slug":{"type":"string"},"url":{"type":"string"},"studio_url":{"type":"string"},"kind":{"type":"string","enum":["store","raise"]},"live":{"type":"boolean"},"identity":{"type":"object","properties":{"needed_for":{"type":"string"},"state":{"type":"string"},"by":{"type":"string"},"verify_at":{"type":"string"}},"required":["needed_for","state","by","verify_at"]},"note":{"type":"string"},"note_draft":{"type":"string"}},"required":["slug","url","studio_url","kind","live"]},"GameEdited":{"type":"object","properties":{"slug":{"type":"string"},"url":{"type":"string"}},"required":["slug","url"]},"OwnGame":{"type":"object","properties":{"slug":{"type":"string"},"url":{"type":"string"},"archived":{"type":"boolean"},"draft":{"$ref":"#/components/schemas/DraftKept"},"raise":{"anyOf":[{"type":"object","properties":{"raised":{"type":"number"},"backers":{"type":"number"},"goal":{"type":"number"},"opensAt":{"type":"number"},"closesAt":{"type":"number"},"state":{"type":"string"},"history":{"type":"array","items":{"type":"number"}},"fundedAt":{"type":["number","null"]}},"required":["raised","backers","goal","opensAt","closesAt","state","history","fundedAt"],"additionalProperties":{}},{"type":"null"}]},"price":{"type":"number","description":"Its price as its developer set it."},"sale":{"anyOf":[{"type":"object","properties":{"percent":{"type":"number"},"was":{"type":"number","description":"The price before the sale."},"ends":{"type":"number"}},"required":["percent","was","ends"],"additionalProperties":{}},{"type":"null"}]}},"required":["slug","url","archived","raise","price","sale"]},"AgentStudio":{"type":"object","properties":{"player":{"type":"string"},"studio":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"},"handle":{"type":"string"},"url":{"type":"string"}},"required":["name","handle","url"]},{"type":"null"}]},"games":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"kind":{"type":"string"},"url":{"type":"string"},"state":{"type":"string","enum":["live","archived (a draft)","taken down"]},"raise":{"type":"object","properties":{"state":{"type":"string"},"raised":{"type":"number"},"goal":{"type":"number"},"closes_at":{"type":"string"}},"required":["state","raised","goal","closes_at"]}},"required":["slug","title","kind","url","state"]}},"identity":{"type":"object","properties":{"needed_for":{"type":"string"},"state":{"type":"string"},"by":{"type":"string"},"verify_at":{"type":"string"}},"required":["needed_for","state","by","verify_at"]}},"required":["player","studio","games","identity"]},"TrophyDefs":{"type":"object","properties":{"slug":{"type":"string"},"trophies":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"how":{"type":"string"},"tier":{"type":"integer"},"xp":{"type":"integer"},"hidden":{"type":"boolean"},"art":{"type":"string"},"sign":{"type":"string"},"drawn":{"type":"boolean"},"stat":{"type":["string","null"]},"target":{"type":["number","null"]},"serverOnly":{"type":"boolean"},"retired":{"type":"boolean"},"earnedBy":{"type":"integer"},"share":{"type":"integer"},"rarity":{"type":"string","enum":["New","Common","Rare","Epic","Legendary","Mythic","Divine"]},"complete":{"type":"boolean"}},"required":["key","name","how","tier","xp","hidden","art","sign","drawn","stat","target","serverOnly","retired","earnedBy","share","rarity","complete"]}},"budget":{"type":"object","properties":{"used":{"type":"integer"},"left":{"type":"integer"},"max":{"type":"integer"}},"required":["used","left","max"]},"count":{"type":"integer"},"most":{"type":"integer"},"players":{"type":"integer"},"counts":{"type":"string","enum":["yes","waiting","off"],"description":"Whether the game's trophies count toward players' levels yet."}},"required":["slug","trophies","budget","count","most","players","counts"]},"BoardDefs":{"type":"object","properties":{"slug":{"type":"string"},"boards":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"order":{"type":"string","enum":["high","low"]},"format":{"type":"string","enum":["number","time","points"]},"min":{"type":["number","null"]},"max":{"type":["number","null"]},"cooldown":{"type":"integer"},"trusted":{"type":"boolean"},"retired":{"type":"boolean"},"players":{"type":"integer"}},"required":["key","name","order","format","min","max","cooldown","trusted","retired","players"]}},"count":{"type":"integer"},"most":{"type":"integer"}},"required":["slug","boards","count","most"]},"PushStarted":{"type":"object","properties":{"build":{"type":"string","description":"The build's key, for the last step."},"upload":{"type":"array","items":{"type":"object","properties":{"sha256":{"type":"string"},"method":{"type":"string"},"url":{"type":"string"},"headers":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"required":["sha256","method","url","headers"]},"description":"Where to send each file the store doesn't hold yet."}},"required":["build","upload"]},"PushDone":{"type":"object","properties":{"live":{"type":"boolean","const":true},"url":{"type":"string","description":"https://<slug>.playertwo.cc/"}},"required":["live","url"]},"Guide":{"type":"object","properties":{"what":{"type":"string"},"auth":{"type":"string"},"steps":{"type":"array","items":{"type":"string"}},"required":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}},"fields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Every field of the draft, its limits and its choices."}},"required":["what","auth","steps","required","fields"],"additionalProperties":{},"description":"How to submit a game: every field, its limits, the rules, the steps, and an example of each kind."},"SessionStart":{"type":"object","properties":{"from":{"type":"string","enum":["web","desktop"]},"device":{"description":"The app's own key for this computer (desktop only).","type":"object","properties":{"key":{"type":"string","minLength":32,"maxLength":128},"name":{"type":"string","maxLength":80},"platform":{"type":"string","enum":["windows","mac","linux"]}},"required":["key","name","platform"]},"build":{"description":"The download the app installed (desktop only).","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["from"]},"SessionOpened":{"type":"object","properties":{"token":{"type":"string","description":"The play session's token (p2s_...), the game's Bearer for /api/v1/sdk."},"session":{"type":"string"},"kind":{"type":"string","enum":["full","demo","test"]},"ticket":{"description":"A desktop session's launch ticket.","type":["string","null"]},"ticketExp":{"type":["number","null"]},"player":{"$ref":"#/components/schemas/GamePlayer"},"game":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"}},"required":["slug","title"]},"origins":{"description":"A web session: the origins the player's page may hand the session to.","type":"array","items":{"type":"string"}}},"required":["token","session","kind","ticket","ticketExp","player","game"]},"Beat":{"type":"object","properties":{"status":{"description":"The line the player's friends see (up to 80 characters kept); null clears it.","anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"join":{"description":"What friends join the player with (invite params); null clears it."}}},"GameEvent":{"type":"object","properties":{"event":{"type":"string","enum":["gameplay.start","gameplay.stop","loading.done"]}},"required":["event"]},"Invite":{"type":"object","properties":{"params":{"description":"What whoever follows the link is given as p2.params."}}},"ScoreSend":{"type":"object","properties":{"value":{"type":"integer","description":"A whole number (a time in milliseconds)."}},"required":["value"]},"StatsSend":{"type":"object","properties":{"set":{"description":"Stats to set: { key: whole number }.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"add":{"description":"Stats to add to: { key: amount }.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"SaveSend":{"type":"object","properties":{"data":{"type":"string","description":"The save, base64, up to 1 MB."},"version":{"description":"The version the game read: a save made elsewhere since is refused (409 version).","anyOf":[{"type":"integer"},{"type":"null"}]}},"required":["data"]},"MirrorSend":{"type":"object","properties":{"data":{"type":"string","description":"JSON text: { items: { key: value } } for local, { databases: [...] } for idb; up to 2 MB."},"version":{"anyOf":[{"type":"integer"},{"type":"null"}]},"skipped":{"description":"What was too big to copy.","maxItems":200,"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"size":{"type":"number"}},"required":["key","size"]}}},"required":["data"]},"CloudSend":{"anyOf":[{"type":"object","properties":{"done":{"type":"string","maxLength":300,"description":"The key the upload went to."},"size":{"type":"integer"}},"required":["done","size"]},{"type":"object","properties":{"size":{"type":"integer","description":"Bytes, up to 100 MB."}},"required":["size"]}]},"SeatAsk":{"type":"object","properties":{"mode":{"description":"A match of this mode (letters, numbers, - and _): the fullest open room of it and its size, or a new one. \"main\" when none is said.","type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,31}$"},"size":{"description":"The match's seats (8 when none is said, up to the game's limit).","type":"integer","minimum":1,"maximum":256},"code":{"description":"A private room's six-letter code, to join it.","type":"string","maxLength":12},"create":{"description":"A new private room: its code comes back in the room.","type":"boolean"},"party":{"description":"The player's party's room, for its members only (409 no-party otherwise).","type":"boolean"},"room":{"description":"The room the player was in (to come back to it with resume), or the one to watch.","type":"string","maxLength":200},"resume":{"description":"The key the room gave the player, to come back to the same seat.","type":"string","pattern":"^[A-Za-z0-9_-]{16,48}$"},"build":{"description":"The build the player's page loaded (__P2_HOSTED__.build): a room is for one build, and a build no longer kept is refused (409 old-build).","type":"string","pattern":"^[a-f0-9]{24}$"},"world":{"description":"A persistent world, and its area below: the live build only.","type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,31}$"},"area":{"description":"The world's area (\"main\" when none is said).","type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,31}$"},"skill":{"description":"Match by skill: rooms of players rated near this one first (room.result in the game's room code).","type":"boolean"},"watch":{"description":"Watch the room named in room: no seat, sees everything, says nothing.","type":"boolean"},"record":{"description":"Keep the room as a replay (asked by its first player).","type":"boolean"}},"description":"What seat the player wants: a match (mode, size, skill), a private room (create, or code), the party's room, a world's area, a room to come back to or to watch. Each field is optional."},"ReplayAsk":{"type":"object","properties":{"id":{"type":"string","maxLength":64,"description":"A replay's id, from p2.rooms.replays."}},"required":["id"]},"RoomsLive":{"type":"object","properties":{"rooms":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"mode":{"type":"string"},"size":{"type":"number"},"players":{"type":"number"}},"required":["id","mode","size","players"],"additionalProperties":{}},"description":"The game's public rooms open now, fullest first, up to 20: { id, mode, size, players, watchers, skill, closed, build }."}},"required":["rooms"]},"Replays":{"type":"object","properties":{"replays":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":{}},"description":"The game's replays, newest first: { id, room, mode, size, players, from, ms, bytes }."}},"required":["replays"]},"ServiceAct":{"oneOf":[{"type":"object","properties":{"do":{"type":"string","const":"trophy.save"},"trophy":{"type":"object","properties":{"key":{"type":"string","maxLength":60,"description":"a-z, 0-9 and dashes, up to 40: what the game's code earns it by. \"complete\" is the completion trophy."},"name":{"type":"string","maxLength":200},"how":{"maxLength":120,"description":"How to earn it, up to 120 characters.","type":"string"},"tier":{"type":"integer"},"hidden":{"description":"Show only that there is one until it is earned.","type":"boolean"},"art":{"description":"A picture from upload_media.","type":"string","maxLength":600},"sign":{"anyOf":[{"anyOf":[{"type":"string","maxLength":600},{"maxItems":40,"type":"array","items":{"type":"string","maxLength":64}}]},{"type":"null"}]},"stat":{"description":"Earned by itself when this stat reaches target.","anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"target":{"description":"A whole number, 1 or more.","type":["number","null"]},"serverOnly":{"description":"Only the game's own server can give it, with a game key.","type":"boolean"}},"required":["key","name","tier"]}},"required":["do","trophy"]},{"type":"object","properties":{"do":{"type":"string","const":"trophy.sign"},"key":{"type":"string","maxLength":60},"sign":{"anyOf":[{"anyOf":[{"type":"string","maxLength":600},{"maxItems":40,"type":"array","items":{"type":"string","maxLength":64}}]},{"type":"null"}]}},"required":["do","key","sign"]},{"type":"object","properties":{"do":{"type":"string","const":"trophy.retire"},"key":{"type":"string","maxLength":60},"retired":{"type":"boolean"}},"required":["do","key","retired"]},{"type":"object","properties":{"do":{"type":"string","const":"trophy.delete"},"key":{"type":"string","maxLength":60}},"required":["do","key"]},{"type":"object","properties":{"do":{"type":"string","const":"trophy.order"},"keys":{"maxItems":120,"type":"array","items":{"type":"string","maxLength":60}}},"required":["do","keys"]},{"type":"object","properties":{"do":{"type":"string","const":"board.save"},"board":{"$ref":"#/components/schemas/BoardInput"}},"required":["do","board"]},{"type":"object","properties":{"do":{"type":"string","const":"board.retire"},"key":{"type":"string","maxLength":60},"retired":{"type":"boolean"}},"required":["do","key","retired"]},{"type":"object","properties":{"do":{"type":"string","const":"board.delete"},"key":{"type":"string","maxLength":60}},"required":["do","key"]},{"type":"object","properties":{"do":{"type":"string","const":"key.make"},"name":{"default":"","type":"string","maxLength":80}},"required":["do"],"description":"A game key (p2g_...) for its own server: in the answer's made, shown once."},{"type":"object","properties":{"do":{"type":"string","const":"key.revoke"},"id":{"type":"string","maxLength":40}},"required":["do","id"]},{"type":"object","properties":{"do":{"type":"string","const":"test.reset"}},"required":["do"],"description":"Wipe what its developers earned testing it."},{"type":"object","properties":{"do":{"type":"string","const":"connect"},"on":{"type":"boolean"}},"required":["do","on"],"description":"Player Two Connect, for a game played on its own site."},{"type":"object","properties":{"do":{"type":"string","const":"rooms"},"on":{"type":"boolean"}},"required":["do","on"],"description":"The older switch: on is multiplayer rooms, off is none."},{"type":"object","properties":{"do":{"type":"string","const":"multiplayer"},"value":{"type":"string","enum":["rooms","none","own"]}},"required":["do","value"],"description":"How a game hosted on Player Two plays with others (Draft.multiplayer): Player Two's rooms through p2.rooms, single-player, or its own servers. Anything but rooms gives no new seats (409 rooms-off); rooms already open play on."}]},"ServicesView":{"type":"object","properties":{"slug":{"type":"string"},"hosted":{"type":"boolean","description":"Player Two hosts it: a web build it keeps, a site it follows, or a live download."},"connect":{"type":"object","properties":{"on":{"type":"boolean"},"hosted":{"type":"boolean"},"origin":{"type":["string","null"]},"why":{"type":["string","null"]}},"required":["on","hosted","origin","why"],"additionalProperties":{}},"trophies":{"type":"object","properties":{"trophies":{"type":"array","items":{}},"count":{"type":"integer"}},"required":["trophies","count"],"additionalProperties":{}},"boards":{"type":"object","properties":{"boards":{"type":"array","items":{}},"count":{"type":"integer"}},"required":["boards","count"],"additionalProperties":{}},"keys":{"type":"array","items":{},"description":"Its game keys, by name and first characters."},"rooms":{"type":"object","properties":{"on":{"type":"boolean"},"multiplayer":{"type":"string","enum":["rooms","none","own"]},"stopped":{"type":"boolean"},"hosted":{"type":"boolean"},"script":{"anyOf":[{"type":"object","properties":{"build":{"type":"string"},"at":{"type":"number"}},"required":["build","at"]},{"type":"null"}],"description":"The live build's room code (room.js or a room/ folder), run on Player Two's servers."},"now":{"anyOf":[{"type":"object","properties":{"rooms":{"type":"number"},"players":{"type":"number"}},"required":["rooms","players"],"additionalProperties":{}},{"type":"null"}]},"error":{"anyOf":[{"type":"object","properties":{"message":{"type":"string"},"at":{"type":"number"}},"required":["message","at"],"additionalProperties":{}},{"type":"null"}]}},"required":["on","multiplayer","stopped","hosted","script","now","error"],"additionalProperties":{}},"made":{"description":"key.make: the new key, shown this once.","type":"object","properties":{"token":{"type":"string"}},"required":["token"],"additionalProperties":{}},"reset":{}},"required":["slug","hosted","connect","trophies","boards","keys","rooms"],"additionalProperties":{}},"ServerScore":{"type":"object","properties":{"player":{"type":"string","maxLength":80,"description":"The player's id for this game."},"value":{"type":"integer"}},"required":["player","value"]},"ServerTrophy":{"type":"object","properties":{"player":{"type":"string","maxLength":80,"description":"The player's id for this game."}},"required":["player"]},"IdentityCheck":{"type":"object","properties":{"token":{"type":"string","maxLength":8192,"description":"The identity the client sent (p2.identity())."}},"required":["token"]},"Me":{"type":"object","properties":{"player":{"$ref":"#/components/schemas/GamePlayer"},"game":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"}},"required":["slug","title"]},"session":{"type":"string"},"test":{"type":"boolean"},"demo":{"type":"boolean"},"from":{"type":"string"}},"required":["player","game","session","test","demo","from"]},"Done":{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"]},"EventHeard":{"type":"object","properties":{"ok":{"type":"boolean","const":true},"event":{"type":"string"}},"required":["ok","event"]},"IdentityToken":{"type":"object","properties":{"token":{"type":"string","description":"A JWT (RS256, typed p2-id) for this game only: the game's server checks it against /.well-known/p2-keys.json, or asks /api/v1/sdk/server/identity."},"exp":{"type":"number"}},"required":["token","exp"]},"InviteLink":{"type":"object","properties":{"url":{"type":"string"},"params":{}},"required":["url","params"]},"Seat":{"type":"object","properties":{"url":{"type":"string","description":"The rooms service's WebSocket address."},"ticket":{"type":"string","description":"Good for two minutes."},"exp":{"type":"number"}},"required":["url","ticket","exp"]},"TrophyList":{"type":"object","properties":{"trophies":{"type":"array","items":{"type":"object","properties":{"key":{"type":["string","null"]},"name":{"type":["string","null"]},"how":{"type":["string","null"]},"tier":{"type":"integer"},"xp":{"type":"integer"},"hidden":{"type":"boolean"},"art":{"type":"string"},"sign":{"type":["string","null"]},"earned":{"anyOf":[{"type":"object","properties":{"at":{"type":"number"},"n":{"anyOf":[{"type":"integer"},{"type":"null"}]},"test":{"type":"boolean"}},"required":["at","n"]},{"type":"null"}]},"share":{"type":"integer","description":"Its share of the game's players, in hundredths of a percent."},"rarity":{"type":"string","enum":["New","Common","Rare","Epic","Legendary","Mythic","Divine"]}},"required":["key","name","how","tier","xp","hidden","art","sign","earned","share","rarity"]}},"xp":{"type":"integer"},"level":{"type":"integer"},"progress":{"type":"object","properties":{"into":{"type":"integer"},"need":{"type":"integer"}},"required":["into","need"]}},"required":["trophies","xp","level","progress"]},"TrophyEarned":{"type":"object","properties":{"trophy":{"type":"object","properties":{"key":{"type":["string","null"]},"name":{"type":["string","null"]},"how":{"type":["string","null"]},"tier":{"type":"integer"},"xp":{"type":"integer"},"hidden":{"type":"boolean"},"art":{"type":"string"},"sign":{"type":["string","null"]},"earned":{"anyOf":[{"type":"object","properties":{"at":{"type":"number"},"n":{"anyOf":[{"type":"integer"},{"type":"null"}]},"test":{"type":"boolean"}},"required":["at","n"]},{"type":"null"}]},"share":{"type":"integer","description":"Its share of the game's players, in hundredths of a percent."},"rarity":{"type":"string","enum":["New","Common","Rare","Epic","Legendary","Mythic","Divine"]}},"required":["key","name","how","tier","xp","hidden","art","sign","earned","share","rarity"]},"new":{"type":"boolean"},"n":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Which holder of it the player is (none in test mode)."},"xp":{"type":"object","properties":{"gained":{"type":"integer"},"total":{"type":"integer"},"pending":{"type":"integer"}},"required":["gained","total"]},"level":{"type":"integer"},"progress":{"type":"object","properties":{"into":{"type":"integer"},"need":{"type":"integer"}},"required":["into","need"]},"complete":{"type":"object","properties":{"trophy":{"type":"object","properties":{"key":{"type":["string","null"]},"name":{"type":["string","null"]},"how":{"type":["string","null"]},"tier":{"type":"integer"},"xp":{"type":"integer"},"hidden":{"type":"boolean"},"art":{"type":"string"},"sign":{"type":["string","null"]},"earned":{"anyOf":[{"type":"object","properties":{"at":{"type":"number"},"n":{"anyOf":[{"type":"integer"},{"type":"null"}]},"test":{"type":"boolean"}},"required":["at","n"]},{"type":"null"}]},"share":{"type":"integer","description":"Its share of the game's players, in hundredths of a percent."},"rarity":{"type":"string","enum":["New","Common","Rare","Epic","Legendary","Mythic","Divine"]}},"required":["key","name","how","tier","xp","hidden","art","sign","earned","share","rarity"]},"n":{"anyOf":[{"type":"integer"},{"type":"null"}]},"xp":{"type":"integer"}},"required":["trophy","n","xp"]},"test":{"type":"boolean"}},"required":["trophy","new","n","xp","level","progress"]},"Stats":{"type":"object","properties":{"stats":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"number"}}},"required":["stats"]},"StatsWritten":{"type":"object","properties":{"stats":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"number"}},"unlocked":{"type":"array","items":{"$ref":"#/components/schemas/TrophyEarned"}}},"required":["stats","unlocked"]},"Scores":{"type":"object","properties":{"board":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"order":{"type":"string","enum":["high","low"]},"format":{"type":"string","enum":["number","time","points"]},"min":{"type":["number","null"]},"max":{"type":["number","null"]},"cooldown":{"type":"integer"},"trusted":{"type":"boolean"},"retired":{"type":"boolean"}},"required":["key","name","order","format","min","max","cooldown","trusted"]},"rows":{"type":"array","items":{"type":"object","properties":{"rank":{"type":"integer"},"value":{"type":"number"},"at":{"type":"number"},"player":{"type":"object","properties":{"id":{"type":["string","null"]},"handle":{"type":["string","null"]},"name":{"type":"string"},"picture":{"type":["string","null"]}},"required":["id","handle","name"]},"me":{"type":"boolean"}},"required":["rank","value","at","player"]}},"total":{"type":"integer"},"me":{"anyOf":[{"type":"object","properties":{"rank":{"type":"integer"},"value":{"type":"number"}},"required":["rank","value"]},{"type":"null"}]}},"required":["board","rows","total","me"]},"ScoreKept":{"type":"object","properties":{"board":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"order":{"type":"string","enum":["high","low"]},"format":{"type":"string","enum":["number","time","points"]},"min":{"type":["number","null"]},"max":{"type":["number","null"]},"cooldown":{"type":"integer"},"trusted":{"type":"boolean"},"retired":{"type":"boolean"}},"required":["key","name","order","format","min","max","cooldown","trusted"]},"value":{"type":"number"},"best":{"type":"number"},"new":{"type":"boolean","description":"It is the player's best."},"previous":{"type":["number","null"]},"rank":{"anyOf":[{"type":"integer"},{"type":"null"}]},"total":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"required":["board","value","best","new","previous","rank","total"]},"SaveList":{"type":"object","properties":{"slots":{"type":"array","items":{"type":"object","properties":{"slot":{"type":"string"},"size":{"type":"integer"},"version":{"type":"integer"},"at":{"type":"number"}},"required":["slot","size","version","at"]}},"max":{"type":"integer"},"maxBytes":{"type":"integer"}},"required":["slots","max","maxBytes"]},"SaveRead":{"type":"object","properties":{"slot":{"type":"string"},"data":{"type":"string","description":"base64"},"size":{"type":"integer"},"version":{"type":"integer"},"at":{"type":"number"}},"required":["slot","data","size","version","at"]},"SaveKept":{"type":"object","properties":{"slot":{"type":"string"},"size":{"type":"integer"},"version":{"type":"integer"},"at":{"type":"number"}},"required":["slot","size","version","at"]},"SaveGone":{"type":"object","properties":{"deleted":{"type":"boolean","const":true},"slot":{"type":"string"}},"required":["deleted","slot"]},"MirrorRead":{"type":"object","properties":{"slot":{"type":"string"},"data":{"type":"string","description":"The copy, as JSON text."},"size":{"type":"integer"},"version":{"type":"integer"},"at":{"type":"number"}},"required":["slot","data","size","version","at"]},"AddonList":{"type":"object","properties":{"addons":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"about":{"type":"string"},"price":{"type":"number"},"owned":{"type":"boolean"}},"required":["key","name","about","price","owned"]}},"owned":{"type":"array","items":{"type":"string"},"description":"The keys of every add-on the player has, retired ones too."}},"required":["addons","owned"]},"AddonOwned":{"type":"object","properties":{"key":{"type":"string"},"owned":{"type":"boolean"}},"required":["key","owned"]},"CloudSave":{"type":"object","properties":{"folders":{"type":"array","items":{},"description":"The save folders its developer named for this system."},"save":{"anyOf":[{"type":"object","properties":{"version":{"type":"integer"},"size":{"type":"integer"},"at":{"type":"number"},"url":{"type":"string"}},"required":["version","size","at","url"]},{"type":"null"}]}},"required":["folders","save"]},"CloudKept":{"anyOf":[{"type":"object","properties":{"key":{"type":"string"},"url":{"type":"string","description":"Where to PUT the zip (fifteen minutes)."}},"required":["key","url"]},{"type":"object","properties":{"version":{"type":"integer"},"size":{"type":"integer"},"at":{"type":"number"}},"required":["version","size","at"]}]},"ServerSession":{"type":"object","properties":{"player":{"$ref":"#/components/schemas/GamePlayer"},"game":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"}},"required":["slug","title"]},"session":{"type":"string"},"test":{"type":"boolean"},"demo":{"type":"boolean"},"from":{"type":"string"},"live":{"type":"boolean"},"startedAt":{"type":"number"},"beatAt":{"type":"number"}},"required":["player","game","session","test","demo","from","live","startedAt","beatAt"]},"ServerAddons":{"type":"object","properties":{"player":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]},{"$ref":"#/components/schemas/GamePlayer"}]},"live":{"type":"boolean"},"addons":{"type":"array","items":{"type":"string"},"description":"The keys of the add-ons the player has."}},"required":["player","addons"]},"IdentityChecked":{"anyOf":[{"type":"object","properties":{"valid":{"type":"boolean","const":true},"player":{"type":"object","properties":{"id":{"type":"string"},"handle":{"type":"string"},"name":{"type":"string"},"picture":{"type":["string","null"]},"level":{"type":"integer"}},"required":["id","handle","name","picture","level"]},"kind":{"type":"string","enum":["full","demo","test"]},"game":{"type":"object","properties":{"slug":{"type":"string"}},"required":["slug"]},"session":{"type":"string"},"live":{"type":"boolean"},"exp":{"type":"number"}},"required":["valid","player","kind","game","session","live","exp"]},{"type":"object","properties":{"valid":{"type":"boolean","const":false},"code":{"type":"string"},"why":{"type":"string"},"player":{"type":"null"},"kind":{"type":"null"}},"required":["valid","code","why","player","kind"]}]},"GameRead":{"type":"object","properties":{"sub":{"type":"object","properties":{"v":{"type":"number","const":1},"slug":{"type":"string"},"createdAt":{"type":"number","description":"When it was listed (milliseconds since 1970)."},"draft":{"$ref":"#/components/schemas/DraftKept"}},"required":["v","slug","createdAt","draft"]},"pledges":{"type":"array","items":{}},"real":{"type":"object","properties":{"studio":{"type":"object","properties":{"name":{"type":"string"},"handle":{"type":"string"},"since":{"type":"number"},"bio":{"type":"string"},"base":{"type":"string"},"sign":{"type":"string"},"site":{"type":"string"},"x":{"type":"string"},"discord":{"type":"string"},"youtube":{"type":"string"},"github":{"anyOf":[{"type":"object","properties":{"username":{"type":"string"},"at":{"type":"number"},"days":{"type":"array","items":{"type":"number"}},"levels":{"type":"array","items":{"type":"number"}},"total":{"type":"number"}},"required":["username","at","days","levels","total"],"additionalProperties":{}},{"type":"null"}]},"verified":{"type":"boolean","description":"Player Two has checked the developer's identity."},"shipped":{"type":"integer"},"followers":{"type":"integer"}},"required":["name","handle","since","bio","base","sign","site","x","discord","youtube","github","verified"],"additionalProperties":{}},"raise":{"type":"object","properties":{"raised":{"type":"number"},"backers":{"type":"number"},"goal":{"type":"number"},"opensAt":{"type":"number"},"closesAt":{"type":"number"},"state":{"type":"string"},"history":{"type":"array","items":{"type":"number"}},"fundedAt":{"type":["number","null"]}},"required":["raised","backers","goal","opensAt","closesAt","state","history","fundedAt"],"additionalProperties":{}},"stages":{"type":"array","items":{"type":"object","properties":{"ord":{"type":"number"},"title":{"type":"string"},"state":{"type":"string"}},"required":["ord","title","state"],"additionalProperties":{}}},"votes":{"type":"array","items":{"type":"object","properties":{"stage":{"type":"number"},"state":{"type":"string"}},"required":["stage","state"],"additionalProperties":{}}},"updates":{"type":"array","items":{"type":"object","properties":{"at":{"type":"number"},"title":{"type":"string"},"body":{"type":"string"}},"required":["at","title","body"],"additionalProperties":{}}},"feed":{"type":"array","items":{"type":"object","properties":{"who":{"type":"string"},"amount":{"type":"number"},"at":{"type":"number"}},"required":["who","amount","at"],"additionalProperties":{}}},"copies":{"type":"number"},"gross":{"type":"number"},"price":{"type":"number","description":"What it costs in the store now: on a sale, the sale's price."},"sale":{"type":"object","properties":{"percent":{"type":"number"},"was":{"type":"number","description":"The price before the sale."},"ends":{"type":"number"}},"required":["percent","was","ends"],"additionalProperties":{}},"prices":{"type":"array","items":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"}],"items":false,"minItems":2,"maxItems":2}},"low30":{"type":"number"},"wishlists":{"type":"number"},"plays":{"type":"number"},"hours":{"type":"number"},"inGame":{"type":"number"},"recent":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"}},"required":["handle"],"additionalProperties":{}}},"players":{"type":"number"},"playerDays":{"type":"array","items":{"type":"number"}},"removed":{"type":"boolean"},"archived":{"type":"boolean"},"featured":{"type":["number","null"]},"reviews":{"type":"object","properties":{"n":{"type":"number"},"yes":{"type":"number"}},"required":["n","yes"],"additionalProperties":{}}},"required":["studio","stages","votes","updates","feed","copies","gross","price","wishlists","plays","players","playerDays","removed"],"additionalProperties":{}}},"required":["sub","pledges","real"]},"GameList":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/GameRead"}}},"required":["games"]},"LiveCounts":{"type":"object","properties":{"games":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer"},"description":"Players in each game now, by slug; a game with nobody in it isn't listed."}},"required":["games"]},"PlayerPublic":{"type":"object","properties":{"handle":{"type":"string"},"name":{"type":"string"},"joined":{"type":"number"},"moved":{},"xp":{"type":"integer"},"level":{"type":"integer"},"bio":{"type":"string"},"hue":{"anyOf":[{},{"type":"null"}]},"links":{},"site":{"type":"string"},"followers":{"type":"integer"},"following":{"type":"integer"},"followed":{"type":"boolean"},"me":{"type":"boolean"},"stats":{"type":"object","properties":{"library":{"type":"integer"},"wishlist":{"type":"integer"},"passes":{"type":"integer"},"reviews":{"type":"integer"}},"required":["library","wishlist","passes","reviews"]},"standing":{},"activity":{"anyOf":[{"type":"array","items":{}},{"type":"null"}]},"friends":{"anyOf":[{"type":"object","properties":{"n":{"type":"integer"},"mutual":{"type":"integer"},"list":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"},"name":{"type":["string","null"]}},"required":["handle","name"],"additionalProperties":{}}}},"required":["n","mutual","list"],"additionalProperties":{}},{"type":"null"}]},"friend":{},"collections":{},"private":{"type":"object","properties":{"standing":{"type":"boolean"},"activity":{"type":"boolean"},"friendsOnly":{"type":"boolean"},"hidden":{"type":"boolean"}},"required":["standing","activity","friendsOnly","hidden"]}},"required":["handle","name","joined","xp","level","bio","hue","links","site","followers","following","followed","me","stats","standing","activity","friends","friend","collections","private"],"additionalProperties":{}},"StudioRead":{"type":"object","properties":{"studio":{"type":"object","properties":{"name":{"type":"string"},"handle":{"type":"string"},"since":{"type":"number"},"bio":{"type":"string"},"base":{"type":"string"},"sign":{"type":"string"},"site":{"type":"string"},"x":{"type":"string"},"discord":{"type":"string"},"youtube":{"type":"string"},"github":{"anyOf":[{"type":"object","properties":{"username":{"type":"string"},"at":{"type":"number"},"days":{"type":"array","items":{"type":"number"}},"levels":{"type":"array","items":{"type":"number"}},"total":{"type":"number"}},"required":["username","at","days","levels","total"],"additionalProperties":{}},{"type":"null"}]},"verified":{"type":"boolean","description":"Player Two has checked the developer's identity."},"shipped":{"type":"integer"},"followers":{"type":"integer"}},"required":["name","handle","since","bio","base","sign","site","x","discord","youtube","github","verified","followers"],"additionalProperties":{}}},"required":["studio"]},"McpMessage":{"type":"object","properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","number","null"]},"method":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["jsonrpc"],"additionalProperties":{}}},"securitySchemes":{"agentKey":{"type":"http","scheme":"bearer","bearerFormat":"p2_agent_...","description":"A player's agent key: they make one in their studio on playertwo.lol, under Agents (shown once). It submits and edits that player's games and nothing else: no payments, no account settings, never an admin's powers."},"playSession":{"type":"http","scheme":"bearer","bearerFormat":"p2s_...","description":"A play session's token: the game's own calls while a player plays it (the SDK sends it). Made by POST /api/v1/games/{slug}/session as the game starts, alive while the game beats once a minute."},"gameKey":{"type":"http","scheme":"bearer","bearerFormat":"p2g_...","description":"A game's key, for its own server only: its developer makes one in their studio (the game's services). Never put it in a game's client."},"session":{"type":"apiKey","in":"cookie","name":"p2-session","description":"A player signed in on playertwo.lol (the session cookie; a Privy access token as Authorization: Bearer works too)."}}}}