{"openapi":"3.0.3","info":{"title":"Educaplay API","version":"1.0.0","description":"Educaplay's public API for integrating third-party applications with the platform.\n\n**Base URL.** Every endpoint is served under the versioned path `\/v1\/`. The unversioned URLs are still accepted as a legacy alias, but new integrations should always use `\/v1\/`.\n\n**Authentication.** Every call takes an `Authorization: Bearer <token>` header; passing the token in the query string is no longer supported. There are two ways to obtain a token. `POST \/v1\/token\/` exchanges the user's email and password for a token that expires after 24 hours, which suits integrations able to authenticate again on their own. When the user cannot hand a password over to the client \u2014 Model Context Protocol clients among them \u2014 they generate an application token from the application tokens screen of their Educaplay profile settings: it lasts a year, is revoked from that same screen, and grants exactly the same access as any other token. API access is included in the Academic and Commercial plans: on any other plan no token is issued, and requests made with a token issued earlier are answered with `403` and the code `license_required`.\n\n**Model Context Protocol.** `POST \/v1\/agent\/mcp\/` is an MCP server (see the MCP tag) through which AI clients such as Claude, ChatGPT or Claude Code create, edit and publish the user's activities. It accepts the same Bearer tokens as the rest of the API, so a client where the user pastes a token works with an application token. Connectors that sign the user in themselves use the OAuth 2.1 flow instead (see the OAuth tag): authorization code with PKCE `S256`, public clients registered dynamically or identified by a client ID metadata document, and discovery through `\/.well-known\/oauth-protected-resource\/v1\/agent\/mcp` and `\/.well-known\/oauth-authorization-server`. The access tokens issued that way last a year, have no refresh token and are listed and revoked from the same application tokens screen.\n\n**Requests and responses.** Request bodies are sent as `application\/x-www-form-urlencoded`. Successful responses follow the HAL convention (`application\/hal+json`), and errors use the shape `{\"error\": {\"code\": 401, \"messages\": [\"...\"]}}`.\n\n**Rate limiting.** Requests are counted per user over a fixed 60 second window, with a limit that depends on the subscription plan. Exceeding it returns `429 Too Many Requests` with a `Retry-After` header."},"servers":[{"url":"https:\/\/api.educaplay.com"}],"tags":[{"name":"Authentication","description":"Endpoints used to obtain credentials for the rest of the API."},{"name":"Guests","description":"Endpoints to manage guest invitations. Guests are pre-registered students that the mentor can invite to play their activities and track results.\n\nFree accounts can create a limited number of guests; Academic and Commercial subscriptions remove that limit."},{"name":"Reports","description":"Read-only reports about the results of your activities: games, players, errors, trends and multiplayer matches. Every endpoint accepts the same period filters and is limited to the retention window of your plan."},{"name":"MCP","description":"Model Context Protocol server: the tools through which AI clients read, create, edit and publish the activities of the authenticated user."},{"name":"OAuth","description":"OAuth 2.1 authorization for MCP connectors: discovery documents, dynamic client registration and token exchange. The authorization page itself is served by the main site at `\/oauth\/authorize\/`."}],"paths":{"\/v1\/token\/":{"post":{"tags":["Authentication"],"summary":"Obtain a Bearer token","description":"Exchanges HTTP Basic credentials for a Bearer token that can be used on every other API call.\n\nSend the user's Educaplay email and password as an `Authorization: Basic base64(email:password)` header. No request body is expected.","responses":{"200":{"description":"Bearer token issued.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/TokenResponse"}}}},"401":{"description":"The supplied credentials are invalid.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"403":{"description":"The credentials are valid but the plan of the account does not include API access, which is only available on the Academic and Commercial plans. The error carries the code `license_required`.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"406":{"description":"The `Authorization` header is missing or is not a `Basic` scheme.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"429":{"description":"Too many failed attempts from this network or for this account, or the account has been signed in from too many networks recently. Retry later, or sign in on the website, where a captcha challenge is required.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}},"security":[{"basicAuth":[]}]}},"\/v1\/guests\/":{"get":{"tags":["Guests"],"summary":"List the authenticated user's guests","description":"Returns the list of guest invitations created by the authenticated user, with custom-named guests first and then alphabetically by name. Results are paginated.","parameters":[{"name":"page","in":"query","required":false,"description":"Page number (page size is 500).","schema":{"type":"integer","minimum":1}},{"name":"group","in":"query","required":false,"description":"Filter by group: a group id, or `none` for guests without any group.","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of guests.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/GuestListResponse"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}},"post":{"tags":["Guests"],"summary":"Create a new guest","description":"Creates guest invitations owned by the authenticated user. Without `names`, creates one guest: if `name` is omitted or empty, an auto-generated placeholder name is used. With `names[]`, creates one guest per name (up to 500 per request) and responds with the list. `groups[]` tags the new guests with existing groups. Each guest carries its nine-letter access code, its direct access link and the content of its QR code.","requestBody":{"required":false,"content":{"application\/x-www-form-urlencoded":{"schema":{"$ref":"#\/components\/schemas\/GuestInput"}}}},"responses":{"200":{"description":"Guest created. With `names[]`, a list of the guests created.","content":{"application\/json":{"schema":{"oneOf":[{"$ref":"#\/components\/schemas\/GuestSummary"},{"$ref":"#\/components\/schemas\/GuestListResponse"}]}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"402":{"$ref":"#\/components\/responses\/PaymentRequired"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/guests\/groups\/":{"get":{"tags":["Guests"],"summary":"List the authenticated user's guest groups","description":"Groups work as tags: a guest may belong to several groups or to none. Each group comes with the number of guests tagged with it.","responses":{"200":{"description":"Groups of the authenticated user.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/GuestGroupListResponse"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}},"post":{"tags":["Guests"],"summary":"Create a guest group","description":"Creates a group owned by the authenticated user. Tag guests with it through `groups[]` when creating them.","requestBody":{"required":true,"content":{"application\/x-www-form-urlencoded":{"schema":{"$ref":"#\/components\/schemas\/GuestGroupInput"}}}},"responses":{"200":{"description":"Group created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/GuestGroup"}}}},"400":{"description":"Empty name."},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/guests\/groups\/{groupId}\/":{"put":{"tags":["Guests"],"summary":"Rename a guest group","parameters":[{"name":"groupId","in":"path","required":true,"description":"Numeric identifier of the group.","schema":{"type":"integer","format":"int64"}}],"requestBody":{"required":true,"content":{"application\/x-www-form-urlencoded":{"schema":{"$ref":"#\/components\/schemas\/GuestGroupInput"}}}},"responses":{"200":{"description":"Group renamed.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/GuestGroup"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"404":{"description":"The group does not exist or is not yours."},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}},"delete":{"tags":["Guests"],"summary":"Delete a guest group","description":"Removes the tag from its guests. No guest is deleted.","parameters":[{"name":"groupId","in":"path","required":true,"description":"Numeric identifier of the group.","schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Group deleted."},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"404":{"description":"The group does not exist or is not yours."},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/guests\/{guestId}\/":{"get":{"tags":["Guests"],"summary":"Retrieve a single guest","description":"Returns the guest identified by `guestId`. The authenticated user must be the mentor that created it.","parameters":[{"name":"guestId","in":"path","required":true,"description":"Numeric identifier of the guest.","schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Guest details.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/GuestSummary"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"403":{"$ref":"#\/components\/responses\/Forbidden"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}},"put":{"tags":["Guests"],"summary":"Update a guest's name","description":"Updates the display name of the guest. An empty `name` is ignored and the previous value is kept.","parameters":[{"name":"guestId","in":"path","required":true,"description":"Numeric identifier of the guest.","schema":{"type":"integer","format":"int64"}}],"requestBody":{"required":true,"content":{"application\/x-www-form-urlencoded":{"schema":{"$ref":"#\/components\/schemas\/GuestInput"}}}},"responses":{"200":{"description":"Guest updated.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/GuestSummary"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"403":{"$ref":"#\/components\/responses\/Forbidden"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}},"delete":{"tags":["Guests"],"summary":"Delete a guest","description":"Permanently deletes the guest and, if it had been linked to a player account through the access code, that linked player account too.","parameters":[{"name":"guestId","in":"path","required":true,"description":"Numeric identifier of the guest.","schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Guest deleted."},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"403":{"$ref":"#\/components\/responses\/Forbidden"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/games\/":{"get":{"tags":["Reports"],"summary":"Games report overview","description":"Aggregated KPIs and charts for every activity owned by the authenticated user over the selected period.","parameters":[{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/GamesOverviewResponse"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/games\/list\/":{"get":{"tags":["Reports"],"summary":"List activities with their results","description":"Paginated list of the user's activities with the aggregated results of the period: number of plays, average accuracy, average time and rating. Pages hold up to 50 items.","parameters":[{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"},{"$ref":"#\/components\/parameters\/Page"},{"$ref":"#\/components\/parameters\/SearchQuery"},{"$ref":"#\/components\/parameters\/ActivityTypeFilter"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/GamesListResponse"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/games\/{gameId}\/":{"get":{"tags":["Reports"],"summary":"Results of a single activity","description":"Detailed report of one activity: KPIs, charts and the most frequent wrong answers over the selected period.","parameters":[{"name":"gameId","in":"path","required":true,"description":"Numeric identifier of the activity.","schema":{"type":"integer"}},{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/GamesDetailResponse"}}}},"404":{"$ref":"#\/components\/responses\/NotFound"},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/games\/{gameId}\/ranking\/":{"get":{"tags":["Reports"],"summary":"Ranking of an activity","description":"Paginated ranking of the players who completed one activity, best score first. Pages hold up to 50 items.","parameters":[{"name":"gameId","in":"path","required":true,"description":"Numeric identifier of the activity.","schema":{"type":"integer"}},{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"},{"$ref":"#\/components\/parameters\/Page"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/GamesRankingResponse"}}}},"404":{"$ref":"#\/components\/responses\/NotFound"},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/players\/kpis\/":{"get":{"tags":["Reports"],"summary":"Players KPIs","description":"Headline KPIs of the players report, together with the weekly sparklines that accompany them.","parameters":[{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"},{"$ref":"#\/components\/parameters\/PlayersSegment"},{"$ref":"#\/components\/parameters\/PlayersIds"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/PlayersPanelResponse"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/players\/evolution\/":{"get":{"tags":["Reports"],"summary":"Players evolution over time","description":"Time series of activity and results for the selected players over the period.","parameters":[{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"},{"$ref":"#\/components\/parameters\/PlayersSegment"},{"$ref":"#\/components\/parameters\/PlayersIds"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/PlayersPanelResponse"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/players\/distribution\/":{"get":{"tags":["Reports"],"summary":"Distribution of players results","description":"Distribution of scores and accuracy across the selected players.","parameters":[{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"},{"$ref":"#\/components\/parameters\/PlayersSegment"},{"$ref":"#\/components\/parameters\/PlayersIds"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/PlayersPanelResponse"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/players\/heatmap\/":{"get":{"tags":["Reports"],"summary":"Players activity heatmap","description":"Activity heatmap by day and hour for the selected players.","parameters":[{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"},{"$ref":"#\/components\/parameters\/PlayersSegment"},{"$ref":"#\/components\/parameters\/PlayersIds"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/PlayersPanelResponse"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/players\/recent\/":{"get":{"tags":["Reports"],"summary":"Most recent plays","description":"Paginated list of the most recent plays, newest first, including the activity, the player and every attempt. Pages hold up to 10 items and the window is limited to the last year.","parameters":[{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"},{"$ref":"#\/components\/parameters\/PlayersSegment"},{"$ref":"#\/components\/parameters\/PlayersIds"},{"$ref":"#\/components\/parameters\/Page"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/PlayersRecentResponse"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/players\/errors\/":{"get":{"tags":["Reports"],"summary":"Ranking of most frequent errors","description":"Paginated ranking of the questions that players get wrong most often, plus the radar data comparing errors per activity. Pages hold up to 10 items.","parameters":[{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"},{"$ref":"#\/components\/parameters\/PlayersSegment"},{"$ref":"#\/components\/parameters\/PlayersIds"},{"$ref":"#\/components\/parameters\/Page"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/PlayersErrorsResponse"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/players\/errors\/player\/":{"get":{"tags":["Reports"],"summary":"Errors of a single player by activity","description":"Errors made by one player across the activities that form the axes of the errors radar. Returns 404 when the player has no results in the period.","parameters":[{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"},{"$ref":"#\/components\/parameters\/PlayersSegment"},{"$ref":"#\/components\/parameters\/PlayersIds"},{"name":"key","in":"query","required":true,"description":"Player key, as returned in the `key` field of the players list (`R<id>` for registered users, `A<token>` for anonymous players).","schema":{"type":"string"}},{"name":"gids","in":"query","required":false,"description":"Comma-separated activity identifiers that define the axes of the radar, in order.","schema":{"type":"string"}}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/PlayersPanelResponse"}}}},"404":{"$ref":"#\/components\/responses\/NotFound"},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/players\/errors\/detail\/":{"get":{"tags":["Reports"],"summary":"Detail of the errors of a player","description":"Detailed breakdown of the wrong answers of one player over the selected period.","parameters":[{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"},{"$ref":"#\/components\/parameters\/PlayersSegment"},{"$ref":"#\/components\/parameters\/PlayersIds"},{"name":"key","in":"query","required":true,"description":"Player key, as returned in the `key` field of the players list (`R<id>` for registered users, `A<token>` for anonymous players).","schema":{"type":"string"}}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/PlayersPanelResponse"}}}},"404":{"$ref":"#\/components\/responses\/NotFound"},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/players\/list\/":{"get":{"tags":["Reports"],"summary":"List players","description":"Paginated list of the players who have completed the user's activities, with their aggregated results. Pages hold up to 50 items.","parameters":[{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"},{"$ref":"#\/components\/parameters\/PlayersSegment"},{"$ref":"#\/components\/parameters\/PlayersIds"},{"$ref":"#\/components\/parameters\/Page"},{"$ref":"#\/components\/parameters\/SearchQuery"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/PlayersListResponse"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/trends\/":{"get":{"tags":["Reports"],"summary":"Trends report","description":"Long-term trends of the account: KPIs, charts, activity heatmap, conversion funnel and generated insights.","parameters":[{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/TrendsResponse"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/matches\/":{"get":{"tags":["Reports"],"summary":"Multiplayer matches overview","description":"Aggregated results of the multiplayer matches hosted by the authenticated user over the selected period.","parameters":[{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"},{"$ref":"#\/components\/parameters\/Page"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/MatchesOverviewResponse"}}}},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/reports\/matches\/{matchId}\/":{"get":{"tags":["Reports"],"summary":"Results of a single match","description":"Detailed results of one multiplayer match, including its participants and their scores.","parameters":[{"name":"matchId","in":"path","required":true,"description":"Identifier of the multiplayer match.","schema":{"type":"string"}},{"$ref":"#\/components\/parameters\/ReportsPeriod"},{"$ref":"#\/components\/parameters\/ReportsDateStart"},{"$ref":"#\/components\/parameters\/ReportsDateEnd"}],"responses":{"200":{"description":"Report data for the requested period.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/MatchesDetailResponse"}}}},"404":{"$ref":"#\/components\/responses\/NotFound"},"401":{"$ref":"#\/components\/responses\/Unauthorized"},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/v1\/agent\/mcp\/":{"post":{"tags":["MCP"],"summary":"MCP server endpoint (JSON-RPC 2.0 over Streamable HTTP)","description":"Model Context Protocol server: a single endpoint through which AI clients (Claude, ChatGPT, Claude Code or any MCP client) read, create, edit and publish the activities of the authenticated user by calling tools.\n\n**Transport.** Streamable HTTP, stateless: every JSON-RPC request or notification is its own `POST`, the answer is always one JSON object (no SSE streams), no session is ever issued (`Mcp-Session-Id` is ignored) and notifications are acknowledged with `202`. `GET` is not served.\n\n**Protocol revisions.** Two eras are served on the same endpoint.\n- Handshake revisions `2024-11-05`, `2025-03-26`, `2025-06-18` and `2025-11-25`: the client sends `initialize` and the server answers with the negotiated version (the newest it supports when the requested one is unknown), `serverInfo`, `capabilities` (`tools`) and `instructions`.\n- Revision `2026-07-28`: no handshake. Each request declares `params._meta[\"io.modelcontextprotocol\/protocolVersion\"]` and mirrors it in the `MCP-Protocol-Version` header, together with `Mcp-Method` (the method) and, on `tools\/call`, `Mcp-Name` (the tool name, Base64 sentinel encoding accepted). Results carry `resultType: \"complete\"`, `_meta[\"io.modelcontextprotocol\/serverInfo\"]` and, on lists, `ttlMs` and `cacheScope`. `server\/discover` returns the supported versions, capabilities, identity and instructions and can be called under either era.\n\n**Methods.** `server\/discover`, `initialize`, `ping`, `tools\/list`, `tools\/call`, `resources\/list` and `prompts\/list` (both empty). Anything else answers `-32601` (`404` under `2026-07-28`, `200` under the handshake revisions).\n\n**Tools.** `tools\/list` returns 26 tools, each with its `title`, its JSON Schema and `annotations` (`title`, `readOnlyHint`, `destructiveHint`, `idempotentHint`):\n- Discover: `list_activity_types`, `get_activity_schema`, `list_my_activities`, `get_activity`, `get_activity_content`, `get_publish_blockers`.\n- Create and edit: `create_activity`, `set_activity_content`, `attach_video`, `update_activity`, `set_activity_audience`, `classify_activity`, `update_activity_settings`, `add_label`, `remove_label`.\n- Media and audio: `list_my_media`, `illustrate_items`, `search_image_library`, `set_item_images`, `remove_item_media`, `set_item_text_visibility`, `describe_image`, `generate_field_audio`.\n- Publication and visibility: `publish_activity`, `unpublish_activity`, `set_activity_privacy`.\n\nEvery tool answers a JSON text, `{\"ok\": true, ...}` or `{\"ok\": false, \"error\": \"<code>\", ...}`, and `isError` mirrors `ok`. Tools that write or publish execute immediately: asking the user for confirmation is the client's job, which is what `destructiveHint` is for. Calls are independent of each other (there is no server-side conversation); the image catalogue returned by `list_my_media` and `search_image_library` stays valid for one hour so that `set_item_images` and `describe_image` can refer to it from later requests.\n\n**Authentication.** Any Bearer token of this API: an application token generated from the profile settings (for clients where the user pastes a token, for example `claude mcp add --transport http educaplay <this URL> --header \"Authorization: Bearer <token>\"`), or an access token obtained through the OAuth 2.1 flow described under the OAuth tag (for connectors that sign the user in, such as the Claude or ChatGPT connector settings, where only this URL is needed). Both grant exactly the same access as any other token of the API.\n\n**Quotas.** Calls count against the API rate limit of the plan like any other request. `describe_image` spends the AI budget the user shares with the site's assistant, the audio tools spend the text to speech quota of the plan, and publishing is subject to the limits of the plan, which come back as `blockers`.","requestBody":{"description":"A single JSON-RPC 2.0 request or notification.","required":true,"content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/JsonRpcRequest"}}}},"responses":{"200":{"description":"JSON-RPC response: `result` on success or `error` on a protocol failure. A tool that fails answers inside `result` with `isError: true` and a JSON text such as `{\"ok\": false, \"error\": \"forbidden\"}`.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/JsonRpcResponse"}}}},"202":{"description":"Notification accepted. Empty body."},"400":{"description":"Only for `2026-07-28` requests: the protocol version is not supported (`-32022`, the supported versions travel in `error.data.supported`) or the `MCP-Protocol-Version`, `Mcp-Method` and `Mcp-Name` headers are missing or do not match the body (`-32020`).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/JsonRpcResponse"}}}},"401":{"description":"Missing or invalid Bearer token. The response carries `WWW-Authenticate: Bearer resource_metadata=\"...\"` pointing at the protected resource metadata, which is how OAuth-capable MCP clients discover the authorization flow.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"403":{"description":"`license_required` when the subscription plan of the user cannot use the MCP server, `profile_not_allowed` for ticket accounts.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"404":{"description":"The MCP server is disabled (`feature_disabled`), or, only for `2026-07-28` requests, the method does not exist (`-32601` in a JSON-RPC error body).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/JsonRpcResponse"}}}},"429":{"$ref":"#\/components\/responses\/TooManyRequests"}}}},"\/.well-known\/oauth-protected-resource\/v1\/agent\/mcp":{"get":{"tags":["OAuth"],"summary":"Protected resource metadata (RFC 9728)","description":"Discovery document of the MCP server as an OAuth 2.1 protected resource. MCP clients fetch it from the URL announced in the `WWW-Authenticate` header of a `401` answer of the MCP endpoint, or directly at this path. It names the authorization server (this same API) and the supported scopes.","responses":{"200":{"description":"Metadata document.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/ProtectedResourceMetadata"}}}}},"security":[]}},"\/.well-known\/oauth-authorization-server":{"get":{"tags":["OAuth"],"summary":"Authorization server metadata (RFC 8414)","description":"Describes the authorization server: the authorization page on the main site, the token and registration endpoints of this API, the `code` response type, the `authorization_code` grant, PKCE `S256`, public clients only (`token_endpoint_auth_methods_supported: [\"none\"]`) and support for client ID metadata documents, so a client that publishes its metadata at an HTTPS URL can use that URL as `client_id` without registering.","responses":{"200":{"description":"Metadata document.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/AuthorizationServerMetadata"}}}}},"security":[]}},"\/v1\/oauth\/register\/":{"post":{"tags":["OAuth"],"summary":"Dynamic client registration (RFC 7591)","description":"Registers a public client and returns its `client_id`. The identifier is self-contained and signed, so nothing is stored on the server: it encodes the registered redirect URIs and the client name, and the authorization page checks every request against them. Clients that publish a client ID metadata document do not need this endpoint.","requestBody":{"description":"Client metadata.","required":true,"content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/ClientRegistrationRequest"}}}},"responses":{"201":{"description":"Client registered.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/ClientRegistrationResponse"}}}},"400":{"description":"`invalid_client_metadata` when the body is not a JSON object, `invalid_redirect_uri` when no acceptable HTTPS or loopback redirect URI is given.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/OAuthError"}}}}},"security":[]}},"\/v1\/oauth\/token\/":{"post":{"tags":["OAuth"],"summary":"Token endpoint (authorization code with PKCE)","description":"Exchanges the authorization code obtained from `\/oauth\/authorize\/` on the main site for an access token. The code is single use, bound to the `client_id` and `redirect_uri` of the authorization request, and verified against the PKCE `code_verifier`. The access token is a regular Bearer token of this API: it lasts a year, there is no refresh token, and the user can see and revoke it from the application tokens screen of their profile.","requestBody":{"description":"Token request.","required":true,"content":{"application\/x-www-form-urlencoded":{"schema":{"type":"object","required":["grant_type","code","redirect_uri","client_id","code_verifier"],"properties":{"grant_type":{"type":"string","enum":["authorization_code"]},"code":{"type":"string","description":"Authorization code returned to the redirect URI."},"redirect_uri":{"type":"string","format":"uri","description":"The same redirect URI used in the authorization request."},"client_id":{"type":"string","description":"Identifier issued by the registration endpoint, or the HTTPS URL of the client ID metadata document."},"code_verifier":{"type":"string","description":"PKCE verifier whose `S256` challenge was sent in the authorization request."}}}}}},"responses":{"200":{"description":"Access token issued.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/OAuthTokenResponse"}}}},"400":{"description":"`unsupported_grant_type`, `invalid_grant` (unknown, used or expired code, redirect URI or verifier mismatch) or `invalid_client`.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/OAuthError"}}}}},"security":[]}}},"components":{"schemas":{"HalLinks":{"type":"array","items":{"$ref":"#\/components\/schemas\/HalLink"}},"HalLink":{"type":"object","required":["rel","href"],"properties":{"rel":{"type":"string","example":"self"},"href":{"type":"string","format":"uri"}}},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"integer","description":"HTTP status code of the error."},"messages":{"type":"array","description":"Optional list of human readable details. Absent on most errors.","items":{"type":"string"}}},"required":["code"]}},"required":["error"]},"TokenResponse":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"Bearer token to use on subsequent API requests as `Authorization: Bearer <token>`."}}},"GuestSummary":{"type":"object","required":["id","name","code","link","qr","groups","_links"],"properties":{"id":{"type":"integer","format":"int64","example":12345},"name":{"type":"string","example":"Alice"},"code":{"type":"string","description":"Auto-generated nine-letter access code in the form `XXX-XXX-XXX`. Share it with the guest to let them play the mentor's activities.","example":"ABC-DEF-GHI"},"_links":{"$ref":"#\/components\/schemas\/HalLinks"},"link":{"type":"string","format":"uri","description":"Direct access link. Opening it shows a confirmation screen (\"Enter as \u2026\") and signs the guest in without typing the code. It is the same secret as the code: share it with the same care.","example":"https:\/\/www.educaplay.com\/login\/invitation\/ABC-DEF-GHI\/"},"qr":{"type":"string","format":"uri","description":"Content to encode in the guest's QR code. Educaplay does not render QR images server-side: it encodes this URL on the client with the same generator used for game QR codes, and so can you.","example":"https:\/\/www.educaplay.com\/login\/invitation\/ABC-DEF-GHI\/"},"groups":{"type":"array","description":"Groups (tags) the guest belongs to. A guest may be in several groups or in none.","items":{"$ref":"#\/components\/schemas\/GuestGroup"}}}},"GuestListResponse":{"type":"object","required":["_embedded","_links"],"properties":{"_embedded":{"type":"object","required":["guests"],"properties":{"guests":{"type":"array","items":{"$ref":"#\/components\/schemas\/GuestSummary"}}}},"_links":{"$ref":"#\/components\/schemas\/HalLinks"}}},"GuestInput":{"type":"object","properties":{"name":{"type":"string","description":"Display name for the guest. If omitted or empty on creation, an auto-generated placeholder is used. On update, an empty value is ignored and the existing name is kept.","example":"Alice"},"names":{"type":"array","description":"Creation only. One guest per name, up to 500 per request; duplicates are allowed. When present, `name` is ignored and the response is a list of guests. Send it as `names[]` form fields.","maxItems":500,"items":{"type":"string"},"example":["Ana G.","Lista 07"]},"groups":{"type":"array","description":"Creation only. Ids of the caller's groups the new guests are tagged with.","items":{"type":"integer","format":"int64"},"example":[42]}}},"ReportsFilters":{"type":"object","description":"Reporting period actually applied to the response.","properties":{"filter":{"type":"string","description":"Period preset that was applied; empty when the default last month was used."},"from":{"type":"integer","description":"Start of the period. Unix timestamp in seconds."},"to":{"type":"integer","description":"End of the period. Unix timestamp in seconds."},"type":{"type":"string","description":"Activity type filter that was applied, if any."},"clampedToLicense":{"type":"boolean","description":"`true` when the requested period reached further back than the retention window of the account's plan and was therefore shortened."}}},"PlayerRef":{"type":"object","properties":{"type":{"type":"string","description":"`registered`, `anonymous` or `unidentified`."},"id":{"type":"string"},"name":{"type":"string"},"photo":{"type":"string"},"slug":{"type":"string"}}},"ActivityRef":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"type":{"type":"string","description":"Activity type, such as `TEST` or `FROGGY_JUMPS`."},"indiceRecursos":{"type":"integer"}}},"PlayersContext":{"type":"object","description":"Selection context echoed back by every endpoint of the players report.","properties":{"filters":{"$ref":"#\/components\/schemas\/ReportsFilters"},"segment":{"type":"string","description":"Player segment that was applied."},"selected":{"type":"array","description":"Player keys the report was restricted to.","items":{"type":"string"}},"tooManySelected":{"type":"boolean","description":"`true` when more than 100 player keys were supplied and the selection was ignored."}}},"PlayersPanelResponse":{"allOf":[{"$ref":"#\/components\/schemas\/PlayersContext"}],"description":"Panel of the players report. Beyond the selection context, each panel adds its own payload (`kpis`, `evolution`, `distribution`, `heatmap` or `playerErrors`), whose shape depends on the panel.","additionalProperties":true},"RecentGameItem":{"type":"object","properties":{"id":{"type":"integer"},"activity":{"$ref":"#\/components\/schemas\/ActivityRef"},"player":{"$ref":"#\/components\/schemas\/PlayerRef"},"score":{"type":"integer","description":"Score of the best attempt, from 0 to 100."},"time":{"type":"integer","description":"Time spent, in seconds."},"attempts":{"type":"integer","description":"Number of attempts of this player on this activity."},"attemptsList":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"score":{"type":"integer"},"time":{"type":"integer"},"date":{"type":"integer","description":"Moment of the attempt. Unix timestamp in seconds."}}}},"date":{"type":"integer","description":"Moment of the most recent attempt. Unix timestamp in seconds."}}},"PlayersRecentResponse":{"allOf":[{"$ref":"#\/components\/schemas\/PlayersContext"}],"properties":{"items":{"type":"array","items":{"$ref":"#\/components\/schemas\/RecentGameItem"}},"hasMore":{"type":"boolean","description":"`true` when another page is available."},"page":{"type":"integer"},"_links":{"$ref":"#\/components\/schemas\/HalLinks"}}},"PlayerListItem":{"type":"object","properties":{"type":{"type":"string","description":"`registered` or `anonymous`."},"id":{"type":"string"},"key":{"type":"string","description":"Player key to use in the `ids` filter and in the per-player endpoints."},"name":{"type":"string"},"photo":{"type":"string"},"accuracy":{"type":"integer","description":"Average accuracy over the period, from 0 to 100."},"games":{"type":"integer","description":"Number of activities completed."},"lastPlayed":{"type":"integer","description":"Most recent play. Unix timestamp in seconds."},"best":{"type":"integer","description":"Best score achieved."},"totalTime":{"type":"integer","description":"Total time spent, in seconds."}}},"PlayersListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#\/components\/schemas\/PlayerListItem"}},"hasMore":{"type":"boolean"},"page":{"type":"integer"},"_links":{"$ref":"#\/components\/schemas\/HalLinks"}}},"PlayersErrorsResponse":{"allOf":[{"$ref":"#\/components\/schemas\/PlayersContext"}],"description":"Ranking of the most frequent wrong answers, plus the `radar` payload that compares errors per activity.","properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true}},"hasMore":{"type":"boolean"},"page":{"type":"integer"},"radar":{"type":"object","additionalProperties":true},"_links":{"$ref":"#\/components\/schemas\/HalLinks"}},"additionalProperties":true},"GameListItem":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"},"type":{"type":"string"},"created":{"type":"integer","description":"Creation date of the activity. Unix timestamp in seconds."},"plays":{"type":"integer","description":"Number of plays over the period."},"accuracy":{"type":"integer","description":"Average accuracy, from 0 to 100."},"avgTime":{"type":"integer","description":"Average time per play, in seconds."},"rating":{"type":"number","description":"Average rating, from 0 to 5."},"ratingCount":{"type":"integer"}}},"GamesListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#\/components\/schemas\/GameListItem"}},"hasMore":{"type":"boolean"},"page":{"type":"integer"},"_links":{"$ref":"#\/components\/schemas\/HalLinks"}}},"GamesOverviewResponse":{"type":"object","description":"Headline KPIs and charts of the games report. The shape of `kpis` and `charts` depends on the panels included.","properties":{"filters":{"$ref":"#\/components\/schemas\/ReportsFilters"},"authorTypes":{"type":"array","description":"Activity types owned by the user, to feed the `type` filter.","items":{"type":"string"}},"kpis":{"type":"object","additionalProperties":true},"charts":{"type":"object","additionalProperties":true},"_links":{"$ref":"#\/components\/schemas\/HalLinks"}},"additionalProperties":true},"GamesDetailResponse":{"type":"object","properties":{"filters":{"$ref":"#\/components\/schemas\/ReportsFilters"},"activity":{"$ref":"#\/components\/schemas\/ActivityRef"},"activities":{"type":"array","description":"Sibling activities of the same author, to switch between reports.","items":{"$ref":"#\/components\/schemas\/ActivityRef"}},"playUrl":{"type":"string","description":"Public URL of the activity."},"stats":{"type":"object","additionalProperties":true},"kpis":{"type":"object","additionalProperties":true},"charts":{"type":"object","additionalProperties":true},"topErrors":{"type":"array","description":"Most frequent wrong answers.","items":{"type":"object","additionalProperties":true}},"_links":{"$ref":"#\/components\/schemas\/HalLinks"}},"additionalProperties":true},"GamesRankingResponse":{"type":"object","properties":{"items":{"type":"array","description":"Ranking rows, best score first.","items":{"type":"object","additionalProperties":true}},"hasMore":{"type":"boolean"},"page":{"type":"integer"}}},"TrendsResponse":{"type":"object","description":"Long-term trends of the account. The payload of each block depends on the panels included.","properties":{"range":{"type":"object","additionalProperties":true},"kpis":{"type":"object","additionalProperties":true},"charts":{"type":"object","additionalProperties":true},"heatmap":{"type":"object","additionalProperties":true},"funnel":{"type":"object","additionalProperties":true},"insights":{"type":"array","items":{"type":"object","additionalProperties":true}},"_links":{"$ref":"#\/components\/schemas\/HalLinks"}},"additionalProperties":true},"MatchesOverviewResponse":{"type":"object","description":"Aggregated results of the multiplayer matches hosted over the period.","properties":{"filters":{"$ref":"#\/components\/schemas\/ReportsFilters"},"items":{"type":"array","items":{"type":"object","additionalProperties":true}},"hasMore":{"type":"boolean"},"page":{"type":"integer"},"_links":{"$ref":"#\/components\/schemas\/HalLinks"}},"additionalProperties":true},"MatchesDetailResponse":{"type":"object","description":"Detailed results of one multiplayer match.","properties":{"filters":{"$ref":"#\/components\/schemas\/ReportsFilters"},"_links":{"$ref":"#\/components\/schemas\/HalLinks"}},"additionalProperties":true},"JsonRpcRequest":{"type":"object","required":["jsonrpc","method"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"description":"Request identifier, string or integer. Omit it to send a notification.","oneOf":[{"type":"string"},{"type":"integer"}]},"method":{"type":"string","example":"tools\/call"},"params":{"type":"object","additionalProperties":true,"description":"Method parameters. `tools\/call` takes `name` and `arguments`; under `2026-07-28` every request also carries `_meta` with `io.modelcontextprotocol\/protocolVersion`."}},"example":{"jsonrpc":"2.0","id":1,"method":"tools\/call","params":{"name":"get_activity","arguments":{"activity_id":12345678}}}},"JsonRpcResponse":{"type":"object","required":["jsonrpc","id"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"oneOf":[{"type":"string"},{"type":"integer"}],"nullable":true},"result":{"type":"object","additionalProperties":true,"description":"Present on success. For `tools\/call`: `content`, a list with one `{\"type\": \"text\", \"text\": \"...\"}` block holding the JSON answer of the tool, and `isError`."},"error":{"type":"object","properties":{"code":{"type":"integer","example":-32601},"message":{"type":"string"},"data":{"type":"object","additionalProperties":true}}}},"example":{"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"{\"ok\":true,\"activity\":{\"id\":12345678,\"title\":\"Rivers of Spain\",\"published\":false}}"}],"isError":false}}},"ProtectedResourceMetadata":{"type":"object","properties":{"resource":{"type":"string","format":"uri","description":"Canonical URL of the MCP endpoint."},"authorization_servers":{"type":"array","items":{"type":"string","format":"uri"}},"bearer_methods_supported":{"type":"array","items":{"type":"string"},"example":["header"]},"scopes_supported":{"type":"array","items":{"type":"string"},"example":["educaplay"]}}},"AuthorizationServerMetadata":{"type":"object","properties":{"issuer":{"type":"string","format":"uri"},"authorization_endpoint":{"type":"string","format":"uri","description":"Authorization page on the main site (`\/oauth\/authorize\/`), where the user signs in and grants access."},"token_endpoint":{"type":"string","format":"uri"},"registration_endpoint":{"type":"string","format":"uri"},"response_types_supported":{"type":"array","items":{"type":"string"},"example":["code"]},"grant_types_supported":{"type":"array","items":{"type":"string"},"example":["authorization_code"]},"code_challenge_methods_supported":{"type":"array","items":{"type":"string"},"example":["S256"]},"token_endpoint_auth_methods_supported":{"type":"array","items":{"type":"string"},"example":["none"]},"client_id_metadata_document_supported":{"type":"boolean","example":true},"scopes_supported":{"type":"array","items":{"type":"string"},"example":["educaplay"]}}},"ClientRegistrationRequest":{"type":"object","required":["redirect_uris"],"properties":{"redirect_uris":{"type":"array","items":{"type":"string","format":"uri"},"description":"HTTPS redirect URIs, or loopback URIs for local clients."},"client_name":{"type":"string"},"token_endpoint_auth_method":{"type":"string","enum":["none"]},"grant_types":{"type":"array","items":{"type":"string"},"example":["authorization_code"]},"response_types":{"type":"array","items":{"type":"string"},"example":["code"]}}},"ClientRegistrationResponse":{"type":"object","properties":{"client_id":{"type":"string"},"client_id_issued_at":{"type":"integer","description":"Unix timestamp."},"redirect_uris":{"type":"array","items":{"type":"string","format":"uri"}},"token_endpoint_auth_method":{"type":"string","example":"none"},"grant_types":{"type":"array","items":{"type":"string"},"example":["authorization_code"]},"response_types":{"type":"array","items":{"type":"string"},"example":["code"]},"client_name":{"type":"string"}}},"OAuthTokenResponse":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","example":"Bearer"},"expires_in":{"type":"integer","description":"Seconds until the token expires.","example":31536000},"scope":{"type":"string","example":"educaplay"}}},"OAuthError":{"type":"object","properties":{"error":{"type":"string","example":"invalid_grant"}}},"GuestGroup":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64","example":42},"name":{"type":"string","example":"3.\u00ba B"},"count":{"type":"integer","description":"Number of guests tagged with this group. Only present when listing groups.","example":27}}},"GuestGroupInput":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Group name (up to 100 characters).","example":"3.\u00ba B"}}},"GuestGroupListResponse":{"type":"object","required":["_embedded","_links"],"properties":{"_embedded":{"type":"object","required":["groups"],"properties":{"groups":{"type":"array","items":{"$ref":"#\/components\/schemas\/GuestGroup"}}}},"_links":{"$ref":"#\/components\/schemas\/HalLinks"}}}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Bearer token, either obtained via `POST \/token\/` or generated as a long-lived application token from the user's profile settings. Send it on every request as the `Authorization: Bearer <token>` header."},"basicAuth":{"type":"http","scheme":"basic","description":"HTTP Basic authentication using the user's Educaplay email and password. Only used to obtain a Bearer token via `POST \/token\/`."}},"responses":{"Unauthorized":{"description":"Authentication is missing or the Bearer token is invalid.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"PaymentRequired":{"description":"The free plan limit for guest invitations has been reached. Upgrade to an Academic or Commercial subscription to create more guests.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"Forbidden":{"description":"Authentication is missing, the token is invalid, the authenticated user is not the owner of the requested resource, or the user does not have an Academic or Commercial subscription.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"NotFound":{"description":"The requested resource does not exist.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"TooManyRequests":{"description":"The request rate limit for the account has been exceeded. Limits depend on the subscription plan (Basic 120, Advanced 300, Academic 600 and Commercial 1200 requests per minute) and are measured over a fixed 60 second window. Wait the number of seconds given in the `Retry-After` header before retrying.","headers":{"Retry-After":{"description":"Seconds remaining until the current rate limit window ends.","schema":{"type":"integer"}}},"content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}},"parameters":{"ReportsPeriod":{"name":"filter","in":"query","required":false,"description":"Reporting period preset. When omitted, the last month is used. Use `custom` together with `tss` and `tse` to define an explicit range. The range is always clamped to the retention window of the account's plan (see `filters.clampedToLicense` in the response).","schema":{"type":"string","enum":["lastDay","lastWeek","lastYear","custom"]}},"ReportsDateStart":{"name":"tss","in":"query","required":false,"description":"Start date of the reporting period, in `YYYYMMDD` format. Only used when `filter=custom`.","schema":{"type":"string","pattern":"^[0-9]{8}$","example":"20260801"}},"ReportsDateEnd":{"name":"tse","in":"query","required":false,"description":"End date of the reporting period, in `YYYYMMDD` format. Only used when `filter=custom`.","schema":{"type":"string","pattern":"^[0-9]{8}$","example":"20260821"}},"Page":{"name":"page","in":"query","required":false,"description":"Zero-based page number. Use the `hasMore` flag in the response to know whether another page is available.","schema":{"type":"integer","minimum":0,"default":0}},"PlayersSegment":{"name":"players","in":"query","required":false,"description":"Restricts the report to a segment of players. Empty (default) covers every player; `guests` covers only guest accounts.","schema":{"type":"string","enum":["","guests"]}},"PlayersIds":{"name":"ids","in":"query","required":false,"description":"Comma-separated list of player keys (the `key` field of the players list) to restrict the report to. At most 100 keys are applied; beyond that the selection is ignored and `tooManySelected` is returned as `true`.","schema":{"type":"string"}},"SearchQuery":{"name":"q","in":"query","required":false,"description":"Free-text search filter applied to the name of the listed items.","schema":{"type":"string"}},"ActivityTypeFilter":{"name":"type","in":"query","required":false,"description":"Restricts the list to a single activity type, such as `TEST`, `SOPA` or `FROGGY_JUMPS`.","schema":{"type":"string"}},"PlayersGroups":{"name":"groups","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated ids of guest groups. Restricts the guests segment to the guests tagged with any of them (same mechanics as `players=guests`).","example":"42,43"}}},"security":[{"bearerAuth":[]}]}